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, &one, NULL))
00158         one = NULL;
00159     if (!headerGetEntry(second, RPMTAG_HDRID, NULL, &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, &arch, NULL);
00218     os = NULL;
00219     xx = hge(h, RPMTAG_OS, NULL, &os, NULL);
00220     if (nplatpat > 1) {
00221         const char * platform = NULL;
00222 
00223         if (hge(h, RPMTAG_PLATFORM, NULL, &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, D_("   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, D_("  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, &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 
00845     if (!rpmioAccess("/etc/rpm/sysinfo", NULL, R_OK)) {
00846 #ifdef  NOTYET  /* XXX just sysinfo Provides: for now. */
00847         rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
00848 #else
00849         rpmTag tagN = RPMTAG_PROVIDENAME;
00850 #endif
00851         rpmds P = rpmdsFromPRCO(ts->PRCO, tagN);
00852         if (rpmdsSearch(P, dep) >= 0) {
00853             rpmdsNotify(dep, _("(sysinfo provides)"), rc);
00854             goto exit;
00855         }
00856     }
00857 
00858     /*
00859      * New features in rpm packaging implicitly add versioned dependencies
00860      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
00861      * Check those dependencies now.
00862      */
00863     if (NSType == RPMNS_TYPE_RPMLIB) {
00864         static rpmds rpmlibP = NULL;
00865         static int oneshot = -1;
00866 
00867         if (oneshot)
00868             oneshot = rpmdsRpmlib(&rpmlibP, NULL);
00869         if (rpmlibP == NULL)
00870             goto unsatisfied;
00871 
00872         if (rpmdsSearch(rpmlibP, dep) >= 0) {
00873             rpmdsNotify(dep, _("(rpmlib provides)"), rc);
00874             goto exit;
00875         }
00876         goto unsatisfied;
00877     }
00878 
00879     if (NSType == RPMNS_TYPE_CPUINFO) {
00880         static rpmds cpuinfoP = NULL;
00881         static int oneshot = -1;
00882 
00883         if (oneshot)
00884             oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
00885         if (cpuinfoP == NULL)
00886             goto unsatisfied;
00887 
00888         if (rpmdsSearch(cpuinfoP, dep) >= 0) {
00889             rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
00890             goto exit;
00891         }
00892         goto unsatisfied;
00893     }
00894 
00895     if (NSType == RPMNS_TYPE_GETCONF) {
00896         static rpmds getconfP = NULL;
00897         static int oneshot = -1;
00898 
00899         if (oneshot)
00900             oneshot = rpmdsGetconf(&getconfP, NULL);
00901         if (getconfP == NULL)
00902             goto unsatisfied;
00903 
00904         if (rpmdsSearch(getconfP, dep) >= 0) {
00905             rpmdsNotify(dep, _("(getconf provides)"), rc);
00906             goto exit;
00907         }
00908         goto unsatisfied;
00909     }
00910 
00911     if (NSType == RPMNS_TYPE_UNAME) {
00912         static rpmds unameP = NULL;
00913         static int oneshot = -1;
00914 
00915         if (oneshot)
00916             oneshot = rpmdsUname(&unameP, NULL);
00917         if (unameP == NULL)
00918             goto unsatisfied;
00919 
00920         if (rpmdsSearch(unameP, dep) >= 0) {
00921             rpmdsNotify(dep, _("(uname provides)"), rc);
00922             goto exit;
00923         }
00924         goto unsatisfied;
00925     }
00926 
00927     if (NSType == RPMNS_TYPE_SONAME) {
00928         rpmds sonameP = NULL;
00929         rpmPRCO PRCO = rpmdsNewPRCO(NULL);
00930         char * fn = strcpy(alloca(strlen(Name)+1), Name);
00931         int flags = 0;  /* XXX RPMELF_FLAG_SKIPREQUIRES? */
00932         rpmds ds;
00933 
00934         /* XXX Only absolute paths for now. */
00935         if (*fn != '/')
00936             goto unsatisfied;
00937         fn[strlen(fn)-1] = '\0';
00938 
00939         /* Extract ELF Provides: from /path/to/DSO. */
00940         xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
00941         sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
00942         if (!(xx == 0 && sonameP != NULL))
00943             goto unsatisfied;
00944 
00945         /* Search using the original {EVR,"",Flags} from the dep set. */
00946         ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
00947         xx = rpmdsSearch(sonameP, ds);
00948         ds = rpmdsFree(ds);
00949         PRCO = rpmdsFreePRCO(PRCO);
00950 
00951         /* Was the dependency satisfied? */
00952         if (xx >= 0) {
00953             rpmdsNotify(dep, _("(soname provides)"), rc);
00954             goto exit;
00955         }
00956         goto unsatisfied;
00957     }
00958 
00959     /* Search added packages for the dependency. */
00960     if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
00961         /*
00962          * XXX Ick, context sensitive answers from dependency cache.
00963          * XXX Always resolve added dependencies within context to disambiguate.
00964          */
00965         if (_rpmds_nopromote)
00966             _cacheThisRC = 0;
00967         goto exit;
00968     }
00969 
00970     /* XXX only the installer does not have the database open here. */
00971     if (rpmtsGetRdb(ts) != NULL) {
00972 /*@-boundsread@*/
00973         if (Name[0] == '/') {
00974             /* depFlags better be 0! */
00975 
00976             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00977             (void) rpmdbPruneIterator(mi,
00978                         ts->removedPackages, ts->numRemovedPackages, 1);
00979             while ((h = rpmdbNextIterator(mi)) != NULL) {
00980                 rpmdsNotify(dep, _("(db files)"), rc);
00981                 mi = rpmdbFreeIterator(mi);
00982                 goto exit;
00983             }
00984             mi = rpmdbFreeIterator(mi);
00985         }
00986 /*@=boundsread@*/
00987 
00988         mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00989         (void) rpmdbPruneIterator(mi,
00990                         ts->removedPackages, ts->numRemovedPackages, 1);
00991         while ((h = rpmdbNextIterator(mi)) != NULL) {
00992             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
00993                 rpmdsNotify(dep, _("(db provides)"), rc);
00994                 mi = rpmdbFreeIterator(mi);
00995                 goto exit;
00996             }
00997         }
00998         mi = rpmdbFreeIterator(mi);
00999 
01000     }
01001 
01002     /*
01003      * Search for an unsatisfied dependency.
01004      */
01005 /*@-boundsread@*/
01006     if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
01007         if (ts->solve != NULL) {
01008             xx = (*ts->solve) (ts, dep, ts->solveData);
01009             if (xx == 0)
01010                 goto exit;
01011             if (xx == -1) {
01012                 retries--;
01013                 rpmalMakeIndex(ts->addedPackages);
01014                 goto retry;
01015             }
01016         }
01017     }
01018 /*@=boundsread@*/
01019 
01020 unsatisfied:
01021     if (Flags & RPMSENSE_MISSINGOK) {
01022         rc = 0; /* dependency is unsatisfied, but just a hint. */
01023         rpmdsNotify(dep, _("(hint skipped)"), rc);
01024     } else {
01025         rc = 1; /* dependency is unsatisfied */
01026         rpmdsNotify(dep, NULL, rc);
01027     }
01028 
01029 exit:
01030     /*
01031      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01032      */
01033     if (_cacheDependsRC && _cacheThisRC) {
01034         dbiIndex dbi;
01035         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
01036         if (dbi == NULL) {
01037             _cacheDependsRC = 0;
01038         } else {
01039             const char * DNEVR;
01040             xx = 0;
01041             /*@-branchstate@*/
01042             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
01043                 DBC * dbcursor = NULL;
01044                 size_t DNEVRlen = strlen(DNEVR);
01045 
01046                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
01047 
01048                 memset(key, 0, sizeof(*key));
01049 /*@i@*/         key->data = (void *) DNEVR;
01050                 key->size = DNEVRlen;
01051                 memset(data, 0, sizeof(*data));
01052                 data->data = &rc;
01053                 data->size = sizeof(rc);
01054 
01055                 /*@-compmempass@*/
01056                 xx = dbiPut(dbi, dbcursor, key, data, 0);
01057                 /*@=compmempass@*/
01058                 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
01059             }
01060             /*@=branchstate@*/
01061             if (xx)
01062                 _cacheDependsRC = 0;
01063         }
01064     }
01065 
01066     return rpmdsNegateRC(dep, rc);
01067 }
01068 
01082 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
01083                 /*@null@*/ rpmds requires,
01084                 /*@null@*/ rpmds conflicts,
01085                 /*@null@*/ rpmds dirnames,
01086                 /*@null@*/ rpmds linktos,
01087                 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
01088         /*@globals rpmGlobalMacroContext, h_errno,
01089                 fileSystem, internalState @*/
01090         /*@modifies ts, requires, conflicts, dirnames, linktos,
01091                 rpmGlobalMacroContext, fileSystem, internalState */
01092 {
01093     rpmps ps = rpmtsProblems(ts);
01094     uint_32 dscolor;
01095     const char * Name;
01096     int rc;
01097     int ourrc = 0;
01098 
01099     requires = rpmdsInit(requires);
01100     if (requires != NULL)
01101     while (!ourrc && rpmdsNext(requires) >= 0) {
01102 
01103         if ((Name = rpmdsN(requires)) == NULL)
01104             continue;   /* XXX can't happen */
01105 
01106         /* Filter out requires that came along for the ride. */
01107         if (depName != NULL && strcmp(depName, Name))
01108             continue;
01109 
01110         /* Ignore colored requires not in our rainbow. */
01111         dscolor = rpmdsColor(requires);
01112         if (tscolor && dscolor && !(tscolor & dscolor))
01113             continue;
01114 
01115         rc = unsatisfiedDepend(ts, requires, adding);
01116 
01117         switch (rc) {
01118         case 0:         /* requirements are satisfied. */
01119             /*@switchbreak@*/ break;
01120         case 1:         /* requirements are not satisfied. */
01121         {   fnpyKey * suggestedKeys = NULL;
01122 
01123             /*@-branchstate@*/
01124             if (ts->availablePackages != NULL) {
01125                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01126                                 requires, NULL);
01127             }
01128             /*@=branchstate@*/
01129 
01130             rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding);
01131 
01132         }
01133             /*@switchbreak@*/ break;
01134         case 2:         /* something went wrong! */
01135         default:
01136             ourrc = 1;
01137             /*@switchbreak@*/ break;
01138         }
01139     }
01140 
01141     conflicts = rpmdsInit(conflicts);
01142     if (conflicts != NULL)
01143     while (!ourrc && rpmdsNext(conflicts) >= 0) {
01144 
01145         if ((Name = rpmdsN(conflicts)) == NULL)
01146             continue;   /* XXX can't happen */
01147 
01148         /* Filter out conflicts that came along for the ride. */
01149         if (depName != NULL && strcmp(depName, Name))
01150             continue;
01151 
01152         /* Ignore colored conflicts not in our rainbow. */
01153         dscolor = rpmdsColor(conflicts);
01154         if (tscolor && dscolor && !(tscolor & dscolor))
01155             continue;
01156 
01157         rc = unsatisfiedDepend(ts, conflicts, adding);
01158 
01159         /* 1 == unsatisfied, 0 == satsisfied */
01160         switch (rc) {
01161         case 0:         /* conflicts exist. */
01162             rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding);
01163             /*@switchbreak@*/ break;
01164         case 1:         /* conflicts don't exist. */
01165             /*@switchbreak@*/ break;
01166         case 2:         /* something went wrong! */
01167         default:
01168             ourrc = 1;
01169             /*@switchbreak@*/ break;
01170         }
01171     }
01172 
01173     dirnames = rpmdsInit(dirnames);
01174     if (dirnames != NULL)
01175     while (!ourrc && rpmdsNext(dirnames) >= 0) {
01176 
01177         if ((Name = rpmdsN(dirnames)) == NULL)
01178             continue;   /* XXX can't happen */
01179 
01180         /* Filter out dirnames that came along for the ride. */
01181         if (depName != NULL && strcmp(depName, Name))
01182             continue;
01183 
01184         /* Ignore colored dirnames not in our rainbow. */
01185         dscolor = rpmdsColor(dirnames);
01186         if (tscolor && dscolor && !(tscolor & dscolor))
01187             continue;
01188 
01189         rc = unsatisfiedDepend(ts, dirnames, adding);
01190 
01191         switch (rc) {
01192         case 0:         /* requirements are satisfied. */
01193             /*@switchbreak@*/ break;
01194         case 1:         /* requirements are not satisfied. */
01195         {   fnpyKey * suggestedKeys = NULL;
01196 
01197             /*@-branchstate@*/
01198             if (ts->availablePackages != NULL) {
01199                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01200                                 dirnames, NULL);
01201             }
01202             /*@=branchstate@*/
01203 
01204             rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding);
01205 
01206         }
01207             /*@switchbreak@*/ break;
01208         case 2:         /* something went wrong! */
01209         default:
01210             ourrc = 1;
01211             /*@switchbreak@*/ break;
01212         }
01213     }
01214 
01215     linktos = rpmdsInit(linktos);
01216     if (linktos != NULL)
01217     while (!ourrc && rpmdsNext(linktos) >= 0) {
01218 
01219         if ((Name = rpmdsN(linktos)) == NULL)
01220             continue;   /* XXX can't happen */
01221         if (*Name == '\0')      /* XXX most linktos are empty */
01222                 continue;
01223 
01224         /* Filter out linktos that came along for the ride. */
01225         if (depName != NULL && strcmp(depName, Name))
01226             continue;
01227 
01228         /* Ignore colored linktos not in our rainbow. */
01229         dscolor = rpmdsColor(linktos);
01230         if (tscolor && dscolor && !(tscolor & dscolor))
01231             continue;
01232 
01233         rc = unsatisfiedDepend(ts, linktos, adding);
01234 
01235         switch (rc) {
01236         case 0:         /* requirements are satisfied. */
01237             /*@switchbreak@*/ break;
01238         case 1:         /* requirements are not satisfied. */
01239         {   fnpyKey * suggestedKeys = NULL;
01240 
01241             /*@-branchstate@*/
01242             if (ts->availablePackages != NULL) {
01243                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01244                                 linktos, NULL);
01245             }
01246             /*@=branchstate@*/
01247 
01248             rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding);
01249 
01250         }
01251             /*@switchbreak@*/ break;
01252         case 2:         /* something went wrong! */
01253         default:
01254             ourrc = 1;
01255             /*@switchbreak@*/ break;
01256         }
01257     }
01258 
01259     ps = rpmpsFree(ps);
01260     return ourrc;
01261 }
01262 
01273 static int checkPackageSet(rpmts ts, const char * depName,
01274                 /*@only@*/ /*@null@*/ rpmdbMatchIterator mi, int adding)
01275         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01276         /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
01277 {
01278     rpmdepFlags depFlags = rpmtsDFlags(ts);
01279     uint_32 tscolor = rpmtsColor(ts);
01280     int scareMem = 0;
01281     Header h;
01282     int ec = 0;
01283 
01284     (void) rpmdbPruneIterator(mi,
01285                 ts->removedPackages, ts->numRemovedPackages, 1);
01286     while ((h = rpmdbNextIterator(mi)) != NULL) {
01287         const char * pkgNEVRA;
01288         rpmds requires = NULL;
01289         rpmds conflicts = NULL;
01290         rpmds dirnames = NULL;
01291         rpmds linktos = NULL;
01292         int rc;
01293 
01294         pkgNEVRA = hGetNEVRA(h, NULL);
01295         if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES))
01296             requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
01297         if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS))
01298             conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
01299         if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS))
01300             dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem);
01301         if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS))
01302             linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem);
01303 
01304         (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
01305         (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
01306         (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote);
01307         (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote);
01308 
01309         rc = checkPackageDeps(ts, pkgNEVRA,
01310                 requires, conflicts, dirnames, linktos,
01311                 depName, tscolor, adding);
01312 
01313         linktos = rpmdsFree(linktos);
01314         dirnames = rpmdsFree(dirnames);
01315         conflicts = rpmdsFree(conflicts);
01316         requires = rpmdsFree(requires);
01317         pkgNEVRA = _free(pkgNEVRA);
01318 
01319         if (rc) {
01320             ec = 1;
01321             break;
01322         }
01323     }
01324     mi = rpmdbFreeIterator(mi);
01325 
01326     return ec;
01327 }
01328 
01335 static int checkDependentPackages(rpmts ts, const char * depName)
01336         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01337         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01338 {
01339     int rc = 0;
01340 
01341     /* XXX rpmdb can be closed here, avoid error msg. */
01342     if (rpmtsGetRdb(ts) != NULL) {
01343         rpmdbMatchIterator mi;
01344         mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0);
01345         rc = checkPackageSet(ts, depName, mi, 0);
01346     }
01347     return rc;
01348 }
01349 
01356 static int checkDependentConflicts(rpmts ts, const char * depName)
01357         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01358         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01359 {
01360     int rc = 0;
01361 
01362     /* XXX rpmdb can be closed here, avoid error msg. */
01363     if (rpmtsGetRdb(ts) != NULL) {
01364         rpmdbMatchIterator mi;
01365         mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0);
01366         rc = checkPackageSet(ts, depName, mi, 1);
01367     }
01368 
01369     return rc;
01370 }
01371 
01372 struct badDeps_s {
01373 /*@observer@*/ /*@owned@*/ /*@null@*/
01374     const char * pname;
01375 /*@observer@*/ /*@dependent@*/ /*@null@*/
01376     const char * qname;
01377 };
01378 
01379 #ifdef REFERENCE
01380 static struct badDeps_s {
01381 /*@observer@*/ /*@null@*/ const char * pname;
01382 /*@observer@*/ /*@null@*/ const char * qname;
01383 } badDeps[] = {
01384     { "libtermcap", "bash" },
01385     { "modutils", "vixie-cron" },
01386     { "ypbind", "yp-tools" },
01387     { "ghostscript-fonts", "ghostscript" },
01388     /* 7.2 only */
01389     { "libgnomeprint15", "gnome-print" },
01390     { "nautilus", "nautilus-mozilla" },
01391     /* 7.1 only */
01392     { "arts", "kdelibs-sound" },
01393     /* 7.0 only */
01394     { "pango-gtkbeta-devel", "pango-gtkbeta" },
01395     { "XFree86", "Mesa" },
01396     { "compat-glibc", "db2" },
01397     { "compat-glibc", "db1" },
01398     { "pam", "initscripts" },
01399     { "initscripts", "sysklogd" },
01400     /* 6.2 */
01401     { "egcs-c++", "libstdc++" },
01402     /* 6.1 */
01403     { "pilot-link-devel", "pilot-link" },
01404     /* 5.2 */
01405     { "pam", "pamconfig" },
01406     { NULL, NULL }
01407 };
01408 #else
01409 /*@unchecked@*/
01410 static int badDepsInitialized = 0;
01411 
01412 /*@unchecked@*/ /*@only@*/ /*@null@*/
01413 static struct badDeps_s * badDeps = NULL;
01414 #endif
01415 
01418 /*@-modobserver -observertrans @*/
01419 static void freeBadDeps(void)
01420         /*@globals badDeps, badDepsInitialized @*/
01421         /*@modifies badDeps, badDepsInitialized @*/
01422 {
01423     if (badDeps) {
01424         struct badDeps_s * bdp;
01425         for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
01426             bdp->pname = _free(bdp->pname);
01427         badDeps = _free(badDeps);
01428     }
01429     badDepsInitialized = 0;
01430 }
01431 /*@=modobserver =observertrans @*/
01432 
01441 /*@-boundsread@*/
01442 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q)
01443         /*@globals badDeps, badDepsInitialized,
01444                 rpmGlobalMacroContext, h_errno @*/
01445         /*@modifies badDeps, badDepsInitialized,
01446                 rpmGlobalMacroContext @*/
01447 {
01448     struct badDeps_s * bdp;
01449 
01450     if (!badDepsInitialized) {
01451         char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
01452         const char ** av = NULL;
01453         int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
01454         int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
01455                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01456         int ac = 0;
01457         int i;
01458 
01459         if (s != NULL && *s != '\0'
01460         && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
01461         && ac > 0 && av != NULL)
01462         {
01463             bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
01464             for (i = 0; i < ac; i++, bdp++) {
01465                 char * pname, * qname;
01466 
01467                 if (av[i] == NULL)
01468                     break;
01469                 pname = xstrdup(av[i]);
01470                 if ((qname = strchr(pname, '>')) != NULL)
01471                     *qname++ = '\0';
01472                 bdp->pname = pname;
01473                 /*@-usereleased@*/
01474                 bdp->qname = qname;
01475                 /*@=usereleased@*/
01476                 rpmMessage(msglvl,
01477                         _("ignore package name relation(s) [%d]\t%s -> %s\n"),
01478                         i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
01479             }
01480             bdp->pname = NULL;
01481             bdp->qname = NULL;
01482         }
01483         av = _free(av);
01484         s = _free(s);
01485         badDepsInitialized++;
01486     }
01487 
01488     /*@-compdef@*/
01489     if (badDeps != NULL)
01490     for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
01491         if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
01492             return 1;
01493     }
01494     return 0;
01495     /*@=compdef@*/
01496 }
01497 /*@=boundsread@*/
01498 
01504 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
01505         /*@globals internalState @*/
01506         /*@uses tsi @*/
01507         /*@modifies internalState @*/
01508 {
01509     rpmte p;
01510 
01511     /*@-branchstate@*/ /* FIX: q is kept */
01512     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
01513         tsi = tsi->tsi_next;
01514         if (rpmteTSI(p)->tsi_chain != NULL)
01515             continue;
01516         /*@-assignexpose -temptrans@*/
01517         rpmteTSI(p)->tsi_chain = q;
01518         /*@=assignexpose =temptrans@*/
01519         if (rpmteTSI(p)->tsi_next != NULL)
01520             markLoop(rpmteTSI(p)->tsi_next, p);
01521     }
01522     /*@=branchstate@*/
01523 }
01524 
01525 /*
01526  * Return display string a dependency, adding contextual flags marker.
01527  * @param f             dependency flags
01528  * @return              display string
01529  */
01530 static inline /*@observer@*/ const char * identifyDepend(int_32 f)
01531         /*@*/
01532 {
01533     f = _notpre(f);
01534     if (f & RPMSENSE_SCRIPT_PRE)
01535         return "Requires(pre):";
01536     if (f & RPMSENSE_SCRIPT_POST)
01537         return "Requires(post):";
01538     if (f & RPMSENSE_SCRIPT_PREUN)
01539         return "Requires(preun):";
01540     if (f & RPMSENSE_SCRIPT_POSTUN)
01541         return "Requires(postun):";
01542     if (f & RPMSENSE_SCRIPT_VERIFY)
01543         return "Requires(verify):";
01544     if (f & RPMSENSE_MISSINGOK)
01545         return "Requires(hint):";
01546     if (f & RPMSENSE_FIND_REQUIRES)
01547         return "Requires(auto):";
01548     return "Requires:";
01549 }
01550 
01563 /*@-boundswrite@*/
01564 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
01565 static /*@owned@*/ /*@null@*/ const char *
01566 zapRelation(rpmte q, rpmte p,
01567                 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl)
01568         /*@globals rpmGlobalMacroContext, h_errno @*/
01569         /*@modifies q, p, *nzaps, rpmGlobalMacroContext @*/
01570 {
01571     rpmds requires;
01572     tsortInfo tsi_prev;
01573     tsortInfo tsi;
01574     const char *dp = NULL;
01575 
01576     for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
01577          tsi != NULL;
01578         /* XXX Note: the loop traverses "not found", break on "found". */
01579         /*@-nullderef@*/
01580          tsi_prev = tsi, tsi = tsi->tsi_next)
01581         /*@=nullderef@*/
01582     {
01583         int_32 Flags;
01584 
01585         /*@-abstractcompare@*/
01586         if (tsi->tsi_suc != p)
01587             continue;
01588         /*@=abstractcompare@*/
01589 
01590         requires = rpmteDS(p, tsi->tsi_tagn);
01591         if (requires == NULL) continue;         /* XXX can't happen */
01592 
01593         (void) rpmdsSetIx(requires, tsi->tsi_reqx);
01594 
01595         Flags = rpmdsFlags(requires);
01596 
01597         dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
01598 
01599         /*
01600          * Attempt to unravel a dependency loop by eliminating Requires's.
01601          */
01602         /*@-branchstate@*/
01603         if (zap) {
01604             rpmMessage(msglvl,
01605                         _("removing %s \"%s\" from tsort relations.\n"),
01606                         (rpmteNEVRA(p) ?  rpmteNEVRA(p) : "???"), dp);
01607             rpmteTSI(p)->tsi_count--;
01608             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01609             tsi->tsi_next = NULL;
01610             tsi->tsi_suc = NULL;
01611             tsi = _free(tsi);
01612             if (nzaps)
01613                 (*nzaps)++;
01614             if (zap)
01615                 zap--;
01616         }
01617         /*@=branchstate@*/
01618         /* XXX Note: the loop traverses "not found", get out now! */
01619         break;
01620     }
01621     return dp;
01622 }
01623 /*@=mustmod@*/
01624 /*@=boundswrite@*/
01625 
01634 /*@-mustmod@*/
01635 static inline int addRelation(rpmts ts,
01636                 /*@dependent@*/ rpmte p,
01637                 unsigned char * selected,
01638                 rpmds requires)
01639         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01640         /*@modifies ts, p, *selected, rpmGlobalMacroContext,
01641                 fileSystem, internalState @*/
01642 {
01643     rpmtsi qi; rpmte q;
01644     tsortInfo tsi;
01645     nsType NSType = rpmdsNSType(requires);
01646     fnpyKey key;
01647     int teType = rpmteType(p);
01648     alKey pkgKey;
01649     int i = 0;
01650     rpmal al = (teType == TR_ADDED ? ts->addedPackages : ts->erasedPackages);
01651 
01652     /* Avoid certain NS dependencies. */
01653     switch (NSType) {
01654     case RPMNS_TYPE_RPMLIB:
01655     case RPMNS_TYPE_CPUINFO:
01656     case RPMNS_TYPE_GETCONF:
01657     case RPMNS_TYPE_UNAME:
01658     case RPMNS_TYPE_SONAME:
01659     case RPMNS_TYPE_ACCESS:
01660     case RPMNS_TYPE_USER:
01661     case RPMNS_TYPE_GROUP:
01662     case RPMNS_TYPE_MOUNTED:
01663     case RPMNS_TYPE_DISKSPACE:
01664     case RPMNS_TYPE_DIGEST:
01665     case RPMNS_TYPE_GNUPG:
01666     case RPMNS_TYPE_MACRO:
01667     case RPMNS_TYPE_ENVVAR:
01668     case RPMNS_TYPE_RUNNING:
01669         return 0;
01670         /*@notreached@*/ break;
01671     default:
01672         break;
01673     }
01674 
01675     {   const char * Name = rpmdsN(requires);
01676 
01677         /* Avoid package config dependencies. */
01678         if (Name == NULL || !strncmp(Name, "config(", sizeof("config(")-1))
01679             return 0;
01680     }
01681 
01682     pkgKey = RPMAL_NOMATCH;
01683     key = rpmalSatisfiesDepend(al, requires, &pkgKey);
01684 
01685     /* Ordering depends only on added/erased package relations. */
01686     if (pkgKey == RPMAL_NOMATCH)
01687         return 0;
01688 
01689 /* XXX Set q to the added/removed package that was found. */
01690     /* XXX pretend erasedPackages are just appended to addedPackages. */
01691     if (teType == TR_REMOVED)
01692         pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
01693 
01694     for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
01695         if (pkgKey == rpmteAddedKey(q))
01696             break;
01697     }
01698     qi = rpmtsiFree(qi);
01699     if (q == NULL || i >= ts->orderCount)
01700         return 0;
01701 
01702     /* Avoid certain dependency relations. */
01703     if (teType == TR_ADDED && ignoreDep(ts, p, q))
01704         return 0;
01705 
01706     /* Avoid redundant relations. */
01707 /*@-boundsread@*/
01708     if (selected[i] != 0)
01709         return 0;
01710 /*@=boundsread@*/
01711 /*@-boundswrite@*/
01712     selected[i] = 1;
01713 /*@=boundswrite@*/
01714 
01715     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01716     rpmteTSI(p)->tsi_count++;                   /* bump p predecessor count */
01717 
01718     if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
01719         (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
01720     if (rpmteDepth(p) > ts->maxDepth)
01721         ts->maxDepth = rpmteDepth(p);
01722 
01723     tsi = xcalloc(1, sizeof(*tsi));
01724     tsi->tsi_suc = p;
01725 
01726     tsi->tsi_tagn = rpmdsTagN(requires);
01727     tsi->tsi_reqx = rpmdsIx(requires);
01728 
01729     tsi->tsi_next = rpmteTSI(q)->tsi_next;
01730     rpmteTSI(q)->tsi_next = tsi;
01731     rpmteTSI(q)->tsi_qcnt++;                    /* bump q successor count */
01732     return 0;
01733 }
01734 /*@=mustmod@*/
01735 
01742 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01743 {
01744     /*@-castexpose@*/
01745     long a = (long) ((const orderListIndex)one)->pkgKey;
01746     long b = (long) ((const orderListIndex)two)->pkgKey;
01747     /*@=castexpose@*/
01748     return (a - b);
01749 }
01750 
01758 /*@-boundswrite@*/
01759 /*@-mustmod@*/
01760 static void addQ(/*@dependent@*/ rpmte p,
01761                 /*@in@*/ /*@out@*/ rpmte * qp,
01762                 /*@in@*/ /*@out@*/ rpmte * rp,
01763                 uint_32 prefcolor)
01764         /*@modifies p, *qp, *rp @*/
01765 {
01766     rpmte q, qprev;
01767 
01768     /* Mark the package as queued. */
01769     rpmteTSI(p)->tsi_queued = 1;
01770 
01771     if ((*rp) == NULL) {        /* 1st element */
01772         /*@-dependenttrans@*/ /* FIX: double indirection */
01773         (*rp) = (*qp) = p;
01774         /*@=dependenttrans@*/
01775         return;
01776     }
01777 
01778     /* Find location in queue using metric tsi_qcnt. */
01779     for (qprev = NULL, q = (*qp);
01780          q != NULL;
01781          qprev = q, q = rpmteTSI(q)->tsi_suc)
01782     {
01783         /* XXX Insure preferred color first. */
01784         if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
01785             continue;
01786 
01787         /* XXX Insure removed after added. */
01788         if (rpmteType(p) == TR_REMOVED && rpmteType(p) != rpmteType(q))
01789             continue;
01790         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01791             break;
01792     }
01793 
01794     if (qprev == NULL) {        /* insert at beginning of list */
01795         rpmteTSI(p)->tsi_suc = q;
01796         /*@-dependenttrans@*/
01797         (*qp) = p;              /* new head */
01798         /*@=dependenttrans@*/
01799     } else if (q == NULL) {     /* insert at end of list */
01800         rpmteTSI(qprev)->tsi_suc = p;
01801         /*@-dependenttrans@*/
01802         (*rp) = p;              /* new tail */
01803         /*@=dependenttrans@*/
01804     } else {                    /* insert between qprev and q */
01805         rpmteTSI(p)->tsi_suc = q;
01806         rpmteTSI(qprev)->tsi_suc = p;
01807     }
01808 }
01809 /*@=mustmod@*/
01810 /*@=boundswrite@*/
01811 
01812 /*@unchecked@*/
01813 #ifdef  NOTYET
01814 static uint32_t _autobits = _notpre(_ALL_REQUIRES_MASK);
01815 #define isAuto(_x)      ((_x) & _autobits)
01816 #else
01817 static uint32_t _autobits = 0xffffffff;
01818 #define isAuto(_x)      (1)
01819 #endif
01820 
01821 /*@-bounds@*/
01822 int rpmtsOrder(rpmts ts)
01823 {
01824     rpmds requires;
01825     int_32 Flags;
01826     int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
01827     uint_32 prefcolor = rpmtsPrefColor(ts);
01828     rpmtsi pi; rpmte p;
01829     rpmtsi qi; rpmte q;
01830     rpmtsi ri; rpmte r;
01831     tsortInfo tsi;
01832     tsortInfo tsi_next;
01833     alKey * ordering;
01834     int orderingCount = 0;
01835     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01836     int loopcheck;
01837     rpmte * newOrder;
01838     int newOrderCount = 0;
01839     orderListIndex orderList;
01840     int numOrderList;
01841     int npeer = 128;    /* XXX more than deep enough for now. */
01842     int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
01843     int nrescans = 10;
01844     int _printed = 0;
01845     char deptypechar;
01846     size_t tsbytes;
01847     int oType = 0;
01848     int treex;
01849     int depth;
01850     int breadth;
01851     int qlen;
01852     int i, j;
01853 
01854 #ifdef  DYING
01855     rpmalMakeIndex(ts->addedPackages);
01856 #endif
01857 
01858     /* Create erased package index. */
01859     pi = rpmtsiInit(ts);
01860     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01861         alKey pkgKey;
01862         fnpyKey key;
01863         uint_32 tscolor = rpmtsColor(ts);
01864         pkgKey = RPMAL_NOMATCH;
01865 /*@-abstract@*/
01866         key = (fnpyKey) p;
01867 /*@=abstract@*/
01868         pkgKey = rpmalAdd(&ts->erasedPackages, pkgKey, key,
01869                         rpmteDS(p, RPMTAG_PROVIDENAME),
01870                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
01871         /* XXX pretend erasedPackages are just appended to addedPackages. */
01872         pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
01873         (void) rpmteSetAddedKey(p, pkgKey);
01874     }
01875     pi = rpmtsiFree(pi);
01876     rpmalMakeIndex(ts->erasedPackages);
01877 
01878     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01879 
01880     /* T1. Initialize. */
01881     if (oType == 0)
01882         numOrderList = ts->orderCount;
01883     else {
01884         numOrderList = 0;
01885         if (oType & TR_ADDED)
01886             numOrderList += ts->numAddedPackages;
01887         if (oType & TR_REMOVED)
01888             numOrderList += ts->numRemovedPackages;
01889      }
01890     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01891     loopcheck = numOrderList;
01892     tsbytes = 0;
01893 
01894     pi = rpmtsiInit(ts);
01895     while ((p = rpmtsiNext(pi, oType)) != NULL)
01896         rpmteNewTSI(p);
01897     pi = rpmtsiFree(pi);
01898 
01899     /* Record all relations. */
01900     rpmMessage(RPMMESS_DEBUG, D_("========== recording tsort relations\n"));
01901     pi = rpmtsiInit(ts);
01902     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01903 
01904         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01905 
01906       if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) != NULL) {
01907 
01908         /* Avoid narcisstic relations. */
01909         selected[rpmtsiOc(pi)] = 1;
01910 
01911         /* T2. Next "q <- p" relation. */
01912 
01913         /* First, do pre-requisites. */
01914         requires = rpmdsInit(requires);
01915         if (requires != NULL)
01916         while (rpmdsNext(requires) >= 0) {
01917 
01918             Flags = rpmdsFlags(requires);
01919             if (!isAuto(Flags))
01920                 /*@innercontinue@*/ continue;
01921 
01922             switch (rpmteType(p)) {
01923             case TR_REMOVED:
01924                 /* Skip if not %preun/%postun requires. */
01925                 if (!isErasePreReq(Flags))
01926                     /*@innercontinue@*/ continue;
01927                 /*@switchbreak@*/ break;
01928             case TR_ADDED:
01929                 /* Skip if not %pre/%post requires. */
01930                 if (!isInstallPreReq(Flags))
01931                     /*@innercontinue@*/ continue;
01932                 /*@switchbreak@*/ break;
01933             }
01934 
01935             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01936             (void) addRelation(ts, p, selected, requires);
01937 
01938         }
01939 
01940         /* Then do co-requisites. */
01941         requires = rpmdsInit(requires);
01942         if (requires != NULL)
01943         while (rpmdsNext(requires) >= 0) {
01944 
01945             Flags = rpmdsFlags(requires);
01946             if (!isAuto(Flags))
01947                 /*@innercontinue@*/ continue;
01948 
01949             switch (rpmteType(p)) {
01950             case TR_REMOVED:
01951                 /* Skip if %preun/%postun requires. */
01952                 if (isErasePreReq(Flags))
01953                     /*@innercontinue@*/ continue;
01954                 /*@switchbreak@*/ break;
01955             case TR_ADDED:
01956                 /* Skip if %pre/%post requires. */
01957                 if (isInstallPreReq(Flags))
01958                     /*@innercontinue@*/ continue;
01959                 /*@switchbreak@*/ break;
01960             }
01961 
01962             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01963             (void) addRelation(ts, p, selected, requires);
01964 
01965         }
01966       }
01967 
01968       if (_autobits != 0xffffffff)
01969       {
01970 
01971         /* Order by requiring parent directories pre-requsites. */
01972         requires = rpmdsInit(rpmteDS(p, RPMTAG_DIRNAMES));
01973         if (requires != NULL)
01974         while (rpmdsNext(requires) >= 0) {
01975 
01976             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01977             (void) addRelation(ts, p, selected, requires);
01978 
01979         }
01980 
01981         /* Order by requiring no dangling symlinks. */
01982         requires = rpmdsInit(rpmteDS(p, RPMTAG_FILELINKTOS));
01983         if (requires != NULL)
01984         while (rpmdsNext(requires) >= 0) {
01985 
01986             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01987             (void) addRelation(ts, p, selected, requires);
01988 
01989         }
01990       }
01991 
01992     }
01993     pi = rpmtsiFree(pi);
01994 
01995     /* Save predecessor count and mark tree roots. */
01996     treex = 0;
01997     pi = rpmtsiInit(ts);
01998     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01999         int npreds;
02000 
02001         npreds = rpmteTSI(p)->tsi_count;
02002 
02003         (void) rpmteSetNpreds(p, npreds);
02004         (void) rpmteSetDepth(p, 0);
02005 
02006         if (npreds == 0) {
02007             treex++;
02008             (void) rpmteSetTree(p, treex);
02009             (void) rpmteSetBreadth(p, treex);
02010         } else
02011             (void) rpmteSetTree(p, -1);
02012 #ifdef  UNNECESSARY
02013         (void) rpmteSetParent(p, NULL);
02014 #endif
02015 
02016     }
02017     pi = rpmtsiFree(pi);
02018     ts->ntrees = treex;
02019 
02020     /* T4. Scan for zeroes. */
02021     rpmMessage(RPMMESS_DEBUG, D_("========== tsorting packages (order, #predecessors, #succesors, tree, Ldepth, Rbreadth)\n"));
02022 
02023 rescan:
02024     if (pi != NULL) pi = rpmtsiFree(pi);
02025     q = r = NULL;
02026     qlen = 0;
02027     pi = rpmtsiInit(ts);
02028     while ((p = rpmtsiNext(pi, oType)) != NULL) {
02029 
02030         /* Prefer packages in chainsaw or anaconda presentation order. */
02031         if (anaconda)
02032             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
02033 
02034         if (rpmteTSI(p)->tsi_count != 0)
02035             continue;
02036         rpmteTSI(p)->tsi_suc = NULL;
02037         addQ(p, &q, &r, prefcolor);
02038         qlen++;
02039     }
02040     pi = rpmtsiFree(pi);
02041 
02042     /* T5. Output front of queue (T7. Remove from queue.) */
02043     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
02044 
02045         /* Mark the package as unqueued. */
02046         rpmteTSI(q)->tsi_queued = 0;
02047 
02048         if (oType != 0)
02049         switch (rpmteType(q)) {
02050         case TR_ADDED:
02051             if (!(oType & TR_ADDED))
02052                 continue;
02053             /*@switchbreak@*/ break;
02054         case TR_REMOVED:
02055             if (!(oType & TR_REMOVED))
02056                 continue;
02057             /*@switchbreak@*/ break;
02058         default:
02059             continue;
02060             /*@notreached@*/ /*@switchbreak@*/ break;
02061         }
02062         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
02063 
02064         treex = rpmteTree(q);
02065         depth = rpmteDepth(q);
02066         breadth = ((depth < npeer) ? peer[depth]++ : 0);
02067         (void) rpmteSetBreadth(q, breadth);
02068 
02069         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
02070                         orderingCount, rpmteNpreds(q),
02071                         rpmteTSI(q)->tsi_qcnt,
02072                         treex, depth, breadth,
02073                         (2 * depth), "",
02074                         deptypechar,
02075                         (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
02076 
02077         (void) rpmteSetDegree(q, 0);
02078         tsbytes += rpmtePkgFileSize(q);
02079 
02080         ordering[orderingCount] = rpmteAddedKey(q);
02081         orderingCount++;
02082         qlen--;
02083         loopcheck--;
02084 
02085         /* T6. Erase relations. */
02086         tsi_next = rpmteTSI(q)->tsi_next;
02087         rpmteTSI(q)->tsi_next = NULL;
02088         while ((tsi = tsi_next) != NULL) {
02089             tsi_next = tsi->tsi_next;
02090             tsi->tsi_next = NULL;
02091             p = tsi->tsi_suc;
02092             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
02093 
02094                 (void) rpmteSetTree(p, treex);
02095                 (void) rpmteSetDepth(p, depth+1);
02096                 (void) rpmteSetParent(p, q);
02097                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
02098 
02099                 /* XXX TODO: add control bit. */
02100                 rpmteTSI(p)->tsi_suc = NULL;
02101 /*@-nullstate@*/        /* XXX FIX: rpmteTSI(q)->tsi_suc can be NULL. */
02102                 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
02103 /*@=nullstate@*/
02104                 qlen++;
02105             }
02106             tsi = _free(tsi);
02107         }
02108         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
02109             _printed++;
02110             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
02111             rpmMessage(RPMMESS_DEBUG,
02112                 D_("========== successors only (%d bytes)\n"), (int)tsbytes);
02113 
02114             /* Relink the queue in presentation order. */
02115             tsi = rpmteTSI(q);
02116             pi = rpmtsiInit(ts);
02117             while ((p = rpmtsiNext(pi, oType)) != NULL) {
02118                 /* Is this element in the queue? */
02119                 if (rpmteTSI(p)->tsi_queued == 0)
02120                     /*@innercontinue@*/ continue;
02121                 tsi->tsi_suc = p;
02122                 tsi = rpmteTSI(p);
02123             }
02124             pi = rpmtsiFree(pi);
02125             tsi->tsi_suc = NULL;
02126         }
02127     }
02128 
02129     /* T8. End of process. Check for loops. */
02130     if (loopcheck != 0) {
02131         int nzaps;
02132 
02133         /* T9. Initialize predecessor chain. */
02134         nzaps = 0;
02135         qi = rpmtsiInit(ts);
02136         while ((q = rpmtsiNext(qi, oType)) != NULL) {
02137             rpmteTSI(q)->tsi_chain = NULL;
02138             rpmteTSI(q)->tsi_queued = 0;
02139             /* Mark packages already sorted. */
02140             if (rpmteTSI(q)->tsi_count == 0)
02141                 rpmteTSI(q)->tsi_count = -1;
02142         }
02143         qi = rpmtsiFree(qi);
02144 
02145         /* T10. Mark all packages with their predecessors. */
02146         qi = rpmtsiInit(ts);
02147         while ((q = rpmtsiNext(qi, oType)) != NULL) {
02148             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
02149                 continue;
02150             rpmteTSI(q)->tsi_next = NULL;
02151             markLoop(tsi, q);
02152             rpmteTSI(q)->tsi_next = tsi;
02153         }
02154         qi = rpmtsiFree(qi);
02155 
02156         /* T11. Print all dependency loops. */
02157         ri = rpmtsiInit(ts);
02158         while ((r = rpmtsiNext(ri, oType)) != NULL)
02159         {
02160             int printed;
02161 
02162             printed = 0;
02163 
02164             /* T12. Mark predecessor chain, looking for start of loop. */
02165             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
02166                  q = rpmteTSI(q)->tsi_chain)
02167             {
02168                 if (rpmteTSI(q)->tsi_queued)
02169                     /*@innerbreak@*/ break;
02170                 rpmteTSI(q)->tsi_queued = 1;
02171             }
02172 
02173             /* T13. Print predecessor chain from start of loop. */
02174             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
02175                 const char * dp;
02176                 char buf[4096];
02177                 int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
02178                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
02179 ;
02180 
02181                 /* Unchain predecessor loop. */
02182                 rpmteTSI(p)->tsi_chain = NULL;
02183 
02184                 if (!printed) {
02185                     rpmMessage(msglvl, _("LOOP:\n"));
02186                     printed = 1;
02187                 }
02188 
02189                 /* Find (and destroy if co-requisite) "q <- p" relation. */
02190                 dp = zapRelation(q, p, 1, &nzaps, msglvl);
02191 
02192                 /* Print next member of loop. */
02193                 buf[0] = '\0';
02194                 if (rpmteNEVRA(p) != NULL)
02195                     (void) stpcpy(buf, rpmteNEVRA(p));
02196                 rpmMessage(msglvl, "    %-40s %s\n", buf,
02197                         (dp ? dp : "not found!?!"));
02198 
02199                 dp = _free(dp);
02200             }
02201 
02202             /* Walk (and erase) linear part of predecessor chain as well. */
02203             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
02204                  p = q, q = rpmteTSI(q)->tsi_chain)
02205             {
02206                 /* Unchain linear part of predecessor loop. */
02207                 rpmteTSI(p)->tsi_chain = NULL;
02208                 rpmteTSI(p)->tsi_queued = 0;
02209             }
02210         }
02211         ri = rpmtsiFree(ri);
02212 
02213         /* If a relation was eliminated, then continue sorting. */
02214         /* XXX TODO: add control bit. */
02215         if (nzaps && nrescans-- > 0) {
02216             rpmMessage(RPMMESS_DEBUG, D_("========== continuing tsort ...\n"));
02217             goto rescan;
02218         }
02219 
02220         /* Return no. of packages that could not be ordered. */
02221         rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
02222                         loopcheck);
02223 
02224 #ifdef  NOTYET
02225         /* Do autorollback goal since we could not sort this transaction properly. */
02226         (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02227 #endif
02228 
02229         return loopcheck;
02230     }
02231 
02232     /* Clean up tsort remnants (if any). */
02233     pi = rpmtsiInit(ts);
02234     while ((p = rpmtsiNext(pi, 0)) != NULL)
02235         rpmteFreeTSI(p);
02236     pi = rpmtsiFree(pi);
02237 
02238     /*
02239      * The order ends up as installed packages followed by removed packages.
02240      */
02241     orderList = xcalloc(numOrderList, sizeof(*orderList));
02242     j = 0;
02243     pi = rpmtsiInit(ts);
02244     while ((p = rpmtsiNext(pi, oType)) != NULL) {
02245         /* Prepare added/erased package ordering permutation. */
02246         orderList[j].pkgKey = rpmteAddedKey(p);
02247         orderList[j].orIndex = rpmtsiOc(pi);
02248         j++;
02249     }
02250     pi = rpmtsiFree(pi);
02251 
02252     qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
02253 
02254 /*@-type@*/
02255     newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
02256 /*@=type@*/
02257     /*@-branchstate@*/
02258     for (i = 0, newOrderCount = 0; i < orderingCount; i++)
02259     {
02260         struct orderListIndex_s key;
02261         orderListIndex needle;
02262 
02263         key.pkgKey = ordering[i];
02264         needle = bsearch(&key, orderList, numOrderList,
02265                                 sizeof(key), orderListIndexCmp);
02266         if (needle == NULL)     /* XXX can't happen */
02267             continue;
02268 
02269         j = needle->orIndex;
02270         if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
02271             continue;
02272 
02273         newOrder[newOrderCount++] = q;
02274         ts->order[j] = NULL;
02275     }
02276     /*@=branchstate@*/
02277 
02278 assert(newOrderCount == ts->orderCount);
02279 
02280 /*@+voidabstract@*/
02281     ts->order = _free(ts->order);
02282 /*@=voidabstract@*/
02283     ts->order = newOrder;
02284     ts->orderAlloced = ts->orderCount;
02285     orderList = _free(orderList);
02286 
02287 #ifdef  DYING   /* XXX now done at the CLI level just before rpmtsRun(). */
02288     rpmtsClean(ts);
02289 #endif
02290     freeBadDeps();
02291 
02292     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
02293 
02294     return 0;
02295 }
02296 /*@=bounds@*/
02297 
02298 int rpmtsCheck(rpmts ts)
02299 {
02300     const char * depName = NULL;;
02301     rpmdepFlags depFlags = rpmtsDFlags(ts);
02302     uint_32 tscolor = rpmtsColor(ts);
02303     rpmdbMatchIterator mi = NULL;
02304     rpmtsi pi = NULL; rpmte p;
02305     int closeatexit = 0;
02306     int xx;
02307     int rc;
02308 
02309     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02310 
02311     /* Do lazy, readonly, open of rpm database. */
02312     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
02313         if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
02314             goto exit;
02315         closeatexit = 1;
02316     }
02317 
02318     ts->probs = rpmpsFree(ts->probs);
02319     ts->probs = rpmpsCreate();
02320 
02321     rpmalMakeIndex(ts->addedPackages);
02322 
02323     /*
02324      * Look at all of the added packages and make sure their dependencies
02325      * are satisfied.
02326      */
02327     pi = rpmtsiInit(ts);
02328     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
02329         rpmds provides, requires, conflicts, dirnames, linktos;
02330 
02331 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
02332         rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
02333                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02334 /*@=nullpass@*/
02335         requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)
02336             ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL);
02337         conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)
02338             ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL);
02339         dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)
02340             ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL);
02341         linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)
02342             ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL);
02343 
02344         rc = checkPackageDeps(ts, rpmteNEVRA(p),
02345                         requires, conflicts, dirnames, linktos,
02346                         NULL, tscolor, 1);
02347         if (rc)
02348             goto exit;
02349 
02350         rc = 0;
02351         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02352         provides = rpmdsInit(provides);
02353         if (provides != NULL)
02354         while (rpmdsNext(provides) >= 0) {
02355             depName = _free(depName);
02356             depName = xstrdup(rpmdsN(provides));
02357 
02358 #ifdef  NOTYET
02359             if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) {
02360                 const char * EVR = rpmdsEVR(provides);
02361                 if (rpmdsNegateRC(provides, 0))
02362                     EVR = NULL;
02363                 rc = envPut(depName, EVR);
02364                 if (!rc)
02365                     /*@innercontinue@*/ continue;
02366                 /*@innerbreak@*/ break;
02367             }
02368 #endif
02369 
02370             /* Adding: check provides key against conflicts matches. */
02371             if (!checkDependentConflicts(ts, depName))
02372                 /*@innercontinue@*/ continue;
02373             rc = 1;
02374             /*@innerbreak@*/ break;
02375         }
02376         if (rc)
02377             goto exit;
02378     }
02379     pi = rpmtsiFree(pi);
02380 
02381     /*
02382      * Look at the removed packages and make sure they aren't critical.
02383      */
02384     pi = rpmtsiInit(ts);
02385     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
02386         rpmds provides;
02387         rpmfi fi;
02388 
02389 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
02390         rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
02391                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02392 /*@=nullpass@*/
02393 
02394         rc = 0;
02395         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02396         provides = rpmdsInit(provides);
02397         if (provides != NULL)
02398         while (rpmdsNext(provides) >= 0) {
02399             depName = _free(depName);
02400             depName = xstrdup(rpmdsN(provides));
02401 
02402             /* Erasing: check provides against requiredby matches. */
02403             if (!checkDependentPackages(ts, depName))
02404                 /*@innercontinue@*/ continue;
02405             rc = 1;
02406             /*@innerbreak@*/ break;
02407         }
02408         if (rc)
02409             goto exit;
02410 
02411         rc = 0;
02412         fi = rpmteFI(p, RPMTAG_BASENAMES);
02413         fi = rpmfiInit(fi, 0);
02414         while (rpmfiNext(fi) >= 0) {
02415             depName = _free(depName);
02416             depName = xstrdup(rpmfiFN(fi));
02417             /* Erasing: check filename against requiredby matches. */
02418             if (!checkDependentPackages(ts, depName))
02419                 /*@innercontinue@*/ continue;
02420             rc = 1;
02421             /*@innerbreak@*/ break;
02422         }
02423         if (rc)
02424             goto exit;
02425     }
02426     pi = rpmtsiFree(pi);
02427 
02428     /*
02429      * Make sure transaction dependencies are satisfied.
02430      */
02431     {   const char * tsNEVRA = "transaction dependencies";
02432         rpmds R = rpmdsFromPRCO(ts->PRCO, RPMTAG_REQUIRENAME);
02433         rpmds C = rpmdsFromPRCO(ts->PRCO, RPMTAG_CONFLICTNAME);
02434         rpmds D = NULL;
02435         rpmds L = NULL;
02436         const char * dep = NULL;
02437         int adding = 2;
02438         tscolor = 0;    /* XXX no coloring for transaction dependencies. */
02439         rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding);
02440         if (rc)
02441             goto exit;
02442     }
02443 
02444     rc = 0;
02445 
02446 exit:
02447     mi = rpmdbFreeIterator(mi);
02448     pi = rpmtsiFree(pi);
02449     depName = _free(depName);
02450 
02451     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02452 
02453     /*@-branchstate@*/
02454     if (closeatexit)
02455         xx = rpmtsCloseDB(ts);
02456     else if (_cacheDependsRC)
02457         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
02458     /*@=branchstate@*/
02459 
02460 #ifdef  NOTYET
02461      /* On failed dependencies, perform the autorollback goal (if any). */
02462     {   rpmps ps = rpmtsProblems(ts);
02463         if (rc || rpmpsNumProblems(ps) > 0)
02464             (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02465         ps = rpmpsFree(ps);
02466     }
02467 #endif
02468 
02469     return rc;
02470 }

Generated on Fri Aug 31 10:38:31 2007 for rpm by  doxygen 1.5.1