rpm 5.2.1

- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

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 }