635bb551200c5ebe91a1deaf26e28ea2e53da7ab
[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 (select == SOLVER_SOLVABLE)
1352         set |= SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
1353       else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
1354         {
1355           Reldep *rd = GETRELDEP(pool, what);
1356           if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
1357             {
1358 #if !defined(DEBIAN_SEMANTICS)
1359               const char *evr = id2str(pool, rd->evr);
1360               if (strchr(evr, '-'))
1361                 set |= SOLVER_SETEVR;
1362               else
1363                 set |= SOLVER_SETEV;
1364 #else
1365               set |= SOLVER_SETEVR;
1366 #endif
1367             }
1368           if (rd->flags <= 7 && ISRELDEP(rd->name))
1369             rd = GETRELDEP(pool, rd->name);
1370           if (rd->flags == REL_ARCH)
1371             set |= SOLVER_SETARCH;
1372         }
1373       if (!set)
1374         return;
1375       if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
1376         {
1377           if (select == SOLVER_SOLVABLE)
1378             queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
1379           else
1380             {
1381               int qcnt = q->count;
1382               FOR_JOB_SELECT(p, pp, select, what)
1383                 {
1384                   s = pool->solvables + p;
1385                   /* unify names */
1386                   for (i = qcnt; i < q->count; i += 2)
1387                     if (q->elements[i + 1] == s->name)
1388                       break;
1389                   if (i < q->count)
1390                     continue;
1391                   queue_push2(q, DISABLE_INFARCH, s->name);
1392                 }
1393             }
1394         }
1395       if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
1396         {
1397           if (select == SOLVER_SOLVABLE)
1398             queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
1399           else
1400             {
1401               int qcnt = q->count;
1402               FOR_JOB_SELECT(p, pp, select, what)
1403                 {
1404                   s = pool->solvables + p;
1405                   /* unify names */
1406                   for (i = qcnt; i < q->count; i += 2)
1407                     if (q->elements[i + 1] == s->name)
1408                       break;
1409                   if (i < q->count)
1410                     continue;
1411                   queue_push2(q, DISABLE_DUP, s->name);
1412                 }
1413             }
1414         }
1415       if (!installed)
1416         return;
1417       /* now the hard part: disable some update rules */
1418
1419       /* first check if we have noobs or installed packages in the job */
1420       FOR_JOB_SELECT(p, pp, select, what)
1421         {
1422           if (pool->solvables[p].repo == installed)
1423             {
1424               if (select == SOLVER_SOLVABLE)
1425                 queue_push2(q, DISABLE_UPDATE, what);
1426               return;
1427             }
1428           if (solv->noobsoletes.size && MAPTST(&solv->noobsoletes, p))
1429             return;
1430         }
1431
1432       /* all job packages obsolete */
1433       qstart = q->count;
1434       pass = 0;
1435       memset(&omap, 0, sizeof(omap));
1436       FOR_JOB_SELECT(p, pp, select, what)
1437         {
1438           Id p2, pp2;
1439
1440           if (pass == 1)
1441             map_grow(&omap, installed->end - installed->start);
1442           s = pool->solvables + p;
1443           if (s->obsoletes)
1444             {
1445               Id obs, *obsp;
1446               obsp = s->repo->idarraydata + s->obsoletes;
1447               while ((obs = *obsp++) != 0)
1448                 FOR_PROVIDES(p2, pp2, obs)
1449                   {
1450                     Solvable *ps = pool->solvables + p2;
1451                     if (ps->repo != installed)
1452                       continue;
1453                     if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
1454                       continue;
1455                     if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1456                       continue;
1457                     if (pass)
1458                       MAPSET(&omap, p2 - installed->start);
1459                     else
1460                       queue_push2(q, DISABLE_UPDATE, p2);
1461                   }
1462             }
1463           FOR_PROVIDES(p2, pp2, s->name)
1464             {
1465               Solvable *ps = pool->solvables + p2;
1466               if (ps->repo != installed)
1467                 continue;
1468               if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
1469                 continue;
1470               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1471                 continue;
1472               if (pass)
1473                 MAPSET(&omap, p2 - installed->start);
1474               else
1475                 queue_push2(q, DISABLE_UPDATE, p2);
1476             }
1477           if (pass)
1478             {
1479               for (i = j = qstart; i < q->count; i += 2)
1480                 {
1481                   if (MAPTST(&omap, q->elements[i + 1] - installed->start))
1482                     {
1483                       MAPCLR(&omap, q->elements[i + 1] - installed->start);
1484                       q->elements[j + 1] = q->elements[i + 1];
1485                       j += 2;
1486                     }
1487                 }
1488               queue_truncate(q, j);
1489             }
1490           if (q->count == qstart)
1491             break;
1492           pass++;
1493         }
1494       if (omap.size)
1495         map_free(&omap);
1496       if (select == SOLVER_SOLVABLE || qstart == q->count)
1497         return;         /* all done already */
1498
1499       /* now that we know which installed packages are obsoleted check each of them */
1500       for (i = j = qstart; i < q->count; i += 2)
1501         {
1502           Solvable *is = pool->solvables + q->elements[i + 1];
1503           FOR_JOB_SELECT(p, pp, select, what)
1504             {
1505               int illegal = 0;
1506               s = pool->solvables + p;
1507               if ((set & SOLVER_SETEVR) != 0)
1508                 illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
1509               if ((set & SOLVER_SETARCH) != 0)
1510                 illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
1511               if ((set & SOLVER_SETVENDOR) != 0)
1512                 illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
1513               illegal = policy_is_illegal(solv, is, s, illegal);
1514               if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
1515                 {
1516                   /* it's ok if the EV is different */
1517                   if (evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
1518                     illegal = 0;
1519                 }
1520               if (illegal)
1521                 break;
1522             }
1523           if (!p)
1524             {   
1525               /* no package conflicts with the update rule */
1526               /* thus keep the DISABLE_UPDATE */
1527               q->elements[j + 1] = q->elements[i + 1];
1528               j += 2;
1529             }
1530         }
1531       queue_truncate(q, j);
1532       return;
1533     case SOLVER_ERASE:
1534       if (!installed)
1535         break;
1536       FOR_JOB_SELECT(p, pp, select, what)
1537         if (pool->solvables[p].repo == installed)
1538           queue_push2(q, DISABLE_UPDATE, p);
1539       return;
1540     default:
1541       return;
1542     }
1543 }
1544
1545 /* disable all policy rules that are in conflict with our job list */
1546 void
1547 solver_disablepolicyrules(Solver *solv)
1548 {
1549   Queue *job = &solv->job;
1550   int i, j;
1551   Queue allq;
1552   Rule *r;
1553   Id lastjob = -1;
1554   Id allqbuf[128];
1555
1556   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
1557
1558   for (i = solv->jobrules; i < solv->jobrules_end; i++)
1559     {
1560       r = solv->rules + i;
1561       if (r->d < 0)     /* disabled? */
1562         continue;
1563       j = solv->ruletojob.elements[i - solv->jobrules];
1564       if (j == lastjob)
1565         continue;
1566       lastjob = j;
1567       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
1568     }
1569   if (solv->cleandepsmap.size)
1570     {
1571       solver_createcleandepsmap(solv);
1572       for (i = solv->installed->start; i < solv->installed->end; i++)
1573         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1574           queue_push2(&allq, DISABLE_UPDATE, i);
1575     }
1576   MAPZERO(&solv->noupdate);
1577   for (i = 0; i < allq.count; i += 2)
1578     {
1579       Id type = allq.elements[i], arg = allq.elements[i + 1];
1580       switch(type)
1581         {
1582         case DISABLE_UPDATE:
1583           disableupdaterule(solv, arg);
1584           break;
1585         case DISABLE_INFARCH:
1586           disableinfarchrule(solv, arg);
1587           break;
1588         case DISABLE_DUP:
1589           disableduprule(solv, arg);
1590           break;
1591         default:
1592           break;
1593         }
1594     }
1595   queue_free(&allq);
1596 }
1597
1598 /* we just disabled job #jobidx, now reenable all policy rules that were
1599  * disabled because of this job */
1600 void
1601 solver_reenablepolicyrules(Solver *solv, int jobidx)
1602 {
1603   Queue *job = &solv->job;
1604   int i, j;
1605   Queue q, allq;
1606   Rule *r;
1607   Id lastjob = -1;
1608   Id qbuf[32], allqbuf[128];
1609
1610   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
1611   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
1612   jobtodisablelist(solv, job->elements[jobidx], job->elements[jobidx + 1], &q);
1613   if (!q.count)
1614     return;
1615   for (i = solv->jobrules; i < solv->jobrules_end; i++)
1616     {
1617       r = solv->rules + i;
1618       if (r->d < 0)     /* disabled? */
1619         continue;
1620       j = solv->ruletojob.elements[i - solv->jobrules];
1621       if (j == lastjob)
1622         continue;
1623       lastjob = j;
1624       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
1625     }
1626   if (solv->cleandepsmap.size)
1627     {
1628       solver_createcleandepsmap(solv);
1629       for (i = solv->installed->start; i < solv->installed->end; i++)
1630         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1631           queue_push2(&allq, DISABLE_UPDATE, i);
1632     }
1633   for (j = 0; j < q.count; j += 2)
1634     {
1635       Id type = q.elements[j], arg = q.elements[j + 1];
1636       for (i = 0; i < allq.count; i += 2)
1637         if (allq.elements[i] == type && allq.elements[i + 1] == arg)
1638           break;
1639       if (i < allq.count)
1640         continue;       /* still disabled */
1641       switch(type)
1642         {
1643         case DISABLE_UPDATE:
1644           reenableupdaterule(solv, arg);
1645           break;
1646         case DISABLE_INFARCH:
1647           reenableinfarchrule(solv, arg);
1648           break;
1649         case DISABLE_DUP:
1650           reenableduprule(solv, arg);
1651           break;
1652         }
1653     }
1654   queue_free(&allq);
1655   queue_free(&q);
1656 }
1657
1658
1659 /***********************************************************************
1660  ***
1661  ***  Rule info part, tell the user what the rule is about.
1662  ***
1663  ***/
1664
1665 static void
1666 addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
1667 {
1668   Pool *pool = solv->pool;
1669   Rule *r;
1670   Id w2, op, od, ow2;
1671
1672   /* check if this creates the rule we're searching for */
1673   r = solv->rules + solv->ruleinfoq->elements[0];
1674   op = r->p;
1675   od = r->d < 0 ? -r->d - 1 : r->d;
1676   ow2 = 0;
1677
1678   /* normalize */
1679   w2 = d > 0 ? 0 : d;
1680   if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
1681     {
1682       w2 = pool->whatprovidesdata[d];
1683       d = 0;
1684
1685     }
1686   if (p > 0 && d < 0)           /* this hack is used for buddy deps */
1687     {
1688       w2 = p;
1689       p = d;
1690     }
1691
1692   if (d > 0)
1693     {
1694       if (p != op && !od)
1695         return;
1696       if (d != od)
1697         {
1698           Id *dp = pool->whatprovidesdata + d;
1699           Id *odp = pool->whatprovidesdata + od;
1700           while (*dp)
1701             if (*dp++ != *odp++)
1702               return;
1703           if (*odp)
1704             return;
1705         }
1706       w2 = 0;
1707       /* handle multiversion conflict rules */
1708       if (p < 0 && pool->whatprovidesdata[d] < 0)
1709         {
1710           w2 = pool->whatprovidesdata[d];
1711           /* XXX: free memory */
1712         }
1713     }
1714   else
1715     {
1716       if (od)
1717         return;
1718       ow2 = r->w2;
1719       if (p > w2)
1720         {
1721           if (w2 != op || p != ow2)
1722             return;
1723         }
1724       else
1725         {
1726           if (p != op || w2 != ow2)
1727             return;
1728         }
1729     }
1730   /* yep, rule matches. record info */
1731   queue_push(solv->ruleinfoq, type);
1732   if (type == SOLVER_RULE_RPM_SAME_NAME)
1733     {
1734       /* we normalize same name order */
1735       queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
1736       queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
1737     }
1738   else
1739     {
1740       queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
1741       queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
1742     }
1743   queue_push(solv->ruleinfoq, dep);
1744 }
1745
1746 static int
1747 solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
1748 {
1749   const Id *a = ap, *b = bp;
1750   int r;
1751
1752   r = a[0] - b[0];
1753   if (r)
1754     return r;
1755   r = a[1] - b[1];
1756   if (r)
1757     return r;
1758   r = a[2] - b[2];
1759   if (r)
1760     return r;
1761   r = a[3] - b[3];
1762   if (r)
1763     return r;
1764   return 0;
1765 }
1766
1767 int
1768 solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
1769 {
1770   Pool *pool = solv->pool;
1771   Rule *r = solv->rules + rid;
1772   int i, j;
1773
1774   queue_empty(rq);
1775   if (rid <= 0 || rid >= solv->rpmrules_end)
1776     {
1777       Id type, from, to, dep;
1778       type = solver_ruleinfo(solv, rid, &from, &to, &dep);
1779       queue_push(rq, type);
1780       queue_push(rq, from);
1781       queue_push(rq, to);
1782       queue_push(rq, dep);
1783       return 1;
1784     }
1785   if (r->p >= 0)
1786     return 0;
1787   queue_push(rq, rid);
1788   solv->ruleinfoq = rq;
1789   solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
1790   /* also try reverse direction for conflicts */
1791   if ((r->d == 0 || r->d == -1) && r->w2 < 0)
1792     solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
1793   solv->ruleinfoq = 0;
1794   queue_shift(rq);
1795   /* now sort & unify em */
1796   if (!rq->count)
1797     return 0;
1798   sat_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
1799   /* throw out identical entries */
1800   for (i = j = 0; i < rq->count; i += 4)
1801     {
1802       if (j)
1803         {
1804           if (rq->elements[i] == rq->elements[j - 4] && 
1805               rq->elements[i + 1] == rq->elements[j - 3] &&
1806               rq->elements[i + 2] == rq->elements[j - 2] &&
1807               rq->elements[i + 3] == rq->elements[j - 1])
1808             continue;
1809         }
1810       rq->elements[j++] = rq->elements[i];
1811       rq->elements[j++] = rq->elements[i + 1];
1812       rq->elements[j++] = rq->elements[i + 2];
1813       rq->elements[j++] = rq->elements[i + 3];
1814     }
1815   rq->count = j;
1816   return j / 4;
1817 }
1818
1819 SolverRuleinfo
1820 solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
1821 {
1822   Pool *pool = solv->pool;
1823   Rule *r = solv->rules + rid;
1824   SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
1825
1826   if (fromp)
1827     *fromp = 0;
1828   if (top)
1829     *top = 0;
1830   if (depp)
1831     *depp = 0;
1832   if (rid > 0 && rid < solv->rpmrules_end)
1833     {
1834       Queue rq;
1835       int i;
1836
1837       if (r->p >= 0)
1838         return SOLVER_RULE_RPM;
1839       if (fromp)
1840         *fromp = -r->p;
1841       queue_init(&rq);
1842       queue_push(&rq, rid);
1843       solv->ruleinfoq = &rq;
1844       solver_addrpmrulesforsolvable(solv, pool->solvables - r->p, 0);
1845       /* also try reverse direction for conflicts */
1846       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
1847         solver_addrpmrulesforsolvable(solv, pool->solvables - r->w2, 0);
1848       solv->ruleinfoq = 0;
1849       type = SOLVER_RULE_RPM;
1850       for (i = 1; i < rq.count; i += 4)
1851         {
1852           Id qt, qo, qp, qd;
1853           qt = rq.elements[i];
1854           qp = rq.elements[i + 1];
1855           qo = rq.elements[i + 2];
1856           qd = rq.elements[i + 3];
1857           if (type == SOLVER_RULE_RPM || type > qt)
1858             {
1859               type = qt;
1860               if (fromp)
1861                 *fromp = qp;
1862               if (top)
1863                 *top = qo;
1864               if (depp)
1865                 *depp = qd;
1866             }
1867         }
1868       queue_free(&rq);
1869       return type;
1870     }
1871   if (rid >= solv->jobrules && rid < solv->jobrules_end)
1872     {
1873       Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
1874       if (fromp)
1875         *fromp = jidx;
1876       if (top)
1877         *top = solv->job.elements[jidx];
1878       if (depp)
1879         *depp = solv->job.elements[jidx + 1];
1880       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE && (solv->job.elements[jidx] & SOLVER_SELECTMASK) != SOLVER_SOLVABLE_ONE_OF)
1881         return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
1882       return SOLVER_RULE_JOB;
1883     }
1884   if (rid >= solv->updaterules && rid < solv->updaterules_end)
1885     {
1886       if (fromp)
1887         *fromp = solv->installed->start + (rid - solv->updaterules);
1888       return SOLVER_RULE_UPDATE;
1889     }
1890   if (rid >= solv->featurerules && rid < solv->featurerules_end)
1891     {
1892       if (fromp)
1893         *fromp = solv->installed->start + (rid - solv->featurerules);
1894       return SOLVER_RULE_FEATURE;
1895     }
1896   if (rid >= solv->duprules && rid < solv->duprules_end)
1897     {
1898       if (fromp)
1899         *fromp = -r->p;
1900       if (depp)
1901         *depp = pool->solvables[-r->p].name;
1902       return SOLVER_RULE_DISTUPGRADE;
1903     }
1904   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
1905     {
1906       if (fromp)
1907         *fromp = -r->p;
1908       if (depp)
1909         *depp = pool->solvables[-r->p].name;
1910       return SOLVER_RULE_INFARCH;
1911     }
1912   if (rid >= solv->choicerules && rid < solv->choicerules_end)
1913     {
1914       return SOLVER_RULE_CHOICE;
1915     }
1916   if (rid >= solv->learntrules)
1917     {
1918       return SOLVER_RULE_LEARNT;
1919     }
1920   return SOLVER_RULE_UNKNOWN;
1921 }
1922
1923 void
1924 solver_addchoicerules(Solver *solv)
1925 {
1926   Pool *pool = solv->pool;
1927   Map m, mneg;
1928   Rule *r;
1929   Queue q, qi;
1930   int i, j, rid, havechoice;
1931   Id p, d, *pp;
1932   Id p2, pp2;
1933   Solvable *s, *s2;
1934
1935   solv->choicerules = solv->nrules;
1936   if (!pool->installed)
1937     {
1938       solv->choicerules_end = solv->nrules;
1939       return;
1940     }
1941   solv->choicerules_ref = sat_calloc(solv->rpmrules_end, sizeof(Id));
1942   queue_init(&q);
1943   queue_init(&qi);
1944   map_init(&m, pool->nsolvables);
1945   map_init(&mneg, pool->nsolvables);
1946   /* set up negative assertion map from infarch and dup rules */
1947   for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
1948     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
1949       MAPSET(&mneg, -r->p);
1950   for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
1951     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
1952       MAPSET(&mneg, -r->p);
1953   for (rid = 1; rid < solv->rpmrules_end ; rid++)
1954     {
1955       r = solv->rules + rid;
1956       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
1957         continue;       /* only look at requires rules */
1958       // solver_printrule(solv, SAT_DEBUG_RESULT, r);
1959       queue_empty(&q);
1960       queue_empty(&qi);
1961       havechoice = 0;
1962       FOR_RULELITERALS(p, pp, r)
1963         {
1964           if (p < 0)
1965             continue;
1966           s = pool->solvables + p;
1967           if (!s->repo)
1968             continue;
1969           if (s->repo == pool->installed)
1970             {
1971               queue_push(&q, p);
1972               continue;
1973             }
1974           /* check if this package is "blocked" by a installed package */
1975           s2 = 0;
1976           FOR_PROVIDES(p2, pp2, s->name)
1977             {
1978               s2 = pool->solvables + p2;
1979               if (s2->repo != pool->installed)
1980                 continue;
1981               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
1982                 continue;
1983               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
1984                 continue;
1985               break;
1986             }
1987           if (p2)
1988             {
1989               /* found installed package p2 that we can update to p */
1990               if (MAPTST(&mneg, p))
1991                 continue;
1992               if (policy_is_illegal(solv, s2, s, 0))
1993                 continue;
1994               queue_push(&qi, p2);
1995               queue_push(&q, p);
1996               continue;
1997             }
1998           if (s->obsoletes)
1999             {
2000               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2001               s2 = 0;
2002               while ((obs = *obsp++) != 0)
2003                 {
2004                   FOR_PROVIDES(p2, pp2, obs)
2005                     {
2006                       s2 = pool->solvables + p2;
2007                       if (s2->repo != pool->installed)
2008                         continue;
2009                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
2010                         continue;
2011                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
2012                         continue;
2013                       break;
2014                     }
2015                   if (p2)
2016                     break;
2017                 }
2018               if (obs)
2019                 {
2020                   /* found installed package p2 that we can update to p */
2021                   if (MAPTST(&mneg, p))
2022                     continue;
2023                   if (policy_is_illegal(solv, s2, s, 0))
2024                     continue;
2025                   queue_push(&qi, p2);
2026                   queue_push(&q, p);
2027                   continue;
2028                 }
2029             }
2030           /* package p is independent of the installed ones */
2031           havechoice = 1;
2032         }
2033       if (!havechoice || !q.count)
2034         continue;       /* no choice */
2035
2036       /* now check the update rules of the installed package.
2037        * if all packages of the update rules are contained in
2038        * the dependency rules, there's no need to set up the choice rule */
2039       map_empty(&m);
2040       FOR_RULELITERALS(p, pp, r)
2041         if (p > 0)
2042           MAPSET(&m, p);
2043       for (i = 0; i < qi.count; i++)
2044         {
2045           if (!qi.elements[i])
2046             continue;
2047           Rule *ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
2048           if (!ur->p)
2049             ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
2050           if (!ur->p)
2051             continue;
2052           FOR_RULELITERALS(p, pp, ur)
2053             if (!MAPTST(&m, p))
2054               break;
2055           if (p)
2056             break;
2057           for (j = i + 1; j < qi.count; j++)
2058             if (qi.elements[i] == qi.elements[j])
2059               qi.elements[j] = 0;
2060         }
2061       if (i == qi.count)
2062         {
2063 #if 0
2064           printf("skipping choice ");
2065           solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
2066 #endif
2067           continue;
2068         }
2069       d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
2070       solver_addrule(solv, r->p, d);
2071       queue_push(&solv->weakruleq, solv->nrules - 1);
2072       solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
2073 #if 0
2074       printf("OLD ");
2075       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + rid);
2076       printf("WEAK CHOICE ");
2077       solver_printrule(solv, SAT_DEBUG_RESULT, solv->rules + solv->nrules - 1);
2078 #endif
2079     }
2080   queue_free(&q);
2081   queue_free(&qi);
2082   map_free(&m);
2083   map_free(&mneg);
2084   solv->choicerules_end = solv->nrules;
2085 }
2086
2087 /* called when a choice rule is disabled by analyze_unsolvable. We also
2088  * have to disable all other choice rules so that the best packages get
2089  * picked */
2090 void
2091 solver_disablechoicerules(Solver *solv, Rule *r)
2092 {
2093   Id rid, p, *pp;
2094   Pool *pool = solv->pool;
2095   Map m;
2096   Rule *or;
2097
2098   or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
2099   map_init(&m, pool->nsolvables);
2100   FOR_RULELITERALS(p, pp, or)
2101     if (p > 0)
2102       MAPSET(&m, p);
2103   FOR_RULELITERALS(p, pp, r)
2104     if (p > 0)
2105       MAPCLR(&m, p);
2106   for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
2107     {
2108       r = solv->rules + rid;
2109       if (r->d < 0)
2110         continue;
2111       or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
2112       FOR_RULELITERALS(p, pp, or)
2113         if (p > 0 && MAPTST(&m, p))
2114           break;
2115       if (p)
2116         solver_disablerule(solv, r);
2117     }
2118 }
2119
2120 static void solver_createcleandepsmap(Solver *solv)
2121 {
2122   Pool *pool = solv->pool;
2123   Repo *installed = solv->installed;
2124   Queue *job = &solv->job;
2125   Map userinstalled;
2126   Map im;
2127   Map installedm;
2128   Rule *r;
2129   Id rid, how, what, select;
2130   Id p, pp, ip, *jp;
2131   Id req, *reqp, sup, *supp;
2132   Solvable *s;
2133   Queue iq;
2134   int i;
2135
2136   map_init(&userinstalled, installed->end - installed->start);
2137   map_init(&im, pool->nsolvables);
2138   map_init(&installedm, pool->nsolvables);
2139   map_empty(&solv->cleandepsmap);
2140   queue_init(&iq);
2141
2142   for (i = 0; i < job->count; i += 2)
2143     {
2144       how = job->elements[i];
2145       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
2146         {
2147           what = job->elements[i + 1];
2148           select = how & SOLVER_SELECTMASK;
2149           FOR_JOB_SELECT(p, pp, select, what)
2150             if (pool->solvables[p].repo == installed)
2151               MAPSET(&userinstalled, p - installed->start);
2152         }
2153     }
2154   /* add all positive elements (e.g. locks) to "userinstalled" */
2155   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2156     {
2157       r = solv->rules + rid;
2158       if (r->d < 0)
2159         continue;
2160       FOR_RULELITERALS(p, jp, r)
2161         if (p > 0 && pool->solvables[p].repo == installed)
2162           MAPSET(&userinstalled, p - installed->start);
2163     }
2164   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2165     {
2166       r = solv->rules + rid;
2167       if (r->p >= 0 || r->d != 0)
2168         continue;       /* disabled or not erase */
2169       p = -r->p;
2170       if (pool->solvables[p].repo != installed)
2171         continue;
2172       MAPCLR(&userinstalled, p - installed->start);
2173       i = solv->ruletojob.elements[rid - solv->jobrules];
2174       how = job->elements[i];
2175       if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
2176         queue_push(&iq, p);
2177     }
2178   for (p = installed->start; p < installed->end; p++)
2179     {
2180       if (pool->solvables[p].repo != installed)
2181         continue;
2182       MAPSET(&installedm, p);
2183       MAPSET(&im, p);
2184     }
2185
2186   while (iq.count)
2187     {
2188       ip = queue_shift(&iq);
2189       s = pool->solvables + ip;
2190       if (!MAPTST(&im, ip))
2191         continue;
2192       if (!MAPTST(&installedm, ip))
2193         continue;
2194       if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
2195         continue;
2196       MAPCLR(&im, ip);
2197 #ifdef CLEANDEPSDEBUG
2198       printf("hello %s\n", solvable2str(pool, s));
2199 #endif
2200       if (s->requires)
2201         {
2202           reqp = s->repo->idarraydata + s->requires;
2203           while ((req = *reqp++) != 0)
2204             {
2205               if (req == SOLVABLE_PREREQMARKER)
2206                 continue;
2207 #if 0
2208               /* count number of installed packages that match */
2209               count = 0;
2210               FOR_PROVIDES(p, pp, req)
2211                 if (MAPTST(&installedm, p))
2212                   count++;
2213               if (count > 1)
2214                 continue;
2215 #endif
2216               FOR_PROVIDES(p, pp, req)
2217                 {
2218                   if (MAPTST(&im, p))
2219                     {
2220 #ifdef CLEANDEPSDEBUG
2221                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2222 #endif
2223                       queue_push(&iq, p);
2224                     }
2225                 }
2226             }
2227         }
2228       if (s->recommends)
2229         {
2230           reqp = s->repo->idarraydata + s->recommends;
2231           while ((req = *reqp++) != 0)
2232             {
2233 #if 0
2234               count = 0;
2235               FOR_PROVIDES(p, pp, req)
2236                 if (MAPTST(&installedm, p))
2237                   count++;
2238               if (count > 1)
2239                 continue;
2240 #endif
2241               FOR_PROVIDES(p, pp, req)
2242                 {
2243                   if (MAPTST(&im, p))
2244                     {
2245 #ifdef CLEANDEPSDEBUG
2246                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2247 #endif
2248                       queue_push(&iq, p);
2249                     }
2250                 }
2251             }
2252         }
2253       if (!iq.count)
2254         {
2255           /* supplements pass */
2256           for (ip = solv->installed->start; ip < solv->installed->end; ip++)
2257             {
2258               if (!MAPTST(&installedm, ip))
2259                 continue;
2260               s = pool->solvables + ip;
2261               if (!s->supplements)
2262                 continue;
2263               if (!MAPTST(&im, ip))
2264                 continue;
2265               supp = s->repo->idarraydata + s->supplements;
2266               while ((sup = *supp++) != 0)
2267                 if (!dep_possible(solv, sup, &im) && dep_possible(solv, sup, &installedm))
2268                   break;
2269               /* no longer supplemented, also erase */
2270               if (sup)
2271                 {
2272 #ifdef CLEANDEPSDEBUG
2273                   printf("%s supplemented\n", solvid2str(pool, ip));
2274 #endif
2275                   queue_push(&iq, ip);
2276                 }
2277             }
2278         }
2279     }
2280
2281   /* turn userinstalled into remove set for pruning */
2282   map_empty(&userinstalled);
2283   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2284     {
2285       r = solv->rules + rid;
2286       if (r->p >= 0 || r->d != 0)
2287         continue;       /* disabled or not erase */
2288       p = -r->p;
2289       MAPCLR(&im, p);
2290       if (pool->solvables[p].repo == installed)
2291         MAPSET(&userinstalled, p - installed->start);
2292     }
2293   for (p = installed->start; p < installed->end; p++)
2294     if (MAPTST(&im, p))
2295       queue_push(&iq, p);
2296   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
2297     {
2298       r = solv->rules + rid;
2299       if (r->d < 0)
2300         continue;
2301       FOR_RULELITERALS(p, jp, r)
2302         if (p > 0)
2303           queue_push(&iq, p);
2304     }
2305   /* also put directly addressed packages on the install queue
2306    * so we can mark patterns as installed */
2307   for (i = 0; i < job->count; i += 2)
2308     {
2309       how = job->elements[i];
2310       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
2311         {
2312           what = job->elements[i + 1];
2313           select = how & SOLVER_SELECTMASK;
2314           if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
2315             queue_push(&iq, what);
2316         }
2317     }
2318   while (iq.count)
2319     {
2320       ip = queue_shift(&iq);
2321       s = pool->solvables + ip;
2322 #ifdef CLEANDEPSDEBUG
2323       printf("bye %s\n", solvable2str(pool, s));
2324 #endif
2325       if (s->requires)
2326         {
2327           reqp = s->repo->idarraydata + s->requires;
2328           while ((req = *reqp++) != 0)
2329             {
2330               FOR_PROVIDES(p, pp, req)
2331                 {
2332                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
2333                     {
2334                       if (p == ip)
2335                         continue;
2336                       if (MAPTST(&userinstalled, p - installed->start))
2337                         continue;
2338 #ifdef CLEANDEPSDEBUG
2339                       printf("%s requires %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2340 #endif
2341                       MAPSET(&im, p);
2342                       queue_push(&iq, p);
2343                     }
2344                 }
2345             }
2346         }
2347       if (s->recommends)
2348         {
2349           reqp = s->repo->idarraydata + s->recommends;
2350           while ((req = *reqp++) != 0)
2351             {
2352               FOR_PROVIDES(p, pp, req)
2353                 {
2354                   if (!MAPTST(&im, p) && MAPTST(&installedm, p))
2355                     {
2356                       if (p == ip)
2357                         continue;
2358                       if (MAPTST(&userinstalled, p - installed->start))
2359                         continue;
2360 #ifdef CLEANDEPSDEBUG
2361                       printf("%s recommends %s\n", solvid2str(pool, ip), solvid2str(pool, p));
2362 #endif
2363                       MAPSET(&im, p);
2364                       queue_push(&iq, p);
2365                     }
2366                 }
2367             }
2368         }
2369       if (!iq.count)
2370         {
2371           /* supplements pass */
2372           for (ip = installed->start; ip < installed->end; ip++)
2373             {
2374               if (!MAPTST(&installedm, ip))
2375                 continue;
2376               if (MAPTST(&userinstalled, ip - installed->start))
2377                 continue;
2378               s = pool->solvables + ip;
2379               if (!s->supplements)
2380                 continue;
2381               if (MAPTST(&im, ip) || !MAPTST(&installedm, ip))
2382                 continue;
2383               supp = s->repo->idarraydata + s->supplements;
2384               while ((sup = *supp++) != 0)
2385                 if (dep_possible(solv, sup, &im))
2386                   break;
2387               if (sup)
2388                 {
2389 #ifdef CLEANDEPSDEBUG
2390                   printf("%s supplemented\n", solvid2str(pool, ip));
2391 #endif
2392                   MAPSET(&im, ip);
2393                   queue_push(&iq, ip);
2394                 }
2395             }
2396         }
2397     }
2398     
2399   queue_free(&iq);
2400   for (p = installed->start; p < installed->end; p++)
2401     {
2402       if (pool->solvables[p].repo != installed)
2403         continue;
2404       if (!MAPTST(&im, p))
2405         MAPSET(&solv->cleandepsmap, p - installed->start);
2406     }
2407   map_free(&im);
2408   map_free(&installedm);
2409   map_free(&userinstalled);
2410 }
2411
2412
2413 /* EOF */