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