improve solver_addrule a bit
[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 "solver_private.h"
22 #include "bitmap.h"
23 #include "pool.h"
24 #include "poolarch.h"
25 #include "util.h"
26 #include "evr.h"
27 #include "policy.h"
28 #include "solverdebug.h"
29 #include "linkedpkg.h"
30 #include "cplxdeps.h"
31
32 #define RULES_BLOCK 63
33
34 static void addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep);
35 static void solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded);
36
37 /*-------------------------------------------------------------------
38  * Check if dependency is possible
39  *
40  * mirrors solver_dep_fulfilled but uses map m instead of the decisionmap.
41  * used in solver_addrpmrulesforweak and solver_createcleandepsmap.
42  */
43
44 static inline int
45 dep_possible(Solver *solv, Id dep, Map *m)
46 {
47   Pool *pool = solv->pool;
48   Id p, pp;
49
50   if (ISRELDEP(dep))
51     {
52       Reldep *rd = GETRELDEP(pool, dep);
53       if (rd->flags >= 8)
54          {
55           if (rd->flags == REL_AND || rd->flags == REL_COND)
56             {
57               if (!dep_possible(solv, rd->name, m))
58                 return 0;
59               return dep_possible(solv, rd->evr, m);
60             }
61           if (rd->flags == REL_OR)
62             {
63               if (dep_possible(solv, rd->name, m))
64                 return 1;
65               return dep_possible(solv, rd->evr, m);
66             }
67           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
68             return solver_splitprovides(solv, rd->evr);
69           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
70             return solver_dep_installed(solv, rd->evr);
71         }
72     }
73   FOR_PROVIDES(p, pp, dep)
74     {
75       if (MAPTST(m, p))
76         return 1;
77     }
78   return 0;
79 }
80
81 static inline int
82 is_otherproviders_dep(Pool *pool, Id dep)
83 {
84   if (ISRELDEP(dep))
85     {
86       Reldep *rd = GETRELDEP(pool, dep);
87       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_OTHERPROVIDERS)
88         return 1;
89     }
90   return 0;
91 }
92
93 /********************************************************************
94  *
95  * Rule handling
96  *
97  * - unify rules, remove duplicates
98  */
99
100 /*-------------------------------------------------------------------
101  *
102  * compare rules for unification sort
103  *
104  */
105
106 static int
107 unifyrules_sortcmp(const void *ap, const void *bp, void *dp)
108 {
109   Pool *pool = dp;
110   Rule *a = (Rule *)ap;
111   Rule *b = (Rule *)bp;
112   Id *ad, *bd;
113   int x;
114
115   x = a->p - b->p;
116   if (x)
117     return x;                          /* p differs */
118
119   /* identical p */
120   if (a->d == 0 && b->d == 0)
121     return a->w2 - b->w2;              /* assertion: return w2 diff */
122
123   if (a->d == 0)                       /* a is assertion, b not */
124     {
125       x = a->w2 - pool->whatprovidesdata[b->d];
126       return x ? x : -1;
127     }
128
129   if (b->d == 0)                       /* b is assertion, a not */
130     {
131       x = pool->whatprovidesdata[a->d] - b->w2;
132       return x ? x : 1;
133     }
134
135   /* compare whatprovidesdata */
136   ad = pool->whatprovidesdata + a->d;
137   bd = pool->whatprovidesdata + b->d;
138   while (*bd)
139     if ((x = *ad++ - *bd++) != 0)
140       return x;
141   return *ad;
142 }
143
144 int
145 solver_rulecmp(Solver *solv, Rule *r1, Rule *r2)
146 {
147   return unifyrules_sortcmp(r1, r2, solv->pool);
148 }
149
150
151 /*-------------------------------------------------------------------
152  *
153  * unify rules
154  * go over all rules and remove duplicates
155  */
156
157 void
158 solver_unifyrules(Solver *solv)
159 {
160   Pool *pool = solv->pool;
161   int i, j;
162   Rule *ir, *jr;
163
164   if (solv->nrules <= 2)               /* nothing to unify */
165     return;
166
167   /* sort rules first */
168   solv_sort(solv->rules + 1, solv->nrules - 1, sizeof(Rule), unifyrules_sortcmp, solv->pool);
169
170   /* prune rules
171    * i = unpruned
172    * j = pruned
173    */
174   jr = 0;
175   for (i = j = 1, ir = solv->rules + i; i < solv->nrules; i++, ir++)
176     {
177       if (jr && !unifyrules_sortcmp(ir, jr, pool))
178         continue;                      /* prune! */
179       jr = solv->rules + j++;          /* keep! */
180       if (ir != jr)
181         *jr = *ir;
182     }
183
184   /* reduced count from nrules to j rules */
185   POOL_DEBUG(SOLV_DEBUG_STATS, "pruned rules from %d to %d\n", solv->nrules, j);
186
187   /* adapt rule buffer */
188   solv->nrules = j;
189   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
190
191   /*
192    * debug: log rule statistics
193    */
194   IF_POOLDEBUG (SOLV_DEBUG_STATS)
195     {
196       int binr = 0;
197       int lits = 0;
198       Id *dp;
199       Rule *r;
200
201       for (i = 1; i < solv->nrules; i++)
202         {
203           r = solv->rules + i;
204           if (r->d == 0)
205             binr++;
206           else
207             {
208               dp = solv->pool->whatprovidesdata + r->d;
209               while (*dp++)
210                 lits++;
211             }
212         }
213       POOL_DEBUG(SOLV_DEBUG_STATS, "  binary: %d\n", binr);
214       POOL_DEBUG(SOLV_DEBUG_STATS, "  normal: %d, %d literals\n", solv->nrules - 1 - binr, lits);
215     }
216 }
217
218 #if 0
219
220 /*
221  * hash rule
222  */
223
224 static Hashval
225 hashrule(Solver *solv, Id p, Id d, int n)
226 {
227   unsigned int x = (unsigned int)p;
228   int *dp;
229
230   if (n <= 1)
231     return (x * 37) ^ (unsigned int)d;
232   dp = solv->pool->whatprovidesdata + d;
233   while (*dp)
234     x = (x * 37) ^ (unsigned int)*dp++;
235   return x;
236 }
237 #endif
238
239
240 /*-------------------------------------------------------------------
241  *
242  */
243
244 /*
245  * add rule
246  *  p = direct literal; always < 0 for installed rpm rules
247  *  d, if < 0 direct literal, if > 0 offset into whatprovides, if == 0 rule is assertion (look at p only)
248  *
249  *
250  * A requires b, b provided by B1,B2,B3 => (-A|B1|B2|B3)
251  *
252  * p < 0 : pkg id of A
253  * d > 0 : Offset in whatprovidesdata (list of providers of b)
254  *
255  * A conflicts b, b provided by B1,B2,B3 => (-A|-B1), (-A|-B2), (-A|-B3)
256  * p < 0 : pkg id of A
257  * d < 0 : Id of solvable (e.g. B1)
258  *
259  * d == 0: unary rule, assertion => (A) or (-A)
260  *
261  *   Install:    p > 0, d = 0   (A)             user requested install
262  *   Remove:     p < 0, d = 0   (-A)            user requested remove (also: uninstallable)
263  *   Requires:   p < 0, d > 0   (-A|B1|B2|...)  d: <list of providers for requirement of p>
264  *   Requires:   p > 0, d < 0   (B|-A)          hack to save a whatprovides allocation, gets converted into (-A|B)
265  *   Updates:    p > 0, d > 0   (A|B1|B2|...)   d: <list of updates for solvable p>
266  *   Conflicts:  p < 0, d < 0   (-A|-B)         either p (conflict issuer) or d (conflict provider) (binary rule)
267  *                                              also used for obsoletes
268  *   No-op ?:    p = 0, d = 0   (null)          (used as placeholder in update/feature rules)
269  *
270  *   resulting watches:
271  *   ------------------
272  *   Direct assertion (no watch needed) --> d = 0, w1 = p, w2 = 0
273  *   Binary rule: p = first literal, d = 0, w2 = second literal, w1 = p
274  *   every other : w1 = p, w2 = whatprovidesdata[d];
275  *
276  *   always returns a rule for non-rpm rules
277  */
278
279 Rule *
280 solver_addrule(Solver *solv, Id p, Id d)
281 {
282   Pool *pool = solv->pool;
283   Rule *r = 0;
284   Id *dp = 0;
285
286   int n = 0;                           /* number of literals in rule - 1
287                                           0 = direct assertion (single literal)
288                                           1 = binary rule
289                                           >1 = multi-literal rule
290                                         */
291
292   /* it often happenes that requires lead to adding the same rpm rule
293    * multiple times, so we prune those duplicates right away to make
294    * the work for unifyrules a bit easier */
295
296   if (!solv->rpmrules_end)              /* we add rpm rules */
297     {
298       r = solv->rules + solv->nrules - 1;       /* get the last added rule */
299       if (r->p == p && r->d == d && (d != 0 || !r->w2))
300         return r;
301     }
302
303   /* compute number of literals (n) in rule */
304   if (d < 0)
305     {
306       if (p == -d)
307         return 0;                       /* rule is self-fulfilling */
308       if (p == d)
309         d = 0;                          /* normalize to assertion */
310       else
311         n = 1;                          /* binary rule */
312     }
313   else if (d > 0)
314     {
315       for (dp = pool->whatprovidesdata + d; *dp; dp++, n++)
316         if (*dp == -p)
317           return 0;                     /* rule is self-fulfilling */
318       if (n == 1)                       /* convert to binary rule */
319         d = dp[-1];
320     }
321
322   if (n == 1 && p > d && !solv->rpmrules_end)
323     {
324       /* put smallest literal first so we can find dups */
325       n = p; p = d; d = n;             /* p <-> d */
326       n = 1;                           /* re-set n, was used as temp var */
327     }
328
329   /*
330    * check for duplicate (r is only set if we're adding rpm rules)
331    */
332   if (r)
333     {
334       /* check if the last added rule (r) is exactly the same as what we're looking for. */
335       if (n == 1 && !r->d && r->p == p && r->w2 == d)
336         return r;
337       /* have n-ary rule with same first literal, check other literals */
338       if (n > 1 && r->d && r->p == p)
339         {
340           /* Rule where d is an offset in whatprovidesdata */
341           Id *dp2;
342           if (d == r->d)
343             return r;
344           dp2 = pool->whatprovidesdata + r->d;
345           for (dp = pool->whatprovidesdata + d; *dp; dp++, dp2++)
346             if (*dp != *dp2)
347               break;
348           if (*dp == *dp2)
349             return r;
350         }
351     }
352
353   /*
354    * allocate new rule r
355    */
356   solv->rules = solv_extend(solv->rules, solv->nrules, 1, sizeof(Rule), RULES_BLOCK);
357   r = solv->rules + solv->nrules++;    /* point to rule space */
358
359   r->p = p;
360   if (n == 0)
361     {
362       /* direct assertion, no watch needed */
363       r->d = 0;
364       r->w1 = p;
365       r->w2 = 0;
366     }
367   else if (n == 1)
368     {
369       /* binary rule */
370       r->d = 0;
371       r->w1 = p;
372       r->w2 = d;
373     }
374   else
375     {
376       r->d = d;
377       r->w1 = p;
378       r->w2 = pool->whatprovidesdata[d];
379     }
380   r->n1 = 0;
381   r->n2 = 0;
382
383   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
384     {
385       POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "  Add rule: ");
386       solver_printrule(solv, SOLV_DEBUG_RULE_CREATION, r);
387     }
388
389   return r;
390 }
391
392 void
393 solver_shrinkrules(Solver *solv, int nrules)
394 {
395   solv->nrules = nrules;
396   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
397 }
398
399 /******************************************************************************
400  ***
401  *** rpm rule part: create rules representing the package dependencies
402  ***
403  ***/
404
405 /*
406  *  special multiversion patch conflict handling:
407  *  a patch conflict is also satisfied if some other
408  *  version with the same name/arch that doesn't conflict
409  *  gets installed. The generated rule is thus:
410  *  -patch|-cpack|opack1|opack2|...
411  */
412 static Id
413 makemultiversionconflict(Solver *solv, Id n, Id con)
414 {
415   Pool *pool = solv->pool;
416   Solvable *s, *sn;
417   Queue q;
418   Id p, pp, qbuf[64];
419
420   sn = pool->solvables + n;
421   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
422   queue_push(&q, -n);
423   FOR_PROVIDES(p, pp, sn->name)
424     {
425       s = pool->solvables + p;
426       if (s->name != sn->name || s->arch != sn->arch)
427         continue;
428       if (!MAPTST(&solv->multiversion, p))
429         continue;
430       if (pool_match_nevr(pool, pool->solvables + p, con))
431         continue;
432       /* here we have a multiversion solvable that doesn't conflict */
433       /* thus we're not in conflict if it is installed */
434       queue_push(&q, p);
435     }
436   if (q.count == 1)
437     return -n;  /* no other package found, generate normal conflict */
438   return pool_queuetowhatprovides(pool, &q);
439 }
440
441 static inline void
442 addrpmrule(Solver *solv, Id p, Id d, int type, Id dep)
443 {
444   if (!solv->ruleinfoq)
445     solver_addrule(solv, p, d);
446   else
447     addrpmruleinfo(solv, p, d, type, dep);
448 }
449
450 #ifdef ENABLE_LINKED_PKGS
451
452 static void
453 addlinks(Solver *solv, Solvable *s, Id req, Queue *qr, Id prv, Queue *qp, Map *m, Queue *workq)
454 {
455   Pool *pool = solv->pool;
456   int i;
457   if (!qr->count)
458     return;
459 #if 0
460   printf("ADDLINKS %s\n -> %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
461   for (i = 0; i < qr->count; i++)
462     printf("    - %s\n", pool_solvid2str(pool, qr->elements[i]));
463   printf(" <- %s\n", pool_dep2str(pool, prv));
464   for (i = 0; i < qp->count; i++)
465     printf("    - %s\n", pool_solvid2str(pool, qp->elements[i]));
466 #endif
467
468   if (qr->count == 1)
469     addrpmrule(solv, qr->elements[0], -(s - pool->solvables), SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
470   else
471     addrpmrule(solv, -(s - pool->solvables), pool_queuetowhatprovides(pool, qr), SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
472   if (qp->count > 1)
473     {
474       Id d = pool_queuetowhatprovides(pool, qp);
475       for (i = 0; i < qr->count; i++)
476         addrpmrule(solv, -qr->elements[i], d, SOLVER_RULE_RPM_PACKAGE_REQUIRES, prv);
477     }
478   else if (qp->count)
479     {
480       for (i = 0; i < qr->count; i++)
481         addrpmrule(solv, qp->elements[0], -qr->elements[i], SOLVER_RULE_RPM_PACKAGE_REQUIRES, prv);
482     }
483   if (!m)
484     return;     /* nothing more to do if called from getrpmruleinfos() */
485   for (i = 0; i < qr->count; i++)
486     if (!MAPTST(m, qr->elements[i]))
487       queue_push(workq, qr->elements[i]);
488   for (i = 0; i < qp->count; i++)
489     if (!MAPTST(m, qp->elements[i]))
490       queue_push(workq, qp->elements[i]);
491   if (solv->installed && s->repo == solv->installed)
492     {
493       Repo *installed = solv->installed;
494       /* record installed buddies */
495       if (!solv->instbuddy)
496         solv->instbuddy = solv_calloc(installed->end - installed->start, sizeof(Id));
497       if (qr->count == 1)
498         solv->instbuddy[s - pool->solvables - installed->start] = qr->elements[0];
499       for (i = 0; i < qp->count; i++)
500         {
501           Id p = qp->elements[i];
502           if (pool->solvables[p].repo != installed)
503             continue;   /* huh? */
504           if (qp->count > 1 || (solv->instbuddy[p - installed->start] != 0 && solv->instbuddy[p - installed->start] != s - pool->solvables))
505             solv->instbuddy[p - installed->start] = 1;  /* 1: ambiguous buddy */
506           else
507             solv->instbuddy[p - installed->start] = s - pool->solvables;
508         }
509     }
510 }
511
512 static void
513 add_package_link(Solver *solv, Solvable *s, Map *m, Queue *workq)
514 {
515   Queue qr, qp;
516   Id req = 0, prv = 0;
517   queue_init(&qr);
518   queue_init(&qp);
519   find_package_link(solv->pool, s, &req, &qr, &prv, &qp);
520   if (qr.count)
521     addlinks(solv, s, req, &qr, prv, &qp, m, workq);
522   queue_free(&qr);
523   queue_free(&qp);
524 }
525
526 #endif
527
528 #ifdef ENABLE_COMPLEX_DEPS
529
530 static void
531 add_complex_deprules(Solver *solv, Id p, Id dep, int type, int dontfix, Queue *workq, Map *m)
532 {
533   Pool *pool = solv->pool;
534   Repo *installed = solv->installed;
535   int i, j;
536   Queue bq;
537
538   queue_init(&bq);
539
540   /* CNF expansion for requires, DNF + INVERT expansion for conflicts */
541   i = pool_normalize_complex_dep(pool, dep, &bq, type == SOLVER_RULE_RPM_PACKAGE_REQUIRES ? 0 : (CPLXDEPS_TODNF | CPLXDEPS_EXPAND | CPLXDEPS_INVERT));
542   /* handle special cases */
543   if (i == 0)
544     {
545       if (dontfix)
546         {
547           POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken dependency %s of installed package %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, p));
548         }
549       else
550         {
551           POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep));
552           addrpmrule(solv, -p, 0, type == SOLVER_RULE_RPM_PACKAGE_REQUIRES ? SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP : type, dep);
553         }
554       queue_free(&bq);
555       return;
556     }
557   if (i == 1)
558     {
559       queue_free(&bq);
560       return;
561     }
562
563   /* go through all blocks and add a rule for each block */
564   for (i = 0; i < bq.count; i++)
565     {
566       if (!bq.elements[i])
567         continue;       /* huh? */
568       if (bq.elements[i] == pool->nsolvables)
569         {
570           /* conventional requires (cannot be a conflicts as they have been expanded) */
571           Id *dp = pool->whatprovidesdata + bq.elements[i + 1];
572           i += 2;
573           if (dontfix)
574             {
575               for (j = 0; dp[j] != 0; j++)
576                 if (pool->solvables[dp[j]].repo == installed)
577                   break;                /* provider was installed */
578               if (!dp[j])
579                 {
580                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, dep), pool_solvid2str(pool, p));
581                   continue;
582                 }
583             }
584           if (!*dp)
585             {
586               /* nothing provides req! */
587               POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, p), p, pool_dep2str(pool, dep));
588               addrpmrule(solv, -p, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, dep);
589               continue;
590             }
591           addrpmrule(solv, -p, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, dep);
592           /* push all non-visited providers on the work queue */
593           if (m)
594             for (; *dp; dp++)
595               if (!MAPTST(m, *dp))
596                 queue_push(workq, *dp);
597           continue;
598         }
599       if (!bq.elements[i + 1])
600         {
601           Id p2 = bq.elements[i];
602           /* simple rule with just two literals */
603           if (dontfix && p2 < 0 && pool->solvables[-p2].repo == installed)
604             continue;
605           if (dontfix && p2 > 0 && pool->solvables[p2].repo != installed)
606             continue;
607           if (p == p2)
608             continue;
609           if (-p == p2)
610             {
611               if (type == SOLVER_RULE_RPM_PACKAGE_CONFLICT)
612                 {
613                   if (pool->forbidselfconflicts && !is_otherproviders_dep(pool, dep))
614                     addrpmrule(solv, -p, 0, SOLVER_RULE_RPM_SELF_CONFLICT, dep);
615                   continue;
616                 }
617               addrpmrule(solv, -p, 0, type, dep);
618               continue;
619             }
620           if (p2 > 0)
621             addrpmrule(solv, p2, -p, type, dep);        /* hack so that we don't need pool_queuetowhatprovides */
622           else
623             addrpmrule(solv, -p, p2, type, dep);
624           if (m && p2 > 0 && !MAPTST(m, p2))
625             queue_push(workq, p2);
626         }
627       else
628         {
629           Id *qele;
630           int qcnt;
631
632           qele = bq.elements + i;
633           qcnt = i;
634           while (bq.elements[i])
635              i++;
636           qcnt = i - qcnt;
637           if (dontfix)
638             {
639               for (j = 0; j < qcnt; j++)
640                 {
641                   if (qele[j] > 0 && pool->solvables[qele[j]].repo == installed)
642                     break;
643                   if (qele[j] < 0 && pool->solvables[-qele[j]].repo != installed)
644                     break;
645                 }
646               if (j == qcnt)
647                 continue;
648             }
649           /* add -p to (ordered) rule (overwriting the trailing zero) */
650           for (j = 0; ; j++)
651             {
652               if (j == qcnt || qele[j] > -p)
653                 {
654                   if (j < qcnt)
655                     memmove(qele + j + 1, qele + j, (qcnt - j) * sizeof(Id));
656                   qele[j] = -p;
657                   qcnt++;
658                   break;
659                 }
660               if (qele[j] == -p)
661                 break;
662             }
663           /* check if the rule contains both p and -p */
664           for (j = 0; j < qcnt; j++)
665             if (qele[j] == p)
666               break;
667           if (j == qcnt)
668             {
669               /* hack: create fake queue 'q' so that we can call pool_queuetowhatprovides */
670               Queue q;
671               memset(&q, 0, sizeof(q));
672               q.count = qcnt - 1;
673               q.elements = qele + 1;
674               addrpmrule(solv, qele[0], pool_queuetowhatprovides(pool, &q), type, dep);
675               if (m)
676                 for (j = 0; j < qcnt; j++)
677                   if (qele[j] > 0 && !MAPTST(m, qele[j]))
678                     queue_push(workq, qele[j]);
679             }
680         }
681     }
682   queue_free(&bq);
683 }
684
685 #endif
686
687 /*-------------------------------------------------------------------
688  *
689  * add (install) rules for solvable
690  *
691  * s: Solvable for which to add rules
692  * m: m[s] = 1 for solvables which have rules, prevent rule duplication
693  *
694  * Algorithm: 'visit all nodes of a graph'. The graph nodes are
695  *  solvables, the edges their dependencies.
696  *  Starting from an installed solvable, this will create all rules
697  *  representing the graph created by the solvables dependencies.
698  *
699  * for unfulfilled requirements, conflicts, obsoletes,....
700  * add a negative assertion for solvables that are not installable
701  *
702  * It will also create rules for all solvables referenced by 's'
703  *  i.e. descend to all providers of requirements of 's'
704  *
705  */
706
707 void
708 solver_addrpmrulesforsolvable(Solver *solv, Solvable *s, Map *m)
709 {
710   Pool *pool = solv->pool;
711   Repo *installed = solv->installed;
712
713   Queue workq;  /* list of solvables we still have to work on */
714   Id workqbuf[64];
715
716   int i;
717   int dontfix;          /* ignore dependency errors for installed solvables */
718   Id req, *reqp;
719   Id con, *conp;
720   Id obs, *obsp;
721   Id rec, *recp;
722   Id sug, *sugp;
723   Id p, pp;             /* whatprovides loops */
724   Id *dp;               /* ptr to 'whatprovides' */
725   Id n;                 /* Id for current solvable 's' */
726
727   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
728   queue_push(&workq, s - pool->solvables);      /* push solvable Id to work queue */
729
730   /* loop until there's no more work left */
731   while (workq.count)
732     {
733       /*
734        * n: Id of solvable
735        * s: Pointer to solvable
736        */
737
738       n = queue_shift(&workq);          /* 'pop' next solvable to work on from queue */
739       if (m)
740         {
741           if (MAPTST(m, n))             /* continue if already visited */
742             continue;
743           MAPSET(m, n);                 /* mark as visited */
744         }
745
746       s = pool->solvables + n;
747
748       dontfix = 0;
749       if (installed                     /* Installed system available */
750           && s->repo == installed       /* solvable is installed */
751           && !solv->fixmap_all          /* NOT repair errors in rpm dependency graph */
752           && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
753         {
754           dontfix = 1;                  /* dont care about broken rpm deps */
755         }
756
757       if (!dontfix)
758         {
759           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC
760                 ? pool_disabled_solvable(pool, s)
761                 : !pool_installable(pool, s))
762             {
763               POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n);
764               addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOT_INSTALLABLE, 0);
765             }
766         }
767
768 #ifdef ENABLE_LINKED_PKGS
769       /* add pseudo-package <-> real-package links */
770       if (has_package_link(pool, s))
771         add_package_link(solv, s, m, &workq);
772 #endif
773
774       /*-----------------------------------------
775        * check requires of s
776        */
777
778       if (s->requires)
779         {
780           reqp = s->repo->idarraydata + s->requires;
781           while ((req = *reqp++) != 0)            /* go through all requires */
782             {
783               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
784                 continue;
785
786 #ifdef ENABLE_COMPLEX_DEPS
787               if (pool_is_complex_dep(pool, req))
788                 {
789                   /* we have AND/COND deps, normalize */
790                   add_complex_deprules(solv, n, req, SOLVER_RULE_RPM_PACKAGE_REQUIRES, dontfix, &workq, m);
791                   continue;
792                 }
793 #endif
794
795               /* find list of solvables providing 'req' */
796               dp = pool_whatprovides_ptr(pool, req);
797
798               if (*dp == SYSTEMSOLVABLE)          /* always installed */
799                 continue;
800
801               if (dontfix)
802                 {
803                   /* the strategy here is to not insist on dependencies
804                    * that are already broken. so if we find one provider
805                    * that was already installed, we know that the
806                    * dependency was not broken before so we enforce it */
807                   for (i = 0; (p = dp[i]) != 0; i++)
808                     if (pool->solvables[p].repo == installed)
809                       break;            /* found installed provider */
810                   if (!p)
811                     {
812                       /* didn't find an installed provider: previously broken dependency */
813                       POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s));
814                       continue;
815                     }
816                 }
817
818               if (!*dp)
819                 {
820                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req));
821                   addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP, req);
822                   continue;
823                 }
824
825               IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
826                 {
827                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION,"  %s requires %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
828                   for (i = 0; dp[i]; i++)
829                     POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "   provided by %s\n", pool_solvid2str(pool, dp[i]));
830                 }
831
832               /* add 'requires' dependency */
833               /* rule: (-requestor|provider1|provider2|...|providerN) */
834               addrpmrule(solv, -n, dp - pool->whatprovidesdata, SOLVER_RULE_RPM_PACKAGE_REQUIRES, req);
835
836               /* push all non-visited providers on the work queue */
837               if (m)
838                 for (; *dp; dp++)
839                   if (!MAPTST(m, *dp))
840                     queue_push(&workq, *dp);
841             }
842         }
843
844       /* that's all we check for src packages */
845       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
846         continue;
847
848       /*-----------------------------------------
849        * check conflicts of s
850        */
851
852       if (s->conflicts)
853         {
854           int ispatch = 0;
855
856           /* we treat conflicts in patches a bit differen:
857            * - nevr matching
858            * - multiversion handling
859            * XXX: we should really handle this different, looking
860            * at the name is a bad hack
861            */
862           if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
863             ispatch = 1;
864           conp = s->repo->idarraydata + s->conflicts;
865           /* foreach conflicts of 's' */
866           while ((con = *conp++) != 0)
867             {
868 #ifdef ENABLE_COMPLEX_DEPS
869               if (!ispatch && pool_is_complex_dep(pool, con))
870                 {
871                   /* we have AND/COND deps, normalize */
872                   add_complex_deprules(solv, n, con, SOLVER_RULE_RPM_PACKAGE_CONFLICT, dontfix, &workq, m);
873                   continue;
874                 }
875 #endif
876               /* foreach providers of a conflict of 's' */
877               FOR_PROVIDES(p, pp, con)
878                 {
879                   if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
880                     continue;
881                   /* dontfix: dont care about conflicts with already installed packs */
882                   if (dontfix && pool->solvables[p].repo == installed)
883                     continue;
884                   if (p == n)           /* p == n: self conflict */
885                     {
886                       if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con))
887                         continue;
888                       addrpmrule(solv, -n, 0, SOLVER_RULE_RPM_SELF_CONFLICT, con);
889                       continue;
890                     }
891                   if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con))
892                     {
893                       /* our patch conflicts with a multiversion package */
894                       p = -makemultiversionconflict(solv, p, con);
895                     }
896                   /* rule: -n|-p: either solvable _or_ provider of conflict */
897                   addrpmrule(solv, -n, p == SYSTEMSOLVABLE ? 0 : -p, SOLVER_RULE_RPM_PACKAGE_CONFLICT, con);
898                 }
899             }
900         }
901
902       /*-----------------------------------------
903        * check obsoletes and implicit obsoletes of a package
904        * if ignoreinstalledsobsoletes is not set, we're also checking
905        * obsoletes of installed packages (like newer rpm versions)
906        */
907       if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
908         {
909           int multi = solv->multiversion.size && MAPTST(&solv->multiversion, n);
910           int isinstalled = (installed && s->repo == installed);
911           if (s->obsoletes && (!multi || solv->keepexplicitobsoletes))
912             {
913               obsp = s->repo->idarraydata + s->obsoletes;
914               /* foreach obsoletes */
915               while ((obs = *obsp++) != 0)
916                 {
917                   /* foreach provider of an obsoletes of 's' */
918                   FOR_PROVIDES(p, pp, obs)
919                     {
920                       Solvable *ps = pool->solvables + p;
921                       if (p == n)
922                         continue;
923                       if (isinstalled && dontfix && ps->repo == installed)
924                         continue;       /* don't repair installed/installed problems */
925                       if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
926                           && !pool_match_nevr(pool, ps, obs))
927                         continue;
928                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
929                         continue;
930                       if (!isinstalled)
931                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_PACKAGE_OBSOLETES, obs);
932                       else
933                         addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES, obs);
934                     }
935                 }
936             }
937           /* check implicit obsoletes
938            * for installed packages we only need to check installed/installed problems (and
939            * only when dontfix is not set), as the others are picked up when looking at the
940            * uninstalled package.
941            */
942           if (!isinstalled || !dontfix)
943             {
944               FOR_PROVIDES(p, pp, s->name)
945                 {
946                   Solvable *ps = pool->solvables + p;
947                   if (p == n)
948                     continue;
949                   if (isinstalled && ps->repo != installed)
950                     continue;
951                   /* we still obsolete packages with same nevra, like rpm does */
952                   /* (actually, rpm mixes those packages. yuck...) */
953                   if (multi && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
954                     continue;
955                   if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
956                     continue;
957                   if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
958                     continue;
959                   if (s->name == ps->name)
960                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_SAME_NAME, 0);
961                   else
962                     addrpmrule(solv, -n, -p, SOLVER_RULE_RPM_IMPLICIT_OBSOLETES, s->name);
963                 }
964             }
965         }
966
967       if (m && pool->implicitobsoleteusescolors && (s->arch > pool->lastarch || pool->id2arch[s->arch] != 1))
968         {
969           int a = pool->id2arch[s->arch];
970           /* check lock-step candidates */
971           FOR_PROVIDES(p, pp, s->name)
972             {
973               Solvable *ps = pool->solvables + p;
974               if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p))
975                 continue;
976               if (ps->arch > pool->lastarch || pool->id2arch[ps->arch] == 1 || pool->id2arch[ps->arch] >= a)
977                 continue;
978               queue_push(&workq, p);
979             }
980         }
981
982       /*-----------------------------------------
983        * add recommends to the work queue
984        */
985       if (s->recommends && m)
986         {
987           recp = s->repo->idarraydata + s->recommends;
988           while ((rec = *recp++) != 0)
989             {
990               FOR_PROVIDES(p, pp, rec)
991                 if (!MAPTST(m, p))
992                   queue_push(&workq, p);
993             }
994         }
995       if (s->suggests && m)
996         {
997           sugp = s->repo->idarraydata + s->suggests;
998           while ((sug = *sugp++) != 0)
999             {
1000               FOR_PROVIDES(p, pp, sug)
1001                 if (!MAPTST(m, p))
1002                   queue_push(&workq, p);
1003             }
1004         }
1005     }
1006   queue_free(&workq);
1007 }
1008
1009 #ifdef ENABLE_LINKED_PKGS
1010 void
1011 solver_addrpmrulesforlinked(Solver *solv, Map *m)
1012 {
1013   Pool *pool = solv->pool;
1014   Solvable *s;
1015   int i, j;
1016   Queue qr;
1017
1018   queue_init(&qr);
1019   for (i = 1; i < pool->nsolvables; i++)
1020     {
1021       if (MAPTST(m, i))
1022         continue;
1023       s = pool->solvables + i;
1024       if (!s->repo || s->repo == solv->installed)
1025         continue;
1026       if (!strchr(pool_id2str(pool, s->name), ':'))
1027         continue;
1028       if (!pool_installable(pool, s))
1029         continue;
1030       find_package_link(pool, s, 0, &qr, 0, 0);
1031       if (qr.count)
1032         {
1033           for (j = 0; j < qr.count; j++)
1034             if (MAPTST(m, qr.elements[j]))
1035               {
1036                 solver_addrpmrulesforsolvable(solv, s, m);
1037                 break;
1038               }
1039           queue_empty(&qr);
1040         }
1041     }
1042   queue_free(&qr);
1043 }
1044 #endif
1045
1046 /*-------------------------------------------------------------------
1047  *
1048  * Add rules for packages possibly selected in by weak dependencies
1049  *
1050  * m: already added solvables
1051  */
1052
1053 void
1054 solver_addrpmrulesforweak(Solver *solv, Map *m)
1055 {
1056   Pool *pool = solv->pool;
1057   Solvable *s;
1058   Id sup, *supp;
1059   int i, n;
1060
1061   /* foreach solvable in pool */
1062   for (i = n = 1; n < pool->nsolvables; i++, n++)
1063     {
1064       if (i == pool->nsolvables)                /* wrap i */
1065         i = 1;
1066       if (MAPTST(m, i))                         /* already added that one */
1067         continue;
1068
1069       s = pool->solvables + i;
1070       if (!s->repo)
1071         continue;
1072       if (s->repo != pool->installed && !pool_installable(pool, s))
1073         continue;       /* only look at installable ones */
1074
1075       sup = 0;
1076       if (s->supplements)
1077         {
1078           /* find possible supplements */
1079           supp = s->repo->idarraydata + s->supplements;
1080           while ((sup = *supp++) != 0)
1081             if (dep_possible(solv, sup, m))
1082               break;
1083         }
1084
1085       /* if nothing found, check for enhances */
1086       if (!sup && s->enhances)
1087         {
1088           supp = s->repo->idarraydata + s->enhances;
1089           while ((sup = *supp++) != 0)
1090             if (dep_possible(solv, sup, m))
1091               break;
1092         }
1093       /* if nothing found, goto next solvables */
1094       if (!sup)
1095         continue;
1096       solver_addrpmrulesforsolvable(solv, s, m);
1097       n = 0;                    /* check all solvables again because we added solvables to m */
1098     }
1099 }
1100
1101
1102 /*-------------------------------------------------------------------
1103  *
1104  * add package rules for possible updates
1105  *
1106  * s: solvable
1107  * m: map of already visited solvables
1108  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
1109  */
1110
1111 void
1112 solver_addrpmrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
1113 {
1114   Pool *pool = solv->pool;
1115   int i;
1116     /* queue and buffer for it */
1117   Queue qs;
1118   Id qsbuf[64];
1119
1120   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1121     /* find update candidates for 's' */
1122   policy_findupdatepackages(solv, s, &qs, allow_all);
1123     /* add rule for 's' if not already done */
1124   if (!MAPTST(m, s - pool->solvables))
1125     solver_addrpmrulesforsolvable(solv, s, m);
1126     /* foreach update candidate, add rule if not already done */
1127   for (i = 0; i < qs.count; i++)
1128     if (!MAPTST(m, qs.elements[i]))
1129       solver_addrpmrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
1130   queue_free(&qs);
1131 }
1132
1133
1134 /***********************************************************************
1135  ***
1136  ***  Update/Feature rule part
1137  ***
1138  ***  Those rules make sure an installed package isn't silently deleted
1139  ***
1140  ***/
1141
1142 static Id
1143 finddistupgradepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
1144 {
1145   Pool *pool = solv->pool;
1146   int i;
1147
1148   policy_findupdatepackages(solv, s, qs, allow_all ? allow_all : 2);
1149   if (!qs->count)
1150     {
1151       if (allow_all)
1152         return 0;       /* orphaned, don't create feature rule */
1153       /* check if this is an orphaned package */
1154       policy_findupdatepackages(solv, s, qs, 1);
1155       if (!qs->count)
1156         return 0;       /* orphaned, don't create update rule */
1157       qs->count = 0;
1158       return -SYSTEMSOLVABLE;   /* supported but not installable */
1159     }
1160   if (allow_all)
1161     return s - pool->solvables;
1162   /* check if it is ok to keep the installed package */
1163   for (i = 0; i < qs->count; i++)
1164     {
1165       Solvable *ns = pool->solvables + qs->elements[i];
1166       if (s->evr == ns->evr && solvable_identical(s, ns))
1167         return s - pool->solvables;
1168     }
1169   /* nope, it must be some other package */
1170   return -SYSTEMSOLVABLE;
1171 }
1172
1173 /* add packages from the dup repositories to the update candidates
1174  * this isn't needed for the global dup mode as all packages are
1175  * from dup repos in that case */
1176 static void
1177 addduppackages(Solver *solv, Solvable *s, Queue *qs)
1178 {
1179   Queue dupqs;
1180   Id p, dupqsbuf[64];
1181   int i;
1182   int oldnoupdateprovide = solv->noupdateprovide;
1183
1184   queue_init_buffer(&dupqs, dupqsbuf, sizeof(dupqsbuf)/sizeof(*dupqsbuf));
1185   solv->noupdateprovide = 1;
1186   policy_findupdatepackages(solv, s, &dupqs, 2);
1187   solv->noupdateprovide = oldnoupdateprovide;
1188   for (i = 0; i < dupqs.count; i++)
1189     {
1190       p = dupqs.elements[i];
1191       if (MAPTST(&solv->dupmap, p))
1192         queue_pushunique(qs, p);
1193     }
1194   queue_free(&dupqs);
1195 }
1196
1197 /*-------------------------------------------------------------------
1198  *
1199  * add rule for update
1200  *   (A|A1|A2|A3...)  An = update candidates for A
1201  *
1202  * s = (installed) solvable
1203  */
1204
1205 void
1206 solver_addupdaterule(Solver *solv, Solvable *s, int allow_all)
1207 {
1208   /* installed packages get a special upgrade allowed rule */
1209   Pool *pool = solv->pool;
1210   Id p, d;
1211   Queue qs;
1212   Id qsbuf[64];
1213
1214   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1215   p = s - pool->solvables;
1216   /* find update candidates for 's' */
1217   if (solv->dupmap_all)
1218     p = finddistupgradepackages(solv, s, &qs, allow_all);
1219   else
1220     {
1221       policy_findupdatepackages(solv, s, &qs, allow_all);
1222       if (!allow_all && solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
1223         addduppackages(solv, s, &qs);
1224     }
1225
1226 #ifdef ENABLE_LINKED_PKGS
1227   if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
1228     {
1229       const char *name = pool_id2str(pool, s->name);
1230       if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
1231         {
1232           /* a linked pseudo package. As it is linked, we do not need an update rule */
1233           /* nevertheless we set specialupdaters so we can update */
1234           solver_addrule(solv, 0, 0);
1235           if (!allow_all && qs.count)
1236             {
1237               if (p != -SYSTEMSOLVABLE)
1238                 queue_unshift(&qs, p);
1239               if (!solv->specialupdaters)
1240                 solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
1241               solv->specialupdaters[s - pool->solvables - solv->installed->start] = pool_queuetowhatprovides(pool, &qs);
1242             }
1243           queue_free(&qs);
1244           return;
1245         }
1246     }
1247 #endif
1248
1249   if (!allow_all && qs.count && solv->multiversion.size)
1250     {
1251       int i, j;
1252
1253       for (i = 0; i < qs.count; i++)
1254         if (MAPTST(&solv->multiversion, qs.elements[i]))
1255           break;
1256       if (i < qs.count)
1257         {
1258           /* filter out all multiversion packages as they don't update */
1259           d = pool_queuetowhatprovides(pool, &qs);
1260           for (j = i; i < qs.count; i++)
1261              {
1262               if (MAPTST(&solv->multiversion, qs.elements[i]))
1263                 {
1264                   Solvable *ps = pool->solvables + qs.elements[i];
1265                   /* if keepexplicitobsoletes is set and the name is different,
1266                    * we assume that there is an obsoletes. XXX: not 100% correct */
1267                   if (solv->keepexplicitobsoletes && ps->name != s->name)
1268                     {
1269                       qs.elements[j++] = qs.elements[i];
1270                       continue;
1271                     }
1272                   /* it's ok if they have same nevra */
1273                   if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
1274                     continue;
1275                 }
1276               qs.elements[j++] = qs.elements[i];
1277             }
1278           if (j < qs.count)
1279             {
1280               if (d && solv->installed && s->repo == solv->installed &&
1281                   (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, s - pool->solvables - solv->installed->start))))
1282                 {
1283                   if (!solv->specialupdaters)
1284                     solv->specialupdaters = solv_calloc(solv->installed->end - solv->installed->start, sizeof(Id));
1285                   solv->specialupdaters[s - pool->solvables - solv->installed->start] = d;
1286                 }
1287               if (j == 0 && p == -SYSTEMSOLVABLE && solv->dupmap_all)
1288                 {
1289                   queue_push(&solv->orphaned, s - pool->solvables);     /* treat as orphaned */
1290                   j = qs.count;
1291                 }
1292               qs.count = j;
1293             }
1294           else if (p != -SYSTEMSOLVABLE)
1295             {
1296               /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
1297               queue_free(&qs);
1298               solver_addrule(solv, p, d);       /* allow update of s */
1299               return;
1300             }
1301         }
1302     }
1303   if (qs.count && p == -SYSTEMSOLVABLE)
1304     p = queue_shift(&qs);
1305   d = qs.count ? pool_queuetowhatprovides(pool, &qs) : 0;
1306   queue_free(&qs);
1307   solver_addrule(solv, p, d);   /* allow update of s */
1308 }
1309
1310 static inline void
1311 disableupdaterule(Solver *solv, Id p)
1312 {
1313   Rule *r;
1314
1315   MAPSET(&solv->noupdate, p - solv->installed->start);
1316   r = solv->rules + solv->updaterules + (p - solv->installed->start);
1317   if (r->p && r->d >= 0)
1318     solver_disablerule(solv, r);
1319   r = solv->rules + solv->featurerules + (p - solv->installed->start);
1320   if (r->p && r->d >= 0)
1321     solver_disablerule(solv, r);
1322   if (solv->bestrules_pkg)
1323     {
1324       int i, ni;
1325       ni = solv->bestrules_end - solv->bestrules;
1326       for (i = 0; i < ni; i++)
1327         if (solv->bestrules_pkg[i] == p)
1328           solver_disablerule(solv, solv->rules + solv->bestrules + i);
1329     }
1330 }
1331
1332 static inline void
1333 reenableupdaterule(Solver *solv, Id p)
1334 {
1335   Pool *pool = solv->pool;
1336   Rule *r;
1337
1338   MAPCLR(&solv->noupdate, p - solv->installed->start);
1339   r = solv->rules + solv->updaterules + (p - solv->installed->start);
1340   if (r->p)
1341     {
1342       if (r->d < 0)
1343         {
1344           solver_enablerule(solv, r);
1345           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1346             {
1347               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1348               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1349             }
1350         }
1351     }
1352   else
1353     {
1354       r = solv->rules + solv->featurerules + (p - solv->installed->start);
1355       if (r->p && r->d < 0)
1356         {
1357           solver_enablerule(solv, r);
1358           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1359             {
1360               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1361               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1362             }
1363         }
1364     }
1365   if (solv->bestrules_pkg)
1366     {
1367       int i, ni;
1368       ni = solv->bestrules_end - solv->bestrules;
1369       for (i = 0; i < ni; i++)
1370         if (solv->bestrules_pkg[i] == p)
1371           solver_enablerule(solv, solv->rules + solv->bestrules + i);
1372     }
1373 }
1374
1375
1376 /***********************************************************************
1377  ***
1378  ***  Infarch rule part
1379  ***
1380  ***  Infarch rules make sure the solver uses the best architecture of
1381  ***  a package if multiple archetectures are available
1382  ***
1383  ***/
1384
1385 void
1386 solver_addinfarchrules(Solver *solv, Map *addedmap)
1387 {
1388   Pool *pool = solv->pool;
1389   Repo *installed = pool->installed;
1390   int first, i, j;
1391   Id p, pp, a, aa, bestarch;
1392   Solvable *s, *ps, *bests;
1393   Queue badq, allowedarchs;
1394   Queue lsq;
1395
1396   queue_init(&badq);
1397   queue_init(&allowedarchs);
1398   queue_init(&lsq);
1399   solv->infarchrules = solv->nrules;
1400   for (i = 1; i < pool->nsolvables; i++)
1401     {
1402       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
1403         continue;
1404       s = pool->solvables + i;
1405       first = i;
1406       bestarch = 0;
1407       bests = 0;
1408       queue_empty(&allowedarchs);
1409       FOR_PROVIDES(p, pp, s->name)
1410         {
1411           ps = pool->solvables + p;
1412           if (ps->name != s->name || !MAPTST(addedmap, p))
1413             continue;
1414           if (p == i)
1415             first = 0;
1416           if (first)
1417             break;
1418           a = ps->arch;
1419           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1420           if (a != 1 && installed && ps->repo == installed)
1421             {
1422               if (!solv->dupmap_all && !(solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1423                 queue_pushunique(&allowedarchs, ps->arch);      /* also ok to keep this architecture */
1424               continue;         /* ignore installed solvables when calculating the best arch */
1425             }
1426           if (a && a != 1 && (!bestarch || a < bestarch))
1427             {
1428               bestarch = a;
1429               bests = ps;
1430             }
1431         }
1432       if (first)
1433         continue;
1434
1435       /* speed up common case where installed package already has best arch */
1436       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
1437         allowedarchs.count--;   /* installed arch is best */
1438
1439       if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestarch)
1440         {
1441           /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
1442            * if the corresponding installed package is not lock-stepped */
1443           queue_empty(&allowedarchs);
1444           FOR_PROVIDES(p, pp, s->name)
1445             {
1446               Id p2, pp2;
1447               ps = pool->solvables + p;
1448               if (ps->name != s->name || ps->repo != installed || !MAPTST(addedmap, p))
1449                 continue;
1450               if (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1451                 continue;
1452               a = ps->arch;
1453               a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1454               if (!a)
1455                 {
1456                   queue_pushunique(&allowedarchs, ps->arch);    /* strange arch, allow */
1457                   continue;
1458                 }
1459               if (a == 1 || ((a ^ bestarch) & 0xffff0000) == 0)
1460                 continue;
1461               /* have installed package with inferior arch, check if lock-stepped */
1462               FOR_PROVIDES(p2, pp2, s->name)
1463                 {
1464                   Solvable *s2 = pool->solvables + p2;
1465                   Id a2;
1466                   if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
1467                     continue;
1468                   a2 = s2->arch;
1469                   a2 = (a2 <= pool->lastarch) ? pool->id2arch[a2] : 0;
1470                   if (a2 && (a2 == 1 || ((a2 ^ bestarch) & 0xffff0000) == 0))
1471                     break;
1472                 }
1473               if (!p2)
1474                 queue_pushunique(&allowedarchs, ps->arch);
1475             }
1476         }
1477
1478       /* find all bad packages */
1479       queue_empty(&badq);
1480       FOR_PROVIDES(p, pp, s->name)
1481         {
1482           ps = pool->solvables + p;
1483           if (ps->name != s->name || !MAPTST(addedmap, p))
1484             continue;
1485           a = ps->arch;
1486           a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1487           if (a != 1 && bestarch && ((a ^ bestarch) & 0xffff0000) != 0)
1488             {
1489               if (installed && ps->repo == installed)
1490                 {
1491                   if (pool->implicitobsoleteusescolors)
1492                     queue_push(&badq, p);               /* special lock-step handling, see below */
1493                   continue;     /* always ok to keep an installed package */
1494                 }
1495               for (j = 0; j < allowedarchs.count; j++)
1496                 {
1497                   aa = allowedarchs.elements[j];
1498                   if (ps->arch == aa)
1499                     break;
1500                   aa = (aa <= pool->lastarch) ? pool->id2arch[aa] : 0;
1501                   if (aa && ((a ^ aa) & 0xffff0000) == 0)
1502                     break;      /* compatible */
1503                 }
1504               if (j == allowedarchs.count)
1505                 queue_push(&badq, p);
1506             }
1507         }
1508
1509       /* block all solvables in the badq! */
1510       for (j = 0; j < badq.count; j++)
1511         {
1512           p = badq.elements[j];
1513           /* lock-step */
1514           if (pool->implicitobsoleteusescolors)
1515             {
1516               Id p2;
1517               int haveinstalled = 0;
1518               queue_empty(&lsq);
1519               FOR_PROVIDES(p2, pp, s->name)
1520                 {
1521                   Solvable *s2 = pool->solvables + p2;
1522                   if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
1523                     continue;
1524                   a = s2->arch;
1525                   a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
1526                   if (a && (a == 1 || ((a ^ bestarch) & 0xffff000) == 0))
1527                     {
1528                       queue_push(&lsq, p2);
1529                       if (installed && s2->repo == installed)
1530                         haveinstalled = 1;
1531                     }
1532                 }
1533               if (installed && pool->solvables[p].repo == installed && !haveinstalled)
1534                 continue;       /* installed package not in lock-step */
1535             }
1536           solver_addrule(solv, -p, lsq.count ? pool_queuetowhatprovides(pool, &lsq) : 0);
1537         }
1538     }
1539   queue_free(&lsq);
1540   queue_free(&badq);
1541   queue_free(&allowedarchs);
1542   solv->infarchrules_end = solv->nrules;
1543 }
1544
1545 static inline void
1546 disableinfarchrule(Solver *solv, Id name)
1547 {
1548   Pool *pool = solv->pool;
1549   Rule *r;
1550   int i;
1551   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1552     {
1553       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
1554         solver_disablerule(solv, r);
1555     }
1556 }
1557
1558 static inline void
1559 reenableinfarchrule(Solver *solv, Id name)
1560 {
1561   Pool *pool = solv->pool;
1562   Rule *r;
1563   int i;
1564   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1565     {
1566       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
1567         {
1568           solver_enablerule(solv, r);
1569           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1570             {
1571               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1572               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1573             }
1574         }
1575     }
1576 }
1577
1578
1579 /***********************************************************************
1580  ***
1581  ***  Dup rule part
1582  ***
1583  ***  Dup rules make sure a package is selected from the specified dup
1584  ***  repositories if an update candidate is included in one of them.
1585  ***
1586  ***/
1587
1588 static inline void
1589 add_cleandeps_package(Solver *solv, Id p)
1590 {
1591   if (!solv->cleandeps_updatepkgs)
1592     {
1593       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
1594       queue_init(solv->cleandeps_updatepkgs);
1595     }
1596   queue_pushunique(solv->cleandeps_updatepkgs, p);
1597 }
1598
1599 static inline void
1600 solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
1601 {
1602   Pool *pool = solv->pool;
1603   Solvable *ps, *s = pool->solvables + p;
1604   Repo *installed = solv->installed;
1605   Id pi, pip, obs, *obsp;
1606
1607   MAPSET(&solv->dupinvolvedmap, p);
1608   if (targeted)
1609     MAPSET(&solv->dupmap, p);
1610   FOR_PROVIDES(pi, pip, s->name)
1611     {
1612       ps = pool->solvables + pi;
1613       if (ps->name != s->name)
1614         continue;
1615       MAPSET(&solv->dupinvolvedmap, pi);
1616       if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
1617         {
1618           Id *opp, pi2;
1619           for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
1620             if (pool->solvables[pi2].repo != installed)
1621               MAPSET(&solv->dupinvolvedmap, pi2);
1622         }
1623       if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
1624         {
1625           if (!solv->bestupdatemap.size)
1626             map_grow(&solv->bestupdatemap, installed->end - installed->start);
1627           MAPSET(&solv->bestupdatemap, pi - installed->start);
1628         }
1629       if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
1630         add_cleandeps_package(solv, pi);
1631       if (!targeted && ps->repo != installed)
1632         MAPSET(&solv->dupmap, pi);
1633     }
1634   if (s->repo == installed && solv->obsoletes && solv->obsoletes[p - installed->start])
1635     {
1636       Id *opp;
1637       for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (pi = *opp++) != 0;)
1638         {
1639           ps = pool->solvables + pi;
1640           if (ps->repo == installed)
1641             continue;
1642           MAPSET(&solv->dupinvolvedmap, pi);
1643           if (!targeted)
1644             MAPSET(&solv->dupmap, pi);
1645         }
1646     }
1647   if (targeted && s->repo != installed && s->obsoletes)
1648     {
1649       /* XXX: check obsoletes/provides combination */
1650       obsp = s->repo->idarraydata + s->obsoletes;
1651       while ((obs = *obsp++) != 0)
1652         {
1653           FOR_PROVIDES(pi, pip, obs)
1654             {
1655               Solvable *ps = pool->solvables + pi;
1656               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
1657                 continue;
1658               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1659                 continue;
1660               MAPSET(&solv->dupinvolvedmap, pi);
1661               if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
1662                 {
1663                   Id *opp, pi2;
1664                   for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
1665                     if (pool->solvables[pi2].repo != installed)
1666                       MAPSET(&solv->dupinvolvedmap, pi2);
1667                 }
1668               if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0)
1669                 {
1670                   if (!solv->bestupdatemap.size)
1671                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
1672                   MAPSET(&solv->bestupdatemap, pi - installed->start);
1673                 }
1674               if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
1675                 add_cleandeps_package(solv, pi);
1676             }
1677         }
1678     }
1679 }
1680
1681 void
1682 solver_createdupmaps(Solver *solv)
1683 {
1684   Queue *job = &solv->job;
1685   Pool *pool = solv->pool;
1686   Repo *installed = solv->installed;
1687   Id select, how, what, p, pp;
1688   Solvable *s;
1689   int i, targeted;
1690
1691   map_init(&solv->dupmap, pool->nsolvables);
1692   map_init(&solv->dupinvolvedmap, pool->nsolvables);
1693   for (i = 0; i < job->count; i += 2)
1694     {
1695       how = job->elements[i];
1696       select = job->elements[i] & SOLVER_SELECTMASK;
1697       what = job->elements[i + 1];
1698       switch (how & SOLVER_JOBMASK)
1699         {
1700         case SOLVER_DISTUPGRADE:
1701           if (select == SOLVER_SOLVABLE_REPO)
1702             {
1703               Repo *repo;
1704               if (what <= 0 || what > pool->nrepos)
1705                 break;
1706               repo = pool_id2repo(pool, what);
1707               if (!repo)
1708                 break;
1709               if (repo != installed && !(how & SOLVER_TARGETED) && solv->noautotarget)
1710                 break;
1711               targeted = repo != installed || (how & SOLVER_TARGETED) != 0;
1712               FOR_REPO_SOLVABLES(repo, p, s)
1713                 {
1714                   if (repo != installed && !pool_installable(pool, s))
1715                     continue;
1716                   solver_addtodupmaps(solv, p, how, targeted);
1717                 }
1718             }
1719           else
1720             {
1721               targeted = how & SOLVER_TARGETED ? 1 : 0;
1722               if (installed && !targeted && !solv->noautotarget)
1723                 {
1724                   FOR_JOB_SELECT(p, pp, select, what)
1725                     if (pool->solvables[p].repo == installed)
1726                       break;
1727                   targeted = p == 0;
1728                 }
1729               else if (!installed && !solv->noautotarget)
1730                 targeted = 1;
1731               FOR_JOB_SELECT(p, pp, select, what)
1732                 {
1733                   Solvable *s = pool->solvables + p;
1734                   if (!s->repo)
1735                     continue;
1736                   if (s->repo != installed && !targeted)
1737                     continue;
1738                   if (s->repo != installed && !pool_installable(pool, s))
1739                     continue;
1740                   solver_addtodupmaps(solv, p, how, targeted);
1741                 }
1742             }
1743           break;
1744         default:
1745           break;
1746         }
1747     }
1748   MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
1749 }
1750
1751 void
1752 solver_freedupmaps(Solver *solv)
1753 {
1754   map_free(&solv->dupmap);
1755   /* we no longer free solv->dupinvolvedmap as we need it in
1756    * policy's priority pruning code. sigh. */
1757 }
1758
1759 void
1760 solver_addduprules(Solver *solv, Map *addedmap)
1761 {
1762   Pool *pool = solv->pool;
1763   Id p, pp;
1764   Solvable *s, *ps;
1765   int first, i;
1766
1767   solv->duprules = solv->nrules;
1768   for (i = 1; i < pool->nsolvables; i++)
1769     {
1770       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
1771         continue;
1772       s = pool->solvables + i;
1773       first = i;
1774       FOR_PROVIDES(p, pp, s->name)
1775         {
1776           ps = pool->solvables + p;
1777           if (ps->name != s->name || !MAPTST(addedmap, p))
1778             continue;
1779           if (p == i)
1780             first = 0;
1781           if (first)
1782             break;
1783           if (!MAPTST(&solv->dupinvolvedmap, p))
1784             continue;
1785           if (solv->installed && ps->repo == solv->installed)
1786             {
1787               if (!solv->updatemap.size)
1788                 map_grow(&solv->updatemap, solv->installed->end - solv->installed->start);
1789               MAPSET(&solv->updatemap, p - solv->installed->start);
1790               if (!MAPTST(&solv->dupmap, p))
1791                 {
1792                   Id ip, ipp;
1793                   /* is installed identical to a good one? */
1794                   FOR_PROVIDES(ip, ipp, ps->name)
1795                     {
1796                       Solvable *is = pool->solvables + ip;
1797                       if (!MAPTST(&solv->dupmap, ip))
1798                         continue;
1799                       if (is->evr == ps->evr && solvable_identical(ps, is))
1800                         break;
1801                     }
1802                   if (!ip)
1803                     solver_addrule(solv, -p, 0);        /* no match, sorry */
1804                   else
1805                     MAPSET(&solv->dupmap, p);           /* for best rules processing */
1806                 }
1807             }
1808           else if (!MAPTST(&solv->dupmap, p))
1809             solver_addrule(solv, -p, 0);
1810         }
1811     }
1812   solv->duprules_end = solv->nrules;
1813 }
1814
1815
1816 static inline void
1817 disableduprule(Solver *solv, Id name)
1818 {
1819   Pool *pool = solv->pool;
1820   Rule *r;
1821   int i;
1822   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
1823     {
1824       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
1825         solver_disablerule(solv, r);
1826     }
1827 }
1828
1829 static inline void
1830 reenableduprule(Solver *solv, Id name)
1831 {
1832   Pool *pool = solv->pool;
1833   Rule *r;
1834   int i;
1835   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
1836     {
1837       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
1838         {
1839           solver_enablerule(solv, r);
1840           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1841             {
1842               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1843               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1844             }
1845         }
1846     }
1847 }
1848
1849
1850 /***********************************************************************
1851  ***
1852  ***  Policy rule disabling/reenabling
1853  ***
1854  ***  Disable all policy rules that conflict with our jobs. If a job
1855  ***  gets disabled later on, reenable the involved policy rules again.
1856  ***
1857  ***/
1858
1859 #define DISABLE_UPDATE  1
1860 #define DISABLE_INFARCH 2
1861 #define DISABLE_DUP     3
1862
1863 /*
1864  * add all installed packages that package p obsoletes to Queue q.
1865  * Package p is not installed. Also, we know that if
1866  * solv->keepexplicitobsoletes is not set, p is not in the multiversion map.
1867  * Entries may get added multiple times.
1868  */
1869 static void
1870 add_obsoletes(Solver *solv, Id p, Queue *q)
1871 {
1872   Pool *pool = solv->pool;
1873   Repo *installed = solv->installed;
1874   Id p2, pp2;
1875   Solvable *s = pool->solvables + p;
1876   Id obs, *obsp;
1877   Id lastp2 = 0;
1878
1879   if (!solv->keepexplicitobsoletes || !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
1880     {
1881       FOR_PROVIDES(p2, pp2, s->name)
1882         {
1883           Solvable *ps = pool->solvables + p2;
1884           if (ps->repo != installed)
1885             continue;
1886           if (!pool->implicitobsoleteusesprovides && ps->name != s->name)
1887             continue;
1888           if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
1889             continue;
1890           queue_push(q, p2);
1891           lastp2 = p2;
1892         }
1893     }
1894   if (!s->obsoletes)
1895     return;
1896   obsp = s->repo->idarraydata + s->obsoletes;
1897   while ((obs = *obsp++) != 0)
1898     FOR_PROVIDES(p2, pp2, obs)
1899       {
1900         Solvable *ps = pool->solvables + p2;
1901         if (ps->repo != installed)
1902           continue;
1903         if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
1904           continue;
1905         if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1906           continue;
1907         if (p2 == lastp2)
1908           continue;
1909         queue_push(q, p2);
1910         lastp2 = p2;
1911       }
1912 }
1913
1914 /*
1915  * Call add_obsoletes and intersect the result with the
1916  * elements in Queue q starting at qstart.
1917  * Assumes that it's the first call if qstart == q->count.
1918  * May use auxillary map m for the intersection process, all
1919  * elements of q starting at qstart must have their bit cleared.
1920  * (This is also true after the function returns.)
1921  */
1922 static void
1923 intersect_obsoletes(Solver *solv, Id p, Queue *q, int qstart, Map *m)
1924 {
1925   int i, j;
1926   int qcount = q->count;
1927
1928   add_obsoletes(solv, p, q);
1929   if (qcount == qstart)
1930     return;     /* first call */
1931   if (qcount == q->count)
1932     j = qstart; 
1933   else if (qcount == qstart + 1)
1934     {
1935       /* easy if there's just one element */
1936       j = qstart;
1937       for (i = qcount; i < q->count; i++)
1938         if (q->elements[i] == q->elements[qstart])
1939           {
1940             j++;        /* keep the element */
1941             break;
1942           }
1943     }
1944   else if (!m->size && q->count - qstart <= 8)
1945     {
1946       /* faster than a map most of the time */
1947       int k;
1948       for (i = j = qstart; i < qcount; i++)
1949         {
1950           Id ip = q->elements[i];
1951           for (k = qcount; k < q->count; k++)
1952             if (q->elements[k] == ip)
1953               {
1954                 q->elements[j++] = ip;
1955                 break;
1956               }
1957         }
1958     }
1959   else
1960     {
1961       /* for the really pathologic cases we use the map */
1962       Repo *installed = solv->installed;
1963       if (!m->size)
1964         map_init(m, installed->end - installed->start);
1965       for (i = qcount; i < q->count; i++)
1966         MAPSET(m, q->elements[i] - installed->start);
1967       for (i = j = qstart; i < qcount; i++)
1968         if (MAPTST(m, q->elements[i] - installed->start))
1969           {
1970             MAPCLR(m, q->elements[i] - installed->start);
1971             q->elements[j++] = q->elements[i];
1972           }
1973     }
1974   queue_truncate(q, j);
1975 }
1976
1977 static void
1978 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
1979 {
1980   Pool *pool = solv->pool;
1981   Id select, p, pp;
1982   Repo *installed;
1983   Solvable *s;
1984   int i, j, set, qstart;
1985   Map omap;
1986
1987   installed = solv->installed;
1988   select = how & SOLVER_SELECTMASK;
1989   switch (how & SOLVER_JOBMASK)
1990     {
1991     case SOLVER_INSTALL:
1992       set = how & SOLVER_SETMASK;
1993       if (!(set & SOLVER_NOAUTOSET))
1994         {
1995           /* automatically add set bits by analysing the job */
1996           if (select == SOLVER_SOLVABLE_NAME)
1997             set |= SOLVER_SETNAME;
1998           if (select == SOLVER_SOLVABLE)
1999             set |= SOLVER_SETNAME | SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
2000           else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
2001             {
2002               Reldep *rd = GETRELDEP(pool, what);
2003               if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
2004                 {
2005                   if (pool->disttype != DISTTYPE_DEB)
2006                     {
2007                       const char *rel = strrchr(pool_id2str(pool, rd->evr), '-');
2008                       set |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
2009                     }
2010                   else
2011                     set |= SOLVER_SETEVR;
2012                 }
2013               if (rd->flags <= 7 && ISRELDEP(rd->name))
2014                 rd = GETRELDEP(pool, rd->name);
2015               if (rd->flags == REL_ARCH)
2016                 set |= SOLVER_SETARCH;
2017             }
2018         }
2019       else
2020         set &= ~SOLVER_NOAUTOSET;
2021       if (!set)
2022         return;
2023       if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
2024         {
2025           if (select == SOLVER_SOLVABLE)
2026             queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
2027           else
2028             {
2029               int qcnt = q->count;
2030               /* does not work for SOLVER_SOLVABLE_ALL and SOLVER_SOLVABLE_REPO, but
2031                  they are not useful for SOLVER_INSTALL jobs anyway */
2032               FOR_JOB_SELECT(p, pp, select, what)
2033                 {
2034                   s = pool->solvables + p;
2035                   /* unify names */
2036                   for (i = qcnt; i < q->count; i += 2)
2037                     if (q->elements[i + 1] == s->name)
2038                       break;
2039                   if (i < q->count)
2040                     continue;
2041                   queue_push2(q, DISABLE_INFARCH, s->name);
2042                 }
2043             }
2044         }
2045       if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
2046         {
2047           if (select == SOLVER_SOLVABLE)
2048             queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
2049           else
2050             {
2051               int qcnt = q->count;
2052               FOR_JOB_SELECT(p, pp, select, what)
2053                 {
2054                   s = pool->solvables + p;
2055                   /* unify names */
2056                   for (i = qcnt; i < q->count; i += 2)
2057                     if (q->elements[i + 1] == s->name)
2058                       break;
2059                   if (i < q->count)
2060                     continue;
2061                   queue_push2(q, DISABLE_DUP, s->name);
2062                 }
2063             }
2064         }
2065       if (!installed || installed->end == installed->start)
2066         return;
2067       /* now the hard part: disable some update rules */
2068
2069       /* first check if we have multiversion or installed packages in the job */
2070       i = j = 0;
2071       FOR_JOB_SELECT(p, pp, select, what)
2072         {
2073           if (pool->solvables[p].repo == installed)
2074             j = p;
2075           else if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
2076             return;
2077           i++;
2078         }
2079       if (j)    /* have installed packages */
2080         {
2081           /* this is for dupmap_all jobs, it can go away if we create
2082            * duprules for them */
2083           if (i == 1 && (set & SOLVER_SETREPO) != 0)
2084             queue_push2(q, DISABLE_UPDATE, j);
2085           return;
2086         }
2087
2088       omap.size = 0;
2089       qstart = q->count;
2090       FOR_JOB_SELECT(p, pp, select, what)
2091         {
2092           intersect_obsoletes(solv, p, q, qstart, &omap);
2093           if (q->count == qstart)
2094             break;
2095         }
2096       if (omap.size)
2097         map_free(&omap);
2098
2099       if (qstart == q->count)
2100         return;         /* nothing to prune */
2101
2102       /* convert result to (DISABLE_UPDATE, p) pairs */
2103       i = q->count;
2104       for (j = qstart; j < i; j++)
2105         queue_push(q, q->elements[j]);
2106       for (j = qstart; j < q->count; j += 2)
2107         {
2108           q->elements[j] = DISABLE_UPDATE;
2109           q->elements[j + 1] = q->elements[i++];
2110         }
2111
2112       /* now that we know which installed packages are obsoleted check each of them */
2113       if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
2114         return;         /* all is set, nothing to do */
2115
2116       for (i = j = qstart; i < q->count; i += 2)
2117         {
2118           Solvable *is = pool->solvables + q->elements[i + 1];
2119           FOR_JOB_SELECT(p, pp, select, what)
2120             {
2121               int illegal = 0;
2122               s = pool->solvables + p;
2123               if ((set & SOLVER_SETEVR) != 0)
2124                 illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
2125               if ((set & SOLVER_SETNAME) != 0)
2126                 illegal |= POLICY_ILLEGAL_NAMECHANGE;   /* ignore */
2127               if ((set & SOLVER_SETARCH) != 0)
2128                 illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
2129               if ((set & SOLVER_SETVENDOR) != 0)
2130                 illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
2131               illegal = policy_is_illegal(solv, is, s, illegal);
2132               if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
2133                 {
2134                   /* it's ok if the EV is different */
2135                   if (pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
2136                     illegal = 0;
2137                 }
2138               if (illegal)
2139                 break;
2140             }
2141           if (!p)
2142             {   
2143               /* no package conflicts with the update rule */
2144               /* thus keep the DISABLE_UPDATE */
2145               q->elements[j + 1] = q->elements[i + 1];
2146               j += 2;
2147             }
2148         }
2149       queue_truncate(q, j);
2150       return;
2151
2152     case SOLVER_ERASE:
2153       if (!installed)
2154         break;
2155       if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
2156         FOR_REPO_SOLVABLES(installed, p, s)
2157           queue_push2(q, DISABLE_UPDATE, p);
2158       FOR_JOB_SELECT(p, pp, select, what)
2159         if (pool->solvables[p].repo == installed)
2160           {
2161             queue_push2(q, DISABLE_UPDATE, p);
2162 #ifdef ENABLE_LINKED_PKGS
2163             if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
2164               queue_push2(q, DISABLE_UPDATE, solv->instbuddy[p - installed->start]);
2165 #endif
2166           }
2167       return;
2168     default:
2169       return;
2170     }
2171 }
2172
2173 /* disable all policy rules that are in conflict with our job list */
2174 void
2175 solver_disablepolicyrules(Solver *solv)
2176 {
2177   Queue *job = &solv->job;
2178   int i, j;
2179   Queue allq;
2180   Rule *r;
2181   Id lastjob = -1;
2182   Id allqbuf[128];
2183
2184   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2185
2186   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2187     {
2188       r = solv->rules + i;
2189       if (r->d < 0)     /* disabled? */
2190         continue;
2191       j = solv->ruletojob.elements[i - solv->jobrules];
2192       if (j == lastjob)
2193         continue;
2194       lastjob = j;
2195       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2196     }
2197   if (solv->cleandepsmap.size)
2198     {
2199       solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
2200       for (i = solv->installed->start; i < solv->installed->end; i++)
2201         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
2202           queue_push2(&allq, DISABLE_UPDATE, i);
2203     }
2204   MAPZERO(&solv->noupdate);
2205   for (i = 0; i < allq.count; i += 2)
2206     {
2207       Id type = allq.elements[i], arg = allq.elements[i + 1];
2208       switch(type)
2209         {
2210         case DISABLE_UPDATE:
2211           disableupdaterule(solv, arg);
2212           break;
2213         case DISABLE_INFARCH:
2214           disableinfarchrule(solv, arg);
2215           break;
2216         case DISABLE_DUP:
2217           disableduprule(solv, arg);
2218           break;
2219         default:
2220           break;
2221         }
2222     }
2223   queue_free(&allq);
2224 }
2225
2226 /* we just disabled job #jobidx, now reenable all policy rules that were
2227  * disabled because of this job */
2228 void
2229 solver_reenablepolicyrules(Solver *solv, int jobidx)
2230 {
2231   Queue *job = &solv->job;
2232   int i, j, k, ai;
2233   Queue q, allq;
2234   Rule *r;
2235   Id lastjob = -1;
2236   Id qbuf[32], allqbuf[32];
2237
2238   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
2239   jobtodisablelist(solv, job->elements[jobidx - 1], job->elements[jobidx], &q);
2240   if (!q.count)
2241     {
2242       queue_free(&q);
2243       return;
2244     }
2245   /* now remove everything from q that is disabled by other jobs */
2246
2247   /* first remove cleandeps packages, they count as DISABLE_UPDATE */
2248   if (solv->cleandepsmap.size)
2249     {
2250       solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
2251       for (j = k = 0; j < q.count; j += 2)
2252         {
2253           if (q.elements[j] == DISABLE_UPDATE)
2254             {
2255               Id p = q.elements[j + 1];
2256               if (p >= solv->installed->start && p < solv->installed->end && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2257                 continue;       /* remove element from q */
2258             }
2259           q.elements[k++] = q.elements[j];
2260           q.elements[k++] = q.elements[j + 1];
2261         }
2262       q.count = k;
2263       if (!q.count)
2264         {
2265           queue_free(&q);
2266           return;
2267         }
2268     }
2269
2270   /* now go through the disable list of all other jobs */
2271   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2272   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2273     {
2274       r = solv->rules + i;
2275       if (r->d < 0)     /* disabled? */
2276         continue;
2277       j = solv->ruletojob.elements[i - solv->jobrules];
2278       if (j == lastjob)
2279         continue;
2280       lastjob = j;
2281       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2282       if (!allq.count)
2283         continue;
2284       /* remove all elements in allq from q */
2285       for (j = k = 0; j < q.count; j += 2)
2286         {
2287           Id type = q.elements[j], arg = q.elements[j + 1];
2288           for (ai = 0; ai < allq.count; ai += 2)
2289             if (allq.elements[ai] == type && allq.elements[ai + 1] == arg)
2290               break;
2291           if (ai < allq.count)
2292             continue;   /* found it in allq, remove element from q */
2293           q.elements[k++] = q.elements[j];
2294           q.elements[k++] = q.elements[j + 1];
2295         }
2296       q.count = k;
2297       if (!q.count)
2298         {
2299           queue_free(&q);
2300           queue_free(&allq);
2301           return;
2302         }
2303       queue_empty(&allq);
2304     }
2305   queue_free(&allq);
2306
2307   /* now re-enable anything that's left in q */
2308   for (j = 0; j < q.count; j += 2)
2309     {
2310       Id type = q.elements[j], arg = q.elements[j + 1];
2311       switch(type)
2312         {
2313         case DISABLE_UPDATE:
2314           reenableupdaterule(solv, arg);
2315           break;
2316         case DISABLE_INFARCH:
2317           reenableinfarchrule(solv, arg);
2318           break;
2319         case DISABLE_DUP:
2320           reenableduprule(solv, arg);
2321           break;
2322         }
2323     }
2324   queue_free(&q);
2325 }
2326
2327 /* we just removed a package from the cleandeps map, now reenable all policy rules that were
2328  * disabled because of this */
2329 void
2330 solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg)
2331 {
2332   Queue *job = &solv->job;
2333   int i, j;
2334   Queue allq;
2335   Rule *r;
2336   Id lastjob = -1;
2337   Id allqbuf[128];
2338
2339   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2340   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2341     {
2342       r = solv->rules + i;
2343       if (r->d < 0)     /* disabled? */
2344         continue;
2345       j = solv->ruletojob.elements[i - solv->jobrules];
2346       if (j == lastjob)
2347         continue;
2348       lastjob = j;
2349       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2350     }
2351   for (i = 0; i < allq.count; i += 2)
2352     if (allq.elements[i] == DISABLE_UPDATE && allq.elements[i + 1] == pkg)
2353       break;
2354   if (i == allq.count)
2355     reenableupdaterule(solv, pkg);
2356   queue_free(&allq);
2357 }
2358
2359
2360 /***********************************************************************
2361  ***
2362  ***  Rule info part, tell the user what the rule is about.
2363  ***
2364  ***/
2365
2366 static void
2367 addrpmruleinfo(Solver *solv, Id p, Id d, int type, Id dep)
2368 {
2369   Pool *pool = solv->pool;
2370   Rule *r;
2371   Id w2, op, od, ow2;
2372
2373   /* check if this creates the rule we're searching for */
2374   r = solv->rules + solv->ruleinfoq->elements[0];
2375   op = r->p;
2376   od = r->d < 0 ? -r->d - 1 : r->d;
2377   ow2 = 0;
2378
2379   /* normalize */
2380   w2 = d > 0 ? 0 : d;
2381   if (p < 0 && d > 0 && (!pool->whatprovidesdata[d] || !pool->whatprovidesdata[d + 1]))
2382     {
2383       w2 = pool->whatprovidesdata[d];
2384       d = 0;
2385     }
2386   if (p > 0 && d < 0)           /* this hack is used for package links and complex deps */
2387     {
2388       w2 = p;
2389       p = d;
2390     }
2391
2392   if (d > 0)
2393     {
2394       if (p != op && !od)
2395         return;
2396       if (d != od)
2397         {
2398           Id *dp = pool->whatprovidesdata + d;
2399           Id *odp = pool->whatprovidesdata + od;
2400           while (*dp)
2401             if (*dp++ != *odp++)
2402               return;
2403           if (*odp)
2404             return;
2405         }
2406       w2 = 0;
2407       /* handle multiversion conflict rules */
2408       if (p < 0 && pool->whatprovidesdata[d] < 0)
2409         {
2410           w2 = pool->whatprovidesdata[d];
2411           /* XXX: free memory */
2412         }
2413     }
2414   else
2415     {
2416       if (od)
2417         return;
2418       ow2 = r->w2;
2419       if (p > w2)
2420         {
2421           if (w2 != op || p != ow2)
2422             return;
2423         }
2424       else
2425         {
2426           if (p != op || w2 != ow2)
2427             return;
2428         }
2429       /* should use a different type instead */
2430       if (type == SOLVER_RULE_RPM_PACKAGE_CONFLICT && !w2)
2431         w2 = -SYSTEMSOLVABLE;
2432     }
2433   /* yep, rule matches. record info */
2434   queue_push(solv->ruleinfoq, type);
2435   if (type == SOLVER_RULE_RPM_SAME_NAME)
2436     {
2437       /* we normalize same name order */
2438       queue_push(solv->ruleinfoq, op < 0 ? -op : 0);
2439       queue_push(solv->ruleinfoq, ow2 < 0 ? -ow2 : 0);
2440     }
2441   else
2442     {
2443       queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
2444       queue_push(solv->ruleinfoq, w2 < 0 ? -w2 : 0);
2445     }
2446   queue_push(solv->ruleinfoq, dep);
2447 }
2448
2449 static int
2450 solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
2451 {
2452   const Id *a = ap, *b = bp;
2453   int r;
2454
2455   r = a[0] - b[0];
2456   if (r)
2457     return r;
2458   r = a[1] - b[1];
2459   if (r)
2460     return r;
2461   r = a[2] - b[2];
2462   if (r)
2463     return r;
2464   r = a[3] - b[3];
2465   if (r)
2466     return r;
2467   return 0;
2468 }
2469
2470 static void
2471 getrpmruleinfos(Solver *solv, Rule *r, Queue *rq)
2472 {
2473   Pool *pool = solv->pool;
2474   Id l, pp;
2475   if (r->p >= 0)
2476     return;
2477   queue_push(rq, r - solv->rules);      /* push the rule we're interested in */
2478   solv->ruleinfoq = rq;
2479   FOR_RULELITERALS(l, pp, r)
2480     {
2481       if (l >= 0)
2482         break;
2483       solver_addrpmrulesforsolvable(solv, pool->solvables - l, 0);
2484     }
2485 #ifdef ENABLE_LINKED_PKGS
2486   FOR_RULELITERALS(l, pp, r)
2487     {
2488       if (l < 0 || l != r->p)
2489         break;
2490       if (!strchr(pool_id2str(pool, pool->solvables[l].name), ':') || !has_package_link(pool, pool->solvables + l))
2491         break;
2492       add_package_link(solv, pool->solvables + l, 0, 0);
2493     }
2494 #endif
2495   solv->ruleinfoq = 0;
2496   queue_shift(rq);
2497 }
2498
2499 int
2500 solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
2501 {
2502   Rule *r = solv->rules + rid;
2503   int i, j;
2504
2505   queue_empty(rq);
2506   if (rid <= 0 || rid >= solv->rpmrules_end)
2507     {
2508       Id type, from, to, dep;
2509       type = solver_ruleinfo(solv, rid, &from, &to, &dep);
2510       queue_push(rq, type);
2511       queue_push(rq, from);
2512       queue_push(rq, to);
2513       queue_push(rq, dep);
2514       return 1;
2515     }
2516   getrpmruleinfos(solv, r, rq);
2517   /* now sort & unify em */
2518   if (!rq->count)
2519     return 0;
2520   solv_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
2521   /* throw out identical entries */
2522   for (i = j = 0; i < rq->count; i += 4)
2523     {
2524       if (j)
2525         {
2526           if (rq->elements[i] == rq->elements[j - 4] &&
2527               rq->elements[i + 1] == rq->elements[j - 3] &&
2528               rq->elements[i + 2] == rq->elements[j - 2] &&
2529               rq->elements[i + 3] == rq->elements[j - 1])
2530             continue;
2531         }
2532       rq->elements[j++] = rq->elements[i];
2533       rq->elements[j++] = rq->elements[i + 1];
2534       rq->elements[j++] = rq->elements[i + 2];
2535       rq->elements[j++] = rq->elements[i + 3];
2536     }
2537   rq->count = j;
2538   return j / 4;
2539 }
2540
2541 SolverRuleinfo
2542 solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
2543 {
2544   Pool *pool = solv->pool;
2545   Rule *r = solv->rules + rid;
2546   SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
2547
2548   if (fromp)
2549     *fromp = 0;
2550   if (top)
2551     *top = 0;
2552   if (depp)
2553     *depp = 0;
2554   if (rid > 0 && rid < solv->rpmrules_end)
2555     {
2556       Queue rq;
2557       int i;
2558
2559       if (r->p >= 0)
2560         return SOLVER_RULE_RPM;
2561       if (fromp)
2562         *fromp = -r->p;
2563       queue_init(&rq);
2564       getrpmruleinfos(solv, r, &rq);
2565       type = SOLVER_RULE_RPM;
2566       for (i = 0; i < rq.count; i += 4)
2567         {
2568           Id qt, qo, qp, qd;
2569           qt = rq.elements[i];
2570           qp = rq.elements[i + 1];
2571           qo = rq.elements[i + 2];
2572           qd = rq.elements[i + 3];
2573           if (type == SOLVER_RULE_RPM || type > qt)
2574             {
2575               type = qt;
2576               if (fromp)
2577                 *fromp = qp;
2578               if (top)
2579                 *top = qo;
2580               if (depp)
2581                 *depp = qd;
2582             }
2583         }
2584       queue_free(&rq);
2585       return type;
2586     }
2587   if (rid >= solv->jobrules && rid < solv->jobrules_end)
2588     {
2589       Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
2590       if (fromp)
2591         *fromp = jidx;
2592       if (top)
2593         *top = solv->job.elements[jidx];
2594       if (depp)
2595         *depp = solv->job.elements[jidx + 1];
2596       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
2597         {
2598           Id how = solv->job.elements[jidx];
2599           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
2600             return SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
2601           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
2602             return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
2603           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
2604             return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
2605           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
2606             return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
2607           return SOLVER_RULE_JOB_UNSUPPORTED;
2608         }
2609       return SOLVER_RULE_JOB;
2610     }
2611   if (rid >= solv->updaterules && rid < solv->updaterules_end)
2612     {
2613       if (fromp)
2614         *fromp = solv->installed->start + (rid - solv->updaterules);
2615       return SOLVER_RULE_UPDATE;
2616     }
2617   if (rid >= solv->featurerules && rid < solv->featurerules_end)
2618     {
2619       if (fromp)
2620         *fromp = solv->installed->start + (rid - solv->featurerules);
2621       return SOLVER_RULE_FEATURE;
2622     }
2623   if (rid >= solv->duprules && rid < solv->duprules_end)
2624     {
2625       if (fromp)
2626         *fromp = -r->p;
2627       if (depp)
2628         *depp = pool->solvables[-r->p].name;
2629       return SOLVER_RULE_DISTUPGRADE;
2630     }
2631   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
2632     {
2633       if (fromp)
2634         *fromp = -r->p;
2635       if (depp)
2636         *depp = pool->solvables[-r->p].name;
2637       return SOLVER_RULE_INFARCH;
2638     }
2639   if (rid >= solv->bestrules && rid < solv->bestrules_end)
2640     {
2641       return SOLVER_RULE_BEST;
2642     }
2643   if (rid >= solv->choicerules && rid < solv->choicerules_end)
2644     {
2645       return SOLVER_RULE_CHOICE;
2646     }
2647   if (rid >= solv->learntrules)
2648     {
2649       return SOLVER_RULE_LEARNT;
2650     }
2651   return SOLVER_RULE_UNKNOWN;
2652 }
2653
2654 SolverRuleinfo
2655 solver_ruleclass(Solver *solv, Id rid)
2656 {
2657   if (rid <= 0)
2658     return SOLVER_RULE_UNKNOWN;
2659   if (rid > 0 && rid < solv->rpmrules_end)
2660     return SOLVER_RULE_RPM;
2661   if (rid >= solv->jobrules && rid < solv->jobrules_end)
2662     return SOLVER_RULE_JOB;
2663   if (rid >= solv->updaterules && rid < solv->updaterules_end)
2664     return SOLVER_RULE_UPDATE;
2665   if (rid >= solv->featurerules && rid < solv->featurerules_end)
2666     return SOLVER_RULE_FEATURE;
2667   if (rid >= solv->duprules && rid < solv->duprules_end)
2668     return SOLVER_RULE_DISTUPGRADE;
2669   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
2670     return SOLVER_RULE_INFARCH;
2671   if (rid >= solv->bestrules && rid < solv->bestrules_end)
2672     return SOLVER_RULE_BEST;
2673   if (rid >= solv->choicerules && rid < solv->choicerules_end)
2674     return SOLVER_RULE_CHOICE;
2675   if (rid >= solv->learntrules)
2676     return SOLVER_RULE_LEARNT;
2677   return SOLVER_RULE_UNKNOWN;
2678 }
2679
2680 void
2681 solver_ruleliterals(Solver *solv, Id rid, Queue *q)
2682 {
2683   Pool *pool = solv->pool;
2684   Id p, pp;
2685   Rule *r;
2686
2687   queue_empty(q);
2688   r = solv->rules + rid;
2689   FOR_RULELITERALS(p, pp, r)
2690     if (p != -SYSTEMSOLVABLE)
2691       queue_push(q, p);
2692   if (!q->count)
2693     queue_push(q, -SYSTEMSOLVABLE);     /* hmm, better to return an empty result? */
2694 }
2695
2696 int
2697 solver_rule2jobidx(Solver *solv, Id rid)
2698 {
2699   if (rid < solv->jobrules || rid >= solv->jobrules_end)
2700     return 0;
2701   return solv->ruletojob.elements[rid - solv->jobrules] + 1;
2702 }
2703
2704 /* job rule introspection */
2705 Id
2706 solver_rule2job(Solver *solv, Id rid, Id *whatp)
2707 {
2708   int idx;
2709   if (rid < solv->jobrules || rid >= solv->jobrules_end)
2710     {
2711       if (whatp)
2712         *whatp = 0;
2713       return 0;
2714     }
2715   idx = solv->ruletojob.elements[rid - solv->jobrules];
2716   if (whatp)
2717     *whatp = solv->job.elements[idx + 1];
2718   return solv->job.elements[idx];
2719 }
2720
2721 /* update/feature rule introspection */
2722 Id
2723 solver_rule2solvable(Solver *solv, Id rid)
2724 {
2725   if (rid >= solv->updaterules && rid < solv->updaterules_end)
2726     return rid - solv->updaterules;
2727   if (rid >= solv->featurerules && rid < solv->featurerules_end)
2728     return rid - solv->featurerules;
2729   return 0;
2730 }
2731
2732 static void
2733 solver_rule2rules_rec(Solver *solv, Id rid, Queue *q, Map *seen)
2734 {
2735   int i;
2736   Id rid2;
2737
2738   if (seen)
2739     MAPSET(seen, rid);
2740   for (i = solv->learnt_why.elements[rid - solv->learntrules]; (rid2 = solv->learnt_pool.elements[i]) != 0; i++)
2741     {
2742       if (seen)
2743         {
2744           if (MAPTST(seen, rid2))
2745             continue;
2746           if (rid2 >= solv->learntrules)
2747             solver_rule2rules_rec(solv, rid2, q, seen);
2748           continue;
2749         }
2750       queue_push(q, rid2);
2751     }
2752 }
2753
2754 /* learnt rule introspection */
2755 void
2756 solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
2757 {
2758   queue_empty(q);
2759   if (rid < solv->learntrules || rid >= solv->nrules)
2760     return;
2761   if (recursive)
2762     {
2763       Map seen;
2764       map_init(&seen, solv->nrules);
2765       solver_rule2rules_rec(solv, rid, q, &seen);
2766       map_free(&seen);
2767     }
2768   else
2769     solver_rule2rules_rec(solv, rid, q, 0);
2770 }
2771
2772
2773 /* check if the newest versions of pi still provides the dependency we're looking for */
2774 static int
2775 solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m)
2776 {
2777   Pool *pool = solv->pool;
2778   Rule *ur;
2779   Queue q;
2780   Id p, pp, qbuf[32];
2781   int i;
2782
2783   ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
2784   if (!ur->p)
2785     ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
2786   if (!ur->p)
2787     return 0;
2788   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
2789   FOR_RULELITERALS(p, pp, ur)
2790     if (p > 0)
2791       queue_push(&q, p);
2792   if (q.count > 1)
2793     policy_filter_unwanted(solv, &q, POLICY_MODE_CHOOSE);
2794   for (i = 0; i < q.count; i++)
2795     if (MAPTST(m, q.elements[i]))
2796       break;
2797   /* 1: none of the newest versions provide it */
2798   i = i == q.count ? 1 : 0;
2799   queue_free(&q);
2800   return i;
2801 }
2802
2803 static inline void
2804 queue_removeelement(Queue *q, Id el)
2805 {
2806   int i, j;
2807   for (i = 0; i < q->count; i++)
2808     if (q->elements[i] == el)
2809       break;
2810   if (i < q->count)
2811     {
2812       for (j = i++; i < q->count; i++)
2813         if (q->elements[i] != el)
2814           q->elements[j++] = q->elements[i];
2815       queue_truncate(q, j);
2816     }
2817 }
2818
2819 void
2820 solver_addchoicerules(Solver *solv)
2821 {
2822   Pool *pool = solv->pool;
2823   Map m, mneg;
2824   Rule *r;
2825   Queue q, qi;
2826   int i, j, rid, havechoice;
2827   Id p, d, pp;
2828   Id p2, pp2;
2829   Solvable *s, *s2;
2830   Id lastaddedp, lastaddedd;
2831   int lastaddedcnt;
2832   unsigned int now;
2833
2834   solv->choicerules = solv->nrules;
2835   if (!pool->installed)
2836     {
2837       solv->choicerules_end = solv->nrules;
2838       return;
2839     }
2840   now = solv_timems(0);
2841   solv->choicerules_ref = solv_calloc(solv->rpmrules_end, sizeof(Id));
2842   queue_init(&q);
2843   queue_init(&qi);
2844   map_init(&m, pool->nsolvables);
2845   map_init(&mneg, pool->nsolvables);
2846   /* set up negative assertion map from infarch and dup rules */
2847   for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
2848     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
2849       MAPSET(&mneg, -r->p);
2850   for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
2851     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
2852       MAPSET(&mneg, -r->p);
2853   lastaddedp = 0;
2854   lastaddedd = 0;
2855   lastaddedcnt = 0;
2856   for (rid = 1; rid < solv->rpmrules_end ; rid++)
2857     {
2858       r = solv->rules + rid;
2859       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0))
2860         continue;       /* only look at requires rules */
2861       /* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */
2862       queue_empty(&q);
2863       queue_empty(&qi);
2864       havechoice = 0;
2865       FOR_RULELITERALS(p, pp, r)
2866         {
2867           if (p < 0)
2868             continue;
2869           s = pool->solvables + p;
2870           if (!s->repo)
2871             continue;
2872           if (s->repo == pool->installed)
2873             {
2874               queue_push(&q, p);
2875               continue;
2876             }
2877           /* check if this package is "blocked" by a installed package */
2878           s2 = 0;
2879           FOR_PROVIDES(p2, pp2, s->name)
2880             {
2881               s2 = pool->solvables + p2;
2882               if (s2->repo != pool->installed)
2883                 continue;
2884               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
2885                 continue;
2886               if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
2887                 continue;
2888               break;
2889             }
2890           if (p2)
2891             {
2892               /* found installed package p2 that we can update to p */
2893               if (MAPTST(&mneg, p))
2894                 continue;
2895               if (policy_is_illegal(solv, s2, s, 0))
2896                 continue;
2897 #if 0
2898               if (solver_choicerulecheck(solv, p2, r, &m))
2899                 continue;
2900               queue_push(&qi, p2);
2901 #else
2902               queue_push2(&qi, p2, p);
2903 #endif
2904               queue_push(&q, p);
2905               continue;
2906             }
2907           if (s->obsoletes)
2908             {
2909               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
2910               s2 = 0;
2911               while ((obs = *obsp++) != 0)
2912                 {
2913                   FOR_PROVIDES(p2, pp2, obs)
2914                     {
2915                       s2 = pool->solvables + p2;
2916                       if (s2->repo != pool->installed)
2917                         continue;
2918                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
2919                         continue;
2920                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
2921                         continue;
2922                       break;
2923                     }
2924                   if (p2)
2925                     break;
2926                 }
2927               if (obs)
2928                 {
2929                   /* found installed package p2 that we can update to p */
2930                   if (MAPTST(&mneg, p))
2931                     continue;
2932                   if (policy_is_illegal(solv, s2, s, 0))
2933                     continue;
2934 #if 0
2935                   if (solver_choicerulecheck(solv, p2, r, &m))
2936                     continue;
2937                   queue_push(&qi, p2);
2938 #else
2939                   queue_push2(&qi, p2, p);
2940 #endif
2941                   queue_push(&q, p);
2942                   continue;
2943                 }
2944             }
2945           /* package p is independent of the installed ones */
2946           havechoice = 1;
2947         }
2948       if (!havechoice || !q.count || !qi.count)
2949         continue;       /* no choice */
2950
2951       FOR_RULELITERALS(p, pp, r)
2952         if (p > 0)
2953           MAPSET(&m, p);
2954
2955       /* do extra checking */
2956       for (i = j = 0; i < qi.count; i += 2)
2957         {
2958           p2 = qi.elements[i];
2959           if (!p2)
2960             continue;
2961           if (solver_choicerulecheck(solv, p2, r, &m))
2962             {
2963               /* oops, remove element p from q */
2964               queue_removeelement(&q, qi.elements[i + 1]);
2965               continue;
2966             }
2967           qi.elements[j++] = p2;
2968         }
2969       queue_truncate(&qi, j);
2970       if (!q.count || !qi.count)
2971         {
2972           FOR_RULELITERALS(p, pp, r)
2973             if (p > 0)
2974               MAPCLR(&m, p);
2975           continue;
2976         }
2977
2978
2979       /* now check the update rules of the installed package.
2980        * if all packages of the update rules are contained in
2981        * the dependency rules, there's no need to set up the choice rule */
2982       for (i = 0; i < qi.count; i++)
2983         {
2984           Rule *ur;
2985           if (!qi.elements[i])
2986             continue;
2987           ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
2988           if (!ur->p)
2989             ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
2990           if (!ur->p)
2991             continue;
2992           FOR_RULELITERALS(p, pp, ur)
2993             if (!MAPTST(&m, p))
2994               break;
2995           if (p)
2996             break;
2997           for (j = i + 1; j < qi.count; j++)
2998             if (qi.elements[i] == qi.elements[j])
2999               qi.elements[j] = 0;
3000         }
3001       /* empty map again */
3002       FOR_RULELITERALS(p, pp, r)
3003         if (p > 0)
3004           MAPCLR(&m, p);
3005       if (i == qi.count)
3006         {
3007 #if 0
3008           printf("skipping choice ");
3009           solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
3010 #endif
3011           continue;
3012         }
3013
3014       /* don't add identical rules */
3015       if (lastaddedp == r->p && lastaddedcnt == q.count)
3016         {
3017           for (i = 0; i < q.count; i++)
3018             if (q.elements[i] != pool->whatprovidesdata[lastaddedd + i])
3019               break;
3020           if (i == q.count)
3021             continue;   /* already added that one */
3022         }
3023       d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
3024
3025       lastaddedp = r->p;
3026       lastaddedd = d;
3027       lastaddedcnt = q.count;
3028
3029       solver_addrule(solv, r->p, d);
3030       queue_push(&solv->weakruleq, solv->nrules - 1);
3031       solv->choicerules_ref[solv->nrules - 1 - solv->choicerules] = rid;
3032 #if 0
3033       printf("OLD ");
3034       solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
3035       printf("WEAK CHOICE ");
3036       solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1);
3037 #endif
3038     }
3039   queue_free(&q);
3040   queue_free(&qi);
3041   map_free(&m);
3042   map_free(&mneg);
3043   solv->choicerules_end = solv->nrules;
3044   /* shrink choicerules_ref */
3045   solv->choicerules_ref = solv_realloc2(solv->choicerules_ref, solv->choicerules_end - solv->choicerules, sizeof(Id));
3046   POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
3047 }
3048
3049 /* called when a choice rule is disabled by analyze_unsolvable. We also
3050  * have to disable all other choice rules so that the best packages get
3051  * picked */
3052 void
3053 solver_disablechoicerules(Solver *solv, Rule *r)
3054 {
3055   Id rid, p, pp;
3056   Pool *pool = solv->pool;
3057   Map m;
3058   Rule *or;
3059
3060   or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
3061   map_init(&m, pool->nsolvables);
3062   FOR_RULELITERALS(p, pp, or)
3063     if (p > 0)
3064       MAPSET(&m, p);
3065   FOR_RULELITERALS(p, pp, r)
3066     if (p > 0)
3067       MAPCLR(&m, p);
3068   for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
3069     {
3070       r = solv->rules + rid;
3071       if (r->d < 0)
3072         continue;
3073       or = solv->rules + solv->choicerules_ref[(r - solv->rules) - solv->choicerules];
3074       FOR_RULELITERALS(p, pp, or)
3075         if (p > 0 && MAPTST(&m, p))
3076           break;
3077       if (p)
3078         solver_disablerule(solv, r);
3079     }
3080 }
3081
3082 static void
3083 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
3084 {
3085   int i, j;
3086   Id p, *cp2;
3087   for (i = j = 0; i < q->count; i++)
3088     {
3089       p = q->elements[i];
3090       for (cp2 = cp; *cp2; cp2++)
3091         if (*cp2 == p)
3092           {
3093             q->elements[j++] = p;
3094             break;
3095           }
3096     }
3097   queue_truncate(q, j);
3098 }
3099
3100 static void
3101 prune_to_dup_packages(Solver *solv, Id p, Queue *q)
3102 {
3103   int i, j;
3104   for (i = j = 0; i < q->count; i++)
3105     {
3106       Id p = q->elements[i];
3107       if (MAPTST(&solv->dupmap, p))
3108         q->elements[j++] = p;
3109     }
3110   queue_truncate(q, j);
3111 }
3112
3113 void
3114 solver_addbestrules(Solver *solv, int havebestinstalljobs)
3115 {
3116   Pool *pool = solv->pool;
3117   Id p;
3118   Solvable *s;
3119   Repo *installed = solv->installed;
3120   Queue q, q2;
3121   Rule *r;
3122   Queue r2pkg;
3123   int i, oldcnt;
3124
3125   solv->bestrules = solv->nrules;
3126   if (!installed)
3127     {
3128       solv->bestrules_end = solv->nrules;
3129       return;
3130     }
3131   queue_init(&q);
3132   queue_init(&q2);
3133   queue_init(&r2pkg);
3134
3135   if (havebestinstalljobs)
3136     {
3137       for (i = 0; i < solv->job.count; i += 2)
3138         {
3139           if ((solv->job.elements[i] & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
3140             {
3141               int j;
3142               Id p2, pp2;
3143               for (j = 0; j < solv->ruletojob.count; j++)
3144                 if (solv->ruletojob.elements[j] == i)
3145                   break;
3146               if (j == solv->ruletojob.count)
3147                 continue;
3148               r = solv->rules + solv->jobrules + j;
3149               queue_empty(&q);
3150               FOR_RULELITERALS(p2, pp2, r)
3151                 if (p2 > 0)
3152                   queue_push(&q, p2);
3153               if (!q.count)
3154                 continue;       /* orphaned */
3155               /* select best packages, just look at prio and version */
3156               oldcnt = q.count;
3157               policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
3158               if (q.count == oldcnt)
3159                 continue;       /* nothing filtered */
3160               p2 = queue_shift(&q);
3161               solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
3162               queue_push(&r2pkg, -(solv->jobrules + j));
3163             }
3164         }
3165     }
3166
3167   if (solv->bestupdatemap_all || solv->bestupdatemap.size)
3168     {
3169       FOR_REPO_SOLVABLES(installed, p, s)
3170         {
3171           Id d, p2, pp2;
3172           if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
3173             continue;
3174           if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
3175             continue;
3176           queue_empty(&q);
3177           if (solv->bestobeypolicy)
3178             r = solv->rules + solv->updaterules + (p - installed->start);
3179           else
3180             {
3181               r = solv->rules + solv->featurerules + (p - installed->start);
3182               if (!r->p)        /* identical to update rule? */
3183                 r = solv->rules + solv->updaterules + (p - installed->start);
3184             }
3185           if (solv->specialupdaters && (d = solv->specialupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
3186             {
3187               /* need to check specialupdaters */
3188               if (r->p == p)    /* be careful with the dup case */
3189                 queue_push(&q, p);
3190               while ((p2 = pool->whatprovidesdata[d++]) != 0)
3191                 queue_push(&q, p2);
3192             }
3193           else
3194             {
3195               FOR_RULELITERALS(p2, pp2, r)
3196                 if (p2 > 0)
3197                   queue_push(&q, p2);
3198             }
3199           if (solv->update_targets && solv->update_targets->elements[p - installed->start])
3200             prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q);
3201           if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
3202             prune_to_dup_packages(solv, p, &q);
3203           /* select best packages, just look at prio and version */
3204           policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
3205           if (!q.count)
3206             continue;   /* orphaned */
3207           if (solv->bestobeypolicy)
3208             {
3209               /* also filter the best of the feature rule packages and add them */
3210               r = solv->rules + solv->featurerules + (p - installed->start);
3211               if (r->p)
3212                 {
3213                   int j;
3214                   queue_empty(&q2);
3215                   FOR_RULELITERALS(p2, pp2, r)
3216                     if (p2 > 0)
3217                       queue_push(&q2, p2);
3218                   if (solv->update_targets && solv->update_targets->elements[p - installed->start])
3219                     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - installed->start], &q2);
3220                   if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
3221                     prune_to_dup_packages(solv, p, &q2);
3222                   policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
3223                   for (j = 0; j < q2.count; j++)
3224                     queue_pushunique(&q, q2.elements[j]);
3225                 }
3226             }
3227           p2 = queue_shift(&q);
3228           solver_addrule(solv, p2, q.count ? pool_queuetowhatprovides(pool, &q) : 0);
3229           queue_push(&r2pkg, p);
3230         }
3231     }
3232   if (r2pkg.count)
3233     solv->bestrules_pkg = solv_memdup2(r2pkg.elements, r2pkg.count, sizeof(Id));
3234   solv->bestrules_end = solv->nrules;
3235   queue_free(&q);
3236   queue_free(&q2);
3237   queue_free(&r2pkg);
3238 }
3239
3240 #undef CLEANDEPSDEBUG
3241
3242 /*
3243  * This functions collects all packages that are looked at
3244  * when a dependency is checked. We need it to "pin" installed
3245  * packages when removing a supplemented package in createcleandepsmap.
3246  * Here's an not uncommon example:
3247  *   A contains "Supplements: packageand(B, C)"
3248  *   B contains "Requires: A"
3249  * Now if we remove C, the supplements is no longer true,
3250  * thus we also remove A. Without the dep_pkgcheck function, we
3251  * would now also remove B, but this is wrong, as adding back
3252  * C doesn't make the supplements true again. Thus we "pin" B
3253  * when we remove A.
3254  * There's probably a better way to do this, but I haven't come
3255  * up with it yet ;)
3256  */
3257 static inline void
3258 dep_pkgcheck(Solver *solv, Id dep, Map *m, Queue *q)
3259 {
3260   Pool *pool = solv->pool;
3261   Id p, pp;
3262
3263   if (ISRELDEP(dep))
3264     {
3265       Reldep *rd = GETRELDEP(pool, dep);
3266       if (rd->flags >= 8)
3267         {
3268           if (rd->flags == REL_AND)
3269             {
3270               dep_pkgcheck(solv, rd->name, m, q);
3271               dep_pkgcheck(solv, rd->evr, m, q);
3272               return;
3273             }
3274           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
3275             return;
3276           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
3277             return;
3278         }
3279     }
3280   FOR_PROVIDES(p, pp, dep)
3281     if (!m || MAPTST(m, p))
3282       queue_push(q, p);
3283 }
3284
3285 static int
3286 check_xsupp(Solver *solv, Queue *depq, Id dep)
3287 {
3288   Pool *pool = solv->pool;
3289   Id p, pp;
3290
3291   if (ISRELDEP(dep))
3292     {
3293       Reldep *rd = GETRELDEP(pool, dep);
3294       if (rd->flags >= 8)
3295         {
3296           if (rd->flags == REL_AND)
3297             {
3298               if (!check_xsupp(solv, depq, rd->name))
3299                 return 0;
3300               return check_xsupp(solv, depq, rd->evr);
3301             }
3302           if (rd->flags == REL_OR)
3303             {
3304               if (check_xsupp(solv, depq, rd->name))
3305                 return 1;
3306               return check_xsupp(solv, depq, rd->evr);
3307             }
3308           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
3309             return solver_splitprovides(solv, rd->evr);
3310           if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
3311             return solver_dep_installed(solv, rd->evr);
3312         }
3313       if (depq && rd->flags == REL_NAMESPACE)
3314         {
3315           int i;
3316           for (i = 0; i < depq->count; i++)
3317             if (depq->elements[i] == dep || depq->elements[i] == rd->name)
3318              return 1;
3319         }
3320     }
3321   FOR_PROVIDES(p, pp, dep)
3322     if (p == SYSTEMSOLVABLE || pool->solvables[p].repo == solv->installed)
3323       return 1;
3324   return 0;
3325 }
3326
3327 static inline int
3328 queue_contains(Queue *q, Id id)
3329 {
3330   int i;
3331   for (i = 0; i < q->count; i++)
3332     if (q->elements[i] == id)
3333       return 1;
3334   return 0;
3335 }
3336
3337 #ifdef ENABLE_COMPLEX_DEPS
3338 static void
3339 complex_cleandeps_remove(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq)
3340 {
3341   int i;
3342   Queue dq;
3343   Id p;
3344
3345   queue_init(&dq);
3346   i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
3347   if (i == 0 || i == 1)
3348     {
3349       queue_free(&dq);
3350       return;
3351     }
3352   for (i = 0; i < dq.count; i++)
3353     {
3354       for (; (p = dq.elements[i]) != 0; i++)
3355         {
3356           if (p < 0)
3357             {
3358               if (!MAPTST(installedm, -p))
3359                 break;
3360               continue;
3361             }
3362           if (p != SYSTEMSOLVABLE && MAPTST(im, p))
3363             {
3364 #ifdef CLEANDEPSDEBUG
3365               printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3366 #endif
3367               queue_push(iq, p);
3368             }
3369         }
3370       while (dq.elements[i])
3371         i++;
3372     }
3373   queue_free(&dq);
3374 }
3375
3376 static void
3377 complex_cleandeps_addback(Pool *pool, Id ip, Id req, Map *im, Map *installedm, Queue *iq, Map *userinstalled)
3378 {
3379   int i, blk;
3380   Queue dq;
3381   Id p;
3382
3383   queue_init(&dq);
3384   i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
3385   if (i == 0 || i == 1)
3386     {
3387       queue_free(&dq);
3388       return;
3389     }
3390   for (i = 0; i < dq.count; i++)
3391     {
3392       blk = i;
3393       for (; (p = dq.elements[i]) != 0; i++)
3394         {
3395           if (p < 0)
3396             {
3397               if (!MAPTST(installedm, -p))
3398                 break;
3399               continue;
3400             }
3401           if (MAPTST(im, p))
3402             break;
3403         }
3404       if (!p)
3405         {
3406           for (i = blk; (p = dq.elements[i]) != 0; i++)
3407             {
3408               if (p < 0)
3409                 continue;
3410               if (!MAPTST(installedm, p))
3411                 continue;
3412               if (p == ip || MAPTST(userinstalled, p - pool->installed->start))
3413                 continue;
3414 #ifdef CLEANDEPSDEBUG
3415               printf("%s requires/recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3416 #endif
3417               MAPSET(im, p);
3418               queue_push(iq, p);
3419             }
3420         }
3421       while (dq.elements[i])
3422         i++;
3423     }
3424   queue_free(&dq);
3425 }
3426
3427 #endif
3428
3429 /*
3430  * Find all installed packages that are no longer
3431  * needed regarding the current solver job.
3432  *
3433  * The algorithm is:
3434  * - remove pass: remove all packages that could have
3435  *   been dragged in by the obsoleted packages.
3436  *   i.e. if package A is obsolete and contains "Requires: B",
3437  *   also remove B, as installing A will have pulled in B.
3438  *   after this pass, we have a set of still installed packages
3439  *   with broken dependencies.
3440  * - add back pass:
3441  *   now add back all packages that the still installed packages
3442  *   require.
3443  *
3444  * The cleandeps packages are the packages removed in the first
3445  * pass and not added back in the second pass.
3446  *
3447  * If we search for unneeded packages (unneeded is true), we
3448  * simply remove all packages except the userinstalled ones in
3449  * the first pass.
3450  */
3451 static void
3452 solver_createcleandepsmap(Solver *solv, Map *cleandepsmap, int unneeded)
3453 {
3454   Pool *pool = solv->pool;
3455   Repo *installed = solv->installed;
3456   Queue *job = &solv->job;
3457   Map userinstalled;
3458   Map im;
3459   Map installedm;
3460   Rule *r;
3461   Id rid, how, what, select;
3462   Id p, pp, ip, jp;
3463   Id req, *reqp, sup, *supp;
3464   Solvable *s;
3465   Queue iq, iqcopy, xsuppq;
3466   int i;
3467
3468   map_empty(cleandepsmap);
3469   if (!installed || installed->end == installed->start)
3470     return;
3471   map_init(&userinstalled, installed->end - installed->start);
3472   map_init(&im, pool->nsolvables);
3473   map_init(&installedm, pool->nsolvables);
3474   queue_init(&iq);
3475   queue_init(&xsuppq);
3476
3477   for (i = 0; i < job->count; i += 2)
3478     {
3479       how = job->elements[i];
3480       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
3481         {
3482           what = job->elements[i + 1];
3483           select = how & SOLVER_SELECTMASK;
3484           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
3485             FOR_REPO_SOLVABLES(installed, p, s)
3486               MAPSET(&userinstalled, p - installed->start);
3487           FOR_JOB_SELECT(p, pp, select, what)
3488             if (pool->solvables[p].repo == installed)
3489               MAPSET(&userinstalled, p - installed->start);
3490         }
3491       if ((how & (SOLVER_JOBMASK | SOLVER_SELECTMASK)) == (SOLVER_ERASE | SOLVER_SOLVABLE_PROVIDES))
3492         {
3493           what = job->elements[i + 1];
3494           if (ISRELDEP(what))
3495             {
3496               Reldep *rd = GETRELDEP(pool, what);
3497               if (rd->flags != REL_NAMESPACE)
3498                 continue;
3499               if (rd->evr == 0)
3500                 {
3501                   queue_pushunique(&iq, rd->name);
3502                   continue;
3503                 }
3504               FOR_PROVIDES(p, pp, what)
3505                 if (p)
3506                   break;
3507               if (p)
3508                 continue;
3509               queue_pushunique(&iq, what);
3510             }
3511         }
3512     }
3513
3514   /* have special namespace cleandeps erases */
3515   if (iq.count)
3516     {
3517       for (ip = solv->installed->start; ip < solv->installed->end; ip++)
3518         {
3519           s = pool->solvables + ip;
3520           if (s->repo != installed)
3521             continue;
3522           if (!s->supplements)
3523             continue;
3524           supp = s->repo->idarraydata + s->supplements;
3525           while ((sup = *supp++) != 0)
3526             if (check_xsupp(solv, &iq, sup) && !check_xsupp(solv, 0, sup))
3527               {
3528 #ifdef CLEANDEPSDEBUG
3529                 printf("xsupp %s from %s\n", pool_dep2str(pool, sup), pool_solvid2str(pool, ip));
3530 #endif
3531                 queue_pushunique(&xsuppq, sup);
3532               }
3533         }
3534       queue_empty(&iq);
3535     }
3536
3537   /* also add visible patterns to userinstalled for openSUSE */
3538   if (1)
3539     {
3540       Dataiterator di;
3541       dataiterator_init(&di, pool, 0, 0, SOLVABLE_ISVISIBLE, 0, 0);
3542       while (dataiterator_step(&di))
3543         {
3544           Id *dp;
3545           if (di.solvid <= 0)
3546             continue;
3547           s = pool->solvables + di.solvid;
3548           if (!s->repo || !s->requires)
3549             continue;
3550           if (s->repo != installed && !pool_installable(pool, s))
3551             continue;
3552           if (strncmp(pool_id2str(pool, s->name), "pattern:", 8) != 0)
3553             continue;
3554           dp = s->repo->idarraydata + s->requires;
3555           for (dp = s->repo->idarraydata + s->requires; *dp; dp++)
3556             FOR_PROVIDES(p, pp, *dp)
3557               if (pool->solvables[p].repo == installed)
3558                 {
3559                   if (strncmp(pool_id2str(pool, pool->solvables[p].name), "pattern", 7) != 0)
3560                     continue;
3561                   MAPSET(&userinstalled, p - installed->start);
3562                 }
3563         }
3564       dataiterator_free(&di);
3565     }
3566   if (1)
3567     {
3568       /* all products and their buddies are userinstalled */
3569       for (p = installed->start; p < installed->end; p++)
3570         {
3571           Solvable *s = pool->solvables + p;
3572           if (s->repo != installed)
3573             continue;
3574           if (!strncmp("product:", pool_id2str(pool, s->name), 8))
3575             {
3576               MAPSET(&userinstalled, p - installed->start);
3577               if (pool->nscallback)
3578                 {
3579                   Id buddy = pool->nscallback(pool, pool->nscallbackdata, NAMESPACE_PRODUCTBUDDY, p);
3580                   if (buddy >= installed->start && buddy < installed->end && pool->solvables[buddy].repo == installed)
3581                     MAPSET(&userinstalled, buddy - installed->start);
3582                 }
3583             }
3584         }
3585     }
3586
3587   /* add all positive elements (e.g. locks) to "userinstalled" */
3588   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
3589     {
3590       r = solv->rules + rid;
3591       if (r->d < 0)
3592         continue;
3593       i = solv->ruletojob.elements[rid - solv->jobrules];
3594       if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
3595         continue;
3596       FOR_RULELITERALS(p, jp, r)
3597         if (p > 0 && pool->solvables[p].repo == installed)
3598           MAPSET(&userinstalled, p - installed->start);
3599     }
3600
3601   /* add all cleandeps candidates to iq */
3602   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
3603     {
3604       r = solv->rules + rid;
3605       if (r->d < 0)                             /* disabled? */
3606         continue;
3607       if (r->d == 0 && r->p < 0 && r->w2 == 0)  /* negative assertion (erase job)? */
3608         {
3609           p = -r->p;
3610           if (pool->solvables[p].repo != installed)
3611             continue;
3612           MAPCLR(&userinstalled, p - installed->start);
3613           if (unneeded)
3614             continue;
3615           i = solv->ruletojob.elements[rid - solv->jobrules];
3616           how = job->elements[i];
3617           if ((how & (SOLVER_JOBMASK|SOLVER_CLEANDEPS)) == (SOLVER_ERASE|SOLVER_CLEANDEPS))
3618             queue_push(&iq, p);
3619         }
3620       else if (r->p > 0)                        /* install job */
3621         {
3622           if (unneeded)
3623             continue;
3624           i = solv->ruletojob.elements[rid - solv->jobrules];
3625           if ((job->elements[i] & SOLVER_CLEANDEPS) == SOLVER_CLEANDEPS)
3626             {
3627               /* check if the literals all obsolete some installed package */
3628               Map om;
3629               int iqstart;
3630
3631               /* just one installed literal */
3632               if (r->d == 0 && r->w2 == 0 && pool->solvables[r->p].repo == installed)
3633                 continue;
3634               /* multiversion is bad */
3635               if (solv->multiversion.size && !solv->keepexplicitobsoletes)
3636                 {
3637                   FOR_RULELITERALS(p, jp, r)
3638                     if (MAPTST(&solv->multiversion, p))
3639                       break;
3640                   if (p)
3641                     continue;
3642                 }
3643
3644               om.size = 0;
3645               iqstart = iq.count;
3646               FOR_RULELITERALS(p, jp, r)
3647                 {
3648                   if (p < 0)
3649                     {
3650                       queue_truncate(&iq, iqstart);     /* abort */
3651                       break;
3652                     }
3653                   if (pool->solvables[p].repo == installed)
3654                     {
3655                       if (iq.count == iqstart)
3656                         queue_push(&iq, p);
3657                       else
3658                         {
3659                           for (i = iqstart; i < iq.count; i++)
3660                             if (iq.elements[i] == p)
3661                               break;
3662                           queue_truncate(&iq, iqstart);
3663                           if (i < iq.count)
3664                             queue_push(&iq, p);
3665                         }
3666                     }
3667                   else
3668                     intersect_obsoletes(solv, p, &iq, iqstart, &om);
3669                   if (iq.count == iqstart)
3670                     break;
3671                 }
3672               if (om.size)
3673                 map_free(&om);
3674             }
3675         }
3676     }
3677   queue_init_clone(&iqcopy, &iq);
3678
3679   if (!unneeded)
3680     {
3681       if (solv->cleandeps_updatepkgs)
3682         for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
3683           queue_push(&iq, solv->cleandeps_updatepkgs->elements[i]);
3684     }
3685
3686   if (unneeded)
3687     queue_empty(&iq);   /* just in case... */
3688
3689   /* clear userinstalled bit for the packages we really want to delete/update */
3690   for (i = 0; i < iq.count; i++)
3691     {
3692       p = iq.elements[i];
3693       if (pool->solvables[p].repo != installed)
3694         continue;
3695       MAPCLR(&userinstalled, p - installed->start);
3696     }
3697
3698   for (p = installed->start; p < installed->end; p++)
3699     {
3700       if (pool->solvables[p].repo != installed)
3701         continue;
3702       MAPSET(&installedm, p);
3703       if (unneeded && !MAPTST(&userinstalled, p - installed->start))
3704         continue;
3705       MAPSET(&im, p);
3706     }
3707   MAPSET(&installedm, SYSTEMSOLVABLE);
3708   MAPSET(&im, SYSTEMSOLVABLE);
3709
3710 #ifdef CLEANDEPSDEBUG
3711   printf("REMOVE PASS\n");
3712 #endif
3713
3714   for (;;)
3715     {
3716       if (!iq.count)
3717         {
3718           if (unneeded)
3719             break;
3720           /* supplements pass */
3721           for (ip = installed->start; ip < installed->end; ip++)
3722             {
3723               if (!MAPTST(&installedm, ip))
3724                 continue;
3725               s = pool->solvables + ip;
3726               if (!s->supplements)
3727                 continue;
3728               if (!MAPTST(&im, ip))
3729                 continue;
3730               if (MAPTST(&userinstalled, ip - installed->start))
3731                 continue;
3732               supp = s->repo->idarraydata + s->supplements;
3733               while ((sup = *supp++) != 0)
3734                 if (dep_possible(solv, sup, &im))
3735                   break;
3736               if (!sup)
3737                 {
3738                   supp = s->repo->idarraydata + s->supplements;
3739                   while ((sup = *supp++) != 0)
3740                     if (dep_possible(solv, sup, &installedm) || (xsuppq.count && queue_contains(&xsuppq, sup)))
3741                       {
3742                         /* no longer supplemented, also erase */
3743                         int iqcount = iq.count;
3744                         /* pin packages, see comment above dep_pkgcheck */
3745                         dep_pkgcheck(solv, sup, &im, &iq);
3746                         for (i = iqcount; i < iq.count; i++)
3747                           {
3748                             Id pqp = iq.elements[i];
3749                             if (pool->solvables[pqp].repo == installed)
3750                               MAPSET(&userinstalled, pqp - installed->start);
3751                           }
3752                         queue_truncate(&iq, iqcount);
3753 #ifdef CLEANDEPSDEBUG
3754                         printf("%s supplemented [%s]\n", pool_solvid2str(pool, ip), pool_dep2str(pool, sup));
3755 #endif
3756                         queue_push(&iq, ip);
3757                       }
3758                 }
3759             }
3760           if (!iq.count)
3761             break;      /* no supplementing package found, we're done */
3762         }
3763       ip = queue_shift(&iq);
3764       s = pool->solvables + ip;
3765       if (!MAPTST(&im, ip))
3766         continue;
3767       if (!MAPTST(&installedm, ip))
3768         continue;
3769       if (s->repo == installed && MAPTST(&userinstalled, ip - installed->start))
3770         continue;
3771       MAPCLR(&im, ip);
3772 #ifdef CLEANDEPSDEBUG
3773       printf("removing %s\n", pool_solvable2str(pool, s));
3774 #endif
3775       if (s->requires)
3776         {
3777           reqp = s->repo->idarraydata + s->requires;
3778           while ((req = *reqp++) != 0)
3779             {
3780               if (req == SOLVABLE_PREREQMARKER)
3781                 continue;
3782 #ifdef ENABLE_COMPLEX_DEPS
3783               if (pool_is_complex_dep(pool, req))
3784                 {
3785                   complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
3786                   continue;
3787                 }
3788 #endif
3789               FOR_PROVIDES(p, pp, req)
3790                 {
3791                   if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
3792                     {
3793 #ifdef CLEANDEPSDEBUG
3794                       printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3795 #endif
3796                       queue_push(&iq, p);
3797                     }
3798                 }
3799             }
3800         }
3801       if (s->recommends)
3802         {
3803           reqp = s->repo->idarraydata + s->recommends;
3804           while ((req = *reqp++) != 0)
3805             {
3806 #ifdef ENABLE_COMPLEX_DEPS
3807               if (pool_is_complex_dep(pool, req))
3808                 {
3809                   complex_cleandeps_remove(pool, ip, req, &im, &installedm, &iq);
3810                   continue;
3811                 }
3812 #endif
3813               FOR_PROVIDES(p, pp, req)
3814                 {
3815                   if (p != SYSTEMSOLVABLE && MAPTST(&im, p))
3816                     {
3817 #ifdef CLEANDEPSDEBUG
3818                       printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3819 #endif
3820                       queue_push(&iq, p);
3821                     }
3822                 }
3823             }
3824         }
3825     }
3826
3827   /* turn userinstalled into remove set for pruning */
3828   map_empty(&userinstalled);
3829   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
3830     {
3831       r = solv->rules + rid;
3832       if (r->p >= 0 || r->d != 0 || r->w2 != 0)
3833         continue;       /* disabled or not erase */
3834       p = -r->p;
3835       MAPCLR(&im, p);
3836       if (pool->solvables[p].repo == installed)
3837         MAPSET(&userinstalled, p - installed->start);
3838     }
3839   if (!unneeded && solv->cleandeps_updatepkgs)
3840     {
3841       for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
3842         {
3843           p = solv->cleandeps_updatepkgs->elements[i];
3844           if (pool->solvables[p].repo == installed)
3845             MAPSET(&userinstalled, p - installed->start);
3846         }
3847     }
3848   MAPSET(&im, SYSTEMSOLVABLE);  /* in case we cleared it above */
3849   for (p = installed->start; p < installed->end; p++)
3850     if (MAPTST(&im, p))
3851       queue_push(&iq, p);
3852   for (rid = solv->jobrules; rid < solv->jobrules_end; rid++)
3853     {
3854       r = solv->rules + rid;
3855       if (r->d < 0)
3856         continue;
3857       FOR_RULELITERALS(p, jp, r)
3858         if (p > 0)
3859           queue_push(&iq, p);
3860     }
3861   /* also put directly addressed packages on the install queue
3862    * so we can mark patterns as installed */
3863   for (i = 0; i < job->count; i += 2)
3864     {
3865       how = job->elements[i];
3866       if ((how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
3867         {
3868           what = job->elements[i + 1];
3869           select = how & SOLVER_SELECTMASK;
3870           if (select == SOLVER_SOLVABLE && pool->solvables[what].repo != installed)
3871             queue_push(&iq, what);
3872         }
3873     }
3874
3875 #ifdef CLEANDEPSDEBUG
3876   printf("ADDBACK PASS\n");
3877 #endif
3878   for (;;)
3879     {
3880       if (!iq.count)
3881         {
3882           /* supplements pass */
3883           for (ip = installed->start; ip < installed->end; ip++)
3884             {
3885               if (!MAPTST(&installedm, ip))
3886                 continue;
3887               if (MAPTST(&userinstalled, ip - installed->start))
3888                 continue;
3889               s = pool->solvables + ip;
3890               if (!s->supplements)
3891                 continue;
3892               if (MAPTST(&im, ip))
3893                 continue;
3894               supp = s->repo->idarraydata + s->supplements;
3895               while ((sup = *supp++) != 0)
3896                 if (dep_possible(solv, sup, &im))
3897                   break;
3898               if (sup)
3899                 {
3900 #ifdef CLEANDEPSDEBUG
3901                   printf("%s supplemented\n", pool_solvid2str(pool, ip));
3902 #endif
3903                   MAPSET(&im, ip);
3904                   queue_push(&iq, ip);
3905                 }
3906             }
3907           if (!iq.count)
3908             break;
3909         }
3910       ip = queue_shift(&iq);
3911       s = pool->solvables + ip;
3912 #ifdef CLEANDEPSDEBUG
3913       printf("adding back %s\n", pool_solvable2str(pool, s));
3914 #endif
3915       if (s->requires)
3916         {
3917           reqp = s->repo->idarraydata + s->requires;
3918           while ((req = *reqp++) != 0)
3919             {
3920 #ifdef ENABLE_COMPLEX_DEPS
3921               if (pool_is_complex_dep(pool, req))
3922                 {
3923                   complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
3924                   continue;
3925                 }
3926 #endif
3927               FOR_PROVIDES(p, pp, req)
3928                 if (MAPTST(&im, p))
3929                   break;
3930               if (p)
3931                 continue;
3932               FOR_PROVIDES(p, pp, req)
3933                 {
3934                   if (MAPTST(&installedm, p))
3935                     {
3936                       if (p == ip)
3937                         continue;
3938                       if (MAPTST(&userinstalled, p - installed->start))
3939                         continue;
3940 #ifdef CLEANDEPSDEBUG
3941                       printf("%s requires %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3942 #endif
3943                       MAPSET(&im, p);
3944                       queue_push(&iq, p);
3945                     }
3946                 }
3947             }
3948         }
3949       if (s->recommends)
3950         {
3951           reqp = s->repo->idarraydata + s->recommends;
3952           while ((req = *reqp++) != 0)
3953             {
3954 #ifdef ENABLE_COMPLEX_DEPS
3955               if (pool_is_complex_dep(pool, req))
3956                 {
3957                   complex_cleandeps_addback(pool, ip, req, &im, &installedm, &iq, &userinstalled);
3958                   continue;
3959                 }
3960 #endif
3961               FOR_PROVIDES(p, pp, req)
3962                 if (MAPTST(&im, p))
3963                   break;
3964               if (p)
3965                 continue;
3966               FOR_PROVIDES(p, pp, req)
3967                 {
3968                   if (MAPTST(&installedm, p))
3969                     {
3970                       if (p == ip)
3971                         continue;
3972                       if (MAPTST(&userinstalled, p - installed->start))
3973                         continue;
3974 #ifdef CLEANDEPSDEBUG
3975                       printf("%s recommends %s\n", pool_solvid2str(pool, ip), pool_solvid2str(pool, p));
3976 #endif
3977                       MAPSET(&im, p);
3978                       queue_push(&iq, p);
3979                     }
3980                 }
3981             }
3982         }
3983     }
3984
3985   queue_free(&iq);
3986   /* make sure the updatepkgs and mistakes are not in the cleandeps map */
3987   if (solv->cleandeps_updatepkgs)
3988     for (i = 0; i < solv->cleandeps_updatepkgs->count; i++)
3989       MAPSET(&im, solv->cleandeps_updatepkgs->elements[i]);
3990   if (solv->cleandeps_mistakes)
3991     for (i = 0; i < solv->cleandeps_mistakes->count; i++)
3992       MAPSET(&im, solv->cleandeps_mistakes->elements[i]);
3993   /* also remove original iq packages */
3994   for (i = 0; i < iqcopy.count; i++)
3995     MAPSET(&im, iqcopy.elements[i]);
3996   queue_free(&iqcopy);
3997   for (p = installed->start; p < installed->end; p++)
3998     {
3999       if (pool->solvables[p].repo != installed)
4000         continue;
4001       if (!MAPTST(&im, p))
4002         MAPSET(cleandepsmap, p - installed->start);
4003     }
4004   map_free(&im);
4005   map_free(&installedm);
4006   map_free(&userinstalled);
4007   queue_free(&xsuppq);
4008 #ifdef CLEANDEPSDEBUG
4009   printf("=== final cleandeps map:\n");
4010   for (p = installed->start; p < installed->end; p++)
4011     if (MAPTST(cleandepsmap, p - installed->start))
4012       printf("  - %s\n", pool_solvid2str(pool, p));
4013 #endif
4014 }
4015
4016
4017 struct trj_data {
4018   Queue *edges;
4019   Id *low;
4020   Id idx;
4021   Id nstack;
4022   Id firstidx;
4023 };
4024
4025 /* Tarjan's SCC algorithm, slightly modifed */
4026 static void
4027 trj_visit(struct trj_data *trj, Id node)
4028 {
4029   Id *low = trj->low;
4030   Queue *edges = trj->edges;
4031   Id nnode, myidx, stackstart;
4032   int i;
4033
4034   low[node] = myidx = trj->idx++;
4035   low[(stackstart = trj->nstack++)] = node;
4036   for (i = edges->elements[node]; (nnode = edges->elements[i]) != 0; i++)
4037     {
4038       Id l = low[nnode];
4039       if (!l)
4040         {
4041           if (!edges->elements[edges->elements[nnode]])
4042             {
4043               trj->idx++;
4044               low[nnode] = -1;
4045               continue;
4046             }
4047           trj_visit(trj, nnode);
4048           l = low[nnode];
4049         }
4050       if (l < 0)
4051         continue;
4052       if (l < trj->firstidx)
4053         {
4054           int k;
4055           for (k = l; low[low[k]] == l; k++)
4056             low[low[k]] = -1;
4057         }
4058       else if (l < low[node])
4059         low[node] = l;
4060     }
4061   if (low[node] == myidx)
4062     {
4063       if (myidx != trj->firstidx)
4064         myidx = -1;
4065       for (i = stackstart; i < trj->nstack; i++)
4066         low[low[i]] = myidx;
4067       trj->nstack = stackstart;
4068     }
4069 }
4070
4071 #ifdef ENABLE_COMPLEX_DEPS
4072 static void
4073 complex_unneeded(Pool *pool, Id ip, Id req, Queue *edges, Map *cleandepsmap, Queue *unneededq)
4074 {
4075   int i, j;
4076   Queue dq;
4077   Id p;
4078
4079   queue_init(&dq);
4080   i = pool_normalize_complex_dep(pool, req, &dq, CPLXDEPS_EXPAND);
4081   if (i == 0 || i == 1)
4082     {
4083       queue_free(&dq);
4084       return;
4085     }
4086   for (i = 0; i < dq.count; i++)
4087     {
4088       for (; (p = dq.elements[i]) != 0; i++)
4089         {
4090           if (p < 0)
4091             {
4092               if (pool->solvables[-p].repo != pool->installed)
4093                 break;
4094               continue;
4095             }
4096           if (p == ip || pool->solvables[p].repo != pool->installed || !MAPTST(cleandepsmap, p - pool->installed->start))
4097             continue;
4098           for (j = 0; j < unneededq->count; j++)
4099             if (p == unneededq->elements[j])
4100               {
4101                 if (edges->elements[edges->count - 1] != j + 1)
4102                   queue_push(edges, j + 1);
4103                 break;
4104               }
4105         }
4106       while (dq.elements[i])
4107         i++;
4108     }
4109   queue_free(&dq);
4110 }
4111 #endif
4112
4113 void
4114 solver_get_unneeded(Solver *solv, Queue *unneededq, int filtered)
4115 {
4116   Repo *installed = solv->installed;
4117   int i;
4118   Map cleandepsmap;
4119
4120   queue_empty(unneededq);
4121   if (!installed || installed->end == installed->start)
4122     return;
4123
4124   map_init(&cleandepsmap, installed->end - installed->start);
4125   solver_createcleandepsmap(solv, &cleandepsmap, 1);
4126   for (i = installed->start; i < installed->end; i++)
4127     if (MAPTST(&cleandepsmap, i - installed->start))
4128       queue_push(unneededq, i);
4129
4130   if (filtered && unneededq->count > 1)
4131     {
4132       Pool *pool = solv->pool;
4133       Queue edges;
4134       Id *nrequires;
4135       Map installedm;
4136       int j, pass, count = unneededq->count;
4137       Id *low;
4138
4139       map_init(&installedm, pool->nsolvables);
4140       for (i = installed->start; i < installed->end; i++)
4141         if (pool->solvables[i].repo == installed)
4142           MAPSET(&installedm, i);
4143
4144       nrequires = solv_calloc(count, sizeof(Id));
4145       queue_init(&edges);
4146       queue_prealloc(&edges, count * 4 + 10);   /* pre-size */
4147
4148       /*
4149        * Go through the solvables in the nodes queue and create edges for
4150        * all requires/recommends/supplements between the nodes.
4151        * The edges are stored in the edges queue, we add 1 to the node
4152        * index so that nodes in the edges queue are != 0 and we can
4153        * terminate the edge list with 0.
4154        * Thus for node element 5, the edges are stored starting at
4155        * edges.elements[6] and are 0-terminated.
4156        */
4157       /* leave first element zero to make things easier */
4158       /* also add trailing zero */
4159       queue_insertn(&edges, 0, 1 + count + 1, 0);
4160
4161       /* first requires and recommends */
4162       for (i = 0; i < count; i++)
4163         {
4164           Solvable *s = pool->solvables + unneededq->elements[i];
4165           int oldcount = edges.count;
4166           edges.elements[i + 1] = oldcount;
4167           for (pass = 0; pass < 2; pass++)
4168             {
4169               unsigned int off = pass == 0 ? s->requires : s->recommends;
4170               Id p, pp, dep, *dp;
4171               if (off)
4172                 for (dp = s->repo->idarraydata + off; (dep = *dp) != 0; dp++)
4173                   {
4174 #ifdef ENABLE_COMPLEX_DEPS
4175                     if (pool_is_complex_dep(pool, dep))
4176                       {
4177                         complex_unneeded(pool, s - pool->solvables, dep, &edges, &cleandepsmap, unneededq);
4178                         continue;
4179                       }
4180 #endif
4181                     FOR_PROVIDES(p, pp, dep)
4182                       {
4183                         Solvable *sp = pool->solvables + p;
4184                         if (s == sp || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start))
4185                           continue;
4186                         for (j = 0; j < count; j++)
4187                           if (p == unneededq->elements[j])
4188                             {
4189                               if (edges.elements[edges.count - 1] != j + 1)
4190                                 queue_push(&edges, j + 1);
4191                             }
4192                       }
4193                   }
4194               if (pass == 0)
4195                 nrequires[i] = edges.count - oldcount;
4196             }
4197           queue_push(&edges, 0);
4198         }
4199 #if 0
4200       printf("requires + recommends\n");
4201       for (i = 0; i < count; i++)
4202         {
4203           int j;
4204           printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
4205           for (j = edges.elements[i + 1]; edges.elements[j]; j++)
4206             printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
4207         }
4208 #endif
4209
4210       /* then add supplements */
4211       for (i = 0; i < count; i++)
4212         {
4213           Solvable *s = pool->solvables + unneededq->elements[i];
4214           if (s->supplements)
4215             {
4216               Id *dp;
4217               int k;
4218               for (dp = s->repo->idarraydata + s->supplements; *dp; dp++)
4219                 if (dep_possible(solv, *dp, &installedm))
4220                   {
4221                     Queue iq;
4222                     Id iqbuf[16];
4223                     queue_init_buffer(&iq, iqbuf, sizeof(iqbuf)/sizeof(*iqbuf));
4224                     dep_pkgcheck(solv, *dp, 0, &iq);
4225                     for (k = 0; k < iq.count; k++)
4226                       {
4227                         Id p = iq.elements[k];
4228                         Solvable *sp = pool->solvables + p;
4229                         if (p == unneededq->elements[i] || sp->repo != installed || !MAPTST(&cleandepsmap, p - installed->start))
4230                           continue;
4231                         for (j = 0; j < count; j++)
4232                           if (p == unneededq->elements[j])
4233                             break;
4234                         /* now add edge from j + 1 to i + 1 */
4235                         queue_insert(&edges, edges.elements[j + 1] + nrequires[j], i + 1);
4236                         /* addapt following edge pointers */
4237                         for (j = j + 2; j < count + 1; j++)
4238                           edges.elements[j]++;
4239                       }
4240                     queue_free(&iq);
4241                   }
4242             }
4243         }
4244 #if 0
4245       /* print result */
4246       printf("+ supplements\n");
4247       for (i = 0; i < count; i++)
4248         {
4249           int j;
4250           printf("  %s (%d requires):\n", pool_solvid2str(pool, unneededq->elements[i]), nrequires[i]);
4251           for (j = edges.elements[i + 1]; edges.elements[j]; j++)
4252             printf("    - %s\n", pool_solvid2str(pool, unneededq->elements[edges.elements[j] - 1]));
4253         }
4254 #endif
4255       map_free(&installedm);
4256
4257       /* now run SCC algo two times, first with requires+recommends+supplements,
4258        * then again without the requires. We run it the second time to get rid
4259        * of packages that got dragged in via recommends/supplements */
4260       /*
4261        * low will contain the result of the SCC search.
4262        * it must be of at least size 2 * (count + 1) and
4263        * must be zero initialized.
4264        * The layout is:
4265        *    0  low low ... low stack stack ...stack 0
4266        *            count              count
4267        */
4268       low = solv_calloc(count + 1, 2 * sizeof(Id));
4269       for (pass = 0; pass < 2; pass++)
4270         {
4271           struct trj_data trj;
4272           if (pass)
4273             {
4274               memset(low, 0, (count + 1) * (2 * sizeof(Id)));
4275               for (i = 0; i < count; i++)
4276                 {
4277                   edges.elements[i + 1] += nrequires[i];
4278                   if (!unneededq->elements[i])
4279                     low[i + 1] = -1;    /* ignore this node */
4280                 }
4281             }
4282           trj.edges = &edges;
4283           trj.low = low;
4284           trj.idx = count + 1;  /* stack starts here */
4285           for (i = 1; i <= count; i++)
4286             {
4287               if (low[i])
4288                 continue;
4289               if (edges.elements[edges.elements[i]])
4290                 {
4291                   trj.firstidx = trj.nstack = trj.idx;
4292                   trj_visit(&trj, i);
4293                 }
4294               else
4295                 {
4296                   Id myidx = trj.idx++;
4297                   low[i] = myidx;
4298                   low[myidx] = i;
4299                 }
4300             }
4301           /* prune packages */
4302           for (i = 0; i < count; i++)
4303             if (low[i + 1] <= 0)
4304               unneededq->elements[i] = 0;
4305         }
4306       solv_free(low);
4307       solv_free(nrequires);
4308       queue_free(&edges);
4309
4310       /* finally remove all pruned entries from unneededq */
4311       for (i = j = 0; i < count; i++)
4312         if (unneededq->elements[i])
4313           unneededq->elements[j++] = unneededq->elements[i];
4314       queue_truncate(unneededq, j);
4315     }
4316   map_free(&cleandepsmap);
4317 }
4318
4319 /* EOF */