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

doxygen