satsolver 0.16.3
|
00001 /* 00002 * Copyright (c) 2007-2009, Novell Inc. 00003 * 00004 * This program is licensed under the BSD license, read LICENSE.BSD 00005 * for further information 00006 */ 00007 00008 /* 00009 * pool.c 00010 * 00011 * The pool contains information about solvables 00012 * stored optimized for memory consumption and fast retrieval. 00013 */ 00014 00015 #include <stdio.h> 00016 #include <stdlib.h> 00017 #include <stdarg.h> 00018 #include <unistd.h> 00019 #include <string.h> 00020 00021 #include "pool.h" 00022 #include "repo.h" 00023 #include "poolid.h" 00024 #include "poolid_private.h" 00025 #include "poolarch.h" 00026 #include "util.h" 00027 #include "bitmap.h" 00028 #include "evr.h" 00029 00030 #define SOLVABLE_BLOCK 255 00031 00032 #define KNOWNID_INITIALIZE 00033 #include "knownid.h" 00034 #undef KNOWNID_INITIALIZE 00035 00036 /* create pool */ 00037 Pool * 00038 pool_create(void) 00039 { 00040 Pool *pool; 00041 Solvable *s; 00042 00043 pool = (Pool *)sat_calloc(1, sizeof(*pool)); 00044 00045 stringpool_init (&pool->ss, initpool_data); 00046 00047 /* alloc space for RelDep 0 */ 00048 pool->rels = sat_extend_resize(0, 1, sizeof(Reldep), REL_BLOCK); 00049 pool->nrels = 1; 00050 memset(pool->rels, 0, sizeof(Reldep)); 00051 00052 /* alloc space for Solvable 0 and system solvable */ 00053 pool->solvables = sat_extend_resize(0, 2, sizeof(Solvable), SOLVABLE_BLOCK); 00054 pool->nsolvables = 2; 00055 memset(pool->solvables, 0, 2 * sizeof(Solvable)); 00056 s = pool->solvables + SYSTEMSOLVABLE; 00057 s->name = SYSTEM_SYSTEM; 00058 s->arch = ARCH_NOARCH; 00059 s->evr = ID_EMPTY; 00060 00061 queue_init(&pool->vendormap); 00062 00063 pool->debugmask = SAT_DEBUG_RESULT; /* FIXME */ 00064 #ifdef FEDORA 00065 pool->obsoleteusescolors = 1; 00066 #endif 00067 #ifdef DEBIAN 00068 pool->allowselfconflicts = 1; 00069 # ifdef MULTI_SEMANTICS 00070 pool->disttype = DISTTYPE_DEB; 00071 # endif 00072 #endif 00073 return pool; 00074 } 00075 00076 00077 /* free all the resources of our pool */ 00078 void 00079 pool_free(Pool *pool) 00080 { 00081 int i; 00082 00083 pool_freewhatprovides(pool); 00084 pool_freeidhashes(pool); 00085 repo_freeallrepos(pool, 1); 00086 sat_free(pool->id2arch); 00087 sat_free(pool->solvables); 00088 stringpool_free(&pool->ss); 00089 sat_free(pool->rels); 00090 queue_free(&pool->vendormap); 00091 for (i = 0; i < POOL_TMPSPACEBUF; i++) 00092 sat_free(pool->tmpspacebuf[i]); 00093 for (i = 0; i < pool->nlanguages; i++) 00094 free((char *)pool->languages[i]); 00095 sat_free(pool->languages); 00096 sat_free(pool->languagecache); 00097 sat_free(pool); 00098 } 00099 00100 #ifdef MULTI_SEMANTICS 00101 void 00102 pool_setdisttype(Pool *pool, int disttype) 00103 { 00104 pool->disttype = disttype; 00105 } 00106 #endif 00107 00108 Id 00109 pool_add_solvable(Pool *pool) 00110 { 00111 pool->solvables = sat_extend(pool->solvables, pool->nsolvables, 1, sizeof(Solvable), SOLVABLE_BLOCK); 00112 memset(pool->solvables + pool->nsolvables, 0, sizeof(Solvable)); 00113 return pool->nsolvables++; 00114 } 00115 00116 Id 00117 pool_add_solvable_block(Pool *pool, int count) 00118 { 00119 Id nsolvables = pool->nsolvables; 00120 if (!count) 00121 return nsolvables; 00122 pool->solvables = sat_extend(pool->solvables, pool->nsolvables, count, sizeof(Solvable), SOLVABLE_BLOCK); 00123 memset(pool->solvables + nsolvables, 0, sizeof(Solvable) * count); 00124 pool->nsolvables += count; 00125 return nsolvables; 00126 } 00127 00128 void 00129 pool_free_solvable_block(Pool *pool, Id start, int count, int reuseids) 00130 { 00131 if (!count) 00132 return; 00133 if (reuseids && start + count == pool->nsolvables) 00134 { 00135 /* might want to shrink solvable array */ 00136 pool->nsolvables = start; 00137 return; 00138 } 00139 memset(pool->solvables + start, 0, sizeof(Solvable) * count); 00140 } 00141 00142 00143 void 00144 pool_set_installed(Pool *pool, Repo *installed) 00145 { 00146 if (pool->installed == installed) 00147 return; 00148 pool->installed = installed; 00149 pool_freewhatprovides(pool); 00150 } 00151 00152 static int 00153 pool_shrink_whatprovides_sortcmp(const void *ap, const void *bp, void *dp) 00154 { 00155 int r; 00156 Pool *pool = dp; 00157 Id oa, ob, *da, *db; 00158 oa = pool->whatprovides[*(Id *)ap]; 00159 ob = pool->whatprovides[*(Id *)bp]; 00160 if (oa == ob) 00161 return *(Id *)ap - *(Id *)bp; 00162 if (!oa) 00163 return -1; 00164 if (!ob) 00165 return 1; 00166 da = pool->whatprovidesdata + oa; 00167 db = pool->whatprovidesdata + ob; 00168 while (*db) 00169 if ((r = (*da++ - *db++)) != 0) 00170 return r; 00171 if (*da) 00172 return *da; 00173 return *(Id *)ap - *(Id *)bp; 00174 } 00175 00176 /* 00177 * pool_shrink_whatprovides - unify whatprovides data 00178 * 00179 * whatprovides_rel must be empty for this to work! 00180 * 00181 */ 00182 static void 00183 pool_shrink_whatprovides(Pool *pool) 00184 { 00185 Id i, id; 00186 Id *sorted; 00187 Id lastid, *last, *dp, *lp; 00188 Offset o; 00189 int r; 00190 00191 if (pool->ss.nstrings < 3) 00192 return; 00193 sorted = sat_malloc2(pool->ss.nstrings, sizeof(Id)); 00194 for (id = 0; id < pool->ss.nstrings; id++) 00195 sorted[id] = id; 00196 sat_sort(sorted + 1, pool->ss.nstrings - 1, sizeof(Id), pool_shrink_whatprovides_sortcmp, pool); 00197 last = 0; 00198 lastid = 0; 00199 for (i = 1; i < pool->ss.nstrings; i++) 00200 { 00201 id = sorted[i]; 00202 o = pool->whatprovides[id]; 00203 if (o == 0 || o == 1) 00204 continue; 00205 dp = pool->whatprovidesdata + o; 00206 if (last) 00207 { 00208 lp = last; 00209 while (*dp) 00210 if (*dp++ != *lp++) 00211 { 00212 last = 0; 00213 break; 00214 } 00215 if (last && *lp) 00216 last = 0; 00217 if (last) 00218 { 00219 pool->whatprovides[id] = -lastid; 00220 continue; 00221 } 00222 } 00223 last = pool->whatprovidesdata + o; 00224 lastid = id; 00225 } 00226 sat_free(sorted); 00227 dp = pool->whatprovidesdata + 2; 00228 for (id = 1; id < pool->ss.nstrings; id++) 00229 { 00230 o = pool->whatprovides[id]; 00231 if (o == 0 || o == 1) 00232 continue; 00233 if ((Id)o < 0) 00234 { 00235 i = -(Id)o; 00236 if (i >= id) 00237 abort(); 00238 pool->whatprovides[id] = pool->whatprovides[i]; 00239 continue; 00240 } 00241 lp = pool->whatprovidesdata + o; 00242 if (lp < dp) 00243 abort(); 00244 pool->whatprovides[id] = dp - pool->whatprovidesdata; 00245 while ((*dp++ = *lp++) != 0) 00246 ; 00247 } 00248 o = dp - pool->whatprovidesdata; 00249 POOL_DEBUG(SAT_DEBUG_STATS, "shrunk whatprovidesdata from %d to %d\n", pool->whatprovidesdataoff, o); 00250 if (pool->whatprovidesdataoff == o) 00251 return; 00252 r = pool->whatprovidesdataoff - o; 00253 pool->whatprovidesdataoff = o; 00254 pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (o + pool->whatprovidesdataleft) * sizeof(Id)); 00255 if (r > pool->whatprovidesdataleft) 00256 r = pool->whatprovidesdataleft; 00257 memset(pool->whatprovidesdata + o, 0, r * sizeof(Id)); 00258 } 00259 00260 00261 /* 00262 * pool_createwhatprovides() 00263 * 00264 * create hashes over pool of solvables to ease provide lookups 00265 * 00266 */ 00267 void 00268 pool_createwhatprovides(Pool *pool) 00269 { 00270 int i, num, np, extra; 00271 Offset off; 00272 Solvable *s; 00273 Id id; 00274 Offset *idp, n; 00275 Offset *whatprovides; 00276 Id *whatprovidesdata, *d; 00277 Repo *installed = pool->installed; 00278 unsigned int now; 00279 00280 now = sat_timems(0); 00281 POOL_DEBUG(SAT_DEBUG_STATS, "number of solvables: %d\n", pool->nsolvables); 00282 POOL_DEBUG(SAT_DEBUG_STATS, "number of ids: %d + %d\n", pool->ss.nstrings, pool->nrels); 00283 00284 pool_freeidhashes(pool); /* XXX: should not be here! */ 00285 pool_freewhatprovides(pool); 00286 num = pool->ss.nstrings; 00287 pool->whatprovides = whatprovides = sat_calloc_block(num, sizeof(Offset), WHATPROVIDES_BLOCK); 00288 pool->whatprovides_rel = sat_calloc_block(pool->nrels, sizeof(Offset), WHATPROVIDES_BLOCK); 00289 00290 /* count providers for each name */ 00291 for (i = pool->nsolvables - 1; i > 0; i--) 00292 { 00293 Id *pp; 00294 s = pool->solvables + i; 00295 if (!s->provides || !s->repo || s->repo->disabled) 00296 continue; 00297 /* we always need the installed solvable in the whatprovides data, 00298 otherwise obsoletes/conflicts on them won't work */ 00299 if (s->repo != installed && !pool_installable(pool, s)) 00300 continue; 00301 pp = s->repo->idarraydata + s->provides; 00302 while ((id = *pp++) != 0) 00303 { 00304 while (ISRELDEP(id)) 00305 { 00306 Reldep *rd = GETRELDEP(pool, id); 00307 id = rd->name; 00308 } 00309 whatprovides[id]++; /* inc count of providers */ 00310 } 00311 } 00312 00313 off = 2; /* first entry is undef, second is empty list */ 00314 np = 0; /* number of names provided */ 00315 for (i = 0, idp = whatprovides; i < num; i++, idp++) 00316 { 00317 n = *idp; 00318 if (!n) /* no providers */ 00319 continue; 00320 off += n; /* make space for all providers */ 00321 *idp = off++; /* now idp points to terminating zero */ 00322 np++; /* inc # of provider 'slots' for stats */ 00323 } 00324 00325 POOL_DEBUG(SAT_DEBUG_STATS, "provide ids: %d\n", np); 00326 00327 /* reserve some space for relation data */ 00328 extra = 2 * pool->nrels; 00329 if (extra < 256) 00330 extra = 256; 00331 00332 POOL_DEBUG(SAT_DEBUG_STATS, "provide space needed: %d + %d\n", off, extra); 00333 00334 /* alloc space for all providers + extra */ 00335 whatprovidesdata = sat_calloc(off + extra, sizeof(Id)); 00336 00337 /* now fill data for all provides */ 00338 for (i = pool->nsolvables - 1; i > 0; i--) 00339 { 00340 Id *pp; 00341 s = pool->solvables + i; 00342 if (!s->provides || !s->repo || s->repo->disabled) 00343 continue; 00344 if (s->repo != installed && !pool_installable(pool, s)) 00345 continue; 00346 00347 /* for all provides of this solvable */ 00348 pp = s->repo->idarraydata + s->provides; 00349 while ((id = *pp++) != 0) 00350 { 00351 while (ISRELDEP(id)) 00352 { 00353 Reldep *rd = GETRELDEP(pool, id); 00354 id = rd->name; 00355 } 00356 d = whatprovidesdata + whatprovides[id]; /* offset into whatprovidesdata */ 00357 if (*d != i) /* don't add same solvable twice */ 00358 { 00359 d[-1] = i; 00360 whatprovides[id]--; 00361 } 00362 } 00363 } 00364 pool->whatprovidesdata = whatprovidesdata; 00365 pool->whatprovidesdataoff = off; 00366 pool->whatprovidesdataleft = extra; 00367 pool_shrink_whatprovides(pool); 00368 POOL_DEBUG(SAT_DEBUG_STATS, "whatprovides memory used: %d K id array, %d K data\n", (pool->ss.nstrings + pool->nrels + WHATPROVIDES_BLOCK) / (int)(1024/sizeof(Id)), (pool->whatprovidesdataoff + pool->whatprovidesdataleft) / (int)(1024/sizeof(Id))); 00369 POOL_DEBUG(SAT_DEBUG_STATS, "createwhatprovides took %d ms\n", sat_timems(now)); 00370 } 00371 00372 /* 00373 * free all of our whatprovides data 00374 * be careful, everything internalized with pool_queuetowhatprovides is 00375 * gone, too 00376 */ 00377 void 00378 pool_freewhatprovides(Pool *pool) 00379 { 00380 pool->whatprovides = sat_free(pool->whatprovides); 00381 pool->whatprovides_rel = sat_free(pool->whatprovides_rel); 00382 pool->whatprovidesdata = sat_free(pool->whatprovidesdata); 00383 pool->whatprovidesdataoff = 0; 00384 pool->whatprovidesdataleft = 0; 00385 } 00386 00387 00388 /******************************************************************************/ 00389 00390 /* 00391 * pool_queuetowhatprovides - add queue contents to whatprovidesdata 00392 * 00393 * on-demand filling of provider information 00394 * move queue data into whatprovidesdata 00395 * q: queue of Ids 00396 * returns: Offset into whatprovides 00397 * 00398 */ 00399 Id 00400 pool_queuetowhatprovides(Pool *pool, Queue *q) 00401 { 00402 Offset off; 00403 int count = q->count; 00404 00405 if (count == 0) /* queue empty -> 1 */ 00406 return 1; 00407 00408 /* extend whatprovidesdata if needed, +1 for ID_NULL-termination */ 00409 if (pool->whatprovidesdataleft < count + 1) 00410 { 00411 POOL_DEBUG(SAT_DEBUG_STATS, "growing provides hash data...\n"); 00412 pool->whatprovidesdata = sat_realloc(pool->whatprovidesdata, (pool->whatprovidesdataoff + count + 4096) * sizeof(Id)); 00413 pool->whatprovidesdataleft = count + 4096; 00414 } 00415 00416 /* copy queue to next free slot */ 00417 off = pool->whatprovidesdataoff; 00418 memcpy(pool->whatprovidesdata + pool->whatprovidesdataoff, q->elements, count * sizeof(Id)); 00419 00420 /* adapt count and ID_NULL-terminate */ 00421 pool->whatprovidesdataoff += count; 00422 pool->whatprovidesdata[pool->whatprovidesdataoff++] = ID_NULL; 00423 pool->whatprovidesdataleft -= count + 1; 00424 00425 return (Id)off; 00426 } 00427 00428 00429 /*************************************************************************/ 00430 00431 #if defined(MULTI_SEMANTICS) 00432 # define EVRCMP_DEPCMP (pool->disttype == DISTTYPE_DEB ? EVRCMP_COMPARE : EVRCMP_MATCH_RELEASE) 00433 #elif defined(DEBIAN_SEMANTICS) 00434 # define EVRCMP_DEPCMP EVRCMP_COMPARE 00435 #else 00436 # define EVRCMP_DEPCMP EVRCMP_MATCH_RELEASE 00437 #endif 00438 00439 /* check if a package's nevr matches a dependency */ 00440 00441 int 00442 pool_match_nevr_rel(Pool *pool, Solvable *s, Id d) 00443 { 00444 Reldep *rd = GETRELDEP(pool, d); 00445 Id name = rd->name; 00446 Id evr = rd->evr; 00447 int flags = rd->flags; 00448 00449 if (flags > 7) 00450 { 00451 switch (flags) 00452 { 00453 case REL_ARCH: 00454 if (s->arch != evr) 00455 return 0; 00456 return pool_match_nevr(pool, s, name); 00457 case REL_OR: 00458 if (pool_match_nevr(pool, s, name)) 00459 return 1; 00460 return pool_match_nevr(pool, s, evr); 00461 case REL_AND: 00462 case REL_WITH: 00463 if (!pool_match_nevr(pool, s, name)) 00464 return 0; 00465 return pool_match_nevr(pool, s, evr); 00466 default: 00467 return 0; 00468 } 00469 } 00470 if (!pool_match_nevr(pool, s, name)) 00471 return 0; 00472 if (evr == s->evr) 00473 return flags & 2 ? 1 : 0; 00474 if (!flags) 00475 return 0; 00476 if (flags == 7) 00477 return 1; 00478 if (flags != 2 && flags != 5) 00479 flags ^= 5; 00480 if ((flags & (1 << (1 + evrcmp(pool, s->evr, evr, EVRCMP_DEPCMP)))) != 0) 00481 return 1; 00482 return 0; 00483 } 00484 00485 /* match (flags, evr) against provider (pflags, pevr) */ 00486 static inline int 00487 pool_match_flags_evr(Pool *pool, int pflags, Id pevr, int flags, int evr) 00488 { 00489 if (!pflags || !flags || pflags >= 8 || flags >= 8) 00490 return 0; 00491 if (flags == 7 || pflags == 7) 00492 return 1; /* rel provides every version */ 00493 if ((pflags & flags & 5) != 0) 00494 return 1; /* both rels show in the same direction */ 00495 if (pevr == evr) 00496 { 00497 if ((pflags & flags & 2) != 0) 00498 return 1; /* both have '=', match */ 00499 } 00500 else 00501 { 00502 int f = flags == 5 ? 5 : flags == 2 ? pflags : (flags ^ 5) & (pflags | 5); 00503 if ((f & (1 << (1 + evrcmp(pool, pevr, evr, EVRCMP_DEPCMP)))) != 0) 00504 return 1; 00505 } 00506 return 0; 00507 } 00508 00509 /* match two dependencies (d1 = provider) */ 00510 00511 int 00512 pool_match_dep(Pool *pool, Id d1, Id d2) 00513 { 00514 Reldep *rd1, *rd2; 00515 00516 if (d1 == d2) 00517 return 1; 00518 if (!ISRELDEP(d1)) 00519 { 00520 if (!ISRELDEP(d2)) 00521 return 0; 00522 rd2 = GETRELDEP(pool, d2); 00523 return pool_match_dep(pool, d1, rd2->name); 00524 } 00525 rd1 = GETRELDEP(pool, d1); 00526 if (!ISRELDEP(d2)) 00527 { 00528 return pool_match_dep(pool, rd1->name, d2); 00529 } 00530 rd2 = GETRELDEP(pool, d2); 00531 /* first match name */ 00532 if (!pool_match_dep(pool, rd1->name, rd2->name)) 00533 return 0; 00534 /* name matches, check flags and evr */ 00535 return pool_match_flags_evr(pool, rd1->flags, rd1->evr, rd2->flags, rd2->evr); 00536 } 00537 00538 /* 00539 * addrelproviders 00540 * 00541 * add packages fulfilling the relation to whatprovides array 00542 * no exact providers, do range match 00543 * 00544 */ 00545 00546 Id 00547 pool_addrelproviders(Pool *pool, Id d) 00548 { 00549 Reldep *rd = GETRELDEP(pool, d); 00550 Reldep *prd; 00551 Queue plist; 00552 Id buf[16]; 00553 Id name = rd->name; 00554 Id evr = rd->evr; 00555 int flags = rd->flags; 00556 Id pid, *pidp; 00557 Id p, *pp; 00558 00559 d = GETRELID(d); 00560 queue_init_buffer(&plist, buf, sizeof(buf)/sizeof(*buf)); 00561 00562 if (flags >= 8) 00563 { 00564 /* special relation */ 00565 Id wp = 0; 00566 Id *pp2, *pp3; 00567 00568 switch (flags) 00569 { 00570 case REL_AND: 00571 case REL_WITH: 00572 wp = pool_whatprovides(pool, name); 00573 pp2 = pool_whatprovides_ptr(pool, evr); 00574 pp = pool->whatprovidesdata + wp; 00575 while ((p = *pp++) != 0) 00576 { 00577 for (pp3 = pp2; *pp3; pp3++) 00578 if (*pp3 == p) 00579 break; 00580 if (*pp3) 00581 queue_push(&plist, p); /* found it */ 00582 else 00583 wp = 0; 00584 } 00585 break; 00586 case REL_OR: 00587 wp = pool_whatprovides(pool, name); 00588 pp = pool->whatprovidesdata + wp; 00589 if (!*pp) 00590 wp = pool_whatprovides(pool, evr); 00591 else 00592 { 00593 int cnt; 00594 while ((p = *pp++) != 0) 00595 queue_push(&plist, p); 00596 cnt = plist.count; 00597 pp = pool_whatprovides_ptr(pool, evr); 00598 while ((p = *pp++) != 0) 00599 queue_pushunique(&plist, p); 00600 if (plist.count != cnt) 00601 wp = 0; 00602 } 00603 break; 00604 case REL_NAMESPACE: 00605 if (name == NAMESPACE_OTHERPROVIDERS) 00606 { 00607 wp = pool_whatprovides(pool, evr); 00608 break; 00609 } 00610 if (pool->nscallback) 00611 { 00612 /* ask callback which packages provide the dependency 00613 * 0: none 00614 * 1: the system (aka SYSTEMSOLVABLE) 00615 * >1: set of packages, stored as offset on whatprovidesdata 00616 */ 00617 p = pool->nscallback(pool, pool->nscallbackdata, name, evr); 00618 if (p > 1) 00619 wp = p; 00620 if (p == 1) 00621 queue_push(&plist, SYSTEMSOLVABLE); 00622 } 00623 break; 00624 case REL_ARCH: 00625 /* small hack: make it possible to match <pkg>.src 00626 * we have to iterate over the solvables as src packages do not 00627 * provide anything, thus they are not indexed in our 00628 * whatprovides hash */ 00629 if (evr == ARCH_SRC) 00630 { 00631 Solvable *s; 00632 for (p = 1, s = pool->solvables + p; p < pool->nsolvables; p++, s++) 00633 { 00634 if (s->arch != ARCH_SRC && s->arch != ARCH_NOSRC) 00635 continue; 00636 if (pool_match_nevr(pool, s, name)) 00637 queue_push(&plist, p); 00638 } 00639 break; 00640 } 00641 wp = pool_whatprovides(pool, name); 00642 pp = pool->whatprovidesdata + wp; 00643 while ((p = *pp++) != 0) 00644 { 00645 Solvable *s = pool->solvables + p; 00646 if (s->arch == evr) 00647 queue_push(&plist, p); 00648 else 00649 wp = 0; 00650 } 00651 break; 00652 case REL_FILECONFLICT: 00653 pp = pool_whatprovides_ptr(pool, name); 00654 while ((p = *pp++) != 0) 00655 { 00656 Id origd = MAKERELDEP(d); 00657 Solvable *s = pool->solvables + p; 00658 if (!s->provides) 00659 continue; 00660 pidp = s->repo->idarraydata + s->provides; 00661 while ((pid = *pidp++) != 0) 00662 if (pid == origd) 00663 break; 00664 if (pid) 00665 queue_push(&plist, p); 00666 } 00667 break; 00668 default: 00669 break; 00670 } 00671 if (wp) 00672 { 00673 /* we can reuse an existing entry */ 00674 queue_free(&plist); 00675 pool->whatprovides_rel[d] = wp; 00676 return wp; 00677 } 00678 } 00679 else if (flags) 00680 { 00681 /* simple version comparison relation */ 00682 #if 0 00683 POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: what provides %s?\n", dep2str(pool, name)); 00684 #endif 00685 pp = pool_whatprovides_ptr(pool, name); 00686 while (ISRELDEP(name)) 00687 { 00688 rd = GETRELDEP(pool, name); 00689 name = rd->name; 00690 } 00691 while ((p = *pp++) != 0) 00692 { 00693 Solvable *s = pool->solvables + p; 00694 if (!s->provides) 00695 { 00696 /* no provides - check nevr */ 00697 if (pool_match_nevr_rel(pool, s, MAKERELDEP(d))) 00698 queue_push(&plist, p); 00699 continue; 00700 } 00701 /* solvable p provides name in some rels */ 00702 pidp = s->repo->idarraydata + s->provides; 00703 while ((pid = *pidp++) != 0) 00704 { 00705 if (pid == name) 00706 { 00707 #if defined(MULTI_SEMANTICS) 00708 if (pool->disttype == DISTTYPE_DEB) 00709 continue; 00710 else 00711 break; 00712 #elif defined(DEBIAN_SEMANTICS) 00713 continue; /* unversioned provides can 00714 * never match versioned deps */ 00715 #else 00716 break; /* yes, provides all versions */ 00717 #endif 00718 } 00719 if (!ISRELDEP(pid)) 00720 continue; /* wrong provides name */ 00721 prd = GETRELDEP(pool, pid); 00722 if (prd->name != name) 00723 continue; /* wrong provides name */ 00724 /* right package, both deps are rels. check flags/evr */ 00725 if (pool_match_flags_evr(pool, prd->flags, prd->evr, flags, evr)) 00726 break; /* matches */ 00727 } 00728 if (!pid) 00729 continue; /* none of the providers matched */ 00730 queue_push(&plist, p); 00731 } 00732 /* make our system solvable provide all unknown rpmlib() stuff */ 00733 if (plist.count == 0 && !strncmp(id2str(pool, name), "rpmlib(", 7)) 00734 queue_push(&plist, SYSTEMSOLVABLE); 00735 } 00736 /* add providers to whatprovides */ 00737 #if 0 00738 POOL_DEBUG(SAT_DEBUG_STATS, "addrelproviders: adding %d packages to %d\n", plist.count, d); 00739 #endif 00740 pool->whatprovides_rel[d] = pool_queuetowhatprovides(pool, &plist); 00741 queue_free(&plist); 00742 00743 return pool->whatprovides_rel[d]; 00744 } 00745 00746 /*************************************************************************/ 00747 00748 void 00749 pool_debug(Pool *pool, int type, const char *format, ...) 00750 { 00751 va_list args; 00752 char buf[1024]; 00753 00754 if ((type & (SAT_FATAL|SAT_ERROR)) == 0) 00755 { 00756 if ((pool->debugmask & type) == 0) 00757 return; 00758 } 00759 va_start(args, format); 00760 if (!pool->debugcallback) 00761 { 00762 if ((type & (SAT_FATAL|SAT_ERROR)) == 0 && !(pool->debugmask & SAT_DEBUG_TO_STDERR)) 00763 vprintf(format, args); 00764 else 00765 vfprintf(stderr, format, args); 00766 return; 00767 } 00768 vsnprintf(buf, sizeof(buf), format, args); 00769 pool->debugcallback(pool, pool->debugcallbackdata, type, buf); 00770 } 00771 00772 void 00773 pool_setdebuglevel(Pool *pool, int level) 00774 { 00775 int mask = SAT_DEBUG_RESULT; 00776 if (level > 0) 00777 mask |= SAT_DEBUG_STATS|SAT_DEBUG_ANALYZE|SAT_DEBUG_UNSOLVABLE|SAT_DEBUG_SOLVER|SAT_DEBUG_TRANSACTION; 00778 if (level > 1) 00779 mask |= SAT_DEBUG_JOB|SAT_DEBUG_SOLUTIONS|SAT_DEBUG_POLICY; 00780 if (level > 2) 00781 mask |= SAT_DEBUG_PROPAGATE; 00782 if (level > 3) 00783 mask |= SAT_DEBUG_RULE_CREATION; 00784 if (level > 4) 00785 mask |= SAT_DEBUG_SCHUBI; 00786 mask |= pool->debugmask & SAT_DEBUG_TO_STDERR; /* keep bit */ 00787 pool->debugmask = mask; 00788 } 00789 00790 /*************************************************************************/ 00791 00792 struct searchfiles { 00793 Id *ids; 00794 char **dirs; 00795 char **names; 00796 int nfiles; 00797 Map seen; 00798 }; 00799 00800 #define SEARCHFILES_BLOCK 127 00801 00802 static void 00803 pool_addfileprovides_dep(Pool *pool, Id *ida, struct searchfiles *sf, struct searchfiles *isf) 00804 { 00805 Id dep, sid; 00806 const char *s, *sr; 00807 struct searchfiles *csf; 00808 00809 while ((dep = *ida++) != 0) 00810 { 00811 csf = sf; 00812 while (ISRELDEP(dep)) 00813 { 00814 Reldep *rd; 00815 sid = pool->ss.nstrings + GETRELID(dep); 00816 if (MAPTST(&csf->seen, sid)) 00817 { 00818 dep = 0; 00819 break; 00820 } 00821 MAPSET(&csf->seen, sid); 00822 rd = GETRELDEP(pool, dep); 00823 if (rd->flags < 8) 00824 dep = rd->name; 00825 else if (rd->flags == REL_NAMESPACE) 00826 { 00827 if (rd->name == NAMESPACE_INSTALLED || rd->name == NAMESPACE_SPLITPROVIDES) 00828 { 00829 csf = isf; 00830 if (!csf || MAPTST(&csf->seen, sid)) 00831 { 00832 dep = 0; 00833 break; 00834 } 00835 MAPSET(&csf->seen, sid); 00836 } 00837 dep = rd->evr; 00838 } 00839 else if (rd->flags == REL_FILECONFLICT) 00840 { 00841 dep = 0; 00842 break; 00843 } 00844 else 00845 { 00846 Id ids[2]; 00847 ids[0] = rd->name; 00848 ids[1] = 0; 00849 pool_addfileprovides_dep(pool, ids, csf, isf); 00850 dep = rd->evr; 00851 } 00852 } 00853 if (!dep) 00854 continue; 00855 if (MAPTST(&csf->seen, dep)) 00856 continue; 00857 MAPSET(&csf->seen, dep); 00858 s = id2str(pool, dep); 00859 if (*s != '/') 00860 continue; 00861 csf->ids = sat_extend(csf->ids, csf->nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); 00862 csf->dirs = sat_extend(csf->dirs, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); 00863 csf->names = sat_extend(csf->names, csf->nfiles, 1, sizeof(const char *), SEARCHFILES_BLOCK); 00864 csf->ids[csf->nfiles] = dep; 00865 sr = strrchr(s, '/'); 00866 csf->names[csf->nfiles] = strdup(sr + 1); 00867 csf->dirs[csf->nfiles] = sat_malloc(sr - s + 1); 00868 if (sr != s) 00869 strncpy(csf->dirs[csf->nfiles], s, sr - s); 00870 csf->dirs[csf->nfiles][sr - s] = 0; 00871 csf->nfiles++; 00872 } 00873 } 00874 00875 struct addfileprovides_cbdata { 00876 int nfiles; 00877 Id *ids; 00878 char **dirs; 00879 char **names; 00880 00881 Id *dids; 00882 00883 Map providedids; 00884 00885 Map useddirs; 00886 }; 00887 00888 static int 00889 addfileprovides_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) 00890 { 00891 struct addfileprovides_cbdata *cbd = cbdata; 00892 int i; 00893 00894 if (!cbd->useddirs.size) 00895 { 00896 map_init(&cbd->useddirs, data->dirpool.ndirs + 1); 00897 for (i = 0; i < cbd->nfiles; i++) 00898 { 00899 Id did; 00900 if (MAPTST(&cbd->providedids, cbd->ids[i])) 00901 { 00902 cbd->dids[i] = 0; 00903 continue; 00904 } 00905 did = repodata_str2dir(data, cbd->dirs[i], 0); 00906 cbd->dids[i] = did; 00907 if (did) 00908 MAPSET(&cbd->useddirs, did); 00909 } 00910 } 00911 if (value->id >= data->dirpool.ndirs || !MAPTST(&cbd->useddirs, value->id)) 00912 return 0; 00913 for (i = 0; i < cbd->nfiles; i++) 00914 { 00915 if (cbd->dids[i] != value->id) 00916 continue; 00917 if (!strcmp(cbd->names[i], value->str)) 00918 break; 00919 } 00920 if (i == cbd->nfiles) 00921 return 0; 00922 s->provides = repo_addid_dep(s->repo, s->provides, cbd->ids[i], SOLVABLE_FILEMARKER); 00923 return 0; 00924 } 00925 00926 static void 00927 pool_addfileprovides_search(Pool *pool, struct addfileprovides_cbdata *cbd, struct searchfiles *sf, Repo *repoonly) 00928 { 00929 Id p; 00930 Repodata *data; 00931 Repo *repo; 00932 Queue fileprovidesq; 00933 int i, j, repoid, repodataid; 00934 int provstart, provend; 00935 Map donemap; 00936 int ndone, incomplete; 00937 00938 if (!pool->nrepos) 00939 return; 00940 00941 cbd->nfiles = sf->nfiles; 00942 cbd->ids = sf->ids; 00943 cbd->dirs = sf->dirs; 00944 cbd->names = sf->names; 00945 cbd->dids = sat_realloc2(cbd->dids, sf->nfiles, sizeof(Id)); 00946 map_init(&cbd->providedids, pool->ss.nstrings); 00947 00948 repoid = 0; 00949 repo = repoonly ? repoonly : pool->repos[0]; 00950 map_init(&donemap, pool->nsolvables); 00951 queue_init(&fileprovidesq); 00952 provstart = provend = 0; 00953 for (;;) 00954 { 00955 if (repo->disabled) 00956 { 00957 if (repoonly || ++repoid == pool->nrepos) 00958 break; 00959 repo = pool->repos[repoid]; 00960 continue; 00961 } 00962 ndone = 0; 00963 for (data = repo->repodata, repodataid = 0; repodataid < repo->nrepodata; repodataid++, data++) 00964 { 00965 if (ndone >= repo->nsolvables) 00966 break; 00967 00968 if (repodata_lookup_idarray(data, SOLVID_META, REPOSITORY_ADDEDFILEPROVIDES, &fileprovidesq)) 00969 { 00970 map_empty(&cbd->providedids); 00971 for (i = 0; i < fileprovidesq.count; i++) 00972 MAPSET(&cbd->providedids, fileprovidesq.elements[i]); 00973 provstart = data->start; 00974 provend = data->end; 00975 for (i = 0; i < cbd->nfiles; i++) 00976 if (!MAPTST(&cbd->providedids, cbd->ids[i])) 00977 break; 00978 if (i == cbd->nfiles) 00979 { 00980 /* great! no need to search files */ 00981 for (p = data->start; p < data->end; p++) 00982 if (pool->solvables[p].repo == repo) 00983 { 00984 if (MAPTST(&donemap, p)) 00985 continue; 00986 MAPSET(&donemap, p); 00987 ndone++; 00988 } 00989 continue; 00990 } 00991 } 00992 00993 if (!repodata_has_keyname(data, SOLVABLE_FILELIST)) 00994 continue; 00995 00996 if (data->start < provstart || data->end > provend) 00997 { 00998 map_empty(&cbd->providedids); 00999 provstart = provend = 0; 01000 } 01001 01002 /* check if the data is incomplete */ 01003 incomplete = 0; 01004 if (data->state == REPODATA_AVAILABLE) 01005 { 01006 for (j = 1; j < data->nkeys; j++) 01007 if (data->keys[j].name != REPOSITORY_SOLVABLES && data->keys[j].name != SOLVABLE_FILELIST) 01008 break; 01009 if (j < data->nkeys) 01010 { 01011 #if 0 01012 for (i = 0; i < cbd->nfiles; i++) 01013 if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i]))) 01014 printf("need complete filelist because of %s\n", id2str(pool, cbd->ids[i])); 01015 #endif 01016 for (i = 0; i < cbd->nfiles; i++) 01017 if (!MAPTST(&cbd->providedids, cbd->ids[i]) && !repodata_filelistfilter_matches(data, id2str(pool, cbd->ids[i]))) 01018 break; 01019 if (i < cbd->nfiles) 01020 incomplete = 1; 01021 } 01022 } 01023 01024 /* do the search */ 01025 map_init(&cbd->useddirs, 0); 01026 for (p = data->start; p < data->end; p++) 01027 if (pool->solvables[p].repo == repo) 01028 { 01029 if (MAPTST(&donemap, p)) 01030 continue; 01031 repodata_search(data, p, SOLVABLE_FILELIST, 0, addfileprovides_cb, cbd); 01032 if (!incomplete) 01033 { 01034 MAPSET(&donemap, p); 01035 ndone++; 01036 } 01037 } 01038 map_free(&cbd->useddirs); 01039 } 01040 01041 if (repoonly || ++repoid == pool->nrepos) 01042 break; 01043 repo = pool->repos[repoid]; 01044 } 01045 map_free(&donemap); 01046 queue_free(&fileprovidesq); 01047 map_free(&cbd->providedids); 01048 } 01049 01050 void 01051 pool_addfileprovides_ids(Pool *pool, Repo *installed, Id **idp) 01052 { 01053 Solvable *s; 01054 Repo *repo; 01055 struct searchfiles sf, isf, *isfp; 01056 struct addfileprovides_cbdata cbd; 01057 int i; 01058 unsigned int now; 01059 01060 now = sat_timems(0); 01061 memset(&sf, 0, sizeof(sf)); 01062 map_init(&sf.seen, pool->ss.nstrings + pool->nrels); 01063 memset(&isf, 0, sizeof(isf)); 01064 map_init(&isf.seen, pool->ss.nstrings + pool->nrels); 01065 01066 isfp = installed ? &isf : 0; 01067 for (i = 1, s = pool->solvables + i; i < pool->nsolvables; i++, s++) 01068 { 01069 repo = s->repo; 01070 if (!repo) 01071 continue; 01072 if (s->obsoletes) 01073 pool_addfileprovides_dep(pool, repo->idarraydata + s->obsoletes, &sf, isfp); 01074 if (s->conflicts) 01075 pool_addfileprovides_dep(pool, repo->idarraydata + s->conflicts, &sf, isfp); 01076 if (s->requires) 01077 pool_addfileprovides_dep(pool, repo->idarraydata + s->requires, &sf, isfp); 01078 if (s->recommends) 01079 pool_addfileprovides_dep(pool, repo->idarraydata + s->recommends, &sf, isfp); 01080 if (s->suggests) 01081 pool_addfileprovides_dep(pool, repo->idarraydata + s->suggests, &sf, isfp); 01082 if (s->supplements) 01083 pool_addfileprovides_dep(pool, repo->idarraydata + s->supplements, &sf, isfp); 01084 if (s->enhances) 01085 pool_addfileprovides_dep(pool, repo->idarraydata + s->enhances, &sf, isfp); 01086 } 01087 map_free(&sf.seen); 01088 map_free(&isf.seen); 01089 POOL_DEBUG(SAT_DEBUG_STATS, "found %d file dependencies, %d installed file dependencies\n", sf.nfiles, isf.nfiles); 01090 cbd.dids = 0; 01091 if (idp) 01092 *idp = 0; 01093 if (sf.nfiles) 01094 { 01095 #if 0 01096 for (i = 0; i < sf.nfiles; i++) 01097 POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in filelist\n", id2str(pool, sf.ids[i])); 01098 #endif 01099 pool_addfileprovides_search(pool, &cbd, &sf, 0); 01100 if (idp) 01101 { 01102 sf.ids = sat_extend(sf.ids, sf.nfiles, 1, sizeof(Id), SEARCHFILES_BLOCK); 01103 sf.ids[sf.nfiles] = 0; 01104 *idp = sf.ids; 01105 sf.ids = 0; 01106 } 01107 sat_free(sf.ids); 01108 for (i = 0; i < sf.nfiles; i++) 01109 { 01110 sat_free(sf.dirs[i]); 01111 sat_free(sf.names[i]); 01112 } 01113 sat_free(sf.dirs); 01114 sat_free(sf.names); 01115 } 01116 if (isf.nfiles) 01117 { 01118 #if 0 01119 for (i = 0; i < isf.nfiles; i++) 01120 POOL_DEBUG(SAT_DEBUG_STATS, "looking up %s in installed filelist\n", id2str(pool, isf.ids[i])); 01121 #endif 01122 if (installed) 01123 pool_addfileprovides_search(pool, &cbd, &isf, installed); 01124 sat_free(isf.ids); 01125 for (i = 0; i < isf.nfiles; i++) 01126 { 01127 sat_free(isf.dirs[i]); 01128 sat_free(isf.names[i]); 01129 } 01130 sat_free(isf.dirs); 01131 sat_free(isf.names); 01132 } 01133 sat_free(cbd.dids); 01134 pool_freewhatprovides(pool); /* as we have added provides */ 01135 POOL_DEBUG(SAT_DEBUG_STATS, "addfileprovides took %d ms\n", sat_timems(now)); 01136 } 01137 01138 void 01139 pool_addfileprovides(Pool *pool) 01140 { 01141 pool_addfileprovides_ids(pool, pool->installed, 0); 01142 } 01143 01144 void 01145 pool_search(Pool *pool, Id p, Id key, const char *match, int flags, int (*callback)(void *cbdata, Solvable *s, struct _Repodata *data, struct _Repokey *key, struct _KeyValue *kv), void *cbdata) 01146 { 01147 if (p) 01148 { 01149 if (pool->solvables[p].repo) 01150 repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata); 01151 return; 01152 } 01153 /* FIXME: obey callback return value! */ 01154 for (p = 1; p < pool->nsolvables; p++) 01155 if (pool->solvables[p].repo) 01156 repo_search(pool->solvables[p].repo, p, key, match, flags, callback, cbdata); 01157 } 01158 01159 void 01160 pool_clear_pos(Pool *pool) 01161 { 01162 memset(&pool->pos, 0, sizeof(pool->pos)); 01163 } 01164 01165 01166 void 01167 pool_set_languages(Pool *pool, const char **languages, int nlanguages) 01168 { 01169 int i; 01170 01171 pool->languagecache = sat_free(pool->languagecache); 01172 pool->languagecacheother = 0; 01173 if (pool->nlanguages) 01174 { 01175 for (i = 0; i < pool->nlanguages; i++) 01176 free((char *)pool->languages[i]); 01177 free(pool->languages); 01178 } 01179 pool->nlanguages = nlanguages; 01180 if (!nlanguages) 01181 return; 01182 pool->languages = sat_calloc(nlanguages, sizeof(const char **)); 01183 for (i = 0; i < pool->nlanguages; i++) 01184 pool->languages[i] = strdup(languages[i]); 01185 } 01186 01187 Id 01188 pool_id2langid(Pool *pool, Id id, const char *lang, int create) 01189 { 01190 const char *n; 01191 char buf[256], *p; 01192 int l; 01193 01194 if (!lang) 01195 return id; 01196 n = id2str(pool, id); 01197 l = strlen(n) + strlen(lang) + 2; 01198 if (l > sizeof(buf)) 01199 p = sat_malloc(strlen(n) + strlen(lang) + 2); 01200 else 01201 p = buf; 01202 sprintf(p, "%s:%s", n, lang); 01203 id = str2id(pool, p, create); 01204 if (p != buf) 01205 free(p); 01206 return id; 01207 } 01208 01209 char * 01210 pool_alloctmpspace(Pool *pool, int len) 01211 { 01212 int n = pool->tmpspacen; 01213 if (!len) 01214 return 0; 01215 if (len > pool->tmpspacelen[n]) 01216 { 01217 pool->tmpspacebuf[n] = sat_realloc(pool->tmpspacebuf[n], len + 32); 01218 pool->tmpspacelen[n] = len + 32; 01219 } 01220 pool->tmpspacen = (n + 1) % POOL_TMPSPACEBUF; 01221 return pool->tmpspacebuf[n]; 01222 } 01223 01224 char * 01225 pool_tmpjoin(Pool *pool, const char *str1, const char *str2, const char *str3) 01226 { 01227 int l1, l2, l3; 01228 char *s, *str; 01229 l1 = str1 ? strlen(str1) : 0; 01230 l2 = str2 ? strlen(str2) : 0; 01231 l3 = str3 ? strlen(str3) : 0; 01232 s = str = pool_alloctmpspace(pool, l1 + l2 + l3 + 1); 01233 if (l1) 01234 { 01235 strcpy(s, str1); 01236 s += l1; 01237 } 01238 if (l2) 01239 { 01240 strcpy(s, str2); 01241 s += l2; 01242 } 01243 if (l3) 01244 { 01245 strcpy(s, str3); 01246 s += l3; 01247 } 01248 *s = 0; 01249 return str; 01250 } 01251 01252 01253 /*******************************************************************/ 01254 01255 struct mptree { 01256 Id sibling; 01257 Id child; 01258 const char *comp; 01259 int compl; 01260 Id mountpoint; 01261 }; 01262 01263 struct ducbdata { 01264 DUChanges *mps; 01265 struct mptree *mptree; 01266 int addsub; 01267 int hasdu; 01268 01269 Id *dirmap; 01270 int nmap; 01271 Repodata *olddata; 01272 }; 01273 01274 01275 static int 01276 solver_fill_DU_cb(void *cbdata, Solvable *s, Repodata *data, Repokey *key, KeyValue *value) 01277 { 01278 struct ducbdata *cbd = cbdata; 01279 Id mp; 01280 01281 if (data != cbd->olddata) 01282 { 01283 Id dn, mp, comp, *dirmap, *dirs; 01284 int i, compl; 01285 const char *compstr; 01286 struct mptree *mptree; 01287 01288 /* create map from dir to mptree */ 01289 cbd->dirmap = sat_free(cbd->dirmap); 01290 cbd->nmap = 0; 01291 dirmap = sat_calloc(data->dirpool.ndirs, sizeof(Id)); 01292 mptree = cbd->mptree; 01293 mp = 0; 01294 for (dn = 2, dirs = data->dirpool.dirs + dn; dn < data->dirpool.ndirs; dn++) 01295 { 01296 comp = *dirs++; 01297 if (comp <= 0) 01298 { 01299 mp = dirmap[-comp]; 01300 continue; 01301 } 01302 if (mp < 0) 01303 { 01304 /* unconnected */ 01305 dirmap[dn] = mp; 01306 continue; 01307 } 01308 if (!mptree[mp].child) 01309 { 01310 dirmap[dn] = -mp; 01311 continue; 01312 } 01313 if (data->localpool) 01314 compstr = stringpool_id2str(&data->spool, comp); 01315 else 01316 compstr = id2str(data->repo->pool, comp); 01317 compl = strlen(compstr); 01318 for (i = mptree[mp].child; i; i = mptree[i].sibling) 01319 if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) 01320 break; 01321 dirmap[dn] = i ? i : -mp; 01322 } 01323 /* change dirmap to point to mountpoint instead of mptree */ 01324 for (dn = 0; dn < data->dirpool.ndirs; dn++) 01325 { 01326 mp = dirmap[dn]; 01327 dirmap[dn] = mptree[mp > 0 ? mp : -mp].mountpoint; 01328 } 01329 cbd->dirmap = dirmap; 01330 cbd->nmap = data->dirpool.ndirs; 01331 cbd->olddata = data; 01332 } 01333 cbd->hasdu = 1; 01334 if (value->id < 0 || value->id >= cbd->nmap) 01335 return 0; 01336 mp = cbd->dirmap[value->id]; 01337 if (mp < 0) 01338 return 0; 01339 if (cbd->addsub > 0) 01340 { 01341 cbd->mps[mp].kbytes += value->num; 01342 cbd->mps[mp].files += value->num2; 01343 } 01344 else 01345 { 01346 cbd->mps[mp].kbytes -= value->num; 01347 cbd->mps[mp].files -= value->num2; 01348 } 01349 return 0; 01350 } 01351 01352 static void 01353 propagate_mountpoints(struct mptree *mptree, int pos, Id mountpoint) 01354 { 01355 int i; 01356 if (mptree[pos].mountpoint == -1) 01357 mptree[pos].mountpoint = mountpoint; 01358 else 01359 mountpoint = mptree[pos].mountpoint; 01360 for (i = mptree[pos].child; i; i = mptree[i].sibling) 01361 propagate_mountpoints(mptree, i, mountpoint); 01362 } 01363 01364 #define MPTREE_BLOCK 15 01365 01366 void 01367 pool_calc_duchanges(Pool *pool, Map *installedmap, DUChanges *mps, int nmps) 01368 { 01369 char *p; 01370 const char *path, *compstr; 01371 struct mptree *mptree; 01372 int i, nmptree; 01373 int pos, compl; 01374 int mp; 01375 struct ducbdata cbd; 01376 Solvable *s; 01377 Id sp; 01378 Map ignoredu; 01379 Repo *oldinstalled = pool->installed; 01380 01381 memset(&ignoredu, 0, sizeof(ignoredu)); 01382 cbd.mps = mps; 01383 cbd.addsub = 0; 01384 cbd.dirmap = 0; 01385 cbd.nmap = 0; 01386 cbd.olddata = 0; 01387 01388 mptree = sat_extend_resize(0, 1, sizeof(struct mptree), MPTREE_BLOCK); 01389 01390 /* our root node */ 01391 mptree[0].sibling = 0; 01392 mptree[0].child = 0; 01393 mptree[0].comp = 0; 01394 mptree[0].compl = 0; 01395 mptree[0].mountpoint = -1; 01396 nmptree = 1; 01397 01398 /* create component tree */ 01399 for (mp = 0; mp < nmps; mp++) 01400 { 01401 mps[mp].kbytes = 0; 01402 mps[mp].files = 0; 01403 pos = 0; 01404 path = mps[mp].path; 01405 while(*path == '/') 01406 path++; 01407 while (*path) 01408 { 01409 if ((p = strchr(path, '/')) == 0) 01410 { 01411 compstr = path; 01412 compl = strlen(compstr); 01413 path += compl; 01414 } 01415 else 01416 { 01417 compstr = path; 01418 compl = p - path; 01419 path = p + 1; 01420 while(*path == '/') 01421 path++; 01422 } 01423 for (i = mptree[pos].child; i; i = mptree[i].sibling) 01424 if (mptree[i].compl == compl && !strncmp(mptree[i].comp, compstr, compl)) 01425 break; 01426 if (!i) 01427 { 01428 /* create new node */ 01429 mptree = sat_extend(mptree, nmptree, 1, sizeof(struct mptree), MPTREE_BLOCK); 01430 i = nmptree++; 01431 mptree[i].sibling = mptree[pos].child; 01432 mptree[i].child = 0; 01433 mptree[i].comp = compstr; 01434 mptree[i].compl = compl; 01435 mptree[i].mountpoint = -1; 01436 mptree[pos].child = i; 01437 } 01438 pos = i; 01439 } 01440 mptree[pos].mountpoint = mp; 01441 } 01442 01443 propagate_mountpoints(mptree, 0, mptree[0].mountpoint); 01444 01445 #if 0 01446 for (i = 0; i < nmptree; i++) 01447 { 01448 printf("#%d sibling: %d\n", i, mptree[i].sibling); 01449 printf("#%d child: %d\n", i, mptree[i].child); 01450 printf("#%d comp: %s\n", i, mptree[i].comp); 01451 printf("#%d compl: %d\n", i, mptree[i].compl); 01452 printf("#%d mountpont: %d\n", i, mptree[i].mountpoint); 01453 } 01454 #endif 01455 01456 cbd.mptree = mptree; 01457 cbd.addsub = 1; 01458 for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) 01459 { 01460 if (!s->repo || (oldinstalled && s->repo == oldinstalled)) 01461 continue; 01462 if (!MAPTST(installedmap, sp)) 01463 continue; 01464 cbd.hasdu = 0; 01465 repo_search(s->repo, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); 01466 if (!cbd.hasdu && oldinstalled) 01467 { 01468 Id op, opp; 01469 /* no du data available, ignore data of all installed solvables we obsolete */ 01470 if (!ignoredu.map) 01471 map_init(&ignoredu, oldinstalled->end - oldinstalled->start); 01472 if (s->obsoletes) 01473 { 01474 Id obs, *obsp = s->repo->idarraydata + s->obsoletes; 01475 while ((obs = *obsp++) != 0) 01476 FOR_PROVIDES(op, opp, obs) 01477 if (op >= oldinstalled->start && op < oldinstalled->end) 01478 MAPSET(&ignoredu, op - oldinstalled->start); 01479 } 01480 FOR_PROVIDES(op, opp, s->name) 01481 if (pool->solvables[op].name == s->name) 01482 if (op >= oldinstalled->start && op < oldinstalled->end) 01483 MAPSET(&ignoredu, op - oldinstalled->start); 01484 } 01485 } 01486 cbd.addsub = -1; 01487 if (oldinstalled) 01488 { 01489 /* assumes we allways have du data for installed solvables */ 01490 FOR_REPO_SOLVABLES(oldinstalled, sp, s) 01491 { 01492 if (MAPTST(installedmap, sp)) 01493 continue; 01494 if (ignoredu.map && MAPTST(&ignoredu, sp - oldinstalled->start)) 01495 continue; 01496 repo_search(oldinstalled, sp, SOLVABLE_DISKUSAGE, 0, 0, solver_fill_DU_cb, &cbd); 01497 } 01498 } 01499 if (ignoredu.map) 01500 map_free(&ignoredu); 01501 sat_free(cbd.dirmap); 01502 sat_free(mptree); 01503 } 01504 01505 int 01506 pool_calc_installsizechange(Pool *pool, Map *installedmap) 01507 { 01508 Id sp; 01509 Solvable *s; 01510 int change = 0; 01511 Repo *oldinstalled = pool->installed; 01512 01513 for (sp = 1, s = pool->solvables + sp; sp < pool->nsolvables; sp++, s++) 01514 { 01515 if (!s->repo || (oldinstalled && s->repo == oldinstalled)) 01516 continue; 01517 if (!MAPTST(installedmap, sp)) 01518 continue; 01519 change += solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0); 01520 } 01521 if (oldinstalled) 01522 { 01523 FOR_REPO_SOLVABLES(oldinstalled, sp, s) 01524 { 01525 if (MAPTST(installedmap, sp)) 01526 continue; 01527 change -= solvable_lookup_num(s, SOLVABLE_INSTALLSIZE, 0); 01528 } 01529 } 01530 return change; 01531 } 01532 01533 /* map: 01534 * 1: installed 01535 * 2: conflicts with installed 01536 * 8: interesting (only true if installed) 01537 * 16: undecided 01538 */ 01539 01540 static inline Id dep2name(Pool *pool, Id dep) 01541 { 01542 while (ISRELDEP(dep)) 01543 { 01544 Reldep *rd = rd = GETRELDEP(pool, dep); 01545 dep = rd->name; 01546 } 01547 return dep; 01548 } 01549 01550 static int providedbyinstalled_multiversion(Pool *pool, unsigned char *map, Id n, Id con) 01551 { 01552 Id p, pp; 01553 Solvable *sn = pool->solvables + n; 01554 01555 FOR_PROVIDES(p, pp, sn->name) 01556 { 01557 Solvable *s = pool->solvables + p; 01558 if (s->name != sn->name || s->arch != sn->arch) 01559 continue; 01560 if ((map[p] & 9) != 9) 01561 continue; 01562 if (pool_match_nevr(pool, pool->solvables + p, con)) 01563 continue; 01564 return 1; /* found installed package that doesn't conflict */ 01565 } 01566 return 0; 01567 } 01568 01569 static inline int providedbyinstalled(Pool *pool, unsigned char *map, Id dep, int ispatch, Map *noobsoletesmap) 01570 { 01571 Id p, pp; 01572 int r = 0; 01573 FOR_PROVIDES(p, pp, dep) 01574 { 01575 if (p == SYSTEMSOLVABLE) 01576 return 1; /* always boring, as never constraining */ 01577 if (ispatch && !pool_match_nevr(pool, pool->solvables + p, dep)) 01578 continue; 01579 if (ispatch && noobsoletesmap && noobsoletesmap->size && MAPTST(noobsoletesmap, p) && ISRELDEP(dep)) 01580 if (providedbyinstalled_multiversion(pool, map, p, dep)) 01581 continue; 01582 if ((map[p] & 9) == 9) 01583 return 9; 01584 r |= map[p] & 17; 01585 } 01586 return r; 01587 } 01588 01589 /* 01590 * pool_trivial_installable - calculate if a set of solvables is 01591 * trivial installable without any other installs/deinstalls of 01592 * packages not belonging to the set. 01593 * 01594 * the state is returned in the result queue: 01595 * 1: solvable is installable without any other package changes 01596 * 0: solvable is not installable 01597 * -1: solvable is installable, but doesn't constrain any installed packages 01598 */ 01599 01600 void 01601 pool_trivial_installable_noobsoletesmap(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res, Map *noobsoletesmap) 01602 { 01603 int i, r, m, did; 01604 Id p, *dp, con, *conp, req, *reqp; 01605 unsigned char *map; 01606 Solvable *s; 01607 01608 map = sat_calloc(pool->nsolvables, 1); 01609 for (p = 1; p < pool->nsolvables; p++) 01610 { 01611 if (!MAPTST(installedmap, p)) 01612 continue; 01613 map[p] |= 9; 01614 s = pool->solvables + p; 01615 if (!s->conflicts) 01616 continue; 01617 conp = s->repo->idarraydata + s->conflicts; 01618 while ((con = *conp++) != 0) 01619 { 01620 dp = pool_whatprovides_ptr(pool, con); 01621 for (; *dp; dp++) 01622 map[p] |= 2; /* XXX: self conflict ? */ 01623 } 01624 } 01625 for (i = 0; i < pkgs->count; i++) 01626 map[pkgs->elements[i]] = 16; 01627 01628 for (i = 0, did = 0; did < pkgs->count; i++, did++) 01629 { 01630 if (i == pkgs->count) 01631 i = 0; 01632 p = pkgs->elements[i]; 01633 if ((map[p] & 16) == 0) 01634 continue; 01635 if ((map[p] & 2) != 0) 01636 { 01637 map[p] = 2; 01638 continue; 01639 } 01640 s = pool->solvables + p; 01641 m = 1; 01642 if (s->requires) 01643 { 01644 reqp = s->repo->idarraydata + s->requires; 01645 while ((req = *reqp++) != 0) 01646 { 01647 if (req == SOLVABLE_PREREQMARKER) 01648 continue; 01649 r = providedbyinstalled(pool, map, req, 0, 0); 01650 if (!r) 01651 { 01652 /* decided and miss */ 01653 map[p] = 2; 01654 break; 01655 } 01656 m |= r; /* 1 | 9 | 16 | 17 */ 01657 } 01658 if (req) 01659 continue; 01660 if ((m & 9) == 9) 01661 m = 9; 01662 } 01663 if (s->conflicts) 01664 { 01665 int ispatch = 0; /* see solver.c patch handling */ 01666 01667 if (!strncmp("patch:", id2str(pool, s->name), 6)) 01668 ispatch = 1; 01669 conp = s->repo->idarraydata + s->conflicts; 01670 while ((con = *conp++) != 0) 01671 { 01672 if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0) 01673 { 01674 map[p] = 2; 01675 break; 01676 } 01677 if ((m == 1 || m == 17) && ISRELDEP(con)) 01678 { 01679 con = dep2name(pool, con); 01680 if ((providedbyinstalled(pool, map, con, ispatch, noobsoletesmap) & 1) != 0) 01681 m = 9; 01682 } 01683 } 01684 if (con) 01685 continue; /* found a conflict */ 01686 } 01687 #if 0 01688 if (s->repo && s->repo != oldinstalled) 01689 { 01690 Id p2, obs, *obsp, *pp; 01691 Solvable *s2; 01692 if (s->obsoletes) 01693 { 01694 obsp = s->repo->idarraydata + s->obsoletes; 01695 while ((obs = *obsp++) != 0) 01696 { 01697 if ((providedbyinstalled(pool, map, obs, 0, 0) & 1) != 0) 01698 { 01699 map[p] = 2; 01700 break; 01701 } 01702 } 01703 if (obs) 01704 continue; 01705 } 01706 FOR_PROVIDES(p2, pp, s->name) 01707 { 01708 s2 = pool->solvables + p2; 01709 if (s2->name == s->name && (map[p2] & 1) != 0) 01710 { 01711 map[p] = 2; 01712 break; 01713 } 01714 } 01715 if (p2) 01716 continue; 01717 } 01718 #endif 01719 if (m != map[p]) 01720 { 01721 map[p] = m; 01722 did = 0; 01723 } 01724 } 01725 queue_free(res); 01726 queue_init_clone(res, pkgs); 01727 for (i = 0; i < pkgs->count; i++) 01728 { 01729 m = map[pkgs->elements[i]]; 01730 if ((m & 9) == 9) 01731 r = 1; 01732 else if (m & 1) 01733 r = -1; 01734 else 01735 r = 0; 01736 res->elements[i] = r; 01737 } 01738 free(map); 01739 } 01740 01741 void 01742 pool_trivial_installable(Pool *pool, Map *installedmap, Queue *pkgs, Queue *res) 01743 { 01744 pool_trivial_installable_noobsoletesmap(pool, installedmap, pkgs, res, 0); 01745 } 01746 01747 const char * 01748 pool_lookup_str(Pool *pool, Id entry, Id keyname) 01749 { 01750 if (entry == SOLVID_POS && pool->pos.repo) 01751 return repodata_lookup_str(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname); 01752 if (entry <= 0) 01753 return 0; 01754 return solvable_lookup_str(pool->solvables + entry, keyname); 01755 } 01756 01757 Id 01758 pool_lookup_id(Pool *pool, Id entry, Id keyname) 01759 { 01760 if (entry == SOLVID_POS && pool->pos.repo) 01761 { 01762 Repodata *data = pool->pos.repo->repodata + pool->pos.repodataid; 01763 Id id = repodata_lookup_id(data, SOLVID_POS, keyname); 01764 return data->localpool ? repodata_globalize_id(data, id, 1) : id; 01765 } 01766 if (entry <= 0) 01767 return 0; 01768 return solvable_lookup_id(pool->solvables + entry, keyname); 01769 } 01770 01771 unsigned int 01772 pool_lookup_num(Pool *pool, Id entry, Id keyname, unsigned int notfound) 01773 { 01774 if (entry == SOLVID_POS && pool->pos.repo) 01775 { 01776 unsigned int value; 01777 if (repodata_lookup_num(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, &value)) 01778 return value; 01779 return notfound; 01780 } 01781 if (entry <= 0) 01782 return notfound; 01783 return solvable_lookup_num(pool->solvables + entry, keyname, notfound); 01784 } 01785 01786 int 01787 pool_lookup_void(Pool *pool, Id entry, Id keyname) 01788 { 01789 if (entry == SOLVID_POS && pool->pos.repo) 01790 return repodata_lookup_void(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname); 01791 if (entry <= 0) 01792 return 0; 01793 return solvable_lookup_void(pool->solvables + entry, keyname); 01794 } 01795 01796 const unsigned char * 01797 pool_lookup_bin_checksum(Pool *pool, Id entry, Id keyname, Id *typep) 01798 { 01799 if (entry == SOLVID_POS && pool->pos.repo) 01800 return repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep); 01801 if (entry <= 0) 01802 return 0; 01803 return solvable_lookup_bin_checksum(pool->solvables + entry, keyname, typep); 01804 } 01805 01806 const char * 01807 pool_lookup_checksum(Pool *pool, Id entry, Id keyname, Id *typep) 01808 { 01809 if (entry == SOLVID_POS && pool->pos.repo) 01810 { 01811 const unsigned char *chk = repodata_lookup_bin_checksum(pool->pos.repo->repodata + pool->pos.repodataid, SOLVID_POS, keyname, typep); 01812 return chk ? repodata_chk2str(pool->pos.repo->repodata + pool->pos.repodataid, *typep, chk) : 0; 01813 } 01814 if (entry <= 0) 01815 return 0; 01816 return solvable_lookup_checksum(pool->solvables + entry, keyname, typep); 01817 } 01818 01819 void 01820 pool_add_fileconflicts_deps(Pool *pool, Queue *conflicts) 01821 { 01822 int hadhashes = pool->relhashtbl ? 1 : 0; 01823 Solvable *s; 01824 Id fn, p, q, md5; 01825 Id id; 01826 int i; 01827 01828 if (!conflicts->count) 01829 return; 01830 pool_freewhatprovides(pool); 01831 for (i = 0; i < conflicts->count; i += 5) 01832 { 01833 fn = conflicts->elements[i]; 01834 p = conflicts->elements[i + 1]; 01835 md5 = conflicts->elements[i + 2]; 01836 q = conflicts->elements[i + 3]; 01837 id = rel2id(pool, fn, md5, REL_FILECONFLICT, 1); 01838 s = pool->solvables + p; 01839 if (!s->repo) 01840 continue; 01841 s->provides = repo_addid_dep(s->repo, s->provides, id, SOLVABLE_FILEMARKER); 01842 s = pool->solvables + q; 01843 if (!s->repo) 01844 continue; 01845 s->conflicts = repo_addid_dep(s->repo, s->conflicts, id, 0); 01846 } 01847 if (!hadhashes) 01848 pool_freeidhashes(pool); 01849 } 01850 01851 /* EOF */