lib/depends.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmio_internal.h"     /* XXX PGPHASHALGO_MD5 */
00008 #include <rpmcli.h>             /* XXX rpmcliPackagesTotal */
00009 
00010 #include <rpmmacro.h>           /* XXX rpmExpand("%{_dependency_whiteout}" */
00011 #include <envvar.h>
00012 #include <ugid.h>               /* XXX user()/group() probes */
00013 
00014 #define _RPMDB_INTERNAL         /* XXX response cache needs dbiOpen et al. */
00015 #include "rpmdb.h"
00016 
00017 #define _RPMEVR_INTERNAL
00018 #include "rpmds.h"
00019 #include "rpmfi.h"
00020 
00021 #define _RPMTE_INTERNAL
00022 #include "rpmte.h"
00023 
00024 #define _RPMTS_INTERNAL
00025 #include "rpmts.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 /*@unchecked@*/
00050 int _cacheDependsRC = 1;
00051 
00052 /*@observer@*/ /*@unchecked@*/
00053 const char *rpmNAME = PACKAGE;
00054 
00055 /*@observer@*/ /*@unchecked@*/
00056 const char *rpmEVR = VERSION;
00057 
00058 /*@unchecked@*/
00059 int rpmFLAGS = RPMSENSE_EQUAL;
00060 
00067 static int intcmp(const void * a, const void * b)
00068         /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
00069 {
00070     const int * aptr = a;
00071     const int * bptr = b;
00072     int rc = (*aptr - *bptr);
00073     return rc;
00074 }
00075 
00085 static int removePackage(rpmts ts, Header h, int dboffset,
00086                 /*@null@*/ int * indexp,
00087                 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
00088         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00089         /*@modifies ts, h, *indexp, rpmGlobalMacroContext, fileSystem, internalState @*/
00090 {
00091     rpmte p;
00092 
00093     /* Filter out duplicate erasures. */
00094     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00095         int * needle = NULL;
00096 /*@-boundswrite@*/
00097         needle = bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00098                         sizeof(*ts->removedPackages), intcmp);
00099         if (needle != NULL) {
00100             /* XXX lastx should be per-call, not per-ts. */
00101             if (indexp != NULL)
00102                 *indexp = needle - ts->removedPackages;
00103             return 0;
00104         }
00105 /*@=boundswrite@*/
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 /*@-boundswrite@*/
00116         ts->removedPackages[ts->numRemovedPackages] = dboffset;
00117         ts->numRemovedPackages++;
00118 /*@=boundswrite@*/
00119         if (ts->numRemovedPackages > 1)
00120             qsort(ts->removedPackages, ts->numRemovedPackages,
00121                         sizeof(*ts->removedPackages), intcmp);
00122     }
00123 
00124     if (ts->orderCount >= ts->orderAlloced) {
00125         ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
00126 /*@-type +voidabstract @*/
00127         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00128 /*@=type =voidabstract @*/
00129     }
00130 
00131     p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
00132 /*@-boundswrite@*/
00133     ts->order[ts->orderCount] = p;
00134     if (indexp != NULL)
00135         *indexp = ts->orderCount;
00136     ts->orderCount++;
00137 /*@=boundswrite@*/
00138 
00139 /*@-nullstate@*/        /* XXX FIX: ts->order[] can be NULL. */
00140    return 0;
00141 /*@=nullstate@*/
00142 }
00143 
00150 static int rpmHeadersIdentical(Header first, Header second)
00151         /*@*/
00152 {
00153     const char * one, * two;
00154     rpmds A, B;
00155     int rc;
00156 
00157     if (!headerGetEntry(first, RPMTAG_HDRID, NULL, (void **) &one, NULL))
00158         one = NULL;
00159     if (!headerGetEntry(second, RPMTAG_HDRID, NULL, (void **) &two, NULL))
00160         two = NULL;
00161 
00162     if (one && two)
00163         return ((strcmp(one, two) == 0) ? 1 : 0);
00164     if (one && !two)
00165         return 0;
00166     if (!one && two)
00167         return 0;
00168     /* XXX Headers w/o digests case devolves to NEVR comparison. */
00169     A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00170     B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00171     rc = rpmdsCompare(A, B);
00172     A = rpmdsFree(A);
00173     B = rpmdsFree(B);
00174     return rc;
00175 }
00176 
00177 int rpmtsAddInstallElement(rpmts ts, Header h,
00178                         fnpyKey key, int upgrade, rpmRelocation relocs)
00179 {
00180     rpmdepFlags depFlags = rpmtsDFlags(ts);
00181     uint_32 tscolor = rpmtsColor(ts);
00182     uint_32 dscolor;
00183     uint_32 hcolor;
00184     rpmdbMatchIterator mi;
00185     Header oh;
00186     uint_32 ohcolor;
00187     int isSource;
00188     int duplicate = 0;
00189     rpmtsi pi = NULL; rpmte p;
00190     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00191     const char * arch;
00192     const char * os;
00193     rpmds oldChk, newChk;
00194     rpmds obsoletes;
00195     alKey pkgKey;       /* addedPackages key */
00196     int xx;
00197     int ec = 0;
00198     int rc;
00199     int oc;
00200 
00201     hcolor = hGetColor(h);
00202     pkgKey = RPMAL_NOMATCH;
00203 
00204     /*
00205      * Always add source headers.
00206      */
00207     isSource = (headerIsEntry(h, RPMTAG_SOURCERPM) == 0) ;
00208     if (isSource) {
00209         oc = ts->orderCount;
00210         goto addheader;
00211     }
00212 
00213     /*
00214      * Check platform affinity of binary packages.
00215      */
00216     arch = NULL;
00217     xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
00218     os = NULL;
00219     xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
00220     if (nplatpat > 1) {
00221         const char * platform = NULL;
00222 
00223         if (hge(h, RPMTAG_PLATFORM, NULL, (void **)&platform, NULL))
00224             platform = xstrdup(platform);
00225         else
00226             platform = rpmExpand(arch, "-unknown-", os, NULL);
00227 
00228         rc = rpmPlatformScore(platform, platpat, nplatpat);
00229         if (rc <= 0) {
00230             const char * pkgNEVR = hGetNEVRA(h, NULL);
00231             rpmps ps = rpmtsProblems(ts);
00232             rpmpsAppend(ps, RPMPROB_BADPLATFORM, pkgNEVR, key,
00233                         platform, NULL, NULL, 0);
00234             ps = rpmpsFree(ps);
00235             pkgNEVR = _free(pkgNEVR);
00236             ec = 1;
00237         }
00238         platform = _free(platform);
00239         if (ec)
00240             goto exit;
00241     }
00242 
00243     /*
00244      * Always install compatible binary packages.
00245      */
00246     if (!upgrade) {
00247         oc = ts->orderCount;
00248         goto addheader;
00249     }
00250 
00251     /*
00252      * Check that upgrade package is uniquely newer, replace older if necessary.
00253      */
00254     oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
00255     newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
00256     /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */
00257     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00258         rpmds this;
00259 
00260         /* XXX Only added packages need be checked for dupes here. */
00261         if (rpmteType(p) == TR_REMOVED)
00262             continue;
00263 
00264         /* XXX Never check source header NEVRAO. */
00265         if (rpmteIsSource(p))
00266             continue;
00267 
00268         if (tscolor) {
00269             const char * parch;
00270             const char * pos;
00271 
00272             if (arch == NULL || (parch = rpmteA(p)) == NULL)
00273                 continue;
00274             /* XXX hackery for i[3456]86 alias matching. */
00275             if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00276                 if (arch[0] != parch[0]) continue;
00277                 if (arch[2] != parch[2]) continue;
00278                 if (arch[3] != parch[3]) continue;
00279             } else if (strcmp(arch, parch))
00280                 continue;
00281             if (os == NULL || (pos = rpmteO(p)) == NULL)
00282                 continue;
00283 
00284             if (strcmp(os, pos))
00285                 continue;
00286         }
00287 
00288         /* OK, binary rpm's with same arch and os.  Check NEVR. */
00289         if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
00290             continue;   /* XXX can't happen */
00291 
00292         /* If newer NEVRAO already added, then skip adding older. */
00293         rc = rpmdsCompare(newChk, this);
00294         if (rc != 0) {
00295             const char * pkgNEVR = rpmdsDNEVR(this);
00296             const char * addNEVR = rpmdsDNEVR(oldChk);
00297             if (rpmIsVerbose())
00298                 rpmMessage(RPMMESS_WARNING,
00299                     _("package %s was already added, skipping %s\n"),
00300                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00301                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00302             ec = 1;
00303             break;
00304         }
00305 
00306         /* If older NEVRAO already added, then replace old with new. */
00307         rc = rpmdsCompare(oldChk, this);
00308         if (rc != 0) {
00309             const char * pkgNEVR = rpmdsDNEVR(this);
00310             const char * addNEVR = rpmdsDNEVR(newChk);
00311             if (rpmIsVerbose())
00312                 rpmMessage(RPMMESS_WARNING,
00313                     _("package %s was already added, replacing with %s\n"),
00314                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00315                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00316             duplicate = 1;
00317             pkgKey = rpmteAddedKey(p);
00318             break;
00319         }
00320     }
00321     pi = rpmtsiFree(pi);
00322     oldChk = rpmdsFree(oldChk);
00323     newChk = rpmdsFree(newChk);
00324 
00325     /* If newer (or same) NEVRAO was already added, exit now. */
00326     if (ec)
00327         goto exit;
00328 
00329 addheader:
00330     if (oc >= ts->orderAlloced) {
00331         ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
00332 /*@-type +voidabstract @*/
00333         ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
00334 /*@=type =voidabstract @*/
00335     }
00336 
00337     p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
00338 assert(p != NULL);
00339 
00340     if (duplicate && oc < ts->orderCount) {
00341 /*@-type -unqualifiedtrans@*/
00342 /*@-boundswrite@*/
00343         ts->order[oc] = rpmteFree(ts->order[oc]);
00344 /*@=boundswrite@*/
00345 /*@=type =unqualifiedtrans@*/
00346     }
00347 
00348 /*@-boundswrite@*/
00349     ts->order[oc] = p;
00350 /*@=boundswrite@*/
00351     if (!duplicate) {
00352         ts->orderCount++;
00353         rpmcliPackagesTotal++;
00354     }
00355     
00356     pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
00357                         rpmteDS(p, RPMTAG_PROVIDENAME),
00358                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
00359     if (pkgKey == RPMAL_NOMATCH) {
00360 /*@-boundswrite@*/
00361         ts->order[oc] = rpmteFree(ts->order[oc]);
00362 /*@=boundswrite@*/
00363         ts->teInstall = NULL;
00364         ec = 1;
00365         goto exit;
00366     }
00367     (void) rpmteSetAddedKey(p, pkgKey);
00368 
00369     if (!duplicate) {
00370         ts->numAddedPackages++;
00371     }
00372 
00373     ts->teInstall = ts->order[oc];
00374 
00375     /* XXX rpmgi hack: Save header in transaction element if requested. */
00376     if (upgrade & 0x2)
00377         (void) rpmteSetHeader(p, h);
00378 
00379     /* If not upgrading, then we're done. */
00380     if (!(upgrade & 0x1))
00381         goto exit;
00382 
00383     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00384     if (isSource)
00385         goto exit;
00386 
00387     /* Do lazy (readonly?) open of rpm database. */
00388     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
00389         if ((ec = rpmtsOpenDB(ts, ts->dbmode)) != 0)
00390             goto exit;
00391     }
00392 
00393     /* On upgrade, erase older packages of same color (if any). */
00394 
00395   if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) {
00396     mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, rpmteN(p), 0);
00397     while((oh = rpmdbNextIterator(mi)) != NULL) {
00398         int lastx;
00399         rpmte q;
00400 
00401         /* Ignore colored packages not in our rainbow. */
00402         ohcolor = hGetColor(oh);
00403         if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00404             continue;
00405 
00406         /* Skip identical packages. */
00407         if (rpmHeadersIdentical(h, oh))
00408             continue;
00409 
00410         /* Create an erasure element. */
00411         lastx = -1;
00412         xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), &lastx, pkgKey);
00413 assert(lastx >= 0 && lastx < ts->orderCount);
00414         q = ts->order[lastx];
00415 
00416         /* Chain through upgrade flink. */
00417         xx = rpmteChain(p, q, oh, "Upgrades");
00418 
00419 /*@-nullptrarith@*/
00420         rpmMessage(RPMMESS_DEBUG, _("   upgrade erases %s\n"), rpmteNEVRA(q));
00421 /*@=nullptrarith@*/
00422 
00423     }
00424     mi = rpmdbFreeIterator(mi);
00425   }
00426 
00427   if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) {
00428     obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
00429     obsoletes = rpmdsInit(obsoletes);
00430     if (obsoletes != NULL)
00431     while (rpmdsNext(obsoletes) >= 0) {
00432         const char * Name;
00433 
00434         if ((Name = rpmdsN(obsoletes)) == NULL)
00435             continue;   /* XXX can't happen */
00436 
00437         /* Ignore colored obsoletes not in our rainbow. */
00438 #if 0
00439         dscolor = rpmdsColor(obsoletes);
00440 #else
00441         dscolor = hcolor;
00442 #endif
00443         /* XXX obsoletes are never colored, so this is for future devel. */
00444         if (tscolor && dscolor && !(tscolor & dscolor))
00445             continue;
00446 
00447         /* XXX avoid self-obsoleting packages. */
00448         if (!strcmp(rpmteN(p), Name))
00449             continue;
00450 
00451         /* Obsolete containing package if given a file, otherwise provide. */
00452         if (Name[0] == '/')
00453             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00454         else
00455             mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00456 
00457         xx = rpmdbPruneIterator(mi,
00458             ts->removedPackages, ts->numRemovedPackages, 1);
00459 
00460         while((oh = rpmdbNextIterator(mi)) != NULL) {
00461             int lastx;
00462             rpmte q;
00463 
00464             /* Ignore colored packages not in our rainbow. */
00465             ohcolor = hGetColor(oh);
00466 
00467             /* XXX provides *are* colored, effectively limiting Obsoletes:
00468                 to matching only colored Provides: based on pkg coloring. */
00469             if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00470                 /*@innercontinue@*/ continue;
00471 
00472             /*
00473              * Rpm prior to 3.0.3 does not have versioned obsoletes.
00474              * If no obsoletes version info is available, match all names.
00475              */
00476             if (!(rpmdsEVR(obsoletes) == NULL
00477              || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)))
00478                 /*@innercontinue@*/ continue;
00479 
00480             /* Create an erasure element. */
00481             lastx = -1;
00482             xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), &lastx, pkgKey);
00483 assert(lastx >= 0 && lastx < ts->orderCount);
00484             q = ts->order[lastx];
00485 
00486             /* Chain through obsoletes flink. */
00487             xx = rpmteChain(p, q, oh, "Obsoletes");
00488 
00489 /*@-nullptrarith@*/
00490             rpmMessage(RPMMESS_DEBUG, _("  Obsoletes: %s\t\terases %s\n"),
00491                         rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q));
00492 /*@=nullptrarith@*/
00493         }
00494         mi = rpmdbFreeIterator(mi);
00495     }
00496     obsoletes = rpmdsFree(obsoletes);
00497   }
00498 
00499     ec = 0;
00500 
00501 exit:
00502     pi = rpmtsiFree(pi);
00503     return ec;
00504 }
00505 
00506 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
00507 {
00508     int oc = -1;
00509     int rc = removePackage(ts, h, dboffset, &oc, RPMAL_NOMATCH);
00510     if (rc == 0 && oc >= 0 && oc < ts->orderCount)
00511         ts->teErase = ts->order[oc];
00512     else
00513         ts->teErase = NULL;
00514     return rc;
00515 }
00516 
00524 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
00525         /*@globals _cacheDependsRC, rpmGlobalMacroContext, h_errno,
00526                 fileSystem, internalState @*/
00527         /*@modifies ts, dep, _cacheDependsRC, rpmGlobalMacroContext,
00528                 fileSystem, internalState @*/
00529 {
00530     DBT * key = alloca(sizeof(*key));
00531     DBT * data = alloca(sizeof(*data));
00532     rpmdbMatchIterator mi;
00533     nsType NSType;
00534     const char * Name;
00535     int_32 Flags;
00536     Header h;
00537     int _cacheThisRC = 1;
00538     int rc;
00539     int xx;
00540     int retries = 10;
00541 
00542     if ((Name = rpmdsN(dep)) == NULL)
00543         return 0;       /* XXX can't happen */
00544     Flags = rpmdsFlags(dep);
00545     NSType = rpmdsNSType(dep);
00546 
00547     /*
00548      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
00549      */
00550     if (_cacheDependsRC) {
00551         dbiIndex dbi;
00552         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00553         if (dbi == NULL)
00554             _cacheDependsRC = 0;
00555         else {
00556             const char * DNEVR;
00557 
00558             rc = -1;
00559 /*@-branchstate@*/
00560             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00561                 DBC * dbcursor = NULL;
00562                 void * datap = NULL;
00563                 size_t datalen = 0;
00564                 size_t DNEVRlen = strlen(DNEVR);
00565 
00566                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
00567 
00568                 memset(key, 0, sizeof(*key));
00569 /*@i@*/         key->data = (void *) DNEVR;
00570                 key->size = DNEVRlen;
00571                 memset(data, 0, sizeof(*data));
00572                 data->data = datap;
00573                 data->size = datalen;
00574 /*@-nullstate@*/ /* FIX: data->data may be NULL */
00575                 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
00576 /*@=nullstate@*/
00577                 DNEVR = key->data;
00578                 DNEVRlen = key->size;
00579                 datap = data->data;
00580                 datalen = data->size;
00581 
00582 /*@-boundswrite@*/
00583                 if (xx == 0 && datap && datalen == 4)
00584                     memcpy(&rc, datap, datalen);
00585 /*@=boundswrite@*/
00586                 xx = dbiCclose(dbi, dbcursor, 0);
00587             }
00588 /*@=branchstate@*/
00589 
00590             if (rc >= 0) {
00591                 rpmdsNotify(dep, _("(cached)"), rc);
00592                 return rpmdsNegateRC(dep, rc);
00593             }
00594         }
00595     }
00596 
00597 retry:
00598     rc = 0;     /* assume dependency is satisfied */
00599 
00600     /* Expand macro probe dependencies. */
00601     if (NSType == RPMNS_TYPE_FUNCTION) {
00602         xx = rpmExpandNumeric(Name);
00603         rc = (xx ? 0 : 1);
00604         if (Flags & RPMSENSE_MISSINGOK)
00605             goto unsatisfied;
00606         rpmdsNotify(dep, _("(function probe)"), rc);
00607         goto exit;
00608     }
00609 
00610     /* Evaluate user/group lookup probes. */
00611     if (NSType == RPMNS_TYPE_USER) {
00612         const char *s;
00613         uid_t uid = 0;
00614         s = Name; while (*s && xisdigit(*s)) s++;
00615 
00616         if (*s)
00617             xx = unameToUid(Name, &uid);
00618         else {
00619             uid = strtol(Name, NULL, 10);
00620             xx = (uidToUname(uid) ? 0 : -1);
00621         }
00622         rc = (xx >= 0 ? 0 : 1);
00623         if (Flags & RPMSENSE_MISSINGOK)
00624             goto unsatisfied;
00625         rpmdsNotify(dep, _("(user lookup)"), rc);
00626         goto exit;
00627     }
00628     if (NSType == RPMNS_TYPE_GROUP) {
00629         const char *s;
00630         gid_t gid = 0;
00631         s = Name; while (*s && xisdigit(*s)) s++;
00632 
00633         if (*s)
00634             xx = gnameToGid(Name, &gid);
00635         else {
00636             gid = strtol(Name, NULL, 10);
00637             xx = (gidToGname(gid) ? 0 : -1);
00638         }
00639         rc = (xx >= 0 ? 0 : 1);
00640         if (Flags & RPMSENSE_MISSINGOK)
00641             goto unsatisfied;
00642         rpmdsNotify(dep, _("(group lookup)"), rc);
00643         goto exit;
00644     }
00645 
00646     /* Evaluate access(2) probe dependencies. */
00647     if (NSType == RPMNS_TYPE_ACCESS) {
00648         rc = rpmioAccess(Name, NULL, X_OK);
00649         if (Flags & RPMSENSE_MISSINGOK)
00650             goto unsatisfied;
00651         rpmdsNotify(dep, _("(access probe)"), rc);
00652         goto exit;
00653     }
00654 
00655     /* Evaluate mtab lookup and diskspace probe dependencies. */
00656     if (NSType == RPMNS_TYPE_MOUNTED) {
00657         const char ** fs = NULL;
00658         int nfs = 0;
00659         int i = 0;
00660 
00661         xx = rpmtsInitDSI(ts);
00662         fs = ts->filesystems;
00663         nfs = ts->filesystemCount;
00664 
00665         if (fs != NULL)
00666         for (i = 0; i < nfs; i++) {
00667             if (!strcmp(fs[i], Name))
00668                 break;
00669         }
00670         rc = (i < nfs ? 0 : 1);
00671         if (Flags & RPMSENSE_MISSINGOK)
00672             goto unsatisfied;
00673         rpmdsNotify(dep, _("(mtab probe)"), rc);
00674         goto exit;
00675     }
00676 
00677     if (NSType == RPMNS_TYPE_DISKSPACE) {
00678         size_t nb = strlen(Name);
00679         rpmDiskSpaceInfo dsi = NULL;
00680         const char ** fs = NULL;
00681         size_t fslen = 0, longest = 0;
00682         int nfs = 0;
00683         int i = 0;
00684 
00685         xx = rpmtsInitDSI(ts);
00686         fs = ts->filesystems;
00687         nfs = ts->filesystemCount;
00688 
00689         if (fs != NULL)
00690         for (i = 0; i < nfs; i++) {
00691             fslen = strlen(fs[i]);
00692             if (fslen > nb)
00693                 continue;
00694             if (strncmp(fs[i], Name, fslen))
00695                 continue;
00696             if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0')
00697                 continue;
00698             if (fslen < longest)
00699                 continue;
00700             longest = fslen;
00701             dsi = ts->dsi + i;
00702         }
00703         if (dsi == NULL)
00704             rc = 1;     /* no mounted paths !?! */
00705         else {
00706             char * end = NULL;
00707             long long needed = strtoll(rpmdsEVR(dep), &end, 0);
00708 
00709             if (end && *end) {
00710                 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2])
00711                     needed *= 1024 * 1024 * 1024;
00712                 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2])
00713                     needed *= 1024 * 1024;
00714                 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2])
00715                     needed *= 1024;
00716             } else
00717                 needed *= 1024 * 1024;  /* XXX assume Mb if no units given */
00718 
00719             needed = BLOCK_ROUND(needed, dsi->f_bsize);
00720             xx = (dsi->f_bavail - needed);
00721             if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0;
00722             else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0;
00723             else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
00724             else rc = 1;
00725         }
00726         if (Flags & RPMSENSE_MISSINGOK)
00727             goto unsatisfied;
00728         rpmdsNotify(dep, _("(diskspace probe)"), rc);
00729         goto exit;
00730     }
00731 
00732     if (NSType == RPMNS_TYPE_DIGEST) {
00733         const char * EVR = rpmdsEVR(dep);
00734         FD_t fd = Fopen(Name, "r");
00735 
00736         rc = 1;         /* XXX assume failure */
00737         if (fd && !Ferror(fd)) {
00738             pgpHashAlgo digestHashAlgo = PGPHASHALGO_MD5;
00739             DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE);
00740             const char * digest = NULL;
00741             size_t digestlen = 0;
00742             int asAscii = 1;
00743             size_t nbuf = 8 * BUFSIZ;
00744             char * buf = alloca(nbuf);
00745             size_t nb;
00746 
00747             while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0)
00748                 xx = rpmDigestUpdate(ctx, buf, nb);
00749             xx = Fclose(fd);    fd = NULL;
00750             xx = rpmDigestFinal(ctx, (void **)&digest, &digestlen, asAscii);
00751 
00752             xx = (EVR && *EVR && digest && *digest) ? strcmp(EVR, digest) : -1;
00753             /* XXX only equality makes sense for digest compares */
00754             if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
00755         }
00756         if (Flags & RPMSENSE_MISSINGOK)
00757             goto unsatisfied;
00758         rpmdsNotify(dep, _("(digest probe)"), rc);
00759         goto exit;
00760     }
00761 
00762     if (NSType == RPMNS_TYPE_GNUPG) {
00763         static const char gnupg_pre[] = "%(%{__gpg} -qv ";
00764         static const char gnupg_post[] = " 2>/dev/null; echo $?)";
00765         const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
00766 
00767         rc = (t && t[0] == '0') ? 0 : 1;
00768         t = _free(t);
00769         if (Flags & RPMSENSE_MISSINGOK)
00770             goto unsatisfied;
00771         rpmdsNotify(dep, _("(gnupg probe)"), rc);
00772         goto exit;
00773     }
00774 
00775     if (NSType == RPMNS_TYPE_MACRO) {
00776         static const char macro_pre[] = "%{?";
00777         static const char macro_post[] = ":0}";
00778         const char * a = rpmExpand(macro_pre, Name, macro_post, NULL);
00779 
00780         rc = (a && a[0] == '0') ? 0 : 1;
00781         a = _free(a);
00782         if (Flags & RPMSENSE_MISSINGOK)
00783             goto unsatisfied;
00784         rpmdsNotify(dep, _("(macro probe)"), rc);
00785         goto exit;
00786     }
00787 
00788     if (NSType == RPMNS_TYPE_ENVVAR) {
00789         const char * a = envGet(Name);
00790         const char * b = rpmdsEVR(dep);
00791 
00792         /* Existence test if EVR is missing/empty. */
00793         if (!(b && *b))
00794             rc = (!(a && *a));
00795         else {
00796             int sense = (a && *a) ? strcmp(a, b) : -1;
00797 
00798             if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL)
00799                 rc = (sense == 0);
00800             else if (sense < 0 && (Flags & RPMSENSE_LESS))
00801                 rc = 0;
00802             else if (sense > 0 && (Flags & RPMSENSE_GREATER))
00803                 rc = 0;
00804             else if (sense == 0 && (Flags & RPMSENSE_EQUAL))
00805                 rc = 0;
00806             else
00807                 rc = (sense != 0);
00808         }
00809 
00810         if (Flags & RPMSENSE_MISSINGOK)
00811             goto unsatisfied;
00812         rpmdsNotify(dep, _("(envvar probe)"), rc);
00813         goto exit;
00814     }
00815 
00816     if (NSType == RPMNS_TYPE_RUNNING) {
00817         char *t = NULL;
00818         pid_t pid = strtol(Name, &t, 10);
00819 
00820         if (t == NULL || *t != '\0') {
00821             const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL);
00822             FD_t fd = NULL;
00823 
00824             if (fn && *fn != '%' && (fd = Fopen(fn, "r")) && !Ferror(fd)) {
00825                 char buf[32];
00826                 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
00827 
00828                 if (nb > 0)
00829                     pid = strtol(buf, &t, 10);
00830             } else
00831                 pid = 0;
00832             if (fd != NULL)
00833                 (void) Fclose(fd);
00834             fn = _free(fn);
00835         }
00836         rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1);
00837         if (Flags & RPMSENSE_MISSINGOK)
00838             goto unsatisfied;
00839         rpmdsNotify(dep, _("(running probe)"), rc);
00840         goto exit;
00841     }
00842 
00843     /* Search system configured provides. */
00844     if (!rpmioAccess("/etc/rpm/sysinfo", NULL, R_OK)) {
00845 #ifdef  NOTYET  /* XXX just sysinfo Provides: for now. */
00846         rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
00847 #else
00848         rpmTag tagN = RPMTAG_PROVIDENAME;
00849 #endif
00850         rpmds P = rpmdsFromPRCO(ts->PRCO, tagN);
00851         if (rpmdsSearch(P, dep) >= 0) {
00852             rpmdsNotify(dep, _("(sysinfo provides)"), rc);
00853             goto exit;
00854         }
00855     }
00856 
00857     /*
00858      * New features in rpm packaging implicitly add versioned dependencies
00859      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
00860      * Check those dependencies now.
00861      */
00862     if (NSType == RPMNS_TYPE_RPMLIB) {
00863         static rpmds rpmlibP = NULL;
00864         static int oneshot = -1;
00865 
00866         if (oneshot)
00867             oneshot = rpmdsRpmlib(&rpmlibP, NULL);
00868         if (rpmlibP == NULL)
00869             goto unsatisfied;
00870 
00871         if (rpmdsSearch(rpmlibP, dep) >= 0) {
00872             rpmdsNotify(dep, _("(rpmlib provides)"), rc);
00873             goto exit;
00874         }
00875         goto unsatisfied;
00876     }
00877 
00878     if (NSType == RPMNS_TYPE_CPUINFO) {
00879         static rpmds cpuinfoP = NULL;
00880         static int oneshot = -1;
00881 
00882         if (oneshot)
00883             oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
00884         if (cpuinfoP == NULL)
00885             goto unsatisfied;
00886 
00887         if (rpmdsSearch(cpuinfoP, dep) >= 0) {
00888             rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
00889             goto exit;
00890         }
00891         goto unsatisfied;
00892     }
00893 
00894     if (NSType == RPMNS_TYPE_GETCONF) {
00895         static rpmds getconfP = NULL;
00896         static int oneshot = -1;
00897 
00898         if (oneshot)
00899             oneshot = rpmdsGetconf(&getconfP, NULL);
00900         if (getconfP == NULL)
00901             goto unsatisfied;
00902 
00903         if (rpmdsSearch(getconfP, dep) >= 0) {
00904             rpmdsNotify(dep, _("(getconf provides)"), rc);
00905             goto exit;
00906         }
00907         goto unsatisfied;
00908     }
00909 
00910     if (NSType == RPMNS_TYPE_UNAME) {
00911         static rpmds unameP = NULL;
00912         static int oneshot = -1;
00913 
00914         if (oneshot)
00915             oneshot = rpmdsUname(&unameP, NULL);
00916         if (unameP == NULL)
00917             goto unsatisfied;
00918 
00919         if (rpmdsSearch(unameP, dep) >= 0) {
00920             rpmdsNotify(dep, _("(uname provides)"), rc);
00921             goto exit;
00922         }
00923         goto unsatisfied;
00924     }
00925 
00926     if (NSType == RPMNS_TYPE_SONAME) {
00927         rpmds sonameP = NULL;
00928         rpmPRCO PRCO = rpmdsNewPRCO(NULL);
00929         char * fn = strcpy(alloca(strlen(Name)+1), Name);
00930         int flags = 0;  /* XXX RPMELF_FLAG_SKIPREQUIRES? */
00931         rpmds ds;
00932 
00933         /* XXX Only absolute paths for now. */
00934         if (*fn != '/')
00935             goto unsatisfied;
00936         fn[strlen(fn)-1] = '\0';
00937 
00938         /* Extract ELF Provides: from /path/to/DSO. */
00939         xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
00940         sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
00941         if (!(xx == 0 && sonameP != NULL))
00942             goto unsatisfied;
00943 
00944         /* Search using the original {EVR,"",Flags} from the dep set. */
00945         ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
00946         xx = rpmdsSearch(sonameP, ds);
00947         ds = rpmdsFree(ds);
00948         PRCO = rpmdsFreePRCO(PRCO);
00949 
00950         /* Was the dependency satisfied? */
00951         if (xx >= 0) {
00952             rpmdsNotify(dep, _("(soname provides)"), rc);
00953             goto exit;
00954         }
00955         goto unsatisfied;
00956     }
00957 
00958     /* Search added packages for the dependency. */
00959     if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
00960         /*
00961          * XXX Ick, context sensitive answers from dependency cache.
00962          * XXX Always resolve added dependencies within context to disambiguate.
00963          */
00964         if (_rpmds_nopromote)
00965             _cacheThisRC = 0;
00966         goto exit;
00967     }
00968 
00969     /* XXX only the installer does not have the database open here. */
00970     if (rpmtsGetRdb(ts) != NULL) {
00971 /*@-boundsread@*/
00972         if (Name[0] == '/') {
00973             /* depFlags better be 0! */
00974 
00975             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00976             (void) rpmdbPruneIterator(mi,
00977                         ts->removedPackages, ts->numRemovedPackages, 1);
00978             while ((h = rpmdbNextIterator(mi)) != NULL) {
00979                 rpmdsNotify(dep, _("(db files)"), rc);
00980                 mi = rpmdbFreeIterator(mi);
00981                 goto exit;
00982             }
00983             mi = rpmdbFreeIterator(mi);
00984         }
00985 /*@=boundsread@*/
00986 
00987         mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00988         (void) rpmdbPruneIterator(mi,
00989                         ts->removedPackages, ts->numRemovedPackages, 1);
00990         while ((h = rpmdbNextIterator(mi)) != NULL) {
00991             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
00992                 rpmdsNotify(dep, _("(db provides)"), rc);
00993                 mi = rpmdbFreeIterator(mi);
00994                 goto exit;
00995             }
00996         }
00997         mi = rpmdbFreeIterator(mi);
00998 
00999     }
01000 
01001     /*
01002      * Search for an unsatisfied dependency.
01003      */
01004 /*@-boundsread@*/
01005     if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
01006         if (ts->solve != NULL) {
01007             xx = (*ts->solve) (ts, dep, ts->solveData);
01008             if (xx == 0)
01009                 goto exit;
01010             if (xx == -1) {
01011                 retries--;
01012                 rpmalMakeIndex(ts->addedPackages);
01013                 goto retry;
01014             }
01015         }
01016     }
01017 /*@=boundsread@*/
01018 
01019 unsatisfied:
01020     if (Flags & RPMSENSE_MISSINGOK) {
01021         rc = 0; /* dependency is unsatisfied, but just a hint. */
01022         rpmdsNotify(dep, _("(hint skipped)"), rc);
01023     } else {
01024         rc = 1; /* dependency is unsatisfied */
01025         rpmdsNotify(dep, NULL, rc);
01026     }
01027 
01028 exit:
01029     /*
01030      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01031      */
01032     if (_cacheDependsRC && _cacheThisRC) {
01033         dbiIndex dbi;
01034         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
01035         if (dbi == NULL) {
01036             _cacheDependsRC = 0;
01037         } else {
01038             const char * DNEVR;
01039             xx = 0;
01040             /*@-branchstate@*/
01041             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
01042                 DBC * dbcursor = NULL;
01043                 size_t DNEVRlen = strlen(DNEVR);
01044 
01045                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
01046 
01047                 memset(key, 0, sizeof(*key));
01048 /*@i@*/         key->data = (void *) DNEVR;
01049                 key->size = DNEVRlen;
01050                 memset(data, 0, sizeof(*data));
01051                 data->data = &rc;
01052                 data->size = sizeof(rc);
01053 
01054                 /*@-compmempass@*/
01055                 xx = dbiPut(dbi, dbcursor, key, data, 0);
01056                 /*@=compmempass@*/
01057                 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
01058             }
01059             /*@=branchstate@*/
01060             if (xx)
01061                 _cacheDependsRC = 0;
01062         }
01063     }
01064 
01065     return rpmdsNegateRC(dep, rc);
01066 }
01067 
01081 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
01082                 /*@null@*/ rpmds requires,
01083                 /*@null@*/ rpmds conflicts,
01084                 /*@null@*/ rpmds dirnames,
01085                 /*@null@*/ rpmds linktos,
01086                 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
01087         /*@globals rpmGlobalMacroContext, h_errno,
01088                 fileSystem, internalState @*/
01089         /*@modifies ts, requires, conflicts, dirnames, linktos,
01090                 rpmGlobalMacroContext, fileSystem, internalState */