- add SOLVER_NOAUTOSET to disable automatic SET deduction
[platform/upstream/libsolv.git] / src / rules.c
1 /*
2  * Copyright (c) 2007-2009, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * rules.c
10  *
11  * SAT based dependency solver
12  */
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <unistd.h>
17 #include <string.h>
18 #include <assert.h>
19
20 #include "solver.h"
21 #include "bitmap.h"
22 #include "pool.h"
23 #include "poolarch.h"
24 #include "util.h"
25 #include "evr.h"
26 #include "policy.h"
27 #include "solverdebug.h"
28
29 #define RULES_BLOCK 63
30
31 static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
32 static void solver_createcleandepsmap(Solver *solv);
33
34 /*-------------------------------------------------------------------
35  * Check if dependency is possible
36  * 
37  * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap
38  */
39
40 static inline int
41 dep_possible(Solver *solv, Id dep, Map *m)
42 {
43   Pool *pool = solv->pool;
44   Id p, pp;
45
46   if (ISRELDEP(dep))
47     {
48       Reldep *rd = GETRELDEP(pool, dep);
49       if (rd->flags == REL_AND)
50         {
51           if (!dep_possible(solv, rd->name, m))
52             return 0;
53           return dep_possible(solv, rd->evr, m);
54         }
55       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
56         return solver_splitprovides(solv, rd->evr);
57       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
58         return solver_dep_installed(solv, rd->evr);
59     }
60   FOR_PROVIDES(p, pp, dep)
61     {
62       if (MAPTST(m, p))
63         return 1;
64     }
65   return 0;
66 }
67
68 /********************************************************************
69  *
70  * Rule handling
71  *
72  * - unify rules, remove duplicates
73  */
74
75 /*-------------------------------------------------------------------
76  *
77  * compare rules for unification sort
78  *
79  */
80
81 static int
82 unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
83 {
84   Pool *pool = dp;
85   Rule *a = (Rule *)ap;
86   Rule *b = (Rule *)bp;
87   Id *ad, *bd;
88   int x;
89
90   x = a->p - b->p;
91   if (x)
92     return x;                          /* p differs */
93
94   /* identical p */
95   if (a->d == 0 && b->d == 0)
96     return a->w2 - b->w2;              /* assertion: return w2 diff */
97
98   if (a->d == 0)                       /* a is assertion, b not */
99     {
100       x = a->w2 - pool->whatprovidesdata[b->d];
101       return x ? x : -1;
102     }
103
104   if (b->d == 0)                       /* b is assertion, a not */
105     {
106       x = pool->whatprovidesdata[a->d] - b->w2;
107       return x ? x : 1;
108     }
109
110   /* compare whatprovidesdata */
111   ad = pool->whatprovidesdata + a->d;
112   bd = pool->whatprovidesdata + b->d;
113   while (*bd)
114     if ((x = *ad++ - *bd++) != 0)
115       return x;
116   return *ad;
117 }
118
119 int
120 solver_samerule(Solver *solv, Rule *r1, Rule *r2)
121 {
122   return unifyrules_sortcmp(r1, r2, solv->pool);
123 }
124
125
126 /*-------------------------------------------------------------------
127  *
128  * unify rules
129  * go over all rules and remove duplicates
130  */
131
132 void
133 solver_unifyrules(Solver *solv)
134 {
135   Pool *pool = solv->pool;
136   int i, j;
137   Rule *ir, *jr;
138
139   if (solv->nrules <= 1)               /* nothing to unify */
140     return;
141
142   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules -----\n");
143
144   /* sort rules first */
145   sat_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
146
147   /* prune rules
148    * i = unpruned
149    * j = pruned
150    */
151   jr = 0;
152   for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
153     {
154       if (jr && !unifyrules_sortcmp(ir, jr, pool))
155         continue;                      /* prune! */
156       jr = solv->rules + j++;          /* keep! */
157       if (ir != jr)
158         *jr = *ir;
159     }
160
161   /* reduced count from nrules to j rules */
162   POOL_DEBUG(SAT_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
163
164   /* adapt rule buffer */
165   solv->nrules = j;
166   solv->rules = sat_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
167
168   /*
169    * debug: log rule statistics
170    */
171   IF_POOLDEBUG (SAT_DEBUG_STATS)
172     {
173       int binr = 0;
174       int lits = 0;
175       Id *dp;
176       Rule *r;
177
178       for (i = 1; i < solv->nrules; i++)
179         {
180           r = solv->rules + i;
181           if (r->d == 0)
182             binr++;
183           else
184             {
185               dp = solv->pool->whatprovidesdata + r->d;
186               while (*dp++)
187                 lits++;
188             }
189         }
190       POOL_DEBUG(SAT_DEBUG_STATS, "  binary: %d\n", binr);
191       POOL_DEBUG(SAT_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
192     }
193   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- unifyrules end -----\n");
194 }
195
196 #if 0
197
198 /*
199  * hash rule
200  */
201
202 static Hashval
203 hashrule(Solver *solv, Id p, Id d, int n)
204 {
205   unsigned int x = (unsigned int)p;
206   int *dp;
207
208   if (n <= 1)
209     return (x * 37) ^ (unsigned int)d;
210   dp = solv->pool->whatprovidesdata + d;
211   while (*dp)
212     x = (x * 37) ^ (unsigned int)*dp++;
213   return x;
214 }
215 #endif
216
217
218 /*-------------------------------------------------------------------
219  * 
220  */
221
222 /*
223  * add rule
224  *  p = direct literal; always < 0 for installed rpm rules
225  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
226  *
227  *
228  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
229  *
230  * p < 0 : pkg id of A
231  * d > 0 : Offset in whatprovidesdata (list of providers of b)
232  *
233  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
234  * p < 0 : pkg id of A
235  * d < 0 : Id of solvable (e.g. B1)
236  *
237  * d == 0: unary rule, assertion => (A) or (-A)
238  *
239  *   Install:    p > 0, d = 0   (A)             user requested install
240  *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
241  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
242  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
243  *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
244  *                                              also used for obsoletes
245  *   ?:          p > 0, d < 0   (A|-B)          
246  *   No-op ?:    p = 0, d = 0   (null)          (used as policy rule placeholder)
247  *
248  *   resulting watches:
249  *   ------------------
250  *   Direct assertion (no watch needed)( if d <0 ) --> d = 0, w1 = p, w2 = 0
251  *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
252  *   every other : w1 = p, w2 = whatprovidesdata[d];
253  *   Disabled rule: w1 = 0
254  *
255  *   always returns a rule for non-rpm rules
256  */
257
258 Rule *
259 solver_addrule(Solver *solv, Id p, Id d)
260 {
261   Pool *pool = solv->pool;
262   Rule *r = 0;
263   Id *dp = 0;
264
265   int n = 0;                           /* number of literals in rule - 1
266                                           0 = direct assertion (single literal)
267                                           1 = binary rule
268                                           >1 = 
269                                         */
270
271   /* it often happenes that requires lead to adding the same rpm rule
272    * multiple times, so we prune those duplicates right away to make
273    * the work for unifyrules a bit easier */
274
275   if (solv->nrules                      /* we already have rules */
276       && !solv->rpmrules_end)           /* but are not done with rpm rules */
277     {
278       r = solv->rules + solv->nrules - 1;   /* get the last added rule */
279       if (r->p == p && r->d == d && d != 0)   /* identical and not user requested */
280         return r;
281     }
282
283     /*
284      * compute number of literals (n) in rule
285      */
286     
287   if (d < 0)
288     {
289       /* always a binary rule */
290       if (p == d)
291         return 0;                      /* ignore self conflict */
292       n = 1;
293     }
294   else if (d > 0)
295     {
296       for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
297         if (*dp == -p)
298           return 0;                     /* rule is self-fulfilling */
299         
300       if (n == 1)   /* have single provider */
301         d = dp[-1];                     /* take single literal */
302     }
303
304   if (n == 1 && p > d && !solv->rpmrules_end)
305     {
306       /* smallest literal first so we can find dups */
307       n = p; p = d; d = n;             /* p <-> d */
308       n = 1;                           /* re-set n, was used as temp var */
309     }
310
311   /*
312    * check for duplicate
313    */
314     
315   /* check if the last added rule (r) is exactly the same as what we're looking for. */
316   if (r && n == 1 && !r->d && r->p == p && r->w2 == d)
317     return r;  /* binary rule */
318
319     /* have n-ary rule with same first literal, check other literals */
320   if (r && n > 1 && r->d && r->p == p)
321     {
322       /* Rule where d is an offset in whatprovidesdata */
323       Id *dp2;
324       if (d == r->d)
325         return r;
326       dp2 = pool->whatprovidesdata + r->d;
327       for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
328         if (*dp != *dp2)
329           break;
330       if (*dp == *dp2)
331         return r;
332    }
333
334   /*
335    * allocate new rule
336    */
337
338   /* extend rule buffer */
339   solv->rules = sat_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
340   r = solv->rules + solv->nrules++;    /* point to rule space */
341
342     /*
343      * r = new rule
344      */
345     
346   r->p = p;
347   if (n == 0)
348     {
349       /* direct assertion, no watch needed */
350       r->d = 0;
351       r->w1 = p;
352       r->w2 = 0;
353     }
354   else if (n == 1)
355     {
356       /* binary rule */
357       r->d = 0;
358       r->w1 = p;
359       r->w2 = d;
360     }
361   else
362     {
363       r->d = d;
364       r->w1 = p;
365       r->w2 = pool->whatprovidesdata[d];
366     }
367   r->n1 = 0;
368   r->n2 = 0;
369
370   IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
371     {
372       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "  Add rule: ");
373       solver_printrule(solv, SAT_DEBUG_RULE_CREATION, r);
374     }
375
376   return r;
377 }
378
379
380 /******************************************************************************
381  ***
382  *** rpm rule part: create rules representing the package dependencies
383  ***
384  ***/
385
386 /*
387  *  special multiversion patch conflict handling:
388  *  a patch conflict is also satisfied if some other
389  *  version with the same name/arch that doesn't conflict
390  *  gets installed. The generated rule is thus:
391  *  -patch|-cpack|opack1|opack2|...
392  */
393 static Id
394 makemultiversionconflict(Solver *solv, Id n, Id con)
395 {
396   Pool *pool = solv->pool;
397   Solvable *s, *sn;
398   Queue q;
399   Id p, pp, qbuf[64];
400
401   sn = pool->solvables + n;
402   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
403   queue_push(&q, -n);
404   FOR_PROVIDES(p, pp, sn->name)
405     {
406       s = pool->solvables + p;
407       if (s->name != sn->name || s->arch != sn->arch)
408         continue;
409       if (!MAPTST(&solv->noobsoletes, p))
410         continue;
411       if (pool_match_nevr(pool, pool->solvables + p, con))
412         continue;
413       /* here we have a multiversion solvable that doesn't conflict */
414       /* thus we're not in conflict if it is installed */
415       queue_push(&q, p);
416     }
417   if (q.count == 1)
418     return -n;  /* no other package found, generate normal conflict */
419   return pool_queuetowhatprovides(pool, &q);
420 }
421
422 static inline void
423 addrpmrule(Solver *solv, Id p, Id d, int type, Id dep)
424 {
425   if (!solv->ruleinfoq)
426     solver_addrule(solv, p, d);
427   else
428     addrpmruleinfo(solv, p, d, type, dep);
429 }
430
431 /*-------------------------------------------------------------------
432  * 
433  * add (install) rules for solvable
434  * 
435  * s: Solvable for which to add rules
436  * m: m[s] = 1 for solvables which have rules, prevent rule duplication
437  * 
438  * Algorithm: 'visit all nodes of a graph'. The graph nodes are
439  *  solvables, the edges their dependencies.
440  *  Starting from an installed solvable, this will create all rules
441  *  representing the graph created by the solvables dependencies.
442  * 
443  * for unfulfilled requirements, conflicts, obsoletes,....
444  * add a negative assertion for solvables that are not installable
445  * 
446  * It will also create rules for all solvables referenced by 's'
447  *  i.e. descend to all providers of requirements of 's'
448  *
449  */
450
451 void
452 solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
453 {
454   Pool *pool = solv->pool;
455   Repo *installed = solv->installed;
456
457   /* 'work' queue. keeps Ids of solvables we still have to work on.
458      And buffer for it. */
459   Queue workq;
460   Id workqbuf[64];
461     
462   int i;
463     /* if to add rules for broken deps ('rpm -V' functionality)
464      * 0 = yes, 1 = no
465      */
466   int dontfix;
467     /* Id var and pointer for each dependency
468      * (not used in parallel)
469      */
470   Id req, *reqp;
471   Id con, *conp;
472   Id obs, *obsp;
473   Id rec, *recp;
474   Id sug, *sugp;
475   Id p, pp;             /* whatprovides loops */
476   Id *dp;               /* ptr to 'whatprovides' */
477   Id n;                 /* Id for current solvable 's' */
478
479   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable -----\n");
480
481   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
482   queue_push(&workq, s - pool->solvables);      /* push solvable Id to work queue */
483
484   /* loop until there's no more work left */
485   while (workq.count)
486     {
487       /*
488        * n: Id of solvable
489        * s: Pointer to solvable
490        */
491
492       n = queue_shift(&workq);          /* 'pop' next solvable to work on from queue */
493       if (m)
494         {
495           if (MAPTST(m, n))             /* continue if already visited */
496             continue;
497           MAPSET(m, n);                 /* mark as visited */
498         }
499
500       s = pool->solvables + n;          /* s = Solvable in question */
501
502       dontfix = 0;
503       if (installed                     /* Installed system available */
504           && s->repo == installed       /* solvable is installed */
505           && !solv->fixmap_all          /* NOT repair errors in rpm dependency graph */
506           && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
507         {
508           dontfix = 1;                  /* dont care about broken rpm deps */
509         }
510
511       if (!dontfix
512           && s->arch != ARCH_SRC
513           && s->arch != ARCH_NOSRC
514           && !pool_installable(pool, s))
515         {
516           POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", solvable2str(pool, s), (Id)(s - pool->solvables));
517           addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOT_INSTALLABLE, 0);
518         }
519
520       /* yet another SUSE hack, sigh */
521       if (pool->nscallback && !strncmp("product:", id2str(pool, s->name), 8))
522         {
523           Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, n);
524           if (buddy > 0 && buddy != SYSTEMSOLVABLE && buddy != n && buddy < pool->nsolvables)
525             {
526               addrpmrule(solv, n, -buddy, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + n));
527               addrpmrule(solv, buddy, -n, SOLVER_RULE_RPM_PACKAGE_REQUIRES, solvable_selfprovidedep(pool->solvables + buddy)); 
528               if (m && !MAPTST(m, buddy))
529                 queue_push(&workq, buddy);
530             }
531         }
532
533       /*-----------------------------------------
534        * check requires of s
535        */
536
537       if (s->requires)
538         {
539           reqp = s->repo->idarraydata + s->requires;
540           while ((req = *reqp++) != 0)            /* go through all requires */
541             {
542               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
543                 continue;
544
545               /* find list of solvables providing 'req' */
546               dp = pool_whatprovides_ptr(pool, req);
547
548               if (*dp == SYSTEMSOLVABLE)          /* always installed */
549                 continue;
550
551               if (dontfix)
552                 {
553                   /* the strategy here is to not insist on dependencies
554                    * that are already broken. so if we find one provider
555                    * that was already installed, we know that the
556                    * dependency was not broken before so we enforce it */
557                  
558                   /* check if any of the providers for 'req' is installed */
559                   for (i = 0; (p = dp[i]) != 0; i++)
560                     {
561                       if (pool->solvables[p].repo == installed)
562                         break;          /* provider was installed */
563                     }
564                   /* didn't find an installed provider: previously broken dependency */
565                   if (!p)
566                     {
567                       POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", dep2str(pool, req), solvable2str(pool, s));
568                       continue;
569                     }
570                 }
571
572               if (!*dp)
573                 {
574                   /* nothing provides req! */
575                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", solvable2str(pool, s), (Id)(s - pool->solvables), dep2str(pool, req));
576                   addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, req);
577                   continue;
578                 }
579
580               IF_POOLDEBUG (SAT_DEBUG_RULE_CREATION)
581                 {
582                   POOL_DEBUG(SAT_DEBUG_RULE_CREATION,"  %s requires %s\n", solvable2str(pool, s), dep2str(pool, req));
583                   for (i = 0; dp[i]; i++)
584                     POOL_DEBUG(SAT_DEBUG_RULE_CREATION, "   provided by %s\n", solvid2str(pool, dp[i]));
585                 }
586
587               /* add 'requires' dependency */
588               /* rule: (-requestor|provider1|provider2|...|providerN) */
589               addrpmrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
590
591               /* descend the dependency tree
592                  push all non-visited providers on the work queue */
593               if (m)
594                 {
595                   for (; *dp; dp++)
596                     {
597                       if (!MAPTST(m, *dp))
598                         queue_push(&workq, *dp);
599                     }
600                 }
601
602             } /* while, requirements of n */
603
604         } /* if, requirements */
605
606       /* that's all we check for src packages */
607       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
608         continue;
609
610       /*-----------------------------------------
611        * check conflicts of s
612        */
613
614       if (s->conflicts)
615         {
616           int ispatch = 0;
617
618           /* we treat conflicts in patches a bit differen:
619            * - nevr matching
620            * - multiversion handling
621            * XXX: we should really handle this different, looking
622            * at the name is a bad hack
623            */
624           if (!strncmp("patch:", id2str(pool, s->name), 6))
625             ispatch = 1;
626           conp = s->repo->idarraydata + s->conflicts;
627           /* foreach conflicts of 's' */
628           while ((con = *conp++) != 0)
629             {
630               /* foreach providers of a conflict of 's' */
631               FOR_PROVIDES(p, pp, con)
632                 {
633                   if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
634                     continue;
635                   /* dontfix: dont care about conflicts with already installed packs */
636                   if (dontfix && pool->solvables[p].repo == installed)
637                     continue;
638                   /* p == n: self conflict */
639                   if (p == n && !pool->allowselfconflicts)
640                     {
641                       if (ISRELDEP(con))
642                         {
643                           Reldep *rd = GETRELDEP(pool, con);
644                           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
645                             continue;
646                         }
647                       p = 0;    /* make it a negative assertion, aka 'uninstallable' */
648                     }
649                   if (p && ispatch && solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p) && ISRELDEP(con))
650                     {
651                       /* our patch conflicts with a noobsoletes (aka multiversion) package */
652                       p = -makemultiversionconflict(solv, p, con);
653                     }
654                  /* rule: -n|-p: either solvable _or_ provider of conflict */
655                   addrpmrule(solv, -n, -p, p ? SOLVER_RULE_RPM_PACKAGE_CONFLICT : SOLVER_RULE_RPM_SELF_CONFLICT, con);
656                 }
657             }
658         }
659
660       /*-----------------------------------------
661        * check obsoletes and implicit obsoletes of a package
662        * if ignoreinstalledsobsoletes is not set, we're also checking
663        * obsoletes of installed packages (like newer rpm versions)
664        */
665       if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
666         {
667           int noobs = solv->noobsoletes.size && MAPTST(&solv->noobsoletes, n);
668           int isinstalled = (installed && s->repo == installed);
669           if (s->obsoletes && !noobs)
670             {
671               obsp = s->repo->idarraydata + s->obsoletes;
672               /* foreach obsoletes */
673               while ((obs = *obsp++) != 0)
674                 {
675                   /* foreach provider of an obsoletes of 's' */ 
676                   FOR_PROVIDES(p, pp, obs)
677                     {
678                       Solvable *ps = pool->solvables + p;
679                       if (p == n)
680                         continue;
681                       if (isinstalled && dontfix && ps->repo == installed)
682                         continue;       /* don't repair installed/installed problems */
683                       if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
684                           && !pool_match_nevr(pool, ps, obs))
685                         continue;
686                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
687                         continue;
688                       if (!isinstalled)
689                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
690                       else
691                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES, obs);
692                     }
693                 }
694             }
695           /* check implicit obsoletes
696            * for installed packages we only need to check installed/installed problems (and
697            * only when dontfix is not set), as the others are picked up when looking at the
698            * uninstalled package.
699            */
700           if (!isinstalled || !dontfix)
701             {
702               FOR_PROVIDES(p, pp, s->name)
703                 {
704                   Solvable *ps = pool->solvables + p;
705                   if (p == n)
706                     continue;
707                   if (isinstalled && ps->repo != installed)
708                     continue;
709                   /* we still obsolete packages with same nevra, like rpm does */
710                   /* (actually, rpm mixes those packages. yuck...) */
711                   if (noobs && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
712                     continue;
713                   if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
714                     continue;
715                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
716                     continue;
717                   if (s->name == ps->name)
718                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
719                   else
720                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
721                 }
722             }
723         }
724
725       /*-----------------------------------------
726        * add recommends to the work queue
727        */
728       if (s->recommends && m)
729         {
730           recp = s->repo->idarraydata + s->recommends;
731           while ((rec = *recp++) != 0)
732             {
733               FOR_PROVIDES(p, pp, rec)
734                 if (!MAPTST(m, p))
735                   queue_push(&workq, p);
736             }
737         }
738       if (s->suggests && m)
739         {
740           sugp = s->repo->idarraydata + s->suggests;
741           while ((sug = *sugp++) != 0)
742             {
743               FOR_PROVIDES(p, pp, sug)
744                 if (!MAPTST(m, p))
745                   queue_push(&workq, p);
746             }
747         }
748     }
749   queue_free(&workq);
750   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforsolvable end -----\n");
751 }
752
753
754 /*-------------------------------------------------------------------
755  * 
756  * Add package rules for weak rules
757  *
758  * m: visited solvables
759  */
760
761 void
762 solver_addrpmrulesforweak(Solver *solv, Map *m)
763 {
764   Pool *pool = solv->pool;
765   Solvable *s;
766   Id sup, *supp;
767   int i, n;
768
769   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak -----\n");
770     /* foreach solvable in pool */
771   for (i = n = 1; n < pool->nsolvables; i++, n++)
772     {
773       if (i == pool->nsolvables)                /* wrap i */
774         i = 1;
775       if (MAPTST(m, i))                         /* been there */
776         continue;
777
778       s = pool->solvables + i;
779       if (!pool_installable(pool, s))           /* only look at installable ones */
780         continue;
781
782       sup = 0;
783       if (s->supplements)
784         {
785           /* find possible supplements */
786           supp = s->repo->idarraydata + s->supplements;
787           while ((sup = *supp++) != ID_NULL)
788             if (dep_possible(solv, sup, m))
789               break;
790         }
791
792       /* if nothing found, check for enhances */
793       if (!sup && s->enhances)
794         {
795           supp = s->repo->idarraydata + s->enhances;
796           while ((sup = *supp++) != ID_NULL)
797             if (dep_possible(solv, sup, m))
798               break;
799         }
800       /* if nothing found, goto next solvables */
801       if (!sup)
802         continue;
803       solver_addrpmrulesforsolvable(solv, s, m);
804       n = 0;                    /* check all solvables again */
805     }
806   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforweak end -----\n");
807 }
808
809
810 /*-------------------------------------------------------------------
811  * 
812  * add package rules for possible updates
813  * 
814  * s: solvable
815  * m: map of already visited solvables
816  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
817  */
818
819 void
820 solver_addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
821 {
822   Pool *pool = solv->pool;
823   int i;
824     /* queue and buffer for it */
825   Queue qs;
826   Id qsbuf[64];
827
828   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
829
830   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
831     /* find update candidates for 's' */
832   policy_findupdatepackages(solv, s, &qs, allow_all);
833     /* add rule for 's' if not already done */
834   if (!MAPTST(m, s - pool->solvables))
835     solver_addrpmrulesforsolvable(solv, s, m);
836     /* foreach update candidate, add rule if not already done */
837   for (i = 0; i < qs.count; i++)
838     if (!MAPTST(m, qs.elements[i]))
839       solver_addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
840   queue_free(&qs);
841
842   POOL_DEBUG(SAT_DEBUG_SCHUBI, "----- addrpmrulesforupdaters -----\n");
843 }
844
845
846 /***********************************************************************
847  ***
848  ***  Update/Feature rule part
849  ***
850  ***  Those rules make sure an installed package isn't silently deleted
851  ***
852  ***/
853
854 static Id
855 finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
856 {
857   Pool *pool = solv->pool;
858   int i;
859
860   policy_findupdatepackages(solv, s, qs, allow_all);
861   if (!qs->count)
862     {
863       if (allow_all)
864         return 0;       /* orphaned, don't create feature rule */
865       /* check if this is an orphaned package */
866       policy_findupdatepackages(solv, s, qs, 1);
867       if (!qs->count)
868         return 0;       /* orphaned, don't create update rule */
869       qs->count = 0;
870       return -SYSTEMSOLVABLE;   /* supported but not installable */
871     }
872   if (allow_all)
873     return s - pool->solvables;
874   /* check if it is ok to keep the installed package */
875   for (i = 0; i < qs->count; i++)
876     {
877       Solvable *ns = pool->solvables + qs->elements[i];
878       if (s->evr == ns->evr && solvable_identical(s, ns))
879         return s - pool->solvables;
880     }
881   /* nope, it must be some other package */
882   return -SYSTEMSOLVABLE;
883 }
884
885 /* add packages from the dup repositories to the update candidates
886  * this isn't needed for the global dup mode as all packages are
887  * from dup repos in that case */
888 static void
889 addduppackages(Solver *solv, Solvable *s, Queue *qs)
890 {
891   Queue dupqs;
892   Id p, dupqsbuf[64];
893   int i;
894   int oldnoupdateprovide = solv->noupdateprovide;
895
896   queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
897   solv->noupdateprovide = 1;
898   policy_findupdatepackages(solv, s, &dupqs, 2);
899   solv->noupdateprovide = oldnoupdateprovide;
900   for (i = 0; i < dupqs.count; i++)
901     {
902       p = dupqs.elements[i];
903       if (MAPTST(&solv->dupmap, p))
904         queue_pushunique(qs, p);
905     }
906   queue_free(&dupqs);
907 }
908
909 /*-------------------------------------------------------------------
910  * 
911  * add rule for update
912  *   (A|A1|A2|A3...)  An = update candidates for A
913  *
914  * s = (installed) solvable
915  */
916
917 void
918 solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
919 {
920   /* installed packages get a special upgrade allowed rule */
921   Pool *pool = solv->pool;
922   Id p, d;
923   Queue qs;
924   Id qsbuf[64];
925
926   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule -----\n");
927   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
928   p = s - pool->solvables;
929   /* find update candidates for 's' */
930   if (solv->dupmap_all)
931     p = finddistupgradepackages(solv, s, &qs, allow_all);
932   else
933     policy_findupdatepackages(solv, s, &qs, allow_all);
934   if (!allow_all && !solv->dupmap_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
935     addduppackages(solv, s, &qs);
936
937   if (!allow_all && qs.count && solv->noobsoletes.size)
938     {
939       int i, j;
940
941       d = pool_queuetowhatprovides(pool, &qs);
942       /* filter out all noobsoletes packages as they don't update */
943       for (i = j = 0; i < qs.count; i++)
944         {
945           if (MAPTST(&solv->noobsoletes, qs.elements[i]))
946             {
947               /* it's ok if they have same nevra */
948               Solvable *ps = pool->solvables + qs.elements[i];
949               if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
950                 continue;
951             }
952           qs.elements[j++] = qs.elements[i];
953         }
954       if (j < qs.count)
955         {
956           if (d && solv->installed && s->repo == solv->installed &&
957               (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
958             {
959               if (!solv->multiversionupdaters)
960                 solv->multiversionupdaters = sat_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
961               solv->multiversionupdaters[s - pool->solvables - solv->installed->start] = d;
962             }
963           if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
964             {
965               queue_push(&solv->orphaned, s - pool->solvables); /* treat as orphaned */
966               j = qs.count;
967             }
968           qs.count = j;
969         }
970     }
971   if (qs.count && p == -SYSTEMSOLVABLE)
972     p = queue_shift(&qs);
973   d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
974   queue_free(&qs);
975   solver_addrule(solv, p, d);   /* allow update of s */
976   POOL_DEBUG(SAT_DEBUG_SCHUBI, "-----  addupdaterule end -----\n");
977 }
978
979 static inline void 
980 disableupdaterule(Solver *solv, Id p)
981 {
982   Rule *r;
983
984   MAPSET(&solv->noupdate, p - solv->installed->start);
985   r = solv->rules + solv->updaterules + (p - solv->installed->start);
986   if (r->p && r->d >= 0)
987     solver_disablerule(solv, r);
988   r = solv->rules + solv->featurerules + (p - solv->installed->start);
989   if (r->p && r->d >= 0)
990     solver_disablerule(solv, r);
991 }
992
993 static inline void 
994 reenableupdaterule(Solver *solv, Id p)
995 {
996   Pool *pool = solv->pool;
997   Rule *r;
998
999   MAPCLR(&solv->noupdate, p - solv->installed->start);
1000   r = solv->rules + solv->updaterules + (p - solv->installed->start);
1001   if (r->p)
1002     {    
1003       if (r->d >= 0)
1004         return;
1005       solver_enablerule(solv, r);
1006       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1007         {
1008           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1009           solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
1010         }
1011       return;
1012     }
1013   r = solv->rules + solv->featurerules + (p - solv->installed->start);
1014   if (r->p && r->d < 0)
1015     {
1016       solver_enablerule(solv, r);
1017       IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1018         {
1019           POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1020           solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
1021         }
1022     }
1023 }
1024
1025
1026 /***********************************************************************
1027  ***
1028  ***  Infarch rule part
1029  ***
1030  ***  Infarch rules make sure the solver uses the best architecture of
1031  ***  a package if multiple archetectures are available
1032  ***
1033  ***/
1034
1035 void
1036 solver_addinfarchrules(Solver *solv, Map *addedmap)
1037 {
1038   Pool *pool = solv->pool;
1039   int first, i, j;
1040   Id p, pp, a, aa, bestarch;
1041   Solvable *s, *ps, *bests;
1042   Queue badq, allowedarchs;
1043
1044   queue_init(&badq);
1045   queue_init(&allowedarchs);
1046   solv->infarchrules = solv->nrules;
1047   for (i = 1; i < pool->nsolvables; i++)
1048     {
1049       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
1050         continue;
1051       s = pool->solvables + i;
1052       first = i;
1053       bestarch = 0;
1054       bests = 0;
1055       queue_empty(&allowedarchs);
1056       FOR_PROVIDES(p, pp, s->name)
1057         {
1058           ps = pool->solvables + p;
1059           if (ps->name != s->name || !MAPTST(addedmap, p))
1060             continue;
1061           if (p == i)
1062             first = 0;
1063           if (first)
1064             break;
1065           a = ps->arch;
1066           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1067           if (a != 1 && pool->installed && ps->repo == pool->installed)
1068             {
1069               if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1070                 queue_pushunique(&allowedarchs, ps->arch);      /* also ok to keep this architecture */
1071               continue;         /* ignore installed solvables when calculating the best arch */
1072             }
1073           if (a && a != 1 && (!bestarch || a < bestarch))
1074             {
1075               bestarch = a;
1076               bests = ps;
1077             }
1078         }
1079       if (first)
1080         continue;
1081       /* speed up common case where installed package already has best arch */
1082       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
1083         allowedarchs.count--;   /* installed arch is best */
1084       queue_empty(&badq);
1085       FOR_PROVIDES(p, pp, s->name)
1086         {
1087           ps = pool->solvables + p;
1088           if (ps->name != s->name || !MAPTST(addedmap, p))
1089             continue;
1090           a = ps->arch;
1091           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1092           if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
1093             {
1094               if (pool->installed && ps->repo == pool->installed)
1095                 continue;       /* always ok to keep an installed package */
1096               for (j = 0; j < allowedarchs.count; j++)
1097                 {
1098                   aa = allowedarchs.elements[j];
1099                   if (ps->arch == aa)
1100                     break;
1101                   aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
1102                   if (aa && ((a ^ aa) & 0xffff0000) == 0)
1103                     break;      /* compatible */
1104                 }
1105               if (j == allowedarchs.count)
1106                 queue_push(&badq, p);
1107             }
1108         }
1109       if (!badq.count)
1110         continue;
1111       /* block all solvables in the badq! */
1112       for (j = 0; j < badq.count; j++)
1113         {
1114           p = badq.elements[j];
1115           solver_addrule(solv, -p, 0);
1116         }
1117     }
1118   queue_free(&badq);
1119   queue_free(&allowedarchs);
1120   solv->infarchrules_end = solv->nrules;
1121 }
1122
1123 static inline void
1124 disableinfarchrule(Solver *solv, Id name)
1125 {
1126   Pool *pool = solv->pool;
1127   Rule *r;
1128   int i;
1129   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1130     {
1131       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
1132         solver_disablerule(solv, r);
1133     }
1134 }
1135
1136 static inline void
1137 reenableinfarchrule(Solver *solv, Id name)
1138 {
1139   Pool *pool = solv->pool;
1140   Rule *r;
1141   int i;
1142   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1143     {
1144       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
1145         {
1146           solver_enablerule(solv, r);
1147           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1148             {
1149               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1150               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
1151             }
1152         }
1153     }
1154 }
1155
1156
1157 /***********************************************************************
1158  ***
1159  ***  Dup rule part
1160  ***
1161  ***  Dup rules make sure a package is selected from the specified dup
1162  ***  repositories if an update candidate is included in one of them.
1163  ***
1164  ***/
1165
1166 void
1167 solver_createdupmaps(Solver *solv)
1168 {
1169   Queue *job = &solv->job;
1170   Pool *pool = solv->pool;
1171   Repo *repo;
1172   Id how, what, p, pi, pp, obs, *obsp;
1173   Solvable *s, *ps;
1174   int i;
1175
1176   map_init(&solv->dupmap, pool->nsolvables);
1177   map_init(&solv->dupinvolvedmap, pool->nsolvables);
1178   for (i = 0; i < job->count; i += 2)
1179     {
1180       how = job->elements[i];
1181       what = job->elements[i + 1];
1182       switch (how & SOLVER_JOBMASK)
1183         {
1184         case SOLVER_DISTUPGRADE:
1185           if ((how & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_REPO)
1186             break;
1187           if (what <= 0 || what > pool->nrepos)
1188             break;
1189           repo = pool_id2repo(pool, what);
1190           FOR_REPO_SOLVABLES(repo, p, s)
1191             {
1192               MAPSET(&solv->dupmap, p);
1193               FOR_PROVIDES(pi, pp, s->name)
1194                 {
1195                   ps = pool->solvables + pi;
1196                   if (ps->name != s->name)
1197                     continue;
1198                   MAPSET(&solv->dupinvolvedmap, pi);
1199                 }
1200               if (s->obsoletes)
1201                 {
1202                   /* FIXME: check obsoletes/provides combination */
1203                   obsp = s->repo->idarraydata + s->obsoletes;
1204                   while ((obs = *obsp++) != 0)
1205                     {
1206                       FOR_PROVIDES(pi, pp, obs)
1207                         {
1208                           Solvable *pis = pool->solvables + pi;
1209                           if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pis, obs))
1210                             continue;
1211                           if (pool->obsoleteusescolors && !pool_colormatch(pool, s, pis))
1212                             continue;
1213                           MAPSET(&solv->dupinvolvedmap, pi);
1214                         }
1215                     }
1216                 }
1217             }
1218           break;
1219         default:
1220           break;
1221         }
1222     }
1223   MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
1224 }
1225
1226 void
1227 solver_freedupmaps(Solver *solv)
1228 {
1229   map_free(&solv->dupmap);
1230   map_free(&solv->dupinvolvedmap);
1231 }
1232
1233 void
1234 solver_addduprules(Solver *solv, Map *addedmap)
1235 {
1236   Pool *pool = solv->pool;
1237   Id p, pp;
1238   Solvable *s, *ps;
1239   int first, i;
1240
1241   solv->duprules = solv->nrules;
1242   for (i = 1; i < pool->nsolvables; i++)
1243     {
1244       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
1245         continue;
1246       s = pool->solvables + i;
1247       first = i;
1248       FOR_PROVIDES(p, pp, s->name)
1249         {
1250           ps = pool->solvables + p;
1251           if (ps->name != s->name || !MAPTST(addedmap, p))
1252             continue;
1253           if (p == i)
1254             first = 0;
1255           if (first)
1256             break;
1257           if (!MAPTST(&solv->dupinvolvedmap, p))
1258             continue;
1259           if (solv->installed && ps->repo == solv->installed)
1260             {
1261               if (!solv->updatemap.size)
1262                 map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
1263               MAPSET(&solv->updatemap, p - solv->installed->start);
1264               if (!MAPTST(&solv->dupmap, p))
1265                 {
1266                   Id ip, ipp;
1267                   /* is installed identical to a good one? */
1268                   FOR_PROVIDES(ip, ipp, ps->name)
1269                     {
1270                       Solvable *is = pool->solvables + ip;
1271                       if (!MAPTST(&solv->dupmap, ip))
1272                         continue;
1273                       if (is->evr == ps->evr && solvable_identical(ps, is))
1274                         break;
1275                     }
1276                   if (!ip)
1277                     solver_addrule(solv, -p, 0);        /* no match, sorry */
1278                 }
1279             }
1280           else if (!MAPTST(&solv->dupmap, p))
1281             solver_addrule(solv, -p, 0);
1282         }
1283     }
1284   solv->duprules_end = solv->nrules;
1285 }
1286
1287
1288 static inline void
1289 disableduprule(Solver *solv, Id name)
1290 {
1291   Pool *pool = solv->pool;
1292   Rule *r;
1293   int i;
1294   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) 
1295     {    
1296       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
1297         solver_disablerule(solv, r);
1298     }    
1299 }
1300
1301 static inline void 
1302 reenableduprule(Solver *solv, Id name)
1303 {
1304   Pool *pool = solv->pool;
1305   Rule *r;
1306   int i;
1307   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++) 
1308     {    
1309       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
1310         {
1311           solver_enablerule(solv, r);
1312           IF_POOLDEBUG (SAT_DEBUG_SOLUTIONS)
1313             {
1314               POOL_DEBUG(SAT_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1315               solver_printruleclass(solv, SAT_DEBUG_SOLUTIONS, r);
1316             }
1317         }
1318     }
1319 }
1320
1321
1322 /***********************************************************************
1323  ***
1324  ***  Policy rule disabling/reenabling
1325  ***
1326  ***  Disable all policy rules that conflict with our jobs. If a job
1327  ***  gets disabled later on, reenable the involved policy rules again.
1328  ***
1329  ***/
1330
1331 #define DISABLE_UPDATE  1
1332 #define DISABLE_INFARCH 2
1333 #define DISABLE_DUP     3
1334
1335 static void
1336 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
1337 {
1338   Pool *pool = solv->pool;
1339   Id select, p, pp;
1340   Repo *installed;
1341   Solvable *s;
1342   int i, j, set, qstart, pass;
1343   Map omap;
1344
1345   installed = solv->installed;
1346   select = how & SOLVER_SELECTMASK;
1347   switch (how & SOLVER_JOBMASK)
1348     {
1349     case SOLVER_INSTALL:
1350       set = how & SOLVER_SETMASK;
1351       if (!(set & SOLVER_NOAUTOSET))
1352         {
1353           /* automatically add set bits by analysing the job */
1354           if (select == SOLVER_SOLVABLE)
1355             set |= SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
1356           else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
1357             {
1358               Reldep *rd = GETRELDEP(pool, what);
1359               if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
1360                 {
1361 #if !defined(DEBIAN_SEMANTICS)
1362                   const char *evr = id2str(pool, rd->evr);
1363                   if (strchr(evr, '-'))
1364                     set |= SOLVER_SETEVR;
1365                   else
1366                     set |= SOLVER_SETEV;
1367 #else
1368                   set |= SOLVER_SETEVR;
1369 #endif
1370                 }
1371               if (rd->flags <= 7 && ISRELDEP(rd->name))
1372                 rd = GETRELDEP(pool, rd->name);
1373               if (rd->flags == REL_ARCH)
1374                 set |= SOLVER_SETARCH;
1375             }
1376         }
1377       else
1378         set &= ~SOLVER_NOAUTOSET;
1379       if (!set)
1380         return;
1381       if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
1382         {
1383           if (select == SOLVER_SOLVABLE)
1384             queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
1385           else
1386             {
1387               int qcnt = q->count;
1388               FOR_JOB_SELECT(p, pp, select, what)
1389                 {
1390                   s = pool->solvables + p;
1391                   /* unify names */
1392                   for (i = qcnt; i < q->count; i += 2)
1393                     if (q->elements[i + 1] == s->name)
1394                       break;
1395                   if (i < q->count)
1396                     continue;
1397                   queue_push2(q, DISABLE_INFARCH, s->name);
1398                 }
1399             }
1400         }
1401       if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
1402         {
1403           if (select == SOLVER_SOLVABLE)
1404             queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
1405           else
1406             {
1407               int qcnt = q->count;
1408               FOR_JOB_SELECT(p, pp, select, what)
1409                 {
1410                   s = pool->solvables + p;
1411                   /* unify names */
1412                   for (i = qcnt; i < q->count; i += 2)
1413                     if (q->elements[i + 1] == s->name)
1414                       break;
1415                   if (i < q->count)
1416                     continue;
1417                   queue_push2(q, DISABLE_DUP, s->name);
1418                 }
1419             }
1420         }
1421       if (!installed)
1422         return;
1423       /* now the hard part: disable some update rules */
1424
1425       /* first check if we have noobs or installed packages in the job */
1426       FOR_JOB_SELECT(p, pp, select, what)
1427         {
1428           if (pool->solvables[p].repo == installed)
1429             {
1430               if (select == SOLVER_SOLVABLE)
1431                 queue_push2(q, DISABLE_UPDATE, what);
1432               return;
1433             }
1434           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
1435             return;
1436         }
1437
1438       /* all job packages obsolete */
1439       qstart = q->count;
1440       pass = 0;
1441       memset(&omap, 0, sizeof(omap));
1442       FOR_JOB_SELECT(p, pp, select, what)
1443         {
1444           Id p2, pp2;
1445
1446           if (pass == 1)
1447             map_grow(&omap, installed->end - installed->start);
1448           s = pool->solvables + p;
1449           if (s->obsoletes)
1450             {
1451               Id obs, *obsp;
1452               obsp = s->repo->idarraydata + s->obsoletes;
1453               while ((obs = *obsp++) != 0)
1454                 FOR_PROVIDES(p2, pp2, obs)
1455                   {
1456                     Solvable *ps = pool->solvables + p2;
1457                     if (ps->repo != installed)
1458                       continue;
1459                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
1460                       continue;
1461                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1462                       continue;
1463                     if (pass)
1464                       MAPSET(&omap, p2 - installed->start);
1465                     else
1466                       queue_push2(q, DISABLE_UPDATE, p2);
1467                   }
1468             }
1469           FOR_PROVIDES(p2, pp2, s->name)
1470             {
1471               Solvable *ps = pool->solvables + p2;
1472               if (ps->repo != installed)
1473                 continue;
1474               if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
1475                 continue;
1476               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1477                 continue;
1478               if (pass)
1479                 MAPSET(&omap, p2 - installed->start);
1480               else
1481                 queue_push2(q, DISABLE_UPDATE, p2);
1482             }
1483           if (pass)
1484             {
1485               for (i = j = qstart; i < q->count; i += 2)
1486                 {
1487                   if (MAPTST(&omap, q->elements[i + 1] - installed->start))
1488                     {
1489                       MAPCLR(&omap, q->elements[i + 1] - installed->start);
1490                       q->elements[j + 1] = q->elements[i + 1];
1491                       j += 2;
1492                     }
1493                 }
1494               queue_truncate(q, j);
1495             }
1496           if (q->count == qstart)
1497             break;
1498           pass++;
1499         }
1500       if (omap.size)
1501         map_free(&omap);
1502
1503       if (qstart == q->count)
1504         return;         /* nothing to prune */
1505       if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
1506         return;         /* all is set */
1507
1508       /* now that we know which installed packages are obsoleted check each of them */
1509       for (i = j = qstart; i < q->count; i += 2)
1510         {
1511           Solvable *is = pool->solvables + q->elements[i + 1];
1512           FOR_JOB_SELECT(p, pp, select, what)
1513             {
1514               int illegal = 0;
1515               s = pool->solvables + p;
1516               if ((set & SOLVER_SETEVR) != 0)
1517                 illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
1518               if ((set & SOLVER_SETARCH) != 0)
1519                 illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
1520               if ((set & SOLVER_SETVENDOR) != 0)
1521                 illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
1522               illegal = policy_is_illegal(solv, is, s, illegal);
1523               if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
1524                 {
1525                   /* it's ok if the EV is different */
1526                   if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
1527                     illegal = 0;
1528                 }
1529               if (illegal)
1530                 break;
1531             }
1532           if (!p)
1533             {   
1534               /* no package conflicts with the update rule */
1535               /* thus keep the DISABLE_UPDATE */
1536               q->elements[j + 1] = q->elements[i + 1];
1537               j += 2;
1538             }
1539         }
1540       queue_truncate(q, j);
1541       return;
1542
1543     case SOLVER_ERASE:
1544       if (!installed)
1545         break;
1546       FOR_JOB_SELECT(p, pp, select, what)
1547         if (pool->solvables[p].repo == installed)
1548           queue_push2(q, DISABLE_UPDATE, p);
1549       return;
1550     default:
1551       return;
1552     }
1553 }
1554
1555 /* disable all policy rules that are in conflict with our job list */
1556 void
1557 solver_disablepolicyrules(Solver *solv)
1558 {
1559   Queue *job = &solv->job;
1560   int i, j;
1561   Queue allq;
1562   Rule *r;
1563   Id lastjob = -1;
1564   Id allqbuf[128];
1565
1566   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
1567
1568   for (i = solv->jobrules; i < solv->jobrules_end; i++)
1569     {
1570       r = solv->rules + i;
1571       if (r->d < 0)     /* disabled? */
1572         continue;
1573       j = solv->ruletojob.elements[i - solv->jobrules];
1574       if (j == lastjob)
1575         continue;
1576       lastjob = j;
1577       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
1578     }
1579   if (solv->cleandepsmap.size)
1580     {
1581       solver_createcleandepsmap(solv);
1582       for (i = solv->installed->start; i < solv->installed->end; i++)
1583         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1584           queue_push2(&allq, DISABLE_UPDATE, i);
1585     }
1586   MAPZERO(&solv->noupdate);
1587   for (i = 0; i < allq.count; i += 2)
1588     {
1589       Id type = allq.elements[i], arg = allq.elements[i + 1];
1590       switch(type)
1591         {
1592         case DISABLE_UPDATE:
1593           disableupdaterule(solv, arg);
1594           break;
1595         case DISABLE_INFARCH:
1596           disableinfarchrule(solv, arg);
1597           break;
1598         case DISABLE_DUP:
1599           disableduprule(solv, arg);
1600           break;
1601         default:
1602           break;
1603         }
1604     }
1605   queue_free(&allq);
1606 }
1607
1608 /* we just disabled job #jobidx, now reenable all policy rules that were
1609  * disabled because of this job */
1610 void
1611 solver_reenablepolicyrules(Solver *solv, int jobidx)
1612 {
1613   Queue *job = &solv->job;
1614   int i, j;
1615   Queue q, allq;
1616   Rule *r;
1617   Id lastjob = -1;
1618   Id qbuf[32], allqbuf[128];
1619
1620   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
1621   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
1622   jobtodisablelist(solv, job->elements[jobidx], job->elements[jobidx + 1], &q);
1623   if (!q.count)
1624     return;
1625   for (i = solv->jobrules; i < solv->jobrules_end; i++)
1626     {
1627       r = solv->rules + i;
1628       if (r->d < 0)     /* disabled? */
1629         continue;
1630       j = solv->ruletojob.elements[i - solv->jobrules];
1631       if (j == lastjob)
1632         continue;
1633       lastjob = j;
1634       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
1635     }
1636   if (solv->cleandepsmap.size)
1637     {
1638       solver_createcleandepsmap(solv);
1639       for (i = solv->installed->start; i < solv->installed->end; i++)
1640         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1641           queue_push2(&allq, DISABLE_UPDATE, i);
1642     }
1643   for (j = 0; j < q.count; j += 2)
1644     {
1645       Id type = q.elements[j], arg = q.elements[j + 1];
1646       for (i = 0; i < allq.count; i += 2)
1647         if (allq.elements[i] == type && allq.elements[i + 1] == arg)
1648           break;
1649       if (i < allq.count)
1650         continue;       /* still disabled */
1651       switch(type)
1652         {
1653         case DISABLE_UPDATE:
1654           reenableupdaterule(solv, arg);
1655           break;
1656         case DISABLE_INFARCH:
1657           reenableinfarchrule(solv, arg);
1658           break;
1659         case DISABLE_DUP:
1660           reenableduprule(solv, arg);
1661           break;
1662         }
1663     }
1664   queue_free(&allq);
1665   queue_free(&q);
1666 }
1667
1668
1669 /***********************************************************************
1670  ***
1671  ***  Rule info part, tell the user what the rule is about.
1672  ***
1673  ***/
1674
1675 static void
1676 addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
1677 {
1678   Pool *pool = solv->pool;
1679   Rule *r;
1680   Id w2, op, od, ow2;
1681
1682   /* check if this creates the rule we're searching for */
1683   r = solv->rules + solv->ruleinfoq->elements[0];
1684   op = r->p;
1685   od = r->d < 0 ? -r->d - 1 : r->d;
1686   ow2 = 0;
1687
1688   /* normalize */
1689   w2 = d > 0 ? 0 : d;
1690   if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
1691     {
1692       w2 = pool->whatprovidesdata[d];
1693       d = 0;
1694
1695     }
1696   if (p > 0 && d < 0)           /* this hack is used for buddy deps */
1697     {
1698       w2 = p;
1699       p = d;
1700     }
1701
1702   if (d > 0)
1703     {
1704       if (p != op && !od)
1705         return;
1706       if (d != od)
1707         {
1708           Id *dp = pool->whatprovidesdata + d;
1709           Id *odp = pool->whatprovidesdata + od;
1710           while (*dp)
1711             if (*dp++ != *odp++)
1712               return;
1713           if (*odp)
1714             return;
1715         }
1716       w2 = 0;
1717       /* handle multiversion conflict rules */
1718       if (p < 0 && pool->whatprovidesdata[d] < 0)
1719         {
1720           w2 = pool->whatprovidesdata[d];
1721           /* XXX: free memory */
1722         }
1723     }
1724   else
1725     {
1726       if (od)
1727         return;
1728       ow2 = r->w2;
1729       if (p > w2)
1730         {
1731           if (w2 != op || p != ow2)
1732             return;
1733         }
1734       else
1735         {
1736           if (p != op || w2 != ow2)
1737             return;
1738         }
1739     }
1740   /* yep, rule matches. record info */
1741   queue_push(solv->ruleinfoq, type);
1742   if (type == SOLVER_RULE_RPM_SAME_NAME)
1743     {
1744       /* we normalize same name order */
1745       queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
1746       queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
1747     }
1748   else
1749     {
1750       queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
1751       queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
1752     }
1753   queue_push(solv->ruleinfoq, dep);
1754 }
1755
1756 static int
1757 solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
1758 {
1759   const Id *a = ap, *b = bp;
1760   int r;
1761
1762   r = a[0] - b[0];
1763   if (r)
1764     return r;
1765   r = a[1] - b[1];
1766   if (r)
1767     return r;
1768   r = a[2] - b[2];
1769   if (r)
1770     return r;
1771   r = a[3] - b[3];
1772   if (r)
1773     return r;
1774   return 0;
1775 }
1776
1777 int
1778 solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
1779 {
1780   Pool *pool = solv->pool;
1781   Rule *r = solv->rules + rid;
1782   int i, j;
1783
1784   queue_empty(rq);
1785   if (rid <= 0 || rid >= solv->rpmrules_end)
1786     {
1787       Id type, from, to, dep;
1788       type = solver_ruleinfo(solv, rid, &from, &to, &dep);
1789       queue_push(rq, type);
1790       queue_push(rq, from);
1791       queue_push(rq, to);
1792       queue_push(rq, dep);
1793       return 1;
1794     }
1795   if (r->p >= 0)
1796     return 0;
1797   queue_push(rq, rid);
1798   solv->ruleinfoq = rq;
1799   solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
1800   /* also try reverse direction for conflicts */
1801   if ((r->d == 0 || r->d == -1) && r->w2 < 0)
1802     solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
1803   solv->ruleinfoq = 0;
1804   queue_shift(rq);
1805   /* now sort & unify em */
1806   if (!rq->count)
1807     return 0;
1808   sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
1809   /* throw out identical entries */
1810   for (i = j = 0; i < rq->count; i += 4)
1811     {
1812       if (j)
1813         {
1814           if (rq->elements[i] == rq->elements[j - 4] && 
1815               rq->elements[i + 1] == rq->elements[j - 3] &&
1816               rq->elements[i + 2] == rq->elements[j - 2] &&
1817               rq->elements[i + 3] == rq->elements[j - 1])
1818             continue;
1819         }
1820       rq->elements[j++] = rq->elements[i];
1821       rq->elements[j++] = rq->elements[i + 1];
1822       rq->elements[j++] = rq->elements[i + 2];
1823       rq->elements[j++] = rq->elements[i + 3];
1824     }
1825   rq->count = j;
1826   return j / 4;
1827 }
1828
1829 SolverRuleinfo
1830 solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
1831 {
1832   Pool *pool = solv->pool;
1833   Rule *r = solv->rules + rid;
1834   SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
1835
1836   if (fromp)
1837     *fromp = 0;
1838   if (top)
1839     *top = 0;
1840   if (depp)
1841     *depp = 0;
1842   if (rid > 0 && rid < solv->rpmrules_end)
1843     {
1844       Queue rq;
1845       int i;
1846
1847       if (r->p >= 0)
1848         return SOLVER_RULE_RPM;
1849       if (fromp)
1850         *fromp = -r->p;
1851       queue_init(&rq);
1852       queue_push(&rq, rid);
1853       solv->ruleinfoq = &rq;
1854       solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
1855       /* also try reverse direction for conflicts */
1856       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
1857         solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
1858       solv->ruleinfoq = 0;
1859       type = SOLVER_RULE_RPM;
1860       for (i = 1; i < rq.count; i += 4)
1861         {
1862           Id qt, qo, qp, qd;
1863           qt = rq.elements[i];
1864           qp = rq.elements[i + 1];
1865           qo = rq.elements[i + 2];
1866           qd = rq.elements[i + 3];
1867           if (type == SOLVER_RULE_RPM || type > qt)
1868             {
1869               type = qt;
1870               if (fromp)
1871                 *fromp = qp;
1872               if (top)
1873                 *top = qo;
1874               if (depp)
1875                 *depp = qd;
1876             }
1877         }
1878       queue_free(&rq);
1879       return type;
1880     }
1881   if (rid >= solv->jobrules && rid < solv->jobrules_end)
1882     {
1883       Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
1884       if (fromp)
1885         *fromp = jidx;
1886       if (top)
1887         *top = solv->job.elements[jidx];
1888       if (depp)
1889         *depp = solv->job.elements[jidx + 1];
1890       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
1891         return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
1892       return SOLVER_RULE_JOB;
1893     }
1894   if (rid >= solv->updaterules && rid < solv->updaterules_end)
1895     {
1896       if (fromp)
1897         *fromp = solv->installed->start + (rid - solv->updaterules);
1898       return SOLVER_RULE_UPDATE;
1899     }
1900   if (rid >= solv->featurerules && rid < solv->featurerules_end)
1901     {
1902       if (fromp)
1903         *fromp = solv->installed->start + (rid - solv->featurerules);
1904       return SOLVER_RULE_FEATURE;
1905     }
1906   if (rid >= solv->duprules && rid < solv->duprules_end)
1907     {
1908       if (fromp)
1909         *fromp = -r->p;
1910       if (depp)
1911         *depp = pool->solvables[-r->p].name;
1912       return SOLVER_RULE_DISTUPGRADE;
1913     }
1914   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
1915     {
1916       if (fromp)
1917         *fromp = -r->p;
1918       if (depp)
1919         *depp = pool->solvables[-r->p].name;
1920       return SOLVER_RULE_INFARCH;
1921     }
1922   if (rid >= solv->choicerules && rid < solv->choicerules_end)
1923     {
1924       return SOLVER_RULE_CHOICE;
1925     }
1926   if (rid >= solv->learntrules)
1927     {
1928       return SOLVER_RULE_LEARNT;
1929     }
1930   return SOLVER_RULE_UNKNOWN;
1931 }
1932
1933 void
1934 solver_addchoicerules(Solver *solv)
1935 {
1936   Pool *pool = solv->pool;
1937   Map m, mneg;
1938   Rule *r;
1939   Queue q, qi;
1940   int i, j, rid, havechoice;
1941   Id p, d, *pp;
1942   Id p2, pp2;
1943   Solvable *s, *s2;
1944
1945   solv->choicerules = solv->nrules;
1946   if (!pool->installed)
1947     {
1948       solv->choicerules_end = solv->nrules;
1949       return;
1950     }
1951   solv->choicerules_ref = sat_calloc(solv->rpmrules_end, sizeof(Id));
1952   queue_init(&q);
1953   queue_init(&qi);
1954   map_init(&m, pool->nsolvables);
1955   map_init(&mneg, pool->nsolvables);
1956   /* set up negative assertion map from infarch and dup rules */
1957   for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
1958     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
1959       MAPSET(&mneg, -r->p);
1960   for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
1961     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
1962       MAPSET(&mneg, -r->p);
1963   for (rid = 1; rid < solv->rpmrules_end ; rid++)
1964     {
1965       r = solv->rules + rid;
1966       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
1967         continue;       /* only look at requires rules */
1968       // solver_printrule(solv, SAT_DEBUG_RESULT, r);
1969       queue_empty(&q);
1970       queue_empty(&qi);
1971       havechoice = 0;
1972       FOR_RULELITERALS(p, pp, r)
1973         {
1974           if (p < 0)
1975             continue;
1976           s = pool->solvables + p;
1977           if (!s->repo)
1978             continue;
1979           if (s->repo == pool->installed)
1980             {
1981               queue_push(&q, p);
1982               continue;
1983             }
1984           /* check if this package is "blocked" by a installed package */
1985           s2 = 0;
1986           FOR_PROVIDES(p2, pp2, s->name)
1987             {
1988               s2 = pool->solvables + p2;
1989               if (s2->repo != pool->installed)
1990                 continue;
1991               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
1992                 continue;
1993               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
1994                 continue;
1995               break;
1996             }
1997           if (p2)
1998             {
1999               /* found installed package p2 that we can update to p */
2000               if (MAPTST(&mneg, p))
2001                 continue;
2002               if (policy_is_illegal(solv, s2, s, 0))
2003                 continue;
2004               queue_push(&qi, p2);
2005               queue_push(&q, p);
2006               continue;
2007             }
2008           if (s->obsoletes)
2009             {
2010               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2011               s2 = 0;
2012               while ((obs = *obsp++) != 0)
2013                 {
2014                   FOR_PROVIDES(p2, pp2, obs)
2015                     {
2016                       s2 = pool->solvables + p2;
2017                       if (s2->repo != pool->installed)
2018                         continue;
2019                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
2020                         continue;
2021                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
2022                         continue;
2023                       break;
2024                     }
2025                   if (p2)
2026                     break;
2027                 }
2028               if (obs)
2029                 {
2030                   /* found installed package p2 that we can update to p */
2031                   if (MAPTST(&mneg, p))
2032                     continue;
2033                   if (policy_is_illegal(solv, s2, s, 0))
2034                     continue;
2035                   queue_push(&qi, p2);
2036                   queue_push(&q, p);
2037                   continue;
2038                 }
2039             }
2040           /* package p is independent of the installed ones */
2041           havechoice = 1;
2042         }
2043       if (!havechoice || !q.count)
2044         continue;       /* no choice */
2045
2046       /* now check the update rules of the installed package.
2047        * if all packages of the update rules are contained in
2048        * the dependency rules, there's no need to set up the choice rule */
2049       map_empty(&m);
2050       FOR_RULELITERALS(p, pp, r)
2051         if (p > 0)
2052           MAPSET(&m, p);
2053       for (i = 0; i < qi.count; i++)
2054         {
2055           if (!qi.elements[i])
2056             continue;
2057           Rule *ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
2058           if (!ur->p)
2059             ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
2060           if (!ur->p)
2061             continue;
2062           FOR_RULELITERALS(p, pp, ur)
2063             if (!MAPTST(&m, p))
2064               break;
2065           if (p)
2066             break;
2067           for (j = i + 1; j < qi.count; j++)
2068             if (qi.elements[i] == qi.elements[j])
2069               qi.elements[j] = 0;
2070         }
2071       if (i == qi.count)
2072         {
2073 #if 0
2074           printf("skipping choice ");
2075           solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
2076 #endif
2077           continue;
2078         }
2079       d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
2080       solver_addrule(solv, r->p, d);
2081       queue_push(&solv->weakruleq, solv->nrules - 1);
2082       solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
2083 #if 0
2084       printf("OLD ");
2085       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
2086       printf("WEAK CHOICE ");
2087       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + solv->nrules - 1);
2088 #endif
2089     }
2090   queue_free(&q);
2091   queue_free(&qi);
2092   map_free(&m);
2093   map_free(&mneg);
2094   solv->choicerules_end = solv->nrules;
2095 }
2096
2097 /* called when a choice rule is disabled by analyze_unsolvable. We also
2098  * have to disable all other choice rules so that the best packages get
2099  * picked */
2100 void
2101 solver_disablechoicerules(Solver *solv, Rule *r)
2102 {
2103   Id rid, p, *pp;
2104   Pool *pool = solv->pool;
2105   Map m;
2106   Rule *or;
2107
2108   or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
2109   map_init(&m, pool->nsolvables);
2110   FOR_RULELITERALS(p, pp, or)
2111     if (p > 0)
2112       MAPSET(&m, p);
2113   FOR_RULELITERALS(p, pp, r)
2114     if (p > 0)
2115       MAPCLR(&m, p);
2116   for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
2117     {
2118       r = solv->rules + rid;
2119       if (r->d < 0)
2120         continue;
2121       or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
2122       FOR_RULELITERALS(p, pp, or)
2123         if (p > 0 && MAPTST(&m, p))
2124           break;
2125       if (p)
2126         solver_disablerule(solv, r);
2127     }
2128 }
2129
2130 static void solver_createcleandepsmap(Solver *solv)
2131 {
2132   Pool *pool = solv->pool;
2133   Repo *installed = solv->installed;
2134   Queue *job = &solv->job;
2135   Map userinstalled;
2136   Map im;
2137   Map installedm;
2138   Rule *r;
2139   Id rid, how, what, select;
2140   Id p, pp, ip, *jp;
2141   Id req, *reqp, sup, *supp;
2142   Solvable *s;
2143   Queue iq;
2144   int i;
2145
2146   map_init(&userinstalled, installed->end - installed->start);
2147   map_init(&im, pool->nsolvables);
2148   map_init(&installedm, pool->nsolvables);
2149   map_empty(&solv->cleandepsmap);
2150   queue_init(&iq);
2151
2152   for (i = 0; i < job->count; i += 2)
2153     {
2154       how = job->elements[i];
2155       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
2156         {
2157           what = job->elements[i + 1];
2158           select = how & SOLVER_SELECTMASK;
2159           FOR_JOB_SELECT(p, pp, select, what)
2160             if (pool->solvables[p].repo == installed)
2161               MAPSET(&userinstalled, p - installed->start);
2162         }
2163     }
2164   /* add all positive elements (e.g. locks) to "userinstalled" */
2165   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2166     {
2167       r = solv->rules + rid;
2168       if (r->d < 0)
2169         continue;
2170       FOR_RULELITERALS(p, jp, r)
2171         if (p > 0 && pool->solvables[p].repo == installed)
2172           MAPSET(&userinstalled, p - installed->start);
2173     }
2174   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2175     {
2176       r = solv->rules + rid;
2177       if (r->p >= 0 || r->d != 0)
2178         continue;       /* disabled or not erase */
2179       p = -r->p;
2180       if (pool->solvables[p].repo != installed)
2181         continue;
2182       MAPCLR(&userinstalled, p - installed->start);
2183       i = solv->ruletojob.elements[rid - solv->jobrules];
2184       how = job->elements[i];
2185       if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
2186         queue_push(&iq, p);
2187     }
2188   for (p = installed->start; p < installed->end; p++)
2189     {
2190       if (pool->solvables[p].repo != installed)
2191         continue;
2192       MAPSET(&installedm, p);
2193       MAPSET(&im, p);
2194     }
2195
2196   while (iq.count)
2197     {
2198       ip = queue_shift(&iq);
2199       s = pool->solvables + ip;
2200       if (!MAPTST(&im, ip))
2201         continue;
2202       if (!MAPTST(&installedm, ip))
2203         continue;
2204       if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
2205         continue;
2206       MAPCLR(&im, ip);
2207 #ifdef CLEANDEPSDEBUG
2208       printf("hello %s\n", solvable2str(pool, s));
2209 #endif
2210       if (s->requires)
2211         {
2212           reqp = s->repo->idarraydata + s->requires;
2213           while ((req = *reqp++) != 0)
2214             {
2215               if (req == SOLVABLE_PREREQMARKER)
2216                 continue;
2217 #if 0
2218               /* count number of installed packages that match */
2219               count = 0;
2220               FOR_PROVIDES(p, pp, req)
2221                 if (MAPTST(&installedm, p))
2222                   count++;
2223               if (count > 1)
2224                 continue;
2225 #endif
2226               FOR_PROVIDES(p, pp, req)
2227                 {
2228                   if (MAPTST(&im, p))
2229                     {
2230 #ifdef CLEANDEPSDEBUG
2231                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2232 #endif
2233                       queue_push(&iq, p);
2234                     }
2235                 }
2236             }
2237         }
2238       if (s->recommends)
2239         {
2240           reqp = s->repo->idarraydata + s->recommends;
2241           while ((req = *reqp++) != 0)
2242             {
2243 #if 0
2244               count = 0;
2245               FOR_PROVIDES(p, pp, req)
2246                 if (MAPTST(&installedm, p))
2247                   count++;
2248               if (count > 1)
2249                 continue;
2250 #endif
2251               FOR_PROVIDES(p, pp, req)
2252                 {
2253                   if (MAPTST(&im, p))
2254                     {
2255 #ifdef CLEANDEPSDEBUG
2256                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2257 #endif
2258                       queue_push(&iq, p);
2259                     }
2260                 }
2261             }
2262         }
2263       if (!iq.count)
2264         {
2265           /* supplements pass */
2266           for (ip = solv->installed->start; ip < solv->installed->end; ip++)
2267             {
2268               if (!MAPTST(&installedm, ip))
2269                 continue;
2270               s = pool->solvables + ip;
2271               if (!s->supplements)
2272                 continue;
2273               if (!MAPTST(&im, ip))
2274                 continue;
2275               supp = s->repo->idarraydata + s->supplements;
2276               while ((sup = *supp++) != 0)
2277                 if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
2278                   break;
2279               /* no longer supplemented, also erase */
2280               if (sup)
2281                 {
2282 #ifdef CLEANDEPSDEBUG
2283                   printf("%s supplemented\n", solvid2str(pool, ip));
2284 #endif
2285                   queue_push(&iq, ip);
2286                 }
2287             }
2288         }
2289     }
2290
2291   /* turn userinstalled into remove set for pruning */
2292   map_empty(&userinstalled);
2293   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2294     {
2295       r = solv->rules + rid;
2296       if (r->p >= 0 || r->d != 0)
2297         continue;       /* disabled or not erase */
2298       p = -r->p;
2299       MAPCLR(&im, p);
2300       if (pool->solvables[p].repo == installed)
2301         MAPSET(&userinstalled, p - installed->start);
2302     }
2303   for (p = installed->start; p < installed->end; p++)
2304     if (MAPTST(&im, p))
2305       queue_push(&iq, p);
2306   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2307     {
2308       r = solv->rules + rid;
2309       if (r->d < 0)
2310         continue;
2311       FOR_RULELITERALS(p, jp, r)
2312         if (p > 0)
2313           queue_push(&iq, p);
2314     }
2315   /* also put directly addressed packages on the install queue
2316    * so we can mark patterns as installed */
2317   for (i = 0; i < job->count; i += 2)
2318     {
2319       how = job->elements[i];
2320       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
2321         {
2322           what = job->elements[i + 1];
2323           select = how & SOLVER_SELECTMASK;
2324           if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
2325             queue_push(&iq, what);
2326         }
2327     }
2328   while (iq.count)
2329     {
2330       ip = queue_shift(&iq);
2331       s = pool->solvables + ip;
2332 #ifdef CLEANDEPSDEBUG
2333       printf("bye %s\n", solvable2str(pool, s));
2334 #endif
2335       if (s->requires)
2336         {
2337           reqp = s->repo->idarraydata + s->requires;
2338           while ((req = *reqp++) != 0)
2339             {
2340               FOR_PROVIDES(p, pp, req)
2341                 {
2342                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
2343                     {
2344                       if (p == ip)
2345                         continue;
2346                       if (MAPTST(&userinstalled, p - installed->start))
2347                         continue;
2348 #ifdef CLEANDEPSDEBUG
2349                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2350 #endif
2351                       MAPSET(&im, p);
2352                       queue_push(&iq, p);
2353                     }
2354                 }
2355             }
2356         }
2357       if (s->recommends)
2358         {
2359           reqp = s->repo->idarraydata + s->recommends;
2360           while ((req = *reqp++) != 0)
2361             {
2362               FOR_PROVIDES(p, pp, req)
2363                 {
2364                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
2365                     {
2366                       if (p == ip)
2367                         continue;
2368                       if (MAPTST(&userinstalled, p - installed->start))
2369                         continue;
2370 #ifdef CLEANDEPSDEBUG
2371                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2372 #endif
2373                       MAPSET(&im, p);
2374                       queue_push(&iq, p);
2375                     }
2376                 }
2377             }
2378         }
2379       if (!iq.count)
2380         {
2381           /* supplements pass */
2382           for (ip = installed->start; ip < installed->end; ip++)
2383             {
2384               if (!MAPTST(&installedm, ip))
2385                 continue;
2386               if (MAPTST(&userinstalled, ip - installed->start))
2387                 continue;
2388               s = pool->solvables + ip;
2389               if (!s->supplements)
2390                 continue;
2391               if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
2392                 continue;
2393               supp = s->repo->idarraydata + s->supplements;
2394               while ((sup = *supp++) != 0)
2395                 if (dep_possible(solv, sup, &im))
2396                   break;
2397               if (sup)
2398                 {
2399 #ifdef CLEANDEPSDEBUG
2400                   printf("%s supplemented\n", solvid2str(pool, ip));
2401 #endif
2402                   MAPSET(&im, ip);
2403                   queue_push(&iq, ip);
2404                 }
2405             }
2406         }
2407     }
2408     
2409   queue_free(&iq);
2410   for (p = installed->start; p < installed->end; p++)
2411     {
2412       if (pool->solvables[p].repo != installed)
2413         continue;
2414       if (!MAPTST(&im, p))
2415         MAPSET(&solv->cleandepsmap, p - installed->start);
2416     }
2417   map_free(&im);
2418   map_free(&installedm);
2419   map_free(&userinstalled);
2420 }
2421
2422
2423 /* EOF */