rules.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (c) 2007-2009, Novell Inc.
00003  *
00004  * This program is licensed under the BSD license, read LICENSE.BSD
00005  * for further information
00006  */
00007 
00008 /*
00009  * rules.c
00010  *
00011  * SAT based dependency solver
00012  */
00013 
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <unistd.h>
00017 #include <string.h>
00018 #include <assert.h>
00019 
00020 #include "solver.h"
00021 #include "bitmap.h"
00022 #include "pool.h"
00023 #include "poolarch.h"
00024 #include "util.h"
00025 #include "evr.h"
00026 #include "policy.h"
00027 #include "solverdebug.h"
00028 
00029 #define RULES_BLOCK 63
00030 
00031 static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
00032 static void solver_createcleandepsmap(Solver *solv);
00033 
00034 /*-------------------------------------------------------------------
00035  * Check if dependency is possible
00036  * 
00037  * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap
00038  * used in solver_addrpmrulesforweak and solver_createcleandepsmap
00039  */
00040 
00041 static inline int
00042 dep_possible(Solver *solv, Id dep, Map *m)
00043 {
00044   Pool *pool = solv->pool;
00045   Id p, pp;
00046 
00047   if (ISRELDEP(dep))
00048     {
00049       Reldep *rd = GETRELDEP(pool, dep);
00050       if (rd->flags >= 8)
00051         {
00052           if (rd->flags == REL_AND)
00053             {
00054               if (!dep_possible(solv, rd->name, m))
00055                 return 0;
00056               return dep_possible(solv, rd->evr, m);
00057             }
00058           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
00059             return solver_splitprovides(solv, rd->evr);
00060           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
00061             return solver_dep_installed(solv, rd->evr);
00062         }
00063     }
00064   FOR_PROVIDES(p, pp, dep)
00065     {
00066       if (MAPTST(m, p))
00067         return 1;
00068     }
00069   return 0;
00070 }
00071 
00072 /********************************************************************
00073  *
00074  * Rule handling
00075  *
00076  * - unify rules, remove duplicates
00077  */
00078 
00079 /*-------------------------------------------------------------------
00080  *
00081  * compare rules for unification sort
00082  *
00083  */
00084 
00085 static int
00086 unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
00087 {
00088   Pool *pool = dp;
00089   Rule *a = (Rule *)ap;
00090   Rule *b = (Rule *)bp;
00091   Id *ad, *bd;
00092   int x;
00093 
00094   x = a->p - b->p;
00095   if (x)
00096     return x;                          /* p differs */
00097 
00098   /* identical p */
00099   if (a->d == 0 && b->d == 0)
00100     return a->w2 - b->w2;              /* assertion: return w2 diff */
00101 
00102   if (a->d == 0)                       /* a is assertion, b not */
00103     {
00104       x = a->w2 - pool->whatprovidesdata[b->d];
00105       return x ? x : -1;
00106     }
00107 
00108   if (b->d == 0)                       /* b is assertion, a not */
00109     {
00110       x = pool->whatprovidesdata[a->d] - b->w2;
00111       return x ? x : 1;
00112     }
00113 
00114   /* compare whatprovidesdata */
00115   ad = pool->whatprovidesdata + a->d;
00116   bd = pool->whatprovidesdata + b->d;
00117   while (*bd)
00118     if ((x = *ad++ - *bd++) != 0)
00119       return x;
00120   return *ad;
00121 }
00122 
00123 int
00124 solver_samerule(Solver *solv, Rule *r1, Rule *r2)
00125 {
00126   return unifyrules_sortcmp(r1, r2, solv->pool);
00127 }
00128 
00129 
00130 /*-------------------------------------------------------------------
00131  *
00132  * unify rules
00133  * go over all rules and remove duplicates
00134  */
00135 
00136 void
00137 solver_unifyrules(Solver *solv)
00138 {
00139   Pool *pool = solv->pool;
00140   int i, j;
00141   Rule *ir, *jr;
00142 
00143   if (solv->nrules <= 2)               /* nothing to unify */
00144     return;
00145 
00146   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
00147 
00148   /* sort rules first */
00149   sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
00150 
00151   /* prune rules
00152    * i = unpruned
00153    * j = pruned
00154    */
00155   jr = 0;
00156   for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
00157     {
00158       if (jr && !unifyrules_sortcmp(ir, jr, pool))
00159         continue;                      /* prune! */
00160       jr = solv->rules + j++;          /* keep! */
00161       if (ir != jr)
00162         *jr = *ir;
00163     }
00164 
00165   /* reduced count from nrules to j rules */
00166   POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
00167 
00168   /* adapt rule buffer */
00169   solv->nrules = j;
00170   solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
00171 
00172   /*
00173    * debug: log rule statistics
00174    */
00175   IF_POOLDEBUG (SAT_DEBUG_STATS)
00176     {
00177       int binr = 0;
00178       int lits = 0;
00179       Id *dp;
00180       Rule *r;
00181 
00182       for (i = 1; i < solv->nrules; i++)
00183         {
00184           r = solv->rules + i;
00185           if (r->d == 0)
00186             binr++;
00187           else
00188             {
00189               dp = solv->pool->whatprovidesdata + r->d;
00190               while (*dp++)
00191                 lits++;
00192             }
00193         }
00194       POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
00195       POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
00196     }
00197   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
00198 }
00199 
00200 #if 0
00201 
00202 /*
00203  * hash rule
00204  */
00205 
00206 static Hashval
00207 hashrule(Solver *solv, Id p, Id d, int n)
00208 {
00209   unsigned int x = (unsigned int)p;
00210   int *dp;
00211 
00212   if (n <= 1)
00213     return (x * 37) ^ (unsigned int)d;
00214   dp = solv->pool->whatprovidesdata + d;
00215   while (*dp)
00216     x = (x * 37) ^ (unsigned int)*dp++;
00217   return x;
00218 }
00219 #endif
00220 
00221 
00222 /*-------------------------------------------------------------------
00223  * 
00224  */
00225 
00226 /*
00227  * add rule
00228  *  p = direct literal; always < 0 for installed rpm rules
00229  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
00230  *
00231  *
00232  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
00233  *
00234  * p < 0 : pkg id of A
00235  * d > 0 : Offset in whatprovidesdata (list of providers of b)
00236  *
00237  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
00238  * p < 0 : pkg id of A
00239  * d < 0 : Id of solvable (e.g. B1)
00240  *
00241  * d == 0: unary rule, assertion => (A) or (-A)
00242  *
00243  *   Install:    p > 0, d = 0   (A)             user requested install
00244  *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
00245  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
00246  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
00247  *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
00248  *                                              also used for obsoletes
00249  *   ?:          p > 0, d < 0   (A|-B)          
00250  *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
00251  *
00252  *   resulting watches:
00253  *   ------------------
00254  *   Direct assertion (no watch needed) --> d = 0, w1 = p, w2 = 0
00255  *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
00256  *   every other : w1 = p, w2 = whatprovidesdata[d];
00257  *   Disabled rule: w1 = 0
00258  *
00259  *   always returns a rule for non-rpm rules
00260  */
00261 
00262 Rule *
00263 solver_addrule(Solver *solv, Id p, Id d)
00264 {
00265   Pool *pool = solv->pool;
00266   Rule *r = 0;
00267   Id *dp = 0;
00268 
00269   int n = 0;                           /* number of literals in rule - 1
00270                                           0 = direct assertion (single literal)
00271                                           1 = binary rule
00272                                           >1 = 
00273                                         */
00274 
00275   /* it often happenes that requires lead to adding the same rpm rule
00276    * multiple times, so we prune those duplicates right away to make
00277    * the work for unifyrules a bit easier */
00278 
00279   if (!solv->rpmrules_end)              /* we add rpm rules */
00280     {
00281       r = solv->rules + solv->nrules - 1;       /* get the last added rule */
00282       if (r->p == p && r->d == d && (d != 0 || !r->w2))
00283         return r;
00284     }
00285 
00286     /*
00287      * compute number of literals (n) in rule
00288      */
00289     
00290   if (d < 0)
00291     {
00292       /* always a binary rule */
00293       if (p == d)
00294         return 0;                      /* ignore self conflict */
00295       n = 1;
00296     }
00297   else if (d > 0)
00298     {
00299       for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
00300         if (*dp == -p)
00301           return 0;                     /* rule is self-fulfilling */
00302         
00303       if (n == 1)                       /* convert to binary rule */
00304         d = dp[-1];
00305     }
00306 
00307   if (n == 1 && p > d && !solv->rpmrules_end)
00308     {
00309       /* smallest literal first so we can find dups */
00310       n = p; p = d; d = n;             /* p <-> d */
00311       n = 1;                           /* re-set n, was used as temp var */
00312     }
00313 
00314   /*
00315    * check for duplicate
00316    */
00317     
00318   /* check if the last added rule (r) is exactly the same as what we're looking for. */
00319   if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
00320     return r;  /* binary rule */
00321 
00322     /* have n-ary rule with same first literal, check other literals */
00323   if (r && n > 1 && r->d && r->p == p)
00324     {
00325       /* Rule where d is an offset in whatprovidesdata */
00326       Id *dp2;
00327       if (d == r->d)
00328         return r;
00329       dp2 = pool->whatprovidesdata + r->d;
00330       for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
00331         if (*dp != *dp2)
00332           break;
00333       if (*dp == *dp2)
00334         return r;
00335    }
00336 
00337   /*
00338    * allocate new rule
00339    */
00340 
00341   /* extend rule buffer */
00342   solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
00343   r = solv->rules + solv->nrules++;    /* point to rule space */
00344 
00345     /*
00346      * r = new rule
00347      */
00348     
00349   r->p = p;
00350   if (n == 0)
00351     {
00352       /* direct assertion, no watch needed */
00353       r->d = 0;
00354       r->w1 = p;
00355       r->w2 = 0;
00356     }
00357   else if (n == 1)
00358     {
00359       /* binary rule */
00360       r->d = 0;
00361       r->w1 = p;
00362       r->w2 = d;
00363     }
00364   else
00365     {
00366       r->d = d;
00367       r->w1 = p;
00368       r->w2 = pool->whatprovidesdata[d];
00369     }
00370   r->n1 = 0;
00371   r->n2 = 0;
00372 
00373   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
00374     {
00375       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
00376       solver_printrule(solv, SAT_DEBUG_RULE_CREATION, r);
00377     }
00378 
00379   return r;
00380 }
00381 
00382 
00383 /******************************************************************************
00384  ***
00385  *** rpm rule part: create rules representing the package dependencies
00386  ***
00387  ***/
00388 
00389 /*
00390  *  special multiversion patch conflict handling:
00391  *  a patch conflict is also satisfied if some other
00392  *  version with the same name/arch that doesn't conflict
00393  *  gets installed. The generated rule is thus:
00394  *  -patch|-cpack|opack1|opack2|...
00395  */
00396 static Id
00397 makemultiversionconflict(Solver *solv, Id n, Id con)
00398 {
00399   Pool *pool = solv->pool;
00400   Solvable *s, *sn;
00401   Queue q;
00402   Id p, pp, qbuf[64];
00403 
00404   sn = pool->solvables + n;
00405   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
00406   queue_push(&q, -n);
00407   FOR_PROVIDES(p, pp, sn->name)
00408     {
00409       s = pool->solvables + p;
00410       if (s->name != sn->name || s->arch != sn->arch)
00411         continue;
00412       if (!MAPTST(&solv->noobsoletes, p))
00413         continue;
00414       if (pool_match_nevr(pool, pool->solvables + p, con))
00415         continue;
00416       /* here we have a multiversion solvable that doesn't conflict */
00417       /* thus we're not in conflict if it is installed */
00418       queue_push(&q, p);
00419     }
00420   if (q.count == 1)
00421     return -n;  /* no other package found, generate normal conflict */
00422   return pool_queuetowhatprovides(pool, &q);
00423 }
00424 
00425 static inline void
00426 addrpmrule(Solver *solv, Id p, Id d, int type, Id dep)
00427 {
00428   if (!solv->ruleinfoq)
00429     solver_addrule(solv, p, d);
00430   else
00431     addrpmruleinfo(solv, p, d, type, dep);
00432 }
00433 
00434 /*-------------------------------------------------------------------
00435  * 
00436  * add (install) rules for solvable
00437  * 
00438  * s: Solvable for which to add rules
00439  * m: m[s] = 1 for solvables which have rules, prevent rule duplication
00440  * 
00441  * Algorithm: 'visit all nodes of a graph'. The graph nodes are
00442  *  solvables, the edges their dependencies.
00443  *  Starting from an installed solvable, this will create all rules
00444  *  representing the graph created by the solvables dependencies.
00445  * 
00446  * for unfulfilled requirements, conflicts, obsoletes,....
00447  * add a negative assertion for solvables that are not installable
00448  * 
00449  * It will also create rules for all solvables referenced by 's'
00450  *  i.e. descend to all providers of requirements of 's'
00451  *
00452  */
00453 
00454 void
00455 solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
00456 {
00457   Pool *pool = solv->pool;
00458   Repo *installed = solv->installed;
00459 
00460   /* 'work' queue. keeps Ids of solvables we still have to work on.
00461      And buffer for it. */
00462   Queue workq;
00463   Id workqbuf[64];
00464     
00465   int i;
00466     /* if to add rules for broken deps ('rpm -V' functionality)
00467      * 0 = yes, 1 = no
00468      */
00469   int dontfix;
00470     /* Id var and pointer for each dependency
00471      * (not used in parallel)
00472      */
00473   Id req, *reqp;
00474   Id con, *conp;
00475   Id obs, *obsp;
00476   Id rec, *recp;
00477   Id sug, *sugp;
00478   Id p, pp;             /* whatprovides loops */
00479   Id *dp;               /* ptr to 'whatprovides' */
00480   Id n;                 /* Id for current solvable 's' */
00481 
00482   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
00483 
00484   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
00485   queue_push(&workq, s - pool->solvables);      /* push solvable Id to work queue */
00486 
00487   /* loop until there's no more work left */
00488   while (workq.count)
00489     {
00490       /*
00491        * n: Id of solvable
00492        * s: Pointer to solvable
00493        */
00494 
00495       n = queue_shift(&workq);          /* 'pop' next solvable to work on from queue */
00496       if (m)
00497         {
00498           if (MAPTST(m, n))             /* continue if already visited */
00499             continue;
00500           MAPSET(m, n);                 /* mark as visited */
00501         }
00502 
00503       s = pool->solvables + n;          /* s = Solvable in question */
00504 
00505       dontfix = 0;
00506       if (installed                     /* Installed system available */
00507           && s->repo == installed       /* solvable is installed */
00508           && !solv->fixmap_all          /* NOT repair errors in rpm dependency graph */
00509           && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
00510         {
00511           dontfix = 1;                  /* dont care about broken rpm deps */
00512         }
00513 
00514       if (!dontfix
00515           && s->arch != ARCH_SRC
00516           && s->arch != ARCH_NOSRC
00517           && !pool_installable(pool, s))
00518         {
00519           POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
00520           addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOT_INSTALLABLE, 0);
00521         }
00522 
00523       /* yet another SUSE hack, sigh */
00524       if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
00525         {
00526           Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
00527           if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
00528             {
00529               addrpmrule(solv, n, -buddy, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + n));
00530               addrpmrule(solv, buddy, -n, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + buddy)); 
00531               if (m && !MAPTST(m, buddy))
00532                 queue_push(&workq, buddy);
00533             }
00534         }
00535 
00536       /*-----------------------------------------
00537        * check requires of s
00538        */
00539 
00540       if (s->requires)
00541         {
00542           reqp = s->repo->idarraydata + s->requires;
00543           while ((req = *reqp++) != 0)            /* go through all requires */
00544             {
00545               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
00546                 continue;
00547 
00548               /* find list of solvables providing 'req' */
00549               dp = pool_whatprovides_ptr(pool, req);
00550 
00551               if (*dp == SYSTEMSOLVABLE)          /* always installed */
00552                 continue;
00553 
00554               if (dontfix)
00555                 {
00556                   /* the strategy here is to not insist on dependencies
00557                    * that are already broken. so if we find one provider
00558                    * that was already installed, we know that the
00559                    * dependency was not broken before so we enforce it */
00560                  
00561                   /* check if any of the providers for 'req' is installed */
00562                   for (i = 0; (p = dp[i]) != 0; i++)
00563                     {
00564                       if (pool->solvables[p].repo == installed)
00565                         break;          /* provider was installed */
00566                     }
00567                   /* didn't find an installed provider: previously broken dependency */
00568                   if (!p)
00569                     {
00570                       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
00571                       continue;
00572                     }
00573                 }
00574 
00575               if (!*dp)
00576                 {
00577                   /* nothing provides req! */
00578                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
00579                   addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, req);
00580                   continue;
00581                 }
00582 
00583               IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
00584                 {
00585                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
00586                   for (i = 0; dp[i]; i++)
00587                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvid2str(pool, dp[i]));
00588                 }
00589 
00590               /* add 'requires' dependency */
00591               /* rule: (-requestor|provider1|provider2|...|providerN) */
00592               addrpmrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
00593 
00594               /* descend the dependency tree
00595                  push all non-visited providers on the work queue */
00596               if (m)
00597                 {
00598                   for (; *dp; dp++)
00599                     {
00600                       if (!MAPTST(m, *dp))
00601                         queue_push(&workq, *dp);
00602                     }
00603                 }
00604 
00605             } /* while, requirements of n */
00606 
00607         } /* if, requirements */
00608 
00609       /* that's all we check for src packages */
00610       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
00611         continue;
00612 
00613       /*-----------------------------------------
00614        * check conflicts of s
00615        */
00616 
00617       if (s->conflicts)
00618         {
00619           int ispatch = 0;
00620 
00621           /* we treat conflicts in patches a bit differen:
00622            * - nevr matching
00623            * - multiversion handling
00624            * XXX: we should really handle this different, looking
00625            * at the name is a bad hack
00626            */
00627           if (!strncmp("patch:", id2str(pool, s->name), 6))
00628             ispatch = 1;
00629           conp = s->repo->idarraydata + s->conflicts;
00630           /* foreach conflicts of 's' */
00631           while ((con = *conp++) != 0)
00632             {
00633               /* foreach providers of a conflict of 's' */
00634               FOR_PROVIDES(p, pp, con)
00635                 {
00636                   if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
00637                     continue;
00638                   /* dontfix: dont care about conflicts with already installed packs */
00639                   if (dontfix && pool->solvables[p].repo == installed)
00640                     continue;
00641                   /* p == n: self conflict */
00642                   if (p == n && !pool->allowselfconflicts)
00643                     {
00644                       if (ISRELDEP(con))
00645                         {
00646                           Reldep *rd = GETRELDEP(pool, con);
00647                           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
00648                             continue;
00649                         }
00650                       p = 0;    /* make it a negative assertion, aka 'uninstallable' */
00651                     }
00652                   if (p && ispatch && solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p) && ISRELDEP(con))
00653                     {
00654                       /* our patch conflicts with a noobsoletes (aka multiversion) package */
00655                       p = -makemultiversionconflict(solv, p, con);
00656                     }
00657                  /* rule: -n|-p: either solvable _or_ provider of conflict */
00658                   addrpmrule(solv, -n, -p, p ? SOLVER_RULE_RPM_PACKAGE_CONFLICT : SOLVER_RULE_RPM_SELF_CONFLICT, con);
00659                 }
00660             }
00661         }
00662 
00663       /*-----------------------------------------
00664        * check obsoletes and implicit obsoletes of a package
00665        * if ignoreinstalledsobsoletes is not set, we're also checking
00666        * obsoletes of installed packages (like newer rpm versions)
00667        */
00668       if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
00669         {
00670           int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
00671           int isinstalled = (installed && s->repo == installed);
00672           if (s->obsoletes && !noobs)
00673             {
00674               obsp = s->repo->idarraydata + s->obsoletes;
00675               /* foreach obsoletes */
00676               while ((obs = *obsp++) != 0)
00677                 {
00678                   /* foreach provider of an obsoletes of 's' */ 
00679                   FOR_PROVIDES(p, pp, obs)
00680                     {
00681                       Solvable *ps = pool->solvables + p;
00682                       if (p == n)
00683                         continue;
00684                       if (isinstalled && dontfix && ps->repo == installed)
00685                         continue;       /* don't repair installed/installed problems */
00686                       if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
00687                           && !pool_match_nevr(pool, ps, obs))
00688                         continue;
00689                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00690                         continue;
00691                       if (!isinstalled)
00692                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
00693                       else
00694                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES, obs);
00695                     }
00696                 }
00697             }
00698           /* check implicit obsoletes
00699            * for installed packages we only need to check installed/installed problems (and
00700            * only when dontfix is not set), as the others are picked up when looking at the
00701            * uninstalled package.
00702            */
00703           if (!isinstalled || !dontfix)
00704             {
00705               FOR_PROVIDES(p, pp, s->name)
00706                 {
00707                   Solvable *ps = pool->solvables + p;
00708                   if (p == n)
00709                     continue;
00710                   if (isinstalled && ps->repo != installed)
00711                     continue;
00712                   /* we still obsolete packages with same nevra, like rpm does */
00713                   /* (actually, rpm mixes those packages. yuck...) */
00714                   if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
00715                     continue;
00716                   if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
00717                     continue;
00718                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00719                     continue;
00720                   if (s->name == ps->name)
00721                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
00722                   else
00723                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
00724                 }
00725             }
00726         }
00727 
00728       /*-----------------------------------------
00729        * add recommends to the work queue
00730        */
00731       if (s->recommends && m)
00732         {
00733           recp = s->repo->idarraydata + s->recommends;
00734           while ((rec = *recp++) != 0)
00735             {
00736               FOR_PROVIDES(p, pp, rec)
00737                 if (!MAPTST(m, p))
00738                   queue_push(&workq, p);
00739             }
00740         }
00741       if (s->suggests && m)
00742         {
00743           sugp = s->repo->idarraydata + s->suggests;
00744           while ((sug = *sugp++) != 0)
00745             {
00746               FOR_PROVIDES(p, pp, sug)
00747                 if (!MAPTST(m, p))
00748                   queue_push(&workq, p);
00749             }
00750         }
00751     }
00752   queue_free(&workq);
00753   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
00754 }
00755 
00756 
00757 /*-------------------------------------------------------------------
00758  * 
00759  * Add rules for packages possibly selected in by weak dependencies
00760  *
00761  * m: already added solvables
00762  */
00763 
00764 void
00765 solver_addrpmrulesforweak(Solver *solv, Map *m)
00766 {
00767   Pool *pool = solv->pool;
00768   Solvable *s;
00769   Id sup, *supp;
00770   int i, n;
00771 
00772   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
00773   /* foreach solvable in pool */
00774   for (i = n = 1; n < pool->nsolvables; i++, n++)
00775     {
00776       if (i == pool->nsolvables)                /* wrap i */
00777         i = 1;
00778       if (MAPTST(m, i))                         /* already added that one */
00779         continue;
00780 
00781       s = pool->solvables + i;
00782       if (!pool_installable(pool, s))           /* only look at installable ones */
00783         continue;
00784 
00785       sup = 0;
00786       if (s->supplements)
00787         {
00788           /* find possible supplements */
00789           supp = s->repo->idarraydata + s->supplements;
00790           while ((sup = *supp++) != 0)
00791             if (dep_possible(solv, sup, m))
00792               break;
00793         }
00794 
00795       /* if nothing found, check for enhances */
00796       if (!sup && s->enhances)
00797         {
00798           supp = s->repo->idarraydata + s->enhances;
00799           while ((sup = *supp++) != 0)
00800             if (dep_possible(solv, sup, m))
00801               break;
00802         }
00803       /* if nothing found, goto next solvables */
00804       if (!sup)
00805         continue;
00806       solver_addrpmrulesforsolvable(solv, s, m);
00807       n = 0;                    /* check all solvables again because we added solvables to m */
00808     }
00809   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
00810 }
00811 
00812 
00813 /*-------------------------------------------------------------------
00814  * 
00815  * add package rules for possible updates
00816  * 
00817  * s: solvable
00818  * m: map of already visited solvables
00819  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
00820  */
00821 
00822 void
00823 solver_addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
00824 {
00825   Pool *pool = solv->pool;
00826   int i;
00827     /* queue and buffer for it */
00828   Queue qs;
00829   Id qsbuf[64];
00830 
00831   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
00832 
00833   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
00834     /* find update candidates for 's' */
00835   policy_findupdatepackages(solv, s, &qs, allow_all);
00836     /* add rule for 's' if not already done */
00837   if (!MAPTST(m, s - pool->solvables))
00838     solver_addrpmrulesforsolvable(solv, s, m);
00839     /* foreach update candidate, add rule if not already done */
00840   for (i = 0; i < qs.count; i++)
00841     if (!MAPTST(m, qs.elements[i]))
00842       solver_addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
00843   queue_free(&qs);
00844 
00845   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
00846 }
00847 
00848 
00849 /***********************************************************************
00850  ***
00851  ***  Update/Feature rule part
00852  ***
00853  ***  Those rules make sure an installed package isn't silently deleted
00854  ***
00855  ***/
00856 
00857 static Id
00858 finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
00859 {
00860   Pool *pool = solv->pool;
00861   int i;
00862 
00863   policy_findupdatepackages(solv, s, qs, allow_all);
00864   if (!qs->count)
00865     {
00866       if (allow_all)
00867         return 0;       /* orphaned, don't create feature rule */
00868       /* check if this is an orphaned package */
00869       policy_findupdatepackages(solv, s, qs, 1);
00870       if (!qs->count)
00871         return 0;       /* orphaned, don't create update rule */
00872       qs->count = 0;
00873       return -SYSTEMSOLVABLE;   /* supported but not installable */
00874     }
00875   if (allow_all)
00876     return s - pool->solvables;
00877   /* check if it is ok to keep the installed package */
00878   for (i = 0; i < qs->count; i++)
00879     {
00880       Solvable *ns = pool->solvables + qs->elements[i];
00881       if (s->evr == ns->evr && solvable_identical(s, ns))
00882         return s - pool->solvables;
00883     }
00884   /* nope, it must be some other package */
00885   return -SYSTEMSOLVABLE;
00886 }
00887 
00888 /* add packages from the dup repositories to the update candidates
00889  * this isn't needed for the global dup mode as all packages are
00890  * from dup repos in that case */
00891 static void
00892 addduppackages(Solver *solv, Solvable *s, Queue *qs)
00893 {
00894   Queue dupqs;
00895   Id p, dupqsbuf[64];
00896   int i;
00897   int oldnoupdateprovide = solv->noupdateprovide;
00898 
00899   queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
00900   solv->noupdateprovide = 1;
00901   policy_findupdatepackages(solv, s, &dupqs, 2);
00902   solv->noupdateprovide = oldnoupdateprovide;
00903   for (i = 0; i < dupqs.count; i++)
00904     {
00905       p = dupqs.elements[i];
00906       if (MAPTST(&solv->dupmap, p))
00907         queue_pushunique(qs, p);
00908     }
00909   queue_free(&dupqs);
00910 }
00911 
00912 /*-------------------------------------------------------------------
00913  * 
00914  * add rule for update
00915  *   (A|A1|A2|A3...)  An = update candidates for A
00916  *
00917  * s = (installed) solvable
00918  */
00919 
00920 void
00921 solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
00922 {
00923   /* installed packages get a special upgrade allowed rule */
00924   Pool *pool = solv->pool;
00925   Id p, d;
00926   Queue qs;
00927   Id qsbuf[64];
00928 
00929   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
00930   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
00931   p = s - pool->solvables;
00932   /* find update candidates for 's' */
00933   if (solv->dupmap_all)
00934     p = finddistupgradepackages(solv, s, &qs, allow_all);
00935   else
00936     policy_findupdatepackages(solv, s, &qs, allow_all);
00937   if (!allow_all && !solv->dupmap_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
00938     addduppackages(solv, s, &qs);
00939 
00940   if (!allow_all && qs.count && solv->noobsoletes.size)
00941     {
00942       int i, j;
00943 
00944       d = pool_queuetowhatprovides(pool, &qs);
00945       /* filter out all noobsoletes packages as they don't update */
00946       for (i = j = 0; i < qs.count; i++)
00947         {
00948           if (MAPTST(&solv->noobsoletes, qs.elements[i]))
00949             {
00950               /* it's ok if they have same nevra */
00951               Solvable *ps = pool->solvables + qs.elements[i];
00952               if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
00953                 continue;
00954             }
00955           qs.elements[j++] = qs.elements[i];
00956         }
00957       if (j < qs.count)
00958         {
00959           if (d && solv->installed && s->repo == solv->installed &&
00960               (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
00961             {
00962               if (!solv->multiversionupdaters)
00963                 solv->multiversionupdaters = sat_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
00964               solv->multiversionupdaters[s - pool->solvables - solv->installed->start] = d;
00965             }
00966           if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
00967             {
00968               queue_push(&solv->orphaned, s - pool->solvables); /* treat as orphaned */
00969               j = qs.count;
00970             }
00971           qs.count = j;
00972         }
00973     }
00974   if (qs.count && p == -SYSTEMSOLVABLE)
00975     p = queue_shift(&qs);
00976   d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
00977   queue_free(&qs);
00978   solver_addrule(solv, p, d);   /* allow update of s */
00979   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
00980 }
00981 
00982 static inline void 
00983 disableupdaterule(Solver *solv, Id p)
00984 {
00985   Rule *r;
00986 
00987   MAPSET(&solv->noupdate, p - solv->installed->start);
00988   r = solv->rules + solv->updaterules + (p - solv->installed->start);
00989   if (r->p && r->d >= 0)
00990     solver_disablerule(solv, r);
00991   r = solv->rules + solv->featurerules + (p - solv->installed->start);
00992   if (r->p && r->d >= 0)
00993     solver_disablerule(solv, r);
00994 }
00995 
00996 static inline void 
00997 reenableupdaterule(Solver *solv, Id p)
00998 {
00999   Pool *pool = solv->pool;
01000   Rule *r;
01001 
01002   MAPCLR(&solv->noupdate, p - solv->installed->start);
01003   r = solv->rules + solv->updaterules + (p - solv->installed->start);
01004   if (r->p)
01005     {    
01006       if (r->d >= 0)
01007         return;
01008       solver_enablerule(solv, r);
01009       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
01010         {
01011           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
01012           solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
01013         }
01014       return;
01015     }
01016   r = solv->rules + solv->featurerules + (p - solv->installed->start);
01017   if (r->p && r->d < 0)
01018     {
01019       solver_enablerule(solv, r);
01020       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
01021         {
01022           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
01023           solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
01024         }
01025     }
01026 }
01027 
01028 
01029 /***********************************************************************
01030  ***
01031  ***  Infarch rule part
01032  ***
01033  ***  Infarch rules make sure the solver uses the best architecture of
01034  ***  a package if multiple archetectures are available
01035  ***
01036  ***/
01037 
01038 void
01039 solver_addinfarchrules(Solver *solv, Map *addedmap)
01040 {
01041   Pool *pool = solv->pool;
01042   int first, i, j;
01043   Id p, pp, a, aa, bestarch;
01044   Solvable *s, *ps, *bests;
01045   Queue badq, allowedarchs;
01046 
01047   queue_init(&badq);
01048   queue_init(&allowedarchs);
01049   solv->infarchrules = solv->nrules;
01050   for (i = 1; i < pool->nsolvables; i++)
01051     {
01052       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
01053         continue;
01054       s = pool->solvables + i;
01055       first = i;
01056       bestarch = 0;
01057       bests = 0;
01058       queue_empty(&allowedarchs);
01059       FOR_PROVIDES(p, pp, s->name)
01060         {
01061           ps = pool->solvables + p;
01062           if (ps->name != s->name || !MAPTST(addedmap, p))
01063             continue;
01064           if (p == i)
01065             first = 0;
01066           if (first)
01067             break;
01068           a = ps->arch;
01069           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
01070           if (a != 1 && pool->installed && ps->repo == pool->installed)
01071             {
01072               if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
01073                 queue_pushunique(&allowedarchs, ps->arch);      /* also ok to keep this architecture */
01074               continue;         /* ignore installed solvables when calculating the best arch */
01075             }
01076           if (a && a != 1 && (!bestarch || a < bestarch))
01077             {
01078               bestarch = a;
01079               bests = ps;
01080             }
01081         }
01082       if (first)
01083         continue;
01084       /* speed up common case where installed package already has best arch */
01085       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
01086         allowedarchs.count--;   /* installed arch is best */
01087       queue_empty(&badq);
01088       FOR_PROVIDES(p, pp, s->name)
01089         {
01090           ps = pool->solvables + p;
01091           if (ps->name != s->name || !MAPTST(addedmap, p))
01092             continue;
01093           a = ps->arch;
01094           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
01095           if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
01096             {
01097               if (pool->installed && ps->repo == pool->installed)
01098                 continue;       /* always ok to keep an installed package */
01099               for (j = 0; j < allowedarchs.count; j++)
01100                 {
01101                   aa = allowedarchs.elements[j];
01102                   if (ps->arch == aa)
01103                     break;
01104                   aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
01105                   if (aa && ((a ^ aa) & 0xffff0000) == 0)
01106                     break;      /* compatible */
01107                 }
01108               if (j == allowedarchs.count)
01109                 queue_push(&badq, p);
01110             }
01111         }
01112       if (!badq.count)
01113         continue;
01114       /* block all solvables in the badq! */
01115       for (j = 0; j < badq.count; j++)
01116         {
01117           p = badq.elements[j];
01118           solver_addrule(solv, -p, 0);
01119         }
01120     }
01121   queue_free(&badq);
01122   queue_free(&allowedarchs);
01123   solv->infarchrules_end = solv->nrules;
01124 }
01125 
01126 static inline void
01127 disableinfarchrule(Solver *solv, Id name)
01128 {
01129   Pool *pool = solv->pool;
01130   Rule *r;
01131   int i;
01132   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
01133     {
01134       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
01135         solver_disablerule(solv, r);
01136     }
01137 }
01138 
01139 static inline void
01140 reenableinfarchrule(Solver *solv, Id name)
01141 {
01142   Pool *pool = solv->pool;
01143   Rule *r;
01144   int i;
01145   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
01146     {
01147       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
01148         {
01149           solver_enablerule(solv, r);
01150           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
01151             {
01152               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
01153               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
01154             }
01155         }
01156     }
01157 }
01158 
01159 
01160 /***********************************************************************
01161  ***
01162  ***  Dup rule part
01163  ***
01164  ***  Dup rules make sure a package is selected from the specified dup
01165  ***  repositories if an update candidate is included in one of them.
01166  ***
01167  ***/
01168 
01169 void
01170 solver_createdupmaps(Solver *solv)
01171 {
01172   Queue *job = &solv->job;
01173   Pool *pool = solv->pool;
01174   Repo *repo;
01175   Id how, what, p, pi, pp, obs, *obsp;
01176   Solvable *s, *ps;
01177   int i;
01178 
01179   map_init(&solv->dupmap, pool->nsolvables);
01180   map_init(&solv->dupinvolvedmap, pool->nsolvables);
01181   for (i = 0; i < job->count; i += 2)
01182     {
01183       how = job->elements[i];
01184       what = job->elements[i + 1];
01185       switch (how & SOLVER_JOBMASK)
01186         {
01187         case SOLVER_DISTUPGRADE:
01188           if ((how & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_REPO)
01189             break;
01190           if (what <= 0 || what > pool->nrepos)
01191             break;
01192           repo = pool_id2repo(pool, what);
01193           FOR_REPO_SOLVABLES(repo, p, s)
01194             {
01195               if (repo != solv->installed && !pool_installable(pool, s))
01196                 continue;
01197               MAPSET(&solv->dupmap, p);
01198               FOR_PROVIDES(pi, pp, s->name)
01199                 {
01200                   ps = pool->solvables + pi;
01201                   if (ps->name != s->name)
01202                     continue;
01203                   MAPSET(&solv->dupinvolvedmap, pi);
01204                 }
01205               if (s->obsoletes)
01206                 {
01207                   /* FIXME: check obsoletes/provides combination */
01208                   obsp = s->repo->idarraydata + s->obsoletes;
01209                   while ((obs = *obsp++) != 0)
01210                     {
01211                       FOR_PROVIDES(pi, pp, obs)
01212                         {
01213                           Solvable *pis = pool->solvables + pi;
01214                           if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pis, obs))
01215                             continue;
01216                           if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pis))
01217                             continue;
01218                           MAPSET(&solv->dupinvolvedmap, pi);
01219                         }
01220                     }
01221                 }
01222             }
01223           break;
01224         default:
01225           break;
01226         }
01227     }
01228   MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
01229 }
01230 
01231 void
01232 solver_freedupmaps(Solver *solv)
01233 {
01234   map_free(&solv->dupmap);
01235   /* we no longer free solv->dupinvolvedmap as we need it in
01236    * policy's priority pruning code. sigh. */
01237 }
01238 
01239 void
01240 solver_addduprules(Solver *solv, Map *addedmap)
01241 {
01242   Pool *pool = solv->pool;
01243   Id p, pp;
01244   Solvable *s, *ps;
01245   int first, i;
01246 
01247   solv->duprules = solv->nrules;
01248   for (i = 1; i < pool->nsolvables; i++)
01249     {
01250       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
01251         continue;
01252       s = pool->solvables + i;
01253       first = i;
01254       FOR_PROVIDES(p, pp, s->name)
01255         {
01256           ps = pool->solvables + p;
01257           if (ps->name != s->name || !MAPTST(addedmap, p))
01258             continue;
01259           if (p == i)
01260             first = 0;
01261           if (first)
01262             break;
01263           if (!MAPTST(&solv->dupinvolvedmap, p))
01264             continue;
01265           if (solv->installed && ps->repo == solv->installed)
01266             {
01267               if (!solv->updatemap.size)
01268                 map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
01269               MAPSET(&solv->updatemap, p - solv->installed->start);
01270               if (!MAPTST(&solv->dupmap, p))
01271                 {
01272                   Id ip, ipp;
01273                   /* is installed identical to a good one? */
01274                   FOR_PROVIDES(ip, ipp, ps->name)
01275                     {
01276                       Solvable *is = pool->solvables + ip;
01277                       if (!MAPTST(&solv->dupmap, ip))
01278                         continue;
01279                       if (is->evr == ps->evr && solvable_identical(ps, is))
01280                         break;
01281                     }
01282                   if (!ip)
01283                     solver_addrule(solv, -p, 0);        /* no match, sorry */
01284                 }
01285             }
01286           else if (!MAPTST(&solv->dupmap, p))
01287             solver_addrule(solv, -p, 0);
01288         }
01289     }
01290   solv->duprules_end = solv->nrules;
01291 }
01292 
01293 
01294 static inline void
01295 disableduprule(Solver *solv, Id name)
01296 {
01297   Pool *pool = solv->pool;
01298   Rule *r;
01299   int i;
01300   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) 
01301     {    
01302       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
01303         solver_disablerule(solv, r);
01304     }    
01305 }
01306 
01307 static inline void 
01308 reenableduprule(Solver *solv, Id name)
01309 {
01310   Pool *pool = solv->pool;
01311   Rule *r;
01312   int i;
01313   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) 
01314     {    
01315       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
01316         {
01317           solver_enablerule(solv, r);
01318           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
01319             {
01320               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
01321               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
01322             }
01323         }
01324     }
01325 }
01326 
01327 
01328 /***********************************************************************
01329  ***
01330  ***  Policy rule disabling/reenabling
01331  ***
01332  ***  Disable all policy rules that conflict with our jobs. If a job
01333  ***  gets disabled later on, reenable the involved policy rules again.
01334  ***
01335  ***/
01336 
01337 #define DISABLE_UPDATE  1
01338 #define DISABLE_INFARCH 2
01339 #define DISABLE_DUP     3
01340 
01341 static void
01342 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
01343 {
01344   Pool *pool = solv->pool;
01345   Id select, p, pp;
01346   Repo *installed;
01347   Solvable *s;
01348   int i, j, set, qstart, pass;
01349   Map omap;
01350 
01351   installed = solv->installed;
01352   select = how & SOLVER_SELECTMASK;
01353   switch (how & SOLVER_JOBMASK)
01354     {
01355     case SOLVER_INSTALL:
01356       set = how & SOLVER_SETMASK;
01357       if (!(set & SOLVER_NOAUTOSET))
01358         {
01359           /* automatically add set bits by analysing the job */
01360           if (select == SOLVER_SOLVABLE)
01361             set |= SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
01362           else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
01363             {
01364               Reldep *rd = GETRELDEP(pool, what);
01365               if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
01366                 {
01367 #if !defined(DEBIAN_SEMANTICS)
01368                   const char *evr = id2str(pool, rd->evr);
01369                   if (strchr(evr, '-'))
01370                     set |= SOLVER_SETEVR;
01371                   else
01372                     set |= SOLVER_SETEV;
01373 #else
01374                   set |= SOLVER_SETEVR;
01375 #endif
01376                 }
01377               if (rd->flags <= 7 && ISRELDEP(rd->name))
01378                 rd = GETRELDEP(pool, rd->name);
01379               if (rd->flags == REL_ARCH)
01380                 set |= SOLVER_SETARCH;
01381             }
01382         }
01383       else
01384         set &= ~SOLVER_NOAUTOSET;
01385       if (!set)
01386         return;
01387       if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
01388         {
01389           if (select == SOLVER_SOLVABLE)
01390             queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
01391           else
01392             {
01393               int qcnt = q->count;
01394               FOR_JOB_SELECT(p, pp, select, what)
01395                 {
01396                   s = pool->solvables + p;
01397                   /* unify names */
01398                   for (i = qcnt; i < q->count; i += 2)
01399                     if (q->elements[i + 1] == s->name)
01400                       break;
01401                   if (i < q->count)
01402                     continue;
01403                   queue_push2(q, DISABLE_INFARCH, s->name);
01404                 }
01405             }
01406         }
01407       if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
01408         {
01409           if (select == SOLVER_SOLVABLE)
01410             queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
01411           else
01412             {
01413               int qcnt = q->count;
01414               FOR_JOB_SELECT(p, pp, select, what)
01415                 {
01416                   s = pool->solvables + p;
01417                   /* unify names */
01418                   for (i = qcnt; i < q->count; i += 2)
01419                     if (q->elements[i + 1] == s->name)
01420                       break;
01421                   if (i < q->count)
01422                     continue;
01423                   queue_push2(q, DISABLE_DUP, s->name);
01424                 }
01425             }
01426         }
01427       if (!installed)
01428         return;
01429       /* now the hard part: disable some update rules */
01430 
01431       /* first check if we have noobs or installed packages in the job */
01432       FOR_JOB_SELECT(p, pp, select, what)
01433         {
01434           if (pool->solvables[p].repo == installed)
01435             {
01436               if (select == SOLVER_SOLVABLE)
01437                 queue_push2(q, DISABLE_UPDATE, what);
01438               return;
01439             }
01440           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
01441             return;
01442         }
01443 
01444       /* all job packages obsolete */
01445       qstart = q->count;
01446       pass = 0;
01447       memset(&omap, 0, sizeof(omap));
01448       FOR_JOB_SELECT(p, pp, select, what)
01449         {
01450           Id p2, pp2;
01451 
01452           if (pass == 1)
01453             map_grow(&omap, installed->end - installed->start);
01454           s = pool->solvables + p;
01455           if (s->obsoletes)
01456             {
01457               Id obs, *obsp;
01458               obsp = s->repo->idarraydata + s->obsoletes;
01459               while ((obs = *obsp++) != 0)
01460                 FOR_PROVIDES(p2, pp2, obs)
01461                   {
01462                     Solvable *ps = pool->solvables + p2;
01463                     if (ps->repo != installed)
01464                       continue;
01465                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
01466                       continue;
01467                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
01468                       continue;
01469                     if (pass)
01470                       MAPSET(&omap, p2 - installed->start);
01471                     else
01472                       queue_push2(q, DISABLE_UPDATE, p2);
01473                   }
01474             }
01475           FOR_PROVIDES(p2, pp2, s->name)
01476             {
01477               Solvable *ps = pool->solvables + p2;
01478               if (ps->repo != installed)
01479                 continue;
01480               if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
01481                 continue;
01482               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
01483                 continue;
01484               if (pass)
01485                 MAPSET(&omap, p2 - installed->start);
01486               else
01487                 queue_push2(q, DISABLE_UPDATE, p2);
01488             }
01489           if (pass)
01490             {
01491               for (i = j = qstart; i < q->count; i += 2)
01492                 {
01493                   if (MAPTST(&omap, q->elements[i + 1] - installed->start))
01494                     {
01495                       MAPCLR(&omap, q->elements[i + 1] - installed->start);
01496                       q->elements[j + 1] = q->elements[i + 1];
01497                       j += 2;
01498                     }
01499                 }
01500               queue_truncate(q, j);
01501             }
01502           if (q->count == qstart)
01503             break;
01504           pass++;
01505         }
01506       if (omap.size)
01507         map_free(&omap);
01508 
01509       if (qstart == q->count)
01510         return;         /* nothing to prune */
01511       if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
01512         return;         /* all is set */
01513 
01514       /* now that we know which installed packages are obsoleted check each of them */
01515       for (i = j = qstart; i < q->count; i += 2)
01516         {
01517           Solvable *is = pool->solvables + q->elements[i + 1];
01518           FOR_JOB_SELECT(p, pp, select, what)
01519             {
01520               int illegal = 0;
01521               s = pool->solvables + p;
01522               if ((set & SOLVER_SETEVR) != 0)
01523                 illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
01524               if ((set & SOLVER_SETARCH) != 0)
01525                 illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
01526               if ((set & SOLVER_SETVENDOR) != 0)
01527                 illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
01528               illegal = policy_is_illegal(solv, is, s, illegal);
01529               if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
01530                 {
01531                   /* it's ok if the EV is different */
01532                   if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
01533                     illegal = 0;
01534                 }
01535               if (illegal)
01536                 break;
01537             }
01538           if (!p)
01539             {   
01540               /* no package conflicts with the update rule */
01541               /* thus keep the DISABLE_UPDATE */
01542               q->elements[j + 1] = q->elements[i + 1];
01543               j += 2;
01544             }
01545         }
01546       queue_truncate(q, j);
01547       return;
01548 
01549     case SOLVER_ERASE:
01550       if (!installed)
01551         break;
01552       FOR_JOB_SELECT(p, pp, select, what)
01553         if (pool->solvables[p].repo == installed)
01554           queue_push2(q, DISABLE_UPDATE, p);
01555       return;
01556     default:
01557       return;
01558     }
01559 }
01560 
01561 /* disable all policy rules that are in conflict with our job list */
01562 void
01563 solver_disablepolicyrules(Solver *solv)
01564 {
01565   Queue *job = &solv->job;
01566   int i, j;
01567   Queue allq;
01568   Rule *r;
01569   Id lastjob = -1;
01570   Id allqbuf[128];
01571 
01572   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
01573 
01574   for (i = solv->jobrules; i < solv->jobrules_end; i++)
01575     {
01576       r = solv->rules + i;
01577       if (r->d < 0)     /* disabled? */
01578         continue;
01579       j = solv->ruletojob.elements[i - solv->jobrules];
01580       if (j == lastjob)
01581         continue;
01582       lastjob = j;
01583       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
01584     }
01585   if (solv->cleandepsmap.size)
01586     {
01587       solver_createcleandepsmap(solv);
01588       for (i = solv->installed->start; i < solv->installed->end; i++)
01589         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
01590           queue_push2(&allq, DISABLE_UPDATE, i);
01591     }
01592   MAPZERO(&solv->noupdate);
01593   for (i = 0; i < allq.count; i += 2)
01594     {
01595       Id type = allq.elements[i], arg = allq.elements[i + 1];
01596       switch(type)
01597         {
01598         case DISABLE_UPDATE:
01599           disableupdaterule(solv, arg);
01600           break;
01601         case DISABLE_INFARCH:
01602           disableinfarchrule(solv, arg);
01603           break;
01604         case DISABLE_DUP:
01605           disableduprule(solv, arg);
01606           break;
01607         default:
01608           break;
01609         }
01610     }
01611   queue_free(&allq);
01612 }
01613 
01614 /* we just disabled job #jobidx, now reenable all policy rules that were
01615  * disabled because of this job */
01616 void
01617 solver_reenablepolicyrules(Solver *solv, int jobidx)
01618 {
01619   Queue *job = &solv->job;
01620   int i, j;
01621   Queue q, allq;
01622   Rule *r;
01623   Id lastjob = -1;
01624   Id qbuf[32], allqbuf[128];
01625 
01626   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
01627   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
01628   jobtodisablelist(solv, job->elements[jobidx], job->elements[jobidx + 1], &q);
01629   if (!q.count)
01630     return;
01631   for (i = solv->jobrules; i < solv->jobrules_end; i++)
01632     {
01633       r = solv->rules + i;
01634       if (r->d < 0)     /* disabled? */
01635         continue;
01636       j = solv->ruletojob.elements[i - solv->jobrules];
01637       if (j == lastjob)
01638         continue;
01639       lastjob = j;
01640       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
01641     }
01642   if (solv->cleandepsmap.size)
01643     {
01644       solver_createcleandepsmap(solv);
01645       for (i = solv->installed->start; i < solv->installed->end; i++)
01646         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
01647           queue_push2(&allq, DISABLE_UPDATE, i);
01648     }
01649   for (j = 0; j < q.count; j += 2)
01650     {
01651       Id type = q.elements[j], arg = q.elements[j + 1];
01652       for (i = 0; i < allq.count; i += 2)
01653         if (allq.elements[i] == type && allq.elements[i + 1] == arg)
01654           break;
01655       if (i < allq.count)
01656         continue;       /* still disabled */
01657       switch(type)
01658         {
01659         case DISABLE_UPDATE:
01660           reenableupdaterule(solv, arg);
01661           break;
01662         case DISABLE_INFARCH:
01663           reenableinfarchrule(solv, arg);
01664           break;
01665         case DISABLE_DUP:
01666           reenableduprule(solv, arg);
01667           break;
01668         }
01669     }
01670   queue_free(&allq);
01671   queue_free(&q);
01672 }
01673 
01674 
01675 /***********************************************************************
01676  ***
01677  ***  Rule info part, tell the user what the rule is about.
01678  ***
01679  ***/
01680 
01681 static void
01682 addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
01683 {
01684   Pool *pool = solv->pool;
01685   Rule *r;
01686   Id w2, op, od, ow2;
01687 
01688   /* check if this creates the rule we're searching for */
01689   r = solv->rules + solv->ruleinfoq->elements[0];
01690   op = r->p;
01691   od = r->d < 0 ? -r->d - 1 : r->d;
01692   ow2 = 0;
01693 
01694   /* normalize */
01695   w2 = d > 0 ? 0 : d;
01696   if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
01697     {
01698       w2 = pool->whatprovidesdata[d];
01699       d = 0;
01700 
01701     }
01702   if (p > 0 && d < 0)           /* this hack is used for buddy deps */
01703     {
01704       w2 = p;
01705       p = d;
01706     }
01707 
01708   if (d > 0)
01709     {
01710       if (p != op && !od)
01711         return;
01712       if (d != od)
01713         {
01714           Id *dp = pool->whatprovidesdata + d;
01715           Id *odp = pool->whatprovidesdata + od;
01716           while (*dp)
01717             if (*dp++ != *odp++)
01718               return;
01719           if (*odp)
01720             return;
01721         }
01722       w2 = 0;
01723       /* handle multiversion conflict rules */
01724       if (p < 0 && pool->whatprovidesdata[d] < 0)
01725         {
01726           w2 = pool->whatprovidesdata[d];
01727           /* XXX: free memory */
01728         }
01729     }
01730   else
01731     {
01732       if (od)
01733         return;
01734       ow2 = r->w2;
01735       if (p > w2)
01736         {
01737           if (w2 != op || p != ow2)
01738             return;
01739         }
01740       else
01741         {
01742           if (p != op || w2 != ow2)
01743             return;
01744         }
01745     }
01746   /* yep, rule matches. record info */
01747   queue_push(solv->ruleinfoq, type);
01748   if (type == SOLVER_RULE_RPM_SAME_NAME)
01749     {
01750       /* we normalize same name order */
01751       queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
01752       queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
01753     }
01754   else
01755     {
01756       queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
01757       queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
01758     }
01759   queue_push(solv->ruleinfoq, dep);
01760 }
01761 
01762 static int
01763 solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
01764 {
01765   const Id *a = ap, *b = bp;
01766   int r;
01767 
01768   r = a[0] - b[0];
01769   if (r)
01770     return r;
01771   r = a[1] - b[1];
01772   if (r)
01773     return r;
01774   r = a[2] - b[2];
01775   if (r)
01776     return r;
01777   r = a[3] - b[3];
01778   if (r)
01779     return r;
01780   return 0;
01781 }
01782 
01783 int
01784 solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
01785 {
01786   Pool *pool = solv->pool;
01787   Rule *r = solv->rules + rid;
01788   int i, j;
01789 
01790   queue_empty(rq);
01791   if (rid <= 0 || rid >= solv->rpmrules_end)
01792     {
01793       Id type, from, to, dep;
01794       type = solver_ruleinfo(solv, rid, &from, &to, &dep);
01795       queue_push(rq, type);
01796       queue_push(rq, from);
01797       queue_push(rq, to);
01798       queue_push(rq, dep);
01799       return 1;
01800     }
01801   if (r->p >= 0)
01802     return 0;
01803   queue_push(rq, rid);
01804   solv->ruleinfoq = rq;
01805   solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
01806   /* also try reverse direction for conflicts */
01807   if ((r->d == 0 || r->d == -1) && r->w2 < 0)
01808     solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
01809   solv->ruleinfoq = 0;
01810   queue_shift(rq);
01811   /* now sort & unify em */
01812   if (!rq->count)
01813     return 0;
01814   sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
01815   /* throw out identical entries */
01816   for (i = j = 0; i < rq->count; i += 4)
01817     {
01818       if (j)
01819         {
01820           if (rq->elements[i] == rq->elements[j - 4] && 
01821               rq->elements[i + 1] == rq->elements[j - 3] &&
01822               rq->elements[i + 2] == rq->elements[j - 2] &&
01823               rq->elements[i + 3] == rq->elements[j - 1])
01824             continue;
01825         }
01826       rq->elements[j++] = rq->elements[i];
01827       rq->elements[j++] = rq->elements[i + 1];
01828       rq->elements[j++] = rq->elements[i + 2];
01829       rq->elements[j++] = rq->elements[i + 3];
01830     }
01831   rq->count = j;
01832   return j / 4;
01833 }
01834 
01835 SolverRuleinfo
01836 solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
01837 {
01838   Pool *pool = solv->pool;
01839   Rule *r = solv->rules + rid;
01840   SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
01841 
01842   if (fromp)
01843     *fromp = 0;
01844   if (top)
01845     *top = 0;
01846   if (depp)
01847     *depp = 0;
01848   if (rid > 0 && rid < solv->rpmrules_end)
01849     {
01850       Queue rq;
01851       int i;
01852 
01853       if (r->p >= 0)
01854         return SOLVER_RULE_RPM;
01855       if (fromp)
01856         *fromp = -r->p;
01857       queue_init(&rq);
01858       queue_push(&rq, rid);
01859       solv->ruleinfoq = &rq;
01860       solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
01861       /* also try reverse direction for conflicts */
01862       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
01863         solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
01864       solv->ruleinfoq = 0;
01865       type = SOLVER_RULE_RPM;
01866       for (i = 1; i < rq.count; i += 4)
01867         {
01868           Id qt, qo, qp, qd;
01869           qt = rq.elements[i];
01870           qp = rq.elements[i + 1];
01871           qo = rq.elements[i + 2];
01872           qd = rq.elements[i + 3];
01873           if (type == SOLVER_RULE_RPM || type > qt)
01874             {
01875               type = qt;
01876               if (fromp)
01877                 *fromp = qp;
01878               if (top)
01879                 *top = qo;
01880               if (depp)
01881                 *depp = qd;
01882             }
01883         }
01884       queue_free(&rq);
01885       return type;
01886     }
01887   if (rid >= solv->jobrules && rid < solv->jobrules_end)
01888     {
01889       Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
01890       if (fromp)
01891         *fromp = jidx;
01892       if (top)
01893         *top = solv->job.elements[jidx];
01894       if (depp)
01895         *depp = solv->job.elements[jidx + 1];
01896       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
01897         return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
01898       return SOLVER_RULE_JOB;
01899     }
01900   if (rid >= solv->updaterules && rid < solv->updaterules_end)
01901     {
01902       if (fromp)
01903         *fromp = solv->installed->start + (rid - solv->updaterules);
01904       return SOLVER_RULE_UPDATE;
01905     }
01906   if (rid >= solv->featurerules && rid < solv->featurerules_end)
01907     {
01908       if (fromp)
01909         *fromp = solv->installed->start + (rid - solv->featurerules);
01910       return SOLVER_RULE_FEATURE;
01911     }
01912   if (rid >= solv->duprules && rid < solv->duprules_end)
01913     {
01914       if (fromp)
01915         *fromp = -r->p;
01916       if (depp)
01917         *depp = pool->solvables[-r->p].name;
01918       return SOLVER_RULE_DISTUPGRADE;
01919     }
01920   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
01921     {
01922       if (fromp)
01923         *fromp = -r->p;
01924       if (depp)
01925         *depp = pool->solvables[-r->p].name;
01926       return SOLVER_RULE_INFARCH;
01927     }
01928   if (rid >= solv->choicerules && rid < solv->choicerules_end)
01929     {
01930       return SOLVER_RULE_CHOICE;
01931     }
01932   if (rid >= solv->learntrules)
01933     {
01934       return SOLVER_RULE_LEARNT;
01935     }
01936   return SOLVER_RULE_UNKNOWN;
01937 }
01938 
01939 void
01940 solver_addchoicerules(Solver *solv)
01941 {
01942   Pool *pool = solv->pool;
01943   Map m, mneg;
01944   Rule *r;
01945   Queue q, qi;
01946   int i, j, rid, havechoice;
01947   Id p, d, *pp;
01948   Id p2, pp2;
01949   Solvable *s, *s2;
01950 
01951   solv->choicerules = solv->nrules;
01952   if (!pool->installed)
01953     {
01954       solv->choicerules_end = solv->nrules;
01955       return;
01956     }
01957   solv->choicerules_ref = sat_calloc(solv->rpmrules_end, sizeof(Id));
01958   queue_init(&q);
01959   queue_init(&qi);
01960   map_init(&m, pool->nsolvables);
01961   map_init(&mneg, pool->nsolvables);
01962   /* set up negative assertion map from infarch and dup rules */
01963   for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
01964     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
01965       MAPSET(&mneg, -r->p);
01966   for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
01967     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
01968       MAPSET(&mneg, -r->p);
01969   for (rid = 1; rid < solv->rpmrules_end ; rid++)
01970     {
01971       r = solv->rules + rid;
01972       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
01973         continue;       /* only look at requires rules */
01974       // solver_printrule(solv, SAT_DEBUG_RESULT, r);
01975       queue_empty(&q);
01976       queue_empty(&qi);
01977       havechoice = 0;
01978       FOR_RULELITERALS(p, pp, r)
01979         {
01980           if (p < 0)
01981             continue;
01982           s = pool->solvables + p;
01983           if (!s->repo)
01984             continue;
01985           if (s->repo == pool->installed)
01986             {
01987               queue_push(&q, p);
01988               continue;
01989             }
01990           /* check if this package is "blocked" by a installed package */
01991           s2 = 0;
01992           FOR_PROVIDES(p2, pp2, s->name)
01993             {
01994               s2 = pool->solvables + p2;
01995               if (s2->repo != pool->installed)
01996                 continue;
01997               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
01998                 continue;
01999               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
02000                 continue;
02001               break;
02002             }
02003           if (p2)
02004             {
02005               /* found installed package p2 that we can update to p */
02006               if (MAPTST(&mneg, p))
02007                 continue;
02008               if (policy_is_illegal(solv, s2, s, 0))
02009                 continue;
02010               queue_push(&qi, p2);
02011               queue_push(&q, p);
02012               continue;
02013             }
02014           if (s->obsoletes)
02015             {
02016               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
02017               s2 = 0;
02018               while ((obs = *obsp++) != 0)
02019                 {
02020                   FOR_PROVIDES(p2, pp2, obs)
02021                     {
02022                       s2 = pool->solvables + p2;
02023                       if (s2->repo != pool->installed)
02024                         continue;
02025                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
02026                         continue;
02027                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
02028                         continue;
02029                       break;
02030                     }
02031                   if (p2)
02032                     break;
02033                 }
02034               if (obs)
02035                 {
02036                   /* found installed package p2 that we can update to p */
02037                   if (MAPTST(&mneg, p))
02038                     continue;
02039                   if (policy_is_illegal(solv, s2, s, 0))
02040                     continue;
02041                   queue_push(&qi, p2);
02042                   queue_push(&q, p);
02043                   continue;
02044                 }
02045             }
02046           /* package p is independent of the installed ones */
02047           havechoice = 1;
02048         }
02049       if (!havechoice || !q.count)
02050         continue;       /* no choice */
02051 
02052       /* now check the update rules of the installed package.
02053        * if all packages of the update rules are contained in
02054        * the dependency rules, there's no need to set up the choice rule */
02055       map_empty(&m);
02056       FOR_RULELITERALS(p, pp, r)
02057         if (p > 0)
02058           MAPSET(&m, p);
02059       for (i = 0; i < qi.count; i++)
02060         {
02061           if (!qi.elements[i])
02062             continue;
02063           Rule *ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
02064           if (!ur->p)
02065             ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
02066           if (!ur->p)
02067             continue;
02068           FOR_RULELITERALS(p, pp, ur)
02069             if (!MAPTST(&m, p))
02070               break;
02071           if (p)
02072             break;
02073           for (j = i + 1; j < qi.count; j++)
02074             if (qi.elements[i] == qi.elements[j])
02075               qi.elements[j] = 0;
02076         }
02077       if (i == qi.count)
02078         {
02079 #if 0
02080           printf("skipping choice ");
02081           solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
02082 #endif
02083           continue;
02084         }
02085       d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
02086       solver_addrule(solv, r->p, d);
02087       queue_push(&solv->weakruleq, solv->nrules - 1);
02088       solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
02089 #if 0
02090       printf("OLD ");
02091       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
02092       printf("WEAK CHOICE ");
02093       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + solv->nrules - 1);
02094 #endif
02095     }
02096   queue_free(&q);
02097   queue_free(&qi);
02098   map_free(&m);
02099   map_free(&mneg);
02100   solv->choicerules_end = solv->nrules;
02101 }
02102 
02103 /* called when a choice rule is disabled by analyze_unsolvable. We also
02104  * have to disable all other choice rules so that the best packages get
02105  * picked */
02106 void
02107 solver_disablechoicerules(Solver *solv, Rule *r)
02108 {
02109   Id rid, p, *pp;
02110   Pool *pool = solv->pool;
02111   Map m;
02112   Rule *or;
02113 
02114   or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
02115   map_init(&m, pool->nsolvables);
02116   FOR_RULELITERALS(p, pp, or)
02117     if (p > 0)
02118       MAPSET(&m, p);
02119   FOR_RULELITERALS(p, pp, r)
02120     if (p > 0)
02121       MAPCLR(&m, p);
02122   for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
02123     {
02124       r = solv->rules + rid;
02125       if (r->d < 0)
02126         continue;
02127       or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
02128       FOR_RULELITERALS(p, pp, or)
02129         if (p > 0 && MAPTST(&m, p))
02130           break;
02131       if (p)
02132         solver_disablerule(solv, r);
02133     }
02134 }
02135 
02136 static void solver_createcleandepsmap(Solver *solv)
02137 {
02138   Pool *pool = solv->pool;
02139   Repo *installed = solv->installed;
02140   Queue *job = &solv->job;
02141   Map userinstalled;
02142   Map im;
02143   Map installedm;
02144   Rule *r;
02145   Id rid, how, what, select;
02146   Id p, pp, ip, *jp;
02147   Id req, *reqp, sup, *supp;
02148   Solvable *s;
02149   Queue iq;
02150   int i;
02151 
02152   map_init(&userinstalled, installed->end - installed->start);
02153   map_init(&im, pool->nsolvables);
02154   map_init(&installedm, pool->nsolvables);
02155   map_empty(&solv->cleandepsmap);
02156   queue_init(&iq);
02157 
02158   for (i = 0; i < job->count; i += 2)
02159     {
02160       how = job->elements[i];
02161       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
02162         {
02163           what = job->elements[i + 1];
02164           select = how & SOLVER_SELECTMASK;
02165           FOR_JOB_SELECT(p, pp, select, what)
02166             if (pool->solvables[p].repo == installed)
02167               MAPSET(&userinstalled, p - installed->start);
02168         }
02169     }
02170   /* add all positive elements (e.g. locks) to "userinstalled" */
02171   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
02172     {
02173       r = solv->rules + rid;
02174       if (r->d < 0)
02175         continue;
02176       FOR_RULELITERALS(p, jp, r)
02177         if (p > 0 && pool->solvables[p].repo == installed)
02178           MAPSET(&userinstalled, p - installed->start);
02179     }
02180   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
02181     {
02182       r = solv->rules + rid;
02183       if (r->p >= 0 || r->d != 0)
02184         continue;       /* disabled or not erase */
02185       p = -r->p;
02186       if (pool->solvables[p].repo != installed)
02187         continue;
02188       MAPCLR(&userinstalled, p - installed->start);
02189       i = solv->ruletojob.elements[rid - solv->jobrules];
02190       how = job->elements[i];
02191       if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
02192         queue_push(&iq, p);
02193     }
02194   for (p = installed->start; p < installed->end; p++)
02195     {
02196       if (pool->solvables[p].repo != installed)
02197         continue;
02198       MAPSET(&installedm, p);
02199       MAPSET(&im, p);
02200     }
02201 
02202   while (iq.count)
02203     {
02204       ip = queue_shift(&iq);
02205       s = pool->solvables + ip;
02206       if (!MAPTST(&im, ip))
02207         continue;
02208       if (!MAPTST(&installedm, ip))
02209         continue;
02210       if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
02211         continue;
02212       MAPCLR(&im, ip);
02213 #ifdef CLEANDEPSDEBUG
02214       printf("hello %s\n", solvable2str(pool, s));
02215 #endif
02216       if (s->requires)
02217         {
02218           reqp = s->repo->idarraydata + s->requires;
02219           while ((req = *reqp++) != 0)
02220             {
02221               if (req == SOLVABLE_PREREQMARKER)
02222                 continue;
02223 #if 0
02224               /* count number of installed packages that match */
02225               count = 0;
02226               FOR_PROVIDES(p, pp, req)
02227                 if (MAPTST(&installedm, p))
02228                   count++;
02229               if (count > 1)
02230                 continue;
02231 #endif
02232               FOR_PROVIDES(p, pp, req)
02233                 {
02234                   if (MAPTST(&im, p))
02235                     {
02236 #ifdef CLEANDEPSDEBUG
02237                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
02238 #endif
02239                       queue_push(&iq, p);
02240                     }
02241                 }
02242             }
02243         }
02244       if (s->recommends)
02245         {
02246           reqp = s->repo->idarraydata + s->recommends;
02247           while ((req = *reqp++) != 0)
02248             {
02249 #if 0
02250               count = 0;
02251               FOR_PROVIDES(p, pp, req)
02252                 if (MAPTST(&installedm, p))
02253                   count++;
02254               if (count > 1)
02255                 continue;
02256 #endif
02257               FOR_PROVIDES(p, pp, req)
02258                 {
02259                   if (MAPTST(&im, p))
02260                     {
02261 #ifdef CLEANDEPSDEBUG
02262                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
02263 #endif
02264                       queue_push(&iq, p);
02265                     }
02266                 }
02267             }
02268         }
02269       if (!iq.count)
02270         {
02271           /* supplements pass */
02272           for (ip = solv->installed->start; ip < solv->installed->end; ip++)
02273             {
02274               if (!MAPTST(&installedm, ip))
02275                 continue;
02276               s = pool->solvables + ip;
02277               if (!s->supplements)
02278                 continue;
02279               if (!MAPTST(&im, ip))
02280                 continue;
02281               supp = s->repo->idarraydata + s->supplements;
02282               while ((sup = *supp++) != 0)
02283                 if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
02284                   break;
02285               /* no longer supplemented, also erase */
02286               if (sup)
02287                 {
02288 #ifdef CLEANDEPSDEBUG
02289                   printf("%s supplemented\n", solvid2str(pool, ip));
02290 #endif
02291                   queue_push(&iq, ip);
02292                 }
02293             }
02294         }
02295     }
02296 
02297   /* turn userinstalled into remove set for pruning */
02298   map_empty(&userinstalled);
02299   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
02300     {
02301       r = solv->rules + rid;
02302       if (r->p >= 0 || r->d != 0)
02303         continue;       /* disabled or not erase */
02304       p = -r->p;
02305       MAPCLR(&im, p);
02306       if (pool->solvables[p].repo == installed)
02307         MAPSET(&userinstalled, p - installed->start);
02308     }
02309   for (p = installed->start; p < installed->end; p++)
02310     if (MAPTST(&im, p))
02311       queue_push(&iq, p);
02312   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
02313     {
02314       r = solv->rules + rid;
02315       if (r->d < 0)
02316         continue;
02317       FOR_RULELITERALS(p, jp, r)
02318         if (p > 0)
02319           queue_push(&iq, p);
02320     }
02321   /* also put directly addressed packages on the install queue
02322    * so we can mark patterns as installed */
02323   for (i = 0; i < job->count; i += 2)
02324     {
02325       how = job->elements[i];
02326       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
02327         {
02328           what = job->elements[i + 1];
02329           select = how & SOLVER_SELECTMASK;
02330           if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
02331             queue_push(&iq, what);
02332         }
02333     }
02334   while (iq.count)
02335     {
02336       ip = queue_shift(&iq);
02337       s = pool->solvables + ip;
02338 #ifdef CLEANDEPSDEBUG
02339       printf("bye %s\n", solvable2str(pool, s));
02340 #endif
02341       if (s->requires)
02342         {
02343           reqp = s->repo->idarraydata + s->requires;
02344           while ((req = *reqp++) != 0)
02345             {
02346               FOR_PROVIDES(p, pp, req)
02347                 {
02348                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
02349                     {
02350                       if (p == ip)
02351                         continue;
02352                       if (MAPTST(&userinstalled, p - installed->start))
02353                         continue;
02354 #ifdef CLEANDEPSDEBUG
02355                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
02356 #endif
02357                       MAPSET(&im, p);
02358                       queue_push(&iq, p);
02359                     }
02360                 }
02361             }
02362         }
02363       if (s->recommends)
02364         {
02365           reqp = s->repo->idarraydata + s->recommends;
02366           while ((req = *reqp++) != 0)
02367             {
02368               FOR_PROVIDES(p, pp, req)
02369                 {
02370                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
02371                     {
02372                       if (p == ip)
02373                         continue;
02374                       if (MAPTST(&userinstalled, p - installed->start))
02375                         continue;
02376 #ifdef CLEANDEPSDEBUG
02377                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
02378 #endif
02379                       MAPSET(&im, p);
02380                       queue_push(&iq, p);
02381                     }
02382                 }
02383             }
02384         }
02385       if (!iq.count)
02386         {
02387           /* supplements pass */
02388           for (ip = installed->start; ip < installed->end; ip++)
02389             {
02390               if (!MAPTST(&installedm, ip))
02391                 continue;
02392               if (MAPTST(&userinstalled, ip - installed->start))
02393                 continue;
02394               s = pool->solvables + ip;
02395               if (!s->supplements)
02396                 continue;
02397               if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
02398                 continue;
02399               supp = s->repo->idarraydata + s->supplements;
02400               while ((sup = *supp++) != 0)
02401                 if (dep_possible(solv, sup, &im))
02402                   break;
02403               if (sup)
02404                 {
02405 #ifdef CLEANDEPSDEBUG
02406                   printf("%s supplemented\n", solvid2str(pool, ip));
02407 #endif
02408                   MAPSET(&im, ip);
02409                   queue_push(&iq, ip);
02410                 }
02411             }
02412         }
02413     }
02414     
02415   queue_free(&iq);
02416   for (p = installed->start; p < installed->end; p++)
02417     {
02418       if (pool->solvables[p].repo != installed)
02419         continue;
02420       if (!MAPTST(&im, p))
02421         MAPSET(&solv->cleandepsmap, p - installed->start);
02422     }
02423   map_free(&im);
02424   map_free(&installedm);
02425   map_free(&userinstalled);
02426 }
02427 
02428 
02429 /* EOF */

Generated on Mon Dec 15 17:56:24 2014 for satsolver by  doxygen 1.5.6