do not count problem resolution install jobs as userinstalled
[platform/upstream/libsolv.git] / src / solver.c
1 /*
2  * Copyright (c) 2007-2008, Novell Inc.
3  *
4  * This program is licensed under the BSD license, read LICENSE.BSD
5  * for further information
6  */
7
8 /*
9  * solver.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 "util.h"
25 #include "policy.h"
26 #include "poolarch.h"
27 #include "solverdebug.h"
28 #include "cplxdeps.h"
29 #include "linkedpkg.h"
30
31 #define RULES_BLOCK 63
32
33 /********************************************************************
34  *
35  * dependency check helpers
36  *
37  */
38
39 /*-------------------------------------------------------------------
40  * handle split provides
41  *
42  * a splitprovides dep looks like
43  *     namespace:splitprovides(pkg REL_WITH path)
44  * and is only true if pkg is installed and contains the specified path.
45  * we also make sure that pkg is selected for an update, otherwise the
46  * update would always be forced onto the user.
47  */
48 int
49 solver_splitprovides(Solver *solv, Id dep)
50 {
51   Pool *pool = solv->pool;
52   Id p, pp;
53   Reldep *rd;
54   Solvable *s;
55
56   if (!solv->dosplitprovides || !solv->installed || (!solv->updatemap_all && !solv->updatemap.size))
57     return 0;
58   if (!ISRELDEP(dep))
59     return 0;
60   rd = GETRELDEP(pool, dep);
61   if (rd->flags != REL_WITH)
62     return 0;
63   /*
64    * things are a bit tricky here if pool->addedprovides == 1, because most split-provides are in
65    * a non-standard location. If we simply call pool_whatprovides, we'll drag in the complete
66    * file list. Instead we rely on pool_addfileprovides ignoring the addfileprovidesfiltered flag
67    * for installed packages and check the lazywhatprovidesq (ignoring the REL_WITH part, but
68    * we filter the package name further down anyway).
69    */
70   if (pool->addedfileprovides == 1 && !ISRELDEP(rd->evr) && !pool->whatprovides[rd->evr])
71     pp = pool_searchlazywhatprovidesq(pool, rd->evr);
72   else
73     pp = pool_whatprovides(pool, dep);
74   while ((p = pool->whatprovidesdata[pp++]) != 0)
75     {
76       /* here we have packages that provide the correct name and contain the path,
77        * now do extra filtering */
78       s = pool->solvables + p;
79       if (s->repo == solv->installed && s->name == rd->name &&
80           (solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, p - solv->installed->start))))
81         return 1;
82     }
83   return 0;
84 }
85
86
87 /*-------------------------------------------------------------------
88  * solver_dep_installed
89  */
90
91 int
92 solver_dep_installed(Solver *solv, Id dep)
93 {
94 #if 0
95   Pool *pool = solv->pool;
96   Id p, pp;
97
98   if (ISRELDEP(dep))
99     {
100       Reldep *rd = GETRELDEP(pool, dep);
101       if (rd->flags == REL_AND)
102         {
103           if (!solver_dep_installed(solv, rd->name))
104             return 0;
105           return solver_dep_installed(solv, rd->evr);
106         }
107       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
108         return solver_dep_installed(solv, rd->evr);
109     }
110   FOR_PROVIDES(p, pp, dep)
111     {
112       if (p == SYSTEMSOLVABLE || (solv->installed && pool->solvables[p].repo == solv->installed))
113         return 1;
114     }
115 #endif
116   return 0;
117 }
118
119 /* mirrors solver_dep_installed, but returns 2 if a
120  * dependency listed in solv->installsuppdepq was involved */
121 static int
122 solver_check_installsuppdepq_dep(Solver *solv, Id dep)
123 {
124   Pool *pool = solv->pool;
125   Id p, pp;
126   Queue *q;
127
128   if (ISRELDEP(dep))
129     {
130       Reldep *rd = GETRELDEP(pool, dep);
131       if (rd->flags == REL_AND)
132         {
133           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
134           if (!r1)
135             return 0;
136           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
137           if (!r2)
138             return 0;
139           return r1 == 2 || r2 == 2 ? 2 : 1;
140         }
141       if (rd->flags == REL_OR)
142         {
143           int r2, r1 = solver_check_installsuppdepq_dep(solv, rd->name);
144           r2 = solver_check_installsuppdepq_dep(solv, rd->evr);
145           if (!r1 && !r2)
146             return 0;
147           return r1 == 2 || r2 == 2 ? 2 : 1;
148         }
149       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_SPLITPROVIDES)
150         return solver_splitprovides(solv, rd->evr);
151       if (rd->flags == REL_NAMESPACE && rd->name == NAMESPACE_INSTALLED)
152         return solver_dep_installed(solv, rd->evr);
153       if (rd->flags == REL_NAMESPACE && (q = solv->installsuppdepq) != 0)
154         {
155           int i;
156           for (i = 0; i < q->count; i++)
157             if (q->elements[i] == dep || q->elements[i] == rd->name)
158               return 2;
159         }
160     }
161   FOR_PROVIDES(p, pp, dep)
162     if (solv->decisionmap[p] > 0)
163       return 1;
164   return 0;
165 }
166
167 static int
168 solver_check_installsuppdepq(Solver *solv, Solvable *s)
169 {
170   Id sup, *supp;
171   supp = s->repo->idarraydata + s->supplements;
172   while ((sup = *supp++) != 0)
173     if (solver_check_installsuppdepq_dep(solv, sup) == 2)
174       return 1;
175   return 0;
176 }
177
178 static Id
179 autouninstall(Solver *solv, Id *problem)
180 {
181   Pool *pool = solv->pool;
182   int i;
183   int lastfeature = 0, lastupdate = 0;
184   Id v;
185   Id extraflags = -1;
186
187   for (i = 0; (v = problem[i]) != 0; i++)
188     {
189       if (v < 0)
190         extraflags &= solv->job.elements[-v - 1];
191       if (v >= solv->featurerules && v < solv->featurerules_end)
192         if (v > lastfeature)
193           lastfeature = v;
194       if (v >= solv->updaterules && v < solv->updaterules_end)
195         {
196           /* check if identical to feature rule */
197           Id p = solv->rules[v].p;
198           Rule *r;
199           if (p <= 0)
200             continue;
201           r = solv->rules + solv->featurerules + (p - solv->installed->start);
202           if (!r->p)
203             {
204               /* update rule == feature rule */
205               if (v > lastfeature)
206                 lastfeature = v;
207               continue;
208             }
209           if (v > lastupdate)
210             lastupdate = v;
211         }
212     }
213   if (!lastupdate && !lastfeature)
214     return 0;
215   v = lastupdate ? lastupdate : lastfeature;
216   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
217   solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
218   solver_disableproblem(solv, v);
219   if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
220     {
221       /* add the package to the updatepkgs list, this will automatically turn
222        * on cleandeps mode */
223       Id p = solv->rules[v].p;
224       if (!solv->cleandeps_updatepkgs)
225         {
226           solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
227           queue_init(solv->cleandeps_updatepkgs);
228         }
229       if (p > 0)
230         {
231           int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
232           queue_pushunique(solv->cleandeps_updatepkgs, p);
233           if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
234             solver_disablepolicyrules(solv);
235         }
236     }
237   return v;
238 }
239
240 /************************************************************************/
241
242 /*
243  * enable/disable learnt rules
244  *
245  * we have enabled or disabled some of our rules. We now reenable all
246  * of our learnt rules except the ones that were learnt from rules that
247  * are now disabled.
248  */
249 static void
250 enabledisablelearntrules(Solver *solv)
251 {
252   Pool *pool = solv->pool;
253   Rule *r;
254   Id why, *whyp;
255   int i;
256
257   POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "enabledisablelearntrules called\n");
258   for (i = solv->learntrules, r = solv->rules + i; i < solv->nrules; i++, r++)
259     {
260       whyp = solv->learnt_pool.elements + solv->learnt_why.elements[i - solv->learntrules];
261       while ((why = *whyp++) != 0)
262         {
263           assert(why > 0 && why < i);
264           if (solv->rules[why].d < 0)
265             break;
266         }
267       /* why != 0: we found a disabled rule, disable the learnt rule */
268       if (why && r->d >= 0)
269         {
270           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
271             {
272               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "disabling ");
273               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
274             }
275           solver_disablerule(solv, r);
276         }
277       else if (!why && r->d < 0)
278         {
279           IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
280             {
281               POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "re-enabling ");
282               solver_printruleclass(solv, SOLV_DEBUG_SOLUTIONS, r);
283             }
284           solver_enablerule(solv, r);
285         }
286     }
287 }
288
289
290 /*
291  * make assertion rules into decisions
292  *
293  * Go through rules and add direct assertions to the decisionqueue.
294  * If we find a conflict, disable rules and add them to problem queue.
295  */
296
297 static void
298 makeruledecisions(Solver *solv)
299 {
300   Pool *pool = solv->pool;
301   int i, ri, ii;
302   Rule *r, *rr;
303   Id v, vv;
304   int decisionstart;
305   int record_proof = 1;
306   int oldproblemcount;
307   int havedisabled = 0;
308
309   /* The system solvable is always installed first */
310   assert(solv->decisionq.count == 0);
311   queue_push(&solv->decisionq, SYSTEMSOLVABLE);
312   queue_push(&solv->decisionq_why, 0);
313   solv->decisionmap[SYSTEMSOLVABLE] = 1;        /* installed at level '1' */
314
315   decisionstart = solv->decisionq.count;
316   for (;;)
317     {
318       /* if we needed to re-run, back up decisions to decisionstart */
319       while (solv->decisionq.count > decisionstart)
320         {
321           v = solv->decisionq.elements[--solv->decisionq.count];
322           --solv->decisionq_why.count;
323           vv = v > 0 ? v : -v;
324           solv->decisionmap[vv] = 0;
325         }
326
327       /* note that the ruleassertions queue is ordered */
328       for (ii = 0; ii < solv->ruleassertions.count; ii++)
329         {
330           ri = solv->ruleassertions.elements[ii];
331           r = solv->rules + ri;
332
333           if (havedisabled && ri >= solv->learntrules)
334             {
335               /* just started with learnt rule assertions. If we have disabled
336                * some rules, adapt the learnt rule status */
337               enabledisablelearntrules(solv);
338               havedisabled = 0;
339             }
340
341           if (r->d < 0 || !r->p || r->w2)       /* disabled, dummy or no assertion */
342             continue;
343
344           /* do weak rules in phase 2 */
345           if (ri < solv->learntrules && MAPTST(&solv->weakrulemap, ri))
346             continue;
347
348           v = r->p;
349           vv = v > 0 ? v : -v;
350
351           if (!solv->decisionmap[vv])          /* if not yet decided */
352             {
353               queue_push(&solv->decisionq, v);
354               queue_push(&solv->decisionq_why, r - solv->rules);
355               solv->decisionmap[vv] = v > 0 ? 1 : -1;
356               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
357                 {
358                   Solvable *s = solv->pool->solvables + vv;
359                   if (v < 0)
360                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (assertion)\n", pool_solvable2str(solv->pool, s));
361                   else
362                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (assertion)\n", pool_solvable2str(solv->pool, s));
363                 }
364               continue;
365             }
366
367           /* check against previous decision: is there a conflict? */
368           if (v > 0 && solv->decisionmap[vv] > 0)    /* ok to install */
369             continue;
370           if (v < 0 && solv->decisionmap[vv] < 0)    /* ok to remove */
371             continue;
372
373           /*
374            * found a conflict!
375            *
376            * The rule (r) we're currently processing says something
377            * different (v = r->p) than a previous decision (decisionmap[abs(v)])
378            * on this literal
379            */
380
381           if (ri >= solv->learntrules)
382             {
383               /* conflict with a learnt rule */
384               /* can happen when packages cannot be installed for multiple reasons. */
385               /* we disable the learnt rule in this case */
386               /* (XXX: we should really call analyze_unsolvable_rule here!) */
387               solver_disablerule(solv, r);
388               continue;
389             }
390
391           /*
392            * find the decision which is the "opposite" of the rule
393            */
394           for (i = 0; i < solv->decisionq.count; i++)
395             if (solv->decisionq.elements[i] == -v)
396               break;
397           assert(i < solv->decisionq.count);         /* assert that we found it */
398           oldproblemcount = solv->problems.count;
399
400           /*
401            * conflict with system solvable ?
402            */
403           if (v == -SYSTEMSOLVABLE)
404             {
405               if (record_proof)
406                 {
407                   queue_push(&solv->problems, solv->learnt_pool.count);
408                   queue_push(&solv->learnt_pool, ri);
409                   queue_push(&solv->learnt_pool, 0);
410                 }
411               else
412                 queue_push(&solv->problems, 0);
413               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with system solvable, disabling rule #%d\n", ri);
414               if  (ri >= solv->jobrules && ri < solv->jobrules_end)
415                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
416               else
417                 v = ri;
418               queue_push(&solv->problems, v);
419               queue_push(&solv->problems, 0);
420               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
421                 solv->problems.count = oldproblemcount;
422               solver_disableproblem(solv, v);
423               havedisabled = 1;
424               break;    /* start over */
425             }
426
427           assert(solv->decisionq_why.elements[i] > 0);
428
429           /*
430            * conflict with an rpm rule ?
431            */
432           if (solv->decisionq_why.elements[i] < solv->rpmrules_end)
433             {
434               if (record_proof)
435                 {
436                   queue_push(&solv->problems, solv->learnt_pool.count);
437                   queue_push(&solv->learnt_pool, ri);
438                   queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
439                   queue_push(&solv->learnt_pool, 0);
440                 }
441               else
442                 queue_push(&solv->problems, 0);
443               assert(v > 0 || v == -SYSTEMSOLVABLE);
444               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflict with rpm rule, disabling rule #%d\n", ri);
445               if (ri >= solv->jobrules && ri < solv->jobrules_end)
446                 v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
447               else
448                 v = ri;
449               queue_push(&solv->problems, v);
450               queue_push(&solv->problems, 0);
451               if (solv->allowuninstall && v >= solv->featurerules && v < solv->updaterules_end)
452                 solv->problems.count = oldproblemcount;
453               solver_disableproblem(solv, v);
454               havedisabled = 1;
455               break;    /* start over */
456             }
457
458           /*
459            * conflict with another job or update/feature rule
460            */
461
462           /* record proof */
463           if (record_proof)
464             {
465               queue_push(&solv->problems, solv->learnt_pool.count);
466               queue_push(&solv->learnt_pool, ri);
467               queue_push(&solv->learnt_pool, solv->decisionq_why.elements[i]);
468               queue_push(&solv->learnt_pool, 0);
469             }
470           else
471             queue_push(&solv->problems, 0);
472
473           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "conflicting update/job assertions over literal %d\n", vv);
474
475           /*
476            * push all of our rules (can only be feature or job rules)
477            * asserting this literal on the problem stack
478            */
479           for (i = solv->featurerules, rr = solv->rules + i; i < solv->learntrules; i++, rr++)
480             {
481               if (rr->d < 0                          /* disabled */
482                   || rr->w2)                         /*  or no assertion */
483                 continue;
484               if (rr->p != vv                        /* not affecting the literal */
485                   && rr->p != -vv)
486                 continue;
487               if (MAPTST(&solv->weakrulemap, i))     /* weak: silently ignore */
488                 continue;
489                 
490               POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, " - disabling rule #%d\n", i);
491               solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + i);
492                 
493               v = i;
494               if (i >= solv->jobrules && i < solv->jobrules_end)
495                 v = -(solv->ruletojob.elements[i - solv->jobrules] + 1);
496               queue_push(&solv->problems, v);
497             }
498           queue_push(&solv->problems, 0);
499
500           if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
501             solv->problems.count = oldproblemcount;
502
503           for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
504             solver_disableproblem(solv, solv->problems.elements[i]);
505           havedisabled = 1;
506           break;        /* start over */
507         }
508       if (ii < solv->ruleassertions.count)
509         continue;
510
511       /*
512        * phase 2: now do the weak assertions
513        */
514       for (ii = 0; ii < solv->ruleassertions.count; ii++)
515         {
516           ri = solv->ruleassertions.elements[ii];
517           r = solv->rules + ri;
518           if (r->d < 0 || r->w2)                         /* disabled or no assertion */
519             continue;
520           if (ri >= solv->learntrules || !MAPTST(&solv->weakrulemap, ri))       /* skip non-weak */
521             continue;
522           v = r->p;
523           vv = v > 0 ? v : -v;
524
525           if (!solv->decisionmap[vv])          /* if not yet decided */
526             {
527               queue_push(&solv->decisionq, v);
528               queue_push(&solv->decisionq_why, r - solv->rules);
529               solv->decisionmap[vv] = v > 0 ? 1 : -1;
530               IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
531                 {
532                   Solvable *s = solv->pool->solvables + vv;
533                   if (v < 0)
534                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "conflicting %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
535                   else
536                     POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "installing  %s (weak assertion)\n", pool_solvable2str(solv->pool, s));
537                 }
538               continue;
539             }
540           /* check against previous decision: is there a conflict? */
541           if (v > 0 && solv->decisionmap[vv] > 0)
542             continue;
543           if (v < 0 && solv->decisionmap[vv] < 0)
544             continue;
545
546           POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "assertion conflict, but I am weak, disabling ");
547           solver_printrule(solv, SOLV_DEBUG_UNSOLVABLE, r);
548
549           if (ri >= solv->jobrules && ri < solv->jobrules_end)
550             v = -(solv->ruletojob.elements[ri - solv->jobrules] + 1);
551           else
552             v = ri;
553           solver_disableproblem(solv, v);
554           if (v < 0)
555             solver_reenablepolicyrules(solv, -v);
556           havedisabled = 1;
557           break;        /* start over */
558         }
559       if (ii == solv->ruleassertions.count)
560         break;  /* finished! */
561     }
562 }
563
564
565 /********************************************************************/
566 /* watches */
567
568
569 /*-------------------------------------------------------------------
570  * makewatches
571  *
572  * initial setup for all watches
573  */
574
575 static void
576 makewatches(Solver *solv)
577 {
578   Rule *r;
579   int i;
580   int nsolvables = solv->pool->nsolvables;
581
582   solv_free(solv->watches);
583                                        /* lower half for removals, upper half for installs */
584   solv->watches = solv_calloc(2 * nsolvables, sizeof(Id));
585 #if 1
586   /* do it reverse so rpm rules get triggered first (XXX: obsolete?) */
587   for (i = 1, r = solv->rules + solv->nrules - 1; i < solv->nrules; i++, r--)
588 #else
589   for (i = 1, r = solv->rules + 1; i < solv->nrules; i++, r++)
590 #endif
591     {
592       if (!r->w2)               /* assertions do not need watches */
593         continue;
594
595       /* see addwatches_rule(solv, r) */
596       r->n1 = solv->watches[nsolvables + r->w1];
597       solv->watches[nsolvables + r->w1] = r - solv->rules;
598
599       r->n2 = solv->watches[nsolvables + r->w2];
600       solv->watches[nsolvables + r->w2] = r - solv->rules;
601     }
602 }
603
604
605 /*-------------------------------------------------------------------
606  *
607  * add watches (for a new learned rule)
608  * sets up watches for a single rule
609  *
610  * see also makewatches() above.
611  */
612
613 static inline void
614 addwatches_rule(Solver *solv, Rule *r)
615 {
616   int nsolvables = solv->pool->nsolvables;
617
618   r->n1 = solv->watches[nsolvables + r->w1];
619   solv->watches[nsolvables + r->w1] = r - solv->rules;
620
621   r->n2 = solv->watches[nsolvables + r->w2];
622   solv->watches[nsolvables + r->w2] = r - solv->rules;
623 }
624
625
626 /********************************************************************/
627 /*
628  * rule propagation
629  */
630
631
632 /* shortcuts to check if a literal (positive or negative) assignment
633  * evaluates to 'true' or 'false'
634  */
635 #define DECISIONMAP_TRUE(p) ((p) > 0 ? (decisionmap[p] > 0) : (decisionmap[-p] < 0))
636 #define DECISIONMAP_FALSE(p) ((p) > 0 ? (decisionmap[p] < 0) : (decisionmap[-p] > 0))
637 #define DECISIONMAP_UNDEF(p) (decisionmap[(p) > 0 ? (p) : -(p)] == 0)
638
639 /*-------------------------------------------------------------------
640  *
641  * propagate
642  *
643  * make decision and propagate to all rules
644  *
645  * Evaluate each term affected by the decision (linked through watches).
646  * If we find unit rules we make new decisions based on them.
647  *
648  * return : 0 = everything is OK
649  *          rule = conflict found in this rule
650  */
651
652 static Rule *
653 propagate(Solver *solv, int level)
654 {
655   Pool *pool = solv->pool;
656   Id *rp, *next_rp;           /* rule pointer, next rule pointer in linked list */
657   Rule *r;                    /* rule */
658   Id p, pkg, other_watch;
659   Id *dp;
660   Id *decisionmap = solv->decisionmap;
661
662   Id *watches = solv->watches + pool->nsolvables;   /* place ptr in middle */
663
664   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate -----\n");
665
666   /* foreach non-propagated decision */
667   while (solv->propagate_index < solv->decisionq.count)
668     {
669         /*
670          * 'pkg' was just decided
671          * negate because our watches trigger if literal goes FALSE
672          */
673       pkg = -solv->decisionq.elements[solv->propagate_index++];
674         
675       IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
676         {
677           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagate for decision %d level %d\n", -pkg, level);
678           solver_printruleelement(solv, SOLV_DEBUG_PROPAGATE, 0, -pkg);
679         }
680
681       /* foreach rule where 'pkg' is now FALSE */
682       for (rp = watches + pkg; *rp; rp = next_rp)
683         {
684           r = solv->rules + *rp;
685           if (r->d < 0)
686             {
687               /* rule is disabled, goto next */
688               if (pkg == r->w1)
689                 next_rp = &r->n1;
690               else
691                 next_rp = &r->n2;
692               continue;
693             }
694
695           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
696             {
697               POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"  watch triggered ");
698               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
699             }
700
701             /* 'pkg' was just decided (was set to FALSE)
702              *
703              *  now find other literal watch, check clause
704              *   and advance on linked list
705              */
706           if (pkg == r->w1)
707             {
708               other_watch = r->w2;
709               next_rp = &r->n1;
710             }
711           else
712             {
713               other_watch = r->w1;
714               next_rp = &r->n2;
715             }
716
717             /*
718              * This term is already true (through the other literal)
719              * so we have nothing to do
720              */
721           if (DECISIONMAP_TRUE(other_watch))
722             continue;
723
724             /*
725              * The other literal is FALSE or UNDEF
726              *
727              */
728
729           if (r->d)
730             {
731               /* Not a binary clause, try to move our watch.
732                *
733                * Go over all literals and find one that is
734                *   not other_watch
735                *   and not FALSE
736                *
737                * (TRUE is also ok, in that case the rule is fulfilled)
738                */
739               if (r->p                                /* we have a 'p' */
740                   && r->p != other_watch              /* which is not watched */
741                   && !DECISIONMAP_FALSE(r->p))        /* and not FALSE */
742                 {
743                   p = r->p;
744                 }
745               else                                    /* go find a 'd' to make 'true' */
746                 {
747                   /* foreach p in 'd'
748                      we just iterate sequentially, doing it in another order just changes the order of decisions, not the decisions itself
749                    */
750                   for (dp = pool->whatprovidesdata + r->d; (p = *dp++) != 0;)
751                     {
752                       if (p != other_watch              /* which is not watched */
753                           && !DECISIONMAP_FALSE(p))     /* and not FALSE */
754                         break;
755                     }
756                 }
757
758               if (p)
759                 {
760                   /*
761                    * if we found some p that is UNDEF or TRUE, move
762                    * watch to it
763                    */
764                   IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
765                     {
766                       if (p > 0)
767                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> move w%d to %s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, p));
768                       else
769                         POOL_DEBUG(SOLV_DEBUG_PROPAGATE,"    -> move w%d to !%s\n", (pkg == r->w1 ? 1 : 2), pool_solvid2str(pool, -p));
770                     }
771
772                   *rp = *next_rp;
773                   next_rp = rp;
774
775                   if (pkg == r->w1)
776                     {
777                       r->w1 = p;
778                       r->n1 = watches[p];
779                     }
780                   else
781                     {
782                       r->w2 = p;
783                       r->n2 = watches[p];
784                     }
785                   watches[p] = r - solv->rules;
786                   continue;
787                 }
788               /* search failed, thus all unwatched literals are FALSE */
789                 
790             } /* not binary */
791
792           /*
793            * unit clause found, set literal other_watch to TRUE
794            */
795
796           if (DECISIONMAP_FALSE(other_watch))      /* check if literal is FALSE */
797             return r;                              /* eek, a conflict! */
798
799           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
800             {
801               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "  unit ");
802               solver_printrule(solv, SOLV_DEBUG_PROPAGATE, r);
803             }
804
805           if (other_watch > 0)
806             decisionmap[other_watch] = level;    /* install! */
807           else
808             decisionmap[-other_watch] = -level;  /* remove! */
809
810           queue_push(&solv->decisionq, other_watch);
811           queue_push(&solv->decisionq_why, r - solv->rules);
812
813           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
814             {
815               if (other_watch > 0)
816                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to install %s\n", pool_solvid2str(pool, other_watch));
817               else
818                 POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "    -> decided to conflict %s\n", pool_solvid2str(pool, -other_watch));
819             }
820
821         } /* foreach rule involving 'pkg' */
822         
823     } /* while we have non-decided decisions */
824
825   POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "----- propagate end-----\n");
826
827   return 0;     /* all is well */
828 }
829
830
831 /********************************************************************/
832 /* Analysis */
833
834 /*-------------------------------------------------------------------
835  *
836  * analyze
837  *   and learn
838  */
839
840 static int
841 analyze(Solver *solv, int level, Rule *c, int *pr, int *dr, int *whyp)
842 {
843   Pool *pool = solv->pool;
844   Queue r;
845   Id r_buf[4];
846   int rlevel = 1;
847   Map seen;             /* global? */
848   Id d, v, vv, *dp, why;
849   int l, i, idx;
850   int num = 0, l1num = 0;
851   int learnt_why = solv->learnt_pool.count;
852   Id *decisionmap = solv->decisionmap;
853
854   queue_init_buffer(&r, r_buf, sizeof(r_buf)/sizeof(*r_buf));
855
856   POOL_DEBUG(SOLV_DEBUG_ANALYZE, "ANALYZE at %d ----------------------\n", level);
857   map_init(&seen, pool->nsolvables);
858   idx = solv->decisionq.count;
859   for (;;)
860     {
861       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
862         solver_printruleclass(solv, SOLV_DEBUG_ANALYZE, c);
863       queue_push(&solv->learnt_pool, c - solv->rules);
864       d = c->d < 0 ? -c->d - 1 : c->d;
865       dp = d ? pool->whatprovidesdata + d : 0;
866       /* go through all literals of the rule */
867       for (i = -1; ; i++)
868         {
869           if (i == -1)
870             v = c->p;
871           else if (d == 0)
872             v = i ? 0 : c->w2;
873           else
874             v = *dp++;
875           if (v == 0)
876             break;
877
878           if (DECISIONMAP_TRUE(v))      /* the one true literal */
879             continue;
880           vv = v > 0 ? v : -v;
881           if (MAPTST(&seen, vv))
882             continue;
883           l = solv->decisionmap[vv];
884           if (l < 0)
885             l = -l;
886           MAPSET(&seen, vv);            /* mark that we also need to look at this literal */
887           if (l == 1)
888             l1num++;                    /* need to do this one in level1 pass */
889           else if (l == level)
890             num++;                      /* need to do this one as well */
891           else
892             {
893               queue_push(&r, v);        /* not level1 or conflict level, add to new rule */
894               if (l > rlevel)
895                 rlevel = l;
896             }
897         }
898 l1retry:
899       if (!num && !--l1num)
900         break;  /* all level 1 literals done */
901
902       /* find the next literal to investigate */
903       /* (as num + l1num > 0, we know that we'll always find one) */
904       for (;;)
905         {
906           assert(idx > 0);
907           v = solv->decisionq.elements[--idx];
908           vv = v > 0 ? v : -v;
909           if (MAPTST(&seen, vv))
910             break;
911         }
912       MAPCLR(&seen, vv);
913
914       if (num && --num == 0)
915         {
916           *pr = -v;     /* so that v doesn't get lost */
917           if (!l1num)
918             break;
919           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "got %d involved level 1 decisions\n", l1num);
920           /* clear non-l1 bits from seen map */
921           for (i = 0; i < r.count; i++)
922             {
923               v = r.elements[i];
924               MAPCLR(&seen, v > 0 ? v : -v);
925             }
926           /* only level 1 marks left in seen map */
927           l1num++;      /* as l1retry decrements it */
928           goto l1retry;
929         }
930
931       why = solv->decisionq_why.elements[idx];
932       if (why <= 0)     /* just in case, maybe for SYSTEMSOLVABLE */
933         goto l1retry;
934       c = solv->rules + why;
935     }
936   map_free(&seen);
937
938   if (r.count == 0)
939     *dr = 0;
940   else if (r.count == 1 && r.elements[0] < 0)
941     *dr = r.elements[0];
942   else
943     *dr = pool_queuetowhatprovides(pool, &r);
944   IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
945     {
946       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "learned rule for level %d (am %d)\n", rlevel, level);
947       solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, *pr);
948       for (i = 0; i < r.count; i++)
949         solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, r.elements[i]);
950     }
951   /* push end marker on learnt reasons stack */
952   queue_push(&solv->learnt_pool, 0);
953   if (whyp)
954     *whyp = learnt_why;
955   queue_free(&r);
956   solv->stats_learned++;
957   return rlevel;
958 }
959
960
961 /*-------------------------------------------------------------------
962  *
963  * solver_reset
964  *
965  * reset all solver decisions
966  * called after rules have been enabled/disabled
967  */
968
969 void
970 solver_reset(Solver *solv)
971 {
972   Pool *pool = solv->pool;
973   int i;
974   Id v;
975
976   /* rewind all decisions */
977   for (i = solv->decisionq.count - 1; i >= 0; i--)
978     {
979       v = solv->decisionq.elements[i];
980       solv->decisionmap[v > 0 ? v : -v] = 0;
981     }
982   queue_empty(&solv->decisionq_why);
983   queue_empty(&solv->decisionq);
984   solv->recommends_index = -1;
985   solv->propagate_index = 0;
986   solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
987   queue_empty(&solv->branches);
988
989   /* adapt learnt rule status to new set of enabled/disabled rules */
990   enabledisablelearntrules(solv);
991
992   /* redo all assertion rule decisions */
993   makeruledecisions(solv);
994   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "decisions so far: %d\n", solv->decisionq.count);
995 }
996
997
998 /*-------------------------------------------------------------------
999  *
1000  * analyze_unsolvable_rule
1001  *
1002  * recursion helper used by analyze_unsolvable
1003  */
1004
1005 static void
1006 analyze_unsolvable_rule(Solver *solv, Rule *r, Id *lastweakp, Map *rseen)
1007 {
1008   Pool *pool = solv->pool;
1009   int i;
1010   Id why = r - solv->rules;
1011
1012   IF_POOLDEBUG (SOLV_DEBUG_UNSOLVABLE)
1013     solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, r);
1014   if (solv->learntrules && why >= solv->learntrules)
1015     {
1016       if (MAPTST(rseen, why - solv->learntrules))
1017         return;
1018       MAPSET(rseen, why - solv->learntrules);
1019       for (i = solv->learnt_why.elements[why - solv->learntrules]; solv->learnt_pool.elements[i]; i++)
1020         if (solv->learnt_pool.elements[i] > 0)
1021           analyze_unsolvable_rule(solv, solv->rules + solv->learnt_pool.elements[i], lastweakp, rseen);
1022       return;
1023     }
1024   if (MAPTST(&solv->weakrulemap, why))
1025     if (!*lastweakp || why > *lastweakp)
1026       *lastweakp = why;
1027   /* do not add rpm rules to problem */
1028   if (why < solv->rpmrules_end)
1029     return;
1030   /* turn rule into problem */
1031   if (why >= solv->jobrules && why < solv->jobrules_end)
1032     why = -(solv->ruletojob.elements[why - solv->jobrules] + 1);
1033   /* normalize dup/infarch rules */
1034   if (why > solv->infarchrules && why < solv->infarchrules_end)
1035     {
1036       Id name = pool->solvables[-solv->rules[why].p].name;
1037       while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
1038         why--;
1039     }
1040   if (why > solv->duprules && why < solv->duprules_end)
1041     {
1042       Id name = pool->solvables[-solv->rules[why].p].name;
1043       while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
1044         why--;
1045     }
1046
1047   /* return if problem already countains our rule */
1048   if (solv->problems.count)
1049     {
1050       for (i = solv->problems.count - 1; i >= 0; i--)
1051         if (solv->problems.elements[i] == 0)    /* end of last problem reached? */
1052           break;
1053         else if (solv->problems.elements[i] == why)
1054           return;
1055     }
1056   queue_push(&solv->problems, why);
1057 }
1058
1059
1060 /*-------------------------------------------------------------------
1061  *
1062  * analyze_unsolvable
1063  *
1064  * We know that the problem is not solvable. Record all involved
1065  * rules (i.e. the "proof") into solv->learnt_pool.
1066  * Record the learnt pool index and all non-rpm rules into
1067  * solv->problems. (Our solutions to fix the problems are to
1068  * disable those rules.)
1069  *
1070  * If the proof contains at least one weak rule, we disable the
1071  * last of them.
1072  *
1073  * Otherwise we return 0 if disablerules is not set or disable
1074  * _all_ of the problem rules and return 1.
1075  *
1076  * return: 1 - disabled some rules, try again
1077  *         0 - hopeless
1078  */
1079
1080 static int
1081 analyze_unsolvable(Solver *solv, Rule *cr, int disablerules)
1082 {
1083   Pool *pool = solv->pool;
1084   Rule *r;
1085   Map seen;             /* global to speed things up? */
1086   Map rseen;
1087   Id d, v, vv, *dp, why;
1088   int l, i, idx;
1089   Id *decisionmap = solv->decisionmap;
1090   int oldproblemcount;
1091   int oldlearntpoolcount;
1092   Id lastweak;
1093   int record_proof = 1;
1094
1095   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "ANALYZE UNSOLVABLE ----------------------\n");
1096   solv->stats_unsolvable++;
1097   oldproblemcount = solv->problems.count;
1098   oldlearntpoolcount = solv->learnt_pool.count;
1099
1100   /* make room for proof index */
1101   /* must update it later, as analyze_unsolvable_rule would confuse
1102    * it with a rule index if we put the real value in already */
1103   queue_push(&solv->problems, 0);
1104
1105   r = cr;
1106   map_init(&seen, pool->nsolvables);
1107   map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1108   if (record_proof)
1109     queue_push(&solv->learnt_pool, r - solv->rules);
1110   lastweak = 0;
1111   analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1112   d = r->d < 0 ? -r->d - 1 : r->d;
1113   dp = d ? pool->whatprovidesdata + d : 0;
1114   for (i = -1; ; i++)
1115     {
1116       if (i == -1)
1117         v = r->p;
1118       else if (d == 0)
1119         v = i ? 0 : r->w2;
1120       else
1121         v = *dp++;
1122       if (v == 0)
1123         break;
1124       if (DECISIONMAP_TRUE(v))  /* the one true literal */
1125           continue;
1126       vv = v > 0 ? v : -v;
1127       l = solv->decisionmap[vv];
1128       if (l < 0)
1129         l = -l;
1130       MAPSET(&seen, vv);
1131     }
1132   idx = solv->decisionq.count;
1133   while (idx > 0)
1134     {
1135       v = solv->decisionq.elements[--idx];
1136       vv = v > 0 ? v : -v;
1137       if (!MAPTST(&seen, vv) || vv == SYSTEMSOLVABLE)
1138         continue;
1139       why = solv->decisionq_why.elements[idx];
1140       assert(why > 0);
1141       if (record_proof)
1142         queue_push(&solv->learnt_pool, why);
1143       r = solv->rules + why;
1144       analyze_unsolvable_rule(solv, r, &lastweak, &rseen);
1145       d = r->d < 0 ? -r->d - 1 : r->d;
1146       dp = d ? pool->whatprovidesdata + d : 0;
1147       for (i = -1; ; i++)
1148         {
1149           if (i == -1)
1150             v = r->p;
1151           else if (d == 0)
1152             v = i ? 0 : r->w2;
1153           else
1154             v = *dp++;
1155           if (v == 0)
1156             break;
1157           if (DECISIONMAP_TRUE(v))      /* the one true literal */
1158               continue;
1159           vv = v > 0 ? v : -v;
1160           l = solv->decisionmap[vv];
1161           if (l < 0)
1162             l = -l;
1163           MAPSET(&seen, vv);
1164         }
1165     }
1166   map_free(&seen);
1167   map_free(&rseen);
1168   queue_push(&solv->problems, 0);       /* mark end of this problem */
1169
1170   if (lastweak)
1171     {
1172       /* disable last weak rule */
1173       solv->problems.count = oldproblemcount;
1174       solv->learnt_pool.count = oldlearntpoolcount;
1175       if (lastweak >= solv->jobrules && lastweak < solv->jobrules_end)
1176         v = -(solv->ruletojob.elements[lastweak - solv->jobrules] + 1);
1177       else
1178         v = lastweak;
1179       POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "disabling ");
1180       solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + lastweak);
1181       if (lastweak >= solv->choicerules && lastweak < solv->choicerules_end)
1182         solver_disablechoicerules(solv, solv->rules + lastweak);
1183       solver_disableproblem(solv, v);
1184       if (v < 0)
1185         solver_reenablepolicyrules(solv, -v);
1186       solver_reset(solv);
1187       return 1;
1188     }
1189
1190   if (solv->allowuninstall && (v = autouninstall(solv, solv->problems.elements + oldproblemcount + 1)) != 0)
1191     {
1192       solv->problems.count = oldproblemcount;
1193       solv->learnt_pool.count = oldlearntpoolcount;
1194       solver_reset(solv);
1195       return 1;
1196     }
1197
1198   /* finish proof */
1199   if (record_proof)
1200     {
1201       queue_push(&solv->learnt_pool, 0);
1202       solv->problems.elements[oldproblemcount] = oldlearntpoolcount;
1203     }
1204
1205   /* + 2: index + trailing zero */
1206   if (disablerules && oldproblemcount + 2 < solv->problems.count)
1207     {
1208       for (i = oldproblemcount + 1; i < solv->problems.count - 1; i++)
1209         solver_disableproblem(solv, solv->problems.elements[i]);
1210       /* XXX: might want to enable all weak rules again */
1211       solver_reset(solv);
1212       return 1;
1213     }
1214   POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "UNSOLVABLE\n");
1215   return 0;
1216 }
1217
1218
1219 /********************************************************************/
1220 /* Decision revert */
1221
1222 /*-------------------------------------------------------------------
1223  *
1224  * revert
1225  * revert decisionq to a level
1226  */
1227
1228 static void
1229 revert(Solver *solv, int level)
1230 {
1231   Pool *pool = solv->pool;
1232   Id v, vv;
1233   while (solv->decisionq.count)
1234     {
1235       v = solv->decisionq.elements[solv->decisionq.count - 1];
1236       vv = v > 0 ? v : -v;
1237       if (solv->decisionmap[vv] <= level && solv->decisionmap[vv] >= -level)
1238         break;
1239       POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "reverting decision %d at %d\n", v, solv->decisionmap[vv]);
1240       solv->decisionmap[vv] = 0;
1241       solv->decisionq.count--;
1242       solv->decisionq_why.count--;
1243       solv->propagate_index = solv->decisionq.count;
1244     }
1245   while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] <= -level)
1246     {
1247       solv->branches.count--;
1248       while (solv->branches.count && solv->branches.elements[solv->branches.count - 1] >= 0)
1249         solv->branches.count--;
1250     }
1251   if (solv->recommends_index > solv->decisionq.count)
1252     solv->recommends_index = -1;        /* rebuild recommends/suggests maps */
1253   if (solv->decisionq.count < solv->decisioncnt_update)
1254     solv->decisioncnt_update = 0;
1255   if (solv->decisionq.count < solv->decisioncnt_keep)
1256     solv->decisioncnt_keep = 0;
1257   if (solv->decisionq.count < solv->decisioncnt_resolve)
1258     solv->decisioncnt_resolve = 0;
1259   if (solv->decisionq.count < solv->decisioncnt_weak)
1260     solv->decisioncnt_weak= 0;
1261   if (solv->decisionq.count < solv->decisioncnt_orphan)
1262     solv->decisioncnt_orphan = 0;
1263 }
1264
1265
1266 /*-------------------------------------------------------------------
1267  *
1268  * watch2onhighest - put watch2 on literal with highest level
1269  */
1270
1271 static inline void
1272 watch2onhighest(Solver *solv, Rule *r)
1273 {
1274   int l, wl = 0;
1275   Id d, v, *dp;
1276
1277   d = r->d < 0 ? -r->d - 1 : r->d;
1278   if (!d)
1279     return;     /* binary rule, both watches are set */
1280   dp = solv->pool->whatprovidesdata + d;
1281   while ((v = *dp++) != 0)
1282     {
1283       l = solv->decisionmap[v < 0 ? -v : v];
1284       if (l < 0)
1285         l = -l;
1286       if (l > wl)
1287         {
1288           r->w2 = dp[-1];
1289           wl = l;
1290         }
1291     }
1292 }
1293
1294
1295 /*-------------------------------------------------------------------
1296  *
1297  * setpropagatelearn
1298  *
1299  * add free decision (solvable to install) to decisionq
1300  * increase level and propagate decision
1301  * return if no conflict.
1302  *
1303  * in conflict case, analyze conflict rule, add resulting
1304  * rule to learnt rule set, make decision from learnt
1305  * rule (always unit) and re-propagate.
1306  *
1307  * returns the new solver level or 0 if unsolvable
1308  *
1309  */
1310
1311 static int
1312 setpropagatelearn(Solver *solv, int level, Id decision, int disablerules, Id ruleid)
1313 {
1314   Pool *pool = solv->pool;
1315   Rule *r;
1316   Id p = 0, d = 0;
1317   int l, why;
1318
1319   assert(ruleid >= 0);
1320   if (decision)
1321     {
1322       level++;
1323       if (decision > 0)
1324         solv->decisionmap[decision] = level;
1325       else
1326         solv->decisionmap[-decision] = -level;
1327       queue_push(&solv->decisionq, decision);
1328       queue_push(&solv->decisionq_why, -ruleid);        /* <= 0 -> free decision */
1329     }
1330   for (;;)
1331     {
1332       r = propagate(solv, level);
1333       if (!r)
1334         break;
1335       if (level == 1)
1336         return analyze_unsolvable(solv, r, disablerules);
1337       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "conflict with rule #%d\n", (int)(r - solv->rules));
1338       l = analyze(solv, level, r, &p, &d, &why);        /* learnt rule in p and d */
1339       assert(l > 0 && l < level);
1340       POOL_DEBUG(SOLV_DEBUG_ANALYZE, "reverting decisions (level %d -> %d)\n", level, l);
1341       level = l;
1342       revert(solv, level);
1343       r = solver_addrule(solv, p, d);
1344       assert(r);
1345       assert(solv->learnt_why.count == (r - solv->rules) - solv->learntrules);
1346       queue_push(&solv->learnt_why, why);
1347       if (d)
1348         {
1349           /* at least 2 literals, needs watches */
1350           watch2onhighest(solv, r);
1351           addwatches_rule(solv, r);
1352         }
1353       else
1354         {
1355           /* learnt rule is an assertion */
1356           queue_push(&solv->ruleassertions, r - solv->rules);
1357         }
1358       /* the new rule is unit by design */
1359       solv->decisionmap[p > 0 ? p : -p] = p > 0 ? level : -level;
1360       queue_push(&solv->decisionq, p);
1361       queue_push(&solv->decisionq_why, r - solv->rules);
1362       IF_POOLDEBUG (SOLV_DEBUG_ANALYZE)
1363         {
1364           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "decision: ");
1365           solver_printruleelement(solv, SOLV_DEBUG_ANALYZE, 0, p);
1366           POOL_DEBUG(SOLV_DEBUG_ANALYZE, "new rule: ");
1367           solver_printrule(solv, SOLV_DEBUG_ANALYZE, r);
1368         }
1369     }
1370   return level;
1371 }
1372
1373 static void
1374 reorder_dq_for_jobrules(Solver *solv, int level, Queue *dq)
1375 {
1376   Pool *pool = solv->pool;
1377   int i, j, haveone = 0, dqcount = dq->count;
1378   Id p;
1379   Solvable *s;
1380
1381   /* at the time we process jobrules the installed packages are not kept yet */
1382   /* reorder so that "future-supplemented" packages come first */
1383   FOR_REPO_SOLVABLES(solv->installed, p, s)
1384     {
1385       if (MAPTST(&solv->noupdate, p - solv->installed->start))
1386         continue;
1387       if (solv->decisionmap[p] == 0)
1388         {
1389           solv->decisionmap[p] = level;
1390           haveone = 1;
1391         }
1392     }
1393   if (!haveone)
1394     return;
1395   for (i = 0; i < dqcount; i++)
1396     if (!solver_is_enhancing(solv, pool->solvables + dq->elements[i]))
1397       {
1398         queue_push(dq, dq->elements[i]);
1399         dq->elements[i] = 0;
1400       }
1401   dqcount = dq->count;
1402   for (i = 0; i < dqcount; i++)
1403     if (dq->elements[i] && !solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1404       {
1405         queue_push(dq, dq->elements[i]);
1406         dq->elements[i] = 0;
1407       }
1408   for (i = j = 0; i < dq->count; i++)
1409     if (dq->elements[i])
1410       dq->elements[j++] = dq->elements[i];
1411   queue_truncate(dq, j);
1412   FOR_REPO_SOLVABLES(solv->installed, p, s)
1413     if (solv->decisionmap[p] == level)
1414       solv->decisionmap[p] = 0;
1415 }
1416
1417 /*-------------------------------------------------------------------
1418  *
1419  * select and install
1420  *
1421  * install best package from the queue. We add an extra package, inst, if
1422  * provided. See comment in weak install section.
1423  *
1424  * returns the new solver level or 0 if unsolvable
1425  *
1426  */
1427
1428 static int
1429 selectandinstall(Solver *solv, int level, Queue *dq, int disablerules, Id ruleid)
1430 {
1431   Pool *pool = solv->pool;
1432   Id p;
1433   int i;
1434
1435   if (dq->count > 1)
1436     policy_filter_unwanted(solv, dq, POLICY_MODE_CHOOSE);
1437   if (dq->count > 1)
1438     {
1439       /* XXX: didn't we already do that? */
1440       /* XXX: shouldn't we prefer installed packages? */
1441       /* XXX: move to policy.c? */
1442       /* choose the supplemented one */
1443       for (i = 0; i < dq->count; i++)
1444         if (solver_is_supplementing(solv, pool->solvables + dq->elements[i]))
1445           {
1446             dq->elements[0] = dq->elements[i];
1447             dq->count = 1;
1448             break;
1449           }
1450     }
1451   if (dq->count > 1 && ruleid >= solv->jobrules && ruleid < solv->jobrules_end && solv->installed)
1452     reorder_dq_for_jobrules(solv, level, dq);
1453   if (dq->count > 1)
1454     {
1455       /* multiple candidates, open a branch */
1456       for (i = 1; i < dq->count; i++)
1457         queue_push(&solv->branches, dq->elements[i]);
1458       queue_push(&solv->branches, -level);
1459     }
1460   p = dq->elements[0];
1461
1462   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing %s\n", pool_solvid2str(pool, p));
1463
1464   return setpropagatelearn(solv, level, p, disablerules, ruleid);
1465 }
1466
1467
1468 /********************************************************************/
1469 /* Main solver interface */
1470
1471
1472 /*-------------------------------------------------------------------
1473  *
1474  * solver_create
1475  * create solver structure
1476  *
1477  * pool: all available solvables
1478  * installed: installed Solvables
1479  *
1480  *
1481  * Upon solving, rules are created to flag the Solvables
1482  * of the 'installed' Repo as installed.
1483  */
1484
1485 Solver *
1486 solver_create(Pool *pool)
1487 {
1488   Solver *solv;
1489   solv = (Solver *)solv_calloc(1, sizeof(Solver));
1490   solv->pool = pool;
1491   solv->installed = pool->installed;
1492
1493   solv->allownamechange = 1;
1494
1495   solv->dup_allowdowngrade = 1;
1496   solv->dup_allownamechange = 1;
1497   solv->dup_allowarchchange = 1;
1498   solv->dup_allowvendorchange = 1;
1499
1500   solv->keepexplicitobsoletes = pool->noobsoletesmultiversion ? 0 : 1;
1501
1502   queue_init(&solv->ruletojob);
1503   queue_init(&solv->decisionq);
1504   queue_init(&solv->decisionq_why);
1505   queue_init(&solv->problems);
1506   queue_init(&solv->orphaned);
1507   queue_init(&solv->learnt_why);
1508   queue_init(&solv->learnt_pool);
1509   queue_init(&solv->branches);
1510   queue_init(&solv->weakruleq);
1511   queue_init(&solv->ruleassertions);
1512   queue_init(&solv->addedmap_deduceq);
1513
1514   queue_push(&solv->learnt_pool, 0);    /* so that 0 does not describe a proof */
1515
1516   map_init(&solv->recommendsmap, pool->nsolvables);
1517   map_init(&solv->suggestsmap, pool->nsolvables);
1518   map_init(&solv->noupdate, solv->installed ? solv->installed->end - solv->installed->start : 0);
1519   solv->recommends_index = 0;
1520
1521   solv->decisionmap = (Id *)solv_calloc(pool->nsolvables, sizeof(Id));
1522   solv->nrules = 1;
1523   solv->rules = solv_extend_resize(solv->rules, solv->nrules, sizeof(Rule), RULES_BLOCK);
1524   memset(solv->rules, 0, sizeof(Rule));
1525
1526   return solv;
1527 }
1528
1529
1530 /*-------------------------------------------------------------------
1531  *
1532  * solver_free
1533  */
1534
1535 static inline void
1536 queuep_free(Queue **qp)
1537 {
1538   if (!*qp)
1539     return;
1540   queue_free(*qp);
1541   *qp = solv_free(*qp);
1542 }
1543
1544 static inline void
1545 map_zerosize(Map *m)
1546 {
1547   if (m->size)
1548     {
1549       map_free(m);
1550       map_init(m, 0);
1551     }
1552 }
1553
1554 void
1555 solver_free(Solver *solv)
1556 {
1557   queue_free(&solv->job);
1558   queue_free(&solv->ruletojob);
1559   queue_free(&solv->decisionq);
1560   queue_free(&solv->decisionq_why);
1561   queue_free(&solv->learnt_why);
1562   queue_free(&solv->learnt_pool);
1563   queue_free(&solv->problems);
1564   queue_free(&solv->solutions);
1565   queue_free(&solv->orphaned);
1566   queue_free(&solv->branches);
1567   queue_free(&solv->weakruleq);
1568   queue_free(&solv->ruleassertions);
1569   queue_free(&solv->addedmap_deduceq);
1570   queuep_free(&solv->cleandeps_updatepkgs);
1571   queuep_free(&solv->cleandeps_mistakes);
1572   queuep_free(&solv->update_targets);
1573   queuep_free(&solv->installsuppdepq);
1574   queuep_free(&solv->recommendscplxq);
1575   queuep_free(&solv->suggestscplxq);
1576
1577   map_free(&solv->recommendsmap);
1578   map_free(&solv->suggestsmap);
1579   map_free(&solv->noupdate);
1580   map_free(&solv->weakrulemap);
1581   map_free(&solv->multiversion);
1582
1583   map_free(&solv->updatemap);
1584   map_free(&solv->bestupdatemap);
1585   map_free(&solv->fixmap);
1586   map_free(&solv->dupmap);
1587   map_free(&solv->dupinvolvedmap);
1588   map_free(&solv->droporphanedmap);
1589   map_free(&solv->cleandepsmap);
1590
1591   solv_free(solv->decisionmap);
1592   solv_free(solv->rules);
1593   solv_free(solv->watches);
1594   solv_free(solv->obsoletes);
1595   solv_free(solv->obsoletes_data);
1596   solv_free(solv->specialupdaters);
1597   solv_free(solv->choicerules_ref);
1598   solv_free(solv->bestrules_pkg);
1599   solv_free(solv->instbuddy);
1600   solv_free(solv);
1601 }
1602
1603 int
1604 solver_get_flag(Solver *solv, int flag)
1605 {
1606   switch (flag)
1607   {
1608   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1609     return solv->allowdowngrade;
1610   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1611     return solv->allownamechange;
1612   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1613     return solv->allowarchchange;
1614   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1615     return solv->allowvendorchange;
1616   case SOLVER_FLAG_ALLOW_UNINSTALL:
1617     return solv->allowuninstall;
1618   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1619     return solv->noupdateprovide;
1620   case SOLVER_FLAG_SPLITPROVIDES:
1621     return solv->dosplitprovides;
1622   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1623     return solv->dontinstallrecommended;
1624   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1625     return solv->addalreadyrecommended;
1626   case SOLVER_FLAG_NO_INFARCHCHECK:
1627     return solv->noinfarchcheck;
1628   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1629     return solv->keepexplicitobsoletes;
1630   case SOLVER_FLAG_BEST_OBEY_POLICY:
1631     return solv->bestobeypolicy;
1632   case SOLVER_FLAG_NO_AUTOTARGET:
1633     return solv->noautotarget;
1634   case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
1635     return solv->dup_allowdowngrade;
1636   case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
1637     return solv->dup_allownamechange;
1638   case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
1639     return solv->dup_allowarchchange;
1640   case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
1641     return solv->dup_allowvendorchange;
1642   default:
1643     break;
1644   }
1645   return -1;
1646 }
1647
1648 int
1649 solver_set_flag(Solver *solv, int flag, int value)
1650 {
1651   int old = solver_get_flag(solv, flag);
1652   switch (flag)
1653   {
1654   case SOLVER_FLAG_ALLOW_DOWNGRADE:
1655     solv->allowdowngrade = value;
1656     break;
1657   case SOLVER_FLAG_ALLOW_NAMECHANGE:
1658     solv->allownamechange = value;
1659     break;
1660   case SOLVER_FLAG_ALLOW_ARCHCHANGE:
1661     solv->allowarchchange = value;
1662     break;
1663   case SOLVER_FLAG_ALLOW_VENDORCHANGE:
1664     solv->allowvendorchange = value;
1665     break;
1666   case SOLVER_FLAG_ALLOW_UNINSTALL:
1667     solv->allowuninstall = value;
1668     break;
1669   case SOLVER_FLAG_NO_UPDATEPROVIDE:
1670     solv->noupdateprovide = value;
1671     break;
1672   case SOLVER_FLAG_SPLITPROVIDES:
1673     solv->dosplitprovides = value;
1674     break;
1675   case SOLVER_FLAG_IGNORE_RECOMMENDED:
1676     solv->dontinstallrecommended = value;
1677     break;
1678   case SOLVER_FLAG_ADD_ALREADY_RECOMMENDED:
1679     solv->addalreadyrecommended = value;
1680     break;
1681   case SOLVER_FLAG_NO_INFARCHCHECK:
1682     solv->noinfarchcheck = value;
1683     break;
1684   case SOLVER_FLAG_KEEP_EXPLICIT_OBSOLETES:
1685     solv->keepexplicitobsoletes = value;
1686     break;
1687   case SOLVER_FLAG_BEST_OBEY_POLICY:
1688     solv->bestobeypolicy = value;
1689     break;
1690   case SOLVER_FLAG_NO_AUTOTARGET:
1691     solv->noautotarget = value;
1692     break;
1693   case SOLVER_FLAG_DUP_ALLOW_DOWNGRADE:
1694     solv->dup_allowdowngrade = value;
1695     break;
1696   case SOLVER_FLAG_DUP_ALLOW_NAMECHANGE:
1697     solv->dup_allownamechange = value;
1698     break;
1699   case SOLVER_FLAG_DUP_ALLOW_ARCHCHANGE:
1700     solv->dup_allowarchchange = value;
1701     break;
1702   case SOLVER_FLAG_DUP_ALLOW_VENDORCHANGE:
1703     solv->dup_allowvendorchange = value;
1704     break;
1705   default:
1706     break;
1707   }
1708   return old;
1709 }
1710
1711 int
1712 cleandeps_check_mistakes(Solver *solv, int level)
1713 {
1714   Pool *pool = solv->pool;
1715   Rule *r;
1716   Id p, pp;
1717   int i;
1718   int mademistake = 0;
1719
1720   if (!solv->cleandepsmap.size)
1721     return 0;
1722   /* check for mistakes */
1723   for (i = solv->installed->start; i < solv->installed->end; i++)
1724     {
1725       if (!MAPTST(&solv->cleandepsmap, i - solv->installed->start))
1726         continue;
1727       r = solv->rules + solv->featurerules + (i - solv->installed->start);
1728       /* a mistake is when the featurerule is true but the updaterule is false */
1729       if (!r->p)
1730         continue;
1731       FOR_RULELITERALS(p, pp, r)
1732         if (p > 0 && solv->decisionmap[p] > 0)
1733           break;
1734       if (!p)
1735         continue;       /* feature rule is not true */
1736       r = solv->rules + solv->updaterules + (i - solv->installed->start);
1737       if (!r->p)
1738         continue;
1739       FOR_RULELITERALS(p, pp, r)
1740         if (p > 0 && solv->decisionmap[p] > 0)
1741           break;
1742       if (p)
1743         continue;       /* update rule is true */
1744       POOL_DEBUG(SOLV_DEBUG_SOLVER, "cleandeps mistake: ");
1745       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, r);
1746       POOL_DEBUG(SOLV_DEBUG_SOLVER, "feature rule: ");
1747       solver_printruleclass(solv, SOLV_DEBUG_SOLVER, solv->rules + solv->featurerules + (i - solv->installed->start));
1748       if (!solv->cleandeps_mistakes)
1749         {
1750           solv->cleandeps_mistakes = solv_calloc(1, sizeof(Queue));
1751           queue_init(solv->cleandeps_mistakes);
1752         }
1753       queue_push(solv->cleandeps_mistakes, i);
1754       MAPCLR(&solv->cleandepsmap, i - solv->installed->start);
1755       solver_reenablepolicyrules_cleandeps(solv, i);
1756       mademistake = 1;
1757     }
1758   if (mademistake)
1759     solver_reset(solv);
1760   return mademistake;
1761 }
1762
1763 static void
1764 prune_to_update_targets(Solver *solv, Id *cp, Queue *q)
1765 {
1766   int i, j;
1767   Id p, *cp2;
1768   for (i = j = 0; i < q->count; i++)
1769     {
1770       p = q->elements[i];
1771       for (cp2 = cp; *cp2; cp2++)
1772         if (*cp2 == p)
1773           {
1774             q->elements[j++] = p;
1775             break;
1776           }
1777     }
1778   queue_truncate(q, j);
1779 }
1780
1781 #ifdef ENABLE_COMPLEX_DEPS
1782
1783 static void
1784 add_complex_recommends(Solver *solv, Id rec, Queue *dq, Map *dqmap)
1785 {
1786   Pool *pool = solv->pool;
1787   int oldcnt = dq->count;
1788   int cutcnt, blkcnt;
1789   Id p;
1790   int i, j;
1791
1792 #if 0
1793   printf("ADD_COMPLEX_RECOMMENDS %s\n", pool_dep2str(pool, rec));
1794 #endif
1795   i = pool_normalize_complex_dep(pool, rec, dq, CPLXDEPS_EXPAND);
1796   if (i == 0 || i == 1)
1797     return;
1798   cutcnt = dq->count;
1799   for (i = oldcnt; i < cutcnt; i++)
1800     {
1801       blkcnt = dq->count;
1802       for (; (p = dq->elements[i]) != 0; i++)
1803         {
1804           if (p < 0)
1805             {
1806               if (solv->decisionmap[-p] <= 0)
1807                 break;
1808               continue;
1809             }
1810           if (solv->decisionmap[p] > 0)
1811             {
1812               queue_truncate(dq, blkcnt);
1813               break;
1814             }
1815           if (dqmap)
1816             {
1817               if (!MAPTST(dqmap, p))
1818                 continue;
1819             }
1820           else
1821             {
1822               if (solv->decisionmap[p] < 0)
1823                 continue;
1824               if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
1825                 continue;
1826             }
1827           queue_push(dq, p);
1828         }
1829       while (dq->elements[i])
1830         i++;
1831     }
1832   queue_deleten(dq, oldcnt, cutcnt - oldcnt);
1833   /* unify */
1834   if (dq->count != oldcnt)
1835     {
1836       for (j = oldcnt; j < dq->count; j++)
1837         {
1838           p = dq->elements[j];
1839           for (i = 0; i < j; i++)
1840             if (dq->elements[i] == p)
1841               {
1842                 dq->elements[j] = 0;
1843                 break;
1844               }
1845         }
1846       for (i = j = oldcnt; j < dq->count; j++)
1847         if (dq->elements[j])
1848           dq->elements[i++] = dq->elements[j];
1849       queue_truncate(dq, i);
1850     }
1851 #if 0
1852   printf("RETURN:\n");
1853   for (i = oldcnt; i < dq->count; i++)
1854     printf("  - %s\n", pool_solvid2str(pool, dq->elements[i]));
1855 #endif
1856 }
1857
1858 static void
1859 do_complex_recommendations(Solver *solv, Id rec, Map *m, int noselected)
1860 {
1861   Pool *pool = solv->pool;
1862   Queue dq;
1863   Id p;
1864   int i, blk;
1865
1866 #if 0
1867   printf("DO_COMPLEX_RECOMMENDATIONS %s\n", pool_dep2str(pool, rec));
1868 #endif
1869   queue_init(&dq);
1870   i = pool_normalize_complex_dep(pool, rec, &dq, CPLXDEPS_EXPAND);
1871   if (i == 0 || i == 1)
1872     {
1873       queue_free(&dq);
1874       return;
1875     }
1876   for (i = 0; i < dq.count; i++)
1877     {
1878       blk = i;
1879       for (; (p = dq.elements[i]) != 0; i++)
1880         {
1881           if (p < 0)
1882             {
1883               if (solv->decisionmap[-p] <= 0)
1884                 break;
1885               continue;
1886             }
1887           if (solv->decisionmap[p] > 0)
1888             {
1889               if (noselected)
1890                 break;
1891               MAPSET(m, p);
1892               for (i++; (p = dq.elements[i]) != 0; i++)
1893                 if (p > 0 && solv->decisionmap[p] > 0)
1894                   MAPSET(m, p);
1895               p = 1;
1896               break;
1897             }
1898         }
1899       if (!p)
1900         {
1901           for (i = blk; (p = dq.elements[i]) != 0; i++)
1902             if (p > 0)
1903               MAPSET(m, p);
1904         }
1905       while (dq.elements[i])
1906         i++;
1907     }
1908   queue_free(&dq);
1909 }
1910
1911 #endif
1912
1913 /*-------------------------------------------------------------------
1914  *
1915  * solver_run_sat
1916  *
1917  * all rules have been set up, now actually run the solver
1918  *
1919  */
1920
1921 void
1922 solver_run_sat(Solver *solv, int disablerules, int doweak)
1923 {
1924   Queue dq;             /* local decisionqueue */
1925   Queue dqs;            /* local decisionqueue for supplements */
1926   int systemlevel;
1927   int level, olevel;
1928   Rule *r;
1929   int i, j, n;
1930   Solvable *s;
1931   Pool *pool = solv->pool;
1932   Id p, pp, *dp;
1933   int minimizationsteps;
1934   int installedpos = solv->installed ? solv->installed->start : 0;
1935
1936   IF_POOLDEBUG (SOLV_DEBUG_RULE_CREATION)
1937     {
1938       POOL_DEBUG (SOLV_DEBUG_RULE_CREATION, "number of rules: %d\n", solv->nrules);
1939       for (i = 1; i < solv->nrules; i++)
1940         solver_printruleclass(solv, SOLV_DEBUG_RULE_CREATION, solv->rules + i);
1941     }
1942
1943   POOL_DEBUG(SOLV_DEBUG_SOLVER, "initial decisions: %d\n", solv->decisionq.count);
1944
1945   /* start SAT algorithm */
1946   level = 1;
1947   systemlevel = level + 1;
1948   POOL_DEBUG(SOLV_DEBUG_SOLVER, "solving...\n");
1949
1950   queue_init(&dq);
1951   queue_init(&dqs);
1952
1953   /*
1954    * here's the main loop:
1955    * 1) propagate new decisions (only needed once)
1956    * 2) fulfill jobs
1957    * 3) try to keep installed packages
1958    * 4) fulfill all unresolved rules
1959    * 5) install recommended packages
1960    * 6) minimalize solution if we had choices
1961    * if we encounter a problem, we rewind to a safe level and restart
1962    * with step 1
1963    */
1964
1965   minimizationsteps = 0;
1966   for (;;)
1967     {
1968       /*
1969        * initial propagation of the assertions
1970        */
1971       if (level == 1)
1972         {
1973           POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "propagating (propagate_index: %d;  size decisionq: %d)...\n", solv->propagate_index, solv->decisionq.count);
1974           if ((r = propagate(solv, level)) != 0)
1975             {
1976               if (analyze_unsolvable(solv, r, disablerules))
1977                 continue;
1978               level = 0;
1979               break;    /* unsolvable */
1980             }
1981         }
1982
1983       /*
1984        * resolve jobs first
1985        */
1986      if (level < systemlevel)
1987         {
1988           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving job rules\n");
1989           for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
1990             {
1991               Id l;
1992               if (r->d < 0)             /* ignore disabled rules */
1993                 continue;
1994               queue_empty(&dq);
1995               FOR_RULELITERALS(l, pp, r)
1996                 {
1997                   if (l < 0)
1998                     {
1999                       if (solv->decisionmap[-l] <= 0)
2000                         break;
2001                     }
2002                   else
2003                     {
2004                       if (solv->decisionmap[l] > 0)
2005                         break;
2006                       if (solv->decisionmap[l] == 0)
2007                         queue_push(&dq, l);
2008                     }
2009                 }
2010               if (l || !dq.count)
2011                 continue;
2012               /* prune to installed if not updating */
2013               if (dq.count > 1 && solv->installed && !solv->updatemap_all &&
2014                   !(solv->job.elements[solv->ruletojob.elements[i - solv->jobrules]] & SOLVER_ORUPDATE))
2015                 {
2016                   int j, k;
2017                   for (j = k = 0; j < dq.count; j++)
2018                     {
2019                       Solvable *s = pool->solvables + dq.elements[j];
2020                       if (s->repo == solv->installed)
2021                         {
2022                           dq.elements[k++] = dq.elements[j];
2023                           if (solv->updatemap.size && MAPTST(&solv->updatemap, dq.elements[j] - solv->installed->start))
2024                             {
2025                               k = 0;    /* package wants to be updated, do not prune */
2026                               break;
2027                             }
2028                         }
2029                     }
2030                   if (k)
2031                     dq.count = k;
2032                 }
2033               olevel = level;
2034               level = selectandinstall(solv, level, &dq, disablerules, i);
2035               if (level == 0)
2036                 break;
2037               if (level <= olevel)
2038                 break;
2039             }
2040           if (level == 0)
2041             break;      /* unsolvable */
2042           systemlevel = level + 1;
2043           if (i < solv->jobrules_end)
2044             continue;
2045           if (!solv->decisioncnt_update)
2046             solv->decisioncnt_update = solv->decisionq.count;
2047         }
2048
2049       /*
2050        * installed packages
2051        */
2052       if (level < systemlevel && solv->installed && solv->installed->nsolvables && !solv->installed->disabled)
2053         {
2054           Repo *installed = solv->installed;
2055           int pass;
2056
2057           POOL_DEBUG(SOLV_DEBUG_SOLVER, "resolving installed packages\n");
2058           /* we use two passes if we need to update packages
2059            * to create a better user experience */
2060           for (pass = solv->updatemap.size ? 0 : 1; pass < 2; pass++)
2061             {
2062               int passlevel = level;
2063               Id *specialupdaters = solv->specialupdaters;
2064               if (pass == 1 && !solv->decisioncnt_keep)
2065                 solv->decisioncnt_keep = solv->decisionq.count;
2066               /* start with installedpos, the position that gave us problems the last time */
2067               for (i = installedpos, n = installed->start; n < installed->end; i++, n++)
2068                 {
2069                   Rule *rr;
2070                   Id d;
2071
2072                   if (i == installed->end)
2073                     i = installed->start;
2074                   s = pool->solvables + i;
2075                   if (s->repo != installed)
2076                     continue;
2077
2078                   if (solv->decisionmap[i] > 0 && (!specialupdaters || !specialupdaters[i - installed->start]))
2079                     continue;           /* already decided */
2080                   if (!pass && solv->updatemap.size && !MAPTST(&solv->updatemap, i - installed->start))
2081                     continue;           /* updates first */
2082                   r = solv->rules + solv->updaterules + (i - installed->start);
2083                   rr = r;
2084                   if (!rr->p || rr->d < 0)      /* disabled -> look at feature rule */
2085                     rr -= solv->installed->end - solv->installed->start;
2086                   if (!rr->p)           /* identical to update rule? */
2087                     rr = r;
2088                   if (!rr->p && !(specialupdaters && specialupdaters[i - installed->start]))
2089                     continue;           /* orpaned package */
2090
2091                   /* check if we should update this package to the latest version
2092                    * noupdate is set for erase jobs, in that case we want to deinstall
2093                    * the installed package and not replace it with a newer version
2094                    * rr->p != i is for dup jobs where the installed package cannot be kept */
2095                   queue_empty(&dq);
2096                   if (!MAPTST(&solv->noupdate, i - installed->start) && (solv->decisionmap[i] < 0 || solv->updatemap_all || (solv->updatemap.size && MAPTST(&solv->updatemap, i - installed->start)) || (rr->p && rr->p != i)))
2097                     {
2098                       if (!rr->p)
2099                         {
2100                           /* specialupdater with no update/feature rule */
2101                           for (d = specialupdaters[i - installed->start]; (p = pool->whatprovidesdata[d++]) != 0; )
2102                             {
2103                               if (solv->decisionmap[p] > 0)
2104                                 {
2105                                   dq.count = 0;
2106                                   break;
2107                                 }
2108                               if (!solv->decisionmap[p])
2109                                 queue_push(&dq, p);
2110                             }
2111                         }
2112                       else if (specialupdaters && (d = specialupdaters[i - installed->start]) != 0)
2113                         {
2114                           /* special multiversion handling, make sure best version is chosen */
2115                           if (rr->p == i && solv->decisionmap[i] >= 0)
2116                             queue_push(&dq, i);
2117                           while ((p = pool->whatprovidesdata[d++]) != 0)
2118                             if (solv->decisionmap[p] >= 0)
2119                               queue_push(&dq, p);
2120                           if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
2121                             prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
2122                           if (dq.count)
2123                             {
2124                               policy_filter_unwanted(solv, &dq, POLICY_MODE_CHOOSE);
2125                               p = dq.elements[0];
2126                               if (p != i && solv->decisionmap[p] == 0)
2127                                 {
2128                                   rr = solv->rules + solv->featurerules + (i - solv->installed->start);
2129                                   if (!rr->p)           /* update rule == feature rule? */
2130                                     rr = rr - solv->featurerules + solv->updaterules;
2131                                   dq.count = 1;
2132                                 }
2133                               else
2134                                 dq.count = 0;
2135                             }
2136                         }
2137                       else
2138                         {
2139                           /* update to best package of the update rule */
2140                           FOR_RULELITERALS(p, pp, rr)
2141                             {
2142                               if (solv->decisionmap[p] > 0)
2143                                 {
2144                                   dq.count = 0;         /* already fulfilled */
2145                                   break;
2146                                 }
2147                               if (!solv->decisionmap[p])
2148                                 queue_push(&dq, p);
2149                             }
2150                         }
2151                     }
2152                   if (dq.count && solv->update_targets && solv->update_targets->elements[i - installed->start])
2153                     prune_to_update_targets(solv, solv->update_targets->elements + solv->update_targets->elements[i - installed->start], &dq);
2154                   /* install best version */
2155                   if (dq.count)
2156                     {
2157                       olevel = level;
2158                       level = selectandinstall(solv, level, &dq, disablerules, rr - solv->rules);
2159                       if (level == 0)
2160                         {
2161                           queue_free(&dq);
2162                           queue_free(&dqs);
2163                           return;
2164                         }
2165                       if (level <= olevel)
2166                         {
2167                           if (level == 1 || level < passlevel)
2168                             break;      /* trouble */
2169                           if (level < olevel)
2170                             n = installed->start;       /* redo all */
2171                           i--;
2172                           n--;
2173                           continue;
2174                         }
2175                     }
2176                   /* if still undecided keep package */
2177                   if (solv->decisionmap[i] == 0)
2178                     {
2179                       olevel = level;
2180                       if (solv->cleandepsmap.size && MAPTST(&solv->cleandepsmap, i - installed->start))
2181                         {
2182 #if 0
2183                           POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, i));
2184                           level = setpropagatelearn(solv, level, -i, disablerules, 0);
2185 #else
2186                           continue;
2187 #endif
2188                         }
2189                       else
2190                         {
2191                           POOL_DEBUG(SOLV_DEBUG_POLICY, "keeping %s\n", pool_solvid2str(pool, i));
2192                           level = setpropagatelearn(solv, level, i, disablerules, r - solv->rules);
2193                         }
2194                       if (level == 0)
2195                         break;
2196                       if (level <= olevel)
2197                         {
2198                           if (level == 1 || level < passlevel)
2199                             break;      /* trouble */
2200                           if (level < olevel)
2201                             n = installed->start;       /* redo all */
2202                           i--;
2203                           n--;
2204                           continue;     /* retry with learnt rule */
2205                         }
2206                     }
2207                 }
2208               if (n < installed->end)
2209                 {
2210                   installedpos = i;     /* retry problem solvable next time */
2211                   break;                /* ran into trouble */
2212                 }
2213               installedpos = installed->start;  /* reset installedpos */
2214             }
2215           if (level == 0)
2216             break;              /* unsolvable */
2217           systemlevel = level + 1;
2218           if (pass < 2)
2219             continue;           /* had trouble, retry */
2220         }
2221       if (!solv->decisioncnt_keep)
2222         solv->decisioncnt_keep = solv->decisionq.count;
2223
2224       if (level < systemlevel)
2225         systemlevel = level;
2226
2227       /*
2228        * decide
2229        */
2230       if (!solv->decisioncnt_resolve)
2231         solv->decisioncnt_resolve = solv->decisionq.count;
2232       POOL_DEBUG(SOLV_DEBUG_POLICY, "deciding unresolved rules\n");
2233       for (i = 1, n = 1; n < solv->nrules; i++, n++)
2234         {
2235           if (i == solv->nrules)
2236             i = 1;
2237           r = solv->rules + i;
2238           if (r->d < 0)         /* ignore disabled rules */
2239             continue;
2240           if (r->p < 0)         /* most common cases first */
2241             {
2242               if (r->d == 0 || solv->decisionmap[-r->p] <= 0)
2243                 continue;
2244             }
2245           if (dq.count)
2246             queue_empty(&dq);
2247           if (r->d == 0)
2248             {
2249               /* binary or unary rule */
2250               /* need two positive undecided literals, r->p already checked above */
2251               if (r->w2 <= 0)
2252                 continue;
2253               if (solv->decisionmap[r->p] || solv->decisionmap[r->w2])
2254                 continue;
2255               queue_push(&dq, r->p);
2256               queue_push(&dq, r->w2);
2257             }
2258           else
2259             {
2260               /* make sure that
2261                * all negative literals are installed
2262                * no positive literal is installed
2263                * i.e. the rule is not fulfilled and we
2264                * just need to decide on the positive literals
2265                * (decisionmap[-r->p] for the r->p < 0 case is already checked above)
2266                */
2267               if (r->p >= 0)
2268                 {
2269                   if (solv->decisionmap[r->p] > 0)
2270                     continue;
2271                   if (solv->decisionmap[r->p] == 0)
2272                     queue_push(&dq, r->p);
2273                 }
2274               dp = pool->whatprovidesdata + r->d;
2275               while ((p = *dp++) != 0)
2276                 {
2277                   if (p < 0)
2278                     {
2279                       if (solv->decisionmap[-p] <= 0)
2280                         break;
2281                     }
2282                   else
2283                     {
2284                       if (solv->decisionmap[p] > 0)
2285                         break;
2286                       if (solv->decisionmap[p] == 0)
2287                         queue_push(&dq, p);
2288                     }
2289                 }
2290               if (p)
2291                 continue;
2292             }
2293           IF_POOLDEBUG (SOLV_DEBUG_PROPAGATE)
2294             {
2295               POOL_DEBUG(SOLV_DEBUG_PROPAGATE, "unfulfilled ");
2296               solver_printruleclass(solv, SOLV_DEBUG_PROPAGATE, r);
2297             }
2298           /* dq.count < 2 cannot happen as this means that
2299            * the rule is unit */
2300           assert(dq.count > 1);
2301
2302           /* prune to cleandeps packages */
2303           if (solv->cleandepsmap.size && solv->installed)
2304             {
2305               Repo *installed = solv->installed;
2306               for (j = 0; j < dq.count; j++)
2307                 if (pool->solvables[dq.elements[j]].repo == installed && MAPTST(&solv->cleandepsmap, dq.elements[j] - installed->start))
2308                   break;
2309               if (j < dq.count)
2310                 {
2311                   dq.elements[0] = dq.elements[j];
2312                   queue_truncate(&dq, 1);
2313                 }
2314             }
2315
2316           olevel = level;
2317           level = selectandinstall(solv, level, &dq, disablerules, r - solv->rules);
2318           if (level == 0)
2319             break;              /* unsolvable */
2320           if (level < systemlevel || level == 1)
2321             break;              /* trouble */
2322           /* something changed, so look at all rules again */
2323           n = 0;
2324         }
2325
2326       if (n != solv->nrules)    /* ran into trouble? */
2327         {
2328           if (level == 0)
2329             break;              /* unsolvable */
2330           continue;             /* start over */
2331         }
2332
2333       /* decide leftover cleandeps packages */
2334       if (solv->cleandepsmap.size && solv->installed)
2335         {
2336           for (p = solv->installed->start; p < solv->installed->end; p++)
2337             {
2338               s = pool->solvables + p;
2339               if (s->repo != solv->installed)
2340                 continue;
2341               if (solv->decisionmap[p] == 0 && MAPTST(&solv->cleandepsmap, p - solv->installed->start))
2342                 {
2343                   POOL_DEBUG(SOLV_DEBUG_POLICY, "cleandeps erasing %s\n", pool_solvid2str(pool, p));
2344                   olevel = level;
2345                   level = setpropagatelearn(solv, level, -p, 0, 0);
2346                   if (level < olevel)
2347                     break;
2348                 }
2349             }
2350           if (p < solv->installed->end)
2351             continue;
2352         }
2353
2354       /* at this point we have a consistent system. now do the extras... */
2355
2356       if (!solv->decisioncnt_weak)
2357         solv->decisioncnt_weak = solv->decisionq.count;
2358       if (doweak)
2359         {
2360           int qcount;
2361
2362           POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended packages\n");
2363           queue_empty(&dq);     /* recommended packages */
2364           queue_empty(&dqs);    /* supplemented packages */
2365           for (i = 1; i < pool->nsolvables; i++)
2366             {
2367               if (solv->decisionmap[i] < 0)
2368                 continue;
2369               if (solv->decisionmap[i] > 0)
2370                 {
2371                   /* installed, check for recommends */
2372                   Id *recp, rec, pp, p;
2373                   s = pool->solvables + i;
2374                   if (!solv->addalreadyrecommended && s->repo == solv->installed)
2375                     continue;
2376                   /* XXX need to special case AND ? */
2377                   if (s->recommends)
2378                     {
2379                       recp = s->repo->idarraydata + s->recommends;
2380                       while ((rec = *recp++) != 0)
2381                         {
2382 #ifdef ENABLE_COMPLEX_DEPS
2383                           if (pool_is_complex_dep(pool, rec))
2384                             {
2385                               add_complex_recommends(solv, rec, &dq, 0);
2386                               continue;
2387                             }
2388 #endif
2389                           qcount = dq.count;
2390                           FOR_PROVIDES(p, pp, rec)
2391                             {
2392                               if (solv->decisionmap[p] > 0)
2393                                 {
2394                                   dq.count = qcount;
2395                                   break;
2396                                 }
2397                               else if (solv->decisionmap[p] == 0)
2398                                 {
2399                                   if (solv->dupmap_all && solv->installed && pool->solvables[p].repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))))
2400                                     continue;
2401                                   queue_pushunique(&dq, p);
2402                                 }
2403                             }
2404                         }
2405                     }
2406                 }
2407               else
2408                 {
2409                   s = pool->solvables + i;
2410                   if (!s->supplements)
2411                     continue;
2412                   if (!pool_installable(pool, s))
2413                     continue;
2414                   if (!solver_is_supplementing(solv, s))
2415                     continue;
2416                   if (solv->dupmap_all && solv->installed && s->repo == solv->installed && (solv->droporphanedmap_all || (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, i - solv->installed->start))))
2417                     continue;
2418                   queue_push(&dqs, i);
2419                 }
2420             }
2421
2422           /* filter out all packages obsoleted by installed packages */
2423           /* this is no longer needed if we have reverse obsoletes */
2424           if ((dqs.count || dq.count) && solv->installed)
2425             {
2426               Map obsmap;
2427               Id obs, *obsp, po, ppo;
2428
2429               map_init(&obsmap, pool->nsolvables);
2430               for (p = solv->installed->start; p < solv->installed->end; p++)
2431                 {
2432                   s = pool->solvables + p;
2433                   if (s->repo != solv->installed || !s->obsoletes)
2434                     continue;
2435                   if (solv->decisionmap[p] <= 0)
2436                     continue;
2437                   if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
2438                     continue;
2439                   obsp = s->repo->idarraydata + s->obsoletes;
2440                   /* foreach obsoletes */
2441                   while ((obs = *obsp++) != 0)
2442                     FOR_PROVIDES(po, ppo, obs)
2443                       MAPSET(&obsmap, po);
2444                 }
2445               for (i = j = 0; i < dqs.count; i++)
2446                 if (!MAPTST(&obsmap, dqs.elements[i]))
2447                   dqs.elements[j++] = dqs.elements[i];
2448               dqs.count = j;
2449               for (i = j = 0; i < dq.count; i++)
2450                 if (!MAPTST(&obsmap, dq.elements[i]))
2451                   dq.elements[j++] = dq.elements[i];
2452               dq.count = j;
2453               map_free(&obsmap);
2454             }
2455
2456           /* filter out all already supplemented packages if requested */
2457           if (!solv->addalreadyrecommended && dqs.count)
2458             {
2459               int dosplitprovides_old = solv->dosplitprovides;
2460               /* turn off all new packages */
2461               for (i = 0; i < solv->decisionq.count; i++)
2462                 {
2463                   p = solv->decisionq.elements[i];
2464                   if (p < 0)
2465                     continue;
2466                   s = pool->solvables + p;
2467                   if (s->repo && s->repo != solv->installed)
2468                     solv->decisionmap[p] = -solv->decisionmap[p];
2469                 }
2470               solv->dosplitprovides = 0;
2471               /* filter out old supplements */
2472               for (i = j = 0; i < dqs.count; i++)
2473                 {
2474                   p = dqs.elements[i];
2475                   s = pool->solvables + p;
2476                   if (!s->supplements)
2477                     continue;
2478                   if (!solver_is_supplementing(solv, s))
2479                     dqs.elements[j++] = p;
2480                   else if (solv->installsuppdepq && solver_check_installsuppdepq(solv, s))
2481                     dqs.elements[j++] = p;
2482                 }
2483               dqs.count = j;
2484               /* undo turning off */
2485               for (i = 0; i < solv->decisionq.count; i++)
2486                 {
2487                   p = solv->decisionq.elements[i];
2488                   if (p < 0)
2489                     continue;
2490                   s = pool->solvables + p;
2491                   if (s->repo && s->repo != solv->installed)
2492                     solv->decisionmap[p] = -solv->decisionmap[p];
2493                 }
2494               solv->dosplitprovides = dosplitprovides_old;
2495             }
2496
2497           /* multiversion doesn't mix well with supplements.
2498            * filter supplemented packages where we already decided
2499            * to install a different version (see bnc#501088) */
2500           if (dqs.count && solv->multiversion.size)
2501             {
2502               for (i = j = 0; i < dqs.count; i++)
2503                 {
2504                   p = dqs.elements[i];
2505                   if (MAPTST(&solv->multiversion, p))
2506                     {
2507                       Id p2, pp2;
2508                       s = pool->solvables + p;
2509                       FOR_PROVIDES(p2, pp2, s->name)
2510                         if (solv->decisionmap[p2] > 0 && pool->solvables[p2].name == s->name)
2511                           break;
2512                       if (p2)
2513                         continue;       /* ignore this package */
2514                     }
2515                   dqs.elements[j++] = p;
2516                 }
2517               dqs.count = j;
2518             }
2519
2520           /* make dq contain both recommended and supplemented pkgs */
2521           if (dqs.count)
2522             {
2523               for (i = 0; i < dqs.count; i++)
2524                 queue_pushunique(&dq, dqs.elements[i]);
2525             }
2526
2527           if (dq.count)
2528             {
2529               Map dqmap;
2530               int decisioncount = solv->decisionq.count;
2531
2532               if (dq.count == 1)
2533                 {
2534                   /* simple case, just one package. no need to choose to best version */
2535                   p = dq.elements[0];
2536                   if (dqs.count)
2537                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2538                   else
2539                     POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2540                   level = setpropagatelearn(solv, level, p, 0, 0);
2541                   if (level == 0)
2542                     break;
2543                   continue;     /* back to main loop */
2544                 }
2545
2546               /* filter packages, this gives us the best versions */
2547               policy_filter_unwanted(solv, &dq, POLICY_MODE_RECOMMEND);
2548
2549               /* create map of result */
2550               map_init(&dqmap, pool->nsolvables);
2551               for (i = 0; i < dq.count; i++)
2552                 MAPSET(&dqmap, dq.elements[i]);
2553
2554               /* install all supplemented packages */
2555               for (i = 0; i < dqs.count; i++)
2556                 {
2557                   p = dqs.elements[i];
2558                   if (solv->decisionmap[p] || !MAPTST(&dqmap, p))
2559                     continue;
2560                   POOL_DEBUG(SOLV_DEBUG_POLICY, "installing supplemented %s\n", pool_solvid2str(pool, p));
2561                   olevel = level;
2562                   level = setpropagatelearn(solv, level, p, 0, 0);
2563                   if (level <= olevel)
2564                     break;
2565                 }
2566               if (i < dqs.count || solv->decisionq.count < decisioncount)
2567                 {
2568                   map_free(&dqmap);
2569                   if (level == 0)
2570                     break;
2571                   continue;
2572                 }
2573
2574               /* install all recommended packages */
2575               /* more work as we want to created branches if multiple
2576                * choices are valid */
2577               for (i = 0; i < decisioncount; i++)
2578                 {
2579                   Id rec, *recp, pp;
2580                   p = solv->decisionq.elements[i];
2581                   if (p < 0)
2582                     continue;
2583                   s = pool->solvables + p;
2584                   if (!s->repo || (!solv->addalreadyrecommended && s->repo == solv->installed))
2585                     continue;
2586                   if (!s->recommends)
2587                     continue;
2588                   recp = s->repo->idarraydata + s->recommends;
2589                   while ((rec = *recp++) != 0)
2590                     {
2591                       queue_empty(&dq);
2592 #ifdef ENABLE_COMPLEX_DEPS
2593                       if (pool_is_complex_dep(pool, rec))
2594                           add_complex_recommends(solv, rec, &dq, &dqmap);
2595                       else
2596 #endif
2597                       FOR_PROVIDES(p, pp, rec)
2598                         {
2599                           if (solv->decisionmap[p] > 0)
2600                             {
2601                               dq.count = 0;
2602                               break;
2603                             }
2604                           else if (solv->decisionmap[p] == 0 && MAPTST(&dqmap, p))
2605                             queue_push(&dq, p);
2606                         }
2607                       if (!dq.count)
2608                         continue;
2609                       if (dq.count > 1)
2610                         {
2611                           /* multiple candidates, open a branch */
2612                           for (i = 1; i < dq.count; i++)
2613                             queue_push(&solv->branches, dq.elements[i]);
2614                           queue_push(&solv->branches, -level);
2615                         }
2616                       p = dq.elements[0];
2617                       POOL_DEBUG(SOLV_DEBUG_POLICY, "installing recommended %s\n", pool_solvid2str(pool, p));
2618                       olevel = level;
2619                       level = setpropagatelearn(solv, level, p, 0, 0);
2620                       if (level <= olevel || solv->decisionq.count < decisioncount)
2621                         break;  /* we had to revert some decisions */
2622                     }
2623                   if (rec)
2624                     break;      /* had a problem above, quit loop */
2625                 }
2626               map_free(&dqmap);
2627               if (level == 0)
2628                 break;
2629               continue;         /* back to main loop so that all deps are checked */
2630             }
2631         }
2632
2633       if (!solv->decisioncnt_orphan)
2634         solv->decisioncnt_orphan = solv->decisionq.count;
2635       if (solv->dupmap_all && solv->installed)
2636         {
2637           int installedone = 0;
2638
2639           /* let's see if we can install some unsupported package */
2640           POOL_DEBUG(SOLV_DEBUG_SOLVER, "deciding orphaned packages\n");
2641           for (i = 0; i < solv->orphaned.count; i++)
2642             {
2643               p = solv->orphaned.elements[i];
2644               if (solv->decisionmap[p])
2645                 continue;       /* already decided */
2646               if (solv->droporphanedmap_all)
2647                 continue;
2648               if (solv->droporphanedmap.size && MAPTST(&solv->droporphanedmap, p - solv->installed->start))
2649                 continue;
2650               POOL_DEBUG(SOLV_DEBUG_SOLVER, "keeping orphaned %s\n", pool_solvid2str(pool, p));
2651               olevel = level;
2652               level = setpropagatelearn(solv, level, p, 0, 0);
2653               installedone = 1;
2654               if (level < olevel)
2655                 break;
2656             }
2657           if (installedone || i < solv->orphaned.count)
2658             {
2659               if (level == 0)
2660                 break;
2661               continue;         /* back to main loop */
2662             }
2663           for (i = 0; i < solv->orphaned.count; i++)
2664             {
2665               p = solv->orphaned.elements[i];
2666               if (solv->decisionmap[p])
2667                 continue;       /* already decided */
2668               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing orphaned %s\n", pool_solvid2str(pool, p));
2669               olevel = level;
2670               level = setpropagatelearn(solv, level, -p, 0, 0);
2671               if (level < olevel)
2672                 break;
2673             }
2674           if (i < solv->orphaned.count)
2675             {
2676               if (level == 0)
2677                 break;
2678               continue;         /* back to main loop */
2679             }
2680         }
2681
2682      /* one final pass to make sure we decided all installed packages */
2683       if (solv->installed)
2684         {
2685           for (p = solv->installed->start; p < solv->installed->end; p++)
2686             {
2687               if (solv->decisionmap[p])
2688                 continue;       /* already decided */
2689               s = pool->solvables + p;
2690               if (s->repo != solv->installed)
2691                 continue;
2692               POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing unwanted %s\n", pool_solvid2str(pool, p));
2693               olevel = level;
2694               level = setpropagatelearn(solv, level, -p, 0, 0);
2695               if (level < olevel)
2696                 break;
2697             }
2698           if (p < solv->installed->end)
2699             {
2700               if (level == 0)
2701                 break;
2702               continue;         /* back to main loop */
2703             }
2704         }
2705
2706       if (solv->installed && solv->cleandepsmap.size)
2707         {
2708           if (cleandeps_check_mistakes(solv, level))
2709             {
2710               level = 1;        /* restart from scratch */
2711               systemlevel = level + 1;
2712               continue;
2713             }
2714         }
2715
2716       if (solv->solution_callback)
2717         {
2718           solv->solution_callback(solv, solv->solution_callback_data);
2719           if (solv->branches.count)
2720             {
2721               int i = solv->branches.count - 1;
2722               int l = -solv->branches.elements[i];
2723               Id why;
2724
2725               for (; i > 0; i--)
2726                 if (solv->branches.elements[i - 1] < 0)
2727                   break;
2728               p = solv->branches.elements[i];
2729               POOL_DEBUG(SOLV_DEBUG_SOLVER, "branching with %s\n", pool_solvid2str(pool, p));
2730               queue_empty(&dq);
2731               for (j = i + 1; j < solv->branches.count; j++)
2732                 queue_push(&dq, solv->branches.elements[j]);
2733               solv->branches.count = i;
2734               level = l;
2735               revert(solv, level);
2736               if (dq.count > 1)
2737                 for (j = 0; j < dq.count; j++)
2738                   queue_push(&solv->branches, dq.elements[j]);
2739               olevel = level;
2740               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2741               assert(why >= 0);
2742               level = setpropagatelearn(solv, level, p, disablerules, why);
2743               if (level == 0)
2744                 break;
2745               continue;
2746             }
2747           /* all branches done, we're finally finished */
2748           break;
2749         }
2750
2751       /* auto-minimization step */
2752       if (solv->branches.count)
2753         {
2754           int l = 0, lasti = -1, lastl = -1;
2755           Id why;
2756
2757           p = 0;
2758           for (i = solv->branches.count - 1; i >= 0; i--)
2759             {
2760               p = solv->branches.elements[i];
2761               if (p < 0)
2762                 l = -p;
2763               else if (p > 0 && solv->decisionmap[p] > l + 1)
2764                 {
2765                   lasti = i;
2766                   lastl = l;
2767                 }
2768             }
2769           if (lasti >= 0)
2770             {
2771               /* kill old solvable so that we do not loop */
2772               p = solv->branches.elements[lasti];
2773               solv->branches.elements[lasti] = 0;
2774               POOL_DEBUG(SOLV_DEBUG_SOLVER, "minimizing %d -> %d with %s\n", solv->decisionmap[p], lastl, pool_solvid2str(pool, p));
2775               minimizationsteps++;
2776
2777               level = lastl;
2778               revert(solv, level);
2779               why = -solv->decisionq_why.elements[solv->decisionq_why.count];
2780               assert(why >= 0);
2781               olevel = level;
2782               level = setpropagatelearn(solv, level, p, disablerules, why);
2783               if (level == 0)
2784                 break;
2785               continue;         /* back to main loop */
2786             }
2787         }
2788       /* no minimization found, we're finally finished! */
2789       break;
2790     }
2791
2792   POOL_DEBUG(SOLV_DEBUG_STATS, "solver statistics: %d learned rules, %d unsolvable, %d minimization steps\n", solv->stats_learned, solv->stats_unsolvable, minimizationsteps);
2793
2794   POOL_DEBUG(SOLV_DEBUG_STATS, "done solving.\n\n");
2795   queue_free(&dq);
2796   queue_free(&dqs);
2797   if (level == 0)
2798     {
2799       /* unsolvable */
2800       solv->decisioncnt_update = solv->decisionq.count;
2801       solv->decisioncnt_keep = solv->decisionq.count;
2802       solv->decisioncnt_resolve = solv->decisionq.count;
2803       solv->decisioncnt_weak = solv->decisionq.count;
2804       solv->decisioncnt_orphan = solv->decisionq.count;
2805     }
2806 #if 0
2807   solver_printdecisionq(solv, SOLV_DEBUG_RESULT);
2808 #endif
2809 }
2810
2811
2812 /*-------------------------------------------------------------------
2813  *
2814  * remove disabled conflicts
2815  *
2816  * purpose: update the decisionmap after some rules were disabled.
2817  * this is used to calculate the suggested/recommended package list.
2818  * Also returns a "removed" list to undo the discisionmap changes.
2819  */
2820
2821 static void
2822 removedisabledconflicts(Solver *solv, Queue *removed)
2823 {
2824   Pool *pool = solv->pool;
2825   int i, n;
2826   Id p, why, *dp;
2827   Id new;
2828   Rule *r;
2829   Id *decisionmap = solv->decisionmap;
2830
2831   queue_empty(removed);
2832   for (i = 0; i < solv->decisionq.count; i++)
2833     {
2834       p = solv->decisionq.elements[i];
2835       if (p > 0)
2836         continue;       /* conflicts only, please */
2837       why = solv->decisionq_why.elements[i];
2838       if (why == 0)
2839         {
2840           /* no rule involved, must be a orphan package drop */
2841           continue;
2842         }
2843       /* we never do conflicts on free decisions, so there
2844        * must have been an unit rule */
2845       assert(why > 0);
2846       r = solv->rules + why;
2847       if (r->d < 0 && decisionmap[-p])
2848         {
2849           /* rule is now disabled, remove from decisionmap */
2850           POOL_DEBUG(SOLV_DEBUG_SOLVER, "removing conflict for package %s[%d]\n", pool_solvid2str(pool, -p), -p);
2851           queue_push(removed, -p);
2852           queue_push(removed, decisionmap[-p]);
2853           decisionmap[-p] = 0;
2854         }
2855     }
2856   if (!removed->count)
2857     return;
2858   /* we removed some confliced packages. some of them might still
2859    * be in conflict, so search for unit rules and re-conflict */
2860   new = 0;
2861   for (i = n = 1, r = solv->rules + i; n < solv->nrules; i++, r++, n++)
2862     {
2863       if (i == solv->nrules)
2864         {
2865           i = 1;
2866           r = solv->rules + i;
2867         }
2868       if (r->d < 0)
2869         continue;
2870       if (!r->w2)
2871         {
2872           if (r->p < 0 && !decisionmap[-r->p])
2873             new = r->p;
2874         }
2875       else if (!r->d)
2876         {
2877           /* binary rule */
2878           if (r->p < 0 && decisionmap[-r->p] == 0 && DECISIONMAP_FALSE(r->w2))
2879             new = r->p;
2880           else if (r->w2 < 0 && decisionmap[-r->w2] == 0 && DECISIONMAP_FALSE(r->p))
2881             new = r->w2;
2882         }
2883       else
2884         {
2885           if (r->p < 0 && decisionmap[-r->p] == 0)
2886             new = r->p;
2887           if (new || DECISIONMAP_FALSE(r->p))
2888             {
2889               dp = pool->whatprovidesdata + r->d;
2890               while ((p = *dp++) != 0)
2891                 {
2892                   if (new && p == new)
2893                     continue;
2894                   if (p < 0 && decisionmap[-p] == 0)
2895                     {
2896                       if (new)
2897                         {
2898                           new = 0;
2899                           break;
2900                         }
2901                       new = p;
2902                     }
2903                   else if (!DECISIONMAP_FALSE(p))
2904                     {
2905                       new = 0;
2906                       break;
2907                     }
2908                 }
2909             }
2910         }
2911       if (new)
2912         {
2913           POOL_DEBUG(SOLV_DEBUG_SOLVER, "re-conflicting package %s[%d]\n", pool_solvid2str(pool, -new), -new);
2914           decisionmap[-new] = -1;
2915           new = 0;
2916           n = 0;        /* redo all rules */
2917         }
2918     }
2919 }
2920
2921 static inline void
2922 undo_removedisabledconflicts(Solver *solv, Queue *removed)
2923 {
2924   int i;
2925   for (i = 0; i < removed->count; i += 2)
2926     solv->decisionmap[removed->elements[i]] = removed->elements[i + 1];
2927 }
2928
2929
2930 /*-------------------------------------------------------------------
2931  *
2932  * weaken solvable dependencies
2933  */
2934
2935 static void
2936 weaken_solvable_deps(Solver *solv, Id p)
2937 {
2938   int i;
2939   Rule *r;
2940
2941   for (i = 1, r = solv->rules + i; i < solv->rpmrules_end; i++, r++)
2942     {
2943       if (r->p != -p)
2944         continue;
2945       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
2946         continue;       /* conflict */
2947       queue_push(&solv->weakruleq, i);
2948     }
2949 }
2950
2951
2952 /********************************************************************/
2953 /* main() */
2954
2955
2956 void
2957 solver_calculate_multiversionmap(Pool *pool, Queue *job, Map *multiversionmap)
2958 {
2959   int i;
2960   Id how, what, select;
2961   Id p, pp;
2962   for (i = 0; i < job->count; i += 2)
2963     {
2964       how = job->elements[i];
2965       if ((how & SOLVER_JOBMASK) != SOLVER_MULTIVERSION)
2966         continue;
2967       what = job->elements[i + 1];
2968       select = how & SOLVER_SELECTMASK;
2969       if (!multiversionmap->size)
2970         map_grow(multiversionmap, pool->nsolvables);
2971       if (select == SOLVER_SOLVABLE_ALL)
2972         {
2973           FOR_POOL_SOLVABLES(p)
2974             MAPSET(multiversionmap, p);
2975         }
2976       else if (select == SOLVER_SOLVABLE_REPO)
2977         {
2978           Solvable *s;
2979           Repo *repo = pool_id2repo(pool, what);
2980           if (repo)
2981             FOR_REPO_SOLVABLES(repo, p, s)
2982               MAPSET(multiversionmap, p);
2983         }
2984       FOR_JOB_SELECT(p, pp, select, what)
2985         MAPSET(multiversionmap, p);
2986     }
2987 }
2988
2989 void
2990 solver_calculate_noobsmap(Pool *pool, Queue *job, Map *multiversionmap)
2991 {
2992   solver_calculate_multiversionmap(pool, job, multiversionmap);
2993 }
2994
2995 /*
2996  * add a rule created by a job, record job number and weak flag
2997  */
2998 static inline void
2999 solver_addjobrule(Solver *solv, Id p, Id d, Id job, int weak)
3000 {
3001   solver_addrule(solv, p, d);
3002   queue_push(&solv->ruletojob, job);
3003   if (weak)
3004     queue_push(&solv->weakruleq, solv->nrules - 1);
3005 }
3006
3007 static inline void
3008 add_cleandeps_package(Solver *solv, Id p)
3009 {
3010   if (!solv->cleandeps_updatepkgs)
3011     {
3012       solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
3013       queue_init(solv->cleandeps_updatepkgs);
3014     }
3015   queue_pushunique(solv->cleandeps_updatepkgs, p);
3016 }
3017
3018 static void
3019 add_update_target(Solver *solv, Id p, Id how)
3020 {
3021   Pool *pool = solv->pool;
3022   Solvable *s = pool->solvables + p;
3023   Repo *installed = solv->installed;
3024   Id pi, pip;
3025   if (!solv->update_targets)
3026     {
3027       solv->update_targets = solv_calloc(1, sizeof(Queue));
3028       queue_init(solv->update_targets);
3029     }
3030   if (s->repo == installed)
3031     {
3032       queue_push2(solv->update_targets, p, p);
3033       return;
3034     }
3035   FOR_PROVIDES(pi, pip, s->name)
3036     {
3037       Solvable *si = pool->solvables + pi;
3038       if (si->repo != installed || si->name != s->name)
3039         continue;
3040       if (how & SOLVER_FORCEBEST)
3041         {
3042           if (!solv->bestupdatemap.size)
3043             map_grow(&solv->bestupdatemap, installed->end - installed->start);
3044           MAPSET(&solv->bestupdatemap, pi - installed->start);
3045         }
3046       if (how & SOLVER_CLEANDEPS)
3047         add_cleandeps_package(solv, pi);
3048       queue_push2(solv->update_targets, pi, p);
3049       /* check if it's ok to keep the installed package */
3050       if (s->evr == si->evr && solvable_identical(s, si))
3051         queue_push2(solv->update_targets, pi, pi);
3052     }
3053   if (s->obsoletes)
3054     {
3055       Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
3056       while ((obs = *obsp++) != 0)
3057         {
3058           FOR_PROVIDES(pi, pip, obs)
3059             {
3060               Solvable *si = pool->solvables + pi;
3061               if (si->repo != installed)
3062                 continue;
3063               if (si->name == s->name)
3064                 continue;       /* already handled above */
3065               if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
3066                 continue;
3067               if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
3068                 continue;
3069               if (how & SOLVER_FORCEBEST)
3070                 {
3071                   if (!solv->bestupdatemap.size)
3072                     map_grow(&solv->bestupdatemap, installed->end - installed->start);
3073                   MAPSET(&solv->bestupdatemap, pi - installed->start);
3074                 }
3075               if (how & SOLVER_CLEANDEPS)
3076                 add_cleandeps_package(solv, pi);
3077               queue_push2(solv->update_targets, pi, p);
3078             }
3079         }
3080     }
3081 }
3082
3083 static int
3084 transform_update_targets_sortfn(const void *ap, const void *bp, void *dp)
3085 {
3086   const Id *a = ap;
3087   const Id *b = bp;
3088   if (a[0] - b[0])
3089     return a[0] - b[0];
3090   return a[1] - b[1];
3091 }
3092
3093 static void
3094 transform_update_targets(Solver *solv)
3095 {
3096   Repo *installed = solv->installed;
3097   Queue *update_targets = solv->update_targets;
3098   int i, j;
3099   Id p, q, lastp, lastq;
3100
3101   if (!update_targets->count)
3102     {
3103       queue_free(update_targets);
3104       solv->update_targets = solv_free(update_targets);
3105       return;
3106     }
3107   if (update_targets->count > 2)
3108     solv_sort(update_targets->elements, update_targets->count >> 1, 2 * sizeof(Id), transform_update_targets_sortfn, solv);
3109   queue_insertn(update_targets, 0, installed->end - installed->start, 0);
3110   lastp = lastq = 0;
3111   for (i = j = installed->end - installed->start; i < update_targets->count; i += 2)
3112     {
3113       if ((p = update_targets->elements[i]) != lastp)
3114         {
3115           if (!solv->updatemap.size)
3116             map_grow(&solv->updatemap, installed->end - installed->start);
3117           MAPSET(&solv->updatemap, p - installed->start);
3118           update_targets->elements[j++] = 0;                    /* finish old set */
3119           update_targets->elements[p - installed->start] = j;   /* start new set */
3120           lastp = p;
3121           lastq = 0;
3122         }
3123       if ((q = update_targets->elements[i + 1]) != lastq)
3124         {
3125           update_targets->elements[j++] = q;
3126           lastq = q;
3127         }
3128     }
3129   queue_truncate(update_targets, j);
3130   queue_push(update_targets, 0);        /* finish last set */
3131 }
3132
3133
3134 static void
3135 addedmap2deduceq(Solver *solv, Map *addedmap)
3136 {
3137   Pool *pool = solv->pool;
3138   int i, j;
3139   Id p;
3140   Rule *r;
3141
3142   queue_empty(&solv->addedmap_deduceq);
3143   for (i = 2, j = solv->rpmrules_end - 1; i < pool->nsolvables && j > 0; j--)
3144     {
3145       r = solv->rules + j;
3146       if (r->p >= 0)
3147         continue;
3148       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
3149         continue;
3150       p = -r->p;
3151       if (!MAPTST(addedmap, p))
3152         {
3153           /* should never happen, but... */
3154           if (!solv->addedmap_deduceq.count || solv->addedmap_deduceq.elements[solv->addedmap_deduceq.count - 1] != -p)
3155             queue_push(&solv->addedmap_deduceq, -p);
3156           continue;
3157         }
3158       for (; i < p; i++)
3159         if (MAPTST(addedmap, i))
3160           queue_push(&solv->addedmap_deduceq, i);
3161       if (i == p)
3162         i++;
3163     }
3164   for (; i < pool->nsolvables; i++)
3165     if (MAPTST(addedmap, i))
3166       queue_push(&solv->addedmap_deduceq, i);
3167   j = 0;
3168   for (i = 2; i < pool->nsolvables; i++)
3169     if (MAPTST(addedmap, i))
3170       j++;
3171 }
3172
3173 static void
3174 deduceq2addedmap(Solver *solv, Map *addedmap)
3175 {
3176   int j;
3177   Id p;
3178   Rule *r;
3179   for (j = solv->rpmrules_end - 1; j > 0; j--)
3180     {
3181       r = solv->rules + j;
3182       if (r->d < 0 && r->p)
3183         solver_enablerule(solv, r);
3184       if (r->p >= 0)
3185         continue;
3186       if ((r->d == 0 || r->d == -1) && r->w2 < 0)
3187         continue;
3188       p = -r->p;
3189       MAPSET(addedmap, p);
3190     }
3191   for (j = 0; j < solv->addedmap_deduceq.count; j++)
3192     {
3193       p = solv->addedmap_deduceq.elements[j];
3194       if (p > 0)
3195         MAPSET(addedmap, p);
3196       else
3197         MAPCLR(addedmap, p);
3198     }
3199 }
3200
3201
3202 /*
3203  *
3204  * solve job queue
3205  *
3206  */
3207
3208 int
3209 solver_solve(Solver *solv, Queue *job)
3210 {
3211   Pool *pool = solv->pool;
3212   Repo *installed = solv->installed;
3213   int i;
3214   int oldnrules, initialnrules;
3215   Map addedmap;                /* '1' == have rpm-rules for solvable */
3216   Map installcandidatemap;
3217   Id how, what, select, name, weak, p, pp, d;
3218   Queue q;
3219   Solvable *s;
3220   Rule *r;
3221   int now, solve_start;
3222   int hasdupjob = 0;
3223   int hasbestinstalljob = 0;
3224
3225   solve_start = solv_timems(0);
3226
3227   /* log solver options */
3228   POOL_DEBUG(SOLV_DEBUG_STATS, "solver started\n");
3229   POOL_DEBUG(SOLV_DEBUG_STATS, "dosplitprovides=%d, noupdateprovide=%d, noinfarchcheck=%d\n", solv->dosplitprovides, solv->noupdateprovide, solv->noinfarchcheck);
3230   POOL_DEBUG(SOLV_DEBUG_STATS, "allowuninstall=%d, allowdowngrade=%d, allownamechange=%d, allowarchchange=%d, allowvendorchange=%d\n", solv->allowuninstall, solv->allowdowngrade, solv->allownamechange, solv->allowarchchange, solv->allowvendorchange);
3231   POOL_DEBUG(SOLV_DEBUG_STATS, "promoteepoch=%d, forbidselfconflicts=%d\n", pool->promoteepoch, pool->forbidselfconflicts);
3232   POOL_DEBUG(SOLV_DEBUG_STATS, "obsoleteusesprovides=%d, implicitobsoleteusesprovides=%d, obsoleteusescolors=%d, implicitobsoleteusescolors=%d\n", pool->obsoleteusesprovides, pool->implicitobsoleteusesprovides, pool->obsoleteusescolors, pool->implicitobsoleteusescolors);
3233   POOL_DEBUG(SOLV_DEBUG_STATS, "dontinstallrecommended=%d, addalreadyrecommended=%d\n", solv->dontinstallrecommended, solv->addalreadyrecommended);
3234
3235   /* create whatprovides if not already there */
3236   if (!pool->whatprovides)
3237     pool_createwhatprovides(pool);
3238
3239   /* create obsolete index */
3240   policy_create_obsolete_index(solv);
3241
3242   /* remember job */
3243   queue_free(&solv->job);
3244   queue_init_clone(&solv->job, job);
3245   solv->pooljobcnt = pool->pooljobs.count;
3246   if (pool->pooljobs.count)
3247     queue_insertn(&solv->job, 0, pool->pooljobs.count, pool->pooljobs.elements);
3248   job = &solv->job;
3249
3250   /* free old stuff in jase we re-run a solver */
3251   queuep_free(&solv->update_targets);
3252   queuep_free(&solv->cleandeps_updatepkgs);
3253   queue_empty(&solv->ruleassertions);
3254   solv->bestrules_pkg = solv_free(solv->bestrules_pkg);
3255   solv->choicerules_ref = solv_free(solv->choicerules_ref);
3256   if (solv->noupdate.size)
3257     map_empty(&solv->noupdate);
3258   map_zerosize(&solv->multiversion);
3259   solv->updatemap_all = 0;
3260   map_zerosize(&solv->updatemap);
3261   solv->bestupdatemap_all = 0;
3262   map_zerosize(&solv->bestupdatemap);
3263   solv->fixmap_all = 0;
3264   map_zerosize(&solv->fixmap);
3265   solv->dupmap_all = 0;
3266   map_zerosize(&solv->dupmap);
3267   map_zerosize(&solv->dupinvolvedmap);
3268   solv->droporphanedmap_all = 0;
3269   map_zerosize(&solv->droporphanedmap);
3270   map_zerosize(&solv->cleandepsmap);
3271   map_zerosize(&solv->weakrulemap);
3272   queue_empty(&solv->weakruleq);
3273   solv->watches = solv_free(solv->watches);
3274   queue_empty(&solv->ruletojob);
3275   if (solv->decisionq.count)
3276     memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
3277   queue_empty(&solv->decisionq);
3278   queue_empty(&solv->decisionq_why);
3279   solv->decisioncnt_update = solv->decisioncnt_keep = solv->decisioncnt_resolve = solv->decisioncnt_weak = solv->decisioncnt_orphan = 0;
3280   queue_empty(&solv->learnt_why);
3281   queue_empty(&solv->learnt_pool);
3282   queue_empty(&solv->branches);
3283   solv->propagate_index = 0;
3284   queue_empty(&solv->problems);
3285   queue_empty(&solv->solutions);
3286   queue_empty(&solv->orphaned);
3287   solv->stats_learned = solv->stats_unsolvable = 0;
3288   if (solv->recommends_index)
3289     {
3290       map_empty(&solv->recommendsmap);
3291       map_empty(&solv->suggestsmap);
3292       queuep_free(&solv->recommendscplxq);
3293       queuep_free(&solv->suggestscplxq);
3294       solv->recommends_index = 0;
3295     }
3296   solv->specialupdaters = solv_free(solv->specialupdaters);
3297
3298
3299   /*
3300    * create basic rule set of all involved packages
3301    * use addedmap bitmap to make sure we don't create rules twice
3302    */
3303
3304   /* create multiversion map if needed */
3305   solver_calculate_multiversionmap(pool, job, &solv->multiversion);
3306
3307   map_init(&addedmap, pool->nsolvables);
3308   MAPSET(&addedmap, SYSTEMSOLVABLE);
3309
3310   map_init(&installcandidatemap, pool->nsolvables);
3311   queue_init(&q);
3312
3313   now = solv_timems(0);
3314   /*
3315    * create rules for all package that could be involved with the solving
3316    * so called: rpm rules
3317    *
3318    */
3319   initialnrules = solv->rpmrules_end ? solv->rpmrules_end : 1;
3320   if (initialnrules > 1)
3321     deduceq2addedmap(solv, &addedmap);
3322   if (solv->nrules != initialnrules)
3323     solver_shrinkrules(solv, initialnrules);
3324   solv->nrules = initialnrules;
3325   solv->rpmrules_end = 0;
3326
3327   if (installed)
3328     {
3329       /* check for update/verify jobs as they need to be known early */
3330       for (i = 0; i < job->count; i += 2)
3331         {
3332           how = job->elements[i];
3333           what = job->elements[i + 1];
3334           select = how & SOLVER_SELECTMASK;
3335           switch (how & SOLVER_JOBMASK)
3336             {
3337             case SOLVER_VERIFY:
3338               if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3339                 solv->fixmap_all = 1;
3340               FOR_JOB_SELECT(p, pp, select, what)
3341                 {
3342                   s = pool->solvables + p;
3343                   if (s->repo != installed)
3344                     continue;
3345                   if (!solv->fixmap.size)
3346                     map_grow(&solv->fixmap, installed->end - installed->start);
3347                   MAPSET(&solv->fixmap, p - installed->start);
3348                 }
3349               break;
3350             case SOLVER_UPDATE:
3351               if (select == SOLVER_SOLVABLE_ALL)
3352                 {
3353                   solv->updatemap_all = 1;
3354                   if (how & SOLVER_FORCEBEST)
3355                     solv->bestupdatemap_all = 1;
3356                   if (how & SOLVER_CLEANDEPS)
3357                     {
3358                       FOR_REPO_SOLVABLES(installed, p, s)
3359                         add_cleandeps_package(solv, p);
3360                     }
3361                 }
3362               else if (select == SOLVER_SOLVABLE_REPO)
3363                 {
3364                   Repo *repo = pool_id2repo(pool, what);
3365                   if (!repo)
3366                     break;
3367                   if (repo == installed && !(how & SOLVER_TARGETED))
3368                     {
3369                       solv->updatemap_all = 1;
3370                       if (how & SOLVER_FORCEBEST)
3371                         solv->bestupdatemap_all = 1;
3372                       if (how & SOLVER_CLEANDEPS)
3373                         {
3374                           FOR_REPO_SOLVABLES(installed, p, s)
3375                             add_cleandeps_package(solv, p);
3376                         }
3377                       break;
3378                     }
3379                   if (solv->noautotarget && !(how & SOLVER_TARGETED))
3380                     break;
3381                   /* targeted update */
3382                   FOR_REPO_SOLVABLES(repo, p, s)
3383                     add_update_target(solv, p, how);
3384                 }
3385               else
3386                 {
3387                   if (!(how & SOLVER_TARGETED))
3388                     {
3389                       int targeted = 1;
3390                       FOR_JOB_SELECT(p, pp, select, what)
3391                         {
3392                           s = pool->solvables + p;
3393                           if (s->repo != installed)
3394                             continue;
3395                           if (!solv->updatemap.size)
3396                             map_grow(&solv->updatemap, installed->end - installed->start);
3397                           MAPSET(&solv->updatemap, p - installed->start);
3398                           if (how & SOLVER_FORCEBEST)
3399                             {
3400                               if (!solv->bestupdatemap.size)
3401                                 map_grow(&solv->bestupdatemap, installed->end - installed->start);
3402                               MAPSET(&solv->bestupdatemap, p - installed->start);
3403                             }
3404                           if (how & SOLVER_CLEANDEPS)
3405                             add_cleandeps_package(solv, p);
3406                           targeted = 0;
3407                         }
3408                       if (!targeted || solv->noautotarget)
3409                         break;
3410                     }
3411                   FOR_JOB_SELECT(p, pp, select, what)
3412                     add_update_target(solv, p, how);
3413                 }
3414               break;
3415             default:
3416               break;
3417             }
3418         }
3419
3420       if (solv->update_targets)
3421         transform_update_targets(solv);
3422
3423       oldnrules = solv->nrules;
3424       FOR_REPO_SOLVABLES(installed, p, s)
3425         solver_addrpmrulesforsolvable(solv, s, &addedmap);
3426       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for installed solvables\n", solv->nrules - oldnrules);
3427       oldnrules = solv->nrules;
3428       FOR_REPO_SOLVABLES(installed, p, s)
3429         solver_addrpmrulesforupdaters(solv, s, &addedmap, 1);
3430       POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for updaters of installed solvables\n", solv->nrules - oldnrules);
3431     }
3432
3433   /*
3434    * create rules for all packages involved in the job
3435    * (to be installed or removed)
3436    */
3437
3438   oldnrules = solv->nrules;
3439   for (i = 0; i < job->count; i += 2)
3440     {
3441       how = job->elements[i];
3442       what = job->elements[i + 1];
3443       select = how & SOLVER_SELECTMASK;
3444
3445       switch (how & SOLVER_JOBMASK)
3446         {
3447         case SOLVER_INSTALL:
3448           FOR_JOB_SELECT(p, pp, select, what)
3449             {
3450               MAPSET(&installcandidatemap, p);
3451               solver_addrpmrulesforsolvable(solv, pool->solvables + p, &addedmap);
3452             }
3453           break;
3454         case SOLVER_DISTUPGRADE:
3455           if (select == SOLVER_SOLVABLE_ALL)
3456             {
3457               solv->dupmap_all = 1;
3458               solv->updatemap_all = 1;
3459               if (how & SOLVER_FORCEBEST)
3460                 solv->bestupdatemap_all = 1;
3461             }
3462           if (!solv->dupmap_all)
3463             hasdupjob = 1;
3464           break;
3465         default:
3466           break;
3467         }
3468     }
3469   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules for packages involved in a job\n", solv->nrules - oldnrules);
3470
3471
3472   /*
3473    * add rules for suggests, enhances
3474    */
3475   oldnrules = solv->nrules;
3476   solver_addrpmrulesforweak(solv, &addedmap);
3477   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of weak dependencies\n", solv->nrules - oldnrules);
3478
3479 #ifdef ENABLE_LINKED_PKGS
3480   oldnrules = solv->nrules;
3481   solver_addrpmrulesforlinked(solv, &addedmap);
3482   POOL_DEBUG(SOLV_DEBUG_STATS, "added %d rpm rules because of linked packages\n", solv->nrules - oldnrules);
3483 #endif
3484
3485   /*
3486    * first pass done, we now have all the rpm rules we need.
3487    * unify existing rules before going over all job rules and
3488    * policy rules.
3489    * at this point the system is always solvable,
3490    * as an empty system (remove all packages) is a valid solution
3491    */
3492
3493   IF_POOLDEBUG (SOLV_DEBUG_STATS)
3494     {
3495       int possible = 0, installable = 0;
3496       for (i = 1; i < pool->nsolvables; i++)
3497         {
3498           if (pool_installable(pool, pool->solvables + i))
3499             installable++;
3500           if (MAPTST(&addedmap, i))
3501             possible++;
3502         }
3503       POOL_DEBUG(SOLV_DEBUG_STATS, "%d of %d installable solvables considered for solving\n", possible, installable);
3504     }
3505
3506   if (solv->nrules > initialnrules)
3507     solver_unifyrules(solv);                    /* remove duplicate rpm rules */
3508   solv->rpmrules_end = solv->nrules;            /* mark end of rpm rules */
3509
3510   if (solv->nrules > initialnrules)
3511     addedmap2deduceq(solv, &addedmap);          /* so that we can recreate the addedmap */
3512
3513   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3514   POOL_DEBUG(SOLV_DEBUG_STATS, "rpm rule creation took %d ms\n", solv_timems(now));
3515
3516   /* create dup maps if needed. We need the maps early to create our
3517    * update rules */
3518   if (hasdupjob)
3519     solver_createdupmaps(solv);
3520
3521   /*
3522    * create feature rules
3523    *
3524    * foreach installed:
3525    *   create assertion (keep installed, if no update available)
3526    *   or
3527    *   create update rule (A|update1(A)|update2(A)|...)
3528    *
3529    * those are used later on to keep a version of the installed packages in
3530    * best effort mode
3531    */
3532
3533   solv->featurerules = solv->nrules;              /* mark start of feature rules */
3534   if (installed)
3535     {
3536       /* foreach possibly installed solvable */
3537       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3538         {
3539           if (s->repo != installed)
3540             {
3541               solver_addrule(solv, 0, 0);       /* create dummy rule */
3542               continue;
3543             }
3544           solver_addupdaterule(solv, s, 1);    /* allow s to be updated */
3545         }
3546       /* make sure we accounted for all rules */
3547       assert(solv->nrules - solv->featurerules == installed->end - installed->start);
3548     }
3549   solv->featurerules_end = solv->nrules;
3550
3551     /*
3552      * Add update rules for installed solvables
3553      *
3554      * almost identical to feature rules
3555      * except that downgrades/archchanges/vendorchanges are not allowed
3556      */
3557
3558   solv->updaterules = solv->nrules;
3559
3560   if (installed)
3561     { /* foreach installed solvables */
3562       /* we create all update rules, but disable some later on depending on the job */
3563       for (i = installed->start, s = pool->solvables + i; i < installed->end; i++, s++)
3564         {
3565           Rule *sr;
3566
3567           if (s->repo != installed)
3568             {
3569               solver_addrule(solv, 0, 0);       /* create dummy rule */
3570               continue;
3571             }
3572           solver_addupdaterule(solv, s, 0);     /* allowall = 0: downgrades not allowed */
3573           /*
3574            * check for and remove duplicate
3575            */
3576           r = solv->rules + solv->nrules - 1;           /* r: update rule */
3577           sr = r - (installed->end - installed->start); /* sr: feature rule */
3578           /* it's orphaned if there is no feature rule or the feature rule
3579            * consists just of the installed package */
3580           if (!sr->p || (sr->p == i && !sr->d && !sr->w2))
3581             queue_push(&solv->orphaned, i);
3582           if (!r->p)
3583             {
3584               /* assert(solv->dupmap_all && !sr->p); */
3585               continue;
3586             }
3587           if (!solver_rulecmp(solv, r, sr))
3588             memset(sr, 0, sizeof(*sr));         /* delete unneeded feature rule */
3589           else
3590             solver_disablerule(solv, sr);       /* disable feature rule */
3591         }
3592       /* consistency check: we added a rule for _every_ installed solvable */
3593       assert(solv->nrules - solv->updaterules == installed->end - installed->start);
3594     }
3595   solv->updaterules_end = solv->nrules;
3596
3597
3598   /*
3599    * now add all job rules
3600    */
3601
3602   solv->jobrules = solv->nrules;
3603   for (i = 0; i < job->count; i += 2)
3604     {
3605       oldnrules = solv->nrules;
3606
3607       if (i && i == solv->pooljobcnt)
3608         POOL_DEBUG(SOLV_DEBUG_JOB, "end of pool jobs\n");
3609       how = job->elements[i];
3610       what = job->elements[i + 1];
3611       weak = how & SOLVER_WEAK;
3612       select = how & SOLVER_SELECTMASK;
3613       switch (how & SOLVER_JOBMASK)
3614         {
3615         case SOLVER_INSTALL:
3616           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sinstall %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3617           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3618             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3619           if (select == SOLVER_SOLVABLE)
3620             {
3621               p = what;
3622               d = 0;
3623             }
3624           else
3625             {
3626               queue_empty(&q);
3627               FOR_JOB_SELECT(p, pp, select, what)
3628                 queue_push(&q, p);
3629               if (!q.count)
3630                 {
3631                   if (select == SOLVER_SOLVABLE_ONE_OF)
3632                     break;      /* ignore empty installs */
3633                   /* no candidate found or unsupported, make this an impossible rule */
3634                   queue_push(&q, -SYSTEMSOLVABLE);
3635                 }
3636               p = queue_shift(&q);      /* get first candidate */
3637               d = !q.count ? 0 : pool_queuetowhatprovides(pool, &q);    /* internalize */
3638             }
3639           /* force install of namespace supplements hack */
3640           if (select == SOLVER_SOLVABLE_PROVIDES && !d && (p == SYSTEMSOLVABLE || p == -SYSTEMSOLVABLE) && ISRELDEP(what))
3641             {
3642               Reldep *rd = GETRELDEP(pool, what);
3643               if (rd->flags == REL_NAMESPACE)
3644                 {
3645                   p = SYSTEMSOLVABLE;
3646                   if (!solv->installsuppdepq)
3647                     {
3648                       solv->installsuppdepq = solv_calloc(1, sizeof(Queue));
3649                       queue_init(solv->installsuppdepq);
3650                     }
3651                   queue_pushunique(solv->installsuppdepq, rd->evr == 0 ? rd->name : what);
3652                 }
3653             }
3654           solver_addjobrule(solv, p, d, i, weak);
3655           if (how & SOLVER_FORCEBEST)
3656             hasbestinstalljob = 1;
3657           break;
3658         case SOLVER_ERASE:
3659           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %s%serase %s\n", weak ? "weak " : "", how & SOLVER_CLEANDEPS ? "clean deps " : "", solver_select2str(pool, select, what));
3660           if ((how & SOLVER_CLEANDEPS) != 0 && !solv->cleandepsmap.size && installed)
3661             map_grow(&solv->cleandepsmap, installed->end - installed->start);
3662           /* specific solvable: by id or by nevra */
3663           name = (select == SOLVER_SOLVABLE || (select == SOLVER_SOLVABLE_NAME && ISRELDEP(what))) ? 0 : -1;
3664           if (select == SOLVER_SOLVABLE_ALL)    /* hmmm ;) */
3665             {
3666               FOR_POOL_SOLVABLES(p)
3667                 solver_addjobrule(solv, -p, 0, i, weak);
3668             }
3669           else if (select == SOLVER_SOLVABLE_REPO)
3670             {
3671               Repo *repo = pool_id2repo(pool, what);
3672               if (repo)
3673                 FOR_REPO_SOLVABLES(repo, p, s)
3674                   solver_addjobrule(solv, -p, 0, i, weak);
3675             }
3676           FOR_JOB_SELECT(p, pp, select, what)
3677             {
3678               s = pool->solvables + p;
3679               if (installed && s->repo == installed)
3680                 name = !name ? s->name : -1;
3681               solver_addjobrule(solv, -p, 0, i, weak);
3682             }
3683           /* special case for "erase a specific solvable": we also
3684            * erase all other solvables with that name, so that they
3685            * don't get picked up as replacement.
3686            * name is > 0 if exactly one installed solvable matched.
3687            */
3688           /* XXX: look also at packages that obsolete this package? */
3689           if (name > 0)
3690             {
3691               int j, k;
3692               k = solv->nrules;
3693               FOR_PROVIDES(p, pp, name)
3694                 {
3695                   s = pool->solvables + p;
3696                   if (s->name != name)
3697                     continue;
3698                   /* keep other versions installed */
3699                   if (s->repo == installed)
3700                     continue;
3701                   /* keep installcandidates of other jobs */
3702                   if (MAPTST(&installcandidatemap, p))
3703                     continue;
3704                   /* don't add the same rule twice */
3705                   for (j = oldnrules; j < k; j++)
3706                     if (solv->rules[j].p == -p)
3707                       break;
3708                   if (j == k)
3709                     solver_addjobrule(solv, -p, 0, i, weak);    /* remove by id */
3710                 }
3711             }
3712           break;
3713
3714         case SOLVER_UPDATE:
3715           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %supdate %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3716           break;
3717         case SOLVER_VERIFY:
3718           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sverify %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3719           break;
3720         case SOLVER_WEAKENDEPS:
3721           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %sweaken deps %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3722           if (select != SOLVER_SOLVABLE)
3723             break;
3724           s = pool->solvables + what;
3725           weaken_solvable_deps(solv, what);
3726           break;
3727         case SOLVER_MULTIVERSION:
3728           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %smultiversion %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3729           break;
3730         case SOLVER_LOCK:
3731           POOL_DEBUG(SOLV_DEBUG_JOB, "job: %slock %s\n", weak ? "weak " : "", solver_select2str(pool, select, what));
3732           if (select == SOLVER_SOLVABLE_ALL)
3733             {
3734               FOR_POOL_SOLVABLES(p)
3735                 solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3736             }
3737           else if (select == SOLVER_SOLVABLE_REPO)
3738             {
3739               Repo *repo = pool_id2repo(pool, what);
3740               if (repo)
3741                 FOR_REPO_SOLVABLES(repo, p, s)
3742                   solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3743             }
3744           FOR_JOB_SELECT(p, pp, select, what)
3745             solver_addjobrule(solv, installed && pool->solvables[p].repo == installed ? p : -p, 0, i, weak);
3746           break;
3747         case SOLVER_DISTUPGRADE:
3748           POOL_DEBUG(SOLV_DEBUG_JOB, "job: distupgrade %s\n", solver_select2str(pool, select, what));
3749           break;
3750         case SOLVER_DROP_ORPHANED:
3751           POOL_DEBUG(SOLV_DEBUG_JOB, "job: drop orphaned %s\n", solver_select2str(pool, select, what));
3752           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && installed && what == installed->repoid))
3753             solv->droporphanedmap_all = 1;
3754           FOR_JOB_SELECT(p, pp, select, what)
3755             {
3756               s = pool->solvables + p;
3757               if (!installed || s->repo != installed)
3758                 continue;
3759               if (!solv->droporphanedmap.size)
3760                 map_grow(&solv->droporphanedmap, installed->end - installed->start);
3761               MAPSET(&solv->droporphanedmap, p - installed->start);
3762             }
3763           break;
3764         case SOLVER_USERINSTALLED:
3765           POOL_DEBUG(SOLV_DEBUG_JOB, "job: user installed %s\n", solver_select2str(pool, select, what));
3766           break;
3767         default:
3768           POOL_DEBUG(SOLV_DEBUG_JOB, "job: unknown job\n");
3769           break;
3770         }
3771         
3772         /*
3773          * debug
3774          */
3775         
3776       IF_POOLDEBUG (SOLV_DEBUG_JOB)
3777         {
3778           int j;
3779           if (solv->nrules == oldnrules)
3780             POOL_DEBUG(SOLV_DEBUG_JOB, "  - no rule created\n");
3781           for (j = oldnrules; j < solv->nrules; j++)
3782             {
3783               POOL_DEBUG(SOLV_DEBUG_JOB, "  - job ");
3784               solver_printrule(solv, SOLV_DEBUG_JOB, solv->rules + j);
3785             }
3786         }
3787     }
3788   assert(solv->ruletojob.count == solv->nrules - solv->jobrules);
3789   solv->jobrules_end = solv->nrules;
3790
3791   /* now create infarch and dup rules */
3792   if (!solv->noinfarchcheck)
3793     {
3794       solver_addinfarchrules(solv, &addedmap);
3795 #if 0
3796       if (pool->implicitobsoleteusescolors)
3797         {
3798           /* currently doesn't work well with infarch rules, so make
3799            * them weak */
3800           for (i = solv->infarchrules; i < solv->infarchrules_end; i++)
3801             queue_push(&solv->weakruleq, i);
3802         }
3803 #endif
3804     }
3805   else
3806     solv->infarchrules = solv->infarchrules_end = solv->nrules;
3807
3808   if (hasdupjob)
3809     solver_addduprules(solv, &addedmap);
3810   else
3811     solv->duprules = solv->duprules_end = solv->nrules;
3812
3813   if (solv->bestupdatemap_all || solv->bestupdatemap.size || hasbestinstalljob)
3814     solver_addbestrules(solv, hasbestinstalljob);
3815   else
3816     solv->bestrules = solv->bestrules_end = solv->nrules;
3817
3818   if (hasdupjob)
3819     solver_freedupmaps(solv);   /* no longer needed */
3820
3821   if (1)
3822     solver_addchoicerules(solv);
3823   else
3824     solv->choicerules = solv->choicerules_end = solv->nrules;
3825
3826   if (0)
3827     {
3828       for (i = solv->featurerules; i < solv->nrules; i++)
3829         solver_printruleclass(solv, SOLV_DEBUG_RESULT, solv->rules + i);
3830     }
3831   /* all rules created
3832    * --------------------------------------------------------------
3833    * prepare for solving
3834    */
3835
3836   /* free unneeded memory */
3837   map_free(&addedmap);
3838   map_free(&installcandidatemap);
3839   queue_free(&q);
3840
3841   POOL_DEBUG(SOLV_DEBUG_STATS, "%d rpm rules, 2 * %d update rules, %d job rules, %d infarch rules, %d dup rules, %d choice rules, %d best rules\n", solv->rpmrules_end - 1, solv->updaterules_end - solv->updaterules, solv->jobrules_end - solv->jobrules, solv->infarchrules_end - solv->infarchrules, solv->duprules_end - solv->duprules, solv->choicerules_end - solv->choicerules, solv->bestrules_end - solv->bestrules);
3842   POOL_DEBUG(SOLV_DEBUG_STATS, "overall rule memory used: %d K\n", solv->nrules * (int)sizeof(Rule) / 1024);
3843
3844   /* create weak map */
3845   map_init(&solv->weakrulemap, solv->nrules);
3846   for (i = 0; i < solv->weakruleq.count; i++)
3847     {
3848       p = solv->weakruleq.elements[i];
3849       MAPSET(&solv->weakrulemap, p);
3850     }
3851
3852   /* enable cleandepsmap creation if we have updatepkgs */
3853   if (solv->cleandeps_updatepkgs && !solv->cleandepsmap.size)
3854     map_grow(&solv->cleandepsmap, installed->end - installed->start);
3855   /* no mistakes */
3856   if (solv->cleandeps_mistakes)
3857     {
3858       queue_free(solv->cleandeps_mistakes);
3859       solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
3860     }
3861
3862   /* all new rules are learnt after this point */
3863   solv->learntrules = solv->nrules;
3864
3865   /* create watches chains */
3866   makewatches(solv);
3867
3868   /* create assertion index. it is only used to speed up
3869    * makeruledecsions() a bit */
3870   for (i = 1, r = solv->rules + i; i < solv->nrules; i++, r++)
3871     if (r->p && !r->w2 && (r->d == 0 || r->d == -1))
3872       queue_push(&solv->ruleassertions, i);
3873
3874   /* disable update rules that conflict with our job */
3875   solver_disablepolicyrules(solv);
3876
3877   /* make initial decisions based on assertion rules */
3878   makeruledecisions(solv);
3879   POOL_DEBUG(SOLV_DEBUG_SOLVER, "problems so far: %d\n", solv->problems.count);
3880
3881   /*
3882    * ********************************************
3883    * solve!
3884    * ********************************************
3885    */
3886
3887   now = solv_timems(0);
3888   solver_run_sat(solv, 1, solv->dontinstallrecommended ? 0 : 1);
3889   POOL_DEBUG(SOLV_DEBUG_STATS, "solver took %d ms\n", solv_timems(now));
3890
3891   /*
3892    * prepare solution queue if there were problems
3893    */
3894   solver_prepare_solutions(solv);
3895
3896   POOL_DEBUG(SOLV_DEBUG_STATS, "final solver statistics: %d problems, %d learned rules, %d unsolvable\n", solv->problems.count / 2, solv->stats_learned, solv->stats_unsolvable);
3897   POOL_DEBUG(SOLV_DEBUG_STATS, "solver_solve took %d ms\n", solv_timems(solve_start));
3898
3899   /* return number of problems */
3900   return solv->problems.count ? solv->problems.count / 2 : 0;
3901 }
3902
3903 Transaction *
3904 solver_create_transaction(Solver *solv)
3905 {
3906   return transaction_create_decisionq(solv->pool, &solv->decisionq, &solv->multiversion);
3907 }
3908
3909 void solver_get_orphaned(Solver *solv, Queue *orphanedq)
3910 {
3911   queue_free(orphanedq);
3912   queue_init_clone(orphanedq, &solv->orphaned);
3913 }
3914
3915 void solver_get_recommendations(Solver *solv, Queue *recommendationsq, Queue *suggestionsq, int noselected)
3916 {
3917   Pool *pool = solv->pool;
3918   Queue redoq, disabledq;
3919   int goterase, i;
3920   Solvable *s;
3921   Rule *r;
3922   Map obsmap;
3923
3924   if (!recommendationsq && !suggestionsq)
3925     return;
3926
3927   map_init(&obsmap, pool->nsolvables);
3928   if (solv->installed)
3929     {
3930       Id obs, *obsp, p, po, ppo;
3931       for (p = solv->installed->start; p < solv->installed->end; p++)
3932         {
3933           s = pool->solvables + p;
3934           if (s->repo != solv->installed || !s->obsoletes)
3935             continue;
3936           if (solv->decisionmap[p] <= 0)
3937             continue;
3938           if (solv->multiversion.size && MAPTST(&solv->multiversion, p))
3939             continue;
3940           obsp = s->repo->idarraydata + s->obsoletes;
3941           /* foreach obsoletes */
3942           while ((obs = *obsp++) != 0)
3943             FOR_PROVIDES(po, ppo, obs)
3944               MAPSET(&obsmap, po);
3945         }
3946     }
3947
3948   queue_init(&redoq);
3949   queue_init(&disabledq);
3950   goterase = 0;
3951   /* disable all erase jobs (including weak "keep uninstalled" rules) */
3952   for (i = solv->jobrules, r = solv->rules + i; i < solv->jobrules_end; i++, r++)
3953     {
3954       if (r->d < 0)     /* disabled ? */
3955         continue;
3956       if (r->p >= 0)    /* install job? */
3957         continue;
3958       queue_push(&disabledq, i);
3959       solver_disablerule(solv, r);
3960       goterase++;
3961     }
3962
3963   if (goterase)
3964     {
3965       enabledisablelearntrules(solv);
3966       removedisabledconflicts(solv, &redoq);
3967     }
3968
3969   /*
3970    * find recommended packages
3971    */
3972   if (recommendationsq)
3973     {
3974       Id rec, *recp, p, pp;
3975
3976       queue_empty(recommendationsq);
3977       /* create map of all recommened packages */
3978       solv->recommends_index = -1;
3979       MAPZERO(&solv->recommendsmap);
3980
3981       /* put all packages the solver already chose in the map */
3982       if (solv->decisioncnt_weak)
3983         {
3984           for (i = solv->decisioncnt_weak; i < solv->decisioncnt_orphan; i++)
3985             {
3986               Id why;
3987               why = solv->decisionq_why.elements[i];
3988               if (why)
3989                 continue;       /* forced by unit rule or dep resolving */
3990               p = solv->decisionq.elements[i];
3991               if (p < 0)
3992                 continue;
3993               MAPSET(&solv->recommendsmap, p);
3994             }
3995         }
3996
3997       for (i = 0; i < solv->decisionq.count; i++)
3998         {
3999           p = solv->decisionq.elements[i];
4000           if (p < 0)
4001             continue;
4002           s = pool->solvables + p;
4003           if (s->recommends)
4004             {
4005               recp = s->repo->idarraydata + s->recommends;
4006               while ((rec = *recp++) != 0)
4007                 {
4008 #ifdef ENABLE_COMPLEX_DEPS
4009                   if (pool_is_complex_dep(pool, rec))
4010                     {
4011                       do_complex_recommendations(solv, rec, &solv->recommendsmap, noselected);
4012                       continue;
4013                     }
4014 #endif
4015                   FOR_PROVIDES(p, pp, rec)
4016                     if (solv->decisionmap[p] > 0)
4017                       break;
4018                   if (p)
4019                     {
4020                       if (!noselected)
4021                         {
4022                           FOR_PROVIDES(p, pp, rec)
4023                             if (solv->decisionmap[p] > 0)
4024                               MAPSET(&solv->recommendsmap, p);
4025                         }
4026                       continue; /* p != 0: already fulfilled */
4027                     }
4028                   FOR_PROVIDES(p, pp, rec)
4029                     MAPSET(&solv->recommendsmap, p);
4030                 }
4031             }
4032         }
4033       for (i = 1; i < pool->nsolvables; i++)
4034         {
4035           if (solv->decisionmap[i] < 0)
4036             continue;
4037           if (solv->decisionmap[i] > 0 && noselected)
4038             continue;
4039           if (MAPTST(&obsmap, i))
4040             continue;
4041           s = pool->solvables + i;
4042           if (!MAPTST(&solv->recommendsmap, i))
4043             {
4044               if (!s->supplements)
4045                 continue;
4046               if (!pool_installable(pool, s))
4047                 continue;
4048               if (!solver_is_supplementing(solv, s))
4049                 continue;
4050             }
4051           queue_push(recommendationsq, i);
4052         }
4053       /* we use MODE_SUGGEST here so that repo prio is ignored */
4054       policy_filter_unwanted(solv, recommendationsq, POLICY_MODE_SUGGEST);
4055     }
4056
4057   /*
4058    * find suggested packages
4059    */
4060
4061   if (suggestionsq)
4062     {
4063       Id sug, *sugp, p, pp;
4064
4065       queue_empty(suggestionsq);
4066       /* create map of all suggests that are still open */
4067       solv->recommends_index = -1;
4068       MAPZERO(&solv->suggestsmap);
4069       for (i = 0; i < solv->decisionq.count; i++)
4070         {
4071           p = solv->decisionq.elements[i];
4072           if (p < 0)
4073             continue;
4074           s = pool->solvables + p;
4075           if (s->suggests)
4076             {
4077               sugp = s->repo->idarraydata + s->suggests;
4078               while ((sug = *sugp++) != 0)
4079                 {
4080 #ifdef ENABLE_COMPLEX_DEPS
4081                   if (pool_is_complex_dep(pool, sug))
4082                     {
4083                       do_complex_recommendations(solv, sug, &solv->suggestsmap, noselected);
4084                       continue;
4085                     }
4086 #endif
4087                   FOR_PROVIDES(p, pp, sug)
4088                     if (solv->decisionmap[p] > 0)
4089                       break;
4090                   if (p)
4091                     {
4092                       if (!noselected)
4093                         {
4094                           FOR_PROVIDES(p, pp, sug)
4095                             if (solv->decisionmap[p] > 0)
4096                               MAPSET(&solv->suggestsmap, p);
4097                         }
4098                       continue; /* already fulfilled */
4099                     }
4100                   FOR_PROVIDES(p, pp, sug)
4101                     MAPSET(&solv->suggestsmap, p);
4102                 }
4103             }
4104         }
4105       for (i = 1; i < pool->nsolvables; i++)
4106         {
4107           if (solv->decisionmap[i] < 0)
4108             continue;
4109           if (solv->decisionmap[i] > 0 && noselected)
4110             continue;
4111           if (MAPTST(&obsmap, i))
4112             continue;
4113           s = pool->solvables + i;
4114           if (!MAPTST(&solv->suggestsmap, i))
4115             {
4116               if (!s->enhances)
4117                 continue;
4118               if (!pool_installable(pool, s))
4119                 continue;
4120               if (!solver_is_enhancing(solv, s))
4121                 continue;
4122             }
4123           queue_push(suggestionsq, i);
4124         }
4125       policy_filter_unwanted(solv, suggestionsq, POLICY_MODE_SUGGEST);
4126     }
4127
4128   /* undo removedisabledconflicts */
4129   if (redoq.count)
4130     undo_removedisabledconflicts(solv, &redoq);
4131   queue_free(&redoq);
4132
4133   /* undo job rule disabling */
4134   for (i = 0; i < disabledq.count; i++)
4135     solver_enablerule(solv, solv->rules + disabledq.elements[i]);
4136   queue_free(&disabledq);
4137   map_free(&obsmap);
4138 }
4139
4140
4141 /***********************************************************************/
4142 /* disk usage computations */
4143
4144 /*-------------------------------------------------------------------
4145  *
4146  * calculate DU changes
4147  */
4148
4149 void
4150 solver_calc_duchanges(Solver *solv, DUChanges *mps, int nmps)
4151 {
4152   Map installedmap;
4153
4154   solver_create_state_maps(solv, &installedmap, 0);
4155   pool_calc_duchanges(solv->pool, &installedmap, mps, nmps);
4156   map_free(&installedmap);
4157 }
4158
4159
4160 /*-------------------------------------------------------------------
4161  *
4162  * calculate changes in install size
4163  */
4164
4165 int
4166 solver_calc_installsizechange(Solver *solv)
4167 {
4168   Map installedmap;
4169   int change;
4170
4171   solver_create_state_maps(solv, &installedmap, 0);
4172   change = pool_calc_installsizechange(solv->pool, &installedmap);
4173   map_free(&installedmap);
4174   return change;
4175 }
4176
4177 void
4178 solver_create_state_maps(Solver *solv, Map *installedmap, Map *conflictsmap)
4179 {
4180   pool_create_state_maps(solv->pool, &solv->decisionq, installedmap, conflictsmap);
4181 }
4182
4183 void
4184 solver_trivial_installable(Solver *solv, Queue *pkgs, Queue *res)
4185 {
4186   Pool *pool = solv->pool;
4187   Map installedmap;
4188   int i;
4189   pool_create_state_maps(pool,  &solv->decisionq, &installedmap, 0);
4190   pool_trivial_installable_multiversionmap(pool, &installedmap, pkgs, res, solv->multiversion.size ? &solv->multiversion : 0);
4191   for (i = 0; i < res->count; i++)
4192     if (res->elements[i] != -1)
4193       {
4194         Solvable *s = pool->solvables + pkgs->elements[i];
4195         if (!strncmp("patch:", pool_id2str(pool, s->name), 6) && solvable_is_irrelevant_patch(s, &installedmap))
4196           res->elements[i] = -1;
4197       }
4198   map_free(&installedmap);
4199 }
4200
4201 /*-------------------------------------------------------------------
4202  *
4203  * decision introspection
4204  */
4205
4206 int
4207 solver_get_decisionlevel(Solver *solv, Id p)
4208 {
4209   return solv->decisionmap[p];
4210 }
4211
4212 void
4213 solver_get_decisionqueue(Solver *solv, Queue *decisionq)
4214 {
4215   queue_free(decisionq);
4216   queue_init_clone(decisionq, &solv->decisionq);
4217 }
4218
4219 int
4220 solver_get_lastdecisionblocklevel(Solver *solv)
4221 {
4222   Id p;
4223   if (solv->decisionq.count == 0)
4224     return 0;
4225   p = solv->decisionq.elements[solv->decisionq.count - 1];
4226   if (p < 0)
4227     p = -p;
4228   return solv->decisionmap[p] < 0 ? -solv->decisionmap[p] : solv->decisionmap[p];
4229 }
4230
4231 void
4232 solver_get_decisionblock(Solver *solv, int level, Queue *decisionq)
4233 {
4234   Id p;
4235   int i;
4236
4237   queue_empty(decisionq);
4238   for (i = 0; i < solv->decisionq.count; i++)
4239     {
4240       p = solv->decisionq.elements[i];
4241       if (p < 0)
4242         p = -p;
4243       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
4244         break;
4245     }
4246   if (i == solv->decisionq.count)
4247     return;
4248   for (i = 0; i < solv->decisionq.count; i++)
4249     {
4250       p = solv->decisionq.elements[i];
4251       if (p < 0)
4252         p = -p;
4253       if (solv->decisionmap[p] == level || solv->decisionmap[p] == -level)
4254         queue_push(decisionq, p);
4255       else
4256         break;
4257     }
4258 }
4259
4260 int
4261 solver_describe_decision(Solver *solv, Id p, Id *infop)
4262 {
4263   int i;
4264   Id pp, why;
4265
4266   if (infop)
4267     *infop = 0;
4268   if (!solv->decisionmap[p])
4269     return SOLVER_REASON_UNRELATED;
4270   pp = solv->decisionmap[p] < 0 ? -p : p;
4271   for (i = 0; i < solv->decisionq.count; i++)
4272     if (solv->decisionq.elements[i] == pp)
4273       break;
4274   if (i == solv->decisionq.count)       /* just in case... */
4275     return SOLVER_REASON_UNRELATED;
4276   why = solv->decisionq_why.elements[i];
4277   if (infop)
4278     *infop = why > 0 ? why : -why;
4279   if (why > 0)
4280     return SOLVER_REASON_UNIT_RULE;
4281   why = -why;
4282   if (i < solv->decisioncnt_update)
4283     {
4284       if (i == 0)
4285         return SOLVER_REASON_KEEP_INSTALLED;
4286       return SOLVER_REASON_RESOLVE_JOB;
4287     }
4288   if (i < solv->decisioncnt_keep)
4289     {
4290       if (why == 0 && pp < 0)
4291         return SOLVER_REASON_CLEANDEPS_ERASE;
4292       return SOLVER_REASON_UPDATE_INSTALLED;
4293     }
4294   if (i < solv->decisioncnt_resolve)
4295     {
4296       if (why == 0 && pp < 0)
4297         return SOLVER_REASON_CLEANDEPS_ERASE;
4298       return SOLVER_REASON_KEEP_INSTALLED;
4299     }
4300   if (why > 0)
4301     return SOLVER_REASON_RESOLVE;
4302   /* weak or orphaned */
4303   if (solv->decisionq.count < solv->decisioncnt_orphan)
4304     return SOLVER_REASON_WEAKDEP;
4305   return SOLVER_REASON_RESOLVE_ORPHAN;
4306 }
4307
4308
4309 void
4310 solver_describe_weakdep_decision(Solver *solv, Id p, Queue *whyq)
4311 {
4312   Pool *pool = solv->pool;
4313   int i;
4314   int level = solv->decisionmap[p];
4315   int decisionno;
4316   Solvable *s;
4317
4318   queue_empty(whyq);
4319   if (level < 0)
4320     return;     /* huh? */
4321   for (decisionno = 0; decisionno < solv->decisionq.count; decisionno++)
4322     if (solv->decisionq.elements[decisionno] == p)
4323       break;
4324   if (decisionno == solv->decisionq.count)
4325     return;     /* huh? */
4326   if (decisionno < solv->decisioncnt_weak || decisionno >= solv->decisioncnt_orphan)
4327     return;     /* huh? */
4328
4329   /* 1) list all packages that recommend us */
4330   for (i = 1; i < pool->nsolvables; i++)
4331     {
4332       Id *recp, rec, pp2, p2;
4333       if (solv->decisionmap[i] < 0 || solv->decisionmap[i] >= level)
4334         continue;
4335       s = pool->solvables + i;
4336       if (!s->recommends)
4337         continue;
4338       if (!solv->addalreadyrecommended && s->repo == solv->installed)
4339         continue;
4340       recp = s->repo->idarraydata + s->recommends;
4341       while ((rec = *recp++) != 0)
4342         {
4343           int found = 0;
4344           FOR_PROVIDES(p2, pp2, rec)
4345             {
4346               if (p2 == p)
4347                 found = 1;
4348               else
4349                 {
4350                   /* if p2 is already installed, this recommends is ignored */
4351                   if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4352                     break;
4353                 }
4354             }
4355           if (!p2 && found)
4356             {
4357               queue_push(whyq, SOLVER_REASON_RECOMMENDED);
4358               queue_push2(whyq, p2, rec);
4359             }
4360         }
4361     }
4362   /* 2) list all supplements */
4363   s = pool->solvables + p;
4364   if (s->supplements && level > 0)
4365     {
4366       Id *supp, sup, pp2, p2;
4367       /* this is a hack. to use solver_dep_fulfilled we temporarily clear
4368        * everything above our level in the decisionmap */
4369       for (i = decisionno; i < solv->decisionq.count; i++ )
4370         {
4371           p2 = solv->decisionq.elements[i];
4372           if (p2 > 0)
4373             solv->decisionmap[p2] = -solv->decisionmap[p2];
4374         }
4375       supp = s->repo->idarraydata + s->supplements;
4376       while ((sup = *supp++) != 0)
4377         if (solver_dep_fulfilled(solv, sup))
4378           {
4379             int found = 0;
4380             /* let's see if this is an easy supp */
4381             FOR_PROVIDES(p2, pp2, sup)
4382               {
4383                 if (!solv->addalreadyrecommended && solv->installed)
4384                   {
4385                     if (pool->solvables[p2].repo == solv->installed)
4386                       continue;
4387                   }
4388                 if (solv->decisionmap[p2] > 0 && solv->decisionmap[p2] < level)
4389                   {
4390                     queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4391                     queue_push2(whyq, p2, sup);
4392                     found = 1;
4393                   }
4394               }
4395             if (!found)
4396               {
4397                 /* hard case, just note dependency with no package */
4398                 queue_push(whyq, SOLVER_REASON_SUPPLEMENTED);
4399                 queue_push2(whyq, 0, sup);
4400               }
4401           }
4402       for (i = decisionno; i < solv->decisionq.count; i++)
4403         {
4404           p2 = solv->decisionq.elements[i];
4405           if (p2 > 0)
4406             solv->decisionmap[p2] = -solv->decisionmap[p2];
4407         }
4408     }
4409 }
4410
4411 void
4412 pool_job2solvables(Pool *pool, Queue *pkgs, Id how, Id what)
4413 {
4414   Id p, pp;
4415   how &= SOLVER_SELECTMASK;
4416   queue_empty(pkgs);
4417   if (how == SOLVER_SOLVABLE_ALL)
4418     {
4419       FOR_POOL_SOLVABLES(p)
4420         queue_push(pkgs, p);
4421     }
4422   else if (how == SOLVER_SOLVABLE_REPO)
4423     {
4424       Repo *repo = pool_id2repo(pool, what);
4425       Solvable *s;
4426       if (repo)
4427         FOR_REPO_SOLVABLES(repo, p, s)
4428           queue_push(pkgs, p);
4429     }
4430   else
4431     {
4432       FOR_JOB_SELECT(p, pp, how, what)
4433         queue_push(pkgs, p);
4434     }
4435 }
4436
4437 int
4438 pool_isemptyupdatejob(Pool *pool, Id how, Id what)
4439 {
4440   Id p, pp, pi, pip;
4441   Id select = how & SOLVER_SELECTMASK;
4442   if ((how & SOLVER_JOBMASK) != SOLVER_UPDATE)
4443     return 0;
4444   if (select == SOLVER_SOLVABLE_ALL || select == SOLVER_SOLVABLE_REPO)
4445     return 0;
4446   if (!pool->installed)
4447     return 1;
4448   FOR_JOB_SELECT(p, pp, select, what)
4449     if (pool->solvables[p].repo == pool->installed)
4450       return 0;
4451   /* hard work */
4452   FOR_JOB_SELECT(p, pp, select, what)
4453     {
4454       Solvable *s = pool->solvables + p;
4455       FOR_PROVIDES(pi, pip, s->name)
4456         {
4457           Solvable *si = pool->solvables + pi;
4458           if (si->repo != pool->installed || si->name != s->name)
4459             continue;
4460           return 0;
4461         }
4462       if (s->obsoletes)
4463         {
4464           Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4465           while ((obs = *obsp++) != 0)
4466             {
4467               FOR_PROVIDES(pi, pip, obs)
4468                 {
4469                   Solvable *si = pool->solvables + pi;
4470                   if (si->repo != pool->installed)
4471                     continue;
4472                   if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, si, obs))
4473                     continue;
4474                   if (pool->obsoleteusescolors && !pool_colormatch(pool, s, si))
4475                     continue;
4476                   return 0;
4477                 }
4478             }
4479         }
4480     }
4481   return 1;
4482 }
4483
4484 static int
4485 get_userinstalled_cmp(const void *ap, const void *bp, void *dp)
4486 {
4487   return *(Id *)ap - *(Id *)bp;
4488 }
4489
4490 static int
4491 get_userinstalled_cmp_names(const void *ap, const void *bp, void *dp)
4492 {
4493   Pool *pool = dp;
4494   return strcmp(pool_id2str(pool, *(Id *)ap), pool_id2str(pool, *(Id *)bp));
4495 }
4496
4497 static void
4498 get_userinstalled_sort_uniq(Pool *pool, Queue *q, int flags)
4499 {
4500   Id lastp = -1;
4501   int i, j;
4502   if ((flags & GET_USERINSTALLED_NAMES) != 0)
4503     solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp_names, pool);
4504   else
4505     solv_sort(q->elements, q->count, sizeof(Id), get_userinstalled_cmp, 0);
4506   for (i = j = 0; i < q->count; i++)
4507     if (q->elements[i] != lastp)
4508       q->elements[j++] = lastp = q->elements[i];
4509   queue_truncate(q, j);
4510 }
4511
4512 void
4513 solver_get_userinstalled(Solver *solv, Queue *q, int flags)
4514 {
4515   Pool *pool = solv->pool;
4516   Id p, p2, pp;
4517   Solvable *s;
4518   Repo *installed = solv->installed;
4519   int i, j;
4520   Map userinstalled;
4521   
4522   map_init(&userinstalled, 0);
4523   queue_empty(q);
4524   /* first process jobs */
4525   for (i = 0; i < solv->job.count; i += 2)
4526     {
4527       Id how = solv->job.elements[i];
4528       Id what, select;
4529       if (installed && (how & SOLVER_JOBMASK) == SOLVER_USERINSTALLED)
4530         {
4531           if (!userinstalled.size)
4532             map_grow(&userinstalled, installed->end - installed->start);
4533           what = solv->job.elements[i + 1];
4534           select = how & SOLVER_SELECTMASK;
4535           if (select == SOLVER_SOLVABLE_ALL || (select == SOLVER_SOLVABLE_REPO && what == installed->repoid))
4536             FOR_REPO_SOLVABLES(installed, p, s)
4537               MAPSET(&userinstalled, p - installed->start);
4538           FOR_JOB_SELECT(p, pp, select, what)
4539             if (pool->solvables[p].repo == installed)
4540               MAPSET(&userinstalled, p - installed->start);
4541           continue;
4542         }
4543       if ((how & SOLVER_JOBMASK) != SOLVER_INSTALL)
4544         continue;
4545       if ((how & SOLVER_NOTBYUSER) != 0)
4546         continue;
4547       what = solv->job.elements[i + 1];
4548       select = how & SOLVER_SELECTMASK;
4549       FOR_JOB_SELECT(p, pp, select, what)
4550         if (solv->decisionmap[p] > 0)
4551           {
4552             queue_push(q, p);
4553 #ifdef ENABLE_LINKED_PKGS
4554             if (has_package_link(pool, pool->solvables + p))
4555               {
4556                 int j;
4557                 Queue lq;
4558                 queue_init(&lq);
4559                 find_package_link(pool, pool->solvables + p, 0, &lq, 0, 0);
4560                 for (j = 0; j < lq.count; j++)
4561                   if (solv->decisionmap[lq.elements[j]] > 0)
4562                     queue_push(q, lq.elements[j]);
4563               }
4564 #endif
4565           }
4566     }
4567   /* now process updates of userinstalled packages */
4568   if (installed && userinstalled.size)
4569     {
4570       for (i = 1; i < solv->decisionq.count; i++)
4571         {
4572           p = solv->decisionq.elements[i];
4573           if (p <= 0)
4574             continue;
4575           s = pool->solvables + p;
4576           if (!s->repo)
4577             continue;
4578           if (s->repo == installed)
4579             {
4580               if (MAPTST(&userinstalled, p - installed->start))
4581                 queue_push(q, p);
4582               continue;
4583             }
4584           /* new package, check if we replace a userinstalled one */
4585           FOR_PROVIDES(p2, pp, s->name)
4586             {
4587               Solvable *ps = pool->solvables + p2;
4588               if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
4589                 continue;
4590               if (!pool->implicitobsoleteusesprovides && s->name != ps->name)
4591                 continue;
4592               if (pool->implicitobsoleteusescolors && !pool_colormatch(pool, s, ps))
4593                 continue;
4594               queue_push(q, p);
4595               break;
4596             }
4597           if (!p2 && s->repo != installed && s->obsoletes)
4598             {
4599               Id obs, *obsp = s->repo->idarraydata + s->obsoletes;
4600               while ((obs = *obsp++) != 0)
4601                 {
4602                   FOR_PROVIDES(p2, pp, obs)
4603                     {
4604                       Solvable *ps = pool->solvables + p2;
4605                       if (p2 == p || ps->repo != installed || !MAPTST(&userinstalled, p2 - installed->start))
4606                         continue;
4607                       if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
4608                         continue;
4609                       if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps)) 
4610                         continue;
4611                       queue_push(q, p); 
4612                       break;
4613                     }
4614                   if (p2)
4615                     break;
4616                 }
4617             }
4618         }
4619     }
4620   map_free(&userinstalled);
4621   /* convert to names if asked */
4622   if ((flags & GET_USERINSTALLED_NAMES) != 0)
4623     {
4624       for (i = 0; i < q->count; i++)
4625         {
4626           s = pool->solvables + q->elements[i];
4627           q->elements[i] = s->name;
4628         }
4629     }
4630   /* sort and unify */
4631   if (q->count > 1)
4632     get_userinstalled_sort_uniq(pool, q, flags);
4633   /* invert if asked */
4634   if ((flags & GET_USERINSTALLED_INVERTED) != 0)
4635     {
4636       /* first generate queue with all installed packages */
4637       Queue invq;
4638       queue_init(&invq);
4639       for (i = 1; i < solv->decisionq.count; i++)
4640         {
4641           p = solv->decisionq.elements[i];
4642           if (p <= 0)
4643             continue;
4644           s = pool->solvables + p;
4645           if (!s->repo)
4646             continue;
4647           if ((flags & GET_USERINSTALLED_NAMES) != 0)
4648             queue_push(&invq, s->name);
4649           else
4650             queue_push(&invq, p);
4651         }
4652       /* push q on invq, just in case... */
4653       queue_insertn(&invq, invq.count, q->count, q->elements);
4654       if (invq.count > 1)
4655         get_userinstalled_sort_uniq(pool, &invq, flags);
4656       /* subtract queues (easy as they are sorted and invq is a superset of q) */
4657       if (q->count)
4658         {
4659           for (i = j = 0; i < invq.count; i++)
4660             if (invq.elements[i] == q->elements[j])
4661               {
4662                 invq.elements[i] = 0;
4663                 if (++j >= q->count)
4664                   break;
4665               }
4666           queue_empty(q);
4667         }
4668       for (i = j = 0; i < invq.count; i++)
4669         if (invq.elements[i])
4670           queue_push(q, invq.elements[i]);
4671       queue_free(&invq);
4672     }
4673 }
4674
4675 void
4676 pool_add_userinstalled_jobs(Pool *pool, Queue *q, Queue *job, int flags)
4677 {
4678   int i;
4679
4680   if (flags & GET_USERINSTALLED_INVERTED)
4681     {
4682       Queue invq;
4683       Id p, lastid;
4684       Solvable *s;
4685       int bad;
4686       if (!pool->installed)
4687         return;
4688       queue_init(&invq);
4689       FOR_REPO_SOLVABLES(pool->installed, p, s)
4690         queue_push(&invq, flags & GET_USERINSTALLED_NAMES ? s->name : p);
4691       queue_insertn(&invq, invq.count, q->count, q->elements);
4692       if (invq.count > 1)
4693         get_userinstalled_sort_uniq(pool, &invq, flags);
4694       /* now the fun part, add q again, sort, and remove all dups */
4695       queue_insertn(&invq, invq.count, q->count, q->elements);
4696       if (invq.count > 1)
4697         {
4698           if ((flags & GET_USERINSTALLED_NAMES) != 0)
4699             solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp_names, pool);
4700           else
4701             solv_sort(invq.elements, invq.count, sizeof(Id), get_userinstalled_cmp, 0);
4702         }
4703       lastid = -1;
4704       bad = 1;
4705       for (i = 0; i < invq.count; i++)
4706         {
4707           if (invq.elements[i] == lastid)
4708             {
4709               bad = 1;
4710               continue;
4711             }
4712           if (!bad)
4713             queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
4714           bad = 0;
4715           lastid = invq.elements[i];
4716         }
4717       if (!bad)
4718         queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), lastid);
4719       queue_free(&invq);
4720     }
4721   else
4722     {
4723       for (i = 0; i < q->count; i++)
4724         queue_push2(job, SOLVER_USERINSTALLED | (flags & GET_USERINSTALLED_NAMES ? SOLVER_SOLVABLE_NAME : SOLVER_SOLVABLE), q->elements[i]);
4725     }
4726 }
4727
4728 const char *
4729 solver_select2str(Pool *pool, Id select, Id what)
4730 {
4731   const char *s;
4732   char *b;
4733   select &= SOLVER_SELECTMASK;
4734   if (select == SOLVER_SOLVABLE)
4735     return pool_solvid2str(pool, what);
4736   if (select == SOLVER_SOLVABLE_NAME)
4737     return pool_dep2str(pool, what);
4738   if (select == SOLVER_SOLVABLE_PROVIDES)
4739     {
4740       s = pool_dep2str(pool, what);
4741       b = pool_alloctmpspace(pool, 11 + strlen(s));
4742       sprintf(b, "providing %s", s);
4743       return b;
4744     }
4745   if (select == SOLVER_SOLVABLE_ONE_OF)
4746     {
4747       Id p;
4748       b = 0;
4749       while ((p = pool->whatprovidesdata[what++]) != 0)
4750         {
4751           s = pool_solvid2str(pool, p);
4752           if (b)
4753             b = pool_tmpappend(pool, b, ", ", s);
4754           else
4755             b = pool_tmpjoin(pool, s, 0, 0);
4756           pool_freetmpspace(pool, s);
4757         }
4758       return b ? b : "nothing";
4759     }
4760   if (select == SOLVER_SOLVABLE_REPO)
4761     {
4762       b = pool_alloctmpspace(pool, 20);
4763       sprintf(b, "repo #%d", what);
4764       return b;
4765     }
4766   if (select == SOLVER_SOLVABLE_ALL)
4767     return "all packages";
4768   return "unknown job select";
4769 }
4770
4771 const char *
4772 pool_job2str(Pool *pool, Id how, Id what, Id flagmask)
4773 {
4774   Id select = how & SOLVER_SELECTMASK;
4775   const char *strstart = 0, *strend = 0;
4776   char *s;
4777   int o;
4778
4779   switch (how & SOLVER_JOBMASK)
4780     {
4781     case SOLVER_NOOP:
4782       return "do nothing";
4783     case SOLVER_INSTALL:
4784       if (select == SOLVER_SOLVABLE && pool->installed && pool->solvables[what].repo == pool->installed)
4785         strstart = "keep ", strend = " installed";
4786       else if (select == SOLVER_SOLVABLE || select == SOLVER_SOLVABLE_NAME)
4787         strstart = "install ";
4788       else if (select == SOLVER_SOLVABLE_PROVIDES)
4789         strstart = "install a package ";
4790       else
4791         strstart = "install one of ";
4792       break;
4793     case SOLVER_ERASE:
4794       if (select == SOLVER_SOLVABLE && !(pool->installed && pool->solvables[what].repo == pool->installed))
4795         strstart = "keep ", strend = " uninstalled";
4796       else if (select == SOLVER_SOLVABLE_PROVIDES)
4797         strstart = "deinstall all packages ";
4798       else
4799         strstart = "deinstall ";
4800       break;
4801     case SOLVER_UPDATE:
4802       strstart = "update ";
4803       break;
4804     case SOLVER_WEAKENDEPS:
4805       strstart = "weaken deps of ";
4806       break;
4807     case SOLVER_MULTIVERSION:
4808       strstart = "multi version ";
4809       break;
4810     case SOLVER_LOCK:
4811       strstart = "lock ";
4812       break;
4813     case SOLVER_DISTUPGRADE:
4814       strstart = "dist upgrade ";
4815       break;
4816     case SOLVER_VERIFY:
4817       strstart = "verify ";
4818       break;
4819     case SOLVER_DROP_ORPHANED:
4820       strstart = "deinstall ", strend = " if orphaned";
4821       break;
4822     case SOLVER_USERINSTALLED:
4823       strstart = "regard ", strend = " as userinstalled";
4824       break;
4825     default:
4826       strstart = "unknown job ";
4827       break;
4828     }
4829   s = pool_tmpjoin(pool, strstart, solver_select2str(pool, select, what), strend);
4830   how &= flagmask;
4831   if ((how & ~(SOLVER_SELECTMASK|SOLVER_JOBMASK)) == 0)
4832     return s;
4833   o = strlen(s);
4834   s = pool_tmpappend(pool, s, " ", 0);
4835   if (how & SOLVER_WEAK)
4836     s = pool_tmpappend(pool, s, ",weak", 0);
4837   if (how & SOLVER_ESSENTIAL)
4838     s = pool_tmpappend(pool, s, ",essential", 0);
4839   if (how & SOLVER_CLEANDEPS)
4840     s = pool_tmpappend(pool, s, ",cleandeps", 0);
4841   if (how & SOLVER_ORUPDATE)
4842     s = pool_tmpappend(pool, s, ",orupdate", 0);
4843   if (how & SOLVER_FORCEBEST)
4844     s = pool_tmpappend(pool, s, ",forcebest", 0);
4845   if (how & SOLVER_TARGETED)
4846     s = pool_tmpappend(pool, s, ",targeted", 0);
4847   if (how & SOLVER_SETEV)
4848     s = pool_tmpappend(pool, s, ",setev", 0);
4849   if (how & SOLVER_SETEVR)
4850     s = pool_tmpappend(pool, s, ",setevr", 0);
4851   if (how & SOLVER_SETARCH)
4852     s = pool_tmpappend(pool, s, ",setarch", 0);
4853   if (how & SOLVER_SETVENDOR)
4854     s = pool_tmpappend(pool, s, ",setvendor", 0);
4855   if (how & SOLVER_SETREPO)
4856     s = pool_tmpappend(pool, s, ",setrepo", 0);
4857   if (how & SOLVER_SETNAME)
4858     s = pool_tmpappend(pool, s, ",setname", 0);
4859   if (how & SOLVER_NOAUTOSET)
4860     s = pool_tmpappend(pool, s, ",noautoset", 0);
4861   if (s[o + 1] != ',')
4862     s = pool_tmpappend(pool, s, ",?", 0);
4863   s[o + 1] = '[';
4864   return pool_tmpappend(pool, s, "]", 0);
4865 }
4866