1 /*
2 * Copyright (c) 2007-2009, Novell Inc.
3 *
4 * This program is licensed under the BSD license, read LICENSE.BSD
5 * for further information
6 */
7
8 /*
9 * problems.c
10 *
11 */
12
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <unistd.h>
16 #include <string.h>
17 #include <assert.h>
18
19 #include "solver.h"
20 #include "solver_private.h"
21 #include "bitmap.h"
22 #include "pool.h"
23 #include "util.h"
24 #include "evr.h"
25 #include "solverdebug.h"
26
27 /**********************************************************************************/
28
29 /* a problem is an item on the solver's problem list. It can either be >0, in that
30 * case it is a update/infarch/dup rule, or it can be <0, which makes it refer to a job
31 * consisting of multiple job rules.
32 */
33
34 static void
solver_disableproblem(Solver * solv,Id v)35 solver_disableproblem(Solver *solv, Id v)
36 {
37 int i;
38 Id *jp;
39
40 if (v > 0)
41 {
42 if (v >= solv->infarchrules && v < solv->infarchrules_end)
43 {
44 Pool *pool = solv->pool;
45 Id name = pool->solvables[-solv->rules[v].p].name;
46 while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
47 v--;
48 for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
49 solver_disablerule(solv, solv->rules + v);
50 return;
51 }
52 if (v >= solv->duprules && v < solv->duprules_end)
53 {
54 Pool *pool = solv->pool;
55 Id name = pool->solvables[-solv->rules[v].p].name;
56 while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
57 v--;
58 for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
59 solver_disablerule(solv, solv->rules + v);
60 return;
61 }
62 solver_disablerule(solv, solv->rules + v);
63 return;
64 }
65 v = -(v + 1);
66 jp = solv->ruletojob.elements;
67 if (solv->bestrules_info)
68 {
69 int ni = solv->bestrules_up - solv->bestrules;
70 for (i = 0; i < ni; i++)
71 {
72 int j = solv->bestrules_info[i];
73 if (j < 0 && jp[-j - solv->jobrules] == v)
74 solver_disablerule(solv, solv->rules + solv->bestrules + i);
75 }
76 }
77 for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
78 if (*jp == v)
79 solver_disablerule(solv, solv->rules + i);
80 }
81
82 /*-------------------------------------------------------------------
83 * enableproblem
84 */
85
86 static void
solver_enableproblem(Solver * solv,Id v)87 solver_enableproblem(Solver *solv, Id v)
88 {
89 Rule *r;
90 int i;
91 Id *jp;
92
93 if (v > 0)
94 {
95 if (v >= solv->infarchrules && v < solv->infarchrules_end)
96 {
97 Pool *pool = solv->pool;
98 Id name = pool->solvables[-solv->rules[v].p].name;
99 while (v > solv->infarchrules && pool->solvables[-solv->rules[v - 1].p].name == name)
100 v--;
101 for (; v < solv->infarchrules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
102 solver_enablerule(solv, solv->rules + v);
103 return;
104 }
105 if (v >= solv->duprules && v < solv->duprules_end)
106 {
107 Pool *pool = solv->pool;
108 Id name = pool->solvables[-solv->rules[v].p].name;
109 while (v > solv->duprules && pool->solvables[-solv->rules[v - 1].p].name == name)
110 v--;
111 for (; v < solv->duprules_end && pool->solvables[-solv->rules[v].p].name == name; v++)
112 solver_enablerule(solv, solv->rules + v);
113 return;
114 }
115 if (v >= solv->featurerules && v < solv->featurerules_end)
116 {
117 /* do not enable feature rule if update rule is enabled */
118 r = solv->rules + (v - solv->featurerules + solv->updaterules);
119 if (r->d >= 0)
120 return;
121 }
122 solver_enablerule(solv, solv->rules + v);
123 if (v >= solv->updaterules && v < solv->updaterules_end)
124 {
125 /* disable feature rule when enabling update rule */
126 r = solv->rules + (v - solv->updaterules + solv->featurerules);
127 if (r->p)
128 solver_disablerule(solv, r);
129 }
130 return;
131 }
132 v = -(v + 1);
133 jp = solv->ruletojob.elements;
134 if (solv->bestrules_info)
135 {
136 int ni = solv->bestrules_up - solv->bestrules;
137 for (i = 0; i < ni; i++)
138 {
139 int j = solv->bestrules_info[i];
140 if (j < 0 && jp[-j - solv->jobrules] == v)
141 solver_enablerule(solv, solv->rules + solv->bestrules + i);
142 }
143 }
144 for (i = solv->jobrules; i < solv->jobrules_end; i++, jp++)
145 if (*jp == v)
146 solver_enablerule(solv, solv->rules + i);
147 }
148
149
150 /*-------------------------------------------------------------------
151 * turn a problem rule into a problem id by normalizing it
152 */
153 static Id
solver_ruletoproblem(Solver * solv,Id rid)154 solver_ruletoproblem(Solver *solv, Id rid)
155 {
156 if (rid >= solv->jobrules && rid < solv->jobrules_end)
157 rid = -(solv->ruletojob.elements[rid - solv->jobrules] + 1);
158 else if (rid >= solv->bestrules && rid < solv->bestrules_up && solv->bestrules_info[rid - solv->bestrules] < 0)
159 rid = -(solv->ruletojob.elements[-solv->bestrules_info[rid - solv->bestrules] - solv->jobrules] + 1);
160 else if (rid > solv->infarchrules && rid < solv->infarchrules_end)
161 {
162 Pool *pool = solv->pool;
163 Id name = pool->solvables[-solv->rules[rid].p].name;
164 while (rid > solv->infarchrules && pool->solvables[-solv->rules[rid - 1].p].name == name)
165 rid--;
166 }
167 else if (rid > solv->duprules && rid < solv->duprules_end)
168 {
169 Pool *pool = solv->pool;
170 Id name = pool->solvables[-solv->rules[rid].p].name;
171 while (rid > solv->duprules && pool->solvables[-solv->rules[rid - 1].p].name == name)
172 rid--;
173 }
174 return rid;
175 }
176
177 /*-------------------------------------------------------------------
178 * when the solver runs into a problem, it needs to disable all
179 * involved non-pkg rules and record the rules for solution
180 * generation.
181 */
182 void
solver_recordproblem(Solver * solv,Id rid)183 solver_recordproblem(Solver *solv, Id rid)
184 {
185 Id v = solver_ruletoproblem(solv, rid);
186 /* return if problem already countains our rule */
187 if (solv->problems.count)
188 {
189 int i;
190 for (i = solv->problems.count - 1; i >= 0; i--)
191 if (solv->problems.elements[i] == 0) /* end of last problem reached? */
192 break;
193 else if (solv->problems.elements[i] == v)
194 return;
195 }
196 queue_push(&solv->problems, v);
197 }
198
199 /*-------------------------------------------------------------------
200 * this is called when a problem is solved by disabling a rule.
201 * It calls disableproblem and then re-enables policy rules
202 */
203 void
solver_fixproblem(Solver * solv,Id rid)204 solver_fixproblem(Solver *solv, Id rid)
205 {
206 Id v = solver_ruletoproblem(solv, rid);
207 solver_disableproblem(solv, v);
208 if (v < 0)
209 solver_reenablepolicyrules(solv, -v);
210 }
211
212 /*-------------------------------------------------------------------
213 * disable a set of problems
214 */
215 void
solver_disableproblemset(Solver * solv,int start)216 solver_disableproblemset(Solver *solv, int start)
217 {
218 int i;
219 for (i = start + 1; i < solv->problems.count - 1; i++)
220 solver_disableproblem(solv, solv->problems.elements[i]);
221 }
222
223 /*-------------------------------------------------------------------
224 * try to fix a problem by auto-uninstalling packages
225 */
226 Id
solver_autouninstall(Solver * solv,int start)227 solver_autouninstall(Solver *solv, int start)
228 {
229 Pool *pool = solv->pool;
230 int i;
231 int lastfeature = 0, lastupdate = 0;
232 Id v;
233 Id extraflags = -1;
234 Map *m = 0;
235
236 if (!solv->allowuninstall && !solv->allowuninstall_all)
237 {
238 if (!solv->allowuninstallmap.size)
239 return 0; /* why did we get called? */
240 m = &solv->allowuninstallmap;
241 }
242 for (i = start + 1; i < solv->problems.count - 1; i++)
243 {
244 v = solv->problems.elements[i];
245 if (v < 0)
246 extraflags &= solv->job.elements[-v - 1];
247 if (v >= solv->updaterules && v < solv->updaterules_end)
248 {
249 Rule *r;
250 Id p = solv->installed->start + (v - solv->updaterules);
251 if (m && !MAPTST(m, v - solv->updaterules))
252 continue;
253 if (pool->considered && !MAPTST(pool->considered, p))
254 continue; /* do not uninstalled disabled packages */
255 if (solv->bestrules_info && solv->bestrules_end > solv->bestrules)
256 {
257 int j;
258 for (j = start + 1; j < solv->problems.count - 1; j++)
259 {
260 Id vv = solv->problems.elements[j];
261 if (vv >= solv->bestrules && vv < solv->bestrules_end && solv->bestrules_info[vv - solv->bestrules] == p)
262 break;
263 }
264 if (j < solv->problems.count - 1)
265 continue; /* best rule involved, do not uninstall */
266 }
267 /* check if identical to feature rule, we don't like that (except for orphans) */
268 r = solv->rules + solv->featurerules + (v - solv->updaterules);
269 if (!r->p)
270 {
271 /* update rule == feature rule */
272 if (v > lastfeature)
273 lastfeature = v;
274 /* prefer orphaned packages in dup mode */
275 if (solv->keep_orphans)
276 {
277 r = solv->rules + v;
278 if (!r->d && !r->w2 && r->p == p)
279 {
280 lastfeature = v;
281 lastupdate = 0;
282 break;
283 }
284 }
285 continue;
286 }
287 if (v > lastupdate)
288 lastupdate = v;
289 }
290 }
291 if (!lastupdate && !lastfeature)
292 return 0;
293 v = lastupdate ? lastupdate : lastfeature;
294 POOL_DEBUG(SOLV_DEBUG_UNSOLVABLE, "allowuninstall disabling ");
295 solver_printruleclass(solv, SOLV_DEBUG_UNSOLVABLE, solv->rules + v);
296 /* should really be solver_fixproblem, but we know v is an update/feature rule */
297 solver_disableproblem(solv, v);
298 if (extraflags != -1 && (extraflags & SOLVER_CLEANDEPS) != 0 && solv->cleandepsmap.size)
299 {
300 /* add the package to the updatepkgs list, this will automatically turn
301 * on cleandeps mode */
302 Id p = solv->rules[v].p;
303 if (!solv->cleandeps_updatepkgs)
304 {
305 solv->cleandeps_updatepkgs = solv_calloc(1, sizeof(Queue));
306 queue_init(solv->cleandeps_updatepkgs);
307 }
308 if (p > 0)
309 {
310 int oldupdatepkgscnt = solv->cleandeps_updatepkgs->count;
311 queue_pushunique(solv->cleandeps_updatepkgs, p);
312 if (solv->cleandeps_updatepkgs->count != oldupdatepkgscnt)
313 solver_disablepolicyrules(solv);
314 }
315 }
316 return v;
317 }
318
319
320 /*-------------------------------------------------------------------
321 * enable weak rules
322 *
323 * Reenable all disabled weak rules (marked in weakrulemap)
324 *
325 */
326
327 static void
enableweakrules(Solver * solv)328 enableweakrules(Solver *solv)
329 {
330 int i;
331 Rule *r;
332
333 if (!solv->weakrulemap.size)
334 return;
335 for (i = 1, r = solv->rules + i; i < solv->learntrules; i++, r++)
336 {
337 if (r->d >= 0) /* already enabled? */
338 continue;
339 if (!MAPTST(&solv->weakrulemap, i))
340 continue;
341 solver_enablerule(solv, r);
342 }
343 /* make sure broken orphan rules stay disabled */
344 if (solv->brokenorphanrules)
345 for (i = 0; i < solv->brokenorphanrules->count; i++)
346 solver_disablerule(solv, solv->rules + solv->brokenorphanrules->elements[i]);
347 }
348
349
350 /*-------------------------------------------------------------------
351 *
352 * refine_suggestion
353 *
354 * at this point, all rules that led to conflicts are disabled.
355 * we re-enable all rules of a problem set but rule "sug", then
356 * continue to disable more rules until there as again a solution.
357 */
358
359 /* FIXME: think about conflicting assertions */
360
361 static void
refine_suggestion(Solver * solv,Id * problem,Id sug,Queue * refined,int essentialok)362 refine_suggestion(Solver *solv, Id *problem, Id sug, Queue *refined, int essentialok)
363 {
364 Pool *pool = solv->pool;
365 int i, j;
366 Id v;
367 Queue disabled;
368 int disabledcnt;
369
370 IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
371 {
372 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion start\n");
373 for (i = 0; problem[i]; i++)
374 {
375 if (problem[i] == sug)
376 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "=> ");
377 solver_printproblem(solv, problem[i]);
378 }
379 }
380 queue_empty(refined);
381 if (!essentialok && sug < 0 && (solv->job.elements[-sug - 1] & SOLVER_ESSENTIAL) != 0)
382 return;
383 queue_push(refined, sug);
384
385 /* re-enable all problem rules with the exception of "sug"(gestion) */
386 solver_reset(solv);
387
388 for (i = 0; problem[i]; i++)
389 if (problem[i] != sug)
390 solver_enableproblem(solv, problem[i]);
391 if (sug < 0)
392 solver_reenablepolicyrules(solv, -sug);
393
394 /* here is where the feature rules come into play: if we disabled an
395 * update rule, we enable the corresponding feature rule if there is
396 * one. We do this to make the solver downgrade packages instead of
397 * deinstalling them */
398 if (sug >= solv->updaterules && sug < solv->updaterules_end)
399 {
400 /* enable feature rule */
401 Rule *r = solv->rules + solv->featurerules + (sug - solv->updaterules);
402 if (r->p)
403 solver_enablerule(solv, r);
404 }
405
406 enableweakrules(solv);
407
408 /* disabled contains all of the rules we disabled in the refinement process */
409 queue_init(&disabled);
410 for (;;)
411 {
412 int nother, nfeature, nupdate, pass;
413 queue_empty(&solv->problems);
414 solver_reset(solv);
415 /* we set disablerules to zero because we are only interested in
416 * the first problem and we don't want the solver to disable the problems */
417 solver_run_sat(solv, 0, 0);
418
419 if (!solv->problems.count)
420 {
421 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no more problems!\n");
422 break; /* great, no more problems */
423 }
424 disabledcnt = disabled.count;
425 nother = nfeature = nupdate = 0;
426 for (pass = 0; pass < 2; pass++)
427 {
428 /* start with 1 to skip over proof index */
429 for (i = 1; i < solv->problems.count - 1; i++)
430 {
431 /* ignore solutions in refined */
432 v = solv->problems.elements[i];
433 if (v == 0)
434 break; /* end of problem reached */
435 if (!essentialok && v < 0 && (solv->job.elements[-v - 1] & SOLVER_ESSENTIAL) != 0)
436 continue; /* not that one! */
437 if (sug != v)
438 {
439 /* check if v is in the given problems list
440 * we allow disabling all problem rules *after* sug in
441 * pass 2, to prevent getting the same solution twice */
442 for (j = 0; problem[j]; j++)
443 if (problem[j] == v || (pass && problem[j] == sug))
444 break;
445 if (problem[j] == v)
446 continue;
447 }
448 if (v >= solv->featurerules && v < solv->featurerules_end)
449 nfeature++;
450 else if (v > solv->updaterules && v < solv->updaterules_end)
451 nupdate++;
452 else
453 nother++;
454 queue_push(&disabled, v);
455 }
456 if (disabled.count != disabledcnt)
457 break;
458 }
459 if (disabled.count == disabledcnt)
460 {
461 /* no solution found, this was an invalid suggestion! */
462 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "no solution found!\n");
463 refined->count = 0;
464 break;
465 }
466 if (!nother && nupdate && nfeature)
467 {
468 /* got only update rules, filter out feature rules */
469 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "throwing away feature rules\n");
470 for (i = j = disabledcnt; i < disabled.count; i++)
471 {
472 v = disabled.elements[i];
473 if (v < solv->featurerules || v >= solv->featurerules_end)
474 disabled.elements[j++] = v;
475 }
476 disabled.count = j;
477 nfeature = 0;
478 }
479 if (disabled.count == disabledcnt + 1)
480 {
481 /* just one suggestion, add it to refined list */
482 v = disabled.elements[disabledcnt];
483 if (!nfeature && v != sug)
484 queue_push(refined, v); /* do not record feature rules */
485 solver_disableproblem(solv, v);
486 if (v < 0)
487 solver_reenablepolicyrules(solv, -v);
488 if (v >= solv->updaterules && v < solv->updaterules_end)
489 {
490 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
491 if (r->p)
492 solver_enablerule(solv, r); /* enable corresponding feature rule */
493 }
494 }
495 else
496 {
497 /* more than one solution, disable all */
498 /* do not push anything on refine list, as we do not know which solution to choose */
499 /* thus, the user will get another problem if he selects this solution, where he
500 * can choose the right one */
501 IF_POOLDEBUG (SOLV_DEBUG_SOLUTIONS)
502 {
503 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "more than one solution found:\n");
504 for (i = disabledcnt; i < disabled.count; i++)
505 solver_printproblem(solv, disabled.elements[i]);
506 }
507 for (i = disabledcnt; i < disabled.count; i++)
508 {
509 v = disabled.elements[i];
510 solver_disableproblem(solv, v);
511 if (v >= solv->updaterules && v < solv->updaterules_end)
512 {
513 Rule *r = solv->rules + (v - solv->updaterules + solv->featurerules);
514 if (r->p)
515 solver_enablerule(solv, r);
516 }
517 }
518 }
519 }
520 /* all done, get us back into the same state as before */
521 /* enable refined rules again */
522 for (i = 0; i < disabled.count; i++)
523 solver_enableproblem(solv, disabled.elements[i]);
524 queue_free(&disabled);
525
526 /* reset policy rules */
527 for (i = 0; problem[i]; i++)
528 solver_enableproblem(solv, problem[i]);
529 solver_disablepolicyrules(solv);
530 /* disable problem rules again */
531 for (i = 0; problem[i]; i++)
532 solver_disableproblem(solv, problem[i]);
533 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "refine_suggestion end\n");
534 }
535
536
537 /*-------------------------------------------------------------------
538 * sorting helper for problems
539 *
540 * bring update rules before job rules
541 * make essential job rules last
542 */
543
544 static int
problems_sortcmp(const void * ap,const void * bp,void * dp)545 problems_sortcmp(const void *ap, const void *bp, void *dp)
546 {
547 Queue *job = dp;
548 Id a = *(Id *)ap, b = *(Id *)bp;
549 if (a < 0 && b > 0)
550 return 1;
551 if (a > 0 && b < 0)
552 return -1;
553 if (a < 0 && b < 0)
554 {
555 int af = job->elements[-a - 1] & SOLVER_ESSENTIAL;
556 int bf = job->elements[-b - 1] & SOLVER_ESSENTIAL;
557 int x = af - bf;
558 if (x)
559 return x;
560 }
561 return a - b;
562 }
563
564 /*
565 * convert a solution rule into a job modifier
566 */
567 static void
convertsolution(Solver * solv,Id why,Queue * solutionq)568 convertsolution(Solver *solv, Id why, Queue *solutionq)
569 {
570 Pool *pool = solv->pool;
571 if (why < 0)
572 {
573 why = -why;
574 if (why < solv->pooljobcnt)
575 {
576 queue_push(solutionq, SOLVER_SOLUTION_POOLJOB);
577 queue_push(solutionq, why);
578 }
579 else
580 {
581 queue_push(solutionq, SOLVER_SOLUTION_JOB);
582 queue_push(solutionq, why - solv->pooljobcnt);
583 }
584 return;
585 }
586 if (why >= solv->infarchrules && why < solv->infarchrules_end)
587 {
588 Id p, name;
589 /* infarch rule, find replacement */
590 assert(solv->rules[why].p < 0);
591 name = pool->solvables[-solv->rules[why].p].name;
592 while (why > solv->infarchrules && pool->solvables[-solv->rules[why - 1].p].name == name)
593 why--;
594 p = 0;
595 for (; why < solv->infarchrules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
596 if (solv->decisionmap[-solv->rules[why].p] > 0)
597 {
598 p = -solv->rules[why].p;
599 break;
600 }
601 if (!p)
602 return; /* false alarm */
603 queue_push(solutionq, SOLVER_SOLUTION_INFARCH);
604 queue_push(solutionq, p);
605 return;
606 }
607 if (why >= solv->duprules && why < solv->duprules_end)
608 {
609 Id p, name;
610 /* dist upgrade rule, find replacement */
611 assert(solv->rules[why].p < 0);
612 name = pool->solvables[-solv->rules[why].p].name;
613 while (why > solv->duprules && pool->solvables[-solv->rules[why - 1].p].name == name)
614 why--;
615 p = 0;
616 for (; why < solv->duprules_end && pool->solvables[-solv->rules[why].p].name == name; why++)
617 if (solv->decisionmap[-solv->rules[why].p] > 0)
618 {
619 p = -solv->rules[why].p;
620 break;
621 }
622 if (!p)
623 return; /* false alarm */
624 queue_push(solutionq, SOLVER_SOLUTION_DISTUPGRADE);
625 queue_push(solutionq, p);
626 return;
627 }
628 if (why >= solv->updaterules && why < solv->updaterules_end)
629 {
630 /* update rule, find replacement package */
631 Id p, pp, rp = 0;
632 Rule *rr;
633
634 /* check if this is a false positive, i.e. the update rule is fulfilled */
635 rr = solv->rules + why;
636 FOR_RULELITERALS(p, pp, rr)
637 if (p > 0 && solv->decisionmap[p] > 0)
638 return; /* false alarm */
639
640 p = solv->installed->start + (why - solv->updaterules);
641 if (solv->decisionmap[p] > 0)
642 return; /* false alarm, turned out we can keep the package */
643 rr = solv->rules + solv->featurerules + (why - solv->updaterules);
644 if (!rr->p)
645 rr = solv->rules + why;
646 if (rr->w2)
647 {
648 int mvrp = 0; /* multi-version replacement */
649 FOR_RULELITERALS(rp, pp, rr)
650 {
651 if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
652 {
653 mvrp = rp;
654 if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
655 break;
656 }
657 }
658 if (!rp && mvrp)
659 {
660 /* found only multi-version replacements */
661 /* have to split solution into two parts */
662 queue_push(solutionq, p);
663 queue_push(solutionq, mvrp);
664 }
665 }
666 queue_push(solutionq, p);
667 queue_push(solutionq, rp);
668 return;
669 }
670 if (why >= solv->bestrules && why < solv->bestrules_end)
671 {
672 int mvrp;
673 Id p, pp, rp = 0;
674 Rule *rr;
675 /* check false positive */
676 rr = solv->rules + why;
677 FOR_RULELITERALS(p, pp, rr)
678 if (p > 0 && solv->decisionmap[p] > 0)
679 return; /* false alarm */
680 /* check update/feature rule */
681 p = solv->bestrules_info[why - solv->bestrules];
682 if (p < 0)
683 {
684 /* install job */
685 queue_push(solutionq, 0);
686 queue_push(solutionq, solv->ruletojob.elements[-p - solv->jobrules] + 1);
687 return;
688 }
689 if (solv->decisionmap[p] > 0)
690 {
691 /* disable best rule by keeping the old package */
692 queue_push(solutionq, SOLVER_SOLUTION_BEST);
693 queue_push(solutionq, p);
694 return;
695 }
696 rr = solv->rules + solv->featurerules + (p - solv->installed->start);
697 if (!rr->p)
698 rr = solv->rules + solv->updaterules + (p - solv->installed->start);
699 mvrp = 0; /* multi-version replacement */
700 FOR_RULELITERALS(rp, pp, rr)
701 if (rp > 0 && solv->decisionmap[rp] > 0 && pool->solvables[rp].repo != solv->installed)
702 {
703 mvrp = rp;
704 if (!(solv->multiversion.size && MAPTST(&solv->multiversion, rp)))
705 break;
706 }
707 if (!rp && mvrp)
708 {
709 queue_push(solutionq, SOLVER_SOLUTION_BEST); /* split, see above */
710 queue_push(solutionq, mvrp);
711 queue_push(solutionq, p);
712 queue_push(solutionq, 0);
713 return;
714 }
715 if (rp)
716 {
717 queue_push(solutionq, SOLVER_SOLUTION_BEST);
718 queue_push(solutionq, rp);
719 }
720 return;
721 }
722 if (why >= solv->blackrules && why < solv->blackrules_end)
723 {
724 queue_push(solutionq, SOLVER_SOLUTION_BLACK);
725 assert(solv->rules[why].p < 0);
726 queue_push(solutionq, -solv->rules[why].p);
727 }
728 }
729
730 /*
731 * convert problem data into a form usable for refining.
732 * Returns the number of problems.
733 */
734 int
solver_prepare_solutions(Solver * solv)735 solver_prepare_solutions(Solver *solv)
736 {
737 int i, j = 1, idx;
738
739 if (!solv->problems.count)
740 return 0;
741 queue_empty(&solv->solutions);
742 queue_push(&solv->solutions, 0); /* dummy so idx is always nonzero */
743 idx = solv->solutions.count;
744 queue_push(&solv->solutions, -1); /* unrefined */
745 /* proofidx stays in position, thus we start with 1 */
746 for (i = 1; i < solv->problems.count; i++)
747 {
748 Id p = solv->problems.elements[i];
749 queue_push(&solv->solutions, p);
750 if (p)
751 continue;
752 /* end of problem reached */
753 solv->problems.elements[j++] = idx;
754 if (i + 1 >= solv->problems.count)
755 break;
756 /* start another problem */
757 solv->problems.elements[j++] = solv->problems.elements[++i]; /* copy proofidx */
758 idx = solv->solutions.count;
759 queue_push(&solv->solutions, -1); /* unrefined */
760 }
761 solv->problems.count = j;
762 return j / 2;
763 }
764
765 /*
766 * refine the simple solution rule list provided by
767 * the solver into multiple lists of job modifiers.
768 */
769 static void
create_solutions(Solver * solv,int probnr,int solidx)770 create_solutions(Solver *solv, int probnr, int solidx)
771 {
772 Pool *pool = solv->pool;
773 Queue redoq;
774 Queue problem, solution, problems_save, branches_save, decisionq_reason_save;
775 int i, j, nsol;
776 int essentialok;
777 unsigned int now;
778 int oldmistakes = solv->cleandeps_mistakes ? solv->cleandeps_mistakes->count : 0;
779 Id extraflags = -1;
780
781 now = solv_timems(0);
782 queue_init(&redoq);
783 /* save decisionq, decisionq_why, decisionmap, and decisioncnt */
784 for (i = 0; i < solv->decisionq.count; i++)
785 {
786 Id p = solv->decisionq.elements[i];
787 queue_push(&redoq, p);
788 queue_push(&redoq, solv->decisionq_why.elements[i]);
789 queue_push(&redoq, solv->decisionmap[p > 0 ? p : -p]);
790 }
791
792 /* save problems queue */
793 problems_save = solv->problems;
794 memset(&solv->problems, 0, sizeof(solv->problems));
795
796 /* save branches queue */
797 branches_save = solv->branches;
798 memset(&solv->branches, 0, sizeof(solv->branches));
799
800 /* save decisionq_reason */
801 decisionq_reason_save = solv->decisionq_reason;
802 memset(&solv->decisionq_reason, 0, sizeof(solv->decisionq_reason));
803
804 /* extract problem from queue */
805 queue_init(&problem);
806 for (i = solidx + 1; i < solv->solutions.count; i++)
807 {
808 Id v = solv->solutions.elements[i];
809 if (!v)
810 break;
811 queue_push(&problem, v);
812 if (v < 0)
813 extraflags &= solv->job.elements[-v - 1];
814 }
815 if (extraflags == -1)
816 extraflags = 0;
817 if (problem.count > 1)
818 solv_sort(problem.elements, problem.count, sizeof(Id), problems_sortcmp, &solv->job);
819 queue_push(&problem, 0); /* mark end for refine_suggestion */
820 problem.count--;
821 #if 0
822 for (i = 0; i < problem.count; i++)
823 printf("PP %d %d\n", i, problem.elements[i]);
824 #endif
825
826 /* refine each solution element */
827 nsol = 0;
828 essentialok = 0;
829 queue_init(&solution);
830 for (i = 0; i < problem.count; i++)
831 {
832 int solstart = solv->solutions.count;
833 refine_suggestion(solv, problem.elements, problem.elements[i], &solution, essentialok);
834 queue_push(&solv->solutions, 0); /* reserve room for number of elements */
835 for (j = 0; j < solution.count; j++)
836 convertsolution(solv, solution.elements[j], &solv->solutions);
837 if (solv->solutions.count == solstart + 1)
838 {
839 solv->solutions.count--; /* this one did not work out */
840 if (nsol || i + 1 < problem.count)
841 continue; /* got one or still hope */
842 if (!essentialok)
843 {
844 /* nothing found, start over */
845 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, re-run with essentialok = 1\n");
846 essentialok = 1;
847 i = -1;
848 continue;
849 }
850 /* this is bad, we found no solution */
851 /* for now just offer a rule */
852 POOL_DEBUG(SOLV_DEBUG_SOLUTIONS, "nothing found, already did essentialok, fake it\n");
853 queue_push(&solv->solutions, 0);
854 for (j = 0; j < problem.count; j++)
855 {
856 convertsolution(solv, problem.elements[j], &solv->solutions);
857 if (solv->solutions.count > solstart + 1)
858 break;
859 }
860 if (solv->solutions.count == solstart + 1)
861 {
862 solv->solutions.count--;
863 continue; /* sorry */
864 }
865 }
866 /* patch in number of solution elements */
867 solv->solutions.elements[solstart] = (solv->solutions.count - (solstart + 1)) / 2;
868 queue_push(&solv->solutions, 0); /* add end marker */
869 queue_push(&solv->solutions, 0); /* add end marker */
870 queue_push(&solv->solutions, problem.elements[i]); /* just for bookkeeping */
871 queue_push(&solv->solutions, extraflags & SOLVER_CLEANDEPS); /* our extraflags */
872 solv->solutions.elements[solidx + 1 + nsol++] = solstart;
873 }
874 solv->solutions.elements[solidx + 1 + nsol] = 0; /* end marker */
875 solv->solutions.elements[solidx] = nsol;
876 queue_free(&problem);
877 queue_free(&solution);
878
879 /* restore decisions */
880 memset(solv->decisionmap, 0, pool->nsolvables * sizeof(Id));
881 queue_empty(&solv->decisionq);
882 queue_empty(&solv->decisionq_why);
883 for (i = 0; i < redoq.count; i += 3)
884 {
885 Id p = redoq.elements[i];
886 queue_push(&solv->decisionq, p);
887 queue_push(&solv->decisionq_why, redoq.elements[i + 1]);
888 solv->decisionmap[p > 0 ? p : -p] = redoq.elements[i + 2];
889 }
890 queue_free(&redoq);
891
892 /* restore decision reasons */
893 queue_free(&solv->decisionq_reason);
894 solv->decisionq_reason = decisionq_reason_save;
895
896 /* restore problems */
897 queue_free(&solv->problems);
898 solv->problems = problems_save;
899
900 /* restore branches */
901 queue_free(&solv->branches);
902 solv->branches = branches_save;
903
904 if (solv->cleandeps_mistakes)
905 {
906 if (oldmistakes)
907 queue_truncate(solv->cleandeps_mistakes, oldmistakes);
908 else
909 {
910 queue_free(solv->cleandeps_mistakes);
911 solv->cleandeps_mistakes = solv_free(solv->cleandeps_mistakes);
912 }
913 }
914
915 POOL_DEBUG(SOLV_DEBUG_STATS, "create_solutions for problem #%d took %d ms\n", probnr, solv_timems(now));
916 }
917
918
919 /**************************************************************************/
920
921 unsigned int
solver_problem_count(Solver * solv)922 solver_problem_count(Solver *solv)
923 {
924 return solv->problems.count / 2;
925 }
926
927 Id
solver_next_problem(Solver * solv,Id problem)928 solver_next_problem(Solver *solv, Id problem)
929 {
930 if (!problem)
931 return solv->problems.count ? 1 : 0;
932 return (problem + 1) * 2 - 1 < solv->problems.count ? problem + 1 : 0;
933 }
934
935 unsigned int
solver_solution_count(Solver * solv,Id problem)936 solver_solution_count(Solver *solv, Id problem)
937 {
938 Id solidx = solv->problems.elements[problem * 2 - 1];
939 if (solv->solutions.elements[solidx] < 0)
940 create_solutions(solv, problem, solidx);
941 return solv->solutions.elements[solidx];
942 }
943
944 Id
solver_next_solution(Solver * solv,Id problem,Id solution)945 solver_next_solution(Solver *solv, Id problem, Id solution)
946 {
947 Id solidx = solv->problems.elements[problem * 2 - 1];
948 if (solv->solutions.elements[solidx] < 0)
949 create_solutions(solv, problem, solidx);
950 return solv->solutions.elements[solidx + solution + 1] ? solution + 1 : 0;
951 }
952
953 unsigned int
solver_solutionelement_count(Solver * solv,Id problem,Id solution)954 solver_solutionelement_count(Solver *solv, Id problem, Id solution)
955 {
956 Id solidx = solv->problems.elements[problem * 2 - 1];
957 solidx = solv->solutions.elements[solidx + solution];
958 return solv->solutions.elements[solidx];
959 }
960
961 Id
solver_solutionelement_internalid(Solver * solv,Id problem,Id solution)962 solver_solutionelement_internalid(Solver *solv, Id problem, Id solution)
963 {
964 Id solidx = solv->problems.elements[problem * 2 - 1];
965 solidx = solv->solutions.elements[solidx + solution];
966 return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 3];
967 }
968
969 Id
solver_solutionelement_extrajobflags(Solver * solv,Id problem,Id solution)970 solver_solutionelement_extrajobflags(Solver *solv, Id problem, Id solution)
971 {
972 Id solidx = solv->problems.elements[problem * 2 - 1];
973 solidx = solv->solutions.elements[solidx + solution];
974 return solv->solutions.elements[solidx + 2 * solv->solutions.elements[solidx] + 4];
975 }
976
977
978 /*
979 * return the next item of the proposed solution
980 * here are the possibilities for p / rp and what
981 * the solver expects the application to do:
982 * p rp
983 * -------------------------------------------------------
984 * SOLVER_SOLUTION_INFARCH pkgid
985 * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
986 * SOLVER_SOLUTION_DISTUPGRADE pkgid
987 * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
988 * SOLVER_SOLUTION_BEST pkgid
989 * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
990 * SOLVER_SOLUTION_BLACK pkgid
991 * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
992 * SOLVER_SOLUTION_JOB jobidx
993 * -> remove job (jobidx - 1, jobidx) from job queue
994 * SOLVER_SOLUTION_POOLJOB jobidx
995 * -> remove job (jobidx - 1, jobidx) from pool job queue
996 * pkgid (> 0) 0
997 * -> add (SOLVER_ERASE|SOLVER_SOLVABLE, p) to the job
998 * pkgid (> 0) pkgid (> 0)
999 * -> add (SOLVER_INSTALL|SOLVER_SOLVABLE, rp) to the job
1000 * (this will replace package p)
1001 *
1002 * Thus, the solver will either ask the application to remove
1003 * a specific job from the job queue, or ask to add an install/erase
1004 * job to it.
1005 *
1006 */
1007
1008 Id
solver_next_solutionelement(Solver * solv,Id problem,Id solution,Id element,Id * p,Id * rp)1009 solver_next_solutionelement(Solver *solv, Id problem, Id solution, Id element, Id *p, Id *rp)
1010 {
1011 Id solidx = solv->problems.elements[problem * 2 - 1];
1012 solidx = solv->solutions.elements[solidx + solution];
1013 if (!solidx)
1014 return 0;
1015 solidx += 1 + element * 2;
1016 if (!solv->solutions.elements[solidx] && !solv->solutions.elements[solidx + 1])
1017 return 0;
1018 *p = solv->solutions.elements[solidx];
1019 *rp = solv->solutions.elements[solidx + 1];
1020 return element + 1;
1021 }
1022
1023 void
solver_take_solutionelement(Solver * solv,Id p,Id rp,Id extrajobflags,Queue * job)1024 solver_take_solutionelement(Solver *solv, Id p, Id rp, Id extrajobflags, Queue *job)
1025 {
1026 int i;
1027
1028 if (p == SOLVER_SOLUTION_POOLJOB)
1029 {
1030 solv->pool->pooljobs.elements[rp - 1] = SOLVER_NOOP;
1031 solv->pool->pooljobs.elements[rp] = 0;
1032 return;
1033 }
1034 if (p == SOLVER_SOLUTION_JOB)
1035 {
1036 job->elements[rp - 1] = SOLVER_NOOP;
1037 job->elements[rp] = 0;
1038 return;
1039 }
1040 if (rp <= 0 && p <= 0)
1041 return; /* just in case */
1042 if (rp > 0)
1043 p = SOLVER_INSTALL|SOLVER_SOLVABLE|SOLVER_NOTBYUSER|extrajobflags;
1044 else
1045 {
1046 rp = p;
1047 p = SOLVER_ERASE|SOLVER_SOLVABLE|extrajobflags;
1048 }
1049 for (i = 0; i < job->count; i += 2)
1050 if (job->elements[i] == p && job->elements[i + 1] == rp)
1051 return;
1052 queue_push2(job, p, rp);
1053 }
1054
1055 void
solver_take_solution(Solver * solv,Id problem,Id solution,Queue * job)1056 solver_take_solution(Solver *solv, Id problem, Id solution, Queue *job)
1057 {
1058 Id p, rp, element = 0;
1059 Id extrajobflags = solver_solutionelement_extrajobflags(solv, problem, solution);
1060 while ((element = solver_next_solutionelement(solv, problem, solution, element, &p, &rp)) != 0)
1061 solver_take_solutionelement(solv, p, rp, extrajobflags, job);
1062 }
1063
1064
1065 /*-------------------------------------------------------------------
1066 *
1067 * find problem rule
1068 */
1069
1070 static void
findproblemrule_internal(Solver * solv,Id idx,Id * reqrp,Id * conrp,Id * sysrp,Id * jobrp,Id * blkrp,Map * rseen)1071 findproblemrule_internal(Solver *solv, Id idx, Id *reqrp, Id *conrp, Id *sysrp, Id *jobrp, Id *blkrp, Map *rseen)
1072 {
1073 Id rid, d;
1074 Id lreqr, lconr, lsysr, ljobr, lblkr;
1075 Rule *r;
1076 Id jobassert = 0;
1077 int i, reqset = 0; /* 0: unset, 1: installed, 2: jobassert, 3: assert */
1078 int conset = 0; /* 0: unset, 1: installed */
1079
1080 /* find us a jobassert rule */
1081 for (i = idx; (rid = solv->learnt_pool.elements[i]) != 0; i++)
1082 {
1083 if (rid < solv->jobrules || rid >= solv->jobrules_end)
1084 continue;
1085 r = solv->rules + rid;
1086 d = r->d < 0 ? -r->d - 1 : r->d;
1087 if (!d && r->w2 == 0 && r->p > 0)
1088 {
1089 jobassert = r->p;
1090 break;
1091 }
1092 }
1093
1094 /* the problem rules are somewhat ordered from "near to the problem" to
1095 * "near to the job" */
1096 lreqr = lconr = lsysr = ljobr = lblkr = 0;
1097 while ((rid = solv->learnt_pool.elements[idx++]) != 0)
1098 {
1099 assert(rid > 0);
1100 if (rid >= solv->learntrules)
1101 {
1102 if (MAPTST(rseen, rid - solv->learntrules))
1103 continue;
1104 MAPSET(rseen, rid - solv->learntrules);
1105 findproblemrule_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], &lreqr, &lconr, &lsysr, &ljobr, &lblkr, rseen);
1106 }
1107 else if ((rid >= solv->jobrules && rid < solv->jobrules_end) || (rid >= solv->infarchrules && rid < solv->infarchrules_end) || (rid >= solv->duprules && rid < solv->duprules_end) || (rid >= solv->bestrules && rid < solv->bestrules_end) || (rid >= solv->yumobsrules && rid < solv->yumobsrules_end))
1108 {
1109 if (!*jobrp)
1110 *jobrp = rid;
1111 }
1112 else if (rid >= solv->updaterules && rid < solv->updaterules_end)
1113 {
1114 if (!*sysrp)
1115 *sysrp = rid;
1116 }
1117 else if (rid >= solv->blackrules && rid < solv->blackrules_end)
1118 {
1119 if (!*blkrp)
1120 *blkrp = rid;
1121 }
1122 else
1123 {
1124 assert(rid < solv->pkgrules_end);
1125 r = solv->rules + rid;
1126 d = r->d < 0 ? -r->d - 1 : r->d;
1127 if (!d && r->w2 < 0)
1128 {
1129 /* prefer conflicts of installed packages */
1130 if (solv->installed && !conset)
1131 {
1132 if (r->p < 0 && (solv->pool->solvables[-r->p].repo == solv->installed ||
1133 solv->pool->solvables[-r->w2].repo == solv->installed))
1134 {
1135 *conrp = rid;
1136 conset = 1;
1137 }
1138 }
1139 if (!*conrp)
1140 *conrp = rid;
1141 }
1142 else
1143 {
1144 if (!d && r->w2 == 0 && reqset < 3)
1145 {
1146 if (*reqrp > 0 && r->p < -1)
1147 {
1148 Pool *pool = solv->pool;
1149 Id op = -solv->rules[*reqrp].p;
1150 if (op > 1 && pool->solvables[op].arch != pool->solvables[-r->p].arch &&
1151 pool->solvables[op].arch != pool->noarchid &&
1152 pool->solvables[-r->p].arch != pool->noarchid)
1153 continue; /* different arch, skip */
1154 }
1155 /* prefer assertions */
1156 *reqrp = rid;
1157 reqset = 3;
1158 }
1159 else if (jobassert && r->p == -jobassert)
1160 {
1161 /* prefer rules of job assertions */
1162 *reqrp = rid;
1163 reqset = 2;
1164 }
1165 else if (solv->installed && r->p < 0 && solv->pool->solvables[-r->p].repo == solv->installed && reqset <= 1)
1166 {
1167 /* prefer rules of job installed package so that the user doesn't get confused by strange packages */
1168 *reqrp = rid;
1169 reqset = 1;
1170 }
1171 else if (!*reqrp)
1172 *reqrp = rid;
1173 }
1174 }
1175 }
1176 if (!*reqrp && lreqr)
1177 *reqrp = lreqr;
1178 if (!*conrp && lconr)
1179 *conrp = lconr;
1180 if (!*jobrp && ljobr)
1181 *jobrp = ljobr;
1182 if (!*sysrp && lsysr)
1183 *sysrp = lsysr;
1184 if (!*blkrp && lblkr)
1185 *blkrp = lblkr;
1186 }
1187
1188 /*
1189 * find problem rule
1190 *
1191 * search for a rule that describes the problem to the
1192 * user. Actually a pretty hopeless task that may leave the user
1193 * puzzled. To get all of the needed information use
1194 * solver_findallproblemrules() instead.
1195 */
1196
1197 Id
solver_findproblemrule(Solver * solv,Id problem)1198 solver_findproblemrule(Solver *solv, Id problem)
1199 {
1200 Id reqr, conr, sysr, jobr, blkr;
1201 Id idx = solv->problems.elements[2 * problem - 2];
1202 Map rseen;
1203 reqr = conr = sysr = jobr = blkr = 0;
1204 map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1205 findproblemrule_internal(solv, idx, &reqr, &conr, &sysr, &jobr, &blkr, &rseen);
1206 map_free(&rseen);
1207 /* check if the request is about a not-installed package requiring a installed
1208 * package conflicting with the non-installed package. In that case return the conflict */
1209 if (reqr && conr && solv->installed && solv->rules[reqr].p < 0 && solv->rules[conr].p < 0 && solv->rules[conr].w2 < 0)
1210 {
1211 Pool *pool = solv->pool;
1212 Solvable *s = pool->solvables - solv->rules[reqr].p;
1213 Solvable *s1 = pool->solvables - solv->rules[conr].p;
1214 Solvable *s2 = pool->solvables - solv->rules[conr].w2;
1215 Id cp = 0;
1216 if (s == s1 && s2->repo == solv->installed)
1217 cp = -solv->rules[conr].w2;
1218 else if (s == s2 && s1->repo == solv->installed)
1219 cp = -solv->rules[conr].p;
1220 if (cp && s1->name != s2->name && s->repo != solv->installed)
1221 {
1222 Id p, pp;
1223 Rule *r = solv->rules + reqr;
1224 FOR_RULELITERALS(p, pp, r)
1225 if (p == cp)
1226 return conr;
1227 }
1228 }
1229 if (reqr)
1230 return reqr; /* some requires */
1231 if (conr)
1232 return conr; /* some conflict */
1233 if (blkr)
1234 return blkr; /* a blacklisted package */
1235 if (sysr)
1236 return sysr; /* an update rule */
1237 if (jobr)
1238 return jobr; /* a user request */
1239 assert(0);
1240 return 0;
1241 }
1242
1243 /*-------------------------------------------------------------------*/
1244
1245 static void
findallproblemrules_internal(Solver * solv,Id idx,Queue * rules,Map * rseen)1246 findallproblemrules_internal(Solver *solv, Id idx, Queue *rules, Map *rseen)
1247 {
1248 Id rid;
1249 while ((rid = solv->learnt_pool.elements[idx++]) != 0)
1250 {
1251 if (rid >= solv->learntrules)
1252 {
1253 if (MAPTST(rseen, rid - solv->learntrules))
1254 continue;
1255 MAPSET(rseen, rid - solv->learntrules);
1256 findallproblemrules_internal(solv, solv->learnt_why.elements[rid - solv->learntrules], rules, rseen);
1257 continue;
1258 }
1259 queue_pushunique(rules, rid);
1260 }
1261 }
1262
1263 /*
1264 * find all problem rule
1265 *
1266 * return all rules that lead to the problem. This gives the user
1267 * all of the information to understand the problem, but the result
1268 * can be a large number of rules.
1269 */
1270
1271 void
solver_findallproblemrules(Solver * solv,Id problem,Queue * rules)1272 solver_findallproblemrules(Solver *solv, Id problem, Queue *rules)
1273 {
1274 Map rseen;
1275 queue_empty(rules);
1276 map_init(&rseen, solv->learntrules ? solv->nrules - solv->learntrules : 0);
1277 findallproblemrules_internal(solv, solv->problems.elements[2 * problem - 2], rules, &rseen);
1278 map_free(&rseen);
1279 }
1280
1281 const char *
solver_problemruleinfo2str(Solver * solv,SolverRuleinfo type,Id source,Id target,Id dep)1282 solver_problemruleinfo2str(Solver *solv, SolverRuleinfo type, Id source, Id target, Id dep)
1283 {
1284 Pool *pool = solv->pool;
1285 char *s;
1286 Solvable *ss;
1287 switch (type)
1288 {
1289 case SOLVER_RULE_DISTUPGRADE:
1290 return pool_tmpjoin(pool, pool_solvid2str(pool, source), " does not belong to a distupgrade repository", 0);
1291 case SOLVER_RULE_INFARCH:
1292 return pool_tmpjoin(pool, pool_solvid2str(pool, source), " has inferior architecture", 0);
1293 case SOLVER_RULE_UPDATE:
1294 return pool_tmpjoin(pool, "problem with installed package ", pool_solvid2str(pool, source), 0);
1295 case SOLVER_RULE_JOB:
1296 return "conflicting requests";
1297 case SOLVER_RULE_JOB_UNSUPPORTED:
1298 return "unsupported request";
1299 case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
1300 return pool_tmpjoin(pool, "nothing provides requested ", pool_dep2str(pool, dep), 0);
1301 case SOLVER_RULE_JOB_UNKNOWN_PACKAGE:
1302 return pool_tmpjoin(pool, "package ", pool_dep2str(pool, dep), " does not exist");
1303 case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
1304 return pool_tmpjoin(pool, pool_dep2str(pool, dep), " is provided by the system", 0);
1305 case SOLVER_RULE_PKG:
1306 return "some dependency problem";
1307 case SOLVER_RULE_BEST:
1308 if (source > 0)
1309 return pool_tmpjoin(pool, "cannot install the best update candidate for package ", pool_solvid2str(pool, source), 0);
1310 return "cannot install the best candidate for the job";
1311 case SOLVER_RULE_PKG_NOT_INSTALLABLE:
1312 ss = pool->solvables + source;
1313 if (pool_disabled_solvable(pool, ss))
1314 return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is disabled");
1315 if (ss->arch && ss->arch != ARCH_SRC && ss->arch != ARCH_NOSRC &&
1316 pool->id2arch && pool_arch2score(pool, ss->arch) == 0)
1317 return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " does not have a compatible architecture");
1318 return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " is not installable");
1319 case SOLVER_RULE_PKG_NOTHING_PROVIDES_DEP:
1320 s = pool_tmpjoin(pool, "nothing provides ", pool_dep2str(pool, dep), 0);
1321 return pool_tmpappend(pool, s, " needed by ", pool_solvid2str(pool, source));
1322 case SOLVER_RULE_PKG_SAME_NAME:
1323 s = pool_tmpjoin(pool, "cannot install both ", pool_solvid2str(pool, source), 0);
1324 return pool_tmpappend(pool, s, " and ", pool_solvid2str(pool, target));
1325 case SOLVER_RULE_PKG_CONFLICTS:
1326 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
1327 s = pool_tmpappend(pool, s, " conflicts with ", pool_dep2str(pool, dep));
1328 return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
1329 case SOLVER_RULE_PKG_OBSOLETES:
1330 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
1331 s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
1332 return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
1333 case SOLVER_RULE_PKG_INSTALLED_OBSOLETES:
1334 s = pool_tmpjoin(pool, "installed package ", pool_solvid2str(pool, source), 0);
1335 s = pool_tmpappend(pool, s, " obsoletes ", pool_dep2str(pool, dep));
1336 return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
1337 case SOLVER_RULE_PKG_IMPLICIT_OBSOLETES:
1338 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
1339 s = pool_tmpappend(pool, s, " implicitly obsoletes ", pool_dep2str(pool, dep));
1340 return pool_tmpappend(pool, s, " provided by ", pool_solvid2str(pool, target));
1341 case SOLVER_RULE_PKG_REQUIRES:
1342 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " requires ");
1343 return pool_tmpappend(pool, s, pool_dep2str(pool, dep), ", but none of the providers can be installed");
1344 case SOLVER_RULE_PKG_SELF_CONFLICT:
1345 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " conflicts with ");
1346 return pool_tmpappend(pool, s, pool_dep2str(pool, dep), " provided by itself");
1347 case SOLVER_RULE_YUMOBS:
1348 s = pool_tmpjoin(pool, "both package ", pool_solvid2str(pool, source), " and ");
1349 s = pool_tmpjoin(pool, s, pool_solvid2str(pool, target), " obsolete ");
1350 return pool_tmpappend(pool, s, pool_dep2str(pool, dep), 0);
1351 case SOLVER_RULE_BLACK:
1352 return pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), " can only be installed by a direct request");
1353 case SOLVER_RULE_PKG_CONSTRAINS:
1354 s = pool_tmpjoin(pool, "package ", pool_solvid2str(pool, source), 0);
1355 s = pool_tmpappend(pool, s, " has constraint ", pool_dep2str(pool, dep));
1356 return pool_tmpappend(pool, s, " conflicting with ", pool_solvid2str(pool, target));
1357 default:
1358 return "bad problem rule type";
1359 }
1360 }
1361
1362 /* convenience function */
1363 const char *
solver_problem2str(Solver * solv,Id problem)1364 solver_problem2str(Solver *solv, Id problem)
1365 {
1366 Id type, source, target, dep;
1367 Id r = solver_findproblemrule(solv, problem);
1368 if (!r)
1369 return "no problem rule?";
1370 type = solver_ruleinfo(solv, r, &source, &target, &dep);
1371 return solver_problemruleinfo2str(solv, type, source, target, dep);
1372 }
1373
1374 const char *
solver_solutionelement2str(Solver * solv,Id p,Id rp)1375 solver_solutionelement2str(Solver *solv, Id p, Id rp)
1376 {
1377 Pool *pool = solv->pool;
1378 if (p == SOLVER_SOLUTION_JOB || p == SOLVER_SOLUTION_POOLJOB)
1379 {
1380 Id how, what;
1381 if (p == SOLVER_SOLUTION_JOB)
1382 rp += solv->pooljobcnt;
1383 how = solv->job.elements[rp - 1];
1384 what = solv->job.elements[rp];
1385 return pool_tmpjoin(pool, "do not ask to ", pool_job2str(pool, how, what, 0), 0);
1386 }
1387 else if (p == SOLVER_SOLUTION_INFARCH)
1388 {
1389 Solvable *s = pool->solvables + rp;
1390 if (solv->installed && s->repo == solv->installed)
1391 return pool_tmpjoin(pool, "keep ", pool_solvable2str(pool, s), " despite the inferior architecture");
1392 else
1393 return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the inferior architecture");
1394 }
1395 else if (p == SOLVER_SOLUTION_DISTUPGRADE)
1396 {
1397 Solvable *s = pool->solvables + rp;
1398 if (solv->installed && s->repo == solv->installed)
1399 return pool_tmpjoin(pool, "keep obsolete ", pool_solvable2str(pool, s), 0);
1400 else
1401 return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " from excluded repository");
1402 }
1403 else if (p == SOLVER_SOLUTION_BEST)
1404 {
1405 Solvable *s = pool->solvables + rp;
1406 if (solv->installed && s->repo == solv->installed)
1407 return pool_tmpjoin(pool, "keep old ", pool_solvable2str(pool, s), 0);
1408 else
1409 return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), " despite the old version");
1410 }
1411 else if (p == SOLVER_SOLUTION_BLACK)
1412 {
1413 Solvable *s = pool->solvables + rp;
1414 return pool_tmpjoin(pool, "install ", pool_solvable2str(pool, s), 0);
1415 }
1416 else if (p > 0 && rp == 0)
1417 return pool_tmpjoin(pool, "allow deinstallation of ", pool_solvid2str(pool, p), 0);
1418 else if (p > 0 && rp > 0)
1419 {
1420 const char *sp = pool_solvid2str(pool, p);
1421 const char *srp = pool_solvid2str(pool, rp);
1422 const char *str = pool_tmpjoin(pool, "allow replacement of ", sp, 0);
1423 return pool_tmpappend(pool, str, " with ", srp);
1424 }
1425 else
1426 return "bad solution element";
1427 }
1428
1429