lib/depends.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include "rpmio_internal.h"     /* XXX PGPHASHALGO_MD5 */
00008 #include <rpmcli.h>             /* XXX rpmcliPackagesTotal */
00009 
00010 #include <rpmmacro.h>           /* XXX rpmExpand("%{_dependency_whiteout}" */
00011 #include <envvar.h>
00012 #include <ugid.h>               /* XXX user()/group() probes */
00013 
00014 #define _RPMDB_INTERNAL         /* XXX response cache needs dbiOpen et al. */
00015 #include "rpmdb.h"
00016 
00017 #define _RPMEVR_INTERNAL
00018 #include "rpmds.h"
00019 #include "rpmfi.h"
00020 
00021 #define _RPMTE_INTERNAL
00022 #include "rpmte.h"
00023 
00024 #define _RPMTS_INTERNAL
00025 #include "rpmts.h"
00026 
00027 #include "debug.h"
00028 
00029 /*@access tsortInfo @*/
00030 /*@access rpmte @*/             /* XXX for install <-> erase associate. */
00031 /*@access rpmts @*/
00032 /*@access rpmDiskSpaceInfo @*/
00033 
00034 /*@access alKey @*/     /* XXX for reordering and RPMAL_NOMATCH assign */
00035 
00038 typedef /*@abstract@*/ struct orderListIndex_s *        orderListIndex;
00039 /*@access orderListIndex@*/
00040 
00043 struct orderListIndex_s {
00044 /*@dependent@*/
00045     alKey pkgKey;
00046     int orIndex;
00047 };
00048 
00049 /*@unchecked@*/
00050 int _cacheDependsRC = 1;
00051 
00052 /*@observer@*/ /*@unchecked@*/
00053 const char *rpmNAME = PACKAGE;
00054 
00055 /*@observer@*/ /*@unchecked@*/
00056 const char *rpmEVR = VERSION;
00057 
00058 /*@unchecked@*/
00059 int rpmFLAGS = RPMSENSE_EQUAL;
00060 
00067 static int intcmp(const void * a, const void * b)
00068         /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
00069 {
00070     const int * aptr = a;
00071     const int * bptr = b;
00072     int rc = (*aptr - *bptr);
00073     return rc;
00074 }
00075 
00085 static int removePackage(rpmts ts, Header h, int dboffset,
00086                 /*@null@*/ int * indexp,
00087                 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
00088         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00089         /*@modifies ts, h, *indexp, rpmGlobalMacroContext, fileSystem, internalState @*/
00090 {
00091     rpmte p;
00092 
00093     /* Filter out duplicate erasures. */
00094     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00095         int * needle = NULL;
00096 /*@-boundswrite@*/
00097         needle = bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00098                         sizeof(*ts->removedPackages), intcmp);
00099         if (needle != NULL) {
00100             /* XXX lastx should be per-call, not per-ts. */
00101             if (indexp != NULL)
00102                 *indexp = needle - ts->removedPackages;
00103             return 0;
00104         }
00105 /*@=boundswrite@*/
00106     }
00107 
00108     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00109         ts->allocedRemovedPackages += ts->delta;
00110         ts->removedPackages = xrealloc(ts->removedPackages,
00111                 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
00112     }
00113 
00114     if (ts->removedPackages != NULL) {  /* XXX can't happen. */
00115 /*@-boundswrite@*/
00116         ts->removedPackages[ts->numRemovedPackages] = dboffset;
00117         ts->numRemovedPackages++;
00118 /*@=boundswrite@*/
00119         if (ts->numRemovedPackages > 1)
00120             qsort(ts->removedPackages, ts->numRemovedPackages,
00121                         sizeof(*ts->removedPackages), intcmp);
00122     }
00123 
00124     if (ts->orderCount >= ts->orderAlloced) {
00125         ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
00126 /*@-type +voidabstract @*/
00127         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00128 /*@=type =voidabstract @*/
00129     }
00130 
00131     p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
00132 /*@-boundswrite@*/
00133     ts->order[ts->orderCount] = p;
00134     if (indexp != NULL)
00135         *indexp = ts->orderCount;
00136     ts->orderCount++;
00137 /*@=boundswrite@*/
00138 
00139 /*@-nullstate@*/        /* XXX FIX: ts->order[] can be NULL. */
00140    return 0;
00141 /*@=nullstate@*/
00142 }
00143 
00150 static int rpmHeadersIdentical(Header first, Header second)
00151         /*@*/
00152 {
00153     const char * one, * two;
00154     rpmds A, B;
00155     int rc;
00156 
00157     if (!headerGetEntry(first, RPMTAG_HDRID, NULL, (void **) &one, NULL))
00158         one = NULL;
00159     if (!headerGetEntry(second, RPMTAG_HDRID, NULL, (void **) &two, NULL))
00160         two = NULL;
00161 
00162     if (one && two)
00163         return ((strcmp(one, two) == 0) ? 1 : 0);
00164     if (one && !two)
00165         return 0;
00166     if (!one && two)
00167         return 0;
00168     /* XXX Headers w/o digests case devolves to NEVR comparison. */
00169     A = rpmdsThis(first, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00170     B = rpmdsThis(second, RPMTAG_REQUIRENAME, RPMSENSE_EQUAL);
00171     rc = rpmdsCompare(A, B);
00172     A = rpmdsFree(A);
00173     B = rpmdsFree(B);
00174     return rc;
00175 }
00176 
00177 int rpmtsAddInstallElement(rpmts ts, Header h,
00178                         fnpyKey key, int upgrade, rpmRelocation relocs)
00179 {
00180     rpmdepFlags depFlags = rpmtsDFlags(ts);
00181     uint_32 tscolor = rpmtsColor(ts);
00182     uint_32 dscolor;
00183     uint_32 hcolor;
00184     rpmdbMatchIterator mi;
00185     Header oh;
00186     uint_32 ohcolor;
00187     int isSource;
00188     int duplicate = 0;
00189     rpmtsi pi = NULL; rpmte p;
00190     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00191     const char * arch;
00192     const char * os;
00193     rpmds oldChk, newChk;
00194     rpmds obsoletes;
00195     alKey pkgKey;       /* addedPackages key */
00196     int xx;
00197     int ec = 0;
00198     int rc;
00199     int oc;
00200 
00201     hcolor = hGetColor(h);
00202     pkgKey = RPMAL_NOMATCH;
00203 
00204     /*
00205      * Always add source headers.
00206      */
00207     isSource = (headerIsEntry(h, RPMTAG_SOURCERPM) == 0) ;
00208     if (isSource) {
00209         oc = ts->orderCount;
00210         goto addheader;
00211     }
00212 
00213     /*
00214      * Check platform affinity of binary packages.
00215      */
00216     arch = NULL;
00217     xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
00218     os = NULL;
00219     xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
00220     if (nplatpat > 1) {
00221         const char * platform = NULL;
00222 
00223         if (hge(h, RPMTAG_PLATFORM, NULL, (void **)&platform, NULL))
00224             platform = xstrdup(platform);
00225         else
00226             platform = rpmExpand(arch, "-unknown-", os, NULL);
00227 
00228         rc = rpmPlatformScore(platform, platpat, nplatpat);
00229         if (rc <= 0) {
00230             const char * pkgNEVR = hGetNEVRA(h, NULL);
00231             rpmps ps = rpmtsProblems(ts);
00232             rpmpsAppend(ps, RPMPROB_BADPLATFORM, pkgNEVR, key,
00233                         platform, NULL, NULL, 0);
00234             ps = rpmpsFree(ps);
00235             pkgNEVR = _free(pkgNEVR);
00236             ec = 1;
00237         }
00238         platform = _free(platform);
00239         if (ec)
00240             goto exit;
00241     }
00242 
00243     /*
00244      * Always install compatible binary packages.
00245      */
00246     if (!upgrade) {
00247         oc = ts->orderCount;
00248         goto addheader;
00249     }
00250 
00251     /*
00252      * Check that upgrade package is uniquely newer, replace older if necessary.
00253      */
00254     oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
00255     newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
00256     /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */
00257     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00258         rpmds this;
00259 
00260         /* XXX Only added packages need be checked for dupes here. */
00261         if (rpmteType(p) == TR_REMOVED)
00262             continue;
00263 
00264         /* XXX Never check source header NEVRAO. */
00265         if (rpmteIsSource(p))
00266             continue;
00267 
00268         if (tscolor) {
00269             const char * parch;
00270             const char * pos;
00271 
00272             if (arch == NULL || (parch = rpmteA(p)) == NULL)
00273                 continue;
00274             /* XXX hackery for i[3456]86 alias matching. */
00275             if (arch[0] == 'i' && arch[2] == '8' && arch[3] == '6') {
00276                 if (arch[0] != parch[0]) continue;
00277                 if (arch[2] != parch[2]) continue;
00278                 if (arch[3] != parch[3]) continue;
00279             } else if (strcmp(arch, parch))
00280                 continue;
00281             if (os == NULL || (pos = rpmteO(p)) == NULL)
00282                 continue;
00283 
00284             if (strcmp(os, pos))
00285                 continue;
00286         }
00287 
00288         /* OK, binary rpm's with same arch and os.  Check NEVR. */
00289         if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
00290             continue;   /* XXX can't happen */
00291 
00292         /* If newer NEVRAO already added, then skip adding older. */
00293         rc = rpmdsCompare(newChk, this);
00294         if (rc != 0) {
00295             const char * pkgNEVR = rpmdsDNEVR(this);
00296             const char * addNEVR = rpmdsDNEVR(oldChk);
00297             if (rpmIsVerbose())
00298                 rpmMessage(RPMMESS_WARNING,
00299                     _("package %s was already added, skipping %s\n"),
00300                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00301                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00302             ec = 1;
00303             break;
00304         }
00305 
00306         /* If older NEVRAO already added, then replace old with new. */
00307         rc = rpmdsCompare(oldChk, this);
00308         if (rc != 0) {
00309             const char * pkgNEVR = rpmdsDNEVR(this);
00310             const char * addNEVR = rpmdsDNEVR(newChk);
00311             if (rpmIsVerbose())
00312                 rpmMessage(RPMMESS_WARNING,
00313                     _("package %s was already added, replacing with %s\n"),
00314                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00315                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00316             duplicate = 1;
00317             pkgKey = rpmteAddedKey(p);
00318             break;
00319         }
00320     }
00321     pi = rpmtsiFree(pi);
00322     oldChk = rpmdsFree(oldChk);
00323     newChk = rpmdsFree(newChk);
00324 
00325     /* If newer (or same) NEVRAO was already added, exit now. */
00326     if (ec)
00327         goto exit;
00328 
00329 addheader:
00330     if (oc >= ts->orderAlloced) {
00331         ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
00332 /*@-type +voidabstract @*/
00333         ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
00334 /*@=type =voidabstract @*/
00335     }
00336 
00337     p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
00338 assert(p != NULL);
00339 
00340     if (duplicate && oc < ts->orderCount) {
00341 /*@-type -unqualifiedtrans@*/
00342 /*@-boundswrite@*/
00343         ts->order[oc] = rpmteFree(ts->order[oc]);
00344 /*@=boundswrite@*/
00345 /*@=type =unqualifiedtrans@*/
00346     }
00347 
00348 /*@-boundswrite@*/
00349     ts->order[oc] = p;
00350 /*@=boundswrite@*/
00351     if (!duplicate) {
00352         ts->orderCount++;
00353         rpmcliPackagesTotal++;
00354     }
00355     
00356     pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
00357                         rpmteDS(p, RPMTAG_PROVIDENAME),
00358                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
00359     if (pkgKey == RPMAL_NOMATCH) {
00360 /*@-boundswrite@*/
00361         ts->order[oc] = rpmteFree(ts->order[oc]);
00362 /*@=boundswrite@*/
00363         ts->teInstall = NULL;
00364         ec = 1;
00365         goto exit;
00366     }
00367     (void) rpmteSetAddedKey(p, pkgKey);
00368 
00369     if (!duplicate) {
00370         ts->numAddedPackages++;
00371     }
00372 
00373     ts->teInstall = ts->order[oc];
00374 
00375     /* XXX rpmgi hack: Save header in transaction element if requested. */
00376     if (upgrade & 0x2)
00377         (void) rpmteSetHeader(p, h);
00378 
00379     /* If not upgrading, then we're done. */
00380     if (!(upgrade & 0x1))
00381         goto exit;
00382 
00383     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00384     if (isSource)
00385         goto exit;
00386 
00387     /* Do lazy (readonly?) open of rpm database. */
00388     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
00389         if ((ec = rpmtsOpenDB(ts, ts->dbmode)) != 0)
00390             goto exit;
00391     }
00392 
00393     /* On upgrade, erase older packages of same color (if any). */
00394 
00395     /* NOTE: in PLD we don't want to remove packages which only provided
00396      * %{name} (e.g. perl-modules in case of some newer perl modules),
00397      * so we use NAME instead of PROVIDENAME (as in vanilla rpm) here */
00398 
00399   if (!(depFlags & RPMDEPS_FLAG_NOUPGRADE)) {
00400     mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
00401     while((oh = rpmdbNextIterator(mi)) != NULL) {
00402         int lastx;
00403         rpmte q;
00404 
00405         /* Ignore colored packages not in our rainbow. */
00406         ohcolor = hGetColor(oh);
00407         if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00408             continue;
00409 
00410         /* Skip identical packages. */
00411         if (rpmHeadersIdentical(h, oh))
00412             continue;
00413 
00414         /* Create an erasure element. */
00415         lastx = -1;
00416         xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), &lastx, pkgKey);
00417 assert(lastx >= 0 && lastx < ts->orderCount);
00418         q = ts->order[lastx];
00419 
00420         /* Chain through upgrade flink. */
00421         xx = rpmteChain(p, q, oh, "Upgrades");
00422 
00423 /*@-nullptrarith@*/
00424         rpmMessage(RPMMESS_DEBUG, _("   upgrade erases %s\n"), rpmteNEVRA(q));
00425 /*@=nullptrarith@*/
00426 
00427     }
00428     mi = rpmdbFreeIterator(mi);
00429   }
00430 
00431   if (!(depFlags & RPMDEPS_FLAG_NOOBSOLETES)) {
00432     obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
00433     obsoletes = rpmdsInit(obsoletes);
00434     if (obsoletes != NULL)
00435     while (rpmdsNext(obsoletes) >= 0) {
00436         const char * Name;
00437 
00438         if ((Name = rpmdsN(obsoletes)) == NULL)
00439             continue;   /* XXX can't happen */
00440 
00441         /* Ignore colored obsoletes not in our rainbow. */
00442 #if 0
00443         dscolor = rpmdsColor(obsoletes);
00444 #else
00445         dscolor = hcolor;
00446 #endif
00447         /* XXX obsoletes are never colored, so this is for future devel. */
00448         if (tscolor && dscolor && !(tscolor & dscolor))
00449             continue;
00450 
00451         /* XXX avoid self-obsoleting packages. */
00452         if (!strcmp(rpmteN(p), Name))
00453             continue;
00454 
00455         /* Obsolete containing package if given a file, otherwise provide. */
00456         if (Name[0] == '/')
00457             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00458         else
00459             mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00460 
00461         xx = rpmdbPruneIterator(mi,
00462             ts->removedPackages, ts->numRemovedPackages, 1);
00463 
00464         while((oh = rpmdbNextIterator(mi)) != NULL) {
00465             int lastx;
00466             rpmte q;
00467 
00468             /* Ignore colored packages not in our rainbow. */
00469             ohcolor = hGetColor(oh);
00470 
00471             /* XXX provides *are* colored, effectively limiting Obsoletes:
00472                 to matching only colored Provides: based on pkg coloring. */
00473             if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00474                 /*@innercontinue@*/ continue;
00475 
00476             /*
00477              * Rpm prior to 3.0.3 does not have versioned obsoletes.
00478              * If no obsoletes version info is available, match all names.
00479              */
00480             if (!(rpmdsEVR(obsoletes) == NULL
00481              || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)))
00482                 /*@innercontinue@*/ continue;
00483 
00484             /* Create an erasure element. */
00485             lastx = -1;
00486             xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), &lastx, pkgKey);
00487 assert(lastx >= 0 && lastx < ts->orderCount);
00488             q = ts->order[lastx];
00489 
00490             /* Chain through obsoletes flink. */
00491             xx = rpmteChain(p, q, oh, "Obsoletes");
00492 
00493 /*@-nullptrarith@*/
00494             rpmMessage(RPMMESS_DEBUG, _("  Obsoletes: %s\t\terases %s\n"),
00495                         rpmdsDNEVR(obsoletes)+2, rpmteNEVRA(q));
00496 /*@=nullptrarith@*/
00497         }
00498         mi = rpmdbFreeIterator(mi);
00499     }
00500     obsoletes = rpmdsFree(obsoletes);
00501   }
00502 
00503     ec = 0;
00504 
00505 exit:
00506     pi = rpmtsiFree(pi);
00507     return ec;
00508 }
00509 
00510 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
00511 {
00512     int oc = -1;
00513     int rc = removePackage(ts, h, dboffset, &oc, RPMAL_NOMATCH);
00514     if (rc == 0 && oc >= 0 && oc < ts->orderCount)
00515         ts->teErase = ts->order[oc];
00516     else
00517         ts->teErase = NULL;
00518     return rc;
00519 }
00520 
00528 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
00529         /*@globals _cacheDependsRC, rpmGlobalMacroContext, h_errno,
00530                 fileSystem, internalState @*/
00531         /*@modifies ts, dep, _cacheDependsRC, rpmGlobalMacroContext,
00532                 fileSystem, internalState @*/
00533 {
00534     DBT * key = alloca(sizeof(*key));
00535     DBT * data = alloca(sizeof(*data));
00536     rpmdbMatchIterator mi;
00537     nsType NSType;
00538     const char * Name;
00539     int_32 Flags;
00540     Header h;
00541     int _cacheThisRC = 1;
00542     int rc;
00543     int xx;
00544     int retries = 10;
00545 
00546     if ((Name = rpmdsN(dep)) == NULL)
00547         return 0;       /* XXX can't happen */
00548     Flags = rpmdsFlags(dep);
00549     NSType = rpmdsNSType(dep);
00550 
00551     /*
00552      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
00553      */
00554     if (_cacheDependsRC) {
00555         dbiIndex dbi;
00556         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00557         if (dbi == NULL)
00558             _cacheDependsRC = 0;
00559         else {
00560             const char * DNEVR;
00561 
00562             rc = -1;
00563 /*@-branchstate@*/
00564             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00565                 DBC * dbcursor = NULL;
00566                 void * datap = NULL;
00567                 size_t datalen = 0;
00568                 size_t DNEVRlen = strlen(DNEVR);
00569 
00570                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, 0);
00571 
00572                 memset(key, 0, sizeof(*key));
00573 /*@i@*/         key->data = (void *) DNEVR;
00574                 key->size = DNEVRlen;
00575                 memset(data, 0, sizeof(*data));
00576                 data->data = datap;
00577                 data->size = datalen;
00578 /*@-nullstate@*/ /* FIX: data->data may be NULL */
00579                 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
00580 /*@=nullstate@*/
00581                 DNEVR = key->data;
00582                 DNEVRlen = key->size;
00583                 datap = data->data;
00584                 datalen = data->size;
00585 
00586 /*@-boundswrite@*/
00587                 if (xx == 0 && datap && datalen == 4)
00588                     memcpy(&rc, datap, datalen);
00589 /*@=boundswrite@*/
00590                 xx = dbiCclose(dbi, dbcursor, 0);
00591             }
00592 /*@=branchstate@*/
00593 
00594             if (rc >= 0) {
00595                 rpmdsNotify(dep, _("(cached)"), rc);
00596                 return rpmdsNegateRC(dep, rc);
00597             }
00598         }
00599     }
00600 
00601 retry:
00602     rc = 0;     /* assume dependency is satisfied */
00603 
00604     /* Expand macro probe dependencies. */
00605     if (NSType == RPMNS_TYPE_FUNCTION) {
00606         xx = rpmExpandNumeric(Name);
00607         rc = (xx ? 0 : 1);
00608         if (Flags & RPMSENSE_MISSINGOK)
00609             goto unsatisfied;
00610         rpmdsNotify(dep, _("(function probe)"), rc);
00611         goto exit;
00612     }
00613 
00614     /* Evaluate user/group lookup probes. */
00615     if (NSType == RPMNS_TYPE_USER) {
00616         const char *s;
00617         uid_t uid = 0;
00618         s = Name; while (*s && xisdigit(*s)) s++;
00619 
00620         if (*s)
00621             xx = unameToUid(Name, &uid);
00622         else {
00623             uid = strtol(Name, NULL, 10);
00624             xx = (uidToUname(uid) ? 0 : -1);
00625         }
00626         rc = (xx >= 0 ? 0 : 1);
00627         if (Flags & RPMSENSE_MISSINGOK)
00628             goto unsatisfied;
00629         rpmdsNotify(dep, _("(user lookup)"), rc);
00630         goto exit;
00631     }
00632     if (NSType == RPMNS_TYPE_GROUP) {
00633         const char *s;
00634         gid_t gid = 0;
00635         s = Name; while (*s && xisdigit(*s)) s++;
00636 
00637         if (*s)
00638             xx = gnameToGid(Name, &gid);
00639         else {
00640             gid = strtol(Name, NULL, 10);
00641             xx = (gidToGname(gid) ? 0 : -1);
00642         }
00643         rc = (xx >= 0 ? 0 : 1);
00644         if (Flags & RPMSENSE_MISSINGOK)
00645             goto unsatisfied;
00646         rpmdsNotify(dep, _("(group lookup)"), rc);
00647         goto exit;
00648     }
00649 
00650     /* Evaluate access(2) probe dependencies. */
00651     if (NSType == RPMNS_TYPE_ACCESS) {
00652         rc = rpmioAccess(Name, NULL, X_OK);
00653         if (Flags & RPMSENSE_MISSINGOK)
00654             goto unsatisfied;
00655         rpmdsNotify(dep, _("(access probe)"), rc);
00656         goto exit;
00657     }
00658 
00659     /* Evaluate mtab lookup and diskspace probe dependencies. */
00660     if (NSType == RPMNS_TYPE_MOUNTED) {
00661         const char ** fs = NULL;
00662         int nfs = 0;
00663         int i = 0;
00664 
00665         xx = rpmtsInitDSI(ts);
00666         fs = ts->filesystems;
00667         nfs = ts->filesystemCount;
00668 
00669         if (fs != NULL)
00670         for (i = 0; i < nfs; i++) {
00671             if (!strcmp(fs[i], Name))
00672                 break;
00673         }
00674         rc = (i < nfs ? 0 : 1);
00675         if (Flags & RPMSENSE_MISSINGOK)
00676             goto unsatisfied;
00677         rpmdsNotify(dep, _("(mtab probe)"), rc);
00678         goto exit;
00679     }
00680 
00681     if (NSType == RPMNS_TYPE_DISKSPACE) {
00682         size_t nb = strlen(Name);
00683         rpmDiskSpaceInfo dsi = NULL;
00684         const char ** fs = NULL;
00685         size_t fslen = 0, longest = 0;
00686         int nfs = 0;
00687         int i = 0;
00688 
00689         xx = rpmtsInitDSI(ts);
00690         fs = ts->filesystems;
00691         nfs = ts->filesystemCount;
00692 
00693         if (fs != NULL)
00694         for (i = 0; i < nfs; i++) {
00695             fslen = strlen(fs[i]);
00696             if (fslen > nb)
00697                 continue;
00698             if (strncmp(fs[i], Name, fslen))
00699                 continue;
00700             if (fslen > 1 && Name[fslen] != '/' && Name[fslen] != '\0')
00701                 continue;
00702             if (fslen < longest)
00703                 continue;
00704             longest = fslen;
00705             dsi = ts->dsi + i;
00706         }
00707         if (dsi == NULL)
00708             rc = 1;     /* no mounted paths !?! */
00709         else {
00710             char * end = NULL;
00711             long long needed = strtoll(rpmdsEVR(dep), &end, 0);
00712 
00713             if (end && *end) {
00714                 if (strchr("Gg", end[0]) && strchr("Bb", end[1]) && !end[2])
00715                     needed *= 1024 * 1024 * 1024;
00716                 if (strchr("Mm", end[0]) && strchr("Bb", end[1]) && !end[2])
00717                     needed *= 1024 * 1024;
00718                 if (strchr("Kk", end[0]) && strchr("Bb", end[1]) && !end[2])
00719                     needed *= 1024;
00720             } else
00721                 needed *= 1024 * 1024;  /* XXX assume Mb if no units given */
00722 
00723             needed = BLOCK_ROUND(needed, dsi->f_bsize);
00724             xx = (dsi->f_bavail - needed);
00725             if ((Flags & RPMSENSE_LESS) && xx < 0) rc = 0;
00726             else if ((Flags & RPMSENSE_GREATER) && xx > 0) rc = 0;
00727             else if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
00728             else rc = 1;
00729         }
00730         if (Flags & RPMSENSE_MISSINGOK)
00731             goto unsatisfied;
00732         rpmdsNotify(dep, _("(diskspace probe)"), rc);
00733         goto exit;
00734     }
00735 
00736     if (NSType == RPMNS_TYPE_DIGEST) {
00737         const char * EVR = rpmdsEVR(dep);
00738         FD_t fd = Fopen(Name, "r");
00739 
00740         rc = 1;         /* XXX assume failure */
00741         if (fd && !Ferror(fd)) {
00742             pgpHashAlgo digestHashAlgo = PGPHASHALGO_MD5;
00743             DIGEST_CTX ctx = rpmDigestInit(digestHashAlgo, RPMDIGEST_NONE);
00744             const char * digest = NULL;
00745             size_t digestlen = 0;
00746             int asAscii = 1;
00747             size_t nbuf = 8 * BUFSIZ;
00748             char * buf = alloca(nbuf);
00749             size_t nb;
00750 
00751             while ((nb = Fread(buf, sizeof(buf[0]), nbuf, fd)) > 0)
00752                 xx = rpmDigestUpdate(ctx, buf, nb);
00753             xx = Fclose(fd);    fd = NULL;
00754             xx = rpmDigestFinal(ctx, (void **)&digest, &digestlen, asAscii);
00755 
00756             xx = (EVR && *EVR && digest && *digest) ? strcmp(EVR, digest) : -1;
00757             /* XXX only equality makes sense for digest compares */
00758             if ((Flags & RPMSENSE_EQUAL) && xx == 0) rc = 0;
00759         }
00760         if (Flags & RPMSENSE_MISSINGOK)
00761             goto unsatisfied;
00762         rpmdsNotify(dep, _("(digest probe)"), rc);
00763         goto exit;
00764     }
00765 
00766     if (NSType == RPMNS_TYPE_GNUPG) {
00767         static const char gnupg_pre[] = "%(%{__gpg} -qv ";
00768         static const char gnupg_post[] = " 2>/dev/null; echo $?)";
00769         const char * t = rpmExpand(gnupg_pre, Name, gnupg_post, NULL);
00770 
00771         rc = (t && t[0] == '0') ? 0 : 1;
00772         t = _free(t);
00773         if (Flags & RPMSENSE_MISSINGOK)
00774             goto unsatisfied;
00775         rpmdsNotify(dep, _("(gnupg probe)"), rc);
00776         goto exit;
00777     }
00778 
00779     if (NSType == RPMNS_TYPE_MACRO) {
00780         static const char macro_pre[] = "%{?";
00781         static const char macro_post[] = ":0}";
00782         const char * a = rpmExpand(macro_pre, Name, macro_post, NULL);
00783 
00784         rc = (a && a[0] == '0') ? 0 : 1;
00785         a = _free(a);
00786         if (Flags & RPMSENSE_MISSINGOK)
00787             goto unsatisfied;
00788         rpmdsNotify(dep, _("(macro probe)"), rc);
00789         goto exit;
00790     }
00791 
00792     if (NSType == RPMNS_TYPE_ENVVAR) {
00793         const char * a = envGet(Name);
00794         const char * b = rpmdsEVR(dep);
00795 
00796         /* Existence test if EVR is missing/empty. */
00797         if (!(b && *b))
00798             rc = (!(a && *a));
00799         else {
00800             int sense = (a && *a) ? strcmp(a, b) : -1;
00801 
00802             if ((Flags & RPMSENSE_SENSEMASK) == RPMSENSE_NOTEQUAL)
00803                 rc = (sense == 0);
00804             else if (sense < 0 && (Flags & RPMSENSE_LESS))
00805                 rc = 0;
00806             else if (sense > 0 && (Flags & RPMSENSE_GREATER))
00807                 rc = 0;
00808             else if (sense == 0 && (Flags & RPMSENSE_EQUAL))
00809                 rc = 0;
00810             else
00811                 rc = (sense != 0);
00812         }
00813 
00814         if (Flags & RPMSENSE_MISSINGOK)
00815             goto unsatisfied;
00816         rpmdsNotify(dep, _("(envvar probe)"), rc);
00817         goto exit;
00818     }
00819 
00820     if (NSType == RPMNS_TYPE_RUNNING) {
00821         char *t = NULL;
00822         pid_t pid = strtol(Name, &t, 10);
00823 
00824         if (t == NULL || *t != '\0') {
00825             const char * fn = rpmGetPath("%{_varrun}/", Name, ".pid", NULL);
00826             FD_t fd = NULL;
00827 
00828             if (fn && *fn != '%' && (fd = Fopen(fn, "r")) && !Ferror(fd)) {
00829                 char buf[32];
00830                 size_t nb = Fread(buf, sizeof(buf[0]), sizeof(buf), fd);
00831 
00832                 if (nb > 0)
00833                     pid = strtol(buf, &t, 10);
00834             } else
00835                 pid = 0;
00836             if (fd != NULL)
00837                 (void) Fclose(fd);
00838             fn = _free(fn);
00839         }
00840         rc = (pid > 0 ? (kill(pid, 0) < 0 && errno == ESRCH) : 1);
00841         if (Flags & RPMSENSE_MISSINGOK)
00842             goto unsatisfied;
00843         rpmdsNotify(dep, _("(running probe)"), rc);
00844         goto exit;
00845     }
00846 
00847     /* Search system configured provides. */
00848     if (!rpmioAccess("/etc/rpm/sysinfo", NULL, R_OK)) {
00849 #ifdef  NOTYET  /* XXX just sysinfo Provides: for now. */
00850         rpmTag tagN = (Name[0] == '/' ? RPMTAG_DIRNAMES : RPMTAG_PROVIDENAME);
00851 #else
00852         rpmTag tagN = RPMTAG_PROVIDENAME;
00853 #endif
00854         rpmds P = rpmdsFromPRCO(ts->PRCO, tagN);
00855         if (rpmdsSearch(P, dep) >= 0) {
00856             rpmdsNotify(dep, _("(sysinfo provides)"), rc);
00857             goto exit;
00858         }
00859     }
00860 
00861     /*
00862      * New features in rpm packaging implicitly add versioned dependencies
00863      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
00864      * Check those dependencies now.
00865      */
00866     if (NSType == RPMNS_TYPE_RPMLIB) {
00867         static rpmds rpmlibP = NULL;
00868         static int oneshot = -1;
00869 
00870         if (oneshot)
00871             oneshot = rpmdsRpmlib(&rpmlibP, NULL);
00872         if (rpmlibP == NULL)
00873             goto unsatisfied;
00874 
00875         if (rpmdsSearch(rpmlibP, dep) >= 0) {
00876             rpmdsNotify(dep, _("(rpmlib provides)"), rc);
00877             goto exit;
00878         }
00879         goto unsatisfied;
00880     }
00881 
00882     if (NSType == RPMNS_TYPE_CPUINFO) {
00883         static rpmds cpuinfoP = NULL;
00884         static int oneshot = -1;
00885 
00886         if (oneshot)
00887             oneshot = rpmdsCpuinfo(&cpuinfoP, NULL);
00888         if (cpuinfoP == NULL)
00889             goto unsatisfied;
00890 
00891         if (rpmdsSearch(cpuinfoP, dep) >= 0) {
00892             rpmdsNotify(dep, _("(cpuinfo provides)"), rc);
00893             goto exit;
00894         }
00895         goto unsatisfied;
00896     }
00897 
00898     if (NSType == RPMNS_TYPE_GETCONF) {
00899         static rpmds getconfP = NULL;
00900         static int oneshot = -1;
00901 
00902         if (oneshot)
00903             oneshot = rpmdsGetconf(&getconfP, NULL);
00904         if (getconfP == NULL)
00905             goto unsatisfied;
00906 
00907         if (rpmdsSearch(getconfP, dep) >= 0) {
00908             rpmdsNotify(dep, _("(getconf provides)"), rc);
00909             goto exit;
00910         }
00911         goto unsatisfied;
00912     }
00913 
00914     if (NSType == RPMNS_TYPE_UNAME) {
00915         static rpmds unameP = NULL;
00916         static int oneshot = -1;
00917 
00918         if (oneshot)
00919             oneshot = rpmdsUname(&unameP, NULL);
00920         if (unameP == NULL)
00921             goto unsatisfied;
00922 
00923         if (rpmdsSearch(unameP, dep) >= 0) {
00924             rpmdsNotify(dep, _("(uname provides)"), rc);
00925             goto exit;
00926         }
00927         goto unsatisfied;
00928     }
00929 
00930     if (NSType == RPMNS_TYPE_SONAME) {
00931         rpmds sonameP = NULL;
00932         rpmPRCO PRCO = rpmdsNewPRCO(NULL);
00933         char * fn = strcpy(alloca(strlen(Name)+1), Name);
00934         int flags = 0;  /* XXX RPMELF_FLAG_SKIPREQUIRES? */
00935         rpmds ds;
00936 
00937         /* XXX Only absolute paths for now. */
00938         if (*fn != '/')
00939             goto unsatisfied;
00940         fn[strlen(fn)-1] = '\0';
00941 
00942         /* Extract ELF Provides: from /path/to/DSO. */
00943         xx = rpmdsELF(fn, flags, rpmdsMergePRCO, PRCO);
00944         sonameP = rpmdsFromPRCO(PRCO, RPMTAG_PROVIDENAME);
00945         if (!(xx == 0 && sonameP != NULL))
00946             goto unsatisfied;
00947 
00948         /* Search using the original {EVR,"",Flags} from the dep set. */
00949         ds = rpmdsSingle(rpmdsTagN(dep), rpmdsEVR(dep), "", Flags);
00950         xx = rpmdsSearch(sonameP, ds);
00951         ds = rpmdsFree(ds);
00952         PRCO = rpmdsFreePRCO(PRCO);
00953 
00954         /* Was the dependency satisfied? */
00955         if (xx >= 0) {
00956             rpmdsNotify(dep, _("(soname provides)"), rc);
00957             goto exit;
00958         }
00959         goto unsatisfied;
00960     }
00961 
00962     /* Search added packages for the dependency. */
00963     if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
00964         /*
00965          * XXX Ick, context sensitive answers from dependency cache.
00966          * XXX Always resolve added dependencies within context to disambiguate.
00967          */
00968         if (_rpmds_nopromote)
00969             _cacheThisRC = 0;
00970         goto exit;
00971     }
00972 
00973     /* XXX only the installer does not have the database open here. */
00974     if (rpmtsGetRdb(ts) != NULL) {
00975 /*@-boundsread@*/
00976         if (Name[0] == '/') {
00977             /* depFlags better be 0! */
00978 
00979             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00980             (void) rpmdbPruneIterator(mi,
00981                         ts->removedPackages, ts->numRemovedPackages, 1);
00982             while ((h = rpmdbNextIterator(mi)) != NULL) {
00983                 rpmdsNotify(dep, _("(db files)"), rc);
00984                 mi = rpmdbFreeIterator(mi);
00985                 goto exit;
00986             }
00987             mi = rpmdbFreeIterator(mi);
00988         }
00989 /*@=boundsread@*/
00990 
00991         mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00992         (void) rpmdbPruneIterator(mi,
00993                         ts->removedPackages, ts->numRemovedPackages, 1);
00994         while ((h = rpmdbNextIterator(mi)) != NULL) {
00995             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
00996                 rpmdsNotify(dep, _("(db provides)"), rc);
00997                 mi = rpmdbFreeIterator(mi);
00998                 goto exit;
00999             }
01000         }
01001         mi = rpmdbFreeIterator(mi);
01002 
01003     }
01004 
01005     /*
01006      * Search for an unsatisfied dependency.
01007      */
01008 /*@-boundsread@*/
01009     if (adding == 1 && retries > 0 && !(rpmtsDFlags(ts) & RPMDEPS_FLAG_NOSUGGEST)) {
01010         if (ts->solve != NULL) {
01011             xx = (*ts->solve) (ts, dep, ts->solveData);
01012             if (xx == 0)
01013                 goto exit;
01014             if (xx == -1) {
01015                 retries--;
01016                 rpmalMakeIndex(ts->addedPackages);
01017                 goto retry;
01018             }
01019         }
01020     }
01021 /*@=boundsread@*/
01022 
01023 unsatisfied:
01024     if (Flags & RPMSENSE_MISSINGOK) {
01025         rc = 0; /* dependency is unsatisfied, but just a hint. */
01026         rpmdsNotify(dep, _("(hint skipped)"), rc);
01027     } else {
01028         rc = 1; /* dependency is unsatisfied */
01029         rpmdsNotify(dep, NULL, rc);
01030     }
01031 
01032 exit:
01033     /*
01034      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01035      */
01036     if (_cacheDependsRC && _cacheThisRC) {
01037         dbiIndex dbi;
01038         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
01039         if (dbi == NULL) {
01040             _cacheDependsRC = 0;
01041         } else {
01042             const char * DNEVR;
01043             xx = 0;
01044             /*@-branchstate@*/
01045             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
01046                 DBC * dbcursor = NULL;
01047                 size_t DNEVRlen = strlen(DNEVR);
01048 
01049                 xx = dbiCopen(dbi, dbiTxnid(dbi), &dbcursor, DB_WRITECURSOR);
01050 
01051                 memset(key, 0, sizeof(*key));
01052 /*@i@*/         key->data = (void *) DNEVR;
01053                 key->size = DNEVRlen;
01054                 memset(data, 0, sizeof(*data));
01055                 data->data = &rc;
01056                 data->size = sizeof(rc);
01057 
01058                 /*@-compmempass@*/
01059                 xx = dbiPut(dbi, dbcursor, key, data, 0);
01060                 /*@=compmempass@*/
01061                 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
01062             }
01063             /*@=branchstate@*/
01064             if (xx)
01065                 _cacheDependsRC = 0;
01066         }
01067     }
01068 
01069     return rpmdsNegateRC(dep, rc);
01070 }
01071 
01085 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
01086                 /*@null@*/ rpmds requires,
01087                 /*@null@*/ rpmds conflicts,
01088                 /*@null@*/ rpmds dirnames,
01089                 /*@null@*/ rpmds linktos,
01090                 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
01091         /*@globals rpmGlobalMacroContext, h_errno,
01092                 fileSystem, internalState @*/
01093         /*@modifies ts, requires, conflicts, dirnames, linktos,
01094                 rpmGlobalMacroContext, fileSystem, internalState */
01095 {
01096     rpmps ps = rpmtsProblems(ts);
01097     uint_32 dscolor;
01098     const char * Name;
01099     int rc;
01100     int ourrc = 0;
01101 
01102     requires = rpmdsInit(requires);
01103     if (requires != NULL)
01104     while (!ourrc && rpmdsNext(requires) >= 0) {
01105 
01106         if ((Name = rpmdsN(requires)) == NULL)
01107             continue;   /* XXX can't happen */
01108 
01109         /* Filter out requires that came along for the ride. */
01110         if (depName != NULL && strcmp(depName, Name))
01111             continue;
01112 
01113         /* Ignore colored requires not in our rainbow. */
01114         dscolor = rpmdsColor(requires);
01115         if (tscolor && dscolor && !(tscolor & dscolor))
01116             continue;
01117 
01118         rc = unsatisfiedDepend(ts, requires, adding);
01119 
01120         switch (rc) {
01121         case 0:         /* requirements are satisfied. */
01122             /*@switchbreak@*/ break;
01123         case 1:         /* requirements are not satisfied. */
01124         {   fnpyKey * suggestedKeys = NULL;
01125 
01126             /*@-branchstate@*/
01127             if (ts->availablePackages != NULL) {
01128                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01129                                 requires, NULL);
01130             }
01131             /*@=branchstate@*/
01132 
01133             rpmdsProblem(ps, pkgNEVRA, requires, suggestedKeys, adding);
01134 
01135         }
01136             /*@switchbreak@*/ break;
01137         case 2:         /* something went wrong! */
01138         default:
01139             ourrc = 1;
01140             /*@switchbreak@*/ break;
01141         }
01142     }
01143 
01144     conflicts = rpmdsInit(conflicts);
01145     if (conflicts != NULL)
01146     while (!ourrc && rpmdsNext(conflicts) >= 0) {
01147 
01148         if ((Name = rpmdsN(conflicts)) == NULL)
01149             continue;   /* XXX can't happen */
01150 
01151         /* Filter out conflicts that came along for the ride. */
01152         if (depName != NULL && strcmp(depName, Name))
01153             continue;
01154 
01155         /* Ignore colored conflicts not in our rainbow. */
01156         dscolor = rpmdsColor(conflicts);
01157         if (tscolor && dscolor && !(tscolor & dscolor))
01158             continue;
01159 
01160         rc = unsatisfiedDepend(ts, conflicts, adding);
01161 
01162         /* 1 == unsatisfied, 0 == satsisfied */
01163         switch (rc) {
01164         case 0:         /* conflicts exist. */
01165             rpmdsProblem(ps, pkgNEVRA, conflicts, NULL, adding);
01166             /*@switchbreak@*/ break;
01167         case 1:         /* conflicts don't exist. */
01168             /*@switchbreak@*/ break;
01169         case 2:         /* something went wrong! */
01170         default:
01171             ourrc = 1;
01172             /*@switchbreak@*/ break;
01173         }
01174     }
01175 
01176     dirnames = rpmdsInit(dirnames);
01177     if (dirnames != NULL)
01178     while (!ourrc && rpmdsNext(dirnames) >= 0) {
01179 
01180         if ((Name = rpmdsN(dirnames)) == NULL)
01181             continue;   /* XXX can't happen */
01182 
01183         /* Filter out dirnames that came along for the ride. */
01184         if (depName != NULL && strcmp(depName, Name))
01185             continue;
01186 
01187         /* Ignore colored dirnames not in our rainbow. */
01188         dscolor = rpmdsColor(dirnames);
01189         if (tscolor && dscolor && !(tscolor & dscolor))
01190             continue;
01191 
01192         rc = unsatisfiedDepend(ts, dirnames, adding);
01193 
01194         switch (rc) {
01195         case 0:         /* requirements are satisfied. */
01196             /*@switchbreak@*/ break;
01197         case 1:         /* requirements are not satisfied. */
01198         {   fnpyKey * suggestedKeys = NULL;
01199 
01200             /*@-branchstate@*/
01201             if (ts->availablePackages != NULL) {
01202                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01203                                 dirnames, NULL);
01204             }
01205             /*@=branchstate@*/
01206 
01207             rpmdsProblem(ps, pkgNEVRA, dirnames, suggestedKeys, adding);
01208 
01209         }
01210             /*@switchbreak@*/ break;
01211         case 2:         /* something went wrong! */
01212         default:
01213             ourrc = 1;
01214             /*@switchbreak@*/ break;
01215         }
01216     }
01217 
01218     linktos = rpmdsInit(linktos);
01219     if (linktos != NULL)
01220     while (!ourrc && rpmdsNext(linktos) >= 0) {
01221 
01222         if ((Name = rpmdsN(linktos)) == NULL)
01223             continue;   /* XXX can't happen */
01224         if (*Name == '\0')      /* XXX most linktos are empty */
01225                 continue;
01226 
01227         /* Filter out linktos that came along for the ride. */
01228         if (depName != NULL && strcmp(depName, Name))
01229             continue;
01230 
01231         /* Ignore colored linktos not in our rainbow. */
01232         dscolor = rpmdsColor(linktos);
01233         if (tscolor && dscolor && !(tscolor & dscolor))
01234             continue;
01235 
01236         rc = unsatisfiedDepend(ts, linktos, adding);
01237 
01238         switch (rc) {
01239         case 0:         /* requirements are satisfied. */
01240             /*@switchbreak@*/ break;
01241         case 1:         /* requirements are not satisfied. */
01242         {   fnpyKey * suggestedKeys = NULL;
01243 
01244             /*@-branchstate@*/
01245             if (ts->availablePackages != NULL) {
01246                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
01247                                 linktos, NULL);
01248             }
01249             /*@=branchstate@*/
01250 
01251             rpmdsProblem(ps, pkgNEVRA, linktos, suggestedKeys, adding);
01252 
01253         }
01254             /*@switchbreak@*/ break;
01255         case 2:         /* something went wrong! */
01256         default:
01257             ourrc = 1;
01258             /*@switchbreak@*/ break;
01259         }
01260     }
01261 
01262     ps = rpmpsFree(ps);
01263     return ourrc;
01264 }
01265 
01276 static int checkPackageSet(rpmts ts, const char * depName,
01277                 /*@only@*/ /*@null@*/ rpmdbMatchIterator mi, int adding)
01278         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01279         /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
01280 {
01281     rpmdepFlags depFlags = rpmtsDFlags(ts);
01282     uint_32 tscolor = rpmtsColor(ts);
01283     int scareMem = 0;
01284     Header h;
01285     int ec = 0;
01286 
01287     (void) rpmdbPruneIterator(mi,
01288                 ts->removedPackages, ts->numRemovedPackages, 1);
01289     while ((h = rpmdbNextIterator(mi)) != NULL) {
01290         const char * pkgNEVRA;
01291         rpmds requires = NULL;
01292         rpmds conflicts = NULL;
01293         rpmds dirnames = NULL;
01294         rpmds linktos = NULL;
01295         int rc;
01296 
01297         pkgNEVRA = hGetNEVRA(h, NULL);
01298         if (!(depFlags & RPMDEPS_FLAG_NOREQUIRES))
01299             requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
01300         if (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS))
01301             conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
01302         if (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS))
01303             dirnames = rpmdsNew(h, RPMTAG_DIRNAMES, scareMem);
01304         if (!(depFlags & RPMDEPS_FLAG_NOLINKTOS))
01305             linktos = rpmdsNew(h, RPMTAG_FILELINKTOS, scareMem);
01306 
01307         (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
01308         (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
01309         (void) rpmdsSetNoPromote(dirnames, _rpmds_nopromote);
01310         (void) rpmdsSetNoPromote(linktos, _rpmds_nopromote);
01311 
01312         rc = checkPackageDeps(ts, pkgNEVRA,
01313                 requires, conflicts, dirnames, linktos,
01314                 depName, tscolor, adding);
01315 
01316         linktos = rpmdsFree(linktos);
01317         dirnames = rpmdsFree(dirnames);
01318         conflicts = rpmdsFree(conflicts);
01319         requires = rpmdsFree(requires);
01320         pkgNEVRA = _free(pkgNEVRA);
01321 
01322         if (rc) {
01323             ec = 1;
01324             break;
01325         }
01326     }
01327     mi = rpmdbFreeIterator(mi);
01328 
01329     return ec;
01330 }
01331 
01338 static int checkDependentPackages(rpmts ts, const char * depName)
01339         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01340         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01341 {
01342     int rc = 0;
01343 
01344     /* XXX rpmdb can be closed here, avoid error msg. */
01345     if (rpmtsGetRdb(ts) != NULL) {
01346         rpmdbMatchIterator mi;
01347         mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, depName, 0);
01348         rc = checkPackageSet(ts, depName, mi, 0);
01349     }
01350     return rc;
01351 }
01352 
01359 static int checkDependentConflicts(rpmts ts, const char * depName)
01360         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01361         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
01362 {
01363     int rc = 0;
01364 
01365     /* XXX rpmdb can be closed here, avoid error msg. */
01366     if (rpmtsGetRdb(ts) != NULL) {
01367         rpmdbMatchIterator mi;
01368         mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, depName, 0);
01369         rc = checkPackageSet(ts, depName, mi, 1);
01370     }
01371 
01372     return rc;
01373 }
01374 
01375 struct badDeps_s {
01376 /*@observer@*/ /*@owned@*/ /*@null@*/
01377     const char * pname;
01378 /*@observer@*/ /*@dependent@*/ /*@null@*/
01379     const char * qname;
01380 };
01381 
01382 #ifdef REFERENCE
01383 static struct badDeps_s {
01384 /*@observer@*/ /*@null@*/ const char * pname;
01385 /*@observer@*/ /*@null@*/ const char * qname;
01386 } badDeps[] = {
01387     { "libtermcap", "bash" },
01388     { "modutils", "vixie-cron" },
01389     { "ypbind", "yp-tools" },
01390     { "ghostscript-fonts", "ghostscript" },
01391     /* 7.2 only */
01392     { "libgnomeprint15", "gnome-print" },
01393     { "nautilus", "nautilus-mozilla" },
01394     /* 7.1 only */
01395     { "arts", "kdelibs-sound" },
01396     /* 7.0 only */
01397     { "pango-gtkbeta-devel", "pango-gtkbeta" },
01398     { "XFree86", "Mesa" },
01399     { "compat-glibc", "db2" },
01400     { "compat-glibc", "db1" },
01401     { "pam", "initscripts" },
01402     { "initscripts", "sysklogd" },
01403     /* 6.2 */
01404     { "egcs-c++", "libstdc++" },
01405     /* 6.1 */
01406     { "pilot-link-devel", "pilot-link" },
01407     /* 5.2 */
01408     { "pam", "pamconfig" },
01409     { NULL, NULL }
01410 };
01411 #else
01412 /*@unchecked@*/
01413 static int badDepsInitialized = 0;
01414 
01415 /*@unchecked@*/ /*@only@*/ /*@null@*/
01416 static struct badDeps_s * badDeps = NULL;
01417 #endif
01418 
01421 /*@-modobserver -observertrans @*/
01422 static void freeBadDeps(void)
01423         /*@globals badDeps, badDepsInitialized @*/
01424         /*@modifies badDeps, badDepsInitialized @*/
01425 {
01426     if (badDeps) {
01427         struct badDeps_s * bdp;
01428         for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
01429             bdp->pname = _free(bdp->pname);
01430         badDeps = _free(badDeps);
01431     }
01432     badDepsInitialized = 0;
01433 }
01434 /*@=modobserver =observertrans @*/
01435 
01444 /*@-boundsread@*/
01445 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q)
01446         /*@globals badDeps, badDepsInitialized,
01447                 rpmGlobalMacroContext, h_errno @*/
01448         /*@modifies badDeps, badDepsInitialized,
01449                 rpmGlobalMacroContext @*/
01450 {
01451     struct badDeps_s * bdp;
01452 
01453     if (!badDepsInitialized) {
01454         char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
01455         const char ** av = NULL;
01456         int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
01457         int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
01458                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01459         int ac = 0;
01460         int i;
01461 
01462         if (s != NULL && *s != '\0'
01463         && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
01464         && ac > 0 && av != NULL)
01465         {
01466             bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
01467             for (i = 0; i < ac; i++, bdp++) {
01468                 char * pname, * qname;
01469 
01470                 if (av[i] == NULL)
01471                     break;
01472                 pname = xstrdup(av[i]);
01473                 if ((qname = strchr(pname, '>')) != NULL)
01474                     *qname++ = '\0';
01475                 bdp->pname = pname;
01476                 /*@-usereleased@*/
01477                 bdp->qname = qname;
01478                 /*@=usereleased@*/
01479                 rpmMessage(msglvl,
01480                         _("ignore package name relation(s) [%d]\t%s -> %s\n"),
01481                         i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
01482             }
01483             bdp->pname = NULL;
01484             bdp->qname = NULL;
01485         }
01486         av = _free(av);
01487         s = _free(s);
01488         badDepsInitialized++;
01489     }
01490 
01491     /*@-compdef@*/
01492     if (badDeps != NULL)
01493     for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
01494         if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
01495             return 1;
01496     }
01497     return 0;
01498     /*@=compdef@*/
01499 }
01500 /*@=boundsread@*/
01501 
01507 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
01508         /*@globals internalState @*/
01509         /*@uses tsi @*/
01510         /*@modifies internalState @*/
01511 {
01512     rpmte p;
01513 
01514     /*@-branchstate@*/ /* FIX: q is kept */
01515     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
01516         tsi = tsi->tsi_next;
01517         if (rpmteTSI(p)->tsi_chain != NULL)
01518             continue;
01519         /*@-assignexpose -temptrans@*/
01520         rpmteTSI(p)->tsi_chain = q;
01521         /*@=assignexpose =temptrans@*/
01522         if (rpmteTSI(p)->tsi_next != NULL)
01523             markLoop(rpmteTSI(p)->tsi_next, p);
01524     }
01525     /*@=branchstate@*/
01526 }
01527 
01528 /*
01529  * Return display string a dependency, adding contextual flags marker.
01530  * @param f             dependency flags
01531  * @return              display string
01532  */
01533 static inline /*@observer@*/ const char * identifyDepend(int_32 f)
01534         /*@*/
01535 {
01536     f = _notpre(f);
01537     if (f & RPMSENSE_SCRIPT_PRE)
01538         return "Requires(pre):";
01539     if (f & RPMSENSE_SCRIPT_POST)
01540         return "Requires(post):";
01541     if (f & RPMSENSE_SCRIPT_PREUN)
01542         return "Requires(preun):";
01543     if (f & RPMSENSE_SCRIPT_POSTUN)
01544         return "Requires(postun):";
01545     if (f & RPMSENSE_SCRIPT_VERIFY)
01546         return "Requires(verify):";
01547     if (f & RPMSENSE_MISSINGOK)
01548         return "Requires(hint):";
01549     if (f & RPMSENSE_FIND_REQUIRES)
01550         return "Requires(auto):";
01551     return "Requires:";
01552 }
01553 
01566 /*@-boundswrite@*/
01567 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
01568 static /*@owned@*/ /*@null@*/ const char *
01569 zapRelation(rpmte q, rpmte p,
01570                 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl)
01571         /*@globals rpmGlobalMacroContext, h_errno @*/
01572         /*@modifies q, p, *nzaps, rpmGlobalMacroContext @*/
01573 {
01574     rpmds requires;
01575     tsortInfo tsi_prev;
01576     tsortInfo tsi;
01577     const char *dp = NULL;
01578 
01579     for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
01580          tsi != NULL;
01581         /* XXX Note: the loop traverses "not found", break on "found". */
01582         /*@-nullderef@*/
01583          tsi_prev = tsi, tsi = tsi->tsi_next)
01584         /*@=nullderef@*/
01585     {
01586         int_32 Flags;
01587 
01588         /*@-abstractcompare@*/
01589         if (tsi->tsi_suc != p)
01590             continue;
01591         /*@=abstractcompare@*/
01592 
01593         requires = rpmteDS(p, tsi->tsi_tagn);
01594         if (requires == NULL) continue;         /* XXX can't happen */
01595 
01596         (void) rpmdsSetIx(requires, tsi->tsi_reqx);
01597 
01598         Flags = rpmdsFlags(requires);
01599 
01600         dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
01601 
01602         /*
01603          * Attempt to unravel a dependency loop by eliminating Requires's.
01604          */
01605         /*@-branchstate@*/
01606         if (zap) {
01607             rpmMessage(msglvl,
01608                         _("removing %s \"%s\" from tsort relations.\n"),
01609                         (rpmteNEVRA(p) ?  rpmteNEVRA(p) : "???"), dp);
01610             rpmteTSI(p)->tsi_count--;
01611             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01612             tsi->tsi_next = NULL;
01613             tsi->tsi_suc = NULL;
01614             tsi = _free(tsi);
01615             if (nzaps)
01616                 (*nzaps)++;
01617             if (zap)
01618                 zap--;
01619         }
01620         /*@=branchstate@*/
01621         /* XXX Note: the loop traverses "not found", get out now! */
01622         break;
01623     }
01624     return dp;
01625 }
01626 /*@=mustmod@*/
01627 /*@=boundswrite@*/
01628 
01637 /*@-mustmod@*/
01638 static inline int addRelation(rpmts ts,
01639                 /*@dependent@*/ rpmte p,
01640                 unsigned char * selected,
01641                 rpmds requires)
01642         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01643         /*@modifies ts, p, *selected, rpmGlobalMacroContext,
01644                 fileSystem, internalState @*/
01645 {
01646     rpmtsi qi; rpmte q;
01647     tsortInfo tsi;
01648     const char * Name;
01649     fnpyKey key;
01650     int teType = rpmteType(p);
01651     alKey pkgKey;
01652     int i = 0;
01653     rpmal al = (teType == TR_ADDED ? ts->addedPackages : ts->erasedPackages);
01654 
01655     if ((Name = rpmdsN(requires)) == NULL)
01656         return 0;
01657 
01658     /* Avoid rpmlib feature dependencies. */
01659     if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
01660         return 0;
01661 
01662     /* Avoid package config dependencies. */
01663     if (!strncmp(Name, "config(", sizeof("config(")-1))
01664         return 0;
01665 
01666     pkgKey = RPMAL_NOMATCH;
01667     key = rpmalSatisfiesDepend(al, requires, &pkgKey);
01668 
01669     /* Ordering depends only on added/erased package relations. */
01670     if (pkgKey == RPMAL_NOMATCH)
01671         return 0;
01672 
01673 /* XXX Set q to the added/removed package that was found. */
01674     /* XXX pretend erasedPackages are just appended to addedPackages. */
01675     if (teType == TR_REMOVED)
01676         pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
01677 
01678     for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
01679         if (pkgKey == rpmteAddedKey(q))
01680             break;
01681     }
01682     qi = rpmtsiFree(qi);
01683     if (q == NULL || i >= ts->orderCount)
01684         return 0;
01685 
01686     /* Avoid certain dependency relations. */
01687     if (teType == TR_ADDED && ignoreDep(ts, p, q))
01688         return 0;
01689 
01690     /* Avoid redundant relations. */
01691 /*@-boundsread@*/
01692     if (selected[i] != 0)
01693         return 0;
01694 /*@=boundsread@*/
01695 /*@-boundswrite@*/
01696     selected[i] = 1;
01697 /*@=boundswrite@*/
01698 
01699     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01700     rpmteTSI(p)->tsi_count++;                   /* bump p predecessor count */
01701 
01702     if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
01703         (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
01704     if (rpmteDepth(p) > ts->maxDepth)
01705         ts->maxDepth = rpmteDepth(p);
01706 
01707     tsi = xcalloc(1, sizeof(*tsi));
01708     tsi->tsi_suc = p;
01709 
01710     tsi->tsi_tagn = rpmdsTagN(requires);
01711     tsi->tsi_reqx = rpmdsIx(requires);
01712 
01713     tsi->tsi_next = rpmteTSI(q)->tsi_next;
01714     rpmteTSI(q)->tsi_next = tsi;
01715     rpmteTSI(q)->tsi_qcnt++;                    /* bump q successor count */
01716     return 0;
01717 }
01718 /*@=mustmod@*/
01719 
01726 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01727 {
01728     /*@-castexpose@*/
01729     long a = (long) ((const orderListIndex)one)->pkgKey;
01730     long b = (long) ((const orderListIndex)two)->pkgKey;
01731     /*@=castexpose@*/
01732     return (a - b);
01733 }
01734 
01742 /*@-boundswrite@*/
01743 /*@-mustmod@*/
01744 static void addQ(/*@dependent@*/ rpmte p,
01745                 /*@in@*/ /*@out@*/ rpmte * qp,
01746                 /*@in@*/ /*@out@*/ rpmte * rp,
01747                 uint_32 prefcolor)
01748         /*@modifies p, *qp, *rp @*/
01749 {
01750     rpmte q, qprev;
01751 
01752     /* Mark the package as queued. */
01753     rpmteTSI(p)->tsi_queued = 1;
01754 
01755     if ((*rp) == NULL) {        /* 1st element */
01756         /*@-dependenttrans@*/ /* FIX: double indirection */
01757         (*rp) = (*qp) = p;
01758         /*@=dependenttrans@*/
01759         return;
01760     }
01761 
01762     /* Find location in queue using metric tsi_qcnt. */
01763     for (qprev = NULL, q = (*qp);
01764          q != NULL;
01765          qprev = q, q = rpmteTSI(q)->tsi_suc)
01766     {
01767         /* XXX Insure preferred color first. */
01768         if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
01769             continue;
01770 
01771         /* XXX Insure removed after added. */
01772         if (rpmteType(p) == TR_REMOVED && rpmteType(p) != rpmteType(q))
01773             continue;
01774         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01775             break;
01776     }
01777 
01778     if (qprev == NULL) {        /* insert at beginning of list */
01779         rpmteTSI(p)->tsi_suc = q;
01780         /*@-dependenttrans@*/
01781         (*qp) = p;              /* new head */
01782         /*@=dependenttrans@*/
01783     } else if (q == NULL) {     /* insert at end of list */
01784         rpmteTSI(qprev)->tsi_suc = p;
01785         /*@-dependenttrans@*/
01786         (*rp) = p;              /* new tail */
01787         /*@=dependenttrans@*/
01788     } else {                    /* insert between qprev and q */
01789         rpmteTSI(p)->tsi_suc = q;
01790         rpmteTSI(qprev)->tsi_suc = p;
01791     }
01792 }
01793 /*@=mustmod@*/
01794 /*@=boundswrite@*/
01795 
01796 /*@unchecked@*/
01797 #ifdef  NOTYET
01798 static uint32_t _autobits = _notpre(_ALL_REQUIRES_MASK);
01799 #define isAuto(_x)      ((_x) & _autobits)
01800 #else
01801 static uint32_t _autobits = 0xffffffff;
01802 #define isAuto(_x)      (1)
01803 #endif
01804 
01805 /*@-bounds@*/
01806 int rpmtsOrder(rpmts ts)
01807 {
01808     rpmds requires;
01809     int_32 Flags;
01810     int anaconda = rpmtsDFlags(ts) & RPMDEPS_FLAG_ANACONDA;
01811     uint_32 prefcolor = rpmtsPrefColor(ts);
01812     rpmtsi pi; rpmte p;
01813     rpmtsi qi; rpmte q;
01814     rpmtsi ri; rpmte r;
01815     tsortInfo tsi;
01816     tsortInfo tsi_next;
01817     alKey * ordering;
01818     int orderingCount = 0;
01819     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01820     int loopcheck;
01821     rpmte * newOrder;
01822     int newOrderCount = 0;
01823     orderListIndex orderList;
01824     int numOrderList;
01825     int npeer = 128;    /* XXX more than deep enough for now. */
01826     int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
01827     int nrescans = 10;
01828     int _printed = 0;
01829     char deptypechar;
01830     size_t tsbytes;
01831     int oType = 0;
01832     int treex;
01833     int depth;
01834     int breadth;
01835     int qlen;
01836     int i, j;
01837 
01838 #ifdef  DYING
01839     rpmalMakeIndex(ts->addedPackages);
01840 #endif
01841 
01842     /* Create erased package index. */
01843     pi = rpmtsiInit(ts);
01844     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01845         alKey pkgKey;
01846         fnpyKey key;
01847         uint_32 tscolor = rpmtsColor(ts);
01848         pkgKey = RPMAL_NOMATCH;
01849 /*@-abstract@*/
01850         key = (fnpyKey) p;
01851 /*@=abstract@*/
01852         pkgKey = rpmalAdd(&ts->erasedPackages, pkgKey, key,
01853                         rpmteDS(p, RPMTAG_PROVIDENAME),
01854                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
01855         /* XXX pretend erasedPackages are just appended to addedPackages. */
01856         pkgKey = (alKey)(((long)pkgKey) + ts->numAddedPackages);
01857         (void) rpmteSetAddedKey(p, pkgKey);
01858     }
01859     pi = rpmtsiFree(pi);
01860     rpmalMakeIndex(ts->erasedPackages);
01861 
01862     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01863 
01864     /* T1. Initialize. */
01865     if (oType == 0)
01866         numOrderList = ts->orderCount;
01867     else {
01868         numOrderList = 0;
01869         if (oType & TR_ADDED)
01870             numOrderList += ts->numAddedPackages;
01871         if (oType & TR_REMOVED)
01872             numOrderList += ts->numRemovedPackages;
01873      }
01874     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01875     loopcheck = numOrderList;
01876     tsbytes = 0;
01877 
01878     pi = rpmtsiInit(ts);
01879     while ((p = rpmtsiNext(pi, oType)) != NULL)
01880         rpmteNewTSI(p);
01881     pi = rpmtsiFree(pi);
01882 
01883     /* Record all relations. */
01884     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01885     pi = rpmtsiInit(ts);
01886     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01887 
01888         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01889 
01890       if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) != NULL) {
01891 
01892         /* Avoid narcisstic relations. */
01893         selected[rpmtsiOc(pi)] = 1;
01894 
01895         /* T2. Next "q <- p" relation. */
01896 
01897         /* First, do pre-requisites. */
01898         requires = rpmdsInit(requires);
01899         if (requires != NULL)
01900         while (rpmdsNext(requires) >= 0) {
01901 
01902             Flags = rpmdsFlags(requires);
01903             if (!isAuto(Flags))
01904                 /*@innercontinue@*/ continue;
01905 
01906             switch (rpmteType(p)) {
01907             case TR_REMOVED:
01908                 /* Skip if not %preun/%postun requires. */
01909                 if (!isErasePreReq(Flags))
01910                     /*@innercontinue@*/ continue;
01911                 /*@switchbreak@*/ break;
01912             case TR_ADDED:
01913                 /* Skip if not %pre/%post requires. */
01914                 if (!isInstallPreReq(Flags))
01915                     /*@innercontinue@*/ continue;
01916                 /*@switchbreak@*/ break;
01917             }
01918 
01919             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01920             (void) addRelation(ts, p, selected, requires);
01921 
01922         }
01923 
01924         /* Then do co-requisites. */
01925         requires = rpmdsInit(requires);
01926         if (requires != NULL)
01927         while (rpmdsNext(requires) >= 0) {
01928 
01929             Flags = rpmdsFlags(requires);
01930             if (!isAuto(Flags))
01931                 /*@innercontinue@*/ continue;
01932 
01933             switch (rpmteType(p)) {
01934             case TR_REMOVED:
01935                 /* Skip if %preun/%postun requires. */
01936                 if (isErasePreReq(Flags))
01937                     /*@innercontinue@*/ continue;
01938                 /*@switchbreak@*/ break;
01939             case TR_ADDED:
01940                 /* Skip if %pre/%post requires. */
01941                 if (isInstallPreReq(Flags))
01942                     /*@innercontinue@*/ continue;
01943                 /*@switchbreak@*/ break;
01944             }
01945 
01946             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01947             (void) addRelation(ts, p, selected, requires);
01948 
01949         }
01950       }
01951 
01952       if (_autobits != 0xffffffff)
01953       {
01954 
01955         /* Order by requiring parent directories pre-requsites. */
01956         requires = rpmdsInit(rpmteDS(p, RPMTAG_DIRNAMES));
01957         if (requires != NULL)
01958         while (rpmdsNext(requires) >= 0) {
01959 
01960             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01961             (void) addRelation(ts, p, selected, requires);
01962 
01963         }
01964 
01965         /* Order by requiring no dangling symlinks. */
01966         requires = rpmdsInit(rpmteDS(p, RPMTAG_FILELINKTOS));
01967         if (requires != NULL)
01968         while (rpmdsNext(requires) >= 0) {
01969 
01970             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01971             (void) addRelation(ts, p, selected, requires);
01972 
01973         }
01974       }
01975 
01976     }
01977     pi = rpmtsiFree(pi);
01978 
01979     /* Save predecessor count and mark tree roots. */
01980     treex = 0;
01981     pi = rpmtsiInit(ts);
01982     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01983         int npreds;
01984 
01985         npreds = rpmteTSI(p)->tsi_count;
01986 
01987         (void) rpmteSetNpreds(p, npreds);
01988         (void) rpmteSetDepth(p, 0);
01989 
01990         if (npreds == 0) {
01991             treex++;
01992             (void) rpmteSetTree(p, treex);
01993             (void) rpmteSetBreadth(p, treex);
01994         } else
01995             (void) rpmteSetTree(p, -1);
01996 #ifdef  UNNECESSARY
01997         (void) rpmteSetParent(p, NULL);
01998 #endif
01999 
02000     }
02001     pi = rpmtsiFree(pi);
02002     ts->ntrees = treex;
02003 
02004     /* T4. Scan for zeroes. */
02005     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, Ldepth, Rbreadth)\n"));
02006 
02007 rescan:
02008     if (pi != NULL) pi = rpmtsiFree(pi);
02009     q = r = NULL;
02010     qlen = 0;
02011     pi = rpmtsiInit(ts);
02012     while ((p = rpmtsiNext(pi, oType)) != NULL) {
02013 
02014         /* Prefer packages in chainsaw or anaconda presentation order. */
02015         if (anaconda)
02016             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
02017 
02018         if (rpmteTSI(p)->tsi_count != 0)
02019             continue;
02020         rpmteTSI(p)->tsi_suc = NULL;
02021         addQ(p, &q, &r, prefcolor);
02022         qlen++;
02023     }
02024     pi = rpmtsiFree(pi);
02025 
02026     /* T5. Output front of queue (T7. Remove from queue.) */
02027     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
02028 
02029         /* Mark the package as unqueued. */
02030         rpmteTSI(q)->tsi_queued = 0;
02031 
02032         if (oType != 0)
02033         switch (rpmteType(q)) {
02034         case TR_ADDED:
02035             if (!(oType & TR_ADDED))
02036                 continue;
02037             /*@switchbreak@*/ break;
02038         case TR_REMOVED:
02039             if (!(oType & TR_REMOVED))
02040                 continue;
02041             /*@switchbreak@*/ break;
02042         default:
02043             continue;
02044             /*@notreached@*/ /*@switchbreak@*/ break;
02045         }
02046         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
02047 
02048         treex = rpmteTree(q);
02049         depth = rpmteDepth(q);
02050         breadth = ((depth < npeer) ? peer[depth]++ : 0);
02051         (void) rpmteSetBreadth(q, breadth);
02052 
02053         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
02054                         orderingCount, rpmteNpreds(q),
02055                         rpmteTSI(q)->tsi_qcnt,
02056                         treex, depth, breadth,
02057                         (2 * depth), "",
02058                         deptypechar,
02059                         (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
02060 
02061         (void) rpmteSetDegree(q, 0);
02062         tsbytes += rpmtePkgFileSize(q);
02063 
02064         ordering[orderingCount] = rpmteAddedKey(q);
02065         orderingCount++;
02066         qlen--;
02067         loopcheck--;
02068 
02069         /* T6. Erase relations. */
02070         tsi_next = rpmteTSI(q)->tsi_next;
02071         rpmteTSI(q)->tsi_next = NULL;
02072         while ((tsi = tsi_next) != NULL) {
02073             tsi_next = tsi->tsi_next;
02074             tsi->tsi_next = NULL;
02075             p = tsi->tsi_suc;
02076             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
02077 
02078                 (void) rpmteSetTree(p, treex);
02079                 (void) rpmteSetDepth(p, depth+1);
02080                 (void) rpmteSetParent(p, q);
02081                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
02082 
02083                 /* XXX TODO: add control bit. */
02084                 rpmteTSI(p)->tsi_suc = NULL;
02085 /*@-nullstate@*/        /* XXX FIX: rpmteTSI(q)->tsi_suc can be NULL. */
02086                 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
02087 /*@=nullstate@*/
02088                 qlen++;
02089             }
02090             tsi = _free(tsi);
02091         }
02092         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
02093             _printed++;
02094             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
02095             rpmMessage(RPMMESS_DEBUG,
02096                 _("========== successors only (%d bytes)\n"), (int)tsbytes);
02097 
02098             /* Relink the queue in presentation order. */
02099             tsi = rpmteTSI(q);
02100             pi = rpmtsiInit(ts);
02101             while ((p = rpmtsiNext(pi, oType)) != NULL) {
02102                 /* Is this element in the queue? */
02103                 if (rpmteTSI(p)->tsi_queued == 0)
02104                     /*@innercontinue@*/ continue;
02105                 tsi->tsi_suc = p;
02106                 tsi = rpmteTSI(p);
02107             }
02108             pi = rpmtsiFree(pi);
02109             tsi->tsi_suc = NULL;
02110         }
02111     }
02112 
02113     /* T8. End of process. Check for loops. */
02114     if (loopcheck != 0) {
02115         int nzaps;
02116 
02117         /* T9. Initialize predecessor chain. */
02118         nzaps = 0;
02119         qi = rpmtsiInit(ts);
02120         while ((q = rpmtsiNext(qi, oType)) != NULL) {
02121             rpmteTSI(q)->tsi_chain = NULL;
02122             rpmteTSI(q)->tsi_queued = 0;
02123             /* Mark packages already sorted. */
02124             if (rpmteTSI(q)->tsi_count == 0)
02125                 rpmteTSI(q)->tsi_count = -1;
02126         }
02127         qi = rpmtsiFree(qi);
02128 
02129         /* T10. Mark all packages with their predecessors. */
02130         qi = rpmtsiInit(ts);
02131         while ((q = rpmtsiNext(qi, oType)) != NULL) {
02132             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
02133                 continue;
02134             rpmteTSI(q)->tsi_next = NULL;
02135             markLoop(tsi, q);
02136             rpmteTSI(q)->tsi_next = tsi;
02137         }
02138         qi = rpmtsiFree(qi);
02139 
02140         /* T11. Print all dependency loops. */
02141         ri = rpmtsiInit(ts);
02142         while ((r = rpmtsiNext(ri, oType)) != NULL)
02143         {
02144             int printed;
02145 
02146             printed = 0;
02147 
02148             /* T12. Mark predecessor chain, looking for start of loop. */
02149             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
02150                  q = rpmteTSI(q)->tsi_chain)
02151             {
02152                 if (rpmteTSI(q)->tsi_queued)
02153                     /*@innerbreak@*/ break;
02154                 rpmteTSI(q)->tsi_queued = 1;
02155             }
02156 
02157             /* T13. Print predecessor chain from start of loop. */
02158             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
02159                 const char * dp;
02160                 char buf[4096];
02161                 int msglvl = (anaconda || (rpmtsDFlags(ts) & RPMDEPS_FLAG_DEPLOOPS))
02162                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
02163 ;
02164 
02165                 /* Unchain predecessor loop. */
02166                 rpmteTSI(p)->tsi_chain = NULL;
02167 
02168                 if (!printed) {
02169                     rpmMessage(msglvl, _("LOOP:\n"));
02170                     printed = 1;
02171                 }
02172 
02173                 /* Find (and destroy if co-requisite) "q <- p" relation. */
02174                 dp = zapRelation(q, p, 1, &nzaps, msglvl);
02175 
02176                 /* Print next member of loop. */
02177                 buf[0] = '\0';
02178                 if (rpmteNEVRA(p) != NULL)
02179                     (void) stpcpy(buf, rpmteNEVRA(p));
02180                 rpmMessage(msglvl, "    %-40s %s\n", buf,
02181                         (dp ? dp : "not found!?!"));
02182 
02183                 dp = _free(dp);
02184             }
02185 
02186             /* Walk (and erase) linear part of predecessor chain as well. */
02187             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
02188                  p = q, q = rpmteTSI(q)->tsi_chain)
02189             {
02190                 /* Unchain linear part of predecessor loop. */
02191                 rpmteTSI(p)->tsi_chain = NULL;
02192                 rpmteTSI(p)->tsi_queued = 0;
02193             }
02194         }
02195         ri = rpmtsiFree(ri);
02196 
02197         /* If a relation was eliminated, then continue sorting. */
02198         /* XXX TODO: add control bit. */
02199         if (nzaps && nrescans-- > 0) {
02200             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
02201             goto rescan;
02202         }
02203 
02204         /* Return no. of packages that could not be ordered. */
02205         rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
02206                         loopcheck);
02207 
02208 #ifdef  NOTYET
02209         /* Do autorollback goal since we could not sort this transaction properly. */
02210         (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02211 #endif
02212 
02213         return loopcheck;
02214     }
02215 
02216     /* Clean up tsort remnants (if any). */
02217     pi = rpmtsiInit(ts);
02218     while ((p = rpmtsiNext(pi, 0)) != NULL)
02219         rpmteFreeTSI(p);
02220     pi = rpmtsiFree(pi);
02221 
02222     /*
02223      * The order ends up as installed packages followed by removed packages.
02224      */
02225     orderList = xcalloc(numOrderList, sizeof(*orderList));
02226     j = 0;
02227     pi = rpmtsiInit(ts);
02228     while ((p = rpmtsiNext(pi, oType)) != NULL) {
02229         /* Prepare added/erased package ordering permutation. */
02230         orderList[j].pkgKey = rpmteAddedKey(p);
02231         orderList[j].orIndex = rpmtsiOc(pi);
02232         j++;
02233     }
02234     pi = rpmtsiFree(pi);
02235 
02236     qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
02237 
02238 /*@-type@*/
02239     newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
02240 /*@=type@*/
02241     /*@-branchstate@*/
02242     for (i = 0, newOrderCount = 0; i < orderingCount; i++)
02243     {
02244         struct orderListIndex_s key;
02245         orderListIndex needle;
02246 
02247         key.pkgKey = ordering[i];
02248         needle = bsearch(&key, orderList, numOrderList,
02249                                 sizeof(key), orderListIndexCmp);
02250         if (needle == NULL)     /* XXX can't happen */
02251             continue;
02252 
02253         j = needle->orIndex;
02254         if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
02255             continue;
02256 
02257         newOrder[newOrderCount++] = q;
02258         ts->order[j] = NULL;
02259     }
02260     /*@=branchstate@*/
02261 
02262 assert(newOrderCount == ts->orderCount);
02263 
02264 /*@+voidabstract@*/
02265     ts->order = _free(ts->order);
02266 /*@=voidabstract@*/
02267     ts->order = newOrder;
02268     ts->orderAlloced = ts->orderCount;
02269     orderList = _free(orderList);
02270 
02271 #ifdef  DYING   /* XXX now done at the CLI level just before rpmtsRun(). */
02272     rpmtsClean(ts);
02273 #endif
02274     freeBadDeps();
02275 
02276     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
02277 
02278     return 0;
02279 }
02280 /*@=bounds@*/
02281 
02282 int rpmtsCheck(rpmts ts)
02283 {
02284     const char * depName = NULL;;
02285     rpmdepFlags depFlags = rpmtsDFlags(ts);
02286     uint_32 tscolor = rpmtsColor(ts);
02287     rpmdbMatchIterator mi = NULL;
02288     rpmtsi pi = NULL; rpmte p;
02289     int closeatexit = 0;
02290     int xx;
02291     int rc;
02292 
02293     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02294 
02295     /* Do lazy, readonly, open of rpm database. */
02296     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
02297         if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
02298             goto exit;
02299         closeatexit = 1;
02300     }
02301 
02302     ts->probs = rpmpsFree(ts->probs);
02303     ts->probs = rpmpsCreate();
02304 
02305     rpmalMakeIndex(ts->addedPackages);
02306 
02307     /*
02308      * Look at all of the added packages and make sure their dependencies
02309      * are satisfied.
02310      */
02311     pi = rpmtsiInit(ts);
02312     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
02313         rpmds provides, requires, conflicts, dirnames, linktos;
02314 
02315 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
02316         rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
02317                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02318 /*@=nullpass@*/
02319         requires = (!(depFlags & RPMDEPS_FLAG_NOREQUIRES)
02320             ? rpmteDS(p, RPMTAG_REQUIRENAME) : NULL);
02321         conflicts = (!(depFlags & RPMDEPS_FLAG_NOCONFLICTS)
02322             ? rpmteDS(p, RPMTAG_CONFLICTNAME) : NULL);
02323         dirnames = (!(depFlags & RPMDEPS_FLAG_NOPARENTDIRS)
02324             ? rpmteDS(p, RPMTAG_DIRNAMES) : NULL);
02325         linktos = (!(depFlags & RPMDEPS_FLAG_NOLINKTOS)
02326             ? rpmteDS(p, RPMTAG_FILELINKTOS) : NULL);
02327 
02328         rc = checkPackageDeps(ts, rpmteNEVRA(p),
02329                         requires, conflicts, dirnames, linktos,
02330                         NULL, tscolor, 1);
02331         if (rc)
02332             goto exit;
02333 
02334         rc = 0;
02335         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02336         provides = rpmdsInit(provides);
02337         if (provides != NULL)
02338         while (rpmdsNext(provides) >= 0) {
02339             depName = _free(depName);
02340             depName = xstrdup(rpmdsN(provides));
02341 
02342 #ifdef  NOTYET
02343             if (rpmdsNSType(provides) == RPMNS_TYPE_ENVVAR) {
02344                 const char * EVR = rpmdsEVR(provides);
02345                 if (rpmdsNegateRC(provides, 0))
02346                     EVR = NULL;
02347                 rc = envPut(depName, EVR);
02348                 if (!rc)
02349                     /*@innercontinue@*/ continue;
02350                 /*@innerbreak@*/ break;
02351             }
02352 #endif
02353 
02354             /* Adding: check provides key against conflicts matches. */
02355             if (!checkDependentConflicts(ts, depName))
02356                 /*@innercontinue@*/ continue;
02357             rc = 1;
02358             /*@innerbreak@*/ break;
02359         }
02360         if (rc)
02361             goto exit;
02362     }
02363     pi = rpmtsiFree(pi);
02364 
02365     /*
02366      * Look at the removed packages and make sure they aren't critical.
02367      */
02368     pi = rpmtsiInit(ts);
02369     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
02370         rpmds provides;
02371         rpmfi fi;
02372 
02373 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
02374         rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
02375                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02376 /*@=nullpass@*/
02377 
02378         rc = 0;
02379         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
02380         provides = rpmdsInit(provides);
02381         if (provides != NULL)
02382         while (rpmdsNext(provides) >= 0) {
02383             depName = _free(depName);
02384             depName = xstrdup(rpmdsN(provides));
02385 
02386             /* Erasing: check provides against requiredby matches. */
02387             if (!checkDependentPackages(ts, depName))
02388                 /*@innercontinue@*/ continue;
02389             rc = 1;
02390             /*@innerbreak@*/ break;
02391         }
02392         if (rc)
02393             goto exit;
02394 
02395         rc = 0;
02396         fi = rpmteFI(p, RPMTAG_BASENAMES);
02397         fi = rpmfiInit(fi, 0);
02398         while (rpmfiNext(fi) >= 0) {
02399             depName = _free(depName);
02400             depName = xstrdup(rpmfiFN(fi));
02401             /* Erasing: check filename 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     pi = rpmtsiFree(pi);
02411 
02412     /*
02413      * Make sure transaction dependencies are satisfied.
02414      */
02415     {   const char * tsNEVRA = "transaction dependencies";
02416         rpmds R = rpmdsFromPRCO(ts->PRCO, RPMTAG_REQUIRENAME);
02417         rpmds C = rpmdsFromPRCO(ts->PRCO, RPMTAG_CONFLICTNAME);
02418         rpmds D = NULL;
02419         rpmds L = NULL;
02420         const char * dep = NULL;
02421         int adding = 2;
02422         tscolor = 0;    /* XXX no coloring for transaction dependencies. */
02423         rc = checkPackageDeps(ts, tsNEVRA, R, C, D, L, dep, tscolor, adding);
02424         if (rc)
02425             goto exit;
02426     }
02427 
02428     rc = 0;
02429 
02430 exit:
02431     mi = rpmdbFreeIterator(mi);
02432     pi = rpmtsiFree(pi);
02433     depName = _free(depName);
02434 
02435     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
02436 
02437     /*@-branchstate@*/
02438     if (closeatexit)
02439         xx = rpmtsCloseDB(ts);
02440     else if (_cacheDependsRC)
02441         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
02442     /*@=branchstate@*/
02443 
02444 #ifdef  NOTYET
02445      /* On failed dependencies, perform the autorollback goal (if any). */
02446     {   rpmps ps = rpmtsProblems(ts);
02447         if (rc || rpmpsNumProblems(ps) > 0)
02448             (void) rpmtsRollback(ts, RPMPROB_FILTER_NONE, 0, NULL);
02449         ps = rpmpsFree(ps);
02450     }
02451 #endif
02452 
02453     return rc;
02454 }

Generated on Wed Feb 6 22:31:48 2008 for rpm by  doxygen 1.5.1