rpm 5.3.12
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 <rpmbf.h>
00011 #include <rpmmacro.h>           /* XXX rpmExpand("%{_dependency_whiteout}" */
00012 #include <envvar.h>
00013 #include <ugid.h>               /* XXX user()/group() probes */
00014 
00015 #include <rpmtag.h>
00016 #define _RPMDB_INTERNAL         /* XXX response cache needs dbiOpen et al. */
00017 #include <rpmdb.h>
00018 
00019 #define _RPMEVR_INTERNAL
00020 #include <rpmds.h>
00021 #include <rpmfi.h>
00022 
00023 #define _RPMTE_INTERNAL
00024 #include <rpmte.h>
00025 #define _RPMTS_INTERNAL
00026 #include <rpmcli.h>             /* XXX rpmcliPackagesTotal */
00027 
00028 #include "debug.h"
00029 
00030 /*@access tsortInfo @*/
00031 /*@access rpmte @*/             /* XXX for install <-> erase associate. */
00032 /*@access rpmts @*/
00033 /*@access rpmDiskSpaceInfo @*/
00034 
00035 #define CACHE_DEPENDENCY_RESULT 1
00036 #if defined(CACHE_DEPENDENCY_RESULT)
00037 /*@unchecked@*/
00038 int _cacheDependsRC = CACHE_DEPENDENCY_RESULT;
00039 #endif
00040 
00041 /*@observer@*/ /*@unchecked@*/
00042 const char *rpmNAME = PACKAGE;
00043 
00044 /*@observer@*/ /*@unchecked@*/
00045 const char *rpmEVR = VERSION;
00046 
00047 /*@unchecked@*/
00048 int rpmFLAGS = RPMSENSE_EQUAL;
00049 
00056 static int uintcmp(const void * a, const void * b)
00057         /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
00058 {
00059     const uint32_t * aptr = a;
00060     const uint32_t * bptr = b;
00061     int rc = (*aptr - *bptr);
00062     return rc;
00063 }
00064 
00074 static int removePackage(rpmts ts, Header h, uint32_t hdrNum,
00075                 /*@null@*/ int * indexp,
00076                 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
00077         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00078         /*@modifies ts, h, *indexp, rpmGlobalMacroContext, fileSystem, internalState @*/
00079 {
00080     rpmte p;
00081     int xx;
00082 
00083     /* Filter out duplicate erasures. */
00084     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00085         uint32_t * needle = NULL;
00086         needle = bsearch(&hdrNum, ts->removedPackages, ts->numRemovedPackages,
00087                         sizeof(*ts->removedPackages), uintcmp);
00088         if (needle != NULL) {
00089             /* XXX lastx should be per-call, not per-ts. */
00090             if (indexp != NULL)
00091                 *indexp = needle - ts->removedPackages;
00092             return 0;
00093         }
00094     }
00095 
00096     if (ts->rbf == NULL) {
00097         static size_t nRemoves = 8192;  /* XXX population estimate */
00098         static double e = 1.0e-4;
00099         size_t m = 0;
00100         size_t k = 0;
00101         rpmbfParams(nRemoves, e, &m, &k);
00102         ts->rbf = rpmbfNew(m, k, 0);
00103     }
00104 
00105     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00106         ts->allocedRemovedPackages += ts->delta;
00107         ts->removedPackages = xrealloc(ts->removedPackages,
00108                 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
00109     }
00110 
00111 assert(ts->removedPackages != NULL);    /* XXX can't happen. */
00112     xx = rpmbfAdd(ts->rbf, &hdrNum, sizeof(hdrNum));
00113 assert(xx == 0);
00114     ts->removedPackages[ts->numRemovedPackages] = hdrNum;
00115     ts->numRemovedPackages++;
00116     if (ts->numRemovedPackages > 1)
00117         qsort(ts->removedPackages, ts->numRemovedPackages,
00118                         sizeof(*ts->removedPackages), uintcmp);
00119 
00120     if (ts->orderCount >= ts->orderAlloced) {
00121         ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
00122 /*@-type +voidabstract @*/
00123         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00124 /*@=type =voidabstract @*/
00125     }
00126 
00127     p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, hdrNum, depends);
00128     ts->order[ts->orderCount] = p;
00129     ts->numErasedFiles += rpmfiFC(rpmteFI(p, RPMTAG_BASENAMES));
00130     if (indexp != NULL)
00131         *indexp = ts->orderCount;
00132     ts->orderCount++;
00133 
00134 /*@-nullstate@*/        /* XXX FIX: ts->order[] can be NULL. */
00135    return 0;
00136 /*@=nullstate@*/
00137 }
00138 
00145 static int rpmHeadersIdentical(Header first, Header second)
00146         /*@globals internalState @*/
00147         /*@modifies internalState @*/
00148 {
00149     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00150     const char * one, * two;
00151     int rc = 0;
00152     int xx;
00153 
00154     he->tag = RPMTAG_HDRID;
00155     xx = headerGet(first, he, 0);
00156     one = he->p.str;
00157     he->tag = RPMTAG_HDRID;
00158     xx = headerGet(second, he, 0);
00159     two = he->p.str;
00160 
00161     if (one && two)
00162         rc = ((strcmp(one, two) == 0) ? 1 : 0);
00163     else if (one && !two)
00164         rc = 0;
00165     else if (!one && two)
00166         rc = 0;
00167     else {
00168         /* XXX Headers w/o digests case devolves to NEVR comparison. */
00169         rpmds A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00170         rpmds B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00171         rc = rpmdsCompare(A, B);
00172         (void)rpmdsFree(A);
00173         A = NULL;
00174         (void)rpmdsFree(B);
00175         B = NULL;
00176     }
00177     one = _free(one);
00178     two = _free(two);
00179     return rc;
00180 }
00181 
00182 /*@unchecked@*/
00183 static rpmTag _upgrade_tag;
00184 /*@unchecked@*/
00185 static rpmTag _debuginfo_tag;
00186 /*@unchecked@*/
00187 static rpmTag _obsolete_tag;
00188 
00197 static int rpmtsAddUpgrades(rpmts ts, rpmte p, rpmuint32_t hcolor, Header h)
00198         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00199         /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
00200 {
00201     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00202     rpmuint32_t tscolor = rpmtsColor(ts);
00203     alKey pkgKey = rpmteAddedKey(p);
00204     rpmuint32_t ohcolor;
00205     rpmmi mi;
00206     Header oh;
00207     int xx;
00208 
00209     if (_upgrade_tag == 0) {
00210         const char * t = rpmExpand("%{?_upgrade_tag}", NULL);
00211 /*@-mods@*/
00212         _upgrade_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
00213 /*@=mods@*/
00214         t = _free(t);
00215     }
00216 
00217     mi = rpmtsInitIterator(ts, _upgrade_tag, rpmteN(p), 0);
00218     while((oh = rpmmiNext(mi)) != NULL) {
00219         int lastx;
00220         rpmte q;
00221 
00222         /* Ignore colored packages not in our rainbow. */
00223         ohcolor = hGetColor(oh);
00224         if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00225             continue;
00226 
00227         /* Snarf the original install tid & time from older package(s). */
00228         he->tag = RPMTAG_ORIGINTID;
00229         xx = headerGet(oh, he, 0);
00230         if (xx && he->p.ui32p != NULL) {
00231             if (p->originTid[0] == 0 || p->originTid[0] > he->p.ui32p[0]
00232              || (he->c > 1 && p->originTid[0] == he->p.ui32p[0] && p->originTid[1] > he->p.ui32p[1]))
00233             {
00234                 p->originTid[0] = he->p.ui32p[0];
00235                 p->originTid[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
00236             }
00237             he->p.ptr = _free(he->p.ptr);
00238         }
00239         he->tag = RPMTAG_ORIGINTIME;
00240         xx = headerGet(oh, he, 0);
00241         if (xx && he->p.ui32p != NULL) {
00242             if (p->originTime[0] == 0 || p->originTime[0] > he->p.ui32p[0]
00243              || (he->c > 1 && p->originTime[0] == he->p.ui32p[0] && p->originTime[1] > he->p.ui32p[1]))
00244             {
00245                 p->originTime[0] = he->p.ui32p[0];
00246                 p->originTime[1] = (he->c > 1 ? he->p.ui32p[1] : 0);
00247             }
00248             he->p.ptr = _free(he->p.ptr);
00249         }
00250 
00251 #if defined(RPM_VENDOR_WINDRIVER)
00252         /*
00253          * If we're capable of installing multiple colors
00254          * but at least one of the packages are white (0), we
00255          * further verify the arch is the same (or compatible) to trigger an upgrade
00256          * we do have a special case to allow upgrades of noarch w/ a arch package
00257          */
00258         if (tscolor && (!hcolor || !ohcolor)) {
00259             const char * arch;
00260             const char * oharch;
00261             he->tag = RPMTAG_ARCH;
00262             xx = headerGet(h, he, 0);
00263             arch = (xx && he->p.str != NULL ? he->p.str : NULL);
00264             he->tag = RPMTAG_ARCH;
00265             xx = headerGet(oh, he, 0);
00266             oharch = (xx && he->p.str != NULL ? he->p.str : NULL);
00267             if (arch != NULL && oharch != NULL) {
00268                 if (strcmp("noarch", arch) || strcmp("noarch", oharch)) {
00269                     if (!_isCompatibleArch(arch, oharch)) {
00270                         arch = _free(arch);
00271                         oharch = _free(oharch);
00272                         continue;
00273                     }
00274                 }
00275             }
00276             arch = _free(arch);
00277             oharch = _free(oharch);
00278         }
00279 #endif
00280 
00281         /* Skip identical packages. */
00282         if (rpmHeadersIdentical(h, oh))
00283             continue;
00284 
00285         /* Create an erasure element. */
00286         lastx = -1;
00287         xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
00288 assert(lastx >= 0 && lastx < ts->orderCount);
00289         q = ts->order[lastx];
00290 
00291         /* Chain through upgrade flink. */
00292         xx = rpmteChain(p, q, oh, "Upgrades");
00293 
00294 /*@-nullptrarith@*/
00295         rpmlog(RPMLOG_DEBUG, D_("   upgrade erases %s\n"), rpmteNEVRA(q));
00296 /*@=nullptrarith@*/
00297 
00298     }
00299     mi = rpmmiFree(mi);
00300 
00301     return 0;
00302 }
00303 
00310 static inline int chkSuffix(const char * fn, const char * suffix)
00311         /*@*/
00312 {
00313     size_t flen = strlen(fn);
00314     size_t slen = strlen(suffix);
00315     return (flen > slen && !strcmp(fn + flen - slen, suffix));
00316 }
00317 
00326 static int rpmtsEraseDebuginfo(rpmts ts, rpmte p, Header h,
00327                 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey pkgKey)
00328         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00329         /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
00330 {
00331     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00332     const void *keyval = NULL;
00333     size_t keylen = 0;
00334     size_t nrefs = 0;
00335     rpmuint32_t debuginfoInstance = 0;
00336     Header debuginfoHeader = NULL;
00337     rpmmi mi;
00338     Header oh;
00339     int xx;
00340 
00341     /* XXX SOURCEPKGID is not populated reliably, do not use (yet). */
00342     if (_debuginfo_tag == 0) {
00343         const char * t = rpmExpand("%{?_debuginfo_tag}", NULL);
00344 /*@-mods@*/
00345         _debuginfo_tag = (*t != '\0' && !strcmp(t, "pkgid")
00346                 ? RPMTAG_SOURCEPKGID : RPMTAG_SOURCERPM);
00347 /*@=mods@*/
00348         t = _free(t);
00349     }
00350 
00351     /* Grab the retrieval key. */
00352     switch (_debuginfo_tag) {
00353     default:            return 0;       /*@notreached@*/        break;
00354     case RPMTAG_SOURCERPM:      keyval = rpmteSourcerpm(p);     break;
00355     }
00356 
00357     /* Count remaining members in build set, excluding -debuginfo (if any). */
00358     mi = rpmtsInitIterator(ts, _debuginfo_tag, keyval, keylen);
00359     xx = rpmmiPrune(mi, ts->removedPackages, ts->numRemovedPackages, 1);
00360     while((oh = rpmmiNext(mi)) != NULL) {
00361         /* Skip identical packages. */
00362         if (rpmHeadersIdentical(h, oh))
00363             continue;
00364 
00365         he->tag = RPMTAG_NAME;
00366         xx = headerGet(oh, he, 0);
00367         if (!xx || he->p.str == NULL)
00368             continue;
00369         /* Save the -debuginfo member. */
00370         if (chkSuffix(he->p.str, "-debuginfo")) {
00371             debuginfoInstance = rpmmiInstance(mi);
00372             debuginfoHeader = headerLink(oh);
00373         } else
00374             nrefs++;
00375         he->p.str = _free(he->p.str);
00376     }
00377     mi = rpmmiFree(mi);
00378 
00379     /* Remove -debuginfo package when last build member is erased. */
00380     if (nrefs == 0 && debuginfoInstance > 0 && debuginfoHeader != NULL) {
00381         int lastx = -1;
00382         rpmte q;
00383 
00384         /* Create an erasure element. */
00385         lastx = -1;
00386         xx = removePackage(ts, debuginfoHeader, debuginfoInstance,
00387                 &lastx, pkgKey);
00388 assert(lastx >= 0 && lastx < ts->orderCount);
00389         q = ts->order[lastx];
00390 
00391         /* Chain through upgrade flink. */
00392         /* XXX avoid assertion failure when erasing. */
00393         if (pkgKey != RPMAL_NOMATCH)
00394             xx = rpmteChain(p, q, oh, "Upgrades");
00395 
00396 /*@-nullptrarith@*/
00397         rpmlog(RPMLOG_DEBUG, D_("   lastref erases %s\n"), rpmteNEVRA(q));
00398 /*@=nullptrarith@*/
00399 
00400     }
00401     (void)headerFree(debuginfoHeader);
00402     debuginfoHeader = NULL;
00403 
00404     return (int)nrefs;
00405 }
00406 
00414 static int rpmtsAddObsoletes(rpmts ts, rpmte p, rpmuint32_t hcolor)
00415         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00416         /*@modifies ts, p, rpmGlobalMacroContext, fileSystem, internalState @*/
00417 {
00418     rpmuint32_t tscolor = rpmtsColor(ts);
00419     alKey pkgKey = rpmteAddedKey(p);
00420     rpmuint32_t ohcolor;
00421     rpmds obsoletes;
00422     rpmuint32_t dscolor;
00423     rpmmi mi;
00424     Header oh;
00425     int xx;
00426 
00427     if (_obsolete_tag == 0) {
00428         const char *t = rpmExpand("%{?_obsolete_tag}", NULL);
00429 /*@-mods@*/
00430         _obsolete_tag = (!strcmp(t, "name") ? RPMTAG_NAME : RPMTAG_PROVIDENAME);
00431 /*@=mods@*/
00432         t = _free(t);
00433     }
00434 
00435     obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
00436     obsoletes = rpmdsInit(obsoletes);
00437     if (obsoletes != NULL)
00438     while (rpmdsNext(obsoletes) >= 0) {
00439         const char * Name;
00440 
00441         if ((Name = rpmdsN(obsoletes)) == NULL)
00442             continue;   /* XXX can't happen */
00443 
00444         /* Ignore colored obsoletes not in our rainbow. */
00445 #if 0
00446         /* XXX obsoletes are never colored, so this is for future devel. */
00447         dscolor = rpmdsColor(obsoletes);
00448 #else
00449         dscolor = hcolor;
00450 #endif
00451         if (tscolor && dscolor && !(tscolor & dscolor))
00452             continue;
00453 
00454         /* XXX avoid self-obsoleting packages. */
00455         if (!strcmp(rpmteN(p), Name))
00456             continue;
00457 
00458         /* Obsolete containing package if given a file, otherwise provide. */
00459         if (Name[0] == '/')
00460             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00461         else
00462             mi = rpmtsInitIterator(ts, _obsolete_tag, Name, 0);
00463 
00464         xx = rpmmiPrune(mi, ts->removedPackages, ts->numRemovedPackages, 1);
00465 
00466         while((oh = rpmmiNext(mi)) != NULL) {
00467             int lastx;
00468             rpmte q;
00469 
00470             /* Ignore colored packages not in our rainbow. */
00471             ohcolor = hGetColor(oh);
00472 
00473             /* XXX provides *are* colored, effectively limiting Obsoletes:
00474                 to matching only colored Provides: based on pkg coloring. */
00475             if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00476                 /*@innercontinue@*/ continue;
00477 
00478             /*
00479              * Rpm prior to 3.0.3 does not have versioned obsoletes.
00480              * If no obsoletes version info is available, match all names.
00481              */
00482             if (!(rpmdsEVR(obsoletes) == NULL
00483              || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)))
00484                 /*@innercontinue@*/ continue;
00485 
00486             /* Create an erasure element. */
00487             lastx = -1;
00488             xx = removePackage(ts, oh, rpmmiInstance(mi), &lastx, pkgKey);
00489 assert(lastx >= 0 && lastx < ts->orderCount);
00490             q = ts->order[lastx];
00491 
00492             /* Chain through obsoletes flink. */
00493             xx = rpmteChain(p, q, oh, "Obsoletes");
00494 
00495 /*@-nullptrarith@*/
00496             rpmlog(RPMLOG_DEBUG, D_("  Obsoletes: %s\t\terases %s\n"),
00497                         rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q));
00498 /*@=nullptrarith@*/
00499         }
00500         mi = rpmmiFree(mi);
00501     }
00502     (void)rpmdsFree(obsoletes);
00503     obsoletes = NULL;
00504 
00505     return 0;
00506 }
00507 
00508 #if defined(RPM_VENDOR_WINDRIVER)
00509 /* Is "compat" compatible w/ arch? */
00510 int _isCompatibleArch(const char * arch, const char * compat)
00511 {
00512     const char * compatArch = rpmExpand(compat, " %{?_", compat, "_compat_arch}", NULL);
00513     const char * p, * pe, * t;
00514     int match = 0;
00515 
00516     /* Hack to ensure iX86 being automatically compatible */
00517     if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00518         if ((arch[0] == compat[0]) &&
00519             (arch[2] == compat[2]) &&
00520             (arch[3] == compat[3]))
00521             match = 1;
00522 
00523         if (!strcmp(compat, "x86_32"))
00524             match = 1;
00525     }
00526 
00527     for ( p = pe = compatArch ; *pe && match == 0 ; ) {
00528         while (*p && xisspace(*p)) p++;
00529         pe = p ; while (*pe && !xisspace(*pe)) pe++;
00530         if (p == pe)
00531             break;
00532         t = strndup(p, (pe - p));
00533         p = pe; /* Advance to next chunk */
00534 rpmlog(RPMLOG_DEBUG, D_("   Comparing compat archs %s ? %s\n"), arch, t);
00535         if (!strcmp(arch, t))
00536             match = 1;
00537         t = _free(t);
00538     }
00539     compatArch = _free(compatArch);
00540     return match;
00541 }
00542 #endif
00543 
00544 int rpmtsAddInstallElement(rpmts ts, Header h,
00545                         fnpyKey key, int upgrade, rpmRelocation relocs)
00546 {
00547     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00548     rpmdepFlags depFlags = rpmtsDFlags(ts);
00549     rpmuint32_t tscolor = rpmtsColor(ts);
00550     rpmuint32_t hcolor;
00551     int isSource;
00552     int duplicate = 0;
00553     rpmtsi pi = NULL; rpmte p;
00554     const char * arch = NULL;
00555     const char * os = NULL;
00556     rpmds oldChk, newChk;
00557     alKey pkgKey;       /* addedPackages key */
00558     int xx;
00559     int ec = 0;
00560     int rc;
00561     int oc;
00562 
00563     hcolor = hGetColor(h);
00564     pkgKey = RPMAL_NOMATCH;
00565 
00566     /*
00567      * Always add source headers.
00568      */
00569     isSource =
00570         (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 &&
00571          headerIsEntry(h, RPMTAG_ARCH) != 0);
00572     if (isSource) {
00573         oc = ts->orderCount;
00574         goto addheader;
00575     }
00576 
00577     /*
00578      * Check platform affinity of binary packages.
00579      */
00580     he->tag = RPMTAG_ARCH;
00581     xx = headerGet(h, he, 0);
00582     arch = he->p.str;
00583     he->tag = RPMTAG_OS;
00584     xx = headerGet(h, he, 0);
00585     os = he->p.str;
00586     if (nplatpat > 1) {
00587         const char * platform = NULL;
00588 
00589         he->tag = RPMTAG_PLATFORM;
00590         xx = headerGet(h, he, 0);
00591         platform = he->p.str;
00592         if (!xx || platform == NULL)
00593             platform = rpmExpand(arch, "-unknown-", os, NULL);
00594 
00595         rc = rpmPlatformScore(platform, platpat, nplatpat);
00596 #if defined(RPM_VENDOR_MANDRIVA)
00597         /*
00598          * If no match on platform tag, we'll try again with arch tag
00599          * in case platform tag is inconsistent with it, which is the case
00600          * for older noarch sub-packages built (mdvbz#61746).
00601          */
00602         if(xx && rc <= 0) {
00603             platform = _free(platform);
00604             platform = rpmExpand(arch, "-unknown-", os, NULL);
00605             rc = rpmPlatformScore(platform, platpat, nplatpat);
00606         }
00607 #endif
00608         if (rc <= 0) {
00609             rpmps ps = rpmtsProblems(ts);
00610             he->tag = RPMTAG_NVRA;
00611             xx = headerGet(h, he, 0);
00612 assert(he->p.str != NULL);
00613 
00614             rpmpsAppend(ps, RPMPROB_BADPLATFORM, he->p.str, key,
00615                         platform, NULL, NULL, 0);
00616 
00617             /* XXX problem string should be printed by caller instead. */
00618             if (rpmIsVerbose()) {
00619                 const char * msg = rpmProblemString(rpmpsGetProblem(ps, -1));
00620                 rpmlog(RPMLOG_WARNING, "%s\n", msg);
00621                 msg = _free(msg);
00622             }
00623 
00624             ps = rpmpsFree(ps);
00625             he->p.ptr = _free(he->p.ptr);
00626             ec = 1;
00627         }
00628         platform = _free(platform);
00629         if (ec)
00630             goto exit;
00631     }
00632 
00633     /*
00634      * Always install compatible binary packages.
00635      */
00636     if (!upgrade) {
00637         oc = ts->orderCount;
00638         goto addheader;
00639     }
00640 
00641     /*
00642      * Check that upgrade package is uniquely newer, replace older if necessary.
00643      */
00644     oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
00645     newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
00646     /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */
00647     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00648         rpmds this;
00649 
00650         /* XXX Only added packages need be checked for dupes here. */
00651         if (rpmteType(p) == TR_REMOVED)
00652             continue;
00653 
00654         /* XXX Never check source header NEVRAO. */
00655         if (rpmteIsSource(p))
00656             continue;
00657 
00658         if (tscolor) {
00659             const char * parch;
00660             const char * pos;
00661 
00662             if (arch == NULL || (parch = rpmteA(p)) == NULL)
00663                 continue;
00664 #if defined(RPM_VENDOR_WINDRIVER)
00665             /* XXX hackery for alias matching. */
00666             if (!_isCompatibleArch(arch, parch))
00667                 continue;
00668 #else
00669             /* XXX hackery for i[3456]86 alias matching. */
00670             if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00671                 if (arch[0] != parch[0]) continue;
00672                 if (arch[2] != parch[2]) continue;
00673                 if (arch[3] != parch[3]) continue;
00674             }
00675 #endif
00676             else if (strcmp(arch, parch))
00677                 continue;
00678             if (os == NULL || (pos = rpmteO(p)) == NULL)
00679                 continue;
00680 
00681             if (strcmp(os, pos))
00682                 continue;
00683         }
00684 
00685         /* OK, binary rpm's with same arch and os.  Check NEVR. */
00686         if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
00687             continue;   /* XXX can't happen */
00688 
00689         /* If newer NEVRAO already added, then skip adding older. */
00690         rc = rpmdsCompare(newChk, this);
00691         if (rc != 0) {
00692             const char * pkgNEVR = rpmdsDNEVR(this);
00693             const char * addNEVR = rpmdsDNEVR(oldChk);
00694             if (rpmIsVerbose())
00695                 rpmlog(RPMLOG_WARNING,
00696                     _("package %s was already added, skipping %s\n"),
00697                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00698                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00699             ec = 1;
00700             break;
00701         }
00702 
00703         /* If older NEVRAO already added, then replace old with new. */
00704         rc = rpmdsCompare(oldChk, this);
00705         if (rc != 0) {
00706             const char * pkgNEVR = rpmdsDNEVR(this);
00707             const char * addNEVR = rpmdsDNEVR(newChk);
00708             if (rpmIsVerbose())
00709                 rpmlog(RPMLOG_WARNING,
00710                     _("package %s was already added, replacing with %s\n"),
00711                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00712                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00713             duplicate = 1;
00714             pkgKey = rpmteAddedKey(p);
00715             break;
00716         }
00717     }
00718     pi = rpmtsiFree(pi);
00719     (void)rpmdsFree(oldChk);
00720     oldChk = NULL;
00721     (void)rpmdsFree(newChk);
00722     newChk = NULL;
00723 
00724     /* If newer (or same) NEVRAO was already added, exit now. */
00725     if (ec)
00726         goto exit;
00727 
00728 addheader:
00729     if (oc >= ts->orderAlloced) {
00730         ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
00731 /*@-type +voidabstract @*/
00732         ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
00733 /*@=type =voidabstract @*/
00734     }
00735 
00736     p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
00737 assert(p != NULL);
00738 
00739     if (duplicate && oc < ts->orderCount) {
00740         ts->numAddedFiles -= rpmfiFC(rpmteFI(ts->order[oc], RPMTAG_BASENAMES));
00741 /*@-type -unqualifiedtrans@*/
00742         ts->order[oc] = rpmteFree(ts->order[oc]);
00743 /*@=type =unqualifiedtrans@*/
00744     }
00745 
00746     ts->order[oc] = p;
00747     ts->numAddedFiles += rpmfiFC(rpmteFI(p, RPMTAG_BASENAMES));
00748     if (!duplicate) {
00749         ts->orderCount++;
00750         rpmcliPackagesTotal++;
00751     }
00752     
00753     pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
00754                         rpmteDS(p, RPMTAG_PROVIDENAME),
00755                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
00756     if (pkgKey == RPMAL_NOMATCH) {
00757         ts->order[oc] = rpmteFree(ts->order[oc]);
00758         ts->teInstall = NULL;
00759         ec = 1;
00760         goto exit;
00761     }
00762     (void) rpmteSetAddedKey(p, pkgKey);
00763 
00764     if (!duplicate) {
00765         ts->numAddedPackages++;
00766     }
00767 
00768     ts->teInstall = ts->order[oc];
00769 
00770     /* XXX rpmgi hack: Save header in transaction element if requested. */
00771     if (upgrade & 0x2)
00772         (void) rpmteSetHeader(p, h);
00773 
00774     /* If not upgrading, then we're done. */
00775     if (!(upgrade & 0x1))
00776         goto exit;
00777 
00778     /* If source rpm, then we're done. */
00779     if (isSource)
00780         goto exit;
00781 
00782     /* Do lazy (readonly?) open of rpm database. */
00783     if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
00784         if ((ec = rpmtsOpenDB(ts, rpmtsDBMode(ts)) != 0))
00785             goto exit;
00786     }
00787 
00788     /* Add upgrades to the transaction (if not disabled). */
00789     if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) {
00790         /*
00791          * Don't upgrade -debuginfo until build set is empty.
00792          *
00793          * XXX Almost, but not quite, correct since the test depends on
00794          * added package arrival order.
00795          * I.e. -debuginfo additions must always follow all
00796          * other additions so that erasures of other members in the
00797          * same build set are seen if/when included in the same transaction.
00798          */
00799         xx = rpmtsEraseDebuginfo(ts, p, h, pkgKey);
00800         if (!chkSuffix(rpmteN(p), "-debuginfo") || xx == 0)
00801             xx = rpmtsAddUpgrades(ts, p, hcolor, h);
00802     }
00803 
00804     /* Add Obsoletes: to the transaction (if not disabled). */
00805     if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) {
00806         xx = rpmtsAddObsoletes(ts, p, hcolor);
00807     }
00808 
00809     ec = 0;
00810 
00811 exit:
00812     arch = _free(arch);
00813     os = _free(os);
00814     pi = rpmtsiFree(pi);
00815     return ec;
00816 }
00817 
00818 int rpmtsAddEraseElement(rpmts ts, Header h, uint32_t hdrNum)
00819 {
00820     int oc = -1;
00821     int rc = removePackage(ts, h, hdrNum, &oc, RPMAL_NOMATCH);
00822     if (rc == 0 && oc >= 0 && oc < ts->orderCount) {
00823         (void) rpmtsEraseDebuginfo(ts, ts->order[oc], h, RPMAL_NOMATCH);
00824         ts->teErase = ts->order[oc];
00825     } else
00826         ts->teErase = NULL;
00827     return rc;
00828 }
00829 
00830 /*@only@*/ /*@null@*/ /*@unchecked@*/
00831 static char *sysinfo_path = NULL;
00832 
00833 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
00834 static rpmds rpmlibP = NULL;
00835 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
00836 rpmds cpuinfoP = NULL;
00837 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
00838 static rpmds getconfP = NULL;
00839 /*@refcounted@*/ /*@null@*/ /*@unchecked@*/
00840 static rpmds unameP = NULL;
00841 
00842 void rpmnsClean(void)
00843         /*@globals sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/
00844         /*@modifies sysinfo_path, _sysinfo_path, rpmlibP, cpuinfoP, getconfP, unameP @*/
00845 {
00846     (void)rpmdsFree(rpmlibP);
00847     rpmlibP = NULL;
00848     (void)rpmdsFree(cpuinfoP);
00849     cpuinfoP = NULL;
00850     (void)rpmdsFree(getconfP);
00851     getconfP = NULL;
00852     (void)rpmdsFree(unameP);
00853     unameP = NULL;
00854 /*@-observertrans@*/
00855     _sysinfo_path = _free(_sysinfo_path);
00856 /*@=observertrans@*/
00857     sysinfo_path = _free(sysinfo_path);
00858 }
00859 
00867 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
00868         /*@globals _cacheDependsRC, rpmGlobalMacroContext, h_errno,
00869                 sysinfo_path, fileSystem, internalState @*/
00870         /*@modifies ts, dep, _cacheDependsRC, rpmGlobalMacroContext,
00871                 sysinfo_path, fileSystem, internalState @*/
00872 {
00873     DBT * key = alloca(sizeof(*key));
00874     DBT * data = alloca(sizeof(*data));
00875     rpmmi mi;
00876     nsType NSType;
00877     const char * Name;
00878     rpmuint32_t Flags;
00879     Header h;
00880 #if defined(CACHE_DEPENDENCY_RESULT)
00881     int _cacheThisRC = 1;
00882 #endif
00883     int rc;
00884     int xx;
00885     int retries = 20;
00886 
00887     if ((Name = rpmdsN(dep)) == NULL)
00888         return 0;       /* XXX can't happen */
00889     Flags = rpmdsFlags(dep);
00890     NSType = rpmdsNSType(dep);
00891 
00892 #if defined(CACHE_DEPENDENCY_RESULT)
00893     /*
00894      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
00895      */
00896     if (_cacheDependsRC) {
00897         dbiIndex dbi;
00898         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00899         if (dbi == NULL)
00900             _cacheDependsRC = 0;
00901         else {
00902             const char * DNEVR;
00903 
00904             rc = -1;
00905             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00906                 DBC * dbcursor = NULL;
00907                 void * datap = NULL;
00908                 size_t datalen = 0;
00909                 size_t DNEVRlen = strlen(DNEVR);
00910 
00911                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
00912 
00913                 memset(key, 0, sizeof(*key));
00914 /*@i@*/         key->data = (void *) DNEVR;
00915                 key->size = DNEVRlen;
00916                 memset(data, 0, sizeof(*data));
00917                 data->data = datap;
00918                 data->size = datalen;
00919 /*@-nullstate@*/ /* FIX: data->data may be NULL */
00920                 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
00921 /*@=nullstate@*/
00922                 DNEVR = key->data;
00923                 DNEVRlen = key->size;
00924                 datap = data->data;
00925                 datalen = data->size;
00926 
00927                 if (xx == 0 && datap && datalen == 4)
00928                     memcpy(&rc, datap, datalen);
00929                 xx = dbiCclose(dbi, dbcursor, 0);
00930             }
00931 
00932             if (rc >= 0) {
00933                 rpmdsNotify(dep, _("(cached)"), rc);
00934                 return rpmdsNegateRC(dep, rc);
00935             }
00936         }
00937     }
00938 #endif
00939 
00940 retry:
00941     rc = 0;     /* assume dependency is satisfied */
00942 
00943     /* Expand macro probe dependencies. */
00944     if (NSType == RPMNS_TYPE_FUNCTION) {
00945         xx = rpmExpandNumeric(Name);
00946         rc = (xx ? 0 : 1);
00947         if (Flags & RPMSENSE_MISSINGOK)
00948             goto unsatisfied;
00949         rpmdsNotify(dep, _("(function probe)"), rc);
00950         goto exit;
00951     }
00952 
00953     /* Evaluate user/group lookup probes. */
00954     if (NSType == RPMNS_TYPE_USER) {
00955         const char *s;
00956         uid_t uid = 0;
00957         s = Name; while (*s && xisdigit(*s)) s++;
00958 
00959         if (*s)
00960             xx = unameToUid(Name, &uid);
00961         else {
00962             uid = strtol(Name, NULL, 10);
00963             xx = (uidToUname(uid) ? 0 : -1);
00964         }
00965         rc = (xx >= 0 ? 0 : 1);
00966         if (Flags & RPMSENSE_MISSINGOK)
00967             goto unsatisfied;
00968         rpmdsNotify(dep, _("(user lookup)"), rc);
00969         goto exit;
00970     }
00971     if (NSType == RPMNS_TYPE_GROUP) {
00972         const char *s;
00973         gid_t gid = 0;
00974         s = Name; while (*s && xisdigit(*s)) s++;
00975 
00976         if (*s)
00977             xx = gnameToGid(Name, &gid);
00978         else {
00979             gid = strtol(Name, NULL, 10);
00980             xx = (gidToGname(gid) ? 0 : -1);
00981         }
00982         rc = (xx >= 0 ? 0 : 1);
00983         if (Flags & RPMSENSE_MISSINGOK)
00984             goto unsatisfied;
00985         rpmdsNotify(dep, _("(group lookup)"), rc);
00986         goto exit;
00987     }
00988 
00989     /* Evaluate access(2) probe dependencies. */
00990     if (NSType == RPMNS_TYPE_ACCESS) {
00991         rc = rpmioAccess(Name, NULL, X_OK);
00992         if (Flags & RPMSENSE_MISSINGOK)
00993             goto unsatisfied;
00994         rpmdsNotify(dep, _("(access probe)"), rc);
00995         goto exit;
00996     }
00997 
00998     /* Evaluate mtab lookup and diskspace probe dependencies. */
00999     if (NSType == RPMNS_TYPE_MOUNTED) {
01000         const char ** fs = NULL;
01001         int nfs = 0;
01002         int i = 0;
01003 
01004         xx = rpmtsInitDSI(ts);
01005         fs = ts->filesystems;
01006         nfs = ts->filesystemCount;
01007 
01008         if (fs != NULL)
01009         for (i = 0; i < nfs; i++) {
01010             if (!strcmp(fs[i], Name))
01011                 break;
01012         }
01013         rc = (i < nfs ? 0 : 1);
01014         if (Flags & RPMSENSE_MISSINGOK)
01015             goto unsatisfied;
01016         rpmdsNotify(dep, _("(mtab probe)"), rc);
01017         goto exit;
01018     }
01019 
01020     if (NSType == RPMNS_TYPE_DISKSPACE) {
01021         size_t nb = strlen(Name);
01022         rpmDiskSpaceInfo dsi = NULL;
01023         const char ** fs = NULL;
01024         size_t fslen = 0, longest = 0;
01025         int nfs = 0;
01026         int i = 0;
01027 
01028         xx = rpmtsInitDSI(ts);
01029         fs = ts->filesystems;
01030         nfs = ts->filesystemCount;
01031 
01032         if (fs != NULL)
01033         for (i = 0; i < nfs; i++) {
01034             fslen = strlen(fs[i]);
01035             if (fslen > nb)
01036                 continue;
01037             if (strncmp(fs[i], Name, fslen))
01038                 continue;
01039             if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0')
01040                 continue;
01041             if (fslen < longest)
01042                 continue;
01043             longest = fslen;
01044             dsi = ts->dsi + i;
01045         }
01046         if (dsi == NULL)
01047             rc = 1;     /* no mounted paths !?! */
01048         else {
01049             char * end = NULL;
01050 /*@-unrecog@*/
01051             rpmuint64_t needed = strtoll(rpmdsEVR(dep), &end, 0);
01052 /*@=unrecog@*/
01053 
01054             if (end && *end) {
01055                 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2])
01056                     needed *= 1024 * 1024 * 1024;
01057                 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2])
01058                     needed *= 1024 * 1024;
01059                 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2])
01060                     needed *= 1024;
01061             } else
01062                 needed *= 1024 * 1024;  /* XXX assume Mb if no units given */
01063 
01064             needed = BLOCK_ROUND(needed, dsi->f_bsize);
01065             xx = (dsi->f_bavail - needed);
01066             if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0;
01067             else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0;
01068             else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
01069             else rc = 1;
01070         }
01071         if (Flags & RPMSENSE_MISSINGOK)
01072             goto unsatisfied;
01073         rpmdsNotify(dep, _("(diskspace probe)"), rc);
01074         goto exit;
01075     }
01076 
01077     if (NSType == RPMNS_TYPE_DIGEST) {
01078         const char * EVR = rpmdsEVR(dep);
01079         const char *filename;
01080         pgpHashAlgo digestHashAlgo;
01081         FD_t fd;
01082         char *cp;
01083         int algo;
01084 
01085         filename = Name;
01086         digestHashAlgo = PGPHASHALGO_MD5;
01087         if ((cp = strchr(filename, ':')) != NULL) {
01088             if ((algo = pgpHashAlgoStringToNumber(filename, cp-filename)) != PGPHASHALGO_ERROR) {
01089                 digestHashAlgo = algo;
01090                 filename = cp + 1;
01091             }
01092         }
01093         rc = 1;         /* XXX assume failure */
01094         fd = Fopen(filename, "r.fdio");
01095         if (fd && !Ferror(fd)) {
01096             DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE);
01097             const char * digest = NULL;
01098             size_t digestlen = 0;
01099             int asAscii = 1;
01100             size_t nbuf = 8 * BUFSIZ;
01101             char * buf = alloca(nbuf);
01102             size_t nb;
01103 
01104             while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0)
01105                 xx = rpmDigestUpdate(ctx, buf, nb);
01106             xx = Fclose(fd);    fd = NULL;
01107             xx = rpmDigestFinal(ctx, &digest, &digestlen, asAscii);
01108 
01109             xx = (EVR && *EVR && digest && *digest) ? strcasecmp(EVR, digest) : -1;
01110             /* XXX only equality makes sense for digest compares */
01111             if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
01112         }
01113         if (Flags & RPMSENSE_MISSINGOK)
01114             goto unsatisfied;
01115         rpmdsNotify(dep, _("(digest probe)"), rc);
01116         goto exit;
01117     }
01118 
01119     if (NSType == RPMNS_TYPE_SIGNATURE) {
01120         const char * EVR = rpmdsEVR(dep);
01121         ARGV_t avN = NULL;
01122         ARGV_t avEVR = NULL;
01123         rpmRC res;
01124 
01125         /* Split /fn:/sig */
01126         xx = argvSplit(&avN, Name, ":");
01127 
01128         /* Split /pub:id */
01129         xx = (EVR && *EVR) ? argvSplit(&avEVR, EVR, ":") : argvAdd(&avEVR, "");
01130 
01131         res = rpmnsProbeSignature(ts, avN[0], avN[1], avEVR[0], avEVR[1], 0);
01132         rc = (res == RPMRC_OK ? 0 : 1);
01133 
01134         avN = argvFree(avN);
01135         avEVR = argvFree(avEVR);
01136 
01137         if (Flags & RPMSENSE_MISSINGOK)
01138             goto unsatisfied;
01139         rpmdsNotify(dep, _("(signature probe)"), rc);
01140         goto exit;
01141     }
01142 
01143     if (NSType == RPMNS_TYPE_VERIFY) {
01144         QVA_t qva = memset(alloca(sizeof(*qva)), 0, sizeof(*qva));
01145 
01146         qva->qva_mode = 'v';
01147         qva->qva_flags = (int)(VERIFY_ALL & ~(VERIFY_DEPS|VERIFY_SCRIPT));
01148         rc = 0;         /* assume success */
01149         if (rpmtsGetRdb(ts) != NULL) {
01150             if (!strcmp(Name, "*"))                     /* -Va probe */
01151                 mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES, NULL, 0);
01152             else if (Name[0] == '/')            /* -Vf probe */
01153                 mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
01154             else                                /* -V probe */
01155                 mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01156             while ((h = rpmmiNext(mi)) != NULL) {
01157                 if (!(Name[0] == '/' || !strcmp(Name, "*")))
01158                 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01159                     continue;
01160                 xx = (showVerifyPackage(qva, ts, h) ? 1 : 0);
01161                 if (xx)
01162                     rc = 1;
01163             }
01164             mi = rpmmiFree(mi);
01165         }
01166 
01167         if (Flags & RPMSENSE_MISSINGOK)
01168             goto unsatisfied;
01169         rpmdsNotify(dep, _("(verify probe)"), rc);
01170         goto exit;
01171     }
01172 
01173     if (NSType == RPMNS_TYPE_GNUPG) {
01174         const char * EVR = rpmdsEVR(dep);
01175         if (!(EVR && *EVR)) {
01176             static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
01177             static const char gnupg_post[] = " 2>/dev/null; echo $?)";
01178             const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
01179             rc = (t && t[0] == '0') ? 0 : 1;
01180             t = _free(t);
01181         }
01182         else {
01183             static const char gnupg_pre[] = "%(%{__gpg} --batch --no-tty --quiet --verify ";
01184             static const char gnupg_post[] = " 2>&1 | grep '^Primary key fingerprint:' | sed -e 's;^.*: *;;' -e 's; *;;g')";
01185             const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
01186             rc = ((Flags & RPMSENSE_EQUAL) && strcasecmp(EVR, t) == 0) ? 0 : 1;
01187             t = _free(t);
01188         }
01189         if (Flags & RPMSENSE_MISSINGOK)
01190             goto unsatisfied;
01191         rpmdsNotify(dep, _("(gnupg probe)"), rc);
01192         goto exit;
01193     }
01194 
01195     if (NSType == RPMNS_TYPE_MACRO) {
01196         static const char macro_pre[] = "%{?";
01197         static const char macro_post[] = ":0}";
01198         const char * a = rpmExpand(macro_pre, Name, macro_post, NULL);
01199 
01200         rc = (a && a[0] == '0') ? 0 : 1;
01201         a = _free(a);
01202         if (Flags & RPMSENSE_MISSINGOK)
01203             goto unsatisfied;
01204         rpmdsNotify(dep, _("(macro probe)"), rc);
01205         goto exit;
01206     }
01207 
01208     if (NSType == RPMNS_TYPE_ENVVAR) {
01209         const char * a = envGet(Name);
01210         const char * b = rpmdsEVR(dep);
01211 
01212         /* Existence test if EVR is missing/empty. */
01213         if (!(b && *b))
01214             rc = (!(a && *a));
01215         else {
01216             int sense = (a && *a) ? strcmp(a, b) : -1;
01217 
01218             if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL)
01219                 rc = (sense == 0);
01220             else if (sense < 0 && (Flags & RPMSENSE_LESS))
01221                 rc = 0;
01222             else if (sense > 0 && (Flags & RPMSENSE_GREATER))
01223                 rc = 0;
01224             else if (sense == 0 && (Flags & RPMSENSE_EQUAL))
01225                 rc = 0;
01226             else
01227                 rc = (sense != 0);
01228         }
01229 
01230         if (Flags & RPMSENSE_MISSINGOK)
01231             goto unsatisfied;
01232         rpmdsNotify(dep, _("(envvar probe)"), rc);
01233         goto exit;
01234     }
01235 
01236     if (NSType == RPMNS_TYPE_RUNNING) {
01237         char *t = NULL;
01238         pid_t pid = strtol(Name, &t, 10);
01239 
01240         if (t == NULL || *t != '\0') {
01241             const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL);
01242             FD_t fd = NULL;
01243 
01244             if (fn && *fn != '%' && (fd = Fopen(fn, "r.fdio")) && !Ferror(fd)) {
01245                 char buf[32];
01246                 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
01247 
01248                 if (nb > 0)
01249                     pid = strtol(buf, &t, 10);
01250             } else
01251                 pid = 0;
01252             if (fd != NULL)
01253                 (void) Fclose(fd);
01254             fn = _free(fn);
01255         }
01256         rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1);
01257         if (Flags & RPMSENSE_MISSINGOK)
01258             goto unsatisfied;
01259         rpmdsNotify(dep, _("(running probe)"), rc);
01260         goto exit;
01261     }
01262 
01263     if (NSType == RPMNS_TYPE_SANITY) {
01264         /* XXX only the installer does not have the database open here. */
01265         rc = 1;         /* assume failure */
01266         if (rpmtsGetRdb(ts) != NULL) {
01267             mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01268             while ((h = rpmmiNext(mi)) != NULL) {
01269                 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01270                     continue;
01271                 rc = (headerIsEntry(h, RPMTAG_SANITYCHECK) == 0);
01272                 if (rc == 0) {
01273                     /* XXX FIXME: actually run the sanitycheck script. */
01274                     break;
01275                 }
01276             }
01277             mi = rpmmiFree(mi);
01278         }
01279         if (Flags & RPMSENSE_MISSINGOK)
01280             goto unsatisfied;
01281         rpmdsNotify(dep, _("(sanity probe)"), rc);
01282         goto exit;
01283     }
01284 
01285     if (NSType == RPMNS_TYPE_VCHECK) {
01286         rc = 1;         /* assume failure */
01287         if (rpmtsGetRdb(ts) != NULL) {
01288             mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01289             while ((h = rpmmiNext(mi)) != NULL) {
01290                 if (!rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote))
01291                     continue;
01292                 rc = (headerIsEntry(h, RPMTAG_TRACK) == 0);
01293                 if (rc == 0) {
01294                     /* XXX FIXME: actually run the vcheck script. */
01295                     break;
01296                 }
01297             }
01298             mi = rpmmiFree(mi);
01299         }
01300         if (Flags & RPMSENSE_MISSINGOK)
01301             goto unsatisfied;
01302         rpmdsNotify(dep, _("(vcheck probe)"), rc);
01303         goto exit;
01304     }
01305 
01306     /* Search system configured provides. */
01307     if (sysinfo_path == NULL) {
01308         sysinfo_path = rpmExpand("%{?_rpmds_sysinfo_path}", NULL);
01309         if (!(sysinfo_path != NULL && *sysinfo_path == '/')) {
01310             sysinfo_path = _free(sysinfo_path);
01311             sysinfo_path = xstrdup(SYSCONFIGDIR "/sysinfo");
01312         }
01313     }
01314 
01315     if (!rpmioAccess(sysinfo_path, NULL, R_OK)) {
01316 #ifdef  NOTYET  /* XXX just sysinfo Provides: for now. */
01317         rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
01318 #else
01319         rpmTag tagN = RPMTAG_PROVIDENAME;
01320 #endif
01321         rpmds P = rpmdsFromPRCO(rpmtsPRCO(ts), tagN);
01322         if (rpmdsSearch(P, dep) >= 0) {
01323             rpmdsNotify(dep, _("(sysinfo provides)"), rc);
01324             goto exit;
01325         }
01326     }
01327 
01328     /*
01329      * New features in rpm packaging implicitly add versioned dependencies
01330      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
01331      * Check those dependencies now.
01332      */
01333     if (NSType == RPMNS_TYPE_RPMLIB) {
01334         static int oneshot = -1;
01335 
01336         if (oneshot)
01337             oneshot = rpmdsRpmlib(&rpmlibP, NULL);
01338         if (rpmlibP == NULL)
01339             goto unsatisfied;
01340 
01341         if (rpmdsSearch(rpmlibP, dep) >= 0) {
01342             rpmdsNotify(dep, _("(rpmlib provides)"), rc);
01343             goto exit;
01344         }
01345         goto unsatisfied;
01346     }
01347 
01348     if (NSType == RPMNS_TYPE_CPUINFO) {
01349         static int oneshot = -1;
01350 
01351         if (oneshot && cpuinfoP == NULL)
01352             oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
01353         if (cpuinfoP == NULL)
01354             goto unsatisfied;
01355 
01356         if (rpmdsSearch(cpuinfoP, dep) >= 0) {
01357             rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
01358             goto exit;
01359         }
01360         goto unsatisfied;
01361     }
01362 
01363     if (NSType == RPMNS_TYPE_GETCONF) {
01364         static int oneshot = -1;
01365 
01366         if (oneshot)
01367             oneshot = rpmdsGetconf(&getconfP, NULL);
01368         if (getconfP == NULL)
01369             goto unsatisfied;
01370 
01371         if (rpmdsSearch(getconfP, dep) >= 0) {
01372             rpmdsNotify(dep, _("(getconf provides)"), rc);
01373             goto exit;
01374         }
01375         goto unsatisfied;
01376     }
01377 
01378     if (NSType == RPMNS_TYPE_UNAME) {
01379         static int oneshot = -1;
01380 
01381         if (oneshot)
01382             oneshot = rpmdsUname(&unameP, NULL);
01383         if (unameP == NULL)
01384             goto unsatisfied;
01385 
01386         if (rpmdsSearch(unameP, dep) >= 0) {
01387             rpmdsNotify(dep, _("(uname provides)"), rc);
01388             goto exit;
01389         }
01390         goto unsatisfied;
01391     }
01392 
01393     if (NSType == RPMNS_TYPE_SONAME) {
01394         rpmds sonameP = NULL;
01395         rpmPRCO PRCO = rpmdsNewPRCO(NULL);
01396         char * fn = strcpy(alloca(strlen(Name)+1), Name);
01397         int flags = 0;  /* XXX RPMELF_FLAG_SKIPREQUIRES? */
01398         rpmds ds;
01399 
01400         /* XXX Only absolute paths for now. */
01401         if (*fn != '/')
01402             goto unsatisfied;
01403         fn[strlen(fn)-1] = '\0';
01404 
01405         /* Extract ELF Provides: from /path/to/DSO. */
01406         xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
01407         sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
01408         if (!(xx == 0 && sonameP != NULL))
01409             goto unsatisfied;
01410 
01411         /* Search using the original {EVR,"",Flags} from the dep set. */
01412         ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
01413         xx = rpmdsSearch(sonameP, ds);
01414         (void)rpmdsFree(ds);
01415         ds = NULL;
01416         PRCO = rpmdsFreePRCO(PRCO);
01417 
01418         /* Was the dependency satisfied? */
01419         if (xx >= 0) {
01420             rpmdsNotify(dep, _("(soname provides)"), rc);
01421             goto exit;
01422         }
01423         goto unsatisfied;
01424     }
01425 
01426     /* Search added packages for the dependency. */
01427     if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
01428 #if defined(CACHE_DEPENDENCY_RESULT)
01429         /*
01430          * XXX Ick, context sensitive answers from dependency cache.
01431          * XXX Always resolve added dependencies within context to disambiguate.
01432          */
01433         if (_rpmds_nopromote)
01434             _cacheThisRC = 0;
01435 #endif
01436         goto exit;
01437     }
01438 
01439     /* XXX only the installer does not have the database open here. */
01440     if (rpmtsGetRdb(ts) != NULL) {
01441         /* XXX Always satisfy Requires: /, SuSE (others?) doesn't package "/" */
01442         if (Name[0] == '/' && Name[1] == '\0') {
01443             rpmdsNotify(dep, _("(root files)"), rc);
01444             goto exit;
01445         }
01446         if (Name[0] == '/') {
01447             /* depFlags better be 0! */
01448 
01449             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
01450             (void) rpmmiPrune(mi,
01451                         ts->removedPackages, ts->numRemovedPackages, 1);
01452             while ((h = rpmmiNext(mi)) != NULL) {
01453                 rpmdsNotify(dep, _("(db files)"), rc);
01454                 mi = rpmmiFree(mi);
01455                 goto exit;
01456             }
01457             mi = rpmmiFree(mi);
01458         }
01459 
01460         mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
01461         (void) rpmmiPrune(mi,
01462                         ts->removedPackages, ts->numRemovedPackages, 1);
01463         while ((h = rpmmiNext(mi)) != NULL) {
01464             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
01465                 rpmdsNotify(dep, _("(db provides)"), rc);
01466                 mi = rpmmiFree(mi);
01467                 goto exit;
01468             }
01469         }
01470         mi = rpmmiFree(mi);
01471     }
01472 
01473     /*
01474      * Search for an unsatisfied dependency.
01475      */
01476     if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
01477         if (ts->solve != NULL) {
01478             xx = (*ts->solve) (ts, dep, ts->solveData);
01479             if (xx == 0)
01480                 goto exit;
01481             if (xx == -1) {
01482                 retries--;
01483                 rpmalMakeIndex(ts->addedPackages);
01484                 goto retry;
01485             }
01486         }
01487     }
01488 
01489 unsatisfied:
01490     if (Flags & RPMSENSE_MISSINGOK) {
01491         rc = 0; /* dependency is unsatisfied, but just a hint. */
01492 #if defined(CACHE_DEPENDENCY_RESULT)
01493         _cacheThisRC = 0;
01494 #endif
01495         rpmdsNotify(dep, _("(hint skipped)"), rc);
01496     } else {
01497         rc = 1; /* dependency is unsatisfied */
01498         rpmdsNotify(dep, NULL, rc);
01499     }
01500 
01501 exit:
01502     /*
01503      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01504      */
01505 #if defined(CACHE_DEPENDENCY_RESULT)
01506     if (_cacheDependsRC && _cacheThisRC) {
01507         dbiIndex dbi;
01508         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
01509         if (dbi == NULL) {
01510             _cacheDependsRC = 0;
01511         } else {
01512             const char * DNEVR;
01513             xx = 0;
01514             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
01515                 DBC * dbcursor = NULL;
01516                 size_t DNEVRlen = strlen(DNEVR);
01517 
01518                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
01519 
01520                 memset(key, 0, sizeof(*key));
01521 /*@i@*/         key->data = (void *) DNEVR;
01522                 key->size = DNEVRlen;
01523                 memset(data, 0, sizeof(*data));
01524                 data->data = &rc;
01525                 data->size = sizeof(rc);
01526 
01527                 /*@-compmempass@*/
01528                 xx = dbiPut(dbi, dbcursor, key, data, 0);
01529                 /*@=compmempass@*/
01530                 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
01531             }
01532             if (xx)
01533                 _cacheDependsRC = 0;
01534         }
01535     }
01536 #endif
01537 
01538     return rpmdsNegateRC(dep, rc);
01539 }
01540 
01554 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
01555                 /*@null@*/ rpmds requires,
01556                 /*@null@*/ rpmds conflicts,
01557                 /*@null@*/ rpmds dirnames,
01558                 /*@null@*/ rpmds linktos,
01559                 /*@null@*/ const char * depName,
01560                 rpmuint32_t tscolor, int adding)
01561         /*@globals rpmGlobalMacroContext, h_errno,
01562                 fileSystem, internalState @*/
01563         /*@modifies ts, requires, conflicts, dirnames, linktos,
01564                 rpmGlobalMacroContext, fileSystem, internalState */
01565 {
01566     rpmps ps = rpmtsProblems(ts);
01567     rpmuint32_t dscolor;
01568     const char * Name;
01569     int terminate = 2;          /* XXX terminate if rc >= terminate */
01570     int rc;
01571     int ourrc = 0;
01572 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) || defined(RPM_VENDOR_OPENMAMBA) || defined(RPM_OPTIONAL_DIRNAME_AND_SYMLINK_DEPS) /* optional-dirname-and-symlink-deps */
01573     int dirname_deps;
01574     int symlink_deps;
01575 #endif
01576 
01577     requires = rpmdsInit(requires);
01578     if (requires != NULL)
01579     while (ourrc < terminate && rpmdsNext(requires) >= 0) {
01580 
01581         if ((Name = rpmdsN(requires)) == NULL)
01582             continue;   /* XXX can't happen */
01583 
01584         /* Filter out requires that came along for the ride. */
01585         if (depName != NULL && strcmp(depName, Name))
01586             continue;
01587 
01588         /* Ignore colored requires not in our rainbow. */
01589         dscolor = rpmdsColor(requires);
01590         if (tscolor && dscolor && !(tscolor & dscolor))
01591             continue;
01592 
01593         rc = unsatisfiedDepend(ts, requires, adding);
01594 
01595         switch (rc) {
01596         case 0:         /* requirements are satisfied. */
01597             /*@switchbreak@*/ break;
01598         case 1:         /* requirements are not satisfied. */
01599         {   fnpyKey * suggestedKeys = NULL;
01600 
01601             if (ts->availablePackages != NULL) {
01602                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01603                                 requires, NULL);
01604             }
01605 
01606             rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding);
01607 
01608         }
01609             ourrc = 1;
01610             /*@switchbreak@*/ break;
01611         case 2:         /* something went wrong! */
01612         default:
01613             ourrc = 2;
01614             /*@switchbreak@*/ break;
01615         }
01616     }
01617 
01618     conflicts = rpmdsInit(conflicts);
01619     if (conflicts != NULL)
01620     while (ourrc < terminate && rpmdsNext(conflicts) >= 0) {
01621 
01622         if ((Name = rpmdsN(conflicts)) == NULL)
01623             continue;   /* XXX can't happen */
01624 
01625         /* Filter out conflicts that came along for the ride. */
01626         if (depName != NULL && strcmp(depName, Name))
01627             continue;
01628 
01629         /* Ignore colored conflicts not in our rainbow. */
01630         dscolor = rpmdsColor(conflicts);
01631         if (tscolor && dscolor && !(tscolor & dscolor))
01632             continue;
01633 
01634         rc = unsatisfiedDepend(ts, conflicts, adding);
01635 
01636         /* 1 == unsatisfied, 0 == satsisfied */
01637         switch (rc) {
01638         case 0:         /* conflicts exist. */
01639             rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding);
01640             ourrc = 1;
01641             /*@switchbreak@*/ break;
01642         case 1:         /* conflicts don't exist. */
01643             /*@switchbreak@*/ break;
01644         case 2:         /* something went wrong! */
01645         default:
01646             ourrc = 2;
01647             /*@switchbreak@*/ break;
01648         }
01649     }
01650 
01651 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) || defined(RPM_VENDOR_OPENMAMBA) || defined(RPM_OPTIONAL_DIRNAME_AND_SYMLINK_DEPS) /* optional-dirname-and-symlink-deps */
01652     dirname_deps = rpmExpandNumeric("%{?_check_dirname_deps}%{?!_check_dirname_deps:1}");
01653     if (dirname_deps) {
01654 #endif
01655     dirnames = rpmdsInit(dirnames);
01656     if (dirnames != NULL)
01657     while (ourrc < terminate && rpmdsNext(dirnames) >= 0) {
01658 
01659         if ((Name = rpmdsN(dirnames)) == NULL)
01660             continue;   /* XXX can't happen */
01661 
01662         /* Filter out dirnames that came along for the ride. */
01663         if (depName != NULL && strcmp(depName, Name))
01664             continue;
01665 
01666         /* Ignore colored dirnames not in our rainbow. */
01667         dscolor = rpmdsColor(dirnames);
01668         if (tscolor && dscolor && !(tscolor & dscolor))
01669             continue;
01670 
01671         rc = unsatisfiedDepend(ts, dirnames, adding);
01672 
01673         switch (rc) {
01674         case 0:         /* requirements are satisfied. */
01675             /*@switchbreak@*/ break;
01676         case 1:         /* requirements are not satisfied. */
01677         {   fnpyKey * suggestedKeys = NULL;
01678 
01679             if (ts->availablePackages != NULL) {
01680                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01681                                 dirnames, NULL);
01682             }
01683 
01684             rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding);
01685 
01686         }
01687             ourrc = 1;
01688             /*@switchbreak@*/ break;
01689         case 2:         /* something went wrong! */
01690         default:
01691             ourrc = 2;
01692             /*@switchbreak@*/ break;
01693         }
01694     }
01695 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) || defined(RPM_VENDOR_OPENMAMBA) || defined(RPM_OPTIONAL_DIRNAME_AND_SYMLINK_DEPS) /* optional-dirname-and-symlink-deps */
01696     }
01697 
01698     symlink_deps = rpmExpandNumeric("%{?_check_symlink_deps}%{?!_check_symlink_deps:1}");
01699     if (symlink_deps) {
01700 #endif
01701     linktos = rpmdsInit(linktos);
01702     if (linktos != NULL)
01703     while (ourrc < terminate && rpmdsNext(linktos) >= 0) {
01704 
01705         if ((Name = rpmdsN(linktos)) == NULL)
01706             continue;   /* XXX can't happen */
01707         if (*Name == '\0')      /* XXX most linktos are empty */
01708                 continue;
01709 
01710         /* Filter out linktos that came along for the ride. */
01711         if (depName != NULL && strcmp(depName, Name))
01712             continue;
01713 
01714         /* Ignore colored linktos not in our rainbow. */
01715         dscolor = rpmdsColor(linktos);
01716         if (tscolor && dscolor && !(tscolor & dscolor))
01717             continue;
01718 
01719         rc = unsatisfiedDepend(ts, linktos, adding);
01720 
01721         switch (rc) {
01722         case 0:         /* requirements are satisfied. */
01723             /*@switchbreak@*/ break;
01724         case 1:         /* requirements are not satisfied. */
01725         {   fnpyKey * suggestedKeys = NULL;
01726 
01727             if (ts->availablePackages != NULL) {
01728                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01729                                 linktos, NULL);
01730             }
01731 
01732             rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding);
01733 
01734         }
01735             ourrc = 1;
01736             /*@switchbreak@*/ break;
01737         case 2:         /* something went wrong! */
01738         default:
01739             ourrc = 2;
01740             /*@switchbreak@*/ break;
01741         }
01742     }
01743 #if defined(RPM_VENDOR_MANDRIVA) || defined(RPM_VENDOR_ARK) || defined(RPM_VENDOR_OPENMAMBA) || defined(RPM_OPTIONAL_DIRNAME_AND_SYMLINK_DEPS) /* optional-dirname-and-symlink-deps */
01744     }
01745 #endif    
01746 
01747     ps = rpmpsFree(ps);
01748     return ourrc;
01749 }
01750 
01761 static int checkPackageSet(rpmts ts, const char * depName,
01762                 /*@only@*/ /*@null@*/ rpmmi mi, int adding)
01763         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01764         /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
01765 {
01766     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01767     rpmdepFlags depFlags = rpmtsDFlags(ts);
01768     rpmuint32_t tscolor = rpmtsColor(ts);
01769     int scareMem = 0;
01770     Header h;
01771     int terminate = 2;          /* XXX terminate if rc >= terminate */
01772     int ourrc = 0;
01773 
01774     (void) rpmmiPrune(mi,
01775                 ts->removedPackages, ts->numRemovedPackages, 1);
01776     while (ourrc < terminate && (h = rpmmiNext(mi)) != NULL) {
01777         rpmds requires = NULL;
01778         rpmds conflicts = NULL;
01779         rpmds dirnames = NULL;
01780         rpmds linktos = NULL;
01781         int rc;
01782 
01783         he->tag = RPMTAG_NVRA;
01784         rc = (headerGet(h, he, 0) ? 0 : 2);
01785         if (rc > ourrc)
01786             ourrc = rc;
01787         if (ourrc >= terminate) {
01788             he->p.str = _free(he->p.str);
01789             break;
01790         }
01791 
01792         if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES))
01793             requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
01794         if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS))
01795             conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
01796         if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS))
01797             dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem);
01798         if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS))
01799             linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem);
01800 
01801         (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
01802         (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
01803         (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote);
01804         (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote);
01805 
01806         rc = checkPackageDeps(ts, he->p.str,
01807                 requires, conflicts, dirnames, linktos,
01808                 depName, tscolor, adding);
01809 
01810         (void)rpmdsFree(linktos);
01811         linktos = NULL;
01812         (void)rpmdsFree(dirnames);
01813         dirnames = NULL;
01814         (void)rpmdsFree(conflicts);
01815         conflicts = NULL;
01816         (void)rpmdsFree(requires);
01817         requires = NULL;
01818         he->p.str = _free(he->p.str);
01819 
01820         if (rc > ourrc)
01821             ourrc = rc;
01822     }
01823     mi = rpmmiFree(mi);
01824 
01825     return ourrc;
01826 }
01827 
01834 static int checkDependentPackages(rpmts ts, const char * depName)
01835         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01836         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01837 {
01838     int rc = 0;
01839 
01840     /* XXX rpmdb can be closed here, avoid error msg. */
01841     if (rpmtsGetRdb(ts) != NULL) {
01842         rpmmi mi;
01843         mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0);
01844         rc = checkPackageSet(ts, depName, mi, 0);
01845     }
01846     return rc;
01847 }
01848 
01855 static int checkDependentConflicts(rpmts ts, const char * depName)
01856         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01857         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01858 {
01859     int rc = 0;
01860 
01861     /* XXX rpmdb can be closed here, avoid error msg. */
01862     if (rpmtsGetRdb(ts) != NULL) {
01863         rpmmi mi;
01864         mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0);
01865         rc = checkPackageSet(ts, depName, mi, 1);
01866     }
01867 
01868     return rc;
01869 }
01870 
01871 int _rpmtsCheck(rpmts ts)
01872 {
01873     const char * depName = NULL;
01874     rpmdepFlags depFlags = rpmtsDFlags(ts);
01875     rpmuint32_t tscolor = rpmtsColor(ts);
01876     rpmmi mi = NULL;
01877     rpmtsi pi = NULL; rpmte p;
01878     int closeatexit = 0;
01879     int xx;
01880     int terminate = 2;          /* XXX terminate if rc >= terminate */
01881     int rc = 0;
01882     int ourrc = 0;
01883 
01884 if (_rpmts_debug)
01885 fprintf(stderr, "--> %s(%p) tsFlags 0x%x\n", __FUNCTION__, ts, rpmtsFlags(ts));
01886 
01887     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01888 
01889     /* Do lazy, readonly, open of rpm database. */
01890     if (rpmtsGetRdb(ts) == NULL && rpmtsDBMode(ts) != -1) {
01891         rc = (rpmtsOpenDB(ts, rpmtsDBMode(ts)) ? 2 : 0);
01892         closeatexit = (rc == 0);
01893     }
01894     if (rc && (ourrc = rc) >= terminate)
01895         goto exit;
01896 
01897     ts->probs = rpmpsFree(ts->probs);
01898 
01899     rpmalMakeIndex(ts->addedPackages);
01900 
01901     /*
01902      * Look at all of the added packages and make sure their dependencies
01903      * are satisfied.
01904      */
01905     pi = rpmtsiInit(ts);
01906     while (ourrc < terminate && (p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01907         rpmds provides, requires, conflicts, dirnames, linktos;
01908         rpmfi fi;
01909 
01910 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01911         rpmlog(RPMLOG_DEBUG, "========== +++ %s %s/%s 0x%x\n",
01912                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01913 /*@=nullpass@*/
01914         requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)
01915             ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL);
01916         conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)
01917             ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL);
01918         /* XXX srpm's don't have directory paths. */
01919         if (p->isSource) {
01920             dirnames = NULL;
01921             linktos = NULL;
01922         } else {
01923             dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)
01924                 ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL);
01925             linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)
01926                 ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL);
01927         }
01928 
01929         rc = checkPackageDeps(ts, rpmteNEVRA(p),
01930                         requires, conflicts, dirnames, linktos,
01931                         NULL, tscolor, 1);
01932         if (rc && (ourrc = rc) >= terminate)
01933             break;
01934 
01935         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01936         provides = rpmdsInit(provides);
01937         if (provides != NULL)
01938         while (ourrc < terminate && rpmdsNext(provides) >= 0) {
01939             depName = _free(depName);
01940             depName = xstrdup(rpmdsN(provides));
01941 
01942 #ifdef  NOTYET
01943             if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) {
01944                 const char * EVR = rpmdsEVR(provides);
01945                 if (rpmdsNegateRC(provides, 0))
01946                     EVR = NULL;
01947                 if (envPut(depName, EVR));
01948                     rc = 2;
01949             } else
01950 #endif
01951 
01952             /* Adding: check provides key against conflicts matches. */
01953             if (checkDependentConflicts(ts, depName))
01954                 rc = 1;
01955         }
01956         if (rc && (ourrc = rc) >= terminate)
01957             break;
01958 
01959         fi = rpmteFI(p, RPMTAG_BASENAMES);
01960         fi = rpmfiInit(fi, 0);
01961         while (ourrc < terminate && rpmfiNext(fi) >= 0) {
01962             depName = _free(depName);
01963             depName = xstrdup(rpmfiFN(fi));
01964             /* Adding: check filename against conflicts matches. */
01965             if (checkDependentConflicts(ts, depName))
01966                 rc = 1;
01967         }
01968         if (rc && (ourrc = rc) >= terminate)
01969             break;
01970     }
01971     pi = rpmtsiFree(pi);
01972     if (rc && (ourrc = rc) >= terminate)
01973         goto exit;
01974 
01975     /*
01976      * Look at the removed packages and make sure they aren't critical.
01977      */
01978     pi = rpmtsiInit(ts);
01979     while (ourrc < terminate && (p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01980         rpmds provides;
01981         rpmfi fi;
01982 
01983 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01984         rpmlog(RPMLOG_DEBUG, "========== --- %s %s/%s 0x%x\n",
01985                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01986 /*@=nullpass@*/
01987 
01988         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01989         provides = rpmdsInit(provides);
01990         if (provides != NULL)
01991         while (ourrc < terminate && rpmdsNext(provides) >= 0) {
01992             depName = _free(depName);
01993             depName = xstrdup(rpmdsN(provides));
01994 
01995             /* Erasing: check provides against requiredby matches. */
01996             if (checkDependentPackages(ts, depName))
01997                 rc = 1;
01998         }
01999         if (rc && (ourrc = rc) >= terminate)
02000             break;
02001 
02002         fi = rpmteFI(p, RPMTAG_BASENAMES);
02003         fi = rpmfiInit(fi, 0);
02004         while (ourrc < terminate && rpmfiNext(fi) >= 0) {
02005             depName = _free(depName);
02006             depName = xstrdup(rpmfiFN(fi));
02007             /* Erasing: check filename against requiredby matches. */
02008             if (checkDependentPackages(ts, depName))
02009                 rc = 1;
02010         }
02011         if (rc && (ourrc = rc) >= terminate)
02012             break;
02013     }
02014     pi = rpmtsiFree(pi);
02015     if (rc && (ourrc = rc) >= terminate)
02016         goto exit;
02017 
02018     /*
02019      * Make sure transaction dependencies are satisfied.
02020      */
02021     {   const char * tsNEVRA = "transaction dependencies";
02022         rpmds R = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_REQUIRENAME);
02023         rpmds C = rpmdsFromPRCO(rpmtsPRCO(ts), RPMTAG_CONFLICTNAME);
02024         rpmds D = NULL;
02025         rpmds L = NULL;
02026         const char * dep = NULL;
02027         int adding = 2;
02028         tscolor = 0;    /* XXX no coloring for transaction dependencies. */
02029         rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding);
02030     }
02031     if (rc && (ourrc = rc) >= terminate)
02032         goto exit;
02033 
02034 exit:
02035     mi = rpmmiFree(mi);
02036     pi = rpmtsiFree(pi);
02037     depName = _free(depName);
02038 
02039     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02040 
02041     if (closeatexit)
02042         xx = rpmtsCloseDB(ts);
02043 #if defined(CACHE_DEPENDENCY_RESULT)
02044     else if (_cacheDependsRC)
02045         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
02046 #endif
02047 
02048 #ifdef  NOTYET
02049      /* On failed dependencies, perform the autorollback goal (if any). */
02050     {   rpmps ps = rpmtsProblems(ts);
02051         if (rc || rpmpsNumProblems(ps) > 0)
02052             (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02053         ps = rpmpsFree(ps);
02054     }
02055 #endif
02056 
02057     return ourrc;
02058 }
02059 
02060 int (*rpmtsCheck) (rpmts ts)
02061         = _rpmtsCheck;