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 prune_to_highest_prio(pool, plist);
00385 if (plist->count > 1 && mode == POLICY_MODE_CHOOSE)
00386 prune_to_recommended(solv, plist);
00387 prune_best_arch_name_version(solv, pool, plist);
00388 }
00389
00390
00391 int
00392 policy_illegal_archchange(Solver *solv, Solvable *s1, Solvable *s2)
00393 {
00394 Pool *pool = solv->pool;
00395 Id a1 = s1->arch, a2 = s2->arch;
00396
00397 if (solv && solv->archCheckCb)
00398 {
00399 return solv->archCheckCb(solv->pool, s1, s2);
00400 }
00401
00402
00403 #ifndef DEBIAN_SEMANTICS
00404 if (a1 == a2 || a1 == ARCH_NOARCH || a2 == ARCH_NOARCH)
00405 return 0;
00406 #else
00407 if (a1 == a2 || a1 == ARCH_ALL || a2 == ARCH_ALL)
00408 return 0;
00409 #endif
00410 if (!pool->id2arch)
00411 return 0;
00412 a1 = a1 <= pool->lastarch ? pool->id2arch[a1] : 0;
00413 a2 = a2 <= pool->lastarch ? pool->id2arch[a2] : 0;
00414 if (((a1 ^ a2) & 0xffff0000) != 0)
00415 return 1;
00416 return 0;
00417 }
00418
00419 int
00420 policy_illegal_vendorchange(Solver *solv, Solvable *s1, Solvable *s2)
00421 {
00422 Pool *pool = solv->pool;
00423 Id v1, v2;
00424 Id vendormask1, vendormask2;
00425
00426 if (solv->vendorCheckCb)
00427 {
00428 return solv->vendorCheckCb(pool, s1, s2);
00429 }
00430
00431 v1 = s1->vendor ? s1->vendor : ID_EMPTY;
00432 v2 = s2->vendor ? s2->vendor : ID_EMPTY;
00433 if (v1 == v2)
00434 return 0;
00435 vendormask1 = pool_vendor2mask(pool, v1);
00436 if (!vendormask1)
00437 return 1;
00438 vendormask2 = pool_vendor2mask(pool, v2);
00439 if ((vendormask1 & vendormask2) != 0)
00440 return 0;
00441 return 1;
00442 }
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453 void
00454 policy_create_obsolete_index(Solver *solv)
00455 {
00456 Pool *pool = solv->pool;
00457 Solvable *s;
00458 Repo *installed = solv->installed;
00459 Id p, pp, obs, *obsp, *obsoletes, *obsoletes_data;
00460 int i, n, cnt;
00461
00462 if (!installed || installed->start == installed->end)
00463 return;
00464 cnt = installed->end - installed->start;
00465 solv->obsoletes = obsoletes = sat_calloc(cnt, sizeof(Id));
00466 for (i = 1; i < pool->nsolvables; i++)
00467 {
00468 s = pool->solvables + i;
00469 if (!s->obsoletes)
00470 continue;
00471 if (!pool_installable(pool, s))
00472 continue;
00473 obsp = s->repo->idarraydata + s->obsoletes;
00474 while ((obs = *obsp++) != 0)
00475 {
00476 FOR_PROVIDES(p, pp, obs)
00477 {
00478 Solvable *ps = pool->solvables + p;;
00479 if (ps->repo != installed)
00480 continue;
00481 if (ps->name == s->name)
00482 continue;
00483 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00484 continue;
00485 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00486 continue;
00487 obsoletes[p - installed->start]++;
00488 }
00489 }
00490 }
00491 n = 0;
00492 for (i = 0; i < cnt; i++)
00493 if (obsoletes[i])
00494 {
00495 n += obsoletes[i] + 1;
00496 obsoletes[i] = n;
00497 }
00498 solv->obsoletes_data = obsoletes_data = sat_calloc(n + 1, sizeof(Id));
00499 POOL_DEBUG(SAT_DEBUG_STATS, "obsoletes data: %d entries\n", n + 1);
00500 for (i = pool->nsolvables - 1; i > 0; i--)
00501 {
00502 s = pool->solvables + i;
00503 if (!s->obsoletes)
00504 continue;
00505 if (!pool_installable(pool, s))
00506 continue;
00507 obsp = s->repo->idarraydata + s->obsoletes;
00508 while ((obs = *obsp++) != 0)
00509 {
00510 FOR_PROVIDES(p, pp, obs)
00511 {
00512 Solvable *ps = pool->solvables + p;;
00513 if (ps->repo != installed)
00514 continue;
00515 if (ps->name == s->name)
00516 continue;
00517 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps, obs))
00518 continue;
00519 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps))
00520 continue;
00521 if (obsoletes_data[obsoletes[p - installed->start]] != i)
00522 obsoletes_data[--obsoletes[p - installed->start]] = i;
00523 }
00524 }
00525 }
00526 }
00527
00528
00529
00530
00531
00532
00533
00534
00535
00536
00537 void
00538 policy_findupdatepackages(Solver *solv, Solvable *s, Queue *qs, int allow_all)
00539 {
00540
00541 Pool *pool = solv->pool;
00542 Id p, pp, n, p2, pp2;
00543 Id obs, *obsp;
00544 Solvable *ps;
00545 int haveprovobs = 0;
00546
00547 queue_empty(qs);
00548
00549 if (solv && solv->updateCandidateCb)
00550 {
00551 return solv->updateCandidateCb(solv->pool, s, qs);
00552 }
00553
00554
00555
00556
00557
00558 n = s - pool->solvables;
00559
00560
00561
00562
00563 FOR_PROVIDES(p, pp, s->name)
00564 {
00565 if (p == n)
00566 continue;
00567
00568 ps = pool->solvables + p;
00569 if (s->name == ps->name)
00570 {
00571 if (!allow_all && !solv->allowdowngrade && evrcmp(pool, s->evr, ps->evr, EVRCMP_COMPARE) > 0)
00572 continue;
00573 }
00574 else if (!solv->noupdateprovide && ps->obsoletes)
00575 {
00576 obsp = ps->repo->idarraydata + ps->obsoletes;
00577 while ((obs = *obsp++) != 0)
00578 {
00579 FOR_PROVIDES(p2, pp2, obs)
00580 {
00581 Solvable *ps2 = pool->solvables + p2;
00582 if (!pool->obsoleteusesprovides && !pool_match_nevr(pool, ps2, obs))
00583 continue;
00584 if (pool->obsoleteusescolors && !pool_colormatch(pool, s, ps2))
00585 continue;
00586 if (p2 == n)
00587 break;
00588 }
00589 if (p2)
00590 break;
00591 }
00592 if (!obs)
00593 continue;
00594
00595
00596
00597 haveprovobs = 1;
00598 }
00599 else
00600 continue;
00601 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00602 continue;
00603 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00604 continue;
00605 queue_push(qs, p);
00606 }
00607
00608
00609 if (!solv->noupdateprovide && haveprovobs)
00610 return;
00611 if (solv->obsoletes && solv->obsoletes[n - solv->installed->start])
00612 {
00613 Id *opp;
00614 for (opp = solv->obsoletes_data + solv->obsoletes[n - solv->installed->start]; (p = *opp++) != 0;)
00615 {
00616 ps = pool->solvables + p;
00617 if (!allow_all && !solv->allowarchchange && s->arch != ps->arch && policy_illegal_archchange(solv, s, ps))
00618 continue;
00619 if (!allow_all && !solv->allowvendorchange && s->vendor != ps->vendor && policy_illegal_vendorchange(solv, s, ps))
00620 continue;
00621 queue_push(qs, p);
00622 }
00623 }
00624 }
00625