- 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 }