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

Generated on Mon Aug 23 10:18:17 2010 for rpm by  doxygen 1.4.4