• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

lib/depends.c

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

Generated on Mon Nov 29 2010 05:18:42 for rpm by  doxygen 1.7.2