e31fe01b36fcda5842eefb58233cbae96163306c
[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 = solv->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;
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           addpkgrule(solv, qele[0], 0, pool_ids2whatprovides(pool, qele + 1, qcnt - 1), type, dep);
657           if (m)
658             for (j = 0; j < qcnt; j++)
659               if (qele[j] > 0 && !MAPTST(m, qele[j]))
660                 queue_push(workq, qele[j]);
661         }
662     }
663   queue_free(&bq);
664 }
665
666 #endif
667
668 #ifdef ENABLE_CONDA
669 void
670 add_conda_constrains_rule(Solver *solv, Id n, Id dep, int dontfix)
671 {
672   Pool *pool = solv->pool;
673   Reldep *rd;
674   Id p, pp, pdep;
675   if (!ISRELDEP(dep))
676     return;
677   rd = GETRELDEP(pool, dep);
678   pdep = pool_whatprovides(pool, dep);
679   FOR_PROVIDES(p, pp, rd->name)
680     {
681       Id p2;
682       if (p == n)
683         continue;
684       if (dontfix && pool->solvables[p].repo == solv->installed)
685         continue;
686       while ((p2 = pool->whatprovidesdata[pdep]) != 0 && p2 < p)
687         pdep++;
688       if (p == p2)
689         pdep++;
690       else
691         addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONSTRAINS, dep);
692     }
693 }
694 #endif
695
696 /*-------------------------------------------------------------------
697  *
698  * add dependency rules for solvable
699  *
700  * s: Solvable for which to add rules
701  * m: m[s] = 1 for solvables which have rules, prevent rule duplication
702  *
703  * Algorithm: 'visit all nodes of a graph'. The graph nodes are
704  *  solvables, the edges their dependencies.
705  *  Starting from an installed solvable, this will create all rules
706  *  representing the graph created by the solvables dependencies.
707  *
708  * for unfulfilled requirements, conflicts, obsoletes,....
709  * add a negative assertion for solvables that are not installable
710  *
711  * It will also create rules for all solvables referenced by 's'
712  *  i.e. descend to all providers of requirements of 's'
713  *
714  */
715
716 void
717 solver_addpkgrulesforsolvable(Solver *solv, Solvable *s, Map *m)
718 {
719   Pool *pool = solv->pool;
720   Repo *installed = solv->installed;
721
722   Queue workq;  /* list of solvables we still have to work on */
723   Id workqbuf[64];
724   Queue depq;   /* list of pre-req ids to ignore */
725   Id depqbuf[16];
726
727   int i;
728   int dontfix;          /* ignore dependency errors for installed solvables */
729   Id req, *reqp;
730   Id con, *conp;
731   Id obs, *obsp;
732   Id rec, *recp;
733   Id sug, *sugp;
734   Id p, pp;             /* whatprovides loops */
735   Id *dp;               /* ptr to 'whatprovides' */
736   Id n;                 /* Id for current solvable 's' */
737
738   queue_init_buffer(&workq, workqbuf, sizeof(workqbuf)/sizeof(*workqbuf));
739   queue_push(&workq, s - pool->solvables);      /* push solvable Id to work queue */
740
741   queue_init_buffer(&depq, depqbuf, sizeof(depqbuf)/sizeof(*depqbuf));
742
743   /* loop until there's no more work left */
744   while (workq.count)
745     {
746       /*
747        * n: Id of solvable
748        * s: Pointer to solvable
749        */
750
751       n = queue_shift(&workq);          /* 'pop' next solvable to work on from queue */
752       if (m)
753         {
754           if (MAPTST(m, n))             /* continue if already visited */
755             continue;
756           MAPSET(m, n);                 /* mark as visited */
757         }
758
759       s = pool->solvables + n;
760
761       dontfix = 0;
762       if (installed                     /* Installed system available */
763           && s->repo == installed       /* solvable is installed */
764           && !solv->fixmap_all          /* NOT repair errors in dependency graph */
765           && !(solv->fixmap.size && MAPTST(&solv->fixmap, n - installed->start)))
766         {
767           dontfix = 1;                  /* dont care about broken deps */
768         }
769
770       if (!dontfix)
771         {
772           if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC
773                 ? pool_disabled_solvable(pool, s)
774                 : !pool_installable(pool, s))
775             {
776               POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable\n", pool_solvid2str(pool, n), n);
777               addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOT_INSTALLABLE, 0);
778             }
779         }
780
781 #ifdef ENABLE_LINKED_PKGS
782       /* add pseudo-package <-> real-package links */
783       if (has_package_link(pool, s))
784         add_package_link(solv, s, m, &workq);
785 #endif
786
787       /*-----------------------------------------
788        * check requires of s
789        */
790
791       if (s->requires)
792         {
793           int filterpre = 0;
794           reqp = s->repo->idarraydata + s->requires;
795           while ((req = *reqp++) != 0)            /* go through all requires */
796             {
797               if (req == SOLVABLE_PREREQMARKER)   /* skip the marker */
798                 {
799                   if (installed && s->repo == installed)
800                     {
801                       solvable_lookup_idarray(s, SOLVABLE_PREREQ_IGNOREINST, &depq);
802                       filterpre = depq.count;
803                     }
804                   continue;
805                 }
806               if (filterpre)
807                 {
808                   /* check if this id is filtered. assumes that depq.count is small */
809                   for (i = 0; i < depq.count; i++)
810                     if (req == depq.elements[i])
811                       break;
812                   if (i < depq.count)
813                     {
814                       POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s: ignoring filtered pre-req dependency %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
815                       continue;
816                     }
817                 }
818
819 #ifdef ENABLE_COMPLEX_DEPS
820               if (pool_is_complex_dep(pool, req))
821                 {
822                   /* we have AND/COND deps, normalize */
823                   add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_REQUIRES, dontfix, &workq, m);
824                   continue;
825                 }
826 #endif
827
828               /* find list of solvables providing 'req' */
829               dp = pool_whatprovides_ptr(pool, req);
830
831               if (*dp == SYSTEMSOLVABLE)          /* always installed */
832                 continue;
833
834               if (dontfix)
835                 {
836                   /* the strategy here is to not insist on dependencies
837                    * that are already broken. so if we find one provider
838                    * that was already installed, we know that the
839                    * dependency was not broken before so we enforce it */
840                   for (i = 0; (p = dp[i]) != 0; i++)
841                     if (pool->solvables[p].repo == installed)
842                       break;            /* found installed provider */
843                   if (!p)
844                     {
845                       /* didn't find an installed provider: previously broken dependency */
846                       POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "ignoring broken requires %s of installed package %s\n", pool_dep2str(pool, req), pool_solvable2str(pool, s));
847                       continue;
848                     }
849                 }
850
851               if (!*dp)
852                 {
853                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "package %s [%d] is not installable (%s)\n", pool_solvid2str(pool, n), n, pool_dep2str(pool, req));
854                   addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP, req);
855                   continue;
856                 }
857
858               for (i = 0; dp[i] != 0; i++)
859                 if (n == dp[i])
860                   break;
861               if (dp[i])
862                 continue;               /* provided by itself, no need to add rule */
863
864               IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
865                 {
866                   POOL_DEBUG(SOLV_DEBUG_RULE_CREATION,"  %s requires %s\n", pool_solvable2str(pool, s), pool_dep2str(pool, req));
867                   for (i = 0; dp[i]; i++)
868                     POOL_DEBUG(SOLV_DEBUG_RULE_CREATION, "   provided by %s\n", pool_solvid2str(pool, dp[i]));
869                 }
870
871               /* add 'requires' dependency */
872               /* rule: (-requestor|provider1|provider2|...|providerN) */
873               addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_REQUIRES, req);
874
875               /* push all non-visited providers on the work queue */
876               if (m)
877                 for (; *dp; dp++)
878                   if (!MAPTST(m, *dp))
879                     queue_push(&workq, *dp);
880             }
881         }
882
883       if (s->recommends && solv->strongrecommends)
884         {
885           int start = solv->nrules;
886           solv->lastpkgrule = 0;
887           reqp = s->repo->idarraydata + s->recommends;
888           while ((req = *reqp++) != 0)            /* go through all recommends */
889             {
890 #ifdef ENABLE_COMPLEX_DEPS
891               if (pool_is_complex_dep(pool, req))
892                 {
893                   /* we have AND/COND deps, normalize */
894                   add_complex_deprules(solv, n, req, SOLVER_RULE_PKG_RECOMMENDS, dontfix, &workq, m);
895                   continue;
896                 }
897 #endif
898               dp = pool_whatprovides_ptr(pool, req);
899               if (*dp == SYSTEMSOLVABLE || !*dp)          /* always installed or not installable */
900                 continue;
901               for (i = 0; dp[i] != 0; i++)
902                 if (n == dp[i])
903                   break;
904               if (dp[i])
905                 continue;               /* provided by itself, no need to add rule */
906               addpkgrule(solv, -n, 0, dp - pool->whatprovidesdata, SOLVER_RULE_PKG_RECOMMENDS, req);
907               if (m)
908                 for (; *dp; dp++)
909                   if (!MAPTST(m, *dp))
910                     queue_push(&workq, *dp);
911             }
912           if (!solv->ruleinfoq && start < solv->nrules)
913             {
914               if (!solv->recommendsruleq)
915                 {
916                   solv->recommendsruleq = solv_calloc(1, sizeof(Queue));
917                   queue_init(solv->recommendsruleq);
918                 }
919               for (i = start; i < solv->nrules; i++)
920                 queue_push(solv->recommendsruleq, i);
921               solv->lastpkgrule = 0;
922             }
923         }
924
925 #ifdef ENABLE_CONDA
926       if (pool->disttype == DISTTYPE_CONDA)
927         {
928           solvable_lookup_idarray(s, SOLVABLE_CONSTRAINS, &depq);
929           for (i = 0; i < depq.count; i++)
930             add_conda_constrains_rule(solv, n, depq.elements[i], dontfix);
931         }
932 #endif
933
934       /* that's all we check for src packages */
935       if (s->arch == ARCH_SRC || s->arch == ARCH_NOSRC)
936         continue;
937
938       /*-----------------------------------------
939        * check conflicts of s
940        */
941
942       if (s->conflicts)
943         {
944           int ispatch = 0;
945
946           /* we treat conflicts in patches a bit differen:
947            * - nevr matching
948            * - multiversion handling
949            * XXX: we should really handle this different, looking
950            * at the name is a bad hack
951            */
952           if (!strncmp("patch:", pool_id2str(pool, s->name), 6))
953             ispatch = 1;
954           conp = s->repo->idarraydata + s->conflicts;
955           /* foreach conflicts of 's' */
956           while ((con = *conp++) != 0)
957             {
958 #ifdef ENABLE_COMPLEX_DEPS
959               if (!ispatch && pool_is_complex_dep(pool, con))
960                 {
961                   /* we have AND/COND deps, normalize */
962                   add_complex_deprules(solv, n, con, SOLVER_RULE_PKG_CONFLICTS, dontfix, &workq, m);
963                   continue;
964                 }
965 #endif
966               /* foreach providers of a conflict of 's' */
967               FOR_PROVIDES(p, pp, con)
968                 {
969                   if (ispatch && !pool_match_nevr(pool, pool->solvables + p, con))
970                     continue;
971                   /* dontfix: dont care about conflicts with already installed packs */
972                   if (dontfix && pool->solvables[p].repo == installed)
973                     continue;
974                   if (p == n)           /* p == n: self conflict */
975                     {
976                       if (!pool->forbidselfconflicts || is_otherproviders_dep(pool, con))
977                         continue;
978                       addpkgrule(solv, -n, 0, 0, SOLVER_RULE_PKG_SELF_CONFLICT, con);
979                       continue;
980                     }
981                   if (ispatch && solv->multiversion.size && MAPTST(&solv->multiversion, p) && ISRELDEP(con))
982                     {
983                       /* our patch conflicts with a multiversion package */
984                       Id d = makemultiversionconflict(solv, p, con);
985                       if (d)
986                         {
987                           addpkgrule(solv, -n, 0, d, SOLVER_RULE_PKG_CONFLICTS, con);
988                           continue;
989                         }
990                     }
991                   if (p == SYSTEMSOLVABLE)
992                     p = 0;
993                   /* rule: -n|-p: either solvable _or_ provider of conflict */
994                   addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_CONFLICTS, con);
995                 }
996             }
997         }
998
999       /*-----------------------------------------
1000        * check obsoletes and implicit obsoletes of a package
1001        * if ignoreinstalledsobsoletes is not set, we're also checking
1002        * obsoletes of installed packages (like newer rpm versions)
1003        */
1004       if ((!installed || s->repo != installed) || !pool->noinstalledobsoletes)
1005         {
1006           int multi = solv->multiversion.size && MAPTST(&solv->multiversion, n);
1007           int isinstalled = (installed && s->repo == installed);
1008           if (s->obsoletes && (!multi || solv->keepexplicitobsoletes))
1009             {
1010               obsp = s->repo->idarraydata + s->obsoletes;
1011               /* foreach obsoletes */
1012               while ((obs = *obsp++) != 0)
1013                 {
1014                   /* foreach provider of an obsoletes of 's' */
1015                   FOR_PROVIDES(p, pp, obs)
1016                     {
1017                       Solvable *ps = pool->solvables + p;
1018                       if (p == n)
1019                         continue;
1020                       if (isinstalled && dontfix && ps->repo == installed)
1021                         continue;       /* don't repair installed/installed problems */
1022                       if (!pool->obsoleteusesprovides /* obsoletes are matched names, not provides */
1023                           && !pool_match_nevr(pool, ps, obs))
1024                         continue;
1025                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1026                         continue;
1027                       if (p == SYSTEMSOLVABLE)
1028                         p = 0;
1029                       if (!isinstalled)
1030                         addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_OBSOLETES, obs);
1031                       else
1032                         addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_INSTALLED_OBSOLETES, obs);
1033                     }
1034                 }
1035             }
1036           /* check implicit obsoletes
1037            * for installed packages we only need to check installed/installed problems (and
1038            * only when dontfix is not set), as the others are picked up when looking at the
1039            * uninstalled package.
1040            */
1041           if (!isinstalled || !dontfix)
1042             {
1043               FOR_PROVIDES(p, pp, s->name)
1044                 {
1045                   Solvable *ps = pool->solvables + p;
1046                   if (p == n)
1047                     continue;
1048                   if (isinstalled && ps->repo != installed)
1049                     continue;
1050                   /* we still obsolete packages with same nevra, like rpm does */
1051                   /* (actually, rpm mixes those packages. yuck...) */
1052                   if (multi && (s->name != ps->name || s->evr != ps->evr || s->arch != ps->arch))
1053                     {
1054                       if (isinstalled || ps->repo != installed)
1055                         continue;
1056                       /* also check the installed package for multi-ness */
1057                       if (MAPTST(&solv->multiversion, p))
1058                         continue;
1059                     }
1060                   if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
1061                     continue;
1062                   if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
1063                     continue;
1064                   if (p == SYSTEMSOLVABLE)
1065                     p = 0;
1066                   if (s->name == ps->name)
1067                     {
1068                       /* optimization: do not add the same-name conflict rule if it was
1069                        * already added when we looked at the other package.
1070                        * (this assumes pool_colormatch is symmetric) */
1071                       if (p && m && ps->repo != installed && MAPTST(m, p) &&
1072                           (ps->arch != ARCH_SRC && ps->arch != ARCH_NOSRC) &&
1073                           !(solv->multiversion.size && MAPTST(&solv->multiversion, p)))
1074                         continue;
1075                       addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_SAME_NAME, 0);
1076                     }
1077                   else
1078                     addpkgrule(solv, -n, -p, 0, SOLVER_RULE_PKG_IMPLICIT_OBSOLETES, s->name);
1079                 }
1080             }
1081         }
1082
1083       if (m && pool->implicitobsoleteusescolors && pool_arch2score(pool, s->arch) > 1)
1084         {
1085           unsigned int pa, a = pool_arch2score(pool, s->arch);
1086           /* check lock-step candidates */
1087           FOR_PROVIDES(p, pp, s->name)
1088             {
1089               Solvable *ps = pool->solvables + p;
1090               if (s->name != ps->name || s->evr != ps->evr || MAPTST(m, p))
1091                 continue;
1092               pa = pool_arch2score(pool, ps->arch);
1093               if (!pa || pa == 1 || pa >= a)
1094                 continue;
1095               queue_push(&workq, p);
1096             }
1097         }
1098
1099       /*-----------------------------------------
1100        * add recommends/suggests to the work queue
1101        */
1102       if (s->recommends && m)
1103         {
1104           recp = s->repo->idarraydata + s->recommends;
1105           while ((rec = *recp++) != 0)
1106             {
1107 #ifdef ENABLE_COMPLEX_DEPS
1108               if (pool_is_complex_dep(pool, rec))
1109                 {
1110                   pool_add_pos_literals_complex_dep(pool, rec, &workq, m, 0);
1111                   continue;
1112                 }
1113 #endif
1114               FOR_PROVIDES(p, pp, rec)
1115                 if (!MAPTST(m, p))
1116                   queue_push(&workq, p);
1117             }
1118         }
1119       if (s->suggests && m)
1120         {
1121           sugp = s->repo->idarraydata + s->suggests;
1122           while ((sug = *sugp++) != 0)
1123             {
1124 #ifdef ENABLE_COMPLEX_DEPS
1125               if (pool_is_complex_dep(pool, sug))
1126                 {
1127                   pool_add_pos_literals_complex_dep(pool, sug, &workq, m, 0);
1128                   continue;
1129                 }
1130 #endif
1131               FOR_PROVIDES(p, pp, sug)
1132                 if (!MAPTST(m, p))
1133                   queue_push(&workq, p);
1134             }
1135         }
1136     }
1137   queue_free(&depq);
1138   queue_free(&workq);
1139 }
1140
1141 #ifdef ENABLE_LINKED_PKGS
1142 void
1143 solver_addpkgrulesforlinked(Solver *solv, Map *m)
1144 {
1145   Pool *pool = solv->pool;
1146   Solvable *s;
1147   int i, j;
1148   Queue qr;
1149
1150   queue_init(&qr);
1151   for (i = 1; i < pool->nsolvables; i++)
1152     {
1153       if (MAPTST(m, i))
1154         continue;
1155       s = pool->solvables + i;
1156       if (!s->repo || s->repo == solv->installed)
1157         continue;
1158       if (!strchr(pool_id2str(pool, s->name), ':'))
1159         continue;
1160       if (!pool_installable(pool, s))
1161         continue;
1162       find_package_link(pool, s, 0, &qr, 0, 0);
1163       if (qr.count)
1164         {
1165           for (j = 0; j < qr.count; j++)
1166             if (MAPTST(m, qr.elements[j]))
1167               {
1168                 solver_addpkgrulesforsolvable(solv, s, m);
1169                 break;
1170               }
1171           queue_empty(&qr);
1172         }
1173     }
1174   queue_free(&qr);
1175 }
1176 #endif
1177
1178 /*-------------------------------------------------------------------
1179  *
1180  * Add rules for packages possibly selected in by weak dependencies
1181  *
1182  * m: already added solvables
1183  */
1184
1185 void
1186 solver_addpkgrulesforweak(Solver *solv, Map *m)
1187 {
1188   Pool *pool = solv->pool;
1189   Solvable *s;
1190   Id sup, *supp;
1191   int i, n;
1192
1193   /* foreach solvable in pool */
1194   for (i = n = 1; n < pool->nsolvables; i++, n++)
1195     {
1196       if (i == pool->nsolvables)                /* wrap i */
1197         i = 1;
1198       if (MAPTST(m, i))                         /* already added that one */
1199         continue;
1200
1201       s = pool->solvables + i;
1202       if (!s->repo)
1203         continue;
1204       if (s->repo != pool->installed && !pool_installable(pool, s))
1205         continue;       /* only look at installable ones */
1206
1207       sup = 0;
1208       if (s->supplements)
1209         {
1210           /* find possible supplements */
1211           supp = s->repo->idarraydata + s->supplements;
1212           while ((sup = *supp++) != 0)
1213             if (solver_dep_possible(solv, sup, m))
1214               break;
1215         }
1216
1217       /* if nothing found, check for enhances */
1218       if (!sup && s->enhances)
1219         {
1220           supp = s->repo->idarraydata + s->enhances;
1221           while ((sup = *supp++) != 0)
1222             if (solver_dep_possible(solv, sup, m))
1223               break;
1224         }
1225       /* if nothing found, goto next solvables */
1226       if (!sup)
1227         continue;
1228       solver_addpkgrulesforsolvable(solv, s, m);
1229       n = 0;                    /* check all solvables again because we added solvables to m */
1230     }
1231 }
1232
1233
1234 /*-------------------------------------------------------------------
1235  *
1236  * add package rules for possible updates
1237  *
1238  * s: solvable
1239  * m: map of already visited solvables
1240  * allow_all: 0 = dont allow downgrades, 1 = allow all candidates
1241  */
1242
1243 void
1244 solver_addpkgrulesforupdaters(Solver *solv, Solvable *s, Map *m, int allow_all)
1245 {
1246   Pool *pool = solv->pool;
1247   int i;
1248     /* queue and buffer for it */
1249   Queue qs;
1250   Id qsbuf[64];
1251
1252   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1253     /* find update candidates for 's' */
1254   policy_findupdatepackages(solv, s, &qs, allow_all);
1255     /* add rule for 's' if not already done */
1256   if (!MAPTST(m, s - pool->solvables))
1257     solver_addpkgrulesforsolvable(solv, s, m);
1258     /* foreach update candidate, add rule if not already done */
1259   for (i = 0; i < qs.count; i++)
1260     if (!MAPTST(m, qs.elements[i]))
1261       solver_addpkgrulesforsolvable(solv, pool->solvables + qs.elements[i], m);
1262   queue_free(&qs);
1263 }
1264
1265
1266 /***********************************************************************
1267  ***
1268  ***  Update/Feature rule part
1269  ***
1270  ***  Those rules make sure an installed package isn't silently deleted
1271  ***
1272  ***/
1273
1274 static int
1275 dup_maykeepinstalled(Solver *solv, Solvable *s)
1276 {
1277   Pool *pool = solv->pool;
1278   Id ip, pp;
1279
1280   if (solv->dupmap.size && MAPTST(&solv->dupmap,  s - pool->solvables))
1281     return 1;
1282   /* is installed identical to a good one? */
1283   FOR_PROVIDES(ip, pp, s->name)
1284     {
1285       Solvable *is = pool->solvables + ip;
1286       if (is->evr != s->evr)
1287         continue;
1288       if (solv->dupmap.size)
1289         {
1290           if (!MAPTST(&solv->dupmap, ip))
1291             continue;
1292         }
1293       else if (is->repo == pool->installed)
1294         continue;
1295       if (solvable_identical(s, is))
1296         return 1;
1297     }
1298   return 0;
1299 }
1300
1301
1302 /* stash away the original updaters for multiversion packages. We do this so that
1303  * we can update the package later */
1304 static inline void
1305 set_specialupdaters(Solver *solv, Solvable *s, Id d)
1306 {
1307   Repo *installed = solv->installed;
1308   if (!solv->specialupdaters)
1309     solv->specialupdaters = solv_calloc(installed->end - installed->start, sizeof(Id));
1310   solv->specialupdaters[s - solv->pool->solvables - installed->start] = d;
1311 }
1312
1313 #ifdef ENABLE_LINKED_PKGS
1314 /* Check if this is a linked pseudo package. As it is linked, we do not need an update/feature rule */
1315 static inline int
1316 is_linked_pseudo_package(Solver *solv, Solvable *s)
1317 {
1318   Pool *pool = solv->pool;
1319   if (solv->instbuddy && solv->instbuddy[s - pool->solvables - solv->installed->start])
1320     {
1321       const char *name = pool_id2str(pool, s->name);
1322       if (strncmp(name, "pattern:", 8) == 0 || strncmp(name, "application:", 12) == 0)
1323         return 1;
1324     }
1325   return 0;
1326 }
1327 #endif
1328
1329 void
1330 solver_addfeaturerule(Solver *solv, Solvable *s)
1331 {
1332   Pool *pool = solv->pool;
1333   int i;
1334   Id p;
1335   Queue qs;
1336   Id qsbuf[64];
1337
1338 #ifdef ENABLE_LINKED_PKGS
1339   if (is_linked_pseudo_package(solv, s))
1340     {
1341       solver_addrule(solv, 0, 0, 0);    /* no feature rules for those */
1342       return;
1343     }
1344 #endif
1345   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1346   p = s - pool->solvables;
1347   policy_findupdatepackages(solv, s, &qs, 1);
1348   if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1349     {
1350       if (!dup_maykeepinstalled(solv, s))
1351         {
1352           for (i = 0; i < qs.count; i++)
1353             {
1354               Solvable *ns = pool->solvables + qs.elements[i];
1355               if (ns->repo != pool->installed || dup_maykeepinstalled(solv, ns))
1356                 break;
1357             }
1358           if (i == qs.count)
1359             {
1360               solver_addrule(solv, 0, 0, 0);    /* this is an orphan */
1361               queue_free(&qs);
1362               return;
1363             }
1364         }
1365     }
1366   if (qs.count > 1)
1367     {
1368       Id d = pool_queuetowhatprovides(pool, &qs);
1369       queue_free(&qs);
1370       solver_addrule(solv, p, 0, d);    /* allow update of s */
1371     }
1372   else
1373     {
1374       Id d = qs.count ? qs.elements[0] : 0;
1375       queue_free(&qs);
1376       solver_addrule(solv, p, d, 0);    /* allow update of s */
1377     }
1378 }
1379
1380 /* check if multiversion solvable s2 has an obsoletes for installed solvable s */
1381 static int
1382 is_multiversion_obsoleteed(Pool *pool, Solvable *s, Solvable *s2)
1383 {
1384   Id *wp, obs, *obsp;
1385
1386   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
1387     return 0;
1388   obsp = s2->repo->idarraydata + s2->obsoletes;
1389   if (!pool->obsoleteusesprovides)
1390     {
1391       while ((obs = *obsp++) != 0)
1392         if (pool_match_nevr(pool, s, obs))
1393           return 1;
1394     }
1395   else
1396     {
1397       while ((obs = *obsp++) != 0)
1398         for (wp = pool_whatprovides_ptr(pool, obs); *wp; wp++)
1399           if (pool->solvables + *wp == s)
1400             return 1;
1401     }
1402   return 0;
1403 }
1404
1405 /*-------------------------------------------------------------------
1406  *
1407  * add rule for update
1408  *   (A|A1|A2|A3...)  An = update candidates for A
1409  *
1410  * s = (installed) solvable
1411  */
1412
1413 void
1414 solver_addupdaterule(Solver *solv, Solvable *s)
1415 {
1416   /* installed packages get a special upgrade allowed rule */
1417   Pool *pool = solv->pool;
1418   Id p, d;
1419   Queue qs;
1420   Id qsbuf[64];
1421   Rule *r;
1422   int dupinvolved = 0;
1423
1424   p = s - pool->solvables;
1425
1426   if (pool->considered && pool_disabled_solvable(pool, s))
1427     {
1428       /* disabled installed solvables must stay installed */
1429       solver_addrule(solv, p, 0, 0);
1430       return;
1431     }
1432
1433   /* Orphan detection. We cheat by looking at the feature rule, which
1434    * we already calculated */
1435   r = solv->rules + solv->featurerules + (p - solv->installed->start);
1436   if (!r->p)
1437     {
1438 #ifdef ENABLE_LINKED_PKGS
1439       if (is_linked_pseudo_package(solv, s))
1440         {
1441           solver_addrule(solv, 0, 0, 0);
1442           return;
1443         }
1444 #endif
1445       p = 0;
1446       queue_push(&solv->orphaned, s - pool->solvables);         /* an orphaned package */
1447       if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, s - pool->solvables - solv->installed->start))))
1448         p = s - pool->solvables;        /* keep this orphaned package installed */
1449       solver_addrule(solv, p, 0, 0);
1450       return;
1451     }
1452
1453   /* find update candidates for 's' */
1454   queue_init_buffer(&qs, qsbuf, sizeof(qsbuf)/sizeof(*qsbuf));
1455   dupinvolved = solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p));
1456   policy_findupdatepackages(solv, s, &qs, dupinvolved ? 2 : 0);
1457
1458   if (qs.count && solv->multiversion.size)
1459     {
1460       int i, j;
1461
1462       for (i = 0; i < qs.count; i++)
1463         if (MAPTST(&solv->multiversion, qs.elements[i]))
1464           break;
1465       if (i < qs.count)
1466         {
1467           /* filter out all multiversion packages as they don't update */
1468           d = pool_queuetowhatprovides(pool, &qs);      /* save qs away */
1469           for (j = i; i < qs.count; i++)
1470              {
1471               if (MAPTST(&solv->multiversion, qs.elements[i]))
1472                 {
1473                   Solvable *ps = pool->solvables + qs.elements[i];
1474                   /* check if there is an explicit obsoletes */
1475                   if (solv->keepexplicitobsoletes && ps->obsoletes && is_multiversion_obsoleteed(pool, s, ps))
1476                     {
1477                       qs.elements[j++] = qs.elements[i];
1478                       continue;
1479                     }
1480                   /* it's ok if they have same nevra */
1481                   if (ps->name != s->name || ps->evr != s->evr || ps->arch != s->arch)
1482                     continue;
1483                 }
1484               qs.elements[j++] = qs.elements[i];
1485             }
1486
1487           if (j == 0 && dupinvolved && !dup_maykeepinstalled(solv, s))
1488             {
1489               /* this is a multiversion orphan */
1490               queue_push(&solv->orphaned, p);
1491               set_specialupdaters(solv, s, d);
1492               if (solv->keep_orphans && !(solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
1493                 {
1494                   /* we need to keep the orphan */
1495                   queue_free(&qs);
1496                   solver_addrule(solv, p, 0, 0);
1497                   return;
1498                 }
1499               /* we can drop it as long as we update */
1500               j = qs.count;
1501             }
1502
1503           if (j < qs.count)             /* filtered at least one package? */
1504             {
1505               if (d && (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
1506                 {
1507                   /* non-orphan multiversion package, set special updaters if we want an update */
1508                   set_specialupdaters(solv, s, d);
1509                 }
1510               qs.count = j;
1511             }
1512           else
1513             {
1514               /* could fallthrough, but then we would do pool_queuetowhatprovides twice */
1515               queue_free(&qs);
1516               solver_addrule(solv, p, 0, d);    /* allow update of s */
1517               return;
1518             }
1519         }
1520     }
1521   if (qs.count > 1)
1522     {
1523       d = pool_queuetowhatprovides(pool, &qs);
1524       queue_free(&qs);
1525       solver_addrule(solv, p, 0, d);    /* allow update of s */
1526     }
1527   else
1528     {
1529       d = qs.count ? qs.elements[0] : 0;
1530       queue_free(&qs);
1531       solver_addrule(solv, p, d, 0);    /* allow update of s */
1532     }
1533 }
1534
1535 static inline void
1536 disableupdaterule(Solver *solv, Id p)
1537 {
1538   Rule *r;
1539
1540   MAPSET(&solv->noupdate, p - solv->installed->start);
1541   r = solv->rules + solv->updaterules + (p - solv->installed->start);
1542   if (r->p && r->d >= 0)
1543     solver_disablerule(solv, r);
1544   r = solv->rules + solv->featurerules + (p - solv->installed->start);
1545   if (r->p && r->d >= 0)
1546     solver_disablerule(solv, r);
1547   if (solv->bestrules_info)
1548     {
1549       int i, ni;
1550       ni = solv->bestrules_end - solv->bestrules;
1551       for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
1552         if (solv->bestrules_info[i] == p)
1553           solver_disablerule(solv, solv->rules + solv->bestrules + i);
1554     }
1555 }
1556
1557 static inline void
1558 reenableupdaterule(Solver *solv, Id p)
1559 {
1560   Pool *pool = solv->pool;
1561   Rule *r;
1562
1563   MAPCLR(&solv->noupdate, p - solv->installed->start);
1564   r = solv->rules + solv->updaterules + (p - solv->installed->start);
1565   if (r->p)
1566     {
1567       if (r->d < 0)
1568         {
1569           solver_enablerule(solv, r);
1570           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1571             {
1572               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1573               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1574             }
1575         }
1576     }
1577   else
1578     {
1579       r = solv->rules + solv->featurerules + (p - solv->installed->start);
1580       if (r->p && r->d < 0)
1581         {
1582           solver_enablerule(solv, r);
1583           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1584             {
1585               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1586               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1587             }
1588         }
1589     }
1590   if (solv->bestrules_info)
1591     {
1592       int i, ni;
1593       ni = solv->bestrules_end - solv->bestrules;
1594       for (i = solv->bestrules_up - solv->bestrules; i < ni; i++)
1595         if (solv->bestrules_info[i] == p)
1596           solver_enablerule(solv, solv->rules + solv->bestrules + i);
1597     }
1598 }
1599
1600
1601 /***********************************************************************
1602  ***
1603  ***  Infarch rule part
1604  ***
1605  ***  Infarch rules make sure the solver uses the best architecture of
1606  ***  a package if multiple archetectures are available
1607  ***
1608  ***/
1609
1610 void
1611 solver_addinfarchrules(Solver *solv, Map *addedmap)
1612 {
1613   Pool *pool = solv->pool;
1614   Repo *installed = pool->installed;
1615   int first, i, j;
1616   Id p, pp, aa;
1617   unsigned int a, bestscore;
1618   Solvable *s, *ps, *bests;
1619   Queue badq, allowedarchs;
1620   Queue lsq;
1621
1622   queue_init(&badq);
1623   queue_init(&allowedarchs);
1624   queue_init(&lsq);
1625   solv->infarchrules = solv->nrules;
1626   for (i = 1; i < pool->nsolvables; i++)
1627     {
1628       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
1629         continue;
1630       s = pool->solvables + i;
1631       first = i;
1632       bestscore = 0;
1633       bests = 0;
1634       queue_empty(&allowedarchs);
1635       FOR_PROVIDES(p, pp, s->name)
1636         {
1637           ps = pool->solvables + p;
1638           if (ps->name != s->name || !MAPTST(addedmap, p))
1639             continue;
1640           if (p == i)
1641             first = 0;
1642           if (first)
1643             break;
1644           a = pool_arch2score(pool, ps->arch);
1645           if (a != 1 && installed && ps->repo == installed)
1646             {
1647               if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1648                 continue;
1649               queue_pushunique(&allowedarchs, ps->arch);        /* also ok to keep this architecture */
1650               continue;         /* but ignore installed solvables when calculating the best arch */
1651             }
1652           if (a && a != 1 && (!bestscore || a < bestscore))
1653             {
1654               bestscore = a;
1655               bests = ps;
1656             }
1657         }
1658       if (first)
1659         continue;
1660
1661       /* speed up common case where installed package already has best arch */
1662       if (allowedarchs.count == 1 && bests && allowedarchs.elements[0] == bests->arch)
1663         allowedarchs.count--;   /* installed arch is best */
1664
1665       if (allowedarchs.count && pool->implicitobsoleteusescolors && installed && bestscore)
1666         {
1667           /* need an extra pass for lockstep checking: we only allow to keep an inferior arch
1668            * if the corresponding installed package is not lock-stepped */
1669           queue_empty(&allowedarchs);
1670           FOR_PROVIDES(p, pp, s->name)
1671             {
1672               Id p2, pp2;
1673               ps = pool->solvables + p;
1674               if (ps->name != s->name || ps->repo != installed || !MAPTST(addedmap, p))
1675                 continue;
1676               if (solv->dupinvolvedmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p)))
1677                 continue;
1678               a = pool_arch2score(pool, ps->arch);
1679               if (!a)
1680                 {
1681                   queue_pushunique(&allowedarchs, ps->arch);    /* strange arch, allow */
1682                   continue;
1683                 }
1684               if (a == 1 || ((a ^ bestscore) & 0xffff0000) == 0)
1685                 continue;
1686               /* have installed package with inferior arch, check if lock-stepped */
1687               FOR_PROVIDES(p2, pp2, s->name)
1688                 {
1689                   Solvable *s2 = pool->solvables + p2;
1690                   unsigned int a2;
1691                   if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
1692                     continue;
1693                   a2 = pool_arch2score(pool, s2->arch);
1694                   if (a2 && (a2 == 1 || ((a2 ^ bestscore) & 0xffff0000) == 0))
1695                     break;
1696                 }
1697               if (!p2)
1698                 queue_pushunique(&allowedarchs, ps->arch);
1699             }
1700         }
1701
1702       /* find all bad packages */
1703       queue_empty(&badq);
1704       FOR_PROVIDES(p, pp, s->name)
1705         {
1706           ps = pool->solvables + p;
1707           if (ps->name != s->name || !MAPTST(addedmap, p))
1708             continue;
1709           a = pool_arch2score(pool, ps->arch);
1710           if (a != 1 && bestscore && ((a ^ bestscore) & 0xffff0000) != 0)
1711             {
1712               if (installed && ps->repo == installed)
1713                 {
1714                   if (pool->implicitobsoleteusescolors)
1715                     queue_push(&badq, p);               /* special lock-step handling, see below */
1716                   continue;     /* always ok to keep an installed package */
1717                 }
1718               for (j = 0; j < allowedarchs.count; j++)
1719                 {
1720                   unsigned int aas;
1721                   aa = allowedarchs.elements[j];
1722                   if (ps->arch == aa)
1723                     break;
1724                   aas = pool_arch2score(pool, aa);
1725                   if (aas && ((a ^ aas) & 0xffff0000) == 0)
1726                     break;      /* compatible */
1727                 }
1728               if (j == allowedarchs.count)
1729                 queue_push(&badq, p);
1730             }
1731         }
1732
1733       /* block all solvables in the badq! */
1734       for (j = 0; j < badq.count; j++)
1735         {
1736           p = badq.elements[j];
1737           /* special lock-step handling */
1738           if (pool->implicitobsoleteusescolors)
1739             {
1740               Id p2;
1741               int haveinstalled = 0;
1742               queue_empty(&lsq);
1743               FOR_PROVIDES(p2, pp, s->name)
1744                 {
1745                   Solvable *s2 = pool->solvables + p2;
1746                   if (p2 == p || s2->name != s->name || s2->evr != pool->solvables[p].evr || s2->arch == pool->solvables[p].arch)
1747                     continue;
1748                   a = pool_arch2score(pool, s2->arch);
1749                   if (a && (a == 1 || ((a ^ bestscore) & 0xffff000) == 0))
1750                     {
1751                       queue_push(&lsq, p2);
1752                       if (installed && s2->repo == installed)
1753                         haveinstalled = 1;
1754                     }
1755                 }
1756               if (installed && pool->solvables[p].repo == installed && !haveinstalled)
1757                 continue;       /* installed package not in lock-step */
1758               if (lsq.count < 2)
1759                 solver_addrule(solv, -p, lsq.count ? lsq.elements[0] : 0, 0);
1760               else
1761                 solver_addrule(solv, -p, 0, pool_queuetowhatprovides(pool, &lsq));
1762             }
1763           else
1764             {
1765               solver_addrule(solv, -p, 0, 0);
1766             }
1767         }
1768     }
1769   queue_free(&lsq);
1770   queue_free(&badq);
1771   queue_free(&allowedarchs);
1772   solv->infarchrules_end = solv->nrules;
1773 }
1774
1775 static inline void
1776 disableinfarchrule(Solver *solv, Id name)
1777 {
1778   Pool *pool = solv->pool;
1779   Rule *r;
1780   int i;
1781   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1782     {
1783       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
1784         solver_disablerule(solv, r);
1785     }
1786 }
1787
1788 static inline void
1789 reenableinfarchrule(Solver *solv, Id name)
1790 {
1791   Pool *pool = solv->pool;
1792   Rule *r;
1793   int i;
1794   for (i = solv->infarchrules, r = solv->rules + i; i < solv->infarchrules_end; i++, r++)
1795     {
1796       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
1797         {
1798           solver_enablerule(solv, r);
1799           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
1800             {
1801               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
1802               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
1803             }
1804         }
1805     }
1806 }
1807
1808
1809 /***********************************************************************
1810  ***
1811  ***  Dup rule part
1812  ***
1813  ***  Dup rules make sure a package is selected from the specified dup
1814  ***  repositories if an update candidate is included in one of them.
1815  ***
1816  ***/
1817
1818 static inline void
1819 add_cleandeps_updatepkg(Solver *solv, Id p)
1820 {
1821   if (!solv->cleandeps_updatepkgs)
1822     {
1823       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
1824       queue_init(solv->cleandeps_updatepkgs);
1825     }
1826   queue_pushunique(solv->cleandeps_updatepkgs, p);
1827 }
1828
1829 static void
1830 solver_addtodupmaps(Solver *solv, Id p, Id how, int targeted)
1831 {
1832   Pool *pool = solv->pool;
1833   Solvable *ps, *s = pool->solvables + p;
1834   Repo *installed = solv->installed;
1835   Id pi, pip, obs, *obsp;
1836
1837   if (!solv->dupinvolvedmap.size)
1838     map_grow(&solv->dupinvolvedmap, pool->nsolvables);
1839
1840   MAPSET(&solv->dupinvolvedmap, p);
1841   if (targeted)
1842     MAPSET(&solv->dupmap, p);
1843   FOR_PROVIDES(pi, pip, s->name)
1844     {
1845       ps = pool->solvables + pi;
1846       if (ps->name != s->name)
1847         continue;
1848       MAPSET(&solv->dupinvolvedmap, pi);
1849       if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
1850         {
1851           Id *opp, pi2;
1852           for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
1853             if (pool->solvables[pi2].repo != installed)
1854               MAPSET(&solv->dupinvolvedmap, pi2);
1855         }
1856       if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all)
1857         {
1858           if (!solv->bestupdatemap.size)
1859             map_grow(&solv->bestupdatemap, installed->end - installed->start);
1860           MAPSET(&solv->bestupdatemap, pi - installed->start);
1861         }
1862       if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
1863         add_cleandeps_updatepkg(solv, pi);
1864       if (!targeted && ps->repo != installed)
1865         MAPSET(&solv->dupmap, pi);
1866     }
1867   if (s->repo == installed && solv->obsoletes && solv->obsoletes[p - installed->start])
1868     {
1869       Id *opp;
1870       for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (pi = *opp++) != 0;)
1871         {
1872           ps = pool->solvables + pi;
1873           if (ps->repo == installed)
1874             continue;
1875           MAPSET(&solv->dupinvolvedmap, pi);
1876           if (!targeted)
1877             MAPSET(&solv->dupmap, pi);
1878         }
1879     }
1880   if (targeted && s->repo != installed && s->obsoletes)
1881     {
1882       /* XXX: check obsoletes/provides combination */
1883       obsp = s->repo->idarraydata + s->obsoletes;
1884       while ((obs = *obsp++) != 0)
1885         {
1886           FOR_PROVIDES(pi, pip, obs)
1887             {
1888               Solvable *ps = pool->solvables + pi;
1889               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
1890                 continue;
1891               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
1892                 continue;
1893               MAPSET(&solv->dupinvolvedmap, pi);
1894               if (targeted && ps->repo == installed && solv->obsoletes && solv->obsoletes[pi - installed->start])
1895                 {
1896                   Id *opp, pi2;
1897                   for (opp = solv->obsoletes_data + solv->obsoletes[pi - installed->start]; (pi2 = *opp++) != 0;)
1898                     if (pool->solvables[pi2].repo != installed)
1899                       MAPSET(&solv->dupinvolvedmap, pi2);
1900                 }
1901               if (ps->repo == installed && (how & SOLVER_FORCEBEST) != 0 && !solv->bestupdatemap_all)
1902                 {
1903                   if (!solv->bestupdatemap.size)
1904                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
1905                   MAPSET(&solv->bestupdatemap, pi - installed->start);
1906                 }
1907               if (ps->repo == installed && (how & SOLVER_CLEANDEPS) != 0)
1908                 add_cleandeps_updatepkg(solv, pi);
1909             }
1910         }
1911     }
1912 }
1913
1914 /* create the two dupmaps:
1915  * - dupmap: packages in that map are good to install/keep
1916  * - dupinvolvedmap: packages are subject to dup mode
1917  */
1918 void
1919 solver_createdupmaps(Solver *solv)
1920 {
1921   Queue *job = &solv->job;
1922   Pool *pool = solv->pool;
1923   Repo *installed = solv->installed;
1924   Id select, how, what, p, pp;
1925   Solvable *s;
1926   int i, targeted;
1927
1928   map_init(&solv->dupmap, pool->nsolvables);
1929   solv->dupinvolvedmap_all = 0;
1930   map_init(&solv->dupinvolvedmap, 0);
1931   for (i = 0; i < job->count; i += 2)
1932     {
1933       how = job->elements[i];
1934       select = job->elements[i] & SOLVER_SELECTMASK;
1935       what = job->elements[i + 1];
1936       switch (how & SOLVER_JOBMASK)
1937         {
1938         case SOLVER_DISTUPGRADE:
1939           if (select == SOLVER_SOLVABLE_REPO)
1940             {
1941               Repo *repo;
1942               if (what <= 0 || what > pool->nrepos)
1943                 break;
1944               repo = pool_id2repo(pool, what);
1945               if (!repo)
1946                 break;
1947               if (repo != installed && !(how & SOLVER_TARGETED) && solv->noautotarget)
1948                 break;
1949               targeted = repo != installed || (how & SOLVER_TARGETED) != 0;
1950               FOR_REPO_SOLVABLES(repo, p, s)
1951                 {
1952                   if (repo != installed && !pool_installable(pool, s))
1953                     continue;
1954                   solver_addtodupmaps(solv, p, how, targeted);
1955                 }
1956             }
1957           else if (select == SOLVER_SOLVABLE_ALL)
1958             {
1959               solv->dupinvolvedmap_all = 1;
1960               FOR_POOL_SOLVABLES(p)
1961                 {
1962                   Solvable *s = pool->solvables + p;
1963                   if (!s->repo || s->repo == installed)
1964                     continue;
1965                   if (!pool_installable(pool, s))
1966                     continue;
1967                   MAPSET(&solv->dupmap, p);
1968                 }
1969               if ((how & SOLVER_FORCEBEST) != 0)
1970                 solv->bestupdatemap_all = 1;
1971               if ((how & SOLVER_CLEANDEPS) != 0 && installed)
1972                 {
1973                   FOR_REPO_SOLVABLES(installed, p, s)
1974                     add_cleandeps_updatepkg(solv, p);
1975                 }
1976             }
1977           else
1978             {
1979               targeted = how & SOLVER_TARGETED ? 1 : 0;
1980               if (installed && !targeted && !solv->noautotarget)
1981                 {
1982                   FOR_JOB_SELECT(p, pp, select, what)
1983                     if (pool->solvables[p].repo == installed)
1984                       break;
1985                   targeted = p == 0;
1986                 }
1987               else if (!installed && !solv->noautotarget)
1988                 targeted = 1;
1989               FOR_JOB_SELECT(p, pp, select, what)
1990                 {
1991                   Solvable *s = pool->solvables + p;
1992                   if (!s->repo)
1993                     continue;
1994                   if (s->repo != installed && !targeted)
1995                     continue;
1996                   if (s->repo != installed && !pool_installable(pool, s))
1997                     continue;
1998                   solver_addtodupmaps(solv, p, how, targeted);
1999                 }
2000             }
2001           break;
2002         default:
2003           break;
2004         }
2005     }
2006   if (solv->dupinvolvedmap.size)
2007     MAPCLR(&solv->dupinvolvedmap, SYSTEMSOLVABLE);
2008   /* set update for all involved installed packages. We need to do
2009    * this before creating the update rules */
2010   if (solv->dupinvolvedmap_all)
2011     solv->updatemap_all = 1;
2012   else if (installed && !solv->updatemap_all && solv->dupinvolvedmap.size)
2013     {
2014       FOR_REPO_SOLVABLES(installed, p, s)
2015         {
2016           if (!MAPTST(&solv->dupinvolvedmap, p))
2017             continue;
2018           if (!solv->updatemap.size)
2019             map_grow(&solv->updatemap, installed->end - installed->start);
2020           MAPSET(&solv->updatemap, p - installed->start);
2021         }
2022     }
2023 }
2024
2025 void
2026 solver_freedupmaps(Solver *solv)
2027 {
2028   map_free(&solv->dupmap);
2029   /* we no longer free solv->dupinvolvedmap as we need it in
2030    * policy's priority pruning code. sigh. */
2031 }
2032
2033 void
2034 solver_addduprules(Solver *solv, Map *addedmap)
2035 {
2036   Pool *pool = solv->pool;
2037   Repo *installed = solv->installed;
2038   Id p, pp;
2039   Solvable *s, *ps;
2040   int first, i;
2041   Rule *r;
2042
2043   solv->duprules = solv->nrules;
2044   for (i = 1; i < pool->nsolvables; i++)
2045     {
2046       if (i == SYSTEMSOLVABLE || !MAPTST(addedmap, i))
2047         continue;
2048       s = pool->solvables + i;
2049       first = i;
2050       FOR_PROVIDES(p, pp, s->name)
2051         {
2052           ps = pool->solvables + p;
2053           if (ps->name != s->name || !MAPTST(addedmap, p))
2054             continue;
2055           if (p == i)
2056             first = 0;
2057           if (first)
2058             break;
2059           if (!solv->dupinvolvedmap_all && !MAPTST(&solv->dupinvolvedmap, p))
2060             continue;
2061           if (installed && ps->repo == installed)
2062             {
2063               if (pool->considered && pool_disabled_solvable(pool, ps))
2064                 continue;               /* always keep disabled installed packages */
2065               if (!MAPTST(&solv->dupmap, p))
2066                 {
2067                   Id ip, ipp;
2068                   /* is installed identical to a good one? */
2069                   FOR_PROVIDES(ip, ipp, ps->name)
2070                     {
2071                       Solvable *is = pool->solvables + ip;
2072                       if (!MAPTST(&solv->dupmap, ip))
2073                         continue;
2074                       if (is->evr == ps->evr && solvable_identical(ps, is))
2075                         break;
2076                     }
2077                   if (ip)
2078                     {
2079                       /* ok, identical to a good one. we may keep this package. */
2080                       MAPSET(&solv->dupmap, p);         /* for best rules processing */
2081                       continue;
2082                     }
2083                   /* check if it's orphaned. If yes, we may keep it */
2084                   r = solv->rules + solv->updaterules + (p - installed->start);
2085                   if (!r->p)
2086                     r = solv->rules + solv->featurerules + (p - installed->start);
2087                   if (!r->p)
2088                     {
2089                       /* no update/feature rule, this is an orphan */
2090                       MAPSET(&solv->dupmap, p);         /* for best rules processing */
2091                       continue;
2092                     }
2093                   if (solv->specialupdaters && solv->specialupdaters[p - installed->start])
2094                     {
2095                       /* this is a multiversion orphan, we're good if an update is installed */
2096                       solver_addrule(solv, -p, 0, solv->specialupdaters[p - installed->start]);
2097                       continue;
2098                     }
2099                   if (r->p == p && !r->d && !r->w2)
2100                     {
2101                       r = solv->rules + solv->featurerules + (p - installed->start);
2102                       if (!r->p || (!r->d && !r->w2))
2103                         {
2104                           /* this is an orphan */
2105                           MAPSET(&solv->dupmap, p);             /* for best rules processing */
2106                           continue;
2107                         }
2108                     }
2109                   solver_addrule(solv, -p, 0, 0);       /* no match, sorry */
2110                 }
2111             }
2112           else if (!MAPTST(&solv->dupmap, p))
2113             solver_addrule(solv, -p, 0, 0);
2114         }
2115     }
2116   solv->duprules_end = solv->nrules;
2117 }
2118
2119
2120 static inline void
2121 disableduprule(Solver *solv, Id name)
2122 {
2123   Pool *pool = solv->pool;
2124   Rule *r;
2125   int i;
2126   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
2127     {
2128       if (r->p < 0 && r->d >= 0 && pool->solvables[-r->p].name == name)
2129         solver_disablerule(solv, r);
2130     }
2131 }
2132
2133 static inline void
2134 reenableduprule(Solver *solv, Id name)
2135 {
2136   Pool *pool = solv->pool;
2137   Rule *r;
2138   int i;
2139   for (i = solv->duprules, r = solv->rules + i; i < solv->duprules_end; i++, r++)
2140     {
2141       if (r->p < 0 && r->d < 0 && pool->solvables[-r->p].name == name)
2142         {
2143           solver_enablerule(solv, r);
2144           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
2145             {
2146               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
2147               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
2148             }
2149         }
2150     }
2151 }
2152
2153 /***********************************************************************
2154  ***
2155  ***  Black rule part
2156  ***/
2157
2158 static inline void
2159 disableblackrule(Solver *solv, Id p)
2160 {
2161   Rule *r;
2162   int i;
2163   for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
2164     if (r->p == -p)
2165       solver_disablerule(solv, r);
2166 }
2167
2168 static inline void
2169 reenableblackrule(Solver *solv, Id p)
2170 {
2171   Pool *pool = solv->pool;
2172   Rule *r;
2173   int i;
2174   for (i = solv->blackrules, r = solv->rules + i; i < solv->blackrules_end; i++, r++)
2175     if (r->p == -p)
2176       {
2177         solver_enablerule(solv, r);
2178         IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
2179           {
2180             POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "@@@ re-enabling ");
2181             solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
2182           }
2183       }
2184 }
2185
2186 void
2187 solver_addblackrules(Solver *solv)
2188 {
2189   int i;
2190   Id how, select, what, p, pp;
2191   Queue *job = &solv->job;
2192   Pool *pool = solv->pool;
2193   Repo *installed = solv->installed;
2194   Map updatemap;
2195
2196   map_init(&updatemap, 0);
2197   solv->blackrules = solv->nrules;
2198   if (installed)
2199     {
2200       for (i = 0; i < job->count; i += 2)
2201         {
2202           how = job->elements[i];
2203           select = job->elements[i] & SOLVER_SELECTMASK;
2204           what = job->elements[i + 1];
2205           switch (how & SOLVER_JOBMASK)
2206             {
2207             case SOLVER_BLACKLIST:
2208               FOR_JOB_SELECT(p, pp, select, what)
2209                 {
2210                   Solvable *s = pool->solvables + p;
2211                   if (s->repo != installed)
2212                     continue;
2213                   if (!updatemap.size)
2214                     map_grow(&updatemap, pool->ss.nstrings);
2215                   if (s->name > 0 && s->name < pool->ss.nstrings)
2216                     MAPSET(&updatemap, s->name);
2217                 }
2218             }
2219         }
2220     }
2221   for (i = 0; i < job->count; i += 2)
2222     {
2223       how = job->elements[i];
2224       select = job->elements[i] & SOLVER_SELECTMASK;
2225       what = job->elements[i + 1];
2226       switch (how & SOLVER_JOBMASK)
2227         {
2228         case SOLVER_BLACKLIST:
2229           FOR_JOB_SELECT(p, pp, select, what)
2230             {
2231               Solvable *s = pool->solvables + p;
2232               if (s->repo == installed)
2233                 continue;
2234               if (updatemap.size && s->name > 0 && s->name < pool->ss.nstrings && MAPTST(&updatemap, s->name))
2235                 continue;       /* installed package with same name is already blacklisted */
2236               solver_addrule(solv, -p, 0, 0);
2237             }
2238           break;
2239         }
2240     }
2241   map_free(&updatemap);
2242   solv->blackrules_end = solv->nrules;
2243 }
2244
2245 /***********************************************************************
2246  ***
2247  ***  Policy rule disabling/reenabling
2248  ***
2249  ***  Disable all policy rules that conflict with our jobs. If a job
2250  ***  gets disabled later on, reenable the involved policy rules again.
2251  ***
2252  ***/
2253
2254 #define DISABLE_UPDATE  1
2255 #define DISABLE_INFARCH 2
2256 #define DISABLE_DUP     3
2257 #define DISABLE_BLACK   4
2258
2259 static void
2260 jobtodisablelist(Solver *solv, Id how, Id what, Queue *q)
2261 {
2262   Pool *pool = solv->pool;
2263   Id select, p, pp;
2264   Repo *installed;
2265   Solvable *s;
2266   int i, j, set, qstart;
2267   Map omap;
2268
2269   installed = solv->installed;
2270   select = how & SOLVER_SELECTMASK;
2271   switch (how & SOLVER_JOBMASK)
2272     {
2273     case SOLVER_INSTALL:
2274       set = how & SOLVER_SETMASK;
2275       if (!(set & SOLVER_NOAUTOSET))
2276         {
2277           /* automatically add set bits by analysing the job */
2278           if (select == SOLVER_SOLVABLE_NAME)
2279             set |= SOLVER_SETNAME;
2280           if (select == SOLVER_SOLVABLE)
2281             set |= SOLVER_SETNAME | SOLVER_SETARCH | SOLVER_SETVENDOR | SOLVER_SETREPO | SOLVER_SETEVR;
2282           else if ((select == SOLVER_SOLVABLE_NAME || select == SOLVER_SOLVABLE_PROVIDES) && ISRELDEP(what))
2283             {
2284               Reldep *rd = GETRELDEP(pool, what);
2285               if (rd->flags == REL_EQ && select == SOLVER_SOLVABLE_NAME)
2286                 {
2287                   if (pool->disttype != DISTTYPE_DEB)
2288                     {
2289                       const char *rel = strrchr(pool_id2str(pool, rd->evr), '-');
2290                       set |= rel ? SOLVER_SETEVR : SOLVER_SETEV;
2291                     }
2292                   else
2293                     set |= SOLVER_SETEVR;
2294                 }
2295               if (rd->flags <= 7 && ISRELDEP(rd->name))
2296                 rd = GETRELDEP(pool, rd->name);
2297               if (rd->flags == REL_ARCH)
2298                 set |= SOLVER_SETARCH;
2299             }
2300         }
2301       else
2302         set &= ~SOLVER_NOAUTOSET;
2303       if (!set)
2304         return;
2305       if ((set & SOLVER_SETARCH) != 0 && solv->infarchrules != solv->infarchrules_end)
2306         {
2307           if (select == SOLVER_SOLVABLE)
2308             {
2309               for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
2310                 if (solv->rules[i].p == -what)
2311                   break;
2312               if (i < solv->infarchrules_end)
2313                 queue_push2(q, DISABLE_INFARCH, pool->solvables[what].name);
2314             }
2315           else
2316             {
2317               int qcnt = q->count;
2318               /* does not work for SOLVER_SOLVABLE_ALL and SOLVER_SOLVABLE_REPO, but
2319                  they are not useful for SOLVER_INSTALL jobs anyway */
2320               FOR_JOB_SELECT(p, pp, select, what)
2321                 {
2322                   s = pool->solvables + p;
2323                   /* unify names */
2324                   for (i = qcnt; i < q->count; i += 2)
2325                     if (q->elements[i + 1] == s->name)
2326                       break;
2327                   if (i < q->count)
2328                     continue;           /* already have that DISABLE_INFARCH element */
2329                   for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
2330                     if (solv->rules[i].p == -p)
2331                       break;
2332                   if (i < solv->infarchrules_end)
2333                     queue_push2(q, DISABLE_INFARCH, s->name);
2334                 }
2335             }
2336         }
2337       if ((set & SOLVER_SETREPO) != 0 && solv->duprules != solv->duprules_end)
2338         {
2339           if (select == SOLVER_SOLVABLE)
2340             queue_push2(q, DISABLE_DUP, pool->solvables[what].name);
2341           else
2342             {
2343               int qcnt = q->count;
2344               FOR_JOB_SELECT(p, pp, select, what)
2345                 {
2346                   s = pool->solvables + p;
2347                   /* unify names */
2348                   for (i = qcnt; i < q->count; i += 2)
2349                     if (q->elements[i + 1] == s->name)
2350                       break;
2351                   if (i < q->count)
2352                     continue;
2353                   queue_push2(q, DISABLE_DUP, s->name);
2354                 }
2355             }
2356         }
2357       if ((set & SOLVER_SETEVR) != 0 && solv->blackrules != solv->blackrules_end)
2358         {
2359           if (select == SOLVER_SOLVABLE)
2360             queue_push2(q, DISABLE_BLACK, what);
2361           else
2362             {
2363               FOR_JOB_SELECT(p, pp, select, what)
2364                 queue_push2(q, DISABLE_BLACK, p);
2365             }
2366         }
2367       if (!installed || installed->end == installed->start)
2368         return;
2369       /* now the hard part: disable some update rules */
2370
2371       /* first check if we have installed or multiversion packages in the job */
2372       FOR_JOB_SELECT(p, pp, select, what)
2373         {
2374           if (pool->solvables[p].repo == installed)
2375             return;
2376           if (solv->multiversion.size && MAPTST(&solv->multiversion, p) && !solv->keepexplicitobsoletes)
2377             return;             /* will not obsolete anything, so just return */
2378         }
2379       omap.size = 0;
2380       qstart = q->count;
2381       FOR_JOB_SELECT(p, pp, select, what)
2382         {
2383           solver_intersect_obsoleted(solv, p, q, qstart, &omap);
2384           if (q->count == qstart)
2385             break;
2386         }
2387       if (omap.size)
2388         map_free(&omap);
2389
2390       if (qstart == q->count)
2391         return;         /* nothing to prune */
2392
2393       /* convert result to (DISABLE_UPDATE, p) pairs */
2394       i = q->count;
2395       for (j = qstart; j < i; j++)
2396         queue_push(q, q->elements[j]);
2397       for (j = qstart; j < q->count; j += 2)
2398         {
2399           q->elements[j] = DISABLE_UPDATE;
2400           q->elements[j + 1] = q->elements[i++];
2401         }
2402
2403       /* now that we know which installed packages are obsoleted check each of them */
2404       if ((set & (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR)) == (SOLVER_SETEVR | SOLVER_SETARCH | SOLVER_SETVENDOR))
2405         return;         /* all is set, nothing to do */
2406
2407       for (i = j = qstart; i < q->count; i += 2)
2408         {
2409           Solvable *is = pool->solvables + q->elements[i + 1];
2410           FOR_JOB_SELECT(p, pp, select, what)
2411             {
2412               int illegal = 0;
2413               s = pool->solvables + p;
2414               if ((set & SOLVER_SETEVR) != 0)
2415                 illegal |= POLICY_ILLEGAL_DOWNGRADE;    /* ignore */
2416               if ((set & SOLVER_SETNAME) != 0)
2417                 illegal |= POLICY_ILLEGAL_NAMECHANGE;   /* ignore */
2418               if ((set & SOLVER_SETARCH) != 0)
2419                 illegal |= POLICY_ILLEGAL_ARCHCHANGE;   /* ignore */
2420               if ((set & SOLVER_SETVENDOR) != 0)
2421                 illegal |= POLICY_ILLEGAL_VENDORCHANGE; /* ignore */
2422               illegal = policy_is_illegal(solv, is, s, illegal);
2423               if (illegal && illegal == POLICY_ILLEGAL_DOWNGRADE && (set & SOLVER_SETEV) != 0)
2424                 {
2425                   /* it's ok if the EV is different */
2426                   if (pool_evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE_EVONLY) != 0)
2427                     illegal = 0;
2428                 }
2429               if (illegal)
2430                 break;
2431             }
2432           if (!p)
2433             {   
2434               /* no package conflicts with the update rule */
2435               /* thus keep the DISABLE_UPDATE */
2436               q->elements[j + 1] = q->elements[i + 1];
2437               j += 2;
2438             }
2439         }
2440       queue_truncate(q, j);
2441       return;
2442
2443     case SOLVER_ERASE:
2444       if (!installed)
2445         break;
2446       if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
2447         {
2448           FOR_REPO_SOLVABLES(installed, p, s)
2449             queue_push2(q, DISABLE_UPDATE, p);
2450         }
2451       FOR_JOB_SELECT(p, pp, select, what)
2452         if (pool->solvables[p].repo == installed)
2453           {
2454             queue_push2(q, DISABLE_UPDATE, p);
2455 #ifdef ENABLE_LINKED_PKGS
2456             if (solv->instbuddy && solv->instbuddy[p - installed->start] > 1)
2457               queue_push2(q, DISABLE_UPDATE, solv->instbuddy[p - installed->start]);
2458 #endif
2459           }
2460       return;
2461
2462     case SOLVER_LOCK:
2463       if (!installed)
2464         break;
2465       qstart = q->count;
2466       if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
2467         {
2468           FOR_REPO_SOLVABLES(installed, p, s)
2469             {
2470               for (i = qstart; i < q->count; i += 2)
2471                 if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name)
2472                   break;
2473               if (i == q->count)
2474                 queue_push2(q, DISABLE_DUP, pool->solvables[p].name);
2475             }
2476         }
2477       FOR_JOB_SELECT(p, pp, select, what)
2478         {
2479           if (pool->solvables[p].repo != installed)
2480             continue;
2481           for (i = qstart; i < q->count; i += 2)
2482             if (q->elements[i] == DISABLE_DUP && q->elements[i + 1] == pool->solvables[p].name)
2483               break;
2484           if (i == q->count)
2485             queue_push2(q, DISABLE_DUP, pool->solvables[p].name);
2486         }
2487       break;
2488
2489     default:
2490       return;
2491     }
2492 }
2493
2494 /* disable all policy rules that are in conflict with our job list */
2495 void
2496 solver_disablepolicyrules(Solver *solv)
2497 {
2498   Queue *job = &solv->job;
2499   int i, j;
2500   Queue allq;
2501   Rule *r;
2502   Id lastjob = -1;
2503   Id allqbuf[128];
2504
2505   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2506
2507   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2508     {
2509       r = solv->rules + i;
2510       if (r->d < 0)     /* disabled? */
2511         continue;
2512       j = solv->ruletojob.elements[i - solv->jobrules];
2513       if (j == lastjob)
2514         continue;
2515       lastjob = j;
2516       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2517     }
2518   if (solv->cleandepsmap.size)
2519     {
2520       solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
2521       for (i = solv->installed->start; i < solv->installed->end; i++)
2522         if (MAPTST(&solv->cleandepsmap, i - solv->installed->start))
2523           queue_push2(&allq, DISABLE_UPDATE, i);
2524     }
2525   MAPZERO(&solv->noupdate);
2526   for (i = 0; i < allq.count; i += 2)
2527     {
2528       Id type = allq.elements[i], arg = allq.elements[i + 1];
2529       switch(type)
2530         {
2531         case DISABLE_UPDATE:
2532           disableupdaterule(solv, arg);
2533           break;
2534         case DISABLE_INFARCH:
2535           disableinfarchrule(solv, arg);
2536           break;
2537         case DISABLE_DUP:
2538           disableduprule(solv, arg);
2539           break;
2540         case DISABLE_BLACK:
2541           disableblackrule(solv, arg);
2542           break;
2543         default:
2544           break;
2545         }
2546     }
2547   queue_free(&allq);
2548 }
2549
2550 /* we just disabled job #jobidx, now reenable all policy rules that were
2551  * disabled because of this job */
2552 void
2553 solver_reenablepolicyrules(Solver *solv, int jobidx)
2554 {
2555   Queue *job = &solv->job;
2556   int i, j, k, ai;
2557   Queue q, allq;
2558   Rule *r;
2559   Id lastjob = -1;
2560   Id qbuf[32], allqbuf[32];
2561
2562   queue_init_buffer(&q, qbuf, sizeof(qbuf)/sizeof(*qbuf));
2563   jobtodisablelist(solv, job->elements[jobidx - 1], job->elements[jobidx], &q);
2564   if (!q.count)
2565     {
2566       queue_free(&q);
2567       return;
2568     }
2569   /* now remove everything from q that is disabled by other jobs */
2570
2571   /* first remove cleandeps packages, they count as DISABLE_UPDATE */
2572   if (solv->cleandepsmap.size)
2573     {
2574       solver_createcleandepsmap(solv, &solv->cleandepsmap, 0);
2575       for (j = k = 0; j < q.count; j += 2)
2576         {
2577           if (q.elements[j] == DISABLE_UPDATE)
2578             {
2579               Id p = q.elements[j + 1];
2580               if (p >= solv->installed->start && p < solv->installed->end && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2581                 continue;       /* remove element from q */
2582             }
2583           q.elements[k++] = q.elements[j];
2584           q.elements[k++] = q.elements[j + 1];
2585         }
2586       q.count = k;
2587       if (!q.count)
2588         {
2589           queue_free(&q);
2590           return;
2591         }
2592     }
2593
2594   /* now go through the disable list of all other jobs */
2595   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2596   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2597     {
2598       r = solv->rules + i;
2599       if (r->d < 0)     /* disabled? */
2600         continue;
2601       j = solv->ruletojob.elements[i - solv->jobrules];
2602       if (j == lastjob)
2603         continue;
2604       lastjob = j;
2605       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2606       if (!allq.count)
2607         continue;
2608       /* remove all elements in allq from q */
2609       for (j = k = 0; j < q.count; j += 2)
2610         {
2611           Id type = q.elements[j], arg = q.elements[j + 1];
2612           for (ai = 0; ai < allq.count; ai += 2)
2613             if (allq.elements[ai] == type && allq.elements[ai + 1] == arg)
2614               break;
2615           if (ai < allq.count)
2616             continue;   /* found it in allq, remove element from q */
2617           q.elements[k++] = q.elements[j];
2618           q.elements[k++] = q.elements[j + 1];
2619         }
2620       q.count = k;
2621       if (!q.count)
2622         {
2623           queue_free(&q);
2624           queue_free(&allq);
2625           return;
2626         }
2627       queue_empty(&allq);
2628     }
2629   queue_free(&allq);
2630
2631   /* now re-enable anything that's left in q */
2632   for (j = 0; j < q.count; j += 2)
2633     {
2634       Id type = q.elements[j], arg = q.elements[j + 1];
2635       switch(type)
2636         {
2637         case DISABLE_UPDATE:
2638           reenableupdaterule(solv, arg);
2639           break;
2640         case DISABLE_INFARCH:
2641           reenableinfarchrule(solv, arg);
2642           break;
2643         case DISABLE_DUP:
2644           reenableduprule(solv, arg);
2645           break;
2646         case DISABLE_BLACK:
2647           reenableblackrule(solv, arg);
2648           break;
2649         }
2650     }
2651   queue_free(&q);
2652 }
2653
2654 /* we just removed a package from the cleandeps map, now reenable all policy rules that were
2655  * disabled because of this */
2656 void
2657 solver_reenablepolicyrules_cleandeps(Solver *solv, Id pkg)
2658 {
2659   Queue *job = &solv->job;
2660   int i, j;
2661   Queue allq;
2662   Rule *r;
2663   Id lastjob = -1;
2664   Id allqbuf[128];
2665
2666   queue_init_buffer(&allq, allqbuf, sizeof(allqbuf)/sizeof(*allqbuf));
2667   for (i = solv->jobrules; i < solv->jobrules_end; i++)
2668     {
2669       r = solv->rules + i;
2670       if (r->d < 0)     /* disabled? */
2671         continue;
2672       j = solv->ruletojob.elements[i - solv->jobrules];
2673       if (j == lastjob)
2674         continue;
2675       lastjob = j;
2676       jobtodisablelist(solv, job->elements[j], job->elements[j + 1], &allq);
2677     }
2678   for (i = 0; i < allq.count; i += 2)
2679     if (allq.elements[i] == DISABLE_UPDATE && allq.elements[i + 1] == pkg)
2680       break;
2681   if (i == allq.count)
2682     reenableupdaterule(solv, pkg);
2683   queue_free(&allq);
2684 }
2685
2686
2687 /***********************************************************************
2688  ***
2689  ***  Rule info part, tell the user what the rule is about.
2690  ***
2691  ***/
2692
2693 static void
2694 addpkgruleinfo(Solver *solv, Id p, Id p2, Id d, int type, Id dep)
2695 {
2696   Pool *pool = solv->pool;
2697   Rule *r;
2698
2699   if (d)
2700     {
2701       assert(!p2 && d > 0);
2702       if (!pool->whatprovidesdata[d])
2703         d = 0;
2704       else if (!pool->whatprovidesdata[d + 1])
2705         {
2706           p2 = pool->whatprovidesdata[d];
2707           d = 0;
2708         }
2709     }
2710
2711   /* check if this creates the rule we're searching for */
2712   r = solv->rules + solv->ruleinfoq->elements[0];
2713   if (d)
2714     {
2715       /* three or more literals */
2716       Id od = r->d < 0 ? -r->d - 1 : r->d;
2717       if (p != r->p && !od)
2718         return;
2719       if (d != od)
2720         {
2721           Id *dp = pool->whatprovidesdata + d;
2722           Id *odp = pool->whatprovidesdata + od;
2723           while (*dp)
2724             if (*dp++ != *odp++)
2725               return;
2726           if (*odp)
2727             return;
2728         }
2729       if (p < 0 && pool->whatprovidesdata[d] < 0 && type == SOLVER_RULE_PKG_CONFLICTS)
2730         p2 = pool->whatprovidesdata[d];
2731     }
2732   else
2733     {
2734       /* one or two literals */
2735       Id op = p, op2 = p2;
2736       if (op2 && op > op2)      /* normalize */
2737         {
2738           Id o = op;
2739           op = op2;
2740           op2 = o;
2741         }
2742       if (r->p != op || r->w2 != op2 || (r->d && r->d != -1))
2743         return;
2744       if (type == SOLVER_RULE_PKG_CONFLICTS && !p2)
2745         p2 = -SYSTEMSOLVABLE;
2746       if (type == SOLVER_RULE_PKG_SAME_NAME)
2747         {
2748           p = op;       /* we normalize same name order */
2749           p2 = op2;
2750         }
2751     }
2752   /* yep, rule matches. record info */
2753   queue_push(solv->ruleinfoq, type);
2754   queue_push(solv->ruleinfoq, p < 0 ? -p : 0);
2755   queue_push(solv->ruleinfoq, p2 < 0 ? -p2 : 0);
2756   queue_push(solv->ruleinfoq, dep);
2757 }
2758
2759 static int
2760 solver_allruleinfos_cmp(const void *ap, const void *bp, void *dp)
2761 {
2762   const Id *a = ap, *b = bp;
2763   int r;
2764
2765   r = a[0] - b[0];
2766   if (r)
2767     return r;
2768   r = a[1] - b[1];
2769   if (r)
2770     return r;
2771   r = a[2] - b[2];
2772   if (r)
2773     return r;
2774   r = a[3] - b[3];
2775   if (r)
2776     return r;
2777   return 0;
2778 }
2779
2780 static void
2781 getpkgruleinfos(Solver *solv, Rule *r, Queue *rq)
2782 {
2783   Pool *pool = solv->pool;
2784   Id l, pp;
2785   if (r->p >= 0)
2786     return;
2787   queue_push(rq, r - solv->rules);      /* push the rule we're interested in */
2788   solv->ruleinfoq = rq;
2789   FOR_RULELITERALS(l, pp, r)
2790     {
2791       if (l >= 0)
2792         break;
2793       solver_addpkgrulesforsolvable(solv, pool->solvables - l, 0);
2794     }
2795 #ifdef ENABLE_LINKED_PKGS
2796   FOR_RULELITERALS(l, pp, r)
2797     {
2798       if (l < 0)
2799         {
2800           if (l == r->p)
2801             continue;
2802           break;
2803         }
2804       if (!strchr(pool_id2str(pool, pool->solvables[l].name), ':') || !has_package_link(pool, pool->solvables + l))
2805         break;
2806       add_package_link(solv, pool->solvables + l, 0, 0);
2807     }
2808 #endif
2809   solv->ruleinfoq = 0;
2810   queue_shift(rq);
2811 }
2812
2813 int
2814 solver_allruleinfos(Solver *solv, Id rid, Queue *rq)
2815 {
2816   Rule *r = solv->rules + rid;
2817   int i, j;
2818
2819   queue_empty(rq);
2820   if (rid <= 0 || rid >= solv->pkgrules_end)
2821     {
2822       Id type, from, to, dep;
2823       type = solver_ruleinfo(solv, rid, &from, &to, &dep);
2824       queue_push(rq, type);
2825       queue_push(rq, from);
2826       queue_push(rq, to);
2827       queue_push(rq, dep);
2828       return 1;
2829     }
2830   getpkgruleinfos(solv, r, rq);
2831   /* now sort & unify em */
2832   if (!rq->count)
2833     return 0;
2834   solv_sort(rq->elements, rq->count / 4, 4 * sizeof(Id), solver_allruleinfos_cmp, 0);
2835   /* throw out identical entries */
2836   for (i = j = 0; i < rq->count; i += 4)
2837     {
2838       if (j)
2839         {
2840           if (rq->elements[i] == rq->elements[j - 4] &&
2841               rq->elements[i + 1] == rq->elements[j - 3] &&
2842               rq->elements[i + 2] == rq->elements[j - 2] &&
2843               rq->elements[i + 3] == rq->elements[j - 1])
2844             continue;
2845         }
2846       rq->elements[j++] = rq->elements[i];
2847       rq->elements[j++] = rq->elements[i + 1];
2848       rq->elements[j++] = rq->elements[i + 2];
2849       rq->elements[j++] = rq->elements[i + 3];
2850     }
2851   rq->count = j;
2852   return j / 4;
2853 }
2854
2855 SolverRuleinfo
2856 solver_ruleinfo(Solver *solv, Id rid, Id *fromp, Id *top, Id *depp)
2857 {
2858   Pool *pool = solv->pool;
2859   Rule *r = solv->rules + rid;
2860   SolverRuleinfo type = SOLVER_RULE_UNKNOWN;
2861
2862   if (fromp)
2863     *fromp = 0;
2864   if (top)
2865     *top = 0;
2866   if (depp)
2867     *depp = 0;
2868   if (rid > 0 && rid < solv->pkgrules_end)
2869     {
2870       Queue rq;
2871       int i;
2872
2873       if (r->p >= 0)
2874         return SOLVER_RULE_PKG;
2875       if (fromp)
2876         *fromp = -r->p;
2877       queue_init(&rq);
2878       getpkgruleinfos(solv, r, &rq);
2879       type = SOLVER_RULE_PKG;
2880       for (i = 0; i < rq.count; i += 4)
2881         {
2882           Id qt, qo, qp, qd;
2883           qt = rq.elements[i];
2884           qp = rq.elements[i + 1];
2885           qo = rq.elements[i + 2];
2886           qd = rq.elements[i + 3];
2887           if (type == SOLVER_RULE_PKG || type > qt)
2888             {
2889               type = qt;
2890               if (fromp)
2891                 *fromp = qp;
2892               if (top)
2893                 *top = qo;
2894               if (depp)
2895                 *depp = qd;
2896             }
2897         }
2898       queue_free(&rq);
2899       return type;
2900     }
2901   if (rid >= solv->jobrules && rid < solv->jobrules_end)
2902     {
2903       Id jidx = solv->ruletojob.elements[rid - solv->jobrules];
2904       if (fromp)
2905         *fromp = jidx;
2906       if (top)
2907         *top = solv->job.elements[jidx];
2908       if (depp)
2909         *depp = solv->job.elements[jidx + 1];
2910       if ((r->d == 0 || r->d == -1) && r->w2 == 0 && r->p == -SYSTEMSOLVABLE)
2911         {
2912           Id how = solv->job.elements[jidx];
2913           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_NAME))
2914             return SOLVER_RULE_JOB_UNKNOWN_PACKAGE;
2915           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_INSTALL|SOLVER_SOLVABLE_PROVIDES))
2916             return SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP;
2917           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_NAME))
2918             return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
2919           if ((how & (SOLVER_JOBMASK|SOLVER_SELECTMASK)) == (SOLVER_ERASE|SOLVER_SOLVABLE_PROVIDES))
2920             return SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM;
2921           return SOLVER_RULE_JOB_UNSUPPORTED;
2922         }
2923       return SOLVER_RULE_JOB;
2924     }
2925   if (rid >= solv->updaterules && rid < solv->updaterules_end)
2926     {
2927       if (fromp)
2928         *fromp = solv->installed->start + (rid - solv->updaterules);
2929       return SOLVER_RULE_UPDATE;
2930     }
2931   if (rid >= solv->featurerules && rid < solv->featurerules_end)
2932     {
2933       if (fromp)
2934         *fromp = solv->installed->start + (rid - solv->featurerules);
2935       return SOLVER_RULE_FEATURE;
2936     }
2937   if (rid >= solv->duprules && rid < solv->duprules_end)
2938     {
2939       if (fromp)
2940         *fromp = -r->p;
2941       if (depp)
2942         *depp = pool->solvables[-r->p].name;
2943       return SOLVER_RULE_DISTUPGRADE;
2944     }
2945   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
2946     {
2947       if (fromp)
2948         *fromp = -r->p;
2949       if (depp)
2950         *depp = pool->solvables[-r->p].name;
2951       return SOLVER_RULE_INFARCH;
2952     }
2953   if (rid >= solv->bestrules && rid < solv->bestrules_end)
2954     {
2955       if (fromp && solv->bestrules_info[rid - solv->bestrules] > 0)
2956         *fromp = solv->bestrules_info[rid - solv->bestrules];
2957       return SOLVER_RULE_BEST;
2958     }
2959   if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
2960     {
2961       if (fromp)
2962         *fromp = -r->p;
2963       if (top)
2964         {
2965           /* first solvable is enough, we just need it for the name */
2966           if (!r->d || r->d == -1)
2967             *top = r->w2;
2968           else
2969             *top = pool->whatprovidesdata[r->d < 0 ? -r->d : r->d];
2970         }
2971       if (depp)
2972         *depp = solv->yumobsrules_info[rid - solv->yumobsrules];
2973       return SOLVER_RULE_YUMOBS;
2974     }
2975   if (rid >= solv->blackrules && rid < solv->blackrules_end)
2976     {
2977       if (fromp)
2978         *fromp = -r->p;
2979       return SOLVER_RULE_BLACK;
2980     }
2981   if (rid >= solv->choicerules && rid < solv->choicerules_end)
2982     return SOLVER_RULE_CHOICE;
2983   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
2984     return SOLVER_RULE_RECOMMENDS;
2985   if (rid >= solv->learntrules)
2986     return SOLVER_RULE_LEARNT;
2987   return SOLVER_RULE_UNKNOWN;
2988 }
2989
2990 SolverRuleinfo
2991 solver_ruleclass(Solver *solv, Id rid)
2992 {
2993   if (rid <= 0)
2994     return SOLVER_RULE_UNKNOWN;
2995   if (rid > 0 && rid < solv->pkgrules_end)
2996     return SOLVER_RULE_PKG;
2997   if (rid >= solv->jobrules && rid < solv->jobrules_end)
2998     return SOLVER_RULE_JOB;
2999   if (rid >= solv->updaterules && rid < solv->updaterules_end)
3000     return SOLVER_RULE_UPDATE;
3001   if (rid >= solv->featurerules && rid < solv->featurerules_end)
3002     return SOLVER_RULE_FEATURE;
3003   if (rid >= solv->duprules && rid < solv->duprules_end)
3004     return SOLVER_RULE_DISTUPGRADE;
3005   if (rid >= solv->infarchrules && rid < solv->infarchrules_end)
3006     return SOLVER_RULE_INFARCH;
3007   if (rid >= solv->bestrules && rid < solv->bestrules_end)
3008     return SOLVER_RULE_BEST;
3009   if (rid >= solv->yumobsrules && rid < solv->yumobsrules_end)
3010     return SOLVER_RULE_YUMOBS;
3011   if (rid >= solv->blackrules && rid < solv->blackrules_end)
3012     return SOLVER_RULE_BLACK;
3013   if (rid >= solv->choicerules && rid < solv->choicerules_end)
3014     return SOLVER_RULE_CHOICE;
3015   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
3016     return SOLVER_RULE_RECOMMENDS;
3017   if (rid >= solv->blackrules && rid < solv->blackrules_end)
3018     return SOLVER_RULE_BLACK;
3019   if (rid >= solv->learntrules && rid < solv->nrules)
3020     return SOLVER_RULE_LEARNT;
3021   return SOLVER_RULE_UNKNOWN;
3022 }
3023
3024 void
3025 solver_ruleliterals(Solver *solv, Id rid, Queue *q)
3026 {
3027   Pool *pool = solv->pool;
3028   Id p, pp;
3029   Rule *r;
3030
3031   queue_empty(q);
3032   r = solv->rules + rid;
3033   FOR_RULELITERALS(p, pp, r)
3034     if (p != -SYSTEMSOLVABLE)
3035       queue_push(q, p);
3036   if (!q->count)
3037     queue_push(q, -SYSTEMSOLVABLE);     /* hmm, better to return an empty result? */
3038 }
3039
3040 int
3041 solver_rule2jobidx(Solver *solv, Id rid)
3042 {
3043   if (rid < solv->jobrules || rid >= solv->jobrules_end)
3044     return 0;
3045   return solv->ruletojob.elements[rid - solv->jobrules] + 1;
3046 }
3047
3048 /* job rule introspection */
3049 Id
3050 solver_rule2job(Solver *solv, Id rid, Id *whatp)
3051 {
3052   int idx;
3053   if (rid < solv->jobrules || rid >= solv->jobrules_end)
3054     {
3055       if (whatp)
3056         *whatp = 0;
3057       return 0;
3058     }
3059   idx = solv->ruletojob.elements[rid - solv->jobrules];
3060   if (whatp)
3061     *whatp = solv->job.elements[idx + 1];
3062   return solv->job.elements[idx];
3063 }
3064
3065 /* update/feature rule introspection */
3066 Id
3067 solver_rule2solvable(Solver *solv, Id rid)
3068 {
3069   if (rid >= solv->updaterules && rid < solv->updaterules_end)
3070     return rid - solv->updaterules;
3071   if (rid >= solv->featurerules && rid < solv->featurerules_end)
3072     return rid - solv->featurerules;
3073   return 0;
3074 }
3075
3076 Id
3077 solver_rule2pkgrule(Solver *solv, Id rid)
3078 {
3079   if (rid >= solv->choicerules && rid < solv->choicerules_end)
3080     return solv->choicerules_info[rid - solv->choicerules];
3081   if (rid >= solv->recommendsrules && rid < solv->recommendsrules_end)
3082     return solv->recommendsrules_info[rid - solv->recommendsrules];
3083   return 0;
3084 }
3085
3086 static void
3087 solver_rule2rules_rec(Solver *solv, Id rid, Queue *q, Map *seen)
3088 {
3089   int i;
3090   Id rid2;
3091
3092   if (seen)
3093     MAPSET(seen, rid);
3094   for (i = solv->learnt_why.elements[rid - solv->learntrules]; (rid2 = solv->learnt_pool.elements[i]) != 0; i++)
3095     {
3096       if (seen)
3097         {
3098           if (MAPTST(seen, rid2))
3099             continue;
3100           if (rid2 >= solv->learntrules)
3101             solver_rule2rules_rec(solv, rid2, q, seen);
3102           continue;
3103         }
3104       queue_push(q, rid2);
3105     }
3106 }
3107
3108 /* learnt rule introspection */
3109 void
3110 solver_rule2rules(Solver *solv, Id rid, Queue *q, int recursive)
3111 {
3112   queue_empty(q);
3113   if (rid < solv->learntrules || rid >= solv->nrules)
3114     return;
3115   if (recursive)
3116     {
3117       Map seen;
3118       map_init(&seen, solv->nrules);
3119       solver_rule2rules_rec(solv, rid, q, &seen);
3120       map_free(&seen);
3121     }
3122   else
3123     solver_rule2rules_rec(solv, rid, q, 0);
3124 }
3125
3126
3127 /* check if the newest versions of pi still provides the dependency we're looking for */
3128 static int
3129 solver_choicerulecheck(Solver *solv, Id pi, Rule *r, Map *m, Queue *q)
3130 {
3131   Pool *pool = solv->pool;
3132   Rule *ur;
3133   Id p, pp;
3134   int i;
3135
3136   if (!q->count || q->elements[0] != pi)
3137     {
3138       if (q->count)
3139         queue_empty(q);
3140       ur = solv->rules + solv->updaterules + (pi - pool->installed->start);
3141       if (!ur->p)
3142         ur = solv->rules + solv->featurerules + (pi - pool->installed->start);
3143       if (!ur->p)
3144         return 0;
3145       queue_push2(q, pi, 0);
3146       FOR_RULELITERALS(p, pp, ur)
3147         if (p > 0)
3148           queue_push(q, p);
3149     }
3150   if (q->count == 2)
3151     return 1;
3152   if (q->count == 3)
3153     {
3154       p = q->elements[2];
3155       return MAPTST(m, p) ? 0 : 1;
3156     }
3157   if (!q->elements[1])
3158     {
3159       for (i = 2; i < q->count; i++)
3160         if (!MAPTST(m, q->elements[i]))
3161           break;
3162       if (i == q->count)
3163         return 0;       /* all provide it, no need to filter */
3164       /* some don't provide it, have to filter */
3165       queue_deleten(q, 0, 2);
3166       policy_filter_unwanted(solv, q, POLICY_MODE_CHOOSE);
3167       queue_unshift(q, 1);      /* filter mark */
3168       queue_unshift(q, pi);
3169     }
3170   for (i = 2; i < q->count; i++)
3171     if (MAPTST(m, q->elements[i]))
3172       return 0;         /* at least one provides it */
3173   return 1;     /* none of the new packages provided it */
3174 }
3175
3176 static inline void
3177 queue_removeelement(Queue *q, Id el)
3178 {
3179   int i, j;
3180   for (i = 0; i < q->count; i++)
3181     if (q->elements[i] == el)
3182       break;
3183   if (i < q->count)
3184     {
3185       for (j = i++; i < q->count; i++)
3186         if (q->elements[i] != el)
3187           q->elements[j++] = q->elements[i];
3188       queue_truncate(q, j);
3189     }
3190 }
3191
3192 void
3193 solver_addchoicerules(Solver *solv)
3194 {
3195   Pool *pool = solv->pool;
3196   Map m, mneg;
3197   Rule *r;
3198   Queue q, qi, qcheck, infoq;
3199   int i, j, rid, havechoice;
3200   Id p, d, pp;
3201   Id p2, pp2;
3202   Solvable *s, *s2;
3203   Id lastaddedp, lastaddedd;
3204   int lastaddedcnt;
3205   unsigned int now;
3206
3207   solv->choicerules = solv->nrules;
3208   if (!pool->installed)
3209     {
3210       solv->choicerules_end = solv->nrules;
3211       return;
3212     }
3213   now = solv_timems(0);
3214   solv->choicerules_info = solv_calloc(solv->pkgrules_end, sizeof(Id));
3215   queue_init(&q);
3216   queue_init(&qi);
3217   queue_init(&qcheck);
3218   queue_init(&infoq);
3219   map_init(&m, pool->nsolvables);
3220   map_init(&mneg, pool->nsolvables);
3221   /* set up negative assertion map from infarch and dup rules */
3222   for (rid = solv->infarchrules, r = solv->rules + rid; rid < solv->infarchrules_end; rid++, r++)
3223     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
3224       MAPSET(&mneg, -r->p);
3225   for (rid = solv->duprules, r = solv->rules + rid; rid < solv->duprules_end; rid++, r++)
3226     if (r->p < 0 && !r->w2 && (r->d == 0 || r->d == -1))
3227       MAPSET(&mneg, -r->p);
3228   lastaddedp = 0;
3229   lastaddedd = 0;
3230   lastaddedcnt = 0;
3231   for (rid = 1; rid < solv->pkgrules_end ; rid++)
3232     {
3233       r = solv->rules + rid;
3234       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 <= 0))
3235         continue;       /* only look at requires rules */
3236       /* solver_printrule(solv, SOLV_DEBUG_RESULT, r); */
3237       queue_empty(&q);
3238       queue_empty(&qi);
3239       havechoice = 0;
3240       FOR_RULELITERALS(p, pp, r)
3241         {
3242           if (p < 0)
3243             continue;
3244           s = pool->solvables + p;
3245           if (!s->repo)
3246             continue;
3247           if (s->repo == pool->installed)
3248             {
3249               queue_push(&q, p);
3250               continue;
3251             }
3252           /* check if this package is "blocked" by a installed package */
3253           s2 = 0;
3254           FOR_PROVIDES(p2, pp2, s->name)
3255             {
3256               s2 = pool->solvables + p2;
3257               if (s2->repo != pool->installed)
3258                 continue;
3259               if (!pool->implicitobsoleteusesprovides && s->name != s2->name)
3260                 continue;
3261               if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, s2))
3262                 continue;
3263               break;
3264             }
3265           if (p2)
3266             {
3267               /* found installed package p2 that we can update to p */
3268               if (MAPTST(&mneg, p))
3269                 continue;
3270               if (policy_is_illegal(solv, s2, s, 0))
3271                 continue;
3272 #if 0
3273               if (solver_choicerulecheck(solv, p2, r, &m))
3274                 continue;
3275               queue_push(&qi, p2);
3276 #else
3277               queue_push2(&qi, p2, p);
3278 #endif
3279               queue_push(&q, p);
3280               continue;
3281             }
3282           if (s->obsoletes)
3283             {
3284               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
3285               s2 = 0;
3286               while ((obs = *obsp++) != 0)
3287                 {
3288                   FOR_PROVIDES(p2, pp2, obs)
3289                     {
3290                       s2 = pool->solvables + p2;
3291                       if (s2->repo != pool->installed)
3292                         continue;
3293                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
3294                         continue;
3295                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, s2))
3296                         continue;
3297                       break;
3298                     }
3299                   if (p2)
3300                     break;
3301                 }
3302               if (obs)
3303                 {
3304                   /* found installed package p2 that we can update to p */
3305                   if (MAPTST(&mneg, p))
3306                     continue;
3307                   if (policy_is_illegal(solv, s2, s, 0))
3308                     continue;
3309 #if 0
3310                   if (solver_choicerulecheck(solv, p2, r, &m))
3311                     continue;
3312                   queue_push(&qi, p2);
3313 #else
3314                   queue_push2(&qi, p2, p);
3315 #endif
3316                   queue_push(&q, p);
3317                   continue;
3318                 }
3319             }
3320           /* package p is independent of the installed ones */
3321           havechoice = 1;
3322         }
3323       if (!havechoice || !q.count || !qi.count)
3324         continue;       /* no choice */
3325
3326       FOR_RULELITERALS(p, pp, r)
3327         if (p > 0)
3328           MAPSET(&m, p);
3329
3330       /* do extra checking */
3331       for (i = j = 0; i < qi.count; i += 2)
3332         {
3333           p2 = qi.elements[i];
3334           if (!p2)
3335             continue;
3336           if (solver_choicerulecheck(solv, p2, r, &m, &qcheck))
3337             {
3338               /* oops, remove element p from q */
3339               queue_removeelement(&q, qi.elements[i + 1]);
3340               continue;
3341             }
3342           qi.elements[j++] = p2;
3343         }
3344       queue_truncate(&qi, j);
3345
3346       if (!q.count || !qi.count)
3347         {
3348           FOR_RULELITERALS(p, pp, r)
3349             if (p > 0)
3350               MAPCLR(&m, p);
3351           continue;
3352         }
3353
3354
3355       /* now check the update rules of the installed package.
3356        * if all packages of the update rules are contained in
3357        * the dependency rules, there's no need to set up the choice rule */
3358       for (i = 0; i < qi.count; i++)
3359         {
3360           Rule *ur;
3361           if (!qi.elements[i])
3362             continue;
3363           ur = solv->rules + solv->updaterules + (qi.elements[i] - pool->installed->start);
3364           if (!ur->p)
3365             ur = solv->rules + solv->featurerules + (qi.elements[i] - pool->installed->start);
3366           if (!ur->p)
3367             continue;
3368           FOR_RULELITERALS(p, pp, ur)
3369             if (!MAPTST(&m, p))
3370               break;
3371           if (p)
3372             break;
3373           for (j = i + 1; j < qi.count; j++)
3374             if (qi.elements[i] == qi.elements[j])
3375               qi.elements[j] = 0;
3376         }
3377       /* empty map again */
3378       FOR_RULELITERALS(p, pp, r)
3379         if (p > 0)
3380           MAPCLR(&m, p);
3381       if (i == qi.count)
3382         {
3383 #if 0
3384           printf("skipping choice ");
3385           solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
3386 #endif
3387           continue;
3388         }
3389
3390       /* don't add identical rules */
3391       if (lastaddedp == r->p && lastaddedcnt == q.count)
3392         {
3393           for (i = 0; i < q.count; i++)
3394             if (q.elements[i] != pool->whatprovidesdata[lastaddedd + i])
3395               break;
3396           if (i == q.count)
3397             continue;   /* already added that one */
3398         }
3399       d = q.count ? pool_queuetowhatprovides(pool, &q) : 0;
3400
3401       lastaddedp = r->p;
3402       lastaddedd = d;
3403       lastaddedcnt = q.count;
3404
3405       solver_addrule(solv, r->p, 0, d);
3406       queue_push(&solv->weakruleq, solv->nrules - 1);
3407       queue_push(&infoq, rid);
3408 #if 0
3409       printf("OLD ");
3410       solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + rid);
3411       printf("WEAK CHOICE ");
3412       solver_printrule(solv, SOLV_DEBUG_RESULT, solv->rules + solv->nrules - 1);
3413 #endif
3414     }
3415   if (infoq.count)
3416     solv->choicerules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
3417   queue_free(&q);
3418   queue_free(&qi);
3419   queue_free(&qcheck);
3420   queue_free(&infoq);
3421   map_free(&m);
3422   map_free(&mneg);
3423   solv->choicerules_end = solv->nrules;
3424   POOL_DEBUG(SOLV_DEBUG_STATS, "choice rule creation took %d ms\n", solv_timems(now));
3425 }
3426
3427 /* called when a choice rule needs to be disabled by analyze_unsolvable.
3428  * We also have to disable all other choice rules so that the best packages
3429  * get picked */
3430 void
3431 solver_disablechoicerules(Solver *solv, Rule *r)
3432 {
3433   Id rid, p, pp;
3434   Pool *pool = solv->pool;
3435   Map m;
3436   Rule *or;
3437
3438   solver_disablerule(solv, r);
3439   or = solv->rules + solv->choicerules_info[(r - solv->rules) - solv->choicerules];
3440   map_init(&m, pool->nsolvables);
3441   FOR_RULELITERALS(p, pp, or)
3442     if (p > 0)
3443       MAPSET(&m, p);
3444   FOR_RULELITERALS(p, pp, r)
3445     if (p > 0)
3446       MAPCLR(&m, p);
3447   for (rid = solv->choicerules; rid < solv->choicerules_end; rid++)
3448     {
3449       r = solv->rules + rid;
3450       if (r->d < 0)
3451         continue;
3452       or = solv->rules + solv->choicerules_info[rid - solv->choicerules];
3453       FOR_RULELITERALS(p, pp, or)
3454         if (p > 0 && MAPTST(&m, p))
3455           break;
3456       if (p)
3457         solver_disablerule(solv, r);
3458     }
3459 }
3460
3461 static void
3462 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
3463 {
3464   int i, j;
3465   Id p, *cp2;
3466   for (i = j = 0; i < q->count; i++)
3467     {
3468       p = q->elements[i];
3469       for (cp2 = cp; *cp2; cp2++)
3470         if (*cp2 == p)
3471           {
3472             q->elements[j++] = p;
3473             break;
3474           }
3475     }
3476   queue_truncate(q, j);
3477 }
3478
3479 static void
3480 prune_to_dup_packages(Solver *solv, Id p, Queue *q)
3481 {
3482   int i, j;
3483   for (i = j = 0; i < q->count; i++)
3484     {
3485       Id p = q->elements[i];
3486       if (MAPTST(&solv->dupmap, p))
3487         q->elements[j++] = p;
3488     }
3489   queue_truncate(q, j);
3490 }
3491
3492 static void
3493 prune_best_update(Solver *solv, Id p, Queue *q)
3494 {
3495   if (solv->update_targets && solv->update_targets->elements[p - solv->installed->start])
3496     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[p - solv->installed->start], q);
3497   if (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))
3498     prune_to_dup_packages(solv, p, q);
3499   /* select best packages, just look at prio and version */
3500   policy_filter_unwanted(solv, q, POLICY_MODE_RECOMMEND);
3501 }
3502
3503 static void
3504 prune_disabled(Pool *pool, Queue *q)
3505 {
3506   int i, j;
3507   for (i = j = 0; i < q->count; i++)
3508     {
3509       Id p = q->elements[i];
3510       Solvable *s = pool->solvables + p;
3511       if (s->repo && s->repo != pool->installed && !MAPTST(pool->considered, p))
3512         continue;
3513       q->elements[j++] = p;
3514     }
3515   queue_truncate(q, j);
3516 }
3517
3518 void
3519 solver_addbestrules(Solver *solv, int havebestinstalljobs, int haslockjob)
3520 {
3521   Pool *pool = solv->pool;
3522   Id p;
3523   Solvable *s;
3524   Repo *installed = solv->installed;
3525   Queue q, q2;
3526   Rule *r;
3527   Queue infoq;
3528   int i, oldcnt;
3529   Map *lockedmap = 0;
3530
3531   solv->bestrules = solv->nrules;
3532   queue_init(&q);
3533   queue_init(&q2);
3534   queue_init(&infoq);
3535
3536   if (haslockjob)
3537     {
3538       int i;
3539       lockedmap = solv_calloc(1, sizeof(Map));
3540       map_init(lockedmap, pool->nsolvables);
3541       for (i = 0, r = solv->rules + solv->jobrules; i < solv->ruletojob.count; i++, r++)
3542         {
3543           if (r->w2 || (solv->job.elements[solv->ruletojob.elements[i]] & SOLVER_JOBMASK) != SOLVER_LOCK)
3544             continue;
3545           p = r->p > 0 ? r->p : -r->p;
3546           MAPSET(lockedmap, p);
3547         }
3548     }
3549   if (havebestinstalljobs)
3550     {
3551       for (i = 0; i < solv->job.count; i += 2)
3552         {
3553           Id how = solv->job.elements[i];
3554           if ((how & (SOLVER_JOBMASK | SOLVER_FORCEBEST)) == (SOLVER_INSTALL | SOLVER_FORCEBEST))
3555             {
3556               int j, k;
3557               Id p2, pp2;
3558               for (j = 0; j < solv->ruletojob.count; j++)
3559                 {
3560                   if (solv->ruletojob.elements[j] != i)
3561                     continue;
3562                   r = solv->rules + solv->jobrules + j;
3563                   queue_empty(&q);
3564                   queue_empty(&q2);
3565                   FOR_RULELITERALS(p2, pp2, r)
3566                     {
3567                       if (p2 > 0)
3568                         queue_push(&q, p2);
3569                       else if (p2 < 0)
3570                         queue_push(&q2, p2);
3571                     }
3572                   if (pool->considered && pool->whatprovideswithdisabled)
3573                     prune_disabled(pool, &q);
3574                   if (!q.count)
3575                     continue;   /* orphaned */
3576                   /* select best packages, just look at prio and version */
3577                   oldcnt = q.count;
3578                   policy_filter_unwanted(solv, &q, POLICY_MODE_RECOMMEND);
3579                   if (q.count == oldcnt)
3580                     continue;   /* nothing filtered */
3581                   if (lockedmap)
3582                     {
3583                       queue_insertn(&q, 0, q2.count, q2.elements);
3584                       queue_empty(&q2);
3585                       FOR_RULELITERALS(p2, pp2, r)
3586                         {
3587                           if (p2 <= 0)
3588                             continue;
3589                           if (installed && pool->solvables[p2].repo == installed)
3590                             {
3591                               if (MAPTST(lockedmap, p2))
3592                                 queue_pushunique(&q, p2);               /* we always want that package */
3593                             }
3594                           else if (MAPTST(lockedmap, p2))
3595                             continue;
3596                           queue_push(&q2, p2);
3597                         }
3598                       if (pool->considered && pool->whatprovideswithdisabled)
3599                         prune_disabled(pool, &q2);
3600                       policy_filter_unwanted(solv, &q2, POLICY_MODE_RECOMMEND);
3601                       for (k = 0; k < q2.count; k++)
3602                         queue_pushunique(&q, q2.elements[k]);
3603                       queue_empty(&q2);
3604                     }
3605                   if (q2.count)
3606                     queue_insertn(&q, 0, q2.count, q2.elements);
3607                   p2 = queue_shift(&q);
3608                   if (q.count < 2)
3609                     solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
3610                   else
3611                     solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
3612                   if ((how & SOLVER_WEAK) != 0)
3613                     queue_push(&solv->weakruleq, solv->nrules - 1);
3614                   queue_push(&infoq, -(solv->jobrules + j));
3615                 }
3616             }
3617         }
3618     }
3619   solv->bestrules_up = solv->nrules;
3620
3621   if (installed && (solv->bestupdatemap_all || solv->bestupdatemap.size))
3622     {
3623       Map m;
3624
3625       if (solv->allowuninstall || solv->allowuninstall_all || solv->allowuninstallmap.size)
3626         map_init(&m, pool->nsolvables);
3627       else
3628         map_init(&m, 0);
3629       FOR_REPO_SOLVABLES(installed, p, s)
3630         {
3631           Id d, p2, pp2;
3632           if (!solv->updatemap_all && (!solv->updatemap.size || !MAPTST(&solv->updatemap, p - installed->start)))
3633             continue;
3634           if (!solv->bestupdatemap_all && (!solv->bestupdatemap.size || !MAPTST(&solv->bestupdatemap, p - installed->start)))
3635             continue;
3636           queue_empty(&q);
3637           if (solv->bestobeypolicy)
3638             r = solv->rules + solv->updaterules + (p - installed->start);
3639           else
3640             {
3641               r = solv->rules + solv->featurerules + (p - installed->start);
3642               if (!r->p)        /* identical to update rule? */
3643                 r = solv->rules + solv->updaterules + (p - installed->start);
3644             }
3645           if (solv->specialupdaters && (d = solv->specialupdaters[p - installed->start]) != 0 && r == solv->rules + solv->updaterules + (p - installed->start))
3646             {
3647               /* need to check specialupdaters */
3648               if (r->p == p)    /* be careful with the dup case */
3649                 queue_push(&q, p);
3650               while ((p2 = pool->whatprovidesdata[d++]) != 0)
3651                 queue_push(&q, p2);
3652             }
3653           else
3654             {
3655               FOR_RULELITERALS(p2, pp2, r)
3656                 if (p2 > 0)
3657                   queue_push(&q, p2);
3658             }
3659           if (lockedmap)
3660             {
3661               queue_empty(&q2);
3662               queue_insertn(&q2, 0, q.count, q.elements);
3663             }
3664           prune_best_update(solv, p, &q);
3665           if (!q.count)
3666             continue;   /* orphaned */
3667           if (lockedmap)
3668             {
3669               int j;
3670               /* always ok to keep installed locked packages */
3671               if (MAPTST(lockedmap, p))
3672                 queue_pushunique(&q2, p);
3673               for (j = 0; j < q2.count; j++)
3674                 {
3675                   Id p2 = q2.elements[j];
3676                   if (pool->solvables[p2].repo == installed && MAPTST(lockedmap, p2))
3677                     queue_pushunique(&q, p2);
3678                 }
3679               /* filter out locked packages */
3680               for (i = j = 0; j < q2.count; j++)
3681                 {
3682                   Id p2 = q2.elements[j];
3683                   if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2))
3684                     q2.elements[i++] = p2;
3685                 }
3686               queue_truncate(&q2, i);
3687               prune_best_update(solv, p, &q2);
3688               for (j = 0; j < q2.count; j++)
3689                 queue_pushunique(&q, q2.elements[j]);
3690             }
3691           if (solv->bestobeypolicy)
3692             {
3693               /* also filter the best of the feature rule packages and add them */
3694               r = solv->rules + solv->featurerules + (p - installed->start);
3695               if (r->p)
3696                 {
3697                   int j;
3698                   queue_empty(&q2);
3699                   FOR_RULELITERALS(p2, pp2, r)
3700                     if (p2 > 0)
3701                       queue_push(&q2, p2);
3702                   prune_best_update(solv, p, &q2);
3703                   for (j = 0; j < q2.count; j++)
3704                     queue_pushunique(&q, q2.elements[j]);
3705                   if (lockedmap)
3706                     {
3707                       queue_empty(&q2);
3708                       FOR_RULELITERALS(p2, pp2, r)
3709                         if (p2 > 0)
3710                           if (pool->solvables[p2].repo == installed || !MAPTST(lockedmap, p2))
3711                             queue_push(&q2, p2);
3712                       prune_best_update(solv, p, &q2);
3713                       for (j = 0; j < q2.count; j++)
3714                         queue_pushunique(&q, q2.elements[j]);
3715                     }
3716                 }
3717             }
3718           if (solv->allowuninstall || solv->allowuninstall_all || (solv->allowuninstallmap.size && MAPTST(&solv->allowuninstallmap, p - installed->start)))
3719             {
3720               /* package is flagged both for allowuninstall and best, add negative rules */
3721               d = q.count == 1 ? q.elements[0] : -pool_queuetowhatprovides(pool, &q);
3722               for (i = 0; i < q.count; i++)
3723                 MAPSET(&m, q.elements[i]);
3724               r = solv->rules + solv->featurerules + (p - installed->start);
3725               if (!r->p)        /* identical to update rule? */
3726                 r = solv->rules + solv->updaterules + (p - installed->start);
3727               FOR_RULELITERALS(p2, pp2, r)
3728                 {
3729                   if (MAPTST(&m, p2))
3730                     continue;
3731                   if (d >= 0)
3732                     solver_addrule(solv, -p2, d, 0);
3733                   else
3734                     solver_addrule(solv, -p2, 0, -d);
3735                   queue_push(&infoq, p);
3736                 }
3737               for (i = 0; i < q.count; i++)
3738                 MAPCLR(&m, q.elements[i]);
3739               continue;
3740             }
3741           p2 = queue_shift(&q);
3742           if (q.count < 2)
3743             solver_addrule(solv, p2, q.count ? q.elements[0] : 0, 0);
3744           else
3745             solver_addrule(solv, p2, 0, pool_queuetowhatprovides(pool, &q));
3746           queue_push(&infoq, p);
3747         }
3748       map_free(&m);
3749     }
3750   if (infoq.count)
3751     solv->bestrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
3752   solv->bestrules_end = solv->nrules;
3753   queue_free(&q);
3754   queue_free(&q2);
3755   queue_free(&infoq);
3756   if (lockedmap)
3757     {
3758       map_free(lockedmap);
3759       solv_free(lockedmap);
3760     }
3761 }
3762
3763
3764
3765
3766 /* yumobs rule handling */
3767 /* note that we use pool->obsoleteusescolors || pool->implicitobsoleteusescolors
3768  * like in policy_findupdatepackages */
3769
3770 static void
3771 find_obsolete_group(Solver *solv, Id obs, Queue *q)
3772 {
3773   Pool *pool = solv->pool;
3774   Queue qn;
3775   Id p2, pp2, op, *opp, opp2;
3776   int i, j, qnc, ncnt;
3777
3778   queue_empty(q);
3779   FOR_PROVIDES(p2, pp2, obs)
3780     {
3781       Solvable *s2 = pool->solvables + p2;
3782       if (s2->repo != pool->installed)
3783         continue;
3784       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
3785         continue;
3786       /* we obsolete installed package s2 with obs. now find all other packages that have the same dep  */
3787       for (opp = solv->obsoletes_data + solv->obsoletes[p2 - solv->installed->start]; (op = *opp++) != 0;)
3788         {
3789           Solvable *os = pool->solvables + op;
3790           Id obs2, *obsp2;
3791           if (!os->obsoletes)
3792             continue;
3793           if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
3794             continue;
3795           obsp2 = os->repo->idarraydata + os->obsoletes;
3796           while ((obs2 = *obsp2++) != 0)
3797             if (obs2 == obs)
3798               break;
3799           if (obs2)
3800             queue_pushunique(q, op);
3801         }
3802       /* also search packages with the same name */
3803       FOR_PROVIDES(op, opp2, s2->name)
3804         {
3805           Solvable *os = pool->solvables + op;
3806           Id obs2, *obsp2;
3807           if (os->name != s2->name)
3808             continue;
3809           if (!os->obsoletes)
3810             continue;
3811           if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s2, os))
3812             continue;
3813           obsp2 = os->repo->idarraydata + os->obsoletes;
3814           while ((obs2 = *obsp2++) != 0)
3815             if (obs2 == obs)
3816               break;
3817           if (obs2)
3818             queue_pushunique(q, op);
3819         }
3820     }
3821   /* find names so that we can build groups */
3822   queue_init_clone(&qn, q);
3823   prune_to_best_version(solv->pool, &qn);
3824 #if 0
3825 {
3826   for (i = 0; i < qn.count; i++)
3827     printf(" + %s\n", pool_solvid2str(pool, qn.elements[i]));
3828 }
3829 #endif
3830   /* filter into name groups */
3831   qnc = qn.count;
3832   if (qnc == 1)
3833     {
3834       queue_free(&qn);
3835       queue_empty(q);
3836       return;
3837     }
3838   ncnt = 0;
3839   for (i = 0; i < qnc; i++)
3840     {
3841       Id n = pool->solvables[qn.elements[i]].name;
3842       int got = 0;
3843       for (j = 0; j < q->count; j++)
3844         {
3845           Id p = q->elements[j];
3846           if (pool->solvables[p].name == n)
3847             {
3848               queue_push(&qn, p);
3849               got = 1;
3850             }
3851         }
3852       if (got)
3853         {
3854           queue_push(&qn, 0);
3855           ncnt++;
3856         }
3857     }
3858   if (ncnt <= 1)
3859     {
3860       queue_empty(q);
3861     }
3862   else
3863     {
3864       queue_empty(q);
3865       queue_insertn(q, 0, qn.count - qnc, qn.elements + qnc);
3866     }
3867   queue_free(&qn);
3868 }
3869
3870 void
3871 solver_addyumobsrules(Solver *solv)
3872 {
3873   Pool *pool = solv->pool;
3874   Repo *installed = solv->installed;
3875   Id p, op, *opp;
3876   Solvable *s;
3877   Queue qo, qq, infoq;
3878   int i, j, k;
3879   unsigned int now;
3880
3881   solv->yumobsrules = solv->nrules;
3882   if (!installed || !solv->obsoletes)
3883     {
3884       solv->yumobsrules_end = solv->nrules;
3885       return;
3886     }
3887   now = solv_timems(0);
3888   queue_init(&qo);
3889   FOR_REPO_SOLVABLES(installed, p, s)
3890     {
3891       if (!solv->obsoletes[p - installed->start])
3892         continue;
3893 #if 0
3894 printf("checking yumobs for %s\n", pool_solvable2str(pool, s));
3895 #endif
3896       for (opp = solv->obsoletes_data + solv->obsoletes[p - installed->start]; (op = *opp++) != 0;)
3897         {
3898           Solvable *os = pool->solvables + op;
3899           Id obs, *obsp = os->repo->idarraydata + os->obsoletes;
3900           Id p2, pp2;
3901           while ((obs = *obsp++) != 0)
3902             {
3903               FOR_PROVIDES(p2, pp2, obs)
3904                 {
3905                   Solvable *s2 = pool->solvables + p2;
3906                   if (s2->repo != installed)
3907                     continue;
3908                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, pool->solvables + p2, obs))
3909                     continue;
3910                   if ((pool->obsoleteusescolors || pool->implicitobsoleteusescolors) && !pool_colormatch(pool, s, s2))
3911                     continue;
3912                   queue_pushunique(&qo, obs);
3913                   break;
3914                 }
3915             }
3916         }
3917     }
3918   if (!qo.count)
3919     {
3920       queue_free(&qo);
3921       return;
3922     }
3923   queue_init(&infoq);
3924   queue_init(&qq);
3925   for (i = 0; i < qo.count; i++)
3926     {
3927       int group, groupk, groupstart;
3928       queue_empty(&qq);
3929 #if 0
3930 printf("investigating %s\n", pool_dep2str(pool, qo.elements[i]));
3931 #endif
3932       find_obsolete_group(solv, qo.elements[i], &qq);
3933 #if 0
3934 printf("result:\n");
3935 for (j = 0; j < qq.count; j++)
3936   if (qq.elements[j] == 0)
3937     printf("---\n");
3938   else
3939     printf("%s\n", pool_solvid2str(pool, qq.elements[j]));
3940 #endif
3941
3942       if (!qq.count)
3943         continue;
3944       /* at least two goups, build rules */
3945       group = 0;
3946       for (j = 0; j < qq.count; j++)
3947         {
3948           p = qq.elements[j];
3949           if (!p)
3950             {
3951               group++;
3952               continue;
3953             }
3954           if (pool->solvables[p].repo == installed)
3955             continue;
3956           groupk = 0;
3957           groupstart = 0;
3958           for (k = 0; k < qq.count; k++)
3959             {
3960               Id pk = qq.elements[k];
3961               if (pk)
3962                 continue;
3963               if (group != groupk && k > groupstart)
3964                 {
3965                   /* add the rule */
3966                   if (k - groupstart == 1)
3967                     solver_addrule(solv, -p, qq.elements[groupstart], 0);
3968                   else
3969                     solver_addrule(solv, -p, 0, pool_ids2whatprovides(pool, qq.elements + groupstart, k - groupstart));
3970                   queue_push(&infoq, qo.elements[i]);
3971                 }
3972               groupstart = k + 1;
3973               groupk++;
3974             }
3975         }
3976     }
3977   if (infoq.count)
3978     solv->yumobsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
3979   queue_free(&infoq);
3980   queue_free(&qq);
3981   queue_free(&qo);
3982   solv->yumobsrules_end = solv->nrules;
3983   POOL_DEBUG(SOLV_DEBUG_STATS, "yumobs rule creation took %d ms\n", solv_timems(now));
3984 }
3985
3986 /* recommendsrules are a copy of some recommends package rule but
3987  * with some disfavored literals removed */
3988 void
3989 solver_addrecommendsrules(Solver *solv)
3990 {
3991   Pool *pool = solv->pool;
3992   int i, havedis, havepos;
3993   Id p, pp;
3994   Queue q, infoq;
3995
3996   solv->recommendsrules = solv->nrules;
3997   queue_init(&q);
3998   queue_init(&infoq);
3999   for (i = 0; i < solv->recommendsruleq->count; i++)
4000     {
4001       int rid = solv->recommendsruleq->elements[i];
4002       Rule *r = solv->rules + rid;
4003       queue_empty(&q);
4004       havedis = havepos = 0;
4005       FOR_RULELITERALS(p, pp, r)
4006         {
4007           if (p > 0 && solv->favormap[p] < 0)
4008             havedis = 1;
4009           else
4010             {
4011               if (p > 0)
4012                 havepos = 1;
4013               queue_push(&q, p);
4014             }
4015         }
4016       if (!havedis)
4017         continue;
4018       solver_disablerule(solv, r);
4019       if (!havepos || q.count < 2)
4020         continue;
4021       if (q.count == 2)
4022         solver_addrule(solv, q.elements[0], q.elements[1], 0);
4023       else
4024         solver_addrule(solv, q.elements[0], 0, pool_ids2whatprovides(pool, q.elements + 1, q.count - 1));
4025       queue_push(&infoq, rid);
4026     }
4027   if (infoq.count)
4028     solv->recommendsrules_info = solv_memdup2(infoq.elements, infoq.count, sizeof(Id));
4029   queue_free(&infoq);
4030   queue_free(&q);
4031   solv->recommendsrules_end = solv->nrules;
4032 }
4033
4034 void
4035 solver_breakorphans(Solver *solv)
4036 {
4037   Pool *pool = solv->pool;
4038   Repo *installed = solv->installed;
4039   int i, rid;
4040   Map m;
4041
4042   if (!installed || solv->droporphanedmap_all)
4043     return;
4044   solv->brokenorphanrules = solv_calloc(1, sizeof(Queue));
4045   queue_init(solv->brokenorphanrules);
4046   map_init(&m, installed->end - installed->start);
4047   for (i = 0; i < solv->orphaned.count; i++)
4048     {
4049       Id p = solv->orphaned.elements[i];
4050       if (pool->solvables[p].repo != installed)
4051         continue;
4052       if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - installed->start))
4053         continue;
4054       MAPSET(&m, p - installed->start);
4055     }
4056   for (rid = 1; rid < solv->pkgrules_end ; rid++)
4057     {
4058       Id p, *dp;
4059       Rule *r = solv->rules + rid;
4060       /* ignore non-deps and simple conflicts */
4061       if (r->p >= 0 || ((r->d == 0 || r->d == -1) && r->w2 < 0))
4062         continue;
4063       p = -r->p;
4064       if (p < installed->start || p >= installed->end || !MAPTST(&m, p - installed->start))
4065         {
4066           /* need to check other literals */
4067           if (r->d == 0 || r->d == -1)
4068             continue;
4069           for (dp = pool->whatprovidesdata + (r->d < 0 ? -r->d - 1 : r->d); *dp < 0; dp++)
4070             {
4071               p = -*dp;
4072               if (p >= installed->start && p < installed->end && MAPTST(&m, p - installed->start))
4073                 break;
4074             }
4075           if (*dp >= 0)
4076             continue;
4077         }
4078       /* ok, disable this rule */
4079       queue_push(solv->brokenorphanrules, rid);
4080       if (r->d >= 0)
4081         solver_disablerule(solv, r);
4082     }
4083   map_free(&m);
4084   if (!solv->brokenorphanrules->count)
4085     {
4086       queue_free(solv->brokenorphanrules);
4087       solv->brokenorphanrules = solv_free(solv->brokenorphanrules);
4088     }
4089 }
4090
4091 void
4092 solver_check_brokenorphanrules(Solver *solv, Queue *dq)
4093 {
4094   Pool *pool = solv->pool;
4095   int i;
4096   Id l, pp;
4097
4098   queue_empty(dq);
4099   if (!solv->brokenorphanrules)
4100     return;
4101   for (i = 0; i < solv->brokenorphanrules->count; i++)
4102     {
4103       int rid = solv->brokenorphanrules->elements[i];
4104       Rule *r = solv->rules + rid;
4105       FOR_RULELITERALS(l, pp, r)
4106         {
4107           if (l < 0)
4108             {
4109               if (solv->decisionmap[-l] <= 0)
4110                 break;
4111             }
4112           else
4113             {
4114               if (solv->decisionmap[l] > 0 && pool->solvables[l].repo != solv->installed)
4115                 break;
4116             }
4117         }
4118       if (l)
4119         continue;
4120       FOR_RULELITERALS(l, pp, r)
4121         if (l > 0 && solv->decisionmap[l] == 0 && pool->solvables[l].repo != solv->installed)
4122           queue_pushunique(dq, l);
4123     }
4124 }
4125