satsolver 0.16.3
|
00001 /* 00002 * Copyright (c) 2008, Novell Inc. 00003 * 00004 * This program is licensed under the BSD license, read LICENSE.BSD 00005 * for further information 00006 */ 00007 00008 /* 00009 * solvable.c 00010 * 00011 * set/retrieve data from solvables 00012 */ 00013 00014 #include <stdio.h> 00015 #include <stdlib.h> 00016 #include <stdarg.h> 00017 #include <unistd.h> 00018 #include <string.h> 00019 00020 #include "pool.h" 00021 #include "repo.h" 00022 #include "util.h" 00023 00024 const char * 00025 solvable2str(Pool *pool, Solvable *s) 00026 { 00027 const char *n, *e, *a; 00028 char *p; 00029 n = id2str(pool, s->name); 00030 e = id2str(pool, s->evr); 00031 a = id2str(pool, s->arch); 00032 p = pool_alloctmpspace(pool, strlen(n) + strlen(e) + strlen(a) + 3); 00033 sprintf(p, "%s-%s.%s", n, e, a); 00034 return p; 00035 } 00036 00037 Id 00038 solvable_lookup_id(Solvable *s, Id keyname) 00039 { 00040 if (!s->repo) 00041 return 0; 00042 return repo_lookup_id(s->repo, s - s->repo->pool->solvables, keyname); 00043 } 00044 00045 int 00046 solvable_lookup_idarray(Solvable *s, Id keyname, Queue *q) 00047 { 00048 Dataiterator di; 00049 int found = 0; 00050 00051 queue_empty(q); 00052 if (!s->repo) 00053 return 0; 00054 dataiterator_init(&di, s->repo->pool, s->repo, s - s->repo->pool->solvables, keyname, 0, SEARCH_ARRAYSENTINEL); 00055 while (dataiterator_step(&di)) 00056 { 00057 if (di.key->type != REPOKEY_TYPE_IDARRAY && di.key->type != REPOKEY_TYPE_REL_IDARRAY) 00058 continue; 00059 found = 1; 00060 if (di.kv.eof) 00061 break; 00062 queue_push(q, di.kv.id); 00063 } 00064 dataiterator_free(&di); 00065 return found; 00066 } 00067 00068 const char * 00069 solvable_lookup_str(Solvable *s, Id keyname) 00070 { 00071 if (!s->repo) 00072 return 0; 00073 return repo_lookup_str(s->repo, s - s->repo->pool->solvables, keyname); 00074 } 00075 00076 static const char * 00077 solvable_lookup_str_base(Solvable *s, Id keyname, Id basekeyname, int usebase) 00078 { 00079 Pool *pool; 00080 const char *str, *basestr; 00081 Id p, pp; 00082 Solvable *s2; 00083 int pass; 00084 00085 if (!s->repo) 00086 return 0; 00087 pool = s->repo->pool; 00088 str = solvable_lookup_str(s, keyname); 00089 if (str || keyname == basekeyname) 00090 return str; 00091 basestr = solvable_lookup_str(s, basekeyname); 00092 if (!basestr) 00093 return 0; 00094 /* search for a solvable with same name and same base that has the 00095 * translation */ 00096 if (!pool->whatprovides) 00097 return usebase ? basestr : 0; 00098 /* we do this in two passes, first same vendor, then all other vendors */ 00099 for (pass = 0; pass < 2; pass++) 00100 { 00101 FOR_PROVIDES(p, pp, s->name) 00102 { 00103 s2 = pool->solvables + p; 00104 if (s2->name != s->name) 00105 continue; 00106 if ((s->vendor == s2->vendor) != (pass == 0)) 00107 continue; 00108 str = solvable_lookup_str(s2, basekeyname); 00109 if (!str || strcmp(str, basestr)) 00110 continue; 00111 str = solvable_lookup_str(s2, keyname); 00112 if (str) 00113 return str; 00114 } 00115 } 00116 return usebase ? basestr : 0; 00117 } 00118 00119 const char * 00120 solvable_lookup_str_poollang(Solvable *s, Id keyname) 00121 { 00122 Pool *pool; 00123 int i, cols; 00124 const char *str; 00125 Id *row; 00126 00127 if (!s->repo) 00128 return 0; 00129 pool = s->repo->pool; 00130 if (!pool->nlanguages) 00131 return solvable_lookup_str(s, keyname); 00132 cols = pool->nlanguages + 1; 00133 if (!pool->languagecache) 00134 { 00135 pool->languagecache = sat_calloc(cols * ID_NUM_INTERNAL, sizeof(Id)); 00136 pool->languagecacheother = 0; 00137 } 00138 if (keyname >= ID_NUM_INTERNAL) 00139 { 00140 row = pool->languagecache + ID_NUM_INTERNAL * cols; 00141 for (i = 0; i < pool->languagecacheother; i++, row += cols) 00142 if (*row == keyname) 00143 break; 00144 if (i >= pool->languagecacheother) 00145 { 00146 pool->languagecache = sat_realloc2(pool->languagecache, pool->languagecacheother + 1, cols * sizeof(Id)); 00147 row = pool->languagecache + cols * (ID_NUM_INTERNAL + pool->languagecacheother++); 00148 *row = keyname; 00149 } 00150 } 00151 else 00152 row = pool->languagecache + keyname * cols; 00153 row++; /* skip keyname */ 00154 for (i = 0; i < pool->nlanguages; i++, row++) 00155 { 00156 if (!*row) 00157 *row = pool_id2langid(pool, keyname, pool->languages[i], 1); 00158 str = solvable_lookup_str_base(s, *row, keyname, 0); 00159 if (str) 00160 return str; 00161 } 00162 return solvable_lookup_str(s, keyname); 00163 } 00164 00165 const char * 00166 solvable_lookup_str_lang(Solvable *s, Id keyname, const char *lang, int usebase) 00167 { 00168 if (s->repo) 00169 { 00170 Id id = pool_id2langid(s->repo->pool, keyname, lang, 0); 00171 if (id) 00172 return solvable_lookup_str_base(s, id, keyname, usebase); 00173 if (!usebase) 00174 return 0; 00175 } 00176 return solvable_lookup_str(s, keyname); 00177 } 00178 00179 unsigned int 00180 solvable_lookup_num(Solvable *s, Id keyname, unsigned int notfound) 00181 { 00182 if (!s->repo) 00183 return notfound; 00184 return repo_lookup_num(s->repo, s - s->repo->pool->solvables, keyname, notfound); 00185 } 00186 00187 int 00188 solvable_lookup_void(Solvable *s, Id keyname) 00189 { 00190 if (!s->repo) 00191 return 0; 00192 return repo_lookup_void(s->repo, s - s->repo->pool->solvables, keyname); 00193 } 00194 00195 int 00196 solvable_lookup_bool(Solvable *s, Id keyname) 00197 { 00198 Repo *repo = s->repo; 00199 Pool *pool; 00200 Repodata *data; 00201 int i, j, n; 00202 00203 if (!repo) 00204 return 0; 00205 pool = repo->pool; 00206 n = s - pool->solvables; 00207 for (i = 0, data = repo->repodata; i < repo->nrepodata; i++, data++) 00208 { 00209 if (n < data->start || n >= data->end) 00210 continue; 00211 /* there are two ways of storing a bool, as num == 1 or void */ 00212 for (j = 1; j < data->nkeys; j++) 00213 { 00214 if (data->keys[j].name == keyname 00215 && (data->keys[j].type == REPOKEY_TYPE_U32 00216 || data->keys[j].type == REPOKEY_TYPE_NUM 00217 || data->keys[j].type == REPOKEY_TYPE_CONSTANT 00218 || data->keys[j].type == REPOKEY_TYPE_VOID)) 00219 { 00220 unsigned int value; 00221 if (repodata_lookup_num(data, n, keyname, &value)) 00222 return value == 1; 00223 if (repodata_lookup_void(data, n, keyname)) 00224 return 1; 00225 } 00226 } 00227 } 00228 return 0; 00229 } 00230 00231 const unsigned char * 00232 solvable_lookup_bin_checksum(Solvable *s, Id keyname, Id *typep) 00233 { 00234 Repo *repo = s->repo; 00235 00236 if (!repo) 00237 { 00238 *typep = 0; 00239 return 0; 00240 } 00241 return repo_lookup_bin_checksum(repo, s - repo->pool->solvables, keyname, typep); 00242 } 00243 00244 const char * 00245 solvable_lookup_checksum(Solvable *s, Id keyname, Id *typep) 00246 { 00247 const unsigned char *chk = solvable_lookup_bin_checksum(s, keyname, typep); 00248 /* we need the repodata just as a reference for a pool */ 00249 return chk ? repodata_chk2str(s->repo->repodata, *typep, chk) : 0; 00250 } 00251 00252 static inline const char * 00253 evrid2vrstr(Pool *pool, Id evrid) 00254 { 00255 const char *p, *evr = id2str(pool, evrid); 00256 if (!evr) 00257 return evr; 00258 for (p = evr; *p >= '0' && *p <= '9'; p++) 00259 ; 00260 return p != evr && *p == ':' ? p + 1 : evr; 00261 } 00262 00263 char * 00264 solvable_get_location(Solvable *s, unsigned int *medianrp) 00265 { 00266 Pool *pool; 00267 int l = 0; 00268 char *loc; 00269 const char *mediadir, *mediafile; 00270 00271 *medianrp = 0; 00272 if (!s->repo) 00273 return 0; 00274 pool = s->repo->pool; 00275 *medianrp = solvable_lookup_num(s, SOLVABLE_MEDIANR, 1); 00276 if (solvable_lookup_void(s, SOLVABLE_MEDIADIR)) 00277 mediadir = id2str(pool, s->arch); 00278 else 00279 mediadir = solvable_lookup_str(s, SOLVABLE_MEDIADIR); 00280 if (mediadir) 00281 l = strlen(mediadir) + 1; 00282 if (solvable_lookup_void(s, SOLVABLE_MEDIAFILE)) 00283 { 00284 const char *name, *evr, *arch; 00285 name = id2str(pool, s->name); 00286 evr = evrid2vrstr(pool, s->evr); 00287 arch = id2str(pool, s->arch); 00288 /* name-vr.arch.rpm */ 00289 loc = pool_alloctmpspace(pool, l + strlen(name) + strlen(evr) + strlen(arch) + 7); 00290 if (mediadir) 00291 sprintf(loc, "%s/%s-%s.%s.rpm", mediadir, name, evr, arch); 00292 else 00293 sprintf(loc, "%s-%s.%s.rpm", name, evr, arch); 00294 } 00295 else 00296 { 00297 mediafile = solvable_lookup_str(s, SOLVABLE_MEDIAFILE); 00298 if (!mediafile) 00299 return 0; 00300 loc = pool_alloctmpspace(pool, l + strlen(mediafile) + 1); 00301 if (mediadir) 00302 sprintf(loc, "%s/%s", mediadir, mediafile); 00303 else 00304 strcpy(loc, mediafile); 00305 } 00306 return loc; 00307 } 00308 00309 /*****************************************************************************/ 00310 00311 static inline Id dep2name(Pool *pool, Id dep) 00312 { 00313 while (ISRELDEP(dep)) 00314 { 00315 Reldep *rd = rd = GETRELDEP(pool, dep); 00316 dep = rd->name; 00317 } 00318 return dep; 00319 } 00320 00321 static inline int providedbyinstalled(Pool *pool, Map *installed, Id dep) 00322 { 00323 Id p, pp; 00324 FOR_PROVIDES(p, pp, dep) 00325 { 00326 if (p == SYSTEMSOLVABLE) 00327 return -1; 00328 if (MAPTST(installed, p)) 00329 return 1; 00330 } 00331 return 0; 00332 } 00333 00334 /* 00335 * solvable_trivial_installable_map - anwers is a solvable is installable 00336 * without any other installs/deinstalls. 00337 * The packages considered to be installed are provided via the 00338 * installedmap bitmap. A additional "conflictsmap" bitmap providing 00339 * information about the conflicts of the installed packages can be 00340 * used for extra speed up. Provide a NULL pointer if you do not 00341 * have this information. 00342 * Both maps can be created with pool_create_state_maps() or 00343 * solver_create_state_maps(). 00344 * 00345 * returns: 00346 * 1: solvable is installable without any other package changes 00347 * 0: solvable is not installable 00348 * -1: solvable is installable, but doesn't constrain any installed packages 00349 */ 00350 int 00351 solvable_trivial_installable_map(Solvable *s, Map *installedmap, Map *conflictsmap) 00352 { 00353 Pool *pool = s->repo->pool; 00354 Solvable *s2; 00355 Id p, pp, *dp; 00356 Id *reqp, req; 00357 Id *conp, con; 00358 Id *obsp, obs; 00359 int r, interesting = 0; 00360 00361 if (conflictsmap && MAPTST(conflictsmap, s - pool->solvables)) 00362 return 0; 00363 if (s->requires) 00364 { 00365 reqp = s->repo->idarraydata + s->requires; 00366 while ((req = *reqp++) != 0) 00367 { 00368 if (req == SOLVABLE_PREREQMARKER) 00369 continue; 00370 r = providedbyinstalled(pool, installedmap, req); 00371 if (!r) 00372 return 0; 00373 if (r > 0) 00374 interesting = 1; 00375 } 00376 } 00377 if (s->conflicts) 00378 { 00379 conp = s->repo->idarraydata + s->conflicts; 00380 while ((con = *conp++) != 0) 00381 { 00382 if (providedbyinstalled(pool, installedmap, con)) 00383 return 0; 00384 if (!interesting && ISRELDEP(con)) 00385 { 00386 con = dep2name(pool, con); 00387 if (providedbyinstalled(pool, installedmap, con)) 00388 interesting = 1; 00389 } 00390 } 00391 } 00392 if (s->repo) 00393 { 00394 Repo *installed = 0; 00395 if (s->obsoletes && s->repo != installed) 00396 { 00397 obsp = s->repo->idarraydata + s->obsoletes; 00398 while ((obs = *obsp++) != 0) 00399 { 00400 if (providedbyinstalled(pool, installedmap, obs)) 00401 return 0; 00402 } 00403 } 00404 if (s->repo != installed) 00405 { 00406 FOR_PROVIDES(p, pp, s->name) 00407 { 00408 s2 = pool->solvables + p; 00409 if (s2->repo == installed && s2->name == s->name) 00410 return 0; 00411 } 00412 } 00413 } 00414 if (!conflictsmap) 00415 { 00416 int i; 00417 00418 p = s - pool->solvables; 00419 for (i = 1; i < pool->nsolvables; i++) 00420 { 00421 if (!MAPTST(installedmap, i)) 00422 continue; 00423 s2 = pool->solvables + i; 00424 if (!s2->conflicts) 00425 continue; 00426 conp = s2->repo->idarraydata + s2->conflicts; 00427 while ((con = *conp++) != 0) 00428 { 00429 dp = pool_whatprovides_ptr(pool, con); 00430 for (; *dp; dp++) 00431 if (*dp == p) 00432 return 0; 00433 } 00434 } 00435 } 00436 return interesting ? 1 : -1; 00437 } 00438 00439 /* 00440 * different interface for solvable_trivial_installable_map, where 00441 * the information about the installed packages is provided 00442 * by a queue. 00443 */ 00444 int 00445 solvable_trivial_installable_queue(Solvable *s, Queue *installed) 00446 { 00447 Pool *pool = s->repo->pool; 00448 int i; 00449 Id p; 00450 Map installedmap; 00451 int r; 00452 00453 map_init(&installedmap, pool->nsolvables); 00454 for (i = 0; i < installed->count; i++) 00455 { 00456 p = installed->elements[i]; 00457 if (p > 0) /* makes it work with decisionq */ 00458 MAPSET(&installedmap, p); 00459 } 00460 r = solvable_trivial_installable_map(s, &installedmap, 0); 00461 map_free(&installedmap); 00462 return r; 00463 } 00464 00465 /* 00466 * different interface for solvable_trivial_installable_map, where 00467 * the information about the installed packages is provided 00468 * by a repo containing the installed solvables. 00469 */ 00470 int 00471 solvable_trivial_installable_repo(Solvable *s, Repo *installed) 00472 { 00473 Pool *pool = s->repo->pool; 00474 Id p; 00475 Solvable *s2; 00476 Map installedmap; 00477 int r; 00478 00479 map_init(&installedmap, pool->nsolvables); 00480 FOR_REPO_SOLVABLES(installed, p, s2) 00481 MAPSET(&installedmap, p); 00482 r = solvable_trivial_installable_map(s, &installedmap, 0); 00483 map_free(&installedmap); 00484 return r; 00485 } 00486 00487 00488 /*****************************************************************************/ 00489 00490 /* 00491 * Create maps containing the state of each solvable. Input is a "installed" queue, 00492 * it contains all solvable ids that are considered to be installed. 00493 * 00494 * The created maps can be used for solvable_trivial_installable_map(), 00495 * pool_calc_duchanges(), pool_calc_installsizechange(). 00496 * 00497 */ 00498 void 00499 pool_create_state_maps(Pool *pool, Queue *installed, Map *installedmap, Map *conflictsmap) 00500 { 00501 int i; 00502 Solvable *s; 00503 Id p, *dp; 00504 Id *conp, con; 00505 00506 map_init(installedmap, pool->nsolvables); 00507 if (conflictsmap) 00508 map_init(conflictsmap, pool->nsolvables); 00509 for (i = 0; i < installed->count; i++) 00510 { 00511 p = installed->elements[i]; 00512 if (p <= 0) /* makes it work with decisionq */ 00513 continue; 00514 MAPSET(installedmap, p); 00515 if (!conflictsmap) 00516 continue; 00517 s = pool->solvables + p; 00518 if (!s->conflicts) 00519 continue; 00520 conp = s->repo->idarraydata + s->conflicts; 00521 while ((con = *conp++) != 0) 00522 { 00523 dp = pool_whatprovides_ptr(pool, con); 00524 for (; *dp; dp++) 00525 MAPSET(conflictsmap, *dp); 00526 } 00527 } 00528 } 00529 00530 /* Tests if two solvables have identical content. Currently 00531 * both solvables need to come from the same pool */ 00532 00533 int 00534 solvable_identical(Solvable *s1, Solvable *s2) 00535 { 00536 unsigned int bt1, bt2; 00537 Id rq1, rq2; 00538 Id *reqp; 00539 00540 if (s1->name != s2->name) 00541 return 0; 00542 if (s1->arch != s2->arch) 00543 return 0; 00544 if (s1->evr != s2->evr) 00545 return 0; 00546 /* map missing vendor to empty string */ 00547 if ((s1->vendor ? s1->vendor : 1) != (s2->vendor ? s2->vendor : 1)) 00548 return 0; 00549 00550 /* looking good, try some fancier stuff */ 00551 /* might also look up the package checksum here */ 00552 bt1 = solvable_lookup_num(s1, SOLVABLE_BUILDTIME, 0); 00553 bt2 = solvable_lookup_num(s2, SOLVABLE_BUILDTIME, 0); 00554 if (bt1 && bt2) 00555 { 00556 if (bt1 != bt2) 00557 return 0; 00558 } 00559 else 00560 { 00561 /* look at requires in a last attempt to find recompiled packages */ 00562 rq1 = rq2 = 0; 00563 if (s1->requires) 00564 for (reqp = s1->repo->idarraydata + s1->requires; *reqp; reqp++) 00565 rq1 ^= *reqp; 00566 if (s2->requires) 00567 for (reqp = s2->repo->idarraydata + s2->requires; *reqp; reqp++) 00568 rq2 ^= *reqp; 00569 if (rq1 != rq2) 00570 return 0; 00571 } 00572 return 1; 00573 } 00574 00575 /* return the self provide dependency of a solvable */ 00576 Id 00577 solvable_selfprovidedep(Solvable *s) 00578 { 00579 Pool *pool; 00580 Reldep *rd; 00581 Id prov, *provp; 00582 00583 if (!s->repo) 00584 return s->name; 00585 pool = s->repo->pool; 00586 if (s->provides) 00587 { 00588 provp = s->repo->idarraydata + s->provides; 00589 while ((prov = *provp++) != 0) 00590 { 00591 if (!ISRELDEP(prov)) 00592 continue; 00593 rd = GETRELDEP(pool, prov); 00594 if (rd->name == s->name && rd->evr == s->evr && rd->flags == REL_EQ) 00595 return prov; 00596 } 00597 } 00598 return rel2id(pool, s->name, s->evr, REL_EQ, 1); 00599 }