rpm  5.2.1
lib/depends.c
Go to the documentation of this file.
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 }