00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <stdio.h>
00014 #include <stdlib.h>
00015 #include <unistd.h>
00016 #include <string.h>
00017
00018 #include "solver.h"
00019 #include "evr.h"
00020 #include "policy.h"
00021 #include "poolvendor.h"
00022 #include "poolarch.h"
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032 static int
00033 prune_to_best_version_sortcmp(const void *ap, const void *bp, void *dp)
00034 {
00035 Pool *pool = dp;
00036 int r;
00037 Id a = *(Id *)ap;
00038 Id b = *(Id *)bp;
00039 Solvable *sa, *sb;
00040
00041 sa = pool->solvables + a;
00042 sb = pool->solvables + b;
00043 r = sa->name - sb->name;
00044 if (r)
00045 {
00046 const char *na, *nb;
00047
00048
00049 na = id2str(pool, sa->name);
00050 nb = id2str(pool, sb->name);
00051 return strcmp(na, nb);
00052 }
00053
00054 if (pool->installed)
00055 {
00056 if (sa->repo == pool->installed)
00057 {
00058 if (sb->repo != pool->installed)
00059 return -1;
00060 }
00061 else if (sb->repo == pool->installed)
00062 return 1;
00063 }
00064
00065 r = (sb->repo ? sb->repo->subpriority : 0) - (sa->repo ? sa->repo->subpriority : 0);
00066 if (r)
00067 return r;
00068
00069 return a - b;
00070 }
00071
00072
00073
00074
00075
00076
00077
00078 static void
00079 prune_to_highest_prio(Pool *pool, Queue *plist)
00080 {
00081 int i, j;
00082 Solvable *s;
00083 int bestprio = 0, bestprioset = 0;
00084
00085
00086 for (i = 0; i < plist->count; i++)
00087 {
00088 s = pool->solvables + plist->elements[i];
00089 if (pool->installed && s->repo == pool->installed)
00090 continue;
00091 if (!bestprioset || s->repo->priority > bestprio)
00092 {
00093 bestprio = s->repo->priority;
00094 bestprioset = 1;
00095 }
00096 }
00097 if (!bestprioset)
00098 return;
00099 for (i = j = 0; i < plist->count; i++)
00100 {
00101 s = pool->solvables + plist->elements[i];
00102 if (s->repo->priority == bestprio || (pool->installed && s->repo == pool->installed))
00103 plist->elements[j++] = plist->elements[i];
00104 }
00105 plist->count = j;
00106 }
00107
00108 static void
00109 prune_to_highest_prio_per_name(Pool *pool, Queue *plist)
00110 {
00111 Queue pq;
00112 int i, j, k;
00113 Id name;
00114
00115 queue_init(&pq);
00116 sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
00117 queue_push(&pq, plist->elements[0]);
00118 name = pool->solvables[pq.elements[0]].name;
00119 for (i = 1, j = 0; i < plist->count; i++)
00120 {
00121 if (pool->solvables[plist->elements[i]].name != name)
00122 {
00123 if (pq.count > 2)
00124 prune_to_highest_prio(pool, &pq);
00125 for (k = 0; k < pq.count; k++)
00126 plist->elements[j++] = pq.elements[k];
00127 queue_empty(&pq);
00128 queue_push(&pq, plist->elements[i]);
00129 name = pool->solvables[pq.elements[0]].name;
00130 }
00131 }
00132 if (pq.count > 2)
00133 prune_to_highest_prio(pool, &pq);
00134 for (k = 0; k < pq.count; k++)
00135 plist->elements[j++] = pq.elements[k];
00136 queue_free(&pq);
00137 plist->count = j;
00138 }
00139
00140
00141
00142
00143
00144
00145
00146 static void
00147 prune_to_recommended(Solver *solv, Queue *plist)
00148 {
00149 Pool *pool = solv->pool;
00150 int i, j, k, ninst;
00151 Solvable *s;
00152 Id p, pp, rec, *recp, sug, *sugp;
00153
00154 ninst = 0;
00155 if (pool->installed)
00156 {
00157 for (i = 0; i < plist->count; i++)
00158 {
00159 p = plist->elements[i];
00160 s = pool->solvables + p;
00161 if (pool->installed && s->repo == pool->installed)
00162 ninst++;
00163 }
00164 }
00165 if (plist->count - ninst < 2)
00166 return;
00167
00168
00169 if (solv->recommends_index < 0)
00170 {
00171 MAPZERO(&solv->recommendsmap);
00172 MAPZERO(&solv->suggestsmap);
00173 solv->recommends_index = 0;
00174 }
00175 while (solv->recommends_index < solv->decisionq.count)
00176 {
00177 p = solv->decisionq.elements[solv->recommends_index++];
00178 if (p < 0)
00179 continue;
00180 s = pool->solvables + p;
00181 if (s->recommends)
00182 {
00183 recp = s->repo->idarraydata + s->recommends;
00184 while ((rec = *recp++) != 0)
00185 FOR_PROVIDES(p, pp, rec)
00186 MAPSET(&solv->recommendsmap, p);
00187 }
00188 if (s->suggests)
00189 {
00190 sugp = s->repo->idarraydata + s->suggests;
00191 while ((sug = *sugp++) != 0)
00192 FOR_PROVIDES(p, pp, sug)
00193 MAPSET(&solv->suggestsmap, p);
00194 }
00195 }
00196
00197
00198 ninst = 0;
00199 for (i = j = 0; i < plist->count; i++)
00200 {
00201 p = plist->elements[i];
00202 s = pool->solvables + p;
00203 if (pool->installed && s->repo == pool->installed)
00204 {
00205 ninst++;
00206 if (j)
00207 plist->elements[j++] = p;
00208 continue;
00209 }
00210 if (!MAPTST(&solv->recommendsmap, p))
00211 if (!solver_is_supplementing(solv, s))
00212 continue;
00213 if (!j && ninst)
00214 {
00215 for (k = 0; j < ninst; k++)
00216 {
00217 s = pool->solvables + plist->elements[k];
00218 if (pool->installed && s->repo == pool->installed)
00219 plist->elements[j++] = plist->elements[k];
00220 }
00221 }
00222 plist->elements[j++] = p;
00223 }
00224 if (j)
00225 plist->count = j;
00226
00227
00228 if (plist->count - ninst < 2)
00229 return;
00230
00231
00232 ninst = 0;
00233 for (i = j = 0; i < plist->count; i++)
00234 {
00235 p = plist->elements[i];
00236 s = pool->solvables + p;
00237 if (pool->installed && s->repo == pool->installed)
00238 {
00239 ninst++;
00240 if (j)
00241 plist->elements[j++] = p;
00242 continue;
00243 }
00244 if (!MAPTST(&solv->suggestsmap, p))
00245 if (!solver_is_enhancing(solv, s))
00246 continue;
00247 if (!j && ninst)
00248 {
00249 for (k = 0; j < ninst; k++)
00250 {
00251 s = pool->solvables + plist->elements[k];
00252 if (pool->installed && s->repo == pool->installed)
00253 plist->elements[j++] = plist->elements[k];
00254 }
00255 }
00256 plist->elements[j++] = p;
00257 }
00258 if (j)
00259 plist->count = j;
00260 }
00261
00262 void
00263 prune_to_best_arch(const Pool *pool, Queue *plist)
00264 {
00265 Id a, bestscore;
00266 Solvable *s;
00267 int i, j;
00268
00269 if (!pool->id2arch || plist->count < 2)
00270 return;
00271 bestscore = 0;
00272 for (i = 0; i < plist->count; i++)
00273 {
00274 s = pool->solvables + plist->elements[i];
00275 a = s->arch;
00276 a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
00277 if (a && a != 1 && (!bestscore || a < bestscore))
00278 bestscore = a;
00279 }
00280 if (!bestscore)
00281 return;
00282 for (i = j = 0; i < plist->count; i++)
00283 {
00284 s = pool->solvables + plist->elements[i];
00285 a = s->arch;
00286 if (a > pool->lastarch)
00287 continue;
00288 a = pool->id2arch[a];
00289
00290 if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
00291 continue;
00292 plist->elements[j++] = plist->elements[i];
00293 }
00294 if (j)
00295 plist->count = j;
00296 }
00297
00298
00299
00300
00301
00302
00303 static void
00304 prune_obsoleted(Pool *pool, Queue *plist)
00305 {
00306 int i, j;
00307 Solvable *s;
00308
00309
00310
00311 for (i = 0; i < plist->count; i++)
00312 {
00313 Id p, pp, obs, *obsp;
00314 s = pool->solvables + plist->elements[i];
00315 if (!s->obsoletes)
00316 continue;
00317 obsp = s->repo->idarraydata + s->obsoletes;
00318 while ((obs = *obsp++) != 0)
00319 {
00320 FOR_PROVIDES(p, pp, obs)
00321 {
00322 Solvable *ps = pool->solvables + p;
00323 if (ps->name == s->name)
00324 continue;
00325 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00326 continue;
00327 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00328 continue;
00329
00330 for (j = 0; j < plist->count; j++)
00331 {
00332 if (i == j)
00333 continue;
00334 if (plist->elements[j] == p)
00335 plist->elements[j] = 0;
00336 }
00337 }
00338 }
00339 }
00340
00341 for (i = j = 0; i < plist->count; i++)
00342 if (plist->elements[i])
00343 plist->elements[j++] = plist->elements[i];
00344 plist->count = j;
00345 }
00346
00347
00348
00349
00350
00351
00352
00353 void
00354 prune_to_best_version(Pool *pool, Queue *plist)
00355 {
00356 int i, j;
00357 Solvable *s, *best;
00358
00359 if (plist->count < 2)
00360 return;
00361 POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
00362
00363
00364 sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
00365
00366
00367 best = 0;
00368 for (i = j = 0; i < plist->count; i++)
00369 {
00370 s = pool->solvables + plist->elements[i];
00371
00372 POOL_DEBUG(SAT_DEBUG_POLICY, "- %s[%s]\n",
00373 solvable2str(pool, s),
00374 (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
00375
00376 if (!best)
00377 {
00378 best = s;
00379 continue;
00380 }
00381
00382
00383 if (best->name != s->name)
00384 {
00385 plist->elements[j++] = best - pool->solvables;
00386 best = s;
00387 continue;
00388 }
00389
00390 if (best->evr != s->evr)
00391 {
00392 if (evrcmp(pool, best->evr, s->evr, EVRCMP_COMPARE) < 0)
00393 best = s;
00394 }
00395 }
00396 plist->elements[j++] = best - pool->solvables;
00397 plist->count = j;
00398
00399
00400
00401 if (plist->count > 1)
00402 prune_obsoleted(pool, plist);
00403 }
00404
00405
00406
00407
00408
00409
00410 void
00411 prune_best_arch_name_version(const Solver *solv, Pool *pool, Queue *plist)
00412 {
00413 if (solv && solv->bestSolvableCb)
00414 {
00415 return solv->bestSolvableCb(solv->pool, plist);
00416 }
00417
00418 if (plist->count > 1)
00419 prune_to_best_arch(pool, plist);
00420 if (plist->count > 1)
00421 prune_to_best_version(pool, plist);
00422 }
00423
00424
00425
00426 static void
00427 prune_installed_dup_packages(Solver *solv, Queue *plist)
00428 {
00429 Pool *pool = solv->pool;
00430 int i, j, k;
00431
00432 for (i = j = 0; i < plist->count; i++)
00433 {
00434 Id p = plist->elements[i];
00435 Solvable *s = pool->solvables + p;
00436 if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
00437 {
00438 for (k = 0; k < plist->count; k++)
00439 {
00440 Solvable *s2 = pool->solvables + plist->elements[k];
00441 if (s2->repo != pool->installed && solvable_identical(s, s2))
00442 break;
00443 }
00444 if (k == plist->count)
00445 continue;
00446 }
00447 plist->elements[j++] = p;
00448 }
00449 if (j)
00450 plist->count = j;
00451 }
00452
00453
00454
00455
00456
00457
00458 void
00459 policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
00460 {
00461 Pool *pool = solv->pool;
00462 if (plist->count > 1)
00463 {
00464 if (mode != POLICY_MODE_SUGGEST)
00465 prune_to_highest_prio(pool, plist);
00466 else
00467 prune_to_highest_prio_per_name(pool, plist);
00468
00469
00470 if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
00471 prune_installed_dup_packages(solv, plist);
00472 }
00473 if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
00474 prune_to_recommended(solv, plist);
00475 prune_best_arch_name_version(solv, pool, plist);
00476 }
00477
00478
00479
00480
00481 int
00482 policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
00483 {
00484 Pool *pool = solv->pool;
00485 Id a1 = s1->arch, a2 = s2->arch;
00486
00487 if (solv && solv->archCheckCb)
00488 {
00489 return solv->archCheckCb(solv->pool, s1, s2);
00490 }
00491
00492
00493 #ifndef DEBIAN_SEMANTICS
00494 if (a1 == a2 || a1 == ARCH_NOARCH || a2 == ARCH_NOARCH)
00495 return 0;
00496 #else
00497 if (a1 == a2 || a1 == ARCH_ALL || a2 == ARCH_ALL)
00498 return 0;
00499 #endif
00500 if (!pool->id2arch)
00501 return 0;
00502 a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
00503 a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
00504 if (((a1 ^ a2) & 0xffff0000) != 0)
00505 return 1;
00506 return 0;
00507 }
00508
00509
00510
00511 int
00512 policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
00513 {
00514 Pool *pool = solv->pool;
00515 Id v1, v2;
00516 Id vendormask1, vendormask2;
00517
00518 if (solv->vendorCheckCb)
00519 {
00520 return solv->vendorCheckCb(pool, s1, s2);
00521 }
00522
00523 v1 = s1->vendor ? s1->vendor : ID_EMPTY;
00524 v2 = s2->vendor ? s2->vendor : ID_EMPTY;
00525 if (v1 == v2)
00526 return 0;
00527 vendormask1 = pool_vendor2mask(pool, v1);
00528 if (!vendormask1)
00529 return 1;
00530 vendormask2 = pool_vendor2mask(pool, v2);
00531 if ((vendormask1 & vendormask2) != 0)
00532 return 0;
00533 return 1;
00534 }
00535
00536
00537
00538
00539 int
00540 policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
00541 {
00542 Pool *pool = solv->pool;
00543 int ret = 0;
00544 if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !solv->allowdowngrade)
00545 {
00546 if (is->name == s->name && evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
00547 ret |= POLICY_ILLEGAL_DOWNGRADE;
00548 }
00549 if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !solv->allowarchchange)
00550 {
00551 if (is->arch != s->arch && policy_illegal_archchange(solv, is, s))
00552 ret |= POLICY_ILLEGAL_ARCHCHANGE;
00553 }
00554 if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !solv->allowvendorchange)
00555 {
00556 if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, is, s))
00557 ret |= POLICY_ILLEGAL_VENDORCHANGE;
00558 }
00559 return ret;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570 void
00571 policy_create_obsolete_index(Solver *solv)
00572 {
00573 Pool *pool = solv->pool;
00574 Solvable *s;
00575 Repo *installed = solv->installed;
00576 Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
00577 int i, n, cnt;
00578
00579 if (!installed || installed->start == installed->end)
00580 return;
00581 cnt = installed->end - installed->start;
00582 solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
00583 for (i = 1; i < pool->nsolvables; i++)
00584 {
00585 s = pool->solvables + i;
00586 if (!s->obsoletes)
00587 continue;
00588 if (!pool_installable(pool, s))
00589 continue;
00590 obsp = s->repo->idarraydata + s->obsoletes;
00591 while ((obs = *obsp++) != 0)
00592 {
00593 FOR_PROVIDES(p, pp, obs)
00594 {
00595 Solvable *ps = pool->solvables + p;;
00596 if (ps->repo != installed)
00597 continue;
00598 if (ps->name == s->name)
00599 continue;
00600 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00601 continue;
00602 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00603 continue;
00604 obsoletes[p - installed->start]++;
00605 }
00606 }
00607 }
00608 n = 0;
00609 for (i = 0; i < cnt; i++)
00610 if (obsoletes[i])
00611 {
00612 n += obsoletes[i] + 1;
00613 obsoletes[i] = n;
00614 }
00615 solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
00616 POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
00617 for (i = pool->nsolvables - 1; i > 0; i--)
00618 {
00619 s = pool->solvables + i;
00620 if (!s->obsoletes)
00621 continue;
00622 if (!pool_installable(pool, s))
00623 continue;
00624 obsp = s->repo->idarraydata + s->obsoletes;
00625 while ((obs = *obsp++) != 0)
00626 {
00627 FOR_PROVIDES(p, pp, obs)
00628 {
00629 Solvable *ps = pool->solvables + p;;
00630 if (ps->repo != installed)
00631 continue;
00632 if (ps->name == s->name)
00633 continue;
00634 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00635 continue;
00636 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00637 continue;
00638 if (obsoletes_data[obsoletes[p - installed->start]] != i)
00639 obsoletes_data[--obsoletes[p - installed->start]] = i;
00640 }
00641 }
00642 }
00643 }
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654 void
00655 policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
00656 {
00657
00658 Pool *pool = solv->pool;
00659 Id p, pp, n, p2, pp2;
00660 Id obs, *obsp;
00661 Solvable *ps;
00662 int haveprovobs = 0;
00663
00664 queue_empty(qs);
00665
00666 if (solv && solv->updateCandidateCb)
00667 {
00668 return solv->updateCandidateCb(solv->pool, s, qs);
00669 }
00670
00671 n = s - pool->solvables;
00672
00673
00674
00675
00676 FOR_PROVIDES(p, pp, s->name)
00677 {
00678 if (p == n)
00679 continue;
00680
00681 ps = pool->solvables + p;
00682 if (s->name == ps->name)
00683 {
00684 if (!allow_all && !solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
00685 continue;
00686 }
00687 else if (!solv->noupdateprovide && ps->obsoletes)
00688 {
00689 obsp = ps->repo->idarraydata + ps->obsoletes;
00690 while ((obs = *obsp++) != 0)
00691 {
00692 FOR_PROVIDES(p2, pp2, obs)
00693 {
00694 Solvable *ps2 = pool->solvables + p2;
00695 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
00696 continue;
00697 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps2))
00698 continue;
00699 if (p2 == n)
00700 break;
00701 }
00702 if (p2)
00703 break;
00704 }
00705 if (!obs)
00706 continue;
00707
00708
00709
00710 haveprovobs = 1;
00711 }
00712 else
00713 continue;
00714 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00715 continue;
00716 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00717 continue;
00718 queue_push(qs, p);
00719 }
00720
00721
00722 if (!solv->noupdateprovide && haveprovobs)
00723 return;
00724 if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
00725 {
00726 Id *opp;
00727 for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
00728 {
00729 ps = pool->solvables + p;
00730 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00731 continue;
00732 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00733 continue;
00734 queue_push(qs, p);
00735 }
00736 }
00737 }
00738