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
00109
00110
00111
00112
00113
00114 static void
00115 prune_to_recommended(Solver *solv, Queue *plist)
00116 {
00117 Pool *pool = solv->pool;
00118 int i, j, k, ninst;
00119 Solvable *s;
00120 Id p, pp, rec, *recp, sug, *sugp;
00121
00122 ninst = 0;
00123 if (pool->installed)
00124 {
00125 for (i = 0; i < plist->count; i++)
00126 {
00127 p = plist->elements[i];
00128 s = pool->solvables + p;
00129 if (pool->installed && s->repo == pool->installed)
00130 ninst++;
00131 }
00132 }
00133 if (plist->count - ninst < 2)
00134 return;
00135
00136
00137 if (solv->recommends_index < 0)
00138 {
00139 MAPZERO(&solv->recommendsmap);
00140 MAPZERO(&solv->suggestsmap);
00141 solv->recommends_index = 0;
00142 }
00143 while (solv->recommends_index < solv->decisionq.count)
00144 {
00145 p = solv->decisionq.elements[solv->recommends_index++];
00146 if (p < 0)
00147 continue;
00148 s = pool->solvables + p;
00149 if (s->recommends)
00150 {
00151 recp = s->repo->idarraydata + s->recommends;
00152 while ((rec = *recp++) != 0)
00153 FOR_PROVIDES(p, pp, rec)
00154 MAPSET(&solv->recommendsmap, p);
00155 }
00156 if (s->suggests)
00157 {
00158 sugp = s->repo->idarraydata + s->suggests;
00159 while ((sug = *sugp++) != 0)
00160 FOR_PROVIDES(p, pp, sug)
00161 MAPSET(&solv->suggestsmap, p);
00162 }
00163 }
00164
00165
00166 ninst = 0;
00167 for (i = j = 0; i < plist->count; i++)
00168 {
00169 p = plist->elements[i];
00170 s = pool->solvables + p;
00171 if (pool->installed && s->repo == pool->installed)
00172 {
00173 ninst++;
00174 if (j)
00175 plist->elements[j++] = p;
00176 continue;
00177 }
00178 if (!MAPTST(&solv->recommendsmap, p))
00179 if (!solver_is_supplementing(solv, s))
00180 continue;
00181 if (!j && ninst)
00182 {
00183 for (k = 0; j < ninst; k++)
00184 {
00185 s = pool->solvables + plist->elements[k];
00186 if (pool->installed && s->repo == pool->installed)
00187 plist->elements[j++] = plist->elements[k];
00188 }
00189 }
00190 plist->elements[j++] = p;
00191 }
00192 if (j)
00193 plist->count = j;
00194
00195
00196 if (plist->count - ninst < 2)
00197 return;
00198
00199
00200 ninst = 0;
00201 for (i = j = 0; i < plist->count; i++)
00202 {
00203 p = plist->elements[i];
00204 s = pool->solvables + p;
00205 if (pool->installed && s->repo == pool->installed)
00206 {
00207 ninst++;
00208 if (j)
00209 plist->elements[j++] = p;
00210 continue;
00211 }
00212 if (!MAPTST(&solv->suggestsmap, p))
00213 if (!solver_is_enhancing(solv, s))
00214 continue;
00215 if (!j && ninst)
00216 {
00217 for (k = 0; j < ninst; k++)
00218 {
00219 s = pool->solvables + plist->elements[k];
00220 if (pool->installed && s->repo == pool->installed)
00221 plist->elements[j++] = plist->elements[k];
00222 }
00223 }
00224 plist->elements[j++] = p;
00225 }
00226 if (j)
00227 plist->count = j;
00228 }
00229
00230 void
00231 prune_to_best_arch(const Pool *pool, Queue *plist)
00232 {
00233 Id a, bestscore;
00234 Solvable *s;
00235 int i, j;
00236
00237 if (!pool->id2arch || plist->count < 2)
00238 return;
00239 bestscore = 0;
00240 for (i = 0; i < plist->count; i++)
00241 {
00242 s = pool->solvables + plist->elements[i];
00243 a = s->arch;
00244 a = (a <= pool->lastarch) ? pool->id2arch[a] : 0;
00245 if (a && a != 1 && (!bestscore || a < bestscore))
00246 bestscore = a;
00247 }
00248 for (i = j = 0; i < plist->count; i++)
00249 {
00250 s = pool->solvables + plist->elements[i];
00251 a = s->arch;
00252 if (a > pool->lastarch)
00253 continue;
00254 a = pool->id2arch[a];
00255
00256 if (a != 1 && ((a ^ bestscore) & 0xffff0000) != 0)
00257 continue;
00258 plist->elements[j++] = plist->elements[i];
00259 }
00260 if (j)
00261 plist->count = j;
00262 }
00263
00264
00265
00266
00267
00268
00269
00270 void
00271 prune_to_best_version(Pool *pool, Queue *plist)
00272 {
00273 Id best;
00274 int i, j;
00275 Solvable *s;
00276
00277 if (plist->count < 2)
00278 return;
00279 POOL_DEBUG(SAT_DEBUG_POLICY, "prune_to_best_version %d\n", plist->count);
00280
00281
00282 sat_sort(plist->elements, plist->count, sizeof(Id), prune_to_best_version_sortcmp, pool);
00283
00284
00285
00286
00287 for (i = 0; i < plist->count; i++)
00288 {
00289 Id p, pp, obs, *obsp;
00290 s = pool->solvables + plist->elements[i];
00291 if (!s->obsoletes)
00292 continue;
00293 obsp = s->repo->idarraydata + s->obsoletes;
00294 while ((obs = *obsp++) != 0)
00295 {
00296 FOR_PROVIDES(p, pp, obs)
00297 {
00298 Solvable *ps = pool->solvables + p;
00299 if (ps->name == s->name)
00300 continue;
00301 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00302 continue;
00303 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00304 continue;
00305 for (j = 0; j < plist->count; j++)
00306 {
00307 if (i == j)
00308 continue;
00309 if (plist->elements[j] == p)
00310 plist->elements[j] = 0;
00311 }
00312 }
00313 }
00314 }
00315
00316 for (i = j = 0; i < plist->count; i++)
00317 if (plist->elements[i])
00318 plist->elements[j++] = plist->elements[i];
00319 plist->count = j;
00320
00321
00322 best = 0;
00323 for (i = j = 0; i < plist->count; i++)
00324 {
00325 s = pool->solvables + plist->elements[i];
00326
00327 POOL_DEBUG(SAT_DEBUG_POLICY, "- %s[%s]\n",
00328 solvable2str(pool, s),
00329 (pool->installed && s->repo == pool->installed) ? "installed" : "not installed");
00330
00331 if (!best)
00332 {
00333 best = plist->elements[i];
00334 continue;
00335 }
00336
00337
00338 if (pool->solvables[best].name != s->name)
00339 {
00340 plist->elements[j++] = best;
00341 best = plist->elements[i];
00342 continue;
00343 }
00344
00345 if (pool->solvables[best].evr != s->evr)
00346 {
00347 if (evrcmp(pool, pool->solvables[best].evr, s->evr, EVRCMP_COMPARE) < 0)
00348 best = plist->elements[i];
00349 }
00350 }
00351
00352 if (!best)
00353 best = plist->elements[0];
00354
00355 plist->elements[j++] = best;
00356 plist->count = j;
00357 }
00358
00359
00360
00361
00362
00363
00364 void
00365 prune_best_arch_name_version(const Solver *solv, Pool *pool, Queue *plist)
00366 {
00367 if (solv && solv->bestSolvableCb)
00368 {
00369 return solv->bestSolvableCb(solv->pool, plist);
00370 }
00371
00372 if (plist->count > 1)
00373 prune_to_best_arch(pool, plist);
00374 if (plist->count > 1)
00375 prune_to_best_version(pool, plist);
00376 }
00377
00378
00379 void
00380 policy_filter_unwanted(Solver *solv, Queue *plist, int mode)
00381 {
00382 Pool *pool = solv->pool;
00383 if (plist->count > 1 && mode != POLICY_MODE_SUGGEST)
00384 {
00385 prune_to_highest_prio(pool, plist);
00386
00387
00388 if (plist->count > 1 && pool->installed && (solv->dupmap_all || solv->dupinvolvedmap.size))
00389 {
00390 int i, j, k;
00391 for (i = j = 0; i < plist->count; i++)
00392 {
00393 Id p = plist->elements[i];
00394 Solvable *s = pool->solvables + p;
00395 if (s->repo == pool->installed && (solv->dupmap_all || (solv->dupinvolvedmap.size && MAPTST(&solv->dupinvolvedmap, p))))
00396 {
00397 for (k = 0; k < plist->count; k++)
00398 {
00399 Solvable *s2 = pool->solvables + plist->elements[k];
00400 if (s2->repo != pool->installed && solvable_identical(s, s2))
00401 break;
00402 }
00403 if (k == plist->count)
00404 continue;
00405 }
00406 plist->elements[j++] = p;
00407 }
00408 if (j)
00409 plist->count = j;
00410 }
00411 }
00412 if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
00413 prune_to_recommended(solv, plist);
00414 prune_best_arch_name_version(solv, pool, plist);
00415 }
00416
00417
00418 int
00419 policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
00420 {
00421 Pool *pool = solv->pool;
00422 Id a1 = s1->arch, a2 = s2->arch;
00423
00424 if (solv && solv->archCheckCb)
00425 {
00426 return solv->archCheckCb(solv->pool, s1, s2);
00427 }
00428
00429
00430 #ifndef DEBIAN_SEMANTICS
00431 if (a1 == a2 || a1 == ARCH_NOARCH || a2 == ARCH_NOARCH)
00432 return 0;
00433 #else
00434 if (a1 == a2 || a1 == ARCH_ALL || a2 == ARCH_ALL)
00435 return 0;
00436 #endif
00437 if (!pool->id2arch)
00438 return 0;
00439 a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
00440 a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
00441 if (((a1 ^ a2) & 0xffff0000) != 0)
00442 return 1;
00443 return 0;
00444 }
00445
00446 int
00447 policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
00448 {
00449 Pool *pool = solv->pool;
00450 Id v1, v2;
00451 Id vendormask1, vendormask2;
00452
00453 if (solv->vendorCheckCb)
00454 {
00455 return solv->vendorCheckCb(pool, s1, s2);
00456 }
00457
00458 v1 = s1->vendor ? s1->vendor : ID_EMPTY;
00459 v2 = s2->vendor ? s2->vendor : ID_EMPTY;
00460 if (v1 == v2)
00461 return 0;
00462 vendormask1 = pool_vendor2mask(pool, v1);
00463 if (!vendormask1)
00464 return 1;
00465 vendormask2 = pool_vendor2mask(pool, v2);
00466 if ((vendormask1 & vendormask2) != 0)
00467 return 0;
00468 return 1;
00469 }
00470
00471
00472
00473
00474 int
00475 policy_is_illegal(Solver *solv, Solvable *is, Solvable *s, int ignore)
00476 {
00477 Pool *pool = solv->pool;
00478 int ret = 0;
00479 if (!(ignore & POLICY_ILLEGAL_DOWNGRADE) && !solv->allowdowngrade)
00480 {
00481 if (is->name == s->name && evrcmp(pool, is->evr, s->evr, EVRCMP_COMPARE) > 0)
00482 ret |= POLICY_ILLEGAL_DOWNGRADE;
00483 }
00484 if (!(ignore & POLICY_ILLEGAL_ARCHCHANGE) && !solv->allowarchchange)
00485 {
00486 if (is->arch != s->arch && policy_illegal_archchange(solv, s, is))
00487 ret |= POLICY_ILLEGAL_ARCHCHANGE;
00488 }
00489 if (!(ignore & POLICY_ILLEGAL_VENDORCHANGE) && !solv->allowvendorchange)
00490 {
00491 if (is->vendor != s->vendor && policy_illegal_vendorchange(solv, s, is))
00492 ret |= POLICY_ILLEGAL_VENDORCHANGE;
00493 }
00494 return ret;
00495 }
00496
00497
00498
00499
00500
00501
00502
00503
00504
00505 void
00506 policy_create_obsolete_index(Solver *solv)
00507 {
00508 Pool *pool = solv->pool;
00509 Solvable *s;
00510 Repo *installed = solv->installed;
00511 Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
00512 int i, n, cnt;
00513
00514 if (!installed || installed->start == installed->end)
00515 return;
00516 cnt = installed->end - installed->start;
00517 solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
00518 for (i = 1; i < pool->nsolvables; i++)
00519 {
00520 s = pool->solvables + i;
00521 if (!s->obsoletes)
00522 continue;
00523 if (!pool_installable(pool, s))
00524 continue;
00525 obsp = s->repo->idarraydata + s->obsoletes;
00526 while ((obs = *obsp++) != 0)
00527 {
00528 FOR_PROVIDES(p, pp, obs)
00529 {
00530 Solvable *ps = pool->solvables + p;;
00531 if (ps->repo != installed)
00532 continue;
00533 if (ps->name == s->name)
00534 continue;
00535 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00536 continue;
00537 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00538 continue;
00539 obsoletes[p - installed->start]++;
00540 }
00541 }
00542 }
00543 n = 0;
00544 for (i = 0; i < cnt; i++)
00545 if (obsoletes[i])
00546 {
00547 n += obsoletes[i] + 1;
00548 obsoletes[i] = n;
00549 }
00550 solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
00551 POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
00552 for (i = pool->nsolvables - 1; i > 0; i--)
00553 {
00554 s = pool->solvables + i;
00555 if (!s->obsoletes)
00556 continue;
00557 if (!pool_installable(pool, s))
00558 continue;
00559 obsp = s->repo->idarraydata + s->obsoletes;
00560 while ((obs = *obsp++) != 0)
00561 {
00562 FOR_PROVIDES(p, pp, obs)
00563 {
00564 Solvable *ps = pool->solvables + p;;
00565 if (ps->repo != installed)
00566 continue;
00567 if (ps->name == s->name)
00568 continue;
00569 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00570 continue;
00571 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00572 continue;
00573 if (obsoletes_data[obsoletes[p - installed->start]] != i)
00574 obsoletes_data[--obsoletes[p - installed->start]] = i;
00575 }
00576 }
00577 }
00578 }
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589 void
00590 policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
00591 {
00592
00593 Pool *pool = solv->pool;
00594 Id p, pp, n, p2, pp2;
00595 Id obs, *obsp;
00596 Solvable *ps;
00597 int haveprovobs = 0;
00598
00599 queue_empty(qs);
00600
00601 if (solv && solv->updateCandidateCb)
00602 {
00603 return solv->updateCandidateCb(solv->pool, s, qs);
00604 }
00605
00606
00607
00608
00609
00610 n = s - pool->solvables;
00611
00612
00613
00614
00615 FOR_PROVIDES(p, pp, s->name)
00616 {
00617 if (p == n)
00618 continue;
00619
00620 ps = pool->solvables + p;
00621 if (s->name == ps->name)
00622 {
00623 if (!allow_all && !solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
00624 continue;
00625 }
00626 else if (!solv->noupdateprovide && ps->obsoletes)
00627 {
00628 obsp = ps->repo->idarraydata + ps->obsoletes;
00629 while ((obs = *obsp++) != 0)
00630 {
00631 FOR_PROVIDES(p2, pp2, obs)
00632 {
00633 Solvable *ps2 = pool->solvables + p2;
00634 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
00635 continue;
00636 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps2))
00637 continue;
00638 if (p2 == n)
00639 break;
00640 }
00641 if (p2)
00642 break;
00643 }
00644 if (!obs)
00645 continue;
00646
00647
00648
00649 haveprovobs = 1;
00650 }
00651 else
00652 continue;
00653 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00654 continue;
00655 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00656 continue;
00657 queue_push(qs, p);
00658 }
00659
00660
00661 if (!solv->noupdateprovide && haveprovobs)
00662 return;
00663 if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
00664 {
00665 Id *opp;
00666 for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
00667 {
00668 ps = pool->solvables + p;
00669 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00670 continue;
00671 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00672 continue;
00673 queue_push(qs, p);
00674 }
00675 }
00676 }
00677