rpm
5.2.1
|
00001 00005 #include "system.h" 00006 00007 #include <rpmio.h> 00008 #include <rpmiotypes.h> /* XXX fnpyKey */ 00009 #include <rpmcb.h> 00010 #include <rpmmacro.h> /* XXX rpmExpand("%{_dependency_whiteout}" */ 00011 #include <envvar.h> 00012 #include <ugid.h> /* XXX user()/group() probes */ 00013 00014 #include <rpmtag.h> 00015 #define _RPMDB_INTERNAL /* XXX response cache needs dbiOpen et al. */ 00016 #include <rpmdb.h> 00017 00018 #define _RPMTE_INTERNAL 00019 #include <rpmte.h> 00020 #define _RPMTS_INTERNAL 00021 #include <rpmcli.h> /* XXX rpmcliPackagesTotal */ 00022 00023 #define _RPMEVR_INTERNAL 00024 #include <rpmds.h> 00025 #include <rpmfi.h> 00026 00027 #include "debug.h" 00028 00029 /*@access tsortInfo @*/ 00030 /*@access rpmte @*/ /* XXX for install <-> erase associate. */ 00031 /*@access rpmts @*/ 00032 /*@access rpmDiskSpaceInfo @*/ 00033 00034 /*@access alKey @*/ /* XXX for reordering and RPMAL_NOMATCH assign */ 00035 00038 typedef /*@abstract@*/ struct orderListIndex_s * orderListIndex; 00039 /*@access orderListIndex@*/ 00040 00043 struct orderListIndex_s { 00044 /*@dependent@*/ 00045 alKey pkgKey; 00046 int orIndex; 00047 }; 00048 00049 #if defined(CACHE_DEPENDENCY_RESULT) 00050 /*@unchecked@*/ 00051 int _cacheDependsRC = CACHE_DEPENDENCY_RESULT; 00052 #endif 00053 00054 /*@observer@*/ /*@unchecked@*/ 00055 const char *rpmNAME = PACKAGE; 00056 00057 /*@observer@*/ /*@unchecked@*/ 00058 const char *rpmEVR = VERSION; 00059 00060 /*@unchecked@*/ 00061 int rpmFLAGS = RPMSENSE_EQUAL; 00062 00069 static int intcmp(const void * a, const void * b) 00070 /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/ 00071 { 00072 const int * aptr = a; 00073 const int * bptr = b; 00074 int rc = (*aptr - *bptr); 00075 return rc; 00076 } 00077 00087 static int removePackage(rpmts ts, Header h, int dboffset, 00088 /*@null@*/ int * indexp, 00089 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends) 00090 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00091 /*@modifies ts, h, *indexp, rpmGlobalMacroContext, fileSystem, internalState @*/ 00092 { 00093 rpmte p; 00094 00095 /* Filter out duplicate erasures. */ 00096 if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) { 00097 int * needle = NULL; 00098 needle = bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages, 00099 sizeof(*ts->removedPackages), intcmp); 00100 if (needle != NULL) { 00101 /* XXX lastx should be per-call, not per-ts. */ 00102 if (indexp != NULL) 00103 *indexp = needle - ts->removedPackages; 00104 return 0; 00105 } 00106 } 00107 00108 if (ts->numRemovedPackages == ts->allocedRemovedPackages) { 00109 ts->allocedRemovedPackages += ts->delta; 00110 ts->removedPackages = xrealloc(ts->removedPackages, 00111 sizeof(ts->removedPackages) * ts->allocedRemovedPackages); 00112 } 00113 00114 if (ts->removedPackages != NULL) { /* XXX can't happen. */ 00115 ts->removedPackages[ts->numRemovedPackages] = dboffset; 00116 ts->numRemovedPackages++; 00117 if (ts->numRemovedPackages > 1) 00118 qsort(ts->removedPackages, ts->numRemovedPackages, 00119 sizeof(*ts->removedPackages), intcmp); 00120 } 00121 00122 if (ts->orderCount >= ts->orderAlloced) { 00123 ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta; 00124 /*@-type +voidabstract @*/ 00125 ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced); 00126 /*@=type =voidabstract @*/ 00127 } 00128 00129 p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends); 00130 ts->order[ts->orderCount] = p; 00131 if (indexp != NULL) 00132 *indexp = ts->orderCount; 00133 ts->orderCount++; 00134 00135 /*@-nullstate@*/ /* XXX FIX: ts->order[] can be NULL. */ 00136 return 0; 00137 /*@=nullstate@*/ 00138 } 00139 00146 static int rpmHeadersIdentical(Header first, Header second) 00147 /*@globals internalState @*/ 00148 /*@modifies internalState @*/ 00149 { 00150 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00151 const char * one, * two; 00152 int rc = 0; 00153 int xx; 00154 00155 he->tag = RPMTAG_HDRID; 00156 xx = headerGet(first, he, 0); 00157 one = he->p.str; 00158 he->tag = RPMTAG_HDRID; 00159 xx = headerGet(second, he, 0); 00160 two = he->p.str; 00161 00162 if (one && two) 00163 rc = ((strcmp(one, two) == 0) ? 1 : 0); 00164 else if (one && !two) 00165 rc = 0; 00166 else if (!one && two) 00167 rc = 0; 00168 else { 00169 /* XXX Headers w/o digests case devolves to NEVR comparison. */ 00170 rpmds A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL); 00171 rpmds B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL); 00172 rc = rpmdsCompare(A, B); 00173 (void)rpmdsFree(A); 00174 A = NULL; 00175 (void)rpmdsFree(B); 00176 B = NULL; 00177 } 00178 one = _free(one); 00179 two = _free(two); 00180 return rc; 00181 } 00182 00183 /*@unchecked@*/ 00184 static rpmTag _upgrade_tag; 00185 /*@unchecked@*/ 00186 static rpmTag _debuginfo_tag; 00187 /*@unchecked@*/ 00188 static rpmTag _obsolete_tag; 00189 00198 static int rpmtsAddUpgrades(rpmts ts, rpmte p, rpmuint32_t hcolor, Header h) 00199 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00200 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/ 00201 { 00202 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00203 rpmuint32_t tscolor = rpmtsColor(ts); 00204 alKey pkgKey = rpmteAddedKey(p); 00205 rpmuint32_t ohcolor; 00206 rpmmi mi; 00207 Header oh; 00208 int xx; 00209 00210 if (_upgrade_tag == 0) { 00211 const char * t = rpmExpand("%{?_upgrade_tag}", NULL); 00212 /*@-mods@*/ 00213 _upgrade_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME); 00214 /*@=mods@*/ 00215 t = _free(t); 00216 } 00217 00218 mi = rpmtsInitIterator(ts, _upgrade_tag, rpmteN(p), 0); 00219 while((oh = rpmmiNext(mi)) != NULL) { 00220 int lastx; 00221 rpmte q; 00222 00223 /* Ignore colored packages not in our rainbow. */ 00224 ohcolor = hGetColor(oh); 00225 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor)) 00226 continue; 00227 00228 /* Snarf the original install tid & time from older package(s). */ 00229 he->tag = RPMTAG_ORIGINTID; 00230 xx = headerGet(oh, he, 0); 00231 if (xx && he->p.ui32p != NULL) { 00232 if (p->originTid[0] == 0 || p->originTid[0] > he->p.ui32p[0] 00233 || (he->c > 1 && p->originTid[0] == he->p.ui32p[0] && p->originTid[1] > he->p.ui32p[1])) 00234 { 00235 p->originTid[0] = he->p.ui32p[0]; 00236 p->originTid[1] = (he->c > 1 ? he->p.ui32p[1] : 0); 00237 } 00238 he->p.ptr = _free(he->p.ptr); 00239 } 00240 he->tag = RPMTAG_ORIGINTIME; 00241 xx = headerGet(oh, he, 0); 00242 if (xx && he->p.ui32p != NULL) { 00243 if (p->originTime[0] == 0 || p->originTime[0] > he->p.ui32p[0] 00244 || (he->c > 1 && p->originTime[0] == he->p.ui32p[0] && p->originTime[1] > he->p.ui32p[1])) 00245 { 00246 p->originTime[0] = he->p.ui32p[0]; 00247 p->originTime[1] = (he->c > 1 ? he->p.ui32p[1] : 0); 00248 } 00249 he->p.ptr = _free(he->p.ptr); 00250 } 00251 00252 #if defined(RPM_VENDOR_WINDRIVER) 00253 /* 00254 * If we're capable of installing multiple colors 00255 * but at least one of the packages are white (0), we 00256 * further verify the arch is the same (or compatible) to trigger an upgrade 00257 * we do have a special case to allow upgrades of noarch w/ a arch package 00258 */ 00259 if (tscolor && (!hcolor || !ohcolor)) { 00260 const char * arch; 00261 const char * oharch; 00262 he->tag = RPMTAG_ARCH; 00263 xx = headerGet(h, he, 0); 00264 arch = (xx && he->p.str != NULL ? he->p.str : NULL); 00265 he->tag = RPMTAG_ARCH; 00266 xx = headerGet(oh, he, 0); 00267 oharch = (xx && he->p.str != NULL ? he->p.str : NULL); 00268 if (arch != NULL && oharch != NULL) { 00269 if (strcmp("noarch", arch) || strcmp("noarch", oharch)) { 00270 if (!_isCompatibleArch(arch, oharch)) { 00271 arch = _free(arch); 00272 oharch = _free(oharch); 00273 continue; 00274 } 00275 } 00276 } 00277 arch = _free(arch); 00278 oharch = _free(oharch); 00279 } 00280 #endif 00281 00282 /* Skip identical packages. */ 00283 if (rpmHeadersIdentical(h, oh)) 00284 continue; 00285 00286 /* Create an erasure element. */ 00287 lastx = -1; 00288 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey); 00289 assert(lastx >= 0 && lastx < ts->orderCount); 00290 q = ts->order[lastx]; 00291 00292 /* Chain through upgrade flink. */ 00293 xx = rpmteChain(p, q, oh, "Upgrades"); 00294 00295 /*@-nullptrarith@*/ 00296 rpmlog(RPMLOG_DEBUG, D_(" upgrade erases %s\n"), rpmteNEVRA(q)); 00297 /*@=nullptrarith@*/ 00298 00299 } 00300 mi = rpmmiFree(mi); 00301 00302 return 0; 00303 } 00304 00311 static inline int chkSuffix(const char * fn, const char * suffix) 00312 /*@*/ 00313 { 00314 size_t flen = strlen(fn); 00315 size_t slen = strlen(suffix); 00316 return (flen > slen && !strcmp(fn + flen - slen, suffix)); 00317 } 00318 00327 static int rpmtsEraseDebuginfo(rpmts ts, rpmte p, Header h, 00328 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey pkgKey) 00329 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00330 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/ 00331 { 00332 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00333 const void *keyval = NULL; 00334 size_t keylen = 0; 00335 size_t nrefs = 0; 00336 rpmuint32_t debuginfoInstance = 0; 00337 Header debuginfoHeader = NULL; 00338 rpmmi mi; 00339 Header oh; 00340 int xx; 00341 00342 /* XXX SOURCEPKGID is not populated reliably, do not use (yet). */ 00343 if (_debuginfo_tag == 0) { 00344 const char * t = rpmExpand("%{?_debuginfo_tag}", NULL); 00345 /*@-mods@*/ 00346 _debuginfo_tag = (*t != '\0' && !strcmp(t, "pkgid") 00347 ? RPMTAG_SOURCEPKGID : RPMTAG_SOURCERPM); 00348 /*@=mods@*/ 00349 t = _free(t); 00350 } 00351 00352 /* Grab the retrieval key. */ 00353 switch (_debuginfo_tag) { 00354 default: return 0; /*@notreached@*/ break; 00355 case RPMTAG_SOURCERPM: keyval = rpmteSourcerpm(p); break; 00356 } 00357 00358 /* Count remaining members in build set, excluding -debuginfo (if any). */ 00359 mi = rpmtsInitIterator(ts, _debuginfo_tag, keyval, keylen); 00360 xx = rpmmiPrune(mi, ts->removedPackages, ts->numRemovedPackages, 1); 00361 while((oh = rpmmiNext(mi)) != NULL) { 00362 /* Skip identical packages. */ 00363 if (rpmHeadersIdentical(h, oh)) 00364 continue; 00365 00366 he->tag = RPMTAG_NAME; 00367 xx = headerGet(oh, he, 0); 00368 if (!xx || he->p.str == NULL) 00369 continue; 00370 /* Save the -debuginfo member. */ 00371 if (chkSuffix(he->p.str, "-debuginfo")) { 00372 debuginfoInstance = rpmmiInstance(mi); 00373 debuginfoHeader = headerLink(oh); 00374 } else 00375 nrefs++; 00376 he->p.str = _free(he->p.str); 00377 } 00378 mi = rpmmiFree(mi); 00379 00380 /* Remove -debuginfo package when last build member is erased. */ 00381 if (nrefs == 0 && debuginfoInstance > 0 && debuginfoHeader != NULL) { 00382 int lastx = -1; 00383 rpmte q; 00384 00385 /* Create an erasure element. */ 00386 lastx = -1; 00387 xx = removePackage(ts, debuginfoHeader, debuginfoInstance, 00388 &lastx, pkgKey); 00389 assert(lastx >= 0 && lastx < ts->orderCount); 00390 q = ts->order[lastx]; 00391 00392 /* Chain through upgrade flink. */ 00393 /* XXX avoid assertion failure when erasing. */ 00394 if (pkgKey != RPMAL_NOMATCH) 00395 xx = rpmteChain(p, q, oh, "Upgrades"); 00396 00397 /*@-nullptrarith@*/ 00398 rpmlog(RPMLOG_DEBUG, D_(" lastref erases %s\n"), rpmteNEVRA(q)); 00399 /*@=nullptrarith@*/ 00400 00401 } 00402 (void)headerFree(debuginfoHeader); 00403 debuginfoHeader = NULL; 00404 00405 return (int)nrefs; 00406 } 00407 00415 static int rpmtsAddObsoletes(rpmts ts, rpmte p, rpmuint32_t hcolor) 00416 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00417 /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/ 00418 { 00419 rpmuint32_t tscolor = rpmtsColor(ts); 00420 alKey pkgKey = rpmteAddedKey(p); 00421 rpmuint32_t ohcolor; 00422 rpmds obsoletes; 00423 rpmuint32_t dscolor; 00424 rpmmi mi; 00425 Header oh; 00426 int xx; 00427 00428 if (_obsolete_tag == 0) { 00429 const char *t = rpmExpand("%{?_obsolete_tag}", NULL); 00430 /*@-mods@*/ 00431 _obsolete_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME); 00432 /*@=mods@*/ 00433 t = _free(t); 00434 } 00435 00436 obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes"); 00437 obsoletes = rpmdsInit(obsoletes); 00438 if (obsoletes != NULL) 00439 while (rpmdsNext(obsoletes) >= 0) { 00440 const char * Name; 00441 00442 if ((Name = rpmdsN(obsoletes)) == NULL) 00443 continue; /* XXX can't happen */ 00444 00445 /* Ignore colored obsoletes not in our rainbow. */ 00446 #if 0 00447 /* XXX obsoletes are never colored, so this is for future devel. */ 00448 dscolor = rpmdsColor(obsoletes); 00449 #else 00450 dscolor = hcolor; 00451 #endif 00452 if (tscolor && dscolor && !(tscolor & dscolor)) 00453 continue; 00454 00455 /* XXX avoid self-obsoleting packages. */ 00456 if (!strcmp(rpmteN(p), Name)) 00457 continue; 00458 00459 /* Obsolete containing package if given a file, otherwise provide. */ 00460 if (Name[0] == '/') 00461 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0); 00462 else 00463 mi = rpmtsInitIterator(ts, _obsolete_tag, Name, 0); 00464 00465 xx = rpmmiPrune(mi, 00466 ts->removedPackages, ts->numRemovedPackages, 1); 00467 00468 while((oh = rpmmiNext(mi)) != NULL) { 00469 int lastx; 00470 rpmte q; 00471 00472 /* Ignore colored packages not in our rainbow. */ 00473 ohcolor = hGetColor(oh); 00474 00475 /* XXX provides *are* colored, effectively limiting Obsoletes: 00476 to matching only colored Provides: based on pkg coloring. */ 00477 if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor)) 00478 /*@innercontinue@*/ continue; 00479 00480 /* 00481 * Rpm prior to 3.0.3 does not have versioned obsoletes. 00482 * If no obsoletes version info is available, match all names. 00483 */ 00484 if (!(rpmdsEVR(obsoletes) == NULL 00485 || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote))) 00486 /*@innercontinue@*/ continue; 00487 00488 /* Create an erasure element. */ 00489 lastx = -1; 00490 xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey); 00491 assert(lastx >= 0 && lastx < ts->orderCount); 00492 q = ts->order[lastx]; 00493 00494 /* Chain through obsoletes flink. */ 00495 xx = rpmteChain(p, q, oh, "Obsoletes"); 00496 00497 /*@-nullptrarith@*/ 00498 rpmlog(RPMLOG_DEBUG, D_(" Obsoletes: %s\t\terases %s\n"), 00499 rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q)); 00500 /*@=nullptrarith@*/ 00501 } 00502 mi = rpmmiFree(mi); 00503 } 00504 (void)rpmdsFree(obsoletes); 00505 obsoletes = NULL; 00506 00507 return 0; 00508 } 00509 00510 #if defined(RPM_VENDOR_WINDRIVER) 00511 /* Is "compat" compatible w/ arch? */ 00512 int _isCompatibleArch(const char * arch, const char * compat) 00513 { 00514 const char * compatArch = rpmExpand(compat, " %{?_", compat, "_compat_arch}", NULL); 00515 const char * p, * pe, * t; 00516 int match = 0; 00517 00518 /* Hack to ensure iX86 being automatically compatible */ 00519 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') { 00520 if ((arch[0] == compat[0]) && 00521 (arch[2] == compat[2]) && 00522 (arch[3] == compat[3])) 00523 match = 1; 00524 00525 if (!strcmp(compat, "x86_32")) 00526 match = 1; 00527 } 00528 00529 for ( p = pe = compatArch ; *pe && match == 0 ; ) { 00530 while (*p && xisspace(*p)) p++; 00531 pe = p ; while (*pe && !xisspace(*pe)) pe++; 00532 if (p == pe) 00533 break; 00534 t = strndup(p, (pe - p)); 00535 p = pe; /* Advance to next chunk */ 00536 rpmlog(RPMLOG_DEBUG, D_(" Comparing compat archs %s ? %s\n"), arch, t); 00537 if (!strcmp(arch, t)) 00538 match = 1; 00539 t = _free(t); 00540 } 00541 compatArch = _free(compatArch); 00542 return match; 00543 } 00544 #endif 00545 00546 int rpmtsAddInstallElement(rpmts ts, Header h, 00547 fnpyKey key, int upgrade, rpmRelocation relocs) 00548 { 00549 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00550 rpmdepFlags depFlags = rpmtsDFlags(ts); 00551 rpmuint32_t tscolor = rpmtsColor(ts); 00552 rpmuint32_t hcolor; 00553 int isSource; 00554 int duplicate = 0; 00555 rpmtsi pi = NULL; rpmte p; 00556 const char * arch = NULL; 00557 const char * os = NULL; 00558 rpmds oldChk, newChk; 00559 alKey pkgKey; /* addedPackages key */ 00560 int xx; 00561 int ec = 0; 00562 int rc; 00563 int oc; 00564 00565 hcolor = hGetColor(h); 00566 pkgKey = RPMAL_NOMATCH; 00567 00568 /* 00569 * Always add source headers. 00570 */ 00571 isSource = 00572 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 && 00573 headerIsEntry(h, RPMTAG_ARCH) != 0); 00574 if (isSource) { 00575 oc = ts->orderCount; 00576 goto addheader; 00577 } 00578 00579 /* 00580 * Check platform affinity of binary packages. 00581 */ 00582 he->tag = RPMTAG_ARCH; 00583 xx = headerGet(h, he, 0); 00584 arch = he->p.str; 00585 he->tag = RPMTAG_OS; 00586 xx = headerGet(h, he, 0); 00587 os = he->p.str; 00588 if (nplatpat > 1) { 00589 const char * platform = NULL; 00590 00591 he->tag = RPMTAG_PLATFORM; 00592 xx = headerGet(h, he, 0); 00593 platform = he->p.str; 00594 if (!xx || platform == NULL) 00595 platform = rpmExpand(arch, "-unknown-", os, NULL); 00596 00597 rc = rpmPlatformScore(platform, platpat, nplatpat); 00598 if (rc <= 0) { 00599 rpmps ps = rpmtsProblems(ts); 00600 he->tag = RPMTAG_NVRA; 00601 xx = headerGet(h, he, 0); 00602 assert(he->p.str != NULL); 00603 00604 rpmpsAppend(ps, RPMPROB_BADPLATFORM, he->p.str, key, 00605 platform, NULL, NULL, 0); 00606 00607 /* XXX problem string should be printed by caller instead. */ 00608 if (rpmIsVerbose()) { 00609 const char * msg = rpmProblemString(rpmpsGetProblem(ps, -1)); 00610 rpmlog(RPMLOG_WARNING, "%s\n", msg); 00611 msg = _free(msg); 00612 } 00613 00614 ps = rpmpsFree(ps); 00615 he->p.ptr = _free(he->p.ptr); 00616 ec = 1; 00617 } 00618 platform = _free(platform); 00619 if (ec) 00620 goto exit; 00621 } 00622 00623 /* 00624 * Always install compatible binary packages. 00625 */ 00626 if (!upgrade) { 00627 oc = ts->orderCount; 00628 goto addheader; 00629 } 00630 00631 /* 00632 * Check that upgrade package is uniquely newer, replace older if necessary. 00633 */ 00634 oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS)); 00635 newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER)); 00636 /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */ 00637 for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) { 00638 rpmds this; 00639 00640 /* XXX Only added packages need be checked for dupes here. */ 00641 if (rpmteType(p) == TR_REMOVED) 00642 continue; 00643 00644 /* XXX Never check source header NEVRAO. */ 00645 if (rpmteIsSource(p)) 00646 continue; 00647 00648 if (tscolor) { 00649 const char * parch; 00650 const char * pos; 00651 00652 if (arch == NULL || (parch = rpmteA(p)) == NULL) 00653 continue; 00654 #if defined(RPM_VENDOR_WINDRIVER) 00655 /* XXX hackery for alias matching. */ 00656 if (!_isCompatibleArch(arch, parch)) 00657 continue; 00658 #else 00659 /* XXX hackery for i[3456]86 alias matching. */ 00660 if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') { 00661 if (arch[0] != parch[0]) continue; 00662 if (arch[2] != parch[2]) continue; 00663 if (arch[3] != parch[3]) continue; 00664 } 00665 #endif 00666 else if (strcmp(arch, parch)) 00667 continue; 00668 if (os == NULL || (pos = rpmteO(p)) == NULL) 00669 continue; 00670 00671 if (strcmp(os, pos)) 00672 continue; 00673 } 00674 00675 /* OK, binary rpm's with same arch and os. Check NEVR. */ 00676 if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL) 00677 continue; /* XXX can't happen */ 00678 00679 /* If newer NEVRAO already added, then skip adding older. */ 00680 rc = rpmdsCompare(newChk, this); 00681 if (rc != 0) { 00682 const char * pkgNEVR = rpmdsDNEVR(this); 00683 const char * addNEVR = rpmdsDNEVR(oldChk); 00684 if (rpmIsVerbose()) 00685 rpmlog(RPMLOG_WARNING, 00686 _("package %s was already added, skipping %s\n"), 00687 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"), 00688 (addNEVR ? addNEVR + 2 : "?addNEVR?")); 00689 ec = 1; 00690 break; 00691 } 00692 00693 /* If older NEVRAO already added, then replace old with new. */ 00694 rc = rpmdsCompare(oldChk, this); 00695 if (rc != 0) { 00696 const char * pkgNEVR = rpmdsDNEVR(this); 00697 const char * addNEVR = rpmdsDNEVR(newChk); 00698 if (rpmIsVerbose()) 00699 rpmlog(RPMLOG_WARNING, 00700 _("package %s was already added, replacing with %s\n"), 00701 (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"), 00702 (addNEVR ? addNEVR + 2 : "?addNEVR?")); 00703 duplicate = 1; 00704 pkgKey = rpmteAddedKey(p); 00705 break; 00706 } 00707 } 00708 pi = rpmtsiFree(pi); 00709 (void)rpmdsFree(oldChk); 00710 oldChk = NULL; 00711 (void)rpmdsFree(newChk); 00712 newChk = NULL; 00713 00714 /* If newer (or same) NEVRAO was already added, exit now. */ 00715 if (ec) 00716 goto exit; 00717 00718 addheader: 00719 if (oc >= ts->orderAlloced) { 00720 ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta; 00721 /*@-type +voidabstract @*/ 00722 ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order)); 00723 /*@=type =voidabstract @*/ 00724 } 00725 00726 p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey); 00727 assert(p != NULL); 00728 00729 if (duplicate && oc < ts->orderCount) { 00730 /*@-type -unqualifiedtrans@*/ 00731 ts->order[oc] = rpmteFree(ts->order[oc]); 00732 /*@=type =unqualifiedtrans@*/ 00733 } 00734 00735 ts->order[oc] = p; 00736 if (!duplicate) { 00737 ts->orderCount++; 00738 rpmcliPackagesTotal++; 00739 } 00740 00741 pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p), 00742 rpmteDS(p, RPMTAG_PROVIDENAME), 00743 rpmteFI(p, RPMTAG_BASENAMES), tscolor); 00744 if (pkgKey == RPMAL_NOMATCH) { 00745 ts->order[oc] = rpmteFree(ts->order[oc]); 00746 ts->teInstall = NULL; 00747 ec = 1; 00748 goto exit; 00749 } 00750 (void) rpmteSetAddedKey(p, pkgKey); 00751 00752 if (!duplicate) { 00753 ts->numAddedPackages++; 00754 } 00755 00756 ts->teInstall = ts->order[oc]; 00757 00758 /* XXX rpmgi hack: Save header in transaction element if requested. */ 00759 if (upgrade & 0x2) 00760 (void) rpmteSetHeader(p, h); 00761 00762 /* If not upgrading, then we're done. */ 00763 if (!(upgrade & 0x1)) 00764 goto exit; 00765 00766 /* If source rpm, then we're done. */ 00767 if (isSource) 00768 goto exit; 00769 00770 /* Do lazy (readonly?) open of rpm database. */ 00771 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) { 00772 if ((ec = rpmtsOpenDB(ts, rpmtsDBMode(ts)) != 0)) 00773 goto exit; 00774 } 00775 00776 /* Add upgrades to the transaction (if not disabled). */ 00777 if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) { 00778 /* 00779 * Don't upgrade -debuginfo until build set is empty. 00780 * 00781 * XXX Almost, but not quite, correct since the test depends on 00782 * added package arrival order. 00783 * I.e. -debuginfo additions must always follow all 00784 * other additions so that erasures of other members in the 00785 * same build set are seen if/when included in the same transaction. 00786 */ 00787 xx = rpmtsEraseDebuginfo(ts, p, h, pkgKey); 00788 if (!chkSuffix(rpmteN(p), "-debuginfo") || xx == 0) 00789 xx = rpmtsAddUpgrades(ts, p, hcolor, h); 00790 } 00791 00792 /* Add Obsoletes: to the transaction (if not disabled). */ 00793 if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) { 00794 xx = rpmtsAddObsoletes(ts, p, hcolor); 00795 } 00796 00797 ec = 0; 00798 00799 exit: 00800 arch = _free(arch); 00801 os = _free(os); 00802 pi = rpmtsiFree(pi); 00803 return ec; 00804 } 00805 00806 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset) 00807 { 00808 int oc = -1; 00809 int rc = removePackage(ts, h, dboffset, &oc, RPMAL_NOMATCH); 00810 if (rc == 0 && oc >= 0 && oc < ts->orderCount) { 00811 (void) rpmtsEraseDebuginfo(ts, ts->order[oc], h, RPMAL_NOMATCH); 00812 ts->teErase = ts->order[oc]; 00813 } else 00814 ts->teErase = NULL; 00815 return rc; 00816 } 00817 00818 /*@only@*/ /*@null@*/ /*@unchecked@*/ 00819 static char *sysinfo_path = NULL; 00820 00821 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/ 00822 static rpmds rpmlibP = NULL; 00823 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/ 00824 rpmds cpuinfoP = NULL; 00825 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/ 00826 static rpmds getconfP = NULL; 00827 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/ 00828 static rpmds unameP = NULL; 00829 00830 void rpmnsClean(void) 00831 /*@globals sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/ 00832 /*@modifies sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/ 00833 { 00834 (void)rpmdsFree(rpmlibP); 00835 rpmlibP = NULL; 00836 (void)rpmdsFree(cpuinfoP); 00837 cpuinfoP = NULL; 00838 (void)rpmdsFree(getconfP); 00839 getconfP = NULL; 00840 (void)rpmdsFree(unameP); 00841 unameP = NULL; 00842 /*@-observertrans@*/ 00843 _sysinfo_path = _free(_sysinfo_path); 00844 /*@=observertrans@*/ 00845 sysinfo_path = _free(sysinfo_path); 00846 } 00847 00855 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding) 00856 /*@globals rpmGlobalMacroContext, h_errno, 00857 sysinfo_path, fileSystem, internalState @*/ 00858 /*@modifies ts, dep, rpmGlobalMacroContext, 00859 sysinfo_path, fileSystem, internalState @*/ 00860 { 00861 DBT * key = alloca(sizeof(*key)); 00862 DBT * data = alloca(sizeof(*data)); 00863 rpmmi mi; 00864 nsType NSType; 00865 const char * Name; 00866 rpmuint32_t Flags; 00867 Header h; 00868 #if defined(CACHE_DEPENDENCY_RESULT) 00869 int _cacheThisRC = 1; 00870 #endif 00871 int rc; 00872 int xx; 00873 int retries = 20; 00874 00875 if ((Name = rpmdsN(dep)) == NULL) 00876 return 0; /* XXX can't happen */ 00877 Flags = rpmdsFlags(dep); 00878 NSType = rpmdsNSType(dep); 00879 00880 #if defined(CACHE_DEPENDENCY_RESULT) 00881 /* 00882 * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache. 00883 */ 00884 if (_cacheDependsRC) { 00885 dbiIndex dbi; 00886 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0); 00887 if (dbi == NULL) 00888 _cacheDependsRC = 0; 00889 else { 00890 const char * DNEVR; 00891 00892 rc = -1; 00893 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) { 00894 DBC * dbcursor = NULL; 00895 void * datap = NULL; 00896 size_t datalen = 0; 00897 size_t DNEVRlen = strlen(DNEVR); 00898 00899 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0); 00900 00901 memset(key, 0, sizeof(*key)); 00902 /*@i@*/ key->data = (void *) DNEVR; 00903 key->size = DNEVRlen; 00904 memset(data, 0, sizeof(*data)); 00905 data->data = datap; 00906 data->size = datalen; 00907 /*@-nullstate@*/ /* FIX: data->data may be NULL */ 00908 xx = dbiGet(dbi, dbcursor, key, data, DB_SET); 00909 /*@=nullstate@*/ 00910 DNEVR = key->data; 00911 DNEVRlen = key->size; 00912 datap = data->data; 00913 datalen = data->size; 00914 00915 if (xx == 0 && datap && datalen == 4) 00916 memcpy(&rc, datap, datalen); 00917 xx = dbiCclose(dbi, dbcursor, 0); 00918 } 00919 00920 if (rc >= 0) { 00921 rpmdsNotify(dep, _("(cached)"), rc); 00922 return rpmdsNegateRC(dep, rc); 00923 } 00924 } 00925 } 00926 #endif 00927 00928 retry: 00929 rc = 0; /* assume dependency is satisfied */ 00930 00931 /* Expand macro probe dependencies. */ 00932 if (NSType == RPMNS_TYPE_FUNCTION) { 00933 xx = rpmExpandNumeric(Name); 00934 rc = (xx ? 0 : 1); 00935 if (Flags & RPMSENSE_MISSINGOK) 00936 goto unsatisfied; 00937 rpmdsNotify(dep, _("(function probe)"), rc); 00938 goto exit; 00939 } 00940 00941 /* Evaluate user/group lookup probes. */ 00942 if (NSType == RPMNS_TYPE_USER) { 00943 const char *s; 00944 uid_t uid = 0; 00945 s = Name; while (*s && xisdigit(*s)) s++; 00946 00947 if (*s) 00948 xx = unameToUid(Name, &uid); 00949 else { 00950 uid = strtol(Name, NULL, 10); 00951 xx = (uidToUname(uid) ? 0 : -1); 00952 } 00953 rc = (xx >= 0 ? 0 : 1); 00954 if (Flags & RPMSENSE_MISSINGOK) 00955 goto unsatisfied; 00956 rpmdsNotify(dep, _("(user lookup)"), rc); 00957 goto exit; 00958 } 00959 if (NSType == RPMNS_TYPE_GROUP) { 00960 const char *s; 00961 gid_t gid = 0; 00962 s = Name; while (*s && xisdigit(*s)) s++; 00963 00964 if (*s) 00965 xx = gnameToGid(Name, &gid); 00966 else { 00967 gid = strtol(Name, NULL, 10); 00968 xx = (gidToGname(gid) ? 0 : -1); 00969 } 00970 rc = (xx >= 0 ? 0 : 1); 00971 if (Flags & RPMSENSE_MISSINGOK) 00972 goto unsatisfied; 00973 rpmdsNotify(dep, _("(group lookup)"), rc); 00974 goto exit; 00975 } 00976 00977 /* Evaluate access(2) probe dependencies. */ 00978 if (NSType == RPMNS_TYPE_ACCESS) { 00979 rc = rpmioAccess(Name, NULL, X_OK); 00980 if (Flags & RPMSENSE_MISSINGOK) 00981 goto unsatisfied; 00982 rpmdsNotify(dep, _("(access probe)"), rc); 00983 goto exit; 00984 } 00985 00986 /* Evaluate mtab lookup and diskspace probe dependencies. */ 00987 if (NSType == RPMNS_TYPE_MOUNTED) { 00988 const char ** fs = NULL; 00989 int nfs = 0; 00990 int i = 0; 00991 00992 xx = rpmtsInitDSI(ts); 00993 fs = ts->filesystems; 00994 nfs = ts->filesystemCount; 00995 00996 if (fs != NULL) 00997 for (i = 0; i < nfs; i++) { 00998 if (!strcmp(fs[i], Name)) 00999 break; 01000 } 01001 rc = (i < nfs ? 0 : 1); 01002 if (Flags & RPMSENSE_MISSINGOK) 01003 goto unsatisfied; 01004 rpmdsNotify(dep, _("(mtab probe)"), rc); 01005 goto exit; 01006 } 01007 01008 if (NSType == RPMNS_TYPE_DISKSPACE) { 01009 size_t nb = strlen(Name); 01010 rpmDiskSpaceInfo dsi = NULL; 01011 const char ** fs = NULL; 01012 size_t fslen = 0, longest = 0; 01013 int nfs = 0; 01014 int i = 0; 01015 01016 xx = rpmtsInitDSI(ts); 01017 fs = ts->filesystems; 01018 nfs = ts->filesystemCount; 01019 01020 if (fs != NULL) 01021 for (i = 0; i < nfs; i++) { 01022 fslen = strlen(fs[i]); 01023 if (fslen > nb) 01024 continue; 01025 if (strncmp(fs[i], Name, fslen)) 01026 continue; 01027 if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0') 01028 continue; 01029 if (fslen < longest) 01030 continue; 01031 longest = fslen; 01032 dsi = ts->dsi + i; 01033 } 01034 if (dsi == NULL) 01035 rc = 1; /* no mounted paths !?! */ 01036 else { 01037 char * end = NULL; 01038 /*@-unrecog@*/ 01039 rpmuint64_t needed = strtoll(rpmdsEVR(dep), &end, 0); 01040 /*@=unrecog@*/ 01041 01042 if (end && *end) { 01043 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2]) 01044 needed *= 1024 * 1024 * 1024; 01045 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2]) 01046 needed *= 1024 * 1024; 01047 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2]) 01048 needed *= 1024; 01049 } else 01050 needed *= 1024 * 1024; /* XXX assume Mb if no units given */ 01051 01052 needed = BLOCK_ROUND(needed, dsi->f_bsize); 01053 xx = (dsi->f_bavail - needed); 01054 if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0; 01055 else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0; 01056 else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0; 01057 else rc = 1; 01058 } 01059 if (Flags & RPMSENSE_MISSINGOK) 01060 goto unsatisfied; 01061 rpmdsNotify(dep, _("(diskspace probe)"), rc); 01062 goto exit; 01063 } 01064 01065 if (NSType == RPMNS_TYPE_DIGEST) { 01066 const char * EVR = rpmdsEVR(dep); 01067 const char *filename; 01068 pgpHashAlgo digestHashAlgo; 01069 FD_t fd; 01070 char *cp; 01071 int algo; 01072 01073 filename = Name; 01074 digestHashAlgo = PGPHASHALGO_MD5; 01075 if ((cp = strchr(filename, ':')) != NULL) { 01076 if ((algo = pgpHashAlgoStringToNumber(filename, cp-filename)) != PGPHASHALGO_ERROR) { 01077 digestHashAlgo = algo; 01078 filename = cp + 1; 01079 } 01080 } 01081 rc = 1; /* XXX assume failure */ 01082 fd = Fopen(filename, "r.fdio"); 01083 if (fd && !Ferror(fd)) { 01084 DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE); 01085 const char * digest = NULL; 01086 size_t digestlen = 0; 01087 int asAscii = 1; 01088 size_t nbuf = 8 * BUFSIZ; 01089 char * buf = alloca(nbuf); 01090 size_t nb; 01091 01092 while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0) 01093 xx = rpmDigestUpdate(ctx, buf, nb); 01094 xx = Fclose(fd); fd = NULL; 01095 xx = rpmDigestFinal(ctx, &digest, &digestlen, asAscii); 01096 01097 xx = (EVR && *EVR && digest && *digest) ? strcasecmp(EVR, digest) : -1; 01098 /* XXX only equality makes sense for digest compares */ 01099 if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0; 01100 } 01101 if (Flags & RPMSENSE_MISSINGOK) 01102 goto unsatisfied; 01103 rpmdsNotify(dep, _("(digest probe)"), rc); 01104 goto exit; 01105 } 01106 01107 if (NSType == RPMNS_TYPE_SIGNATURE) { 01108 const char * EVR = rpmdsEVR(dep); 01109 ARGV_t avN = NULL; 01110 ARGV_t avEVR = NULL; 01111 rpmRC res; 01112 01113 /* Split /fn:/sig */ 01114 xx = argvSplit(&avN, Name, ":"); 01115 01116 /* Split /pub:id */ 01117 xx = (EVR && *EVR) ? argvSplit(&avEVR, EVR, ":") : argvAdd(&avEVR, ""); 01118 01119 res = rpmnsProbeSignature(ts, avN[0], avN[1], avEVR[0], avEVR[1], 0); 01120 rc = (res == RPMRC_OK ? 0 : 1); 01121 01122 avN = argvFree(avN); 01123 avEVR = argvFree(avEVR); 01124 01125 if (Flags & RPMSENSE_MISSINGOK) 01126 goto unsatisfied; 01127 rpmdsNotify(dep, _("(signature probe)"), rc); 01128 goto exit; 01129 } 01130 01131 if (NSType == RPMNS_TYPE_VERIFY) { 01132 QVA_t qva = memset(alloca(sizeof(*qva)), 0, sizeof(*qva)); 01133 01134 qva->qva_mode = 'v'; 01135 qva->qva_flags = (int)(VERIFY_ALL & ~(VERIFY_DEPS|VERIFY_SCRIPT)); 01136 rc = 0; /* assume success */ 01137 if (rpmtsGetRdb(ts) != NULL) { 01138 if (!strcmp(Name, "*")) /* -Va probe */ 01139 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0); 01140 else if (Name[0] == '/') /* -Vf probe */ 01141 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0); 01142 else /* -V probe */ 01143 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0); 01144 while ((h = rpmmiNext(mi)) != NULL) { 01145 if (!(Name[0] == '/' || !strcmp(Name, "*"))) 01146 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) 01147 continue; 01148 xx = (showVerifyPackage(qva, ts, h) ? 1 : 0); 01149 if (xx) 01150 rc = 1; 01151 } 01152 mi = rpmmiFree(mi); 01153 } 01154 01155 if (Flags & RPMSENSE_MISSINGOK) 01156 goto unsatisfied; 01157 rpmdsNotify(dep, _("(verify probe)"), rc); 01158 goto exit; 01159 } 01160 01161 if (NSType == RPMNS_TYPE_GNUPG) { 01162 const char * EVR = rpmdsEVR(dep); 01163 if (!(EVR && *EVR)) { 01164 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify "; 01165 static const char gnupg_post[] = " 2>/dev/null; echo $?)"; 01166 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL); 01167 rc = (t && t[0] == '0') ? 0 : 1; 01168 t = _free(t); 01169 } 01170 else { 01171 static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify "; 01172 static const char gnupg_post[] = " 2>&1 | grep '^Primary key fingerprint:' | sed -e 's;^.*: *;;' -e 's; *;;g')"; 01173 const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL); 01174 rc = ((Flags & RPMSENSE_EQUAL) && strcasecmp(EVR, t) == 0) ? 0 : 1; 01175 t = _free(t); 01176 } 01177 if (Flags & RPMSENSE_MISSINGOK) 01178 goto unsatisfied; 01179 rpmdsNotify(dep, _("(gnupg probe)"), rc); 01180 goto exit; 01181 } 01182 01183 if (NSType == RPMNS_TYPE_MACRO) { 01184 static const char macro_pre[] = "%{?"; 01185 static const char macro_post[] = ":0}"; 01186 const char * a = rpmExpand(macro_pre, Name, macro_post, NULL); 01187 01188 rc = (a && a[0] == '0') ? 0 : 1; 01189 a = _free(a); 01190 if (Flags & RPMSENSE_MISSINGOK) 01191 goto unsatisfied; 01192 rpmdsNotify(dep, _("(macro probe)"), rc); 01193 goto exit; 01194 } 01195 01196 if (NSType == RPMNS_TYPE_ENVVAR) { 01197 const char * a = envGet(Name); 01198 const char * b = rpmdsEVR(dep); 01199 01200 /* Existence test if EVR is missing/empty. */ 01201 if (!(b && *b)) 01202 rc = (!(a && *a)); 01203 else { 01204 int sense = (a && *a) ? strcmp(a, b) : -1; 01205 01206 if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL) 01207 rc = (sense == 0); 01208 else if (sense < 0 && (Flags & RPMSENSE_LESS)) 01209 rc = 0; 01210 else if (sense > 0 && (Flags & RPMSENSE_GREATER)) 01211 rc = 0; 01212 else if (sense == 0 && (Flags & RPMSENSE_EQUAL)) 01213 rc = 0; 01214 else 01215 rc = (sense != 0); 01216 } 01217 01218 if (Flags & RPMSENSE_MISSINGOK) 01219 goto unsatisfied; 01220 rpmdsNotify(dep, _("(envvar probe)"), rc); 01221 goto exit; 01222 } 01223 01224 if (NSType == RPMNS_TYPE_RUNNING) { 01225 char *t = NULL; 01226 pid_t pid = strtol(Name, &t, 10); 01227 01228 if (t == NULL || *t != '\0') { 01229 const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL); 01230 FD_t fd = NULL; 01231 01232 if (fn && *fn != '%' && (fd = Fopen(fn, "r.fdio")) && !Ferror(fd)) { 01233 char buf[32]; 01234 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd); 01235 01236 if (nb > 0) 01237 pid = strtol(buf, &t, 10); 01238 } else 01239 pid = 0; 01240 if (fd != NULL) 01241 (void) Fclose(fd); 01242 fn = _free(fn); 01243 } 01244 rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1); 01245 if (Flags & RPMSENSE_MISSINGOK) 01246 goto unsatisfied; 01247 rpmdsNotify(dep, _("(running probe)"), rc); 01248 goto exit; 01249 } 01250 01251 if (NSType == RPMNS_TYPE_SANITY) { 01252 /* XXX only the installer does not have the database open here. */ 01253 rc = 1; /* assume failure */ 01254 if (rpmtsGetRdb(ts) != NULL) { 01255 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0); 01256 while ((h = rpmmiNext(mi)) != NULL) { 01257 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) 01258 continue; 01259 rc = (headerIsEntry(h, RPMTAG_SANITYCHECK) == 0); 01260 if (rc == 0) { 01261 /* XXX FIXME: actually run the sanitycheck script. */ 01262 break; 01263 } 01264 } 01265 mi = rpmmiFree(mi); 01266 } 01267 if (Flags & RPMSENSE_MISSINGOK) 01268 goto unsatisfied; 01269 rpmdsNotify(dep, _("(sanity probe)"), rc); 01270 goto exit; 01271 } 01272 01273 if (NSType == RPMNS_TYPE_VCHECK) { 01274 rc = 1; /* assume failure */ 01275 if (rpmtsGetRdb(ts) != NULL) { 01276 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0); 01277 while ((h = rpmmiNext(mi)) != NULL) { 01278 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) 01279 continue; 01280 rc = (headerIsEntry(h, RPMTAG_TRACK) == 0); 01281 if (rc == 0) { 01282 /* XXX FIXME: actually run the vcheck script. */ 01283 break; 01284 } 01285 } 01286 mi = rpmmiFree(mi); 01287 } 01288 if (Flags & RPMSENSE_MISSINGOK) 01289 goto unsatisfied; 01290 rpmdsNotify(dep, _("(vcheck probe)"), rc); 01291 goto exit; 01292 } 01293 01294 /* Search system configured provides. */ 01295 if (sysinfo_path == NULL) { 01296 sysinfo_path = rpmExpand("%{?_rpmds_sysinfo_path}", NULL); 01297 if (!(sysinfo_path != NULL && *sysinfo_path == '/')) { 01298 sysinfo_path = _free(sysinfo_path); 01299 sysinfo_path = xstrdup(SYSCONFIGDIR "/sysinfo"); 01300 } 01301 } 01302 01303 if (!rpmioAccess(sysinfo_path, NULL, R_OK)) { 01304 #ifdef NOTYET /* XXX just sysinfo Provides: for now. */ 01305 rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME); 01306 #else 01307 rpmTag tagN = RPMTAG_PROVIDENAME; 01308 #endif 01309 rpmds P = rpmdsFromPRCO(rpmtsPRCO(ts), tagN); 01310 if (rpmdsSearch(P, dep) >= 0) { 01311 rpmdsNotify(dep, _("(sysinfo provides)"), rc); 01312 goto exit; 01313 } 01314 } 01315 01316 /* 01317 * New features in rpm packaging implicitly add versioned dependencies 01318 * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)". 01319 * Check those dependencies now. 01320 */ 01321 if (NSType == RPMNS_TYPE_RPMLIB) { 01322 static int oneshot = -1; 01323 01324 if (oneshot) 01325 oneshot = rpmdsRpmlib(&rpmlibP, NULL); 01326 if (rpmlibP == NULL) 01327 goto unsatisfied; 01328 01329 if (rpmdsSearch(rpmlibP, dep) >= 0) { 01330 rpmdsNotify(dep, _("(rpmlib provides)"), rc); 01331 goto exit; 01332 } 01333 goto unsatisfied; 01334 } 01335 01336 if (NSType == RPMNS_TYPE_CPUINFO) { 01337 static int oneshot = -1; 01338 01339 if (oneshot && cpuinfoP == NULL) 01340 oneshot = rpmdsCpuinfo(&cpuinfoP, NULL); 01341 if (cpuinfoP == NULL) 01342 goto unsatisfied; 01343 01344 if (rpmdsSearch(cpuinfoP, dep) >= 0) { 01345 rpmdsNotify(dep, _("(cpuinfo provides)"), rc); 01346 goto exit; 01347 } 01348 goto unsatisfied; 01349 } 01350 01351 if (NSType == RPMNS_TYPE_GETCONF) { 01352 static int oneshot = -1; 01353 01354 if (oneshot) 01355 oneshot = rpmdsGetconf(&getconfP, NULL); 01356 if (getconfP == NULL) 01357 goto unsatisfied; 01358 01359 if (rpmdsSearch(getconfP, dep) >= 0) { 01360 rpmdsNotify(dep, _("(getconf provides)"), rc); 01361 goto exit; 01362 } 01363 goto unsatisfied; 01364 } 01365 01366 if (NSType == RPMNS_TYPE_UNAME) { 01367 static int oneshot = -1; 01368 01369 if (oneshot) 01370 oneshot = rpmdsUname(&unameP, NULL); 01371 if (unameP == NULL) 01372 goto unsatisfied; 01373 01374 if (rpmdsSearch(unameP, dep) >= 0) { 01375 rpmdsNotify(dep, _("(uname provides)"), rc); 01376 goto exit; 01377 } 01378 goto unsatisfied; 01379 } 01380 01381 if (NSType == RPMNS_TYPE_SONAME) { 01382 rpmds sonameP = NULL; 01383 rpmPRCO PRCO = rpmdsNewPRCO(NULL); 01384 char * fn = strcpy(alloca(strlen(Name)+1), Name); 01385 int flags = 0; /* XXX RPMELF_FLAG_SKIPREQUIRES? */ 01386 rpmds ds; 01387 01388 /* XXX Only absolute paths for now. */ 01389 if (*fn != '/') 01390 goto unsatisfied; 01391 fn[strlen(fn)-1] = '\0'; 01392 01393 /* Extract ELF Provides: from /path/to/DSO. */ 01394 xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO); 01395 sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME); 01396 if (!(xx == 0 && sonameP != NULL)) 01397 goto unsatisfied; 01398 01399 /* Search using the original {EVR,"",Flags} from the dep set. */ 01400 ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags); 01401 xx = rpmdsSearch(sonameP, ds); 01402 (void)rpmdsFree(ds); 01403 ds = NULL; 01404 PRCO = rpmdsFreePRCO(PRCO); 01405 01406 /* Was the dependency satisfied? */ 01407 if (xx >= 0) { 01408 rpmdsNotify(dep, _("(soname provides)"), rc); 01409 goto exit; 01410 } 01411 goto unsatisfied; 01412 } 01413 01414 /* Search added packages for the dependency. */ 01415 if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) { 01416 #if defined(CACHE_DEPENDENCY_RESULT) 01417 /* 01418 * XXX Ick, context sensitive answers from dependency cache. 01419 * XXX Always resolve added dependencies within context to disambiguate. 01420 */ 01421 if (_rpmds_nopromote) 01422 _cacheThisRC = 0; 01423 #endif 01424 goto exit; 01425 } 01426 01427 /* XXX only the installer does not have the database open here. */ 01428 if (rpmtsGetRdb(ts) != NULL) { 01429 if (Name[0] == '/') { 01430 /* depFlags better be 0! */ 01431 01432 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0); 01433 (void) rpmmiPrune(mi, 01434 ts->removedPackages, ts->numRemovedPackages, 1); 01435 while ((h = rpmmiNext(mi)) != NULL) { 01436 rpmdsNotify(dep, _("(db files)"), rc); 01437 mi = rpmmiFree(mi); 01438 goto exit; 01439 } 01440 mi = rpmmiFree(mi); 01441 } 01442 01443 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0); 01444 (void) rpmmiPrune(mi, 01445 ts->removedPackages, ts->numRemovedPackages, 1); 01446 while ((h = rpmmiNext(mi)) != NULL) { 01447 if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) { 01448 rpmdsNotify(dep, _("(db provides)"), rc); 01449 mi = rpmmiFree(mi); 01450 goto exit; 01451 } 01452 } 01453 mi = rpmmiFree(mi); 01454 } 01455 01456 /* 01457 * Search for an unsatisfied dependency. 01458 */ 01459 if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) { 01460 if (ts->solve != NULL) { 01461 xx = (*ts->solve) (ts, dep, ts->solveData); 01462 if (xx == 0) 01463 goto exit; 01464 if (xx == -1) { 01465 retries--; 01466 rpmalMakeIndex(ts->addedPackages); 01467 goto retry; 01468 } 01469 } 01470 } 01471 01472 unsatisfied: 01473 if (Flags & RPMSENSE_MISSINGOK) { 01474 rc = 0; /* dependency is unsatisfied, but just a hint. */ 01475 #if defined(CACHE_DEPENDENCY_RESULT) 01476 _cacheThisRC = 0; 01477 #endif 01478 rpmdsNotify(dep, _("(hint skipped)"), rc); 01479 } else { 01480 rc = 1; /* dependency is unsatisfied */ 01481 rpmdsNotify(dep, NULL, rc); 01482 } 01483 01484 exit: 01485 /* 01486 * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache. 01487 */ 01488 #if defined(CACHE_DEPENDENCY_RESULT) 01489 if (_cacheDependsRC && _cacheThisRC) { 01490 dbiIndex dbi; 01491 dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0); 01492 if (dbi == NULL) { 01493 _cacheDependsRC = 0; 01494 } else { 01495 const char * DNEVR; 01496 xx = 0; 01497 if ((DNEVR = rpmdsDNEVR(dep)) != NULL) { 01498 DBC * dbcursor = NULL; 01499 size_t DNEVRlen = strlen(DNEVR); 01500 01501 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR); 01502 01503 memset(key, 0, sizeof(*key)); 01504 /*@i@*/ key->data = (void *) DNEVR; 01505 key->size = DNEVRlen; 01506 memset(data, 0, sizeof(*data)); 01507 data->data = &rc; 01508 data->size = sizeof(rc); 01509 01510 /*@-compmempass@*/ 01511 xx = dbiPut(dbi, dbcursor, key, data, 0); 01512 /*@=compmempass@*/ 01513 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR); 01514 } 01515 if (xx) 01516 _cacheDependsRC = 0; 01517 } 01518 } 01519 #endif 01520 01521 return rpmdsNegateRC(dep, rc); 01522 } 01523 01537 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA, 01538 /*@null@*/ rpmds requires, 01539 /*@null@*/ rpmds conflicts, 01540 /*@null@*/ rpmds dirnames, 01541 /*@null@*/ rpmds linktos, 01542 /*@null@*/ const char * depName, 01543 rpmuint32_t tscolor, int adding) 01544 /*@globals rpmGlobalMacroContext, h_errno, 01545 fileSystem, internalState @*/ 01546 /*@modifies ts, requires, conflicts, dirnames, linktos, 01547 rpmGlobalMacroContext, fileSystem, internalState */ 01548 { 01549 rpmps ps = rpmtsProblems(ts); 01550 rpmuint32_t dscolor; 01551 const char * Name; 01552 int terminate = 2; /* XXX terminate if rc >= terminate */ 01553 int rc; 01554 int ourrc = 0; 01555 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */ 01556 int dirname_deps; 01557 int symlink_deps; 01558 #endif 01559 01560 requires = rpmdsInit(requires); 01561 if (requires != NULL) 01562 while (ourrc < terminate && rpmdsNext(requires) >= 0) { 01563 01564 if ((Name = rpmdsN(requires)) == NULL) 01565 continue; /* XXX can't happen */ 01566 01567 /* Filter out requires that came along for the ride. */ 01568 if (depName != NULL && strcmp(depName, Name)) 01569 continue; 01570 01571 /* Ignore colored requires not in our rainbow. */ 01572 dscolor = rpmdsColor(requires); 01573 if (tscolor && dscolor && !(tscolor & dscolor)) 01574 continue; 01575 01576 rc = unsatisfiedDepend(ts, requires, adding); 01577 01578 switch (rc) { 01579 case 0: /* requirements are satisfied. */ 01580 /*@switchbreak@*/ break; 01581 case 1: /* requirements are not satisfied. */ 01582 { fnpyKey * suggestedKeys = NULL; 01583 01584 if (ts->availablePackages != NULL) { 01585 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages, 01586 requires, NULL); 01587 } 01588 01589 rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding); 01590 01591 } 01592 ourrc = 1; 01593 /*@switchbreak@*/ break; 01594 case 2: /* something went wrong! */ 01595 default: 01596 ourrc = 2; 01597 /*@switchbreak@*/ break; 01598 } 01599 } 01600 01601 conflicts = rpmdsInit(conflicts); 01602 if (conflicts != NULL) 01603 while (ourrc < terminate && rpmdsNext(conflicts) >= 0) { 01604 01605 if ((Name = rpmdsN(conflicts)) == NULL) 01606 continue; /* XXX can't happen */ 01607 01608 /* Filter out conflicts that came along for the ride. */ 01609 if (depName != NULL && strcmp(depName, Name)) 01610 continue; 01611 01612 /* Ignore colored conflicts not in our rainbow. */ 01613 dscolor = rpmdsColor(conflicts); 01614 if (tscolor && dscolor && !(tscolor & dscolor)) 01615 continue; 01616 01617 rc = unsatisfiedDepend(ts, conflicts, adding); 01618 01619 /* 1 == unsatisfied, 0 == satsisfied */ 01620 switch (rc) { 01621 case 0: /* conflicts exist. */ 01622 rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding); 01623 ourrc = 1; 01624 /*@switchbreak@*/ break; 01625 case 1: /* conflicts don't exist. */ 01626 /*@switchbreak@*/ break; 01627 case 2: /* something went wrong! */ 01628 default: 01629 ourrc = 2; 01630 /*@switchbreak@*/ break; 01631 } 01632 } 01633 01634 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */ 01635 dirname_deps = rpmExpandNumeric("%{?_check_dirname_deps}%{?!_check_dirname_deps:1}"); 01636 if (dirname_deps) { 01637 #endif 01638 dirnames = rpmdsInit(dirnames); 01639 if (dirnames != NULL) 01640 while (ourrc < terminate && rpmdsNext(dirnames) >= 0) { 01641 01642 if ((Name = rpmdsN(dirnames)) == NULL) 01643 continue; /* XXX can't happen */ 01644 01645 /* Filter out dirnames that came along for the ride. */ 01646 if (depName != NULL && strcmp(depName, Name)) 01647 continue; 01648 01649 /* Ignore colored dirnames not in our rainbow. */ 01650 dscolor = rpmdsColor(dirnames); 01651 if (tscolor && dscolor && !(tscolor & dscolor)) 01652 continue; 01653 01654 rc = unsatisfiedDepend(ts, dirnames, adding); 01655 01656 switch (rc) { 01657 case 0: /* requirements are satisfied. */ 01658 /*@switchbreak@*/ break; 01659 case 1: /* requirements are not satisfied. */ 01660 { fnpyKey * suggestedKeys = NULL; 01661 01662 if (ts->availablePackages != NULL) { 01663 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages, 01664 dirnames, NULL); 01665 } 01666 01667 rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding); 01668 01669 } 01670 ourrc = 1; 01671 /*@switchbreak@*/ break; 01672 case 2: /* something went wrong! */ 01673 default: 01674 ourrc = 2; 01675 /*@switchbreak@*/ break; 01676 } 01677 } 01678 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */ 01679 } 01680 01681 symlink_deps = rpmExpandNumeric("%{?_check_symlink_deps}%{?!_check_symlink_deps:1}"); 01682 if (symlink_deps) { 01683 #endif 01684 linktos = rpmdsInit(linktos); 01685 if (linktos != NULL) 01686 while (ourrc < terminate && rpmdsNext(linktos) >= 0) { 01687 01688 if ((Name = rpmdsN(linktos)) == NULL) 01689 continue; /* XXX can't happen */ 01690 if (*Name == '\0') /* XXX most linktos are empty */ 01691 continue; 01692 01693 /* Filter out linktos that came along for the ride. */ 01694 if (depName != NULL && strcmp(depName, Name)) 01695 continue; 01696 01697 /* Ignore colored linktos not in our rainbow. */ 01698 dscolor = rpmdsColor(linktos); 01699 if (tscolor && dscolor && !(tscolor & dscolor)) 01700 continue; 01701 01702 rc = unsatisfiedDepend(ts, linktos, adding); 01703 01704 switch (rc) { 01705 case 0: /* requirements are satisfied. */ 01706 /*@switchbreak@*/ break; 01707 case 1: /* requirements are not satisfied. */ 01708 { fnpyKey * suggestedKeys = NULL; 01709 01710 if (ts->availablePackages != NULL) { 01711 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages, 01712 linktos, NULL); 01713 } 01714 01715 rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding); 01716 01717 } 01718 ourrc = 1; 01719 /*@switchbreak@*/ break; 01720 case 2: /* something went wrong! */ 01721 default: 01722 ourrc = 2; 01723 /*@switchbreak@*/ break; 01724 } 01725 } 01726 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) /* optional-dirname-and-symlink-deps */ 01727 } 01728 #endif 01729 01730 ps = rpmpsFree(ps); 01731 return ourrc; 01732 } 01733 01744 static int checkPackageSet(rpmts ts, const char * depName, 01745 /*@only@*/ /*@null@*/ rpmmi mi, int adding) 01746 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01747 /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/ 01748 { 01749 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 01750 rpmdepFlags depFlags = rpmtsDFlags(ts); 01751 rpmuint32_t tscolor = rpmtsColor(ts); 01752 int scareMem = 0; 01753 Header h; 01754 int terminate = 2; /* XXX terminate if rc >= terminate */ 01755 int ourrc = 0; 01756 01757 (void) rpmmiPrune(mi, 01758 ts->removedPackages, ts->numRemovedPackages, 1); 01759 while (ourrc < terminate && (h = rpmmiNext(mi)) != NULL) { 01760 rpmds requires = NULL; 01761 rpmds conflicts = NULL; 01762 rpmds dirnames = NULL; 01763 rpmds linktos = NULL; 01764 int rc; 01765 01766 he->tag = RPMTAG_NVRA; 01767 rc = (headerGet(h, he, 0) ? 0 : 2); 01768 if (rc > ourrc) 01769 ourrc = rc; 01770 if (ourrc >= terminate) { 01771 he->p.str = _free(he->p.str); 01772 break; 01773 } 01774 01775 if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)) 01776 requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem); 01777 if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)) 01778 conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem); 01779 if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)) 01780 dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem); 01781 if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)) 01782 linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem); 01783 01784 (void) rpmdsSetNoPromote(requires, _rpmds_nopromote); 01785 (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote); 01786 (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote); 01787 (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote); 01788 01789 rc = checkPackageDeps(ts, he->p.str, 01790 requires, conflicts, dirnames, linktos, 01791 depName, tscolor, adding); 01792 01793 (void)rpmdsFree(linktos); 01794 linktos = NULL; 01795 (void)rpmdsFree(dirnames); 01796 dirnames = NULL; 01797 (void)rpmdsFree(conflicts); 01798 conflicts = NULL; 01799 (void)rpmdsFree(requires); 01800 requires = NULL; 01801 he->p.str = _free(he->p.str); 01802 01803 if (rc > ourrc) 01804 ourrc = rc; 01805 } 01806 mi = rpmmiFree(mi); 01807 01808 return ourrc; 01809 } 01810 01817 static int checkDependentPackages(rpmts ts, const char * depName) 01818 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01819 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/ 01820 { 01821 int rc = 0; 01822 01823 /* XXX rpmdb can be closed here, avoid error msg. */ 01824 if (rpmtsGetRdb(ts) != NULL) { 01825 rpmmi mi; 01826 mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0); 01827 rc = checkPackageSet(ts, depName, mi, 0); 01828 } 01829 return rc; 01830 } 01831 01838 static int checkDependentConflicts(rpmts ts, const char * depName) 01839 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 01840 /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/ 01841 { 01842 int rc = 0; 01843 01844 /* XXX rpmdb can be closed here, avoid error msg. */ 01845 if (rpmtsGetRdb(ts) != NULL) { 01846 rpmmi mi; 01847 mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0); 01848 rc = checkPackageSet(ts, depName, mi, 1); 01849 } 01850 01851 return rc; 01852 } 01853 01854 struct badDeps_s { 01855 /*@observer@*/ /*@owned@*/ /*@null@*/ 01856 const char * pname; 01857 /*@observer@*/ /*@dependent@*/ /*@null@*/ 01858 const char * qname; 01859 }; 01860 01861 #ifdef REFERENCE 01862 static struct badDeps_s { 01863 /*@observer@*/ /*@null@*/ const char * pname; 01864 /*@observer@*/ /*@null@*/ const char * qname; 01865 } badDeps[] = { 01866 { NULL, NULL } 01867 }; 01868 #else 01869 /*@unchecked@*/ 01870 static int badDepsInitialized = 0; 01871 01872 /*@unchecked@*/ /*@only@*/ /*@null@*/ 01873 static struct badDeps_s * badDeps = NULL; 01874 #endif 01875 01878 /*@-modobserver -observertrans @*/ 01879 static void freeBadDeps(void) 01880 /*@globals badDeps, badDepsInitialized @*/ 01881 /*@modifies badDeps, badDepsInitialized @*/ 01882 { 01883 if (badDeps) { 01884 struct badDeps_s * bdp; 01885 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) 01886 bdp->pname = _free(bdp->pname); 01887 badDeps = _free(badDeps); 01888 } 01889 badDepsInitialized = 0; 01890 } 01891 /*@=modobserver =observertrans @*/ 01892 01901 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q) 01902 /*@globals badDeps, badDepsInitialized, 01903 rpmGlobalMacroContext, h_errno, internalState @*/ 01904 /*@modifies badDeps, badDepsInitialized, 01905 rpmGlobalMacroContext, internalState @*/ 01906 { 01907 struct badDeps_s * bdp; 01908 01909 if (!badDepsInitialized) { 01910 char * s = rpmExpand("%{?_dependency_whiteout}", NULL); 01911 const char ** av = NULL; 01912 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA; 01913 int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS)) 01914 ? RPMLOG_WARNING : RPMLOG_DEBUG; 01915 int ac = 0; 01916 int i; 01917 01918 if (s != NULL && *s != '\0' 01919 && !(i = poptParseArgvString(s, &ac, (const char ***)&av)) 01920 && ac > 0 && av != NULL) 01921 { 01922 bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps)); 01923 for (i = 0; i < ac; i++, bdp++) { 01924 char * pname, * qname; 01925 01926 if (av[i] == NULL) 01927 break; 01928 pname = xstrdup(av[i]); 01929 if ((qname = strchr(pname, '>')) != NULL) 01930 *qname++ = '\0'; 01931 bdp->pname = pname; 01932 /*@-usereleased@*/ 01933 bdp->qname = qname; 01934 /*@=usereleased@*/ 01935 rpmlog(msglvl, 01936 _("ignore package name relation(s) [%d]\t%s -> %s\n"), 01937 i, bdp->pname, (bdp->qname ? bdp->qname : "???")); 01938 } 01939 bdp->pname = NULL; 01940 bdp->qname = NULL; 01941 } 01942 av = _free(av); 01943 s = _free(s); 01944 badDepsInitialized++; 01945 } 01946 01947 /*@-compdef@*/ 01948 if (badDeps != NULL) 01949 for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) { 01950 if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname)) 01951 return 1; 01952 } 01953 return 0; 01954 /*@=compdef@*/ 01955 } 01956 01962 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q) 01963 /*@globals internalState @*/ 01964 /*@uses tsi @*/ 01965 /*@modifies internalState @*/ 01966 { 01967 rpmte p; 01968 01969 while (tsi != NULL && (p = tsi->tsi_suc) != NULL) { 01970 tsi = tsi->tsi_next; 01971 if (rpmteTSI(p)->tsi_chain != NULL) 01972 continue; 01973 /*@-assignexpose -temptrans@*/ 01974 rpmteTSI(p)->tsi_chain = q; 01975 /*@=assignexpose =temptrans@*/ 01976 if (rpmteTSI(p)->tsi_next != NULL) 01977 markLoop(rpmteTSI(p)->tsi_next, p); 01978 } 01979 } 01980 01981 /* 01982 * Return display string a dependency, adding contextual flags marker. 01983 * @param f dependency flags 01984 * @return display string 01985 */ 01986 static inline /*@observer@*/ const char * identifyDepend(rpmuint32_t f) 01987 /*@*/ 01988 { 01989 f = _notpre(f); 01990 if (f & RPMSENSE_SCRIPT_PRE) 01991 return "Requires(pre):"; 01992 if (f & RPMSENSE_SCRIPT_POST) 01993 return "Requires(post):"; 01994 if (f & RPMSENSE_SCRIPT_PREUN) 01995 return "Requires(preun):"; 01996 if (f & RPMSENSE_SCRIPT_POSTUN) 01997 return "Requires(postun):"; 01998 if (f & RPMSENSE_SCRIPT_VERIFY) 01999 return "Requires(verify):"; 02000 if (f & RPMSENSE_MISSINGOK) 02001 return "Requires(hint):"; 02002 if (f & RPMSENSE_FIND_REQUIRES) 02003 return "Requires(auto):"; 02004 return "Requires:"; 02005 } 02006 02019 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */ 02020 static /*@owned@*/ /*@null@*/ const char * 02021 zapRelation(rpmte q, rpmte p, 02022 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl) 02023 /*@globals rpmGlobalMacroContext, h_errno, internalState @*/ 02024 /*@modifies q, p, *nzaps, rpmGlobalMacroContext, internalState @*/ 02025 { 02026 rpmds requires; 02027 tsortInfo tsi_prev; 02028 tsortInfo tsi; 02029 const char *dp = NULL; 02030 02031 for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next; 02032 tsi != NULL; 02033 /* XXX Note: the loop traverses "not found", break on "found". */ 02034 /*@-nullderef@*/ 02035 tsi_prev = tsi, tsi = tsi->tsi_next) 02036 /*@=nullderef@*/ 02037 { 02038 rpmuint32_t Flags; 02039 02040 /*@-abstractcompare@*/ 02041 if (tsi->tsi_suc != p) 02042 continue; 02043 /*@=abstractcompare@*/ 02044 02045 requires = rpmteDS((rpmteType(p) == TR_REMOVED ? q : p), tsi->tsi_tagn); 02046 if (requires == NULL) continue; /* XXX can't happen */ 02047 02048 (void) rpmdsSetIx(requires, tsi->tsi_reqx); 02049 02050 Flags = rpmdsFlags(requires); 02051 02052 dp = rpmdsNewDNEVR( identifyDepend(Flags), requires); 02053 02054 /* 02055 * Attempt to unravel a dependency loop by eliminating Requires's. 02056 */ 02057 if (zap) { 02058 rpmlog(msglvl, 02059 _("removing %s \"%s\" from tsort relations.\n"), 02060 (rpmteNEVRA(p) ? rpmteNEVRA(p) : "???"), dp); 02061 rpmteTSI(p)->tsi_count--; 02062 if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next; 02063 tsi->tsi_next = NULL; 02064 tsi->tsi_suc = NULL; 02065 tsi = _free(tsi); 02066 if (nzaps) 02067 (*nzaps)++; 02068 if (zap) 02069 zap--; 02070 } 02071 /* XXX Note: the loop traverses "not found", get out now! */ 02072 break; 02073 } 02074 return dp; 02075 } 02076 /*@=mustmod@*/ 02077 02086 /*@-mustmod@*/ 02087 static inline int addRelation(rpmts ts, 02088 /*@dependent@*/ rpmte p, 02089 unsigned char * selected, 02090 rpmds requires) 02091 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 02092 /*@modifies ts, p, *selected, rpmGlobalMacroContext, 02093 fileSystem, internalState @*/ 02094 { 02095 rpmtsi qi; rpmte q; 02096 tsortInfo tsi; 02097 nsType NSType = rpmdsNSType(requires); 02098 fnpyKey key; 02099 int teType = rpmteType(p); 02100 alKey pkgKey; 02101 int i = 0; 02102 rpmal al = (teType == TR_ADDED ? ts->addedPackages : ts->erasedPackages); 02103 02104 /* Avoid certain NS dependencies. */ 02105 switch (NSType) { 02106 case RPMNS_TYPE_RPMLIB: 02107 case RPMNS_TYPE_CONFIG: 02108 case RPMNS_TYPE_CPUINFO: 02109 case RPMNS_TYPE_GETCONF: 02110 case RPMNS_TYPE_UNAME: 02111 case RPMNS_TYPE_SONAME: 02112 case RPMNS_TYPE_ACCESS: 02113 case RPMNS_TYPE_USER: 02114 case RPMNS_TYPE_GROUP: 02115 case RPMNS_TYPE_MOUNTED: 02116 case RPMNS_TYPE_DISKSPACE: 02117 case RPMNS_TYPE_DIGEST: 02118 case RPMNS_TYPE_GNUPG: 02119 case RPMNS_TYPE_MACRO: 02120 case RPMNS_TYPE_ENVVAR: 02121 case RPMNS_TYPE_RUNNING: 02122 case RPMNS_TYPE_SANITY: 02123 case RPMNS_TYPE_VCHECK: 02124 case RPMNS_TYPE_SIGNATURE: 02125 return 0; 02126 /*@notreached@*/ break; 02127 default: 02128 break; 02129 } 02130 02131 pkgKey = RPMAL_NOMATCH; 02132 key = rpmalSatisfiesDepend(al, requires, &pkgKey); 02133 02134 /* Ordering depends only on added/erased package relations. */ 02135 if (pkgKey == RPMAL_NOMATCH) 02136 return 0; 02137 02138 /* XXX Set q to the added/removed package that was found. */ 02139 /* XXX pretend erasedPackages are just appended to addedPackages. */ 02140 if (teType == TR_REMOVED) 02141 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages); 02142 02143 for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) { 02144 if (pkgKey == rpmteAddedKey(q)) 02145 break; 02146 } 02147 qi = rpmtsiFree(qi); 02148 if (q == NULL || i >= ts->orderCount) 02149 return 0; 02150 02151 /* Avoid certain dependency relations. */ 02152 if (ignoreDep(ts, p, q)) 02153 return 0; 02154 02155 /* Avoid redundant relations. */ 02156 if (selected[i] != 0) 02157 return 0; 02158 selected[i] = 1; 02159 02160 /* Erasures are reversed installs. */ 02161 if (teType == TR_REMOVED) { 02162 rpmte r = p; 02163 p = q; 02164 q = r; 02165 } 02166 02167 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */ 02168 rpmteTSI(p)->tsi_count++; /* bump p predecessor count */ 02169 02170 if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */ 02171 (void) rpmteSetDepth(p, (rpmteDepth(q) + 1)); 02172 if (rpmteDepth(p) > ts->maxDepth) 02173 ts->maxDepth = rpmteDepth(p); 02174 02175 tsi = xcalloc(1, sizeof(*tsi)); 02176 tsi->tsi_suc = p; 02177 02178 tsi->tsi_tagn = rpmdsTagN(requires); 02179 tsi->tsi_reqx = rpmdsIx(requires); 02180 02181 tsi->tsi_next = rpmteTSI(q)->tsi_next; 02182 rpmteTSI(q)->tsi_next = tsi; 02183 rpmteTSI(q)->tsi_qcnt++; /* bump q successor count */ 02184 02185 return 0; 02186 } 02187 /*@=mustmod@*/ 02188 02195 static int orderListIndexCmp(const void * one, const void * two) /*@*/ 02196 { 02197 /*@-castexpose@*/ 02198 long a = (long) ((const orderListIndex)one)->pkgKey; 02199 long b = (long) ((const orderListIndex)two)->pkgKey; 02200 /*@=castexpose@*/ 02201 return (a - b); 02202 } 02203 02211 /*@-mustmod@*/ 02212 static void addQ(/*@dependent@*/ rpmte p, 02213 /*@in@*/ /*@out@*/ rpmte * qp, 02214 /*@in@*/ /*@out@*/ rpmte * rp, 02215 rpmuint32_t prefcolor) 02216 /*@modifies p, *qp, *rp @*/ 02217 { 02218 rpmte q, qprev; 02219 02220 /* Mark the package as queued. */ 02221 rpmteTSI(p)->tsi_queued = 1; 02222 02223 if ((*rp) == NULL) { /* 1st element */ 02224 /*@-dependenttrans@*/ /* FIX: double indirection */ 02225 (*rp) = (*qp) = p; 02226 /*@=dependenttrans@*/ 02227 return; 02228 } 02229 02230 /* Find location in queue using metric tsi_qcnt. */ 02231 for (qprev = NULL, q = (*qp); 02232 q != NULL; 02233 qprev = q, q = rpmteTSI(q)->tsi_suc) 02234 { 02235 /* XXX Insure preferred color first. */ 02236 if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q)) 02237 continue; 02238 02239 /* XXX Insure removed after added. */ 02240 if (rpmteType(p) == TR_REMOVED && rpmteType(p) != rpmteType(q)) 02241 continue; 02242 if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt) 02243 break; 02244 } 02245 02246 if (qprev == NULL) { /* insert at beginning of list */ 02247 rpmteTSI(p)->tsi_suc = q; 02248 /*@-dependenttrans@*/ 02249 (*qp) = p; /* new head */ 02250 /*@=dependenttrans@*/ 02251 } else if (q == NULL) { /* insert at end of list */ 02252 rpmteTSI(qprev)->tsi_suc = p; 02253 /*@-dependenttrans@*/ 02254 (*rp) = p; /* new tail */ 02255 /*@=dependenttrans@*/ 02256 } else { /* insert between qprev and q */ 02257 rpmteTSI(p)->tsi_suc = q; 02258 rpmteTSI(qprev)->tsi_suc = p; 02259 } 02260 } 02261 /*@=mustmod@*/ 02262 02263 /*@unchecked@*/ 02264 #ifdef NOTYET 02265 static rpmuint32_t _autobits = _notpre(_ALL_REQUIRES_MASK); 02266 #else 02267 static rpmuint32_t _autobits = 0xffffffff; 02268 #endif 02269 #define isAuto(_x) ((_x) & _autobits) 02270 02271 /*@unchecked@*/ 02272 static int slashDepth = 100; /* #slashes pemitted in parentdir deps. */ 02273 02274 static int countSlashes(const char * dn) 02275 /*@*/ 02276 { 02277 int nslashes = 0; 02278 int c; 02279 02280 while ((c = (int)*dn++) != 0) { 02281 switch (c) { 02282 default: continue; /*@notreached@*/ /*@switchbreak@*/break; 02283 case '/': nslashes++; /*@switchbreak@*/break; 02284 } 02285 } 02286 02287 return nslashes; 02288 } 02289 02290 int rpmtsOrder(rpmts ts) 02291 { 02292 rpmds requires; 02293 rpmuint32_t Flags; 02294 int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA; 02295 rpmuint32_t prefcolor = rpmtsPrefColor(ts); 02296 rpmtsi pi; rpmte p; 02297 rpmtsi qi; rpmte q; 02298 rpmtsi ri; rpmte r; 02299 tsortInfo tsi; 02300 tsortInfo tsi_next; 02301 alKey * ordering; 02302 int orderingCount = 0; 02303 unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1)); 02304 int loopcheck; 02305 rpmte * newOrder; 02306 int newOrderCount = 0; 02307 orderListIndex orderList; 02308 int numOrderList; 02309 int npeer = 128; /* XXX more than deep enough for now. */ 02310 int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer))); 02311 int nrescans = 10; 02312 int _printed = 0; 02313 char deptypechar; 02314 size_t tsbytes; 02315 int oType = 0; 02316 int treex; 02317 int depth; 02318 int breadth; 02319 int qlen; 02320 int i, j; 02321 02322 #ifdef DYING 02323 rpmalMakeIndex(ts->addedPackages); 02324 #endif 02325 02326 /* Create erased package index. */ 02327 pi = rpmtsiInit(ts); 02328 while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { 02329 alKey pkgKey; 02330 fnpyKey key; 02331 rpmuint32_t tscolor = rpmtsColor(ts); 02332 pkgKey = RPMAL_NOMATCH; 02333 /*@-abstract@*/ 02334 key = (fnpyKey) p; 02335 /*@=abstract@*/ 02336 pkgKey = rpmalAdd(&ts->erasedPackages, pkgKey, key, 02337 rpmteDS(p, RPMTAG_PROVIDENAME), 02338 rpmteFI(p, RPMTAG_BASENAMES), tscolor); 02339 /* XXX pretend erasedPackages are just appended to addedPackages. */ 02340 pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages); 02341 (void) rpmteSetAddedKey(p, pkgKey); 02342 } 02343 pi = rpmtsiFree(pi); 02344 rpmalMakeIndex(ts->erasedPackages); 02345 02346 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0); 02347 02348 /* T1. Initialize. */ 02349 if (oType == 0) 02350 numOrderList = ts->orderCount; 02351 else { 02352 numOrderList = 0; 02353 if (oType & TR_ADDED) 02354 numOrderList += ts->numAddedPackages; 02355 if (oType & TR_REMOVED) 02356 numOrderList += ts->numRemovedPackages; 02357 } 02358 ordering = alloca(sizeof(*ordering) * (numOrderList + 1)); 02359 loopcheck = numOrderList; 02360 tsbytes = 0; 02361 02362 pi = rpmtsiInit(ts); 02363 while ((p = rpmtsiNext(pi, oType)) != NULL) 02364 rpmteNewTSI(p); 02365 pi = rpmtsiFree(pi); 02366 02367 /* Record all relations. */ 02368 rpmlog(RPMLOG_DEBUG, D_("========== recording tsort relations\n")); 02369 pi = rpmtsiInit(ts); 02370 while ((p = rpmtsiNext(pi, oType)) != NULL) { 02371 02372 memset(selected, 0, sizeof(*selected) * ts->orderCount); 02373 02374 if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) != NULL) { 02375 02376 /* Avoid narcisstic relations. */ 02377 selected[rpmtsiOc(pi)] = 1; 02378 02379 /* T2. Next "q <- p" relation. */ 02380 02381 /* First, do pre-requisites. */ 02382 requires = rpmdsInit(requires); 02383 if (requires != NULL) 02384 while (rpmdsNext(requires) >= 0) { 02385 02386 Flags = rpmdsFlags(requires); 02387 if (!isAuto(Flags)) 02388 /*@innercontinue@*/ continue; 02389 02390 switch (rpmteType(p)) { 02391 case TR_REMOVED: 02392 /* Skip if not %preun/%postun requires. */ 02393 if (!isErasePreReq(Flags)) 02394 /*@innercontinue@*/ continue; 02395 /*@switchbreak@*/ break; 02396 case TR_ADDED: 02397 /* Skip if not %pre/%post requires. */ 02398 if (!isInstallPreReq(Flags)) 02399 /*@innercontinue@*/ continue; 02400 /*@switchbreak@*/ break; 02401 } 02402 02403 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */ 02404 (void) addRelation(ts, p, selected, requires); 02405 02406 } 02407 02408 /* Then do co-requisites. */ 02409 requires = rpmdsInit(requires); 02410 if (requires != NULL) 02411 while (rpmdsNext(requires) >= 0) { 02412 02413 Flags = rpmdsFlags(requires); 02414 if (!isAuto(Flags)) 02415 /*@innercontinue@*/ continue; 02416 02417 switch (rpmteType(p)) { 02418 case TR_REMOVED: 02419 /* Skip if %preun/%postun requires. */ 02420 if (isErasePreReq(Flags)) 02421 /*@innercontinue@*/ continue; 02422 /*@switchbreak@*/ break; 02423 case TR_ADDED: 02424 /* Skip if %pre/%post requires. */ 02425 if (isInstallPreReq(Flags)) 02426 /*@innercontinue@*/ continue; 02427 /*@switchbreak@*/ break; 02428 } 02429 02430 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */ 02431 (void) addRelation(ts, p, selected, requires); 02432 02433 } 02434 } 02435 02436 /* Ensure that erasures follow installs during upgrades. */ 02437 if (rpmteType(p) == TR_REMOVED && p->flink.Pkgid && p->flink.Pkgid[0]) { 02438 02439 qi = rpmtsiInit(ts); 02440 while ((q = rpmtsiNext(qi, TR_ADDED)) != NULL) { 02441 if (strcmp(q->pkgid, p->flink.Pkgid[0])) 02442 /*@innercontinue@*/ continue; 02443 requires = rpmdsFromPRCO(q->PRCO, RPMTAG_NAME); 02444 if (requires != NULL) { 02445 /* XXX disable erased arrow reversal. */ 02446 p->type = TR_ADDED; 02447 (void) addRelation(ts, p, selected, requires); 02448 p->type = TR_REMOVED; 02449 } 02450 } 02451 qi = rpmtsiFree(qi); 02452 } 02453 02454 { 02455 02456 /* Order by requiring parent directories pre-requsites. */ 02457 requires = rpmdsInit(rpmteDS(p, RPMTAG_DIRNAMES)); 02458 if (requires != NULL) 02459 while (rpmdsNext(requires) >= 0) { 02460 02461 /* XXX Attempt to avoid loops by filtering out deep paths. */ 02462 if (countSlashes(rpmdsN(requires)) > slashDepth) 02463 /*@innercontinue@*/ continue; 02464 02465 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */ 02466 (void) addRelation(ts, p, selected, requires); 02467 02468 } 02469 02470 /* Order by requiring no dangling symlinks. */ 02471 requires = rpmdsInit(rpmteDS(p, RPMTAG_FILELINKTOS)); 02472 if (requires != NULL) 02473 while (rpmdsNext(requires) >= 0) { 02474 02475 /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */ 02476 (void) addRelation(ts, p, selected, requires); 02477 02478 } 02479 } 02480 02481 } 02482 pi = rpmtsiFree(pi); 02483 02484 /* Save predecessor count and mark tree roots. */ 02485 treex = 0; 02486 pi = rpmtsiInit(ts); 02487 while ((p = rpmtsiNext(pi, oType)) != NULL) { 02488 int npreds; 02489 02490 npreds = rpmteTSI(p)->tsi_count; 02491 02492 (void) rpmteSetNpreds(p, npreds); 02493 (void) rpmteSetDepth(p, 0); 02494 02495 if (npreds == 0) { 02496 treex++; 02497 (void) rpmteSetTree(p, treex); 02498 (void) rpmteSetBreadth(p, treex); 02499 } else 02500 (void) rpmteSetTree(p, -1); 02501 #ifdef UNNECESSARY 02502 (void) rpmteSetParent(p, NULL); 02503 #endif 02504 02505 } 02506 pi = rpmtsiFree(pi); 02507 ts->ntrees = treex; 02508 02509 /* T4. Scan for zeroes. */ 02510 rpmlog(RPMLOG_DEBUG, D_("========== tsorting packages (order, #predecessors, #succesors, tree, Ldepth, Rbreadth)\n")); 02511 02512 rescan: 02513 if (pi != NULL) pi = rpmtsiFree(pi); 02514 q = r = NULL; 02515 qlen = 0; 02516 pi = rpmtsiInit(ts); 02517 while ((p = rpmtsiNext(pi, oType)) != NULL) { 02518 02519 /* Prefer packages in chainsaw or anaconda presentation order. */ 02520 if (anaconda) 02521 rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi)); 02522 02523 if (rpmteTSI(p)->tsi_count != 0) 02524 continue; 02525 rpmteTSI(p)->tsi_suc = NULL; 02526 addQ(p, &q, &r, prefcolor); 02527 qlen++; 02528 } 02529 pi = rpmtsiFree(pi); 02530 02531 /* T5. Output front of queue (T7. Remove from queue.) */ 02532 for (; q != NULL; q = rpmteTSI(q)->tsi_suc) { 02533 02534 /* Mark the package as unqueued. */ 02535 rpmteTSI(q)->tsi_queued = 0; 02536 02537 if (oType != 0) 02538 switch (rpmteType(q)) { 02539 case TR_ADDED: 02540 if (!(oType & TR_ADDED)) 02541 continue; 02542 /*@switchbreak@*/ break; 02543 case TR_REMOVED: 02544 if (!(oType & TR_REMOVED)) 02545 continue; 02546 /*@switchbreak@*/ break; 02547 default: 02548 continue; 02549 /*@notreached@*/ /*@switchbreak@*/ break; 02550 } 02551 deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+'); 02552 02553 treex = rpmteTree(q); 02554 depth = rpmteDepth(q); 02555 breadth = ((depth < npeer) ? peer[depth]++ : 0); 02556 (void) rpmteSetBreadth(q, breadth); 02557 02558 rpmlog(RPMLOG_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n", 02559 orderingCount, rpmteNpreds(q), 02560 rpmteTSI(q)->tsi_qcnt, 02561 treex, depth, breadth, 02562 (2 * depth), "", 02563 deptypechar, 02564 (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???")); 02565 02566 (void) rpmteSetDegree(q, 0); 02567 tsbytes += rpmtePkgFileSize(q); 02568 02569 ordering[orderingCount] = rpmteAddedKey(q); 02570 orderingCount++; 02571 qlen--; 02572 loopcheck--; 02573 02574 /* T6. Erase relations. */ 02575 tsi_next = rpmteTSI(q)->tsi_next; 02576 rpmteTSI(q)->tsi_next = NULL; 02577 while ((tsi = tsi_next) != NULL) { 02578 tsi_next = tsi->tsi_next; 02579 tsi->tsi_next = NULL; 02580 p = tsi->tsi_suc; 02581 if (p && (--rpmteTSI(p)->tsi_count) <= 0) { 02582 02583 (void) rpmteSetTree(p, treex); 02584 (void) rpmteSetDepth(p, depth+1); 02585 (void) rpmteSetParent(p, q); 02586 (void) rpmteSetDegree(q, rpmteDegree(q)+1); 02587 02588 /* XXX TODO: add control bit. */ 02589 rpmteTSI(p)->tsi_suc = NULL; 02590 /*@-nullstate@*/ /* XXX FIX: rpmteTSI(q)->tsi_suc can be NULL. */ 02591 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor); 02592 /*@=nullstate@*/ 02593 qlen++; 02594 } 02595 tsi = _free(tsi); 02596 } 02597 if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) { 02598 _printed++; 02599 (void) rpmtsUnorderedSuccessors(ts, orderingCount); 02600 rpmlog(RPMLOG_DEBUG, 02601 D_("========== successors only (%d bytes)\n"), (int)tsbytes); 02602 02603 /* Relink the queue in presentation order. */ 02604 tsi = rpmteTSI(q); 02605 pi = rpmtsiInit(ts); 02606 while ((p = rpmtsiNext(pi, oType)) != NULL) { 02607 /* Is this element in the queue? */ 02608 if (rpmteTSI(p)->tsi_queued == 0) 02609 /*@innercontinue@*/ continue; 02610 tsi->tsi_suc = p; 02611 tsi = rpmteTSI(p); 02612 } 02613 pi = rpmtsiFree(pi); 02614 tsi->tsi_suc = NULL; 02615 } 02616 } 02617 02618 /* T8. End of process. Check for loops. */ 02619 if (loopcheck != 0) { 02620 int nzaps; 02621 02622 /* T9. Initialize predecessor chain. */ 02623 nzaps = 0; 02624 qi = rpmtsiInit(ts); 02625 while ((q = rpmtsiNext(qi, oType)) != NULL) { 02626 rpmteTSI(q)->tsi_chain = NULL; 02627 rpmteTSI(q)->tsi_queued = 0; 02628 /* Mark packages already sorted. */ 02629 if (rpmteTSI(q)->tsi_count == 0) 02630 rpmteTSI(q)->tsi_count = -1; 02631 } 02632 qi = rpmtsiFree(qi); 02633 02634 /* T10. Mark all packages with their predecessors. */ 02635 qi = rpmtsiInit(ts); 02636 while ((q = rpmtsiNext(qi, oType)) != NULL) { 02637 if ((tsi = rpmteTSI(q)->tsi_next) == NULL) 02638 continue; 02639 rpmteTSI(q)->tsi_next = NULL; 02640 markLoop(tsi, q); 02641 rpmteTSI(q)->tsi_next = tsi; 02642 } 02643 qi = rpmtsiFree(qi); 02644 02645 /* T11. Print all dependency loops. */ 02646 ri = rpmtsiInit(ts); 02647 while ((r = rpmtsiNext(ri, oType)) != NULL) 02648 { 02649 int printed; 02650 02651 printed = 0; 02652 02653 /* T12. Mark predecessor chain, looking for start of loop. */ 02654 for (q = rpmteTSI(r)->tsi_chain; q != NULL; 02655 q = rpmteTSI(q)->tsi_chain) 02656 { 02657 if (rpmteTSI(q)->tsi_queued) 02658 /*@innerbreak@*/ break; 02659 rpmteTSI(q)->tsi_queued = 1; 02660 } 02661 02662 /* T13. Print predecessor chain from start of loop. */ 02663 while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) { 02664 #if 0 02665 const char * nevra; 02666 #endif 02667 const char * dp; 02668 rpmlogLvl msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS)) 02669 ? RPMLOG_WARNING : RPMLOG_ERR; 02670 #if defined(RPM_VENDOR_MANDRIVA) /* loop-detection-optional-loglevel */ 02671 // Report loops as debug-level message by default (7 = RPMLOG_DEBUG), overridable 02672 msglvl = rpmExpandNumeric("%{?_loop_detection_loglevel}%{?!_loop_detection_loglevel:7}"); 02673 #endif 02674 02675 /* Unchain predecessor loop. */ 02676 rpmteTSI(p)->tsi_chain = NULL; 02677 02678 if (!printed) { 02679 rpmlog(msglvl, _("LOOP:\n")); 02680 printed = 1; 02681 } 02682 02683 /* Find (and destroy if co-requisite) "q <- p" relation. */ 02684 dp = zapRelation(q, p, 1, &nzaps, msglvl); 02685 02686 #if 0 02687 /* Print next member of loop. */ 02688 nevra = rpmteNEVRA(p); 02689 rpmlog(msglvl, " %-40s %s\n", (nevra ? nevra : "???"), 02690 (dp ? dp : "not found!?!")); 02691 #endif 02692 02693 dp = _free(dp); 02694 } 02695 02696 /* Walk (and erase) linear part of predecessor chain as well. */ 02697 for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL; 02698 p = q, q = rpmteTSI(q)->tsi_chain) 02699 { 02700 /* Unchain linear part of predecessor loop. */ 02701 rpmteTSI(p)->tsi_chain = NULL; 02702 rpmteTSI(p)->tsi_queued = 0; 02703 } 02704 } 02705 ri = rpmtsiFree(ri); 02706 02707 /* If a relation was eliminated, then continue sorting. */ 02708 /* XXX TODO: add control bit. */ 02709 if (nzaps && nrescans-- > 0) { 02710 rpmlog(RPMLOG_DEBUG, D_("========== continuing tsort ...\n")); 02711 goto rescan; 02712 } 02713 02714 /* Return no. of packages that could not be ordered. */ 02715 rpmlog(RPMLOG_ERR, _("rpmtsOrder failed, %d elements remain\n"), 02716 loopcheck); 02717 02718 #ifdef NOTYET 02719 /* Do autorollback goal since we could not sort this transaction properly. */ 02720 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL); 02721 #endif 02722 02723 return loopcheck; 02724 } 02725 02726 /* Clean up tsort remnants (if any). */ 02727 pi = rpmtsiInit(ts); 02728 while ((p = rpmtsiNext(pi, 0)) != NULL) 02729 rpmteFreeTSI(p); 02730 pi = rpmtsiFree(pi); 02731 02732 /* 02733 * The order ends up as installed packages followed by removed packages. 02734 */ 02735 orderList = xcalloc(numOrderList, sizeof(*orderList)); 02736 j = 0; 02737 pi = rpmtsiInit(ts); 02738 while ((p = rpmtsiNext(pi, oType)) != NULL) { 02739 /* Prepare added/erased package ordering permutation. */ 02740 orderList[j].pkgKey = rpmteAddedKey(p); 02741 orderList[j].orIndex = rpmtsiOc(pi); 02742 j++; 02743 } 02744 pi = rpmtsiFree(pi); 02745 02746 qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp); 02747 02748 /*@-type@*/ 02749 newOrder = xcalloc(ts->orderCount, sizeof(*newOrder)); 02750 /*@=type@*/ 02751 for (i = 0, newOrderCount = 0; i < orderingCount; i++) 02752 { 02753 struct orderListIndex_s key; 02754 orderListIndex needle; 02755 02756 key.pkgKey = ordering[i]; 02757 needle = bsearch(&key, orderList, numOrderList, 02758 sizeof(key), orderListIndexCmp); 02759 if (needle == NULL) /* XXX can't happen */ 02760 continue; 02761 02762 j = needle->orIndex; 02763 if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH) 02764 continue; 02765 02766 newOrder[newOrderCount++] = q; 02767 ts->order[j] = NULL; 02768 } 02769 02770 assert(newOrderCount == ts->orderCount); 02771 02772 /*@+voidabstract@*/ 02773 ts->order = _free(ts->order); 02774 /*@=voidabstract@*/ 02775 ts->order = newOrder; 02776 ts->orderAlloced = ts->orderCount; 02777 orderList = _free(orderList); 02778 02779 #ifdef DYING /* XXX now done at the CLI level just before rpmtsRun(). */ 02780 rpmtsClean(ts); 02781 #endif 02782 freeBadDeps(); 02783 02784 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0); 02785 02786 return 0; 02787 } 02788 02789 int rpmtsCheck(rpmts ts) 02790 { 02791 const char * depName = NULL; 02792 rpmdepFlags depFlags = rpmtsDFlags(ts); 02793 rpmuint32_t tscolor = rpmtsColor(ts); 02794 rpmmi mi = NULL; 02795 rpmtsi pi = NULL; rpmte p; 02796 int closeatexit = 0; 02797 int xx; 02798 int terminate = 2; /* XXX terminate if rc >= terminate */ 02799 int rc = 0; 02800 int ourrc = 0; 02801 02802 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0); 02803 02804 /* Do lazy, readonly, open of rpm database. */ 02805 if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) { 02806 rc = (rpmtsOpenDB(ts, rpmtsDBMode(ts)) ? 2 : 0); 02807 closeatexit = (rc == 0); 02808 } 02809 if (rc && (ourrc = rc) >= terminate) 02810 goto exit; 02811 02812 ts->probs = rpmpsFree(ts->probs); 02813 02814 rpmalMakeIndex(ts->addedPackages); 02815 02816 /* 02817 * Look at all of the added packages and make sure their dependencies 02818 * are satisfied. 02819 */ 02820 pi = rpmtsiInit(ts); 02821 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_ADDED)) != NULL) { 02822 rpmds provides, requires, conflicts, dirnames, linktos; 02823 rpmfi fi; 02824 02825 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */ 02826 rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n", 02827 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); 02828 /*@=nullpass@*/ 02829 requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES) 02830 ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL); 02831 conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS) 02832 ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL); 02833 /* XXX srpm's don't have directory paths. */ 02834 if (p->isSource) { 02835 dirnames = NULL; 02836 linktos = NULL; 02837 } else { 02838 dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS) 02839 ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL); 02840 linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS) 02841 ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL); 02842 } 02843 02844 rc = checkPackageDeps(ts, rpmteNEVRA(p), 02845 requires, conflicts, dirnames, linktos, 02846 NULL, tscolor, 1); 02847 if (rc && (ourrc = rc) >= terminate) 02848 break; 02849 02850 provides = rpmteDS(p, RPMTAG_PROVIDENAME); 02851 provides = rpmdsInit(provides); 02852 if (provides != NULL) 02853 while (ourrc < terminate && rpmdsNext(provides) >= 0) { 02854 depName = _free(depName); 02855 depName = xstrdup(rpmdsN(provides)); 02856 02857 #ifdef NOTYET 02858 if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) { 02859 const char * EVR = rpmdsEVR(provides); 02860 if (rpmdsNegateRC(provides, 0)) 02861 EVR = NULL; 02862 if (envPut(depName, EVR)); 02863 rc = 2; 02864 } else 02865 #endif 02866 02867 /* Adding: check provides key against conflicts matches. */ 02868 if (checkDependentConflicts(ts, depName)) 02869 rc = 1; 02870 } 02871 if (rc && (ourrc = rc) >= terminate) 02872 break; 02873 02874 fi = rpmteFI(p, RPMTAG_BASENAMES); 02875 fi = rpmfiInit(fi, 0); 02876 while (ourrc < terminate && rpmfiNext(fi) >= 0) { 02877 depName = _free(depName); 02878 depName = xstrdup(rpmfiFN(fi)); 02879 /* Adding: check filename against conflicts matches. */ 02880 if (checkDependentConflicts(ts, depName)) 02881 rc = 1; 02882 } 02883 if (rc && (ourrc = rc) >= terminate) 02884 break; 02885 } 02886 pi = rpmtsiFree(pi); 02887 if (rc && (ourrc = rc) >= terminate) 02888 goto exit; 02889 02890 /* 02891 * Look at the removed packages and make sure they aren't critical. 02892 */ 02893 pi = rpmtsiInit(ts); 02894 while (ourrc < terminate && (p = rpmtsiNext(pi, TR_REMOVED)) != NULL) { 02895 rpmds provides; 02896 rpmfi fi; 02897 02898 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */ 02899 rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n", 02900 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); 02901 /*@=nullpass@*/ 02902 02903 provides = rpmteDS(p, RPMTAG_PROVIDENAME); 02904 provides = rpmdsInit(provides); 02905 if (provides != NULL) 02906 while (ourrc < terminate && rpmdsNext(provides) >= 0) { 02907 depName = _free(depName); 02908 depName = xstrdup(rpmdsN(provides)); 02909 02910 /* Erasing: check provides against requiredby matches. */ 02911 if (checkDependentPackages(ts, depName)) 02912 rc = 1; 02913 } 02914 if (rc && (ourrc = rc) >= terminate) 02915 break; 02916 02917 fi = rpmteFI(p, RPMTAG_BASENAMES); 02918 fi = rpmfiInit(fi, 0); 02919 while (ourrc < terminate && rpmfiNext(fi) >= 0) { 02920 depName = _free(depName); 02921 depName = xstrdup(rpmfiFN(fi)); 02922 /* Erasing: check filename against requiredby matches. */ 02923 if (checkDependentPackages(ts, depName)) 02924 rc = 1; 02925 } 02926 if (rc && (ourrc = rc) >= terminate) 02927 break; 02928 } 02929 pi = rpmtsiFree(pi); 02930 if (rc && (ourrc = rc) >= terminate) 02931 goto exit; 02932 02933 /* 02934 * Make sure transaction dependencies are satisfied. 02935 */ 02936 { const char * tsNEVRA = "transaction dependencies"; 02937 rpmds R = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_REQUIRENAME); 02938 rpmds C = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_CONFLICTNAME); 02939 rpmds D = NULL; 02940 rpmds L = NULL; 02941 const char * dep = NULL; 02942 int adding = 2; 02943 tscolor = 0; /* XXX no coloring for transaction dependencies. */ 02944 rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding); 02945 } 02946 if (rc && (ourrc = rc) >= terminate) 02947 goto exit; 02948 02949 exit: 02950 mi = rpmmiFree(mi); 02951 pi = rpmtsiFree(pi); 02952 depName = _free(depName); 02953 02954 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0); 02955 02956 if (closeatexit) 02957 xx = rpmtsCloseDB(ts); 02958 #if defined(CACHE_DEPENDENCY_RESULT) 02959 else if (_cacheDependsRC) 02960 xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS); 02961 #endif 02962 02963 #ifdef NOTYET 02964 /* On failed dependencies, perform the autorollback goal (if any). */ 02965 { rpmps ps = rpmtsProblems(ts); 02966 if (rc || rpmpsNumProblems(ps) > 0) 02967 (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL); 02968 ps = rpmpsFree(ps); 02969 } 02970 #endif 02971 02972 return ourrc; 02973 }