satsolver 0.16.3

policy.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007, Novell Inc.
00003  *
00004  * This program is licensed under the BSD license, read LICENSE.BSD
00005  * for further information
00006  */
00007 
00008 /*
00009  * Generic policy interface for SAT solver
00010  *
00011  */
00012 
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <unistd.h>
00016 #include <string.h>
00017 
00018 #include "solver.h"
00019 #include "evr.h"
00020 #include "policy.h"
00021 #include "poolvendor.h"
00022 #include "poolarch.h"
00023 
00024 
00025 /*-----------------------------------------------------------------*/
00026 
00027 /*
00028  * prep for prune_best_version
00029  *   sort by name
00030  */
00031 
00032 static int
00033 prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
00034 {
00035   Pool *pool = dp;
00036   int r;
00037   Id a = *(Id *)ap;
00038   Id b = *(Id *)bp;
00039   Solvable *sa, *sb;
00040 
00041   sa = pool->solvables + a;
00042   sb = pool->solvables + b;
00043   r = sa->name - sb->name;
00044   if (r)
00045     {
00046       const char *na, *nb;
00047       /* different names. We use real strcmp here so that the result
00048        * is not depending on some random solvable order */
00049       na = id2str(pool, sa->name);
00050       nb = id2str(pool, sb->name);
00051       return strcmp(na, nb);
00052     }
00053   /* the same name, bring installed solvables to the front */
00054   if (pool->installed)
00055     {
00056       if (sa->repo == pool->installed)
00057         {
00058           if (sb->repo != pool->installed)
00059             return -1;
00060         }
00061       else if (sb->repo == pool->installed)
00062         return 1;       
00063     }
00064   /* sort by repository sub-prio (installed repo handled above) */
00065   r = (sb->repo ? sb->repo->subpriority : 0) - (sa->repo ? sa->repo->subpriority : 0);
00066   if (r)
00067     return r;
00068   /* no idea about the order, sort by id */
00069   return a - b;
00070 }
00071 
00072 
00073 /*
00074  * prune to repository with highest priority.
00075  * does not prune installed solvables.
00076  */
00077 
00078 static void
00079 prune_to_highest_prio(Pool *pool, Queue *plist)
00080 {
00081   int i, j;
00082   Solvable *s;
00083   int bestprio = 0, bestprioset = 0;
00084 
00085   /* prune to highest priority */
00086   for (i = 0; i < plist->count; i++)  /* find highest prio in queue */
00087     {
00088       s = pool->solvables + plist->elements[i];
00089       if (pool->installed && s->repo == pool->installed)
00090         continue;
00091       if (!bestprioset || s->repo->priority > bestprio)
00092         {
00093           bestprio = s->repo->priority;
00094           bestprioset = 1;
00095         }
00096     }
00097   if (!bestprioset)
00098     return;
00099   for (i = j = 0; i < plist->count; i++) /* remove all with lower prio */
00100     {
00101       s = pool->solvables + plist->elements[i];
00102       if (s->repo->priority == bestprio || (pool->installed && s->repo == pool->installed))
00103         plist->elements[j++] = plist->elements[i];
00104     }
00105   plist->count = j;
00106 }
00107 
00108 static void
00109 prune_to_highest_prio_per_name(Pool *pool, Queue *plist)
00110 {
00111   Queue pq;
00112   int i, j, k;
00113   Id name;
00114 
00115   queue_init(&pq);
00116   sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
00117   queue_push(&pq, plist->elements[0]);
00118   name = pool->solvables[pq.elements[0]].name;
00119   for (i = 1, j = 0; i < plist->count; i++)
00120     {
00121       if (pool->solvables[plist->elements[i]].name != name)
00122         {
00123           if (pq.count > 2)
00124             prune_to_highest_prio(pool, &pq);
00125           for (k = 0; k < pq.count; k++)
00126             plist->elements[j++] = pq.elements[k];
00127           queue_empty(&pq);
00128           queue_push(&pq, plist->elements[i]);
00129           name = pool->solvables[pq.elements[0]].name;
00130         }
00131     }
00132   if (pq.count > 2)
00133     prune_to_highest_prio(pool, &pq);
00134   for (k = 0; k < pq.count; k++)
00135     plist->elements[j++] = pq.elements[k];
00136   queue_free(&pq);
00137   plist->count = j;
00138 }
00139 
00140 
00141 /*
00142  * prune to recommended/suggested packages.
00143  * does not prune installed packages (they are also somewhat recommended).
00144  */
00145 
00146 static void
00147 prune_to_recommended(Solver *solv, Queue *plist)
00148 {
00149   Pool *pool = solv->pool;
00150   int i, j, k, ninst;
00151   Solvable *s;
00152   Id p, pp, rec, *recp, sug, *sugp;
00153 
00154   ninst = 0;
00155   if (pool->installed)
00156     {
00157       for (i = 0; i < plist->count; i++)
00158         {
00159           p = plist->elements[i];
00160           s = pool->solvables + p;
00161           if (pool->installed && s->repo == pool->installed)
00162             ninst++;
00163         }
00164     }
00165   if (plist->count - ninst < 2)
00166     return;
00167 
00168   /* update our recommendsmap/suggestsmap */
00169   if (solv->recommends_index < 0)
00170     {
00171       MAPZERO(&solv->recommendsmap);
00172       MAPZERO(&solv->suggestsmap);
00173       solv->recommends_index = 0;
00174     }
00175   while (solv->recommends_index < solv->decisionq.count)
00176     {
00177       p = solv->decisionq.elements[solv->recommends_index++];
00178       if (p < 0)
00179         continue;
00180       s = pool->solvables + p;
00181       if (s->recommends)
00182         {
00183           recp = s->repo->idarraydata + s->recommends;
00184           while ((rec = *recp++) != 0)
00185             FOR_PROVIDES(p, pp, rec)
00186               MAPSET(&solv->recommendsmap, p);
00187         }
00188       if (s->suggests)
00189         {
00190           sugp = s->repo->idarraydata + s->suggests;
00191           while ((sug = *sugp++) != 0)
00192             FOR_PROVIDES(p, pp, sug)
00193               MAPSET(&solv->suggestsmap, p);
00194         }
00195     }
00196 
00197   /* prune to recommended/supplemented */
00198   ninst = 0;
00199   for (i = j = 0; i < plist->count; i++)
00200     {
00201       p = plist->elements[i];
00202       s = pool->solvables + p;
00203       if (pool->installed && s->repo == pool->installed)
00204         {
00205           ninst++;
00206           if (j)
00207             plist->elements[j++] = p;
00208           continue;
00209         }
00210       if (!MAPTST(&solv->recommendsmap, p))
00211         if (!solver_is_supplementing(solv, s))
00212           continue;
00213       if (!j && ninst)
00214         {
00215           for (k = 0; j < ninst; k++)
00216             {
00217               s = pool->solvables + plist->elements[k];
00218               if (pool->installed && s->repo == pool->installed)
00219                 plist->elements[j++] = plist->elements[k];
00220             }
00221         }
00222       plist->elements[j++] = p;
00223     }
00224   if (j)
00225     plist->count = j;
00226 
00227   /* anything left to prune? */
00228   if (plist->count - ninst < 2)
00229     return;
00230 
00231   /* prune to suggested/enhanced*/
00232   ninst = 0;
00233   for (i = j = 0; i < plist->count; i++)
00234     {
00235       p = plist->elements[i];
00236       s = pool->solvables + p;
00237       if (pool->installed && s->repo == pool->installed)
00238         {
00239           ninst++;
00240           if (j)
00241             plist->elements[j++] = p;
00242           continue;
00243         }
00244       if (!MAPTST(&solv->suggestsmap, p))
00245         if (!solver_is_enhancing(solv, s))
00246           continue;
00247       if (!j && ninst)
00248         {
00249           for (k = 0; j < ninst; k++)
00250             {
00251               s = pool->solvables + plist->elements[k];
00252               if (pool->installed && s->repo == pool->installed)
00253                 plist->elements[j++] = plist->elements[k];
00254             }
00255         }
00256       plist->elements[j++] = p;
00257     }
00258   if (j)
00259     plist->count = j;
00260 }
00261 
00262 void
00263 prune_to_best_arch(const Pool *pool, Queue *plist)
00264 {
00265   Id a, bestscore;
00266   Solvable *s;
00267   int i, j;
00268 
00269   if (!pool->id2arch || plist->count < 2)
00270     return;
00271   bestscore = 0;
00272   for (i = 0; i < plist->count; i++)
00273     {
00274       s = pool->solvables + plist->elements[i];
00275       a = s->arch;
00276       a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
00277       if (a && a != 1 && (!bestscore || a < bestscore))
00278         bestscore = a;
00279     }
00280   for (i = j = 0; i < plist->count; i++)
00281     {
00282       s = pool->solvables + plist->elements[i];
00283       a = s->arch;
00284       if (a > pool->lastarch)
00285         continue;
00286       a = pool->id2arch[a];
00287       /* a == 1 -> noarch */
00288       if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
00289         continue;
00290       plist->elements[j++] = plist->elements[i];
00291     }
00292   if (j)
00293     plist->count = j;
00294 }
00295 
00296 /*
00297  * remove entries from plist that are obsoleted by other entries
00298  * with different name.
00299  * plist should be sorted in some way.
00300  */
00301 static void
00302 prune_obsoleted(Pool *pool, Queue *plist)
00303 {
00304   int i, j;
00305   Solvable *s;
00306 
00307   /* FIXME maybe also check provides depending on noupdateprovide? */
00308   /* FIXME do not prune cycles */
00309   for (i = 0; i < plist->count; i++)
00310     {
00311       Id p, pp, obs, *obsp;
00312       s = pool->solvables + plist->elements[i];
00313       if (!s->obsoletes)
00314         continue;
00315       obsp = s->repo->idarraydata + s->obsoletes;
00316       while ((obs = *obsp++) != 0)
00317         {
00318           FOR_PROVIDES(p, pp, obs)
00319             {
00320               Solvable *ps = pool->solvables + p;
00321               if (ps->name == s->name)
00322                 continue;
00323               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00324                 continue;
00325               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00326                 continue;
00327               /* hmm, expensive. should use hash if plist is big */
00328               for (j = 0; j < plist->count; j++)
00329                 {
00330                   if (i == j)
00331                     continue;
00332                   if (plist->elements[j] == p)
00333                     plist->elements[j] = 0;
00334                 }
00335             }
00336         }
00337     }
00338   /* delete zeroed out queue entries */
00339   for (i = j = 0; i < plist->count; i++)
00340     if (plist->elements[i])
00341       plist->elements[j++] = plist->elements[i];
00342   plist->count = j;
00343 }
00344 
00345 /*
00346  * prune_to_best_version
00347  *
00348  * sort list of packages (given through plist) by name and evr
00349  * return result through plist
00350  */
00351 void
00352 prune_to_best_version(Pool *pool, Queue *plist)
00353 {
00354   int i, j;
00355   Solvable *s, *best;
00356 
00357   if (plist->count < 2)         /* no need to prune for a single entry */
00358     return;
00359   POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
00360 
00361   /* sort by name first, prefer installed */
00362   sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
00363 
00364   /* now find best 'per name' */
00365   best = 0;
00366   for (i = j = 0; i < plist->count; i++)
00367     {
00368       s = pool->solvables + plist->elements[i];
00369 
00370       POOL_DEBUG(SAT_DEBUG_POLICY, "- %s[%s]\n",
00371                  solvable2str(pool, s),
00372                  (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
00373 
00374       if (!best)                /* if no best yet, the current is best */
00375         {
00376           best = s;
00377           continue;
00378         }
00379 
00380       /* name switch: finish group, re-init */
00381       if (best->name != s->name)   /* new name */
00382         {
00383           plist->elements[j++] = best - pool->solvables; /* move old best to front */
00384           best = s;             /* take current as new best */
00385           continue;
00386         }
00387 
00388       if (best->evr != s->evr)  /* compare evr */
00389         {
00390           if (evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) < 0)
00391             best = s;
00392         }
00393     }
00394   plist->elements[j++] = best - pool->solvables;        /* finish last group */
00395   plist->count = j;
00396 
00397   /* we reduced the list to one package per name, now look at
00398    * package obsoletes */
00399   if (plist->count > 1)
00400     prune_obsoleted(pool, plist);
00401 }
00402 
00403 
00404 /* legacy, do not use anymore!
00405  * (rates arch higher than version, but thats a policy)
00406  */
00407 
00408 void
00409 prune_best_arch_name_version(const Solver *solv, Pool *pool, Queue *plist)
00410 {
00411   if (solv && solv->bestSolvableCb)
00412     { /* The application is responsible for */
00413       return solv->bestSolvableCb(solv->pool, plist);
00414     }
00415 
00416   if (plist->count > 1)
00417     prune_to_best_arch(pool, plist);
00418   if (plist->count > 1)
00419     prune_to_best_version(pool, plist);
00420 }
00421 
00422 /* installed packages involed in a dup operation can only be kept
00423 * if they are identical to a non-installed one */
00424 static void
00425 prune_installed_dup_packages(Solver *solv, Queue *plist)
00426 {
00427   Pool *pool = solv->pool;
00428   int i, j, k;
00429 
00430   for (i = j = 0; i < plist->count; i++)
00431     {
00432       Id p = plist->elements[i];
00433       Solvable *s = pool->solvables + p;
00434       if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
00435         {
00436           for (k = 0; k < plist->count; k++)
00437             {
00438               Solvable *s2 = pool->solvables + plist->elements[k];
00439               if (s2->repo != pool->installed && solvable_identical(s, s2))
00440                 break;
00441             }
00442           if (k == plist->count)
00443             continue;   /* no identical package found, ignore installed package */
00444         }
00445       plist->elements[j++] = p;
00446     }
00447   if (j)
00448     plist->count = j;
00449 }
00450 
00451 /*
00452  *  POLICY_MODE_CHOOSE:     default, do all pruning steps
00453  *  POLICY_MODE_RECOMMEND:  leave out prune_to_recommended
00454  *  POLICY_MODE_SUGGEST:    leave out prune_to_recommended, do prio pruning just per name
00455  */
00456 void
00457 policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
00458 {
00459   Pool *pool = solv->pool;
00460   if (plist->count > 1)
00461     {
00462       if (mode != POLICY_MODE_SUGGEST)
00463         prune_to_highest_prio(pool, plist);
00464       else
00465         prune_to_highest_prio_per_name(pool, plist);
00466       /* installed dup packages need special treatment as prio pruning
00467        * does not prune installed packages */
00468       if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
00469         prune_installed_dup_packages(solv, plist);
00470     }
00471   if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
00472     prune_to_recommended(solv, plist);
00473   prune_best_arch_name_version(solv, pool, plist);
00474 }
00475 
00476 
00477 int
00478 policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
00479 {
00480   Pool *pool = solv->pool;
00481   Id a1 = s1->arch, a2 = s2->arch;
00482 
00483   if (solv && solv->archCheckCb)
00484     { /* The application is responsible for */
00485       return solv->archCheckCb(solv->pool, s1, s2);
00486     }
00487 
00488   /* we allow changes to/from noarch */
00489 #ifndef DEBIAN_SEMANTICS
00490   if (a1 == a2 || a1 == ARCH_NOARCH || a2 == ARCH_NOARCH)
00491     return 0;
00492 #else
00493   if (a1 == a2 || a1 == ARCH_ALL || a2 == ARCH_ALL)
00494     return 0;
00495 #endif
00496   if (!pool->id2arch)
00497     return 0;
00498   a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
00499   a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
00500   if (((a1 ^ a2) & 0xffff0000) != 0)
00501     return 1;
00502   return 0;
00503 }
00504 
00505 int
00506 policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
00507 {
00508   Pool *pool = solv->pool;
00509   Id v1, v2;
00510   Id vendormask1, vendormask2;
00511 
00512   if (solv->vendorCheckCb)
00513    {   /* The application is responsible for */
00514      return solv->vendorCheckCb(pool, s1, s2);
00515    }
00516   /* treat a missing vendor as empty string */
00517   v1 = s1->vendor ? s1->vendor : ID_EMPTY;
00518   v2 = s2->vendor ? s2->vendor : ID_EMPTY;
00519   if (v1 == v2)
00520     return 0;
00521   vendormask1 = pool_vendor2mask(pool, v1);
00522   if (!vendormask1)
00523     return 1;   /* can't match */
00524   vendormask2 = pool_vendor2mask(pool, v2);
00525   if ((vendormask1 & vendormask2) != 0)
00526     return 0;
00527   return 1;     /* no class matches */
00528 }
00529 
00530 /* check if it is illegal to replace installed
00531  * package "is" with package "s" (which must obsolete "is")
00532  */
00533 int
00534 policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
00535 {
00536   Pool *pool = solv->pool;
00537   int ret = 0;
00538   if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !solv->allowdowngrade)
00539     {
00540       if (is->name == s->name && evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
00541         ret |= POLICY_ILLEGAL_DOWNGRADE;
00542     }
00543   if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !solv->allowarchchange)
00544     {
00545       if (is->arch != s->arch && policy_illegal_archchange(solv, s, is))
00546         ret |= POLICY_ILLEGAL_ARCHCHANGE;
00547     }
00548   if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !solv->allowvendorchange)
00549     {
00550       if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, s, is))
00551         ret |= POLICY_ILLEGAL_VENDORCHANGE;
00552     }
00553   return ret;
00554 }
00555 
00556 /*-------------------------------------------------------------------
00557  * 
00558  * create reverse obsoletes map for installed solvables
00559  *
00560  * For each installed solvable find which packages with *different* names
00561  * obsolete the solvable.
00562  * This index is used in policy_findupdatepackages() below.
00563  */
00564 void
00565 policy_create_obsolete_index(Solver *solv)
00566 {
00567   Pool *pool = solv->pool;
00568   Solvable *s;
00569   Repo *installed = solv->installed;
00570   Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
00571   int i, n, cnt;
00572 
00573   if (!installed || installed->start == installed->end)
00574     return;
00575   cnt = installed->end - installed->start;
00576   solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
00577   for (i = 1; i < pool->nsolvables; i++)
00578     {
00579       s = pool->solvables + i;
00580       if (!s->obsoletes)
00581         continue;
00582       if (!pool_installable(pool, s))
00583         continue;
00584       obsp = s->repo->idarraydata + s->obsoletes;
00585       while ((obs = *obsp++) != 0)
00586         {
00587           FOR_PROVIDES(p, pp, obs)
00588             {
00589               Solvable *ps = pool->solvables + p;;
00590               if (ps->repo != installed)
00591                 continue;
00592               if (ps->name == s->name)
00593                 continue;
00594               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00595                 continue;
00596               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00597                 continue;
00598               obsoletes[p - installed->start]++;
00599             }
00600         }
00601     }
00602   n = 0;
00603   for (i = 0; i < cnt; i++)
00604     if (obsoletes[i])
00605       {
00606         n += obsoletes[i] + 1;
00607         obsoletes[i] = n;
00608       }
00609   solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
00610   POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
00611   for (i = pool->nsolvables - 1; i > 0; i--)
00612     {
00613       s = pool->solvables + i;
00614       if (!s->obsoletes)
00615         continue;
00616       if (!pool_installable(pool, s))
00617         continue;
00618       obsp = s->repo->idarraydata + s->obsoletes;
00619       while ((obs = *obsp++) != 0)
00620         {
00621           FOR_PROVIDES(p, pp, obs)
00622             {
00623               Solvable *ps = pool->solvables + p;;
00624               if (ps->repo != installed)
00625                 continue;
00626               if (ps->name == s->name)
00627                 continue;
00628               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00629                 continue;
00630               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00631                 continue;
00632               if (obsoletes_data[obsoletes[p - installed->start]] != i)
00633                 obsoletes_data[--obsoletes[p - installed->start]] = i;
00634             }
00635         }
00636     }
00637 }
00638 
00639 
00640 /*
00641  * find update candidates
00642  * 
00643  * s: solvable to be updated
00644  * qs: [out] queue to hold Ids of candidates
00645  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
00646  * 
00647  */
00648 void
00649 policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
00650 {
00651   /* installed packages get a special upgrade allowed rule */
00652   Pool *pool = solv->pool;
00653   Id p, pp, n, p2, pp2;
00654   Id obs, *obsp;
00655   Solvable *ps;
00656   int haveprovobs = 0;
00657 
00658   queue_empty(qs);
00659 
00660   if (solv && solv->updateCandidateCb)
00661     { /* The application is responsible for */
00662       return solv->updateCandidateCb(solv->pool, s, qs);
00663     }
00664 
00665   /*
00666    * s = solvable ptr
00667    * n = solvable Id
00668    */
00669   n = s - pool->solvables;
00670 
00671   /*
00672    * look for updates for s
00673    */
00674   FOR_PROVIDES(p, pp, s->name)  /* every provider of s' name */
00675     {
00676       if (p == n)               /* skip itself */
00677         continue;
00678 
00679       ps = pool->solvables + p;
00680       if (s->name == ps->name)  /* name match */
00681         {
00682           if (!allow_all && !solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
00683             continue;
00684         }
00685       else if (!solv->noupdateprovide && ps->obsoletes)   /* provides/obsoletes combination ? */
00686         {
00687           obsp = ps->repo->idarraydata + ps->obsoletes;
00688           while ((obs = *obsp++) != 0)  /* for all obsoletes */
00689             {
00690               FOR_PROVIDES(p2, pp2, obs)   /* and all matching providers of the obsoletes */
00691                 {
00692                   Solvable *ps2 = pool->solvables + p2;
00693                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
00694                     continue;
00695                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps2))
00696                     continue;
00697                   if (p2 == n)          /* match ! */
00698                     break;
00699                 }
00700               if (p2)                   /* match! */
00701                 break;
00702             }
00703           if (!obs)                     /* continue if no match */
00704             continue;
00705           /* here we have 'p' with a matching provides/obsoletes combination
00706            * thus flagging p as a valid update candidate for s
00707            */
00708           haveprovobs = 1;
00709         }
00710       else
00711         continue;
00712       if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00713         continue;
00714       if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00715         continue;
00716       queue_push(qs, p);
00717     }
00718   /* if we have found some valid candidates and noupdateprovide is not set, we're
00719      done. otherwise we fallback to all obsoletes */
00720   if (!solv->noupdateprovide && haveprovobs)
00721     return;
00722   if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
00723     {
00724       Id *opp;
00725       for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
00726         {
00727           ps = pool->solvables + p;
00728           if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00729             continue;
00730           if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00731             continue;
00732           queue_push(qs, p);
00733         }
00734     }
00735 }
00736