Main Page | Modules | Data Structures | File List | Data Fields | Globals | Related Pages

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

Generated on Sat Oct 1 16:24:14 2011 for rpm by  doxygen 1.4.4