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

Generated on Fri Aug 31 12:48:24 2007 for rpm by  doxygen 1.5.1