lib/depends.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmcli.h>             /* XXX rpmcliPackagesTotal */
00008 
00009 #include <rpmmacro.h>           /* XXX rpmExpand("%{_dependency_whiteout}" */
00010 
00011 #include "rpmdb.h"              /* XXX response cache needs dbiOpen et al. */
00012 
00013 #include "rpmds.h"
00014 #include "rpmfi.h"
00015 
00016 #define _RPMTE_INTERNAL
00017 #include "rpmte.h"
00018 
00019 #define _RPMTS_INTERNAL
00020 #include "rpmts.h"
00021 
00022 #include "debug.h"
00023 
00024 /*@access tsortInfo @*/
00025 /*@access rpmts @*/
00026 
00027 /*@access dbiIndex @*/          /* XXX for dbi->dbi_txnid */
00028 
00029 /*@access alKey @*/     /* XXX for reordering and RPMAL_NOMATCH assign */
00030 
00033 typedef /*@abstract@*/ struct orderListIndex_s *        orderListIndex;
00034 /*@access orderListIndex@*/
00035 
00038 struct orderListIndex_s {
00039 /*@dependent@*/
00040     alKey pkgKey;
00041     int orIndex;
00042 };
00043 
00044 /*@unchecked@*/
00045 int _cacheDependsRC = 1;
00046 
00047 /*@observer@*/ /*@unchecked@*/
00048 const char *rpmNAME = PACKAGE;
00049 
00050 /*@observer@*/ /*@unchecked@*/
00051 const char *rpmEVR = VERSION;
00052 
00053 /*@unchecked@*/
00054 int rpmFLAGS = RPMSENSE_EQUAL;
00055 
00062 static int intcmp(const void * a, const void * b)
00063         /*@requires maxRead(a) == 0 /\ maxRead(b) == 0 @*/
00064 {
00065     const int * aptr = a;
00066     const int * bptr = b;
00067     int rc = (*aptr - *bptr);
00068     return rc;
00069 }
00070 
00079 static int removePackage(rpmts ts, Header h, int dboffset,
00080                 /*@exposed@*/ /*@dependent@*/ /*@null@*/ alKey depends)
00081         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00082         /*@modifies ts, h, rpmGlobalMacroContext, fileSystem, internalState @*/
00083 {
00084     rpmte p;
00085 
00086     /* Filter out duplicate erasures. */
00087     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00088 /*@-boundswrite@*/
00089         if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00090                         sizeof(*ts->removedPackages), intcmp) != NULL)
00091             return 0;
00092 /*@=boundswrite@*/
00093     }
00094 
00095     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00096         ts->allocedRemovedPackages += ts->delta;
00097         ts->removedPackages = xrealloc(ts->removedPackages,
00098                 sizeof(ts->removedPackages) * ts->allocedRemovedPackages);
00099     }
00100 
00101     if (ts->removedPackages != NULL) {  /* XXX can't happen. */
00102 /*@-boundswrite@*/
00103         ts->removedPackages[ts->numRemovedPackages] = dboffset;
00104         ts->numRemovedPackages++;
00105 /*@=boundswrite@*/
00106         if (ts->numRemovedPackages > 1)
00107             qsort(ts->removedPackages, ts->numRemovedPackages,
00108                         sizeof(*ts->removedPackages), intcmp);
00109     }
00110 
00111     if (ts->orderCount >= ts->orderAlloced) {
00112         ts->orderAlloced += (ts->orderCount - ts->orderAlloced) + ts->delta;
00113 /*@-type +voidabstract @*/
00114         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00115 /*@=type =voidabstract @*/
00116     }
00117 
00118     p = rpmteNew(ts, h, TR_REMOVED, NULL, NULL, dboffset, depends);
00119 /*@-boundswrite@*/
00120     ts->order[ts->orderCount] = p;
00121     ts->orderCount++;
00122 /*@=boundswrite@*/
00123 
00124     return 0;
00125 }
00126 
00127 int rpmtsAddInstallElement(rpmts ts, Header h,
00128                         fnpyKey key, int upgrade, rpmRelocation * relocs)
00129 {
00130     uint_32 tscolor = rpmtsColor(ts);
00131     uint_32 dscolor;
00132     uint_32 hcolor;
00133     rpmdbMatchIterator mi;
00134     Header oh;
00135     uint_32 ohcolor;
00136     int isSource;
00137     int duplicate = 0;
00138     rpmtsi pi = NULL; rpmte p;
00139     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00140     const char * arch;
00141     const char * os;
00142     rpmds oldChk, newChk;
00143     rpmds obsoletes;
00144     alKey pkgKey;       /* addedPackages key */
00145     int xx;
00146     int ec = 0;
00147     int rc;
00148     int oc;
00149 
00150     /*
00151      * Check for previously added versions with the same name and arch/os.
00152      * FIXME: only catches previously added, older packages.
00153      */
00154     arch = NULL;
00155     xx = hge(h, RPMTAG_ARCH, NULL, (void **)&arch, NULL);
00156     os = NULL;
00157     xx = hge(h, RPMTAG_OS, NULL, (void **)&os, NULL);
00158     hcolor = hGetColor(h);
00159     pkgKey = RPMAL_NOMATCH;
00160 
00161     /* Check for supported payload format if it's a package */
00162     if (key && headerCheckPayloadFormat(h) != RPMRC_OK) {
00163         ec = 1;
00164         goto exit;
00165     }
00166 
00167     /* XXX Always add source headers. */
00168     isSource = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
00169     if (isSource) {
00170         oc = ts->orderCount;
00171         goto addheader;
00172     }
00173 
00174     oldChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_LESS));
00175     newChk = rpmdsThis(h, RPMTAG_REQUIRENAME, (RPMSENSE_EQUAL|RPMSENSE_GREATER));
00176     /* XXX can't use rpmtsiNext() filter or oc will have wrong value. */
00177     for (pi = rpmtsiInit(ts), oc = 0; (p = rpmtsiNext(pi, 0)) != NULL; oc++) {
00178         rpmds this;
00179 
00180         /* XXX Only added packages need be checked for dupes. */
00181         if (rpmteType(p) == TR_REMOVED)
00182             continue;
00183 
00184         /* XXX Never check source headers. */
00185         if (rpmteIsSource(p))
00186             continue;
00187 
00188         if (tscolor) {
00189             const char * parch;
00190             const char * pos;
00191 
00192             if (arch == NULL || (parch = rpmteA(p)) == NULL)
00193                 continue;
00194             if (os == NULL || (pos = rpmteO(p)) == NULL)
00195                 continue;
00196             if (strcmp(arch, parch) || strcmp(os, pos))
00197                 continue;
00198         }
00199 
00200         /* OK, binary rpm's with same arch and os.  Check NEVR. */
00201         if ((this = rpmteDS(p, RPMTAG_NAME)) == NULL)
00202             continue;   /* XXX can't happen */
00203 
00204         /* 
00205          * On upgrade, if newer NEVR was previously added, 
00206          * then skip adding older. 
00207          */
00208         rc = rpmdsCompare(newChk, this);
00209         if (upgrade && rc != 0) {
00210             const char * pkgNEVR = rpmdsDNEVR(this);
00211             const char * addNEVR = rpmdsDNEVR(oldChk);
00212             if (rpmIsVerbose())
00213                 rpmMessage(RPMMESS_WARNING,
00214                     _("package %s was already added, skipping %s\n"),
00215                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00216                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00217             ec = 0;
00218             goto exit;
00219         }
00220 
00221         /*
00222          * On upgrade, if older NEVR was previously added, 
00223          * then replace old with new. 
00224          */
00225         rc = rpmdsCompare(oldChk, this);
00226         if (upgrade && rc != 0) {
00227             const char * pkgNEVR = rpmdsDNEVR(this);
00228             const char * addNEVR = rpmdsDNEVR(newChk);
00229             if (rpmIsVerbose())
00230                 rpmMessage(RPMMESS_WARNING,
00231                     _("package %s was already added, replacing with %s\n"),
00232                     (pkgNEVR ? pkgNEVR + 2 : "?pkgNEVR?"),
00233                     (addNEVR ? addNEVR + 2 : "?addNEVR?"));
00234             duplicate = 1;
00235             pkgKey = rpmteAddedKey(p);
00236             break;
00237         }
00238     }
00239     pi = rpmtsiFree(pi);
00240     oldChk = rpmdsFree(oldChk);
00241     newChk = rpmdsFree(newChk);
00242 
00243     /* If newer NEVR was already added, exit now. */
00244     if (ec)
00245         goto exit;
00246 
00247 addheader:
00248     if (oc >= ts->orderAlloced) {
00249         ts->orderAlloced += (oc - ts->orderAlloced) + ts->delta;
00250 /*@-type +voidabstract @*/
00251         ts->order = xrealloc(ts->order, ts->orderAlloced * sizeof(*ts->order));
00252 /*@=type =voidabstract @*/
00253     }
00254 
00255     p = rpmteNew(ts, h, TR_ADDED, key, relocs, -1, pkgKey);
00256 
00257     if (duplicate && oc < ts->orderCount) {
00258 /*@-type -unqualifiedtrans@*/
00259 /*@-boundswrite@*/
00260         ts->order[oc] = rpmteFree(ts->order[oc]);
00261 /*@=boundswrite@*/
00262 /*@=type =unqualifiedtrans@*/
00263     }
00264 
00265 /*@-boundswrite@*/
00266     ts->order[oc] = p;
00267 /*@=boundswrite@*/
00268     if (!duplicate) {
00269         ts->orderCount++;
00270         rpmcliPackagesTotal++;
00271     }
00272     
00273     pkgKey = rpmalAdd(&ts->addedPackages, pkgKey, rpmteKey(p),
00274                         rpmteDS(p, RPMTAG_PROVIDENAME),
00275                         rpmteFI(p, RPMTAG_BASENAMES), tscolor);
00276     if (pkgKey == RPMAL_NOMATCH) {
00277 /*@-boundswrite@*/
00278         ts->order[oc] = rpmteFree(ts->order[oc]);
00279 /*@=boundswrite@*/
00280         ec = 1;
00281         goto exit;
00282     }
00283     (void) rpmteSetAddedKey(p, pkgKey);
00284 
00285     if (!duplicate) {
00286         ts->numAddedPackages++;
00287     }
00288 
00289     /* XXX rpmgi hack: Save header in transaction element if requested. */
00290     if (upgrade & 0x2)
00291         (void) rpmteSetHeader(p, h);
00292 
00293     /* If not upgrading, then we're done. */
00294     if (!(upgrade & 0x1))
00295         goto exit;
00296 
00297     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00298     if (isSource)
00299         goto exit;
00300 
00301     /* Do lazy (readonly?) open of rpm database. */
00302     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
00303         if ((ec = rpmtsOpenDB(ts, ts->dbmode)) != 0)
00304             goto exit;
00305     }
00306 
00307     /* On upgrade, erase older packages of same color (if any). */
00308 
00309     mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
00310     while((oh = rpmdbNextIterator(mi)) != NULL) {
00311 
00312         /* Ignore colored packages not in our rainbow. */
00313         ohcolor = hGetColor(oh);
00314         if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00315             continue;
00316 
00317         /* Skip packages that contain identical NEVR. */
00318         if (rpmVersionCompare(h, oh) == 0)
00319             continue;
00320 
00321         xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), pkgKey);
00322     }
00323     mi = rpmdbFreeIterator(mi);
00324 
00325     obsoletes = rpmdsLink(rpmteDS(p, RPMTAG_OBSOLETENAME), "Obsoletes");
00326     obsoletes = rpmdsInit(obsoletes);
00327     if (obsoletes != NULL)
00328     while (rpmdsNext(obsoletes) >= 0) {
00329         const char * Name;
00330 
00331         if ((Name = rpmdsN(obsoletes)) == NULL)
00332             continue;   /* XXX can't happen */
00333 
00334         /* Ignore colored obsoletes not in our rainbow. */
00335 #if 0
00336         dscolor = rpmdsColor(obsoletes);
00337 #else
00338         dscolor = hcolor;
00339 #endif
00340         /* XXX obsoletes are never colored, so this is for future devel. */
00341         if (tscolor && dscolor && !(tscolor & dscolor))
00342             continue;
00343 
00344         /* XXX avoid self-obsoleting packages. */
00345         if (!strcmp(rpmteN(p), Name))
00346             continue;
00347 
00348         if (Name[0] == '/')
00349             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00350         else
00351             mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
00352 
00353         xx = rpmdbPruneIterator(mi,
00354             ts->removedPackages, ts->numRemovedPackages, 1);
00355 
00356         while((oh = rpmdbNextIterator(mi)) != NULL) {
00357             /* Ignore colored packages not in our rainbow. */
00358             ohcolor = hGetColor(oh);
00359             /* XXX provides *are* colored, effectively limiting Obsoletes:
00360                 to matching only colored Provides: based on pkg coloring. */
00361             if (tscolor && hcolor && ohcolor && !(hcolor & ohcolor))
00362                 /*@innercontinue@*/ continue;
00363 
00364             /*
00365              * Rpm prior to 3.0.3 does not have versioned obsoletes.
00366              * If no obsoletes version info is available, match all names.
00367              */
00368             if (rpmdsEVR(obsoletes) == NULL
00369              || rpmdsAnyMatchesDep(oh, obsoletes, _rpmds_nopromote)) {
00370                 const char * ohNEVRA = hGetNEVRA(oh, NULL);
00371 #ifdef  DYING   /* XXX see http://bugzilla.redhat.com #134497 */
00372                 if (rpmVersionCompare(h, oh))
00373 #endif
00374                     xx = removePackage(ts, oh, rpmdbGetIteratorOffset(mi), pkgKey);
00375 /*@-nullptrarith@*/
00376                 rpmMessage(RPMMESS_DEBUG, _("  Obsoletes: %s\t\terases %s\n"),
00377                         rpmdsDNEVR(obsoletes)+2, ohNEVRA);
00378 /*@=nullptrarith@*/
00379                 ohNEVRA = _free(ohNEVRA);
00380             }
00381         }
00382         mi = rpmdbFreeIterator(mi);
00383     }
00384     obsoletes = rpmdsFree(obsoletes);
00385 
00386     ec = 0;
00387 
00388 exit:
00389     pi = rpmtsiFree(pi);
00390     return ec;
00391 }
00392 
00393 int rpmtsAddEraseElement(rpmts ts, Header h, int dboffset)
00394 {
00395     return removePackage(ts, h, dboffset, RPMAL_NOMATCH);
00396 }
00397 
00405 static int unsatisfiedDepend(rpmts ts, rpmds dep, int adding)
00406         /*@globals _cacheDependsRC, rpmGlobalMacroContext, h_errno,
00407                 fileSystem, internalState @*/
00408         /*@modifies ts, _cacheDependsRC, rpmGlobalMacroContext,
00409                 fileSystem, internalState @*/
00410 {
00411     DBT * key = alloca(sizeof(*key));
00412     DBT * data = alloca(sizeof(*data));
00413     rpmdbMatchIterator mi;
00414     const char * Name;
00415     Header h;
00416     int _cacheThisRC = 1;
00417     int rc;
00418     int xx;
00419     int retrying = 0;
00420 
00421     if ((Name = rpmdsN(dep)) == NULL)
00422         return 0;       /* XXX can't happen */
00423 
00424     /*
00425      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
00426      */
00427     if (_cacheDependsRC) {
00428         dbiIndex dbi;
00429         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00430         if (dbi == NULL)
00431             _cacheDependsRC = 0;
00432         else {
00433             const char * DNEVR;
00434 
00435             rc = -1;
00436 /*@-branchstate@*/
00437             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00438                 DBC * dbcursor = NULL;
00439                 void * datap = NULL;
00440                 size_t datalen = 0;
00441                 size_t DNEVRlen = strlen(DNEVR);
00442 
00443                 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, 0);
00444 
00445                 memset(key, 0, sizeof(*key));
00446 /*@i@*/         key->data = (void *) DNEVR;
00447                 key->size = DNEVRlen;
00448                 memset(data, 0, sizeof(*data));
00449                 data->data = datap;
00450                 data->size = datalen;
00451 /*@-nullstate@*/ /* FIX: data->data may be NULL */
00452                 xx = dbiGet(dbi, dbcursor, key, data, DB_SET);
00453 /*@=nullstate@*/
00454                 DNEVR = key->data;
00455                 DNEVRlen = key->size;
00456                 datap = data->data;
00457                 datalen = data->size;
00458 
00459 /*@-boundswrite@*/
00460                 if (xx == 0 && datap && datalen == 4)
00461                     memcpy(&rc, datap, datalen);
00462 /*@=boundswrite@*/
00463                 xx = dbiCclose(dbi, dbcursor, 0);
00464             }
00465 /*@=branchstate@*/
00466 
00467             if (rc >= 0) {
00468                 rpmdsNotify(dep, _("(cached)"), rc);
00469                 return rc;
00470             }
00471         }
00472     }
00473 
00474 retry:
00475     rc = 0;     /* assume dependency is satisfied */
00476 
00477 #if defined(DYING) || defined(__LCLINT__)
00478   { static /*@observer@*/ const char noProvidesString[] = "nada";
00479     static /*@observer@*/ const char * rcProvidesString = noProvidesString;
00480     int_32 Flags = rpmdsFlags(dep);
00481     const char * start;
00482     int i;
00483 
00484     if (rcProvidesString == noProvidesString)
00485         rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
00486 
00487     if (rcProvidesString != NULL && !(Flags & RPMSENSE_SENSEMASK)) {
00488 
00489         i = strlen(Name);
00490         /*@-observertrans -mayaliasunique@*/
00491         while ((start = strstr(rcProvidesString, Name))) {
00492         /*@=observertrans =mayaliasunique@*/
00493 /*@-boundsread@*/
00494             if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
00495                 rpmdsNotify(dep, _("(rpmrc provides)"), rc);
00496                 goto exit;
00497             }
00498 /*@=boundsread@*/
00499             rcProvidesString = start + 1;
00500         }
00501     }
00502   }
00503 #endif
00504 
00505     /*
00506      * New features in rpm packaging implicitly add versioned dependencies
00507      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
00508      * Check those dependencies now.
00509      */
00510     if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1)) {
00511         if (rpmCheckRpmlibProvides(dep)) {
00512             rpmdsNotify(dep, _("(rpmlib provides)"), rc);
00513             goto exit;
00514         }
00515         goto unsatisfied;
00516     }
00517 
00518     /* Search added packages for the dependency. */
00519     if (rpmalSatisfiesDepend(ts->addedPackages, dep, NULL) != NULL) {
00520         /*
00521          * XXX Ick, context sensitive answers from dependency cache.
00522          * XXX Always resolve added dependencies within context to disambiguate.
00523          */
00524         if (_rpmds_nopromote)
00525             _cacheThisRC = 0;
00526         goto exit;
00527     }
00528 
00529     /* XXX only the installer does not have the database open here. */
00530     if (rpmtsGetRdb(ts) != NULL) {
00531 /*@-boundsread@*/
00532         if (Name[0] == '/') {
00533             /* depFlags better be 0! */
00534 
00535             mi = rpmtsInitIterator(ts, RPMTAG_BASENAMES, Name, 0);
00536 
00537             (void) rpmdbPruneIterator(mi,
00538                         ts->removedPackages, ts->numRemovedPackages, 1);
00539 
00540             while ((h = rpmdbNextIterator(mi)) != NULL) {
00541                 rpmdsNotify(dep, _("(db files)"), rc);
00542                 mi = rpmdbFreeIterator(mi);
00543                 goto exit;
00544             }
00545             mi = rpmdbFreeIterator(mi);
00546         }
00547 /*@=boundsread@*/
00548 
00549         mi = rpmtsInitIterator(ts, RPMTAG_PROVIDENAME, Name, 0);
00550         (void) rpmdbPruneIterator(mi,
00551                         ts->removedPackages, ts->numRemovedPackages, 1);
00552         while ((h = rpmdbNextIterator(mi)) != NULL) {
00553             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
00554                 rpmdsNotify(dep, _("(db provides)"), rc);
00555                 mi = rpmdbFreeIterator(mi);
00556                 goto exit;
00557             }
00558         }
00559         mi = rpmdbFreeIterator(mi);
00560 
00561 #if defined(DYING) || defined(__LCLINT__)
00562         mi = rpmtsInitIterator(ts, RPMTAG_NAME, Name, 0);
00563         (void) rpmdbPruneIterator(mi,
00564                         ts->removedPackages, ts->numRemovedPackages, 1);
00565         while ((h = rpmdbNextIterator(mi)) != NULL) {
00566             if (rpmdsAnyMatchesDep(h, dep, _rpmds_nopromote)) {
00567                 rpmdsNotify(dep, _("(db package)"), rc);
00568                 mi = rpmdbFreeIterator(mi);
00569                 goto exit;
00570             }
00571         }
00572         mi = rpmdbFreeIterator(mi);
00573 #endif
00574 
00575     }
00576 
00577     /*
00578      * Search for an unsatisfied dependency.
00579      */
00580 /*@-boundsread@*/
00581     if (adding && !retrying && !(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST)) {
00582         if (ts->solve != NULL) {
00583             xx = (*ts->solve) (ts, dep, ts->solveData);
00584             if (xx == 0)
00585                 goto exit;
00586             if (xx == -1) {
00587                 retrying = 1;
00588                 rpmalMakeIndex(ts->addedPackages);
00589                 goto retry;
00590             }
00591         }
00592     }
00593 /*@=boundsread@*/
00594 
00595 unsatisfied:
00596     rc = 1;     /* dependency is unsatisfied */
00597     rpmdsNotify(dep, NULL, rc);
00598 
00599 exit:
00600     /*
00601      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
00602      */
00603     if (_cacheDependsRC && _cacheThisRC) {
00604         dbiIndex dbi;
00605         dbi = dbiOpen(rpmtsGetRdb(ts), RPMDBI_DEPENDS, 0);
00606         if (dbi == NULL) {
00607             _cacheDependsRC = 0;
00608         } else {
00609             const char * DNEVR;
00610             xx = 0;
00611             /*@-branchstate@*/
00612             if ((DNEVR = rpmdsDNEVR(dep)) != NULL) {
00613                 DBC * dbcursor = NULL;
00614                 size_t DNEVRlen = strlen(DNEVR);
00615 
00616                 xx = dbiCopen(dbi, dbi->dbi_txnid, &dbcursor, DB_WRITECURSOR);
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 = &rc;
00623                 data->size = sizeof(rc);
00624 
00625                 /*@-compmempass@*/
00626                 xx = dbiPut(dbi, dbcursor, key, data, 0);
00627                 /*@=compmempass@*/
00628                 xx = dbiCclose(dbi, dbcursor, DB_WRITECURSOR);
00629             }
00630             /*@=branchstate@*/
00631             if (xx)
00632                 _cacheDependsRC = 0;
00633         }
00634     }
00635     return rc;
00636 }
00637 
00649 static int checkPackageDeps(rpmts ts, const char * pkgNEVRA,
00650                 /*@null@*/ rpmds requires, /*@null@*/ rpmds conflicts,
00651                 /*@null@*/ const char * depName, uint_32 tscolor, int adding)
00652         /*@globals rpmGlobalMacroContext, h_errno,
00653                 fileSystem, internalState @*/
00654         /*@modifies ts, requires, conflicts, rpmGlobalMacroContext,
00655                 fileSystem, internalState */
00656 {
00657     uint_32 dscolor;
00658     const char * Name;
00659     int rc;
00660     int ourrc = 0;
00661 
00662     requires = rpmdsInit(requires);
00663     if (requires != NULL)
00664     while (!ourrc && rpmdsNext(requires) >= 0) {
00665 
00666         if ((Name = rpmdsN(requires)) == NULL)
00667             continue;   /* XXX can't happen */
00668 
00669         /* Filter out requires that came along for the ride. */
00670         if (depName != NULL && strcmp(depName, Name))
00671             continue;
00672 
00673         /* Ignore colored requires not in our rainbow. */
00674         dscolor = rpmdsColor(requires);
00675         if (tscolor && dscolor && !(tscolor & dscolor))
00676             continue;
00677 
00678         rc = unsatisfiedDepend(ts, requires, adding);
00679 
00680         switch (rc) {
00681         case 0:         /* requirements are satisfied. */
00682             /*@switchbreak@*/ break;
00683         case 1:         /* requirements are not satisfied. */
00684         {   fnpyKey * suggestedKeys = NULL;
00685 
00686             /*@-branchstate@*/
00687             if (ts->availablePackages != NULL) {
00688                 suggestedKeys = rpmalAllSatisfiesDepend(ts->availablePackages,
00689                                 requires, NULL);
00690             }
00691             /*@=branchstate@*/
00692 
00693             rpmdsProblem(ts->probs, pkgNEVRA, requires, suggestedKeys, adding);
00694 
00695         }
00696             /*@switchbreak@*/ break;
00697         case 2:         /* something went wrong! */
00698         default:
00699             ourrc = 1;
00700             /*@switchbreak@*/ break;
00701         }
00702     }
00703 
00704     conflicts = rpmdsInit(conflicts);
00705     if (conflicts != NULL)
00706     while (!ourrc && rpmdsNext(conflicts) >= 0) {
00707 
00708         if ((Name = rpmdsN(conflicts)) == NULL)
00709             continue;   /* XXX can't happen */
00710 
00711         /* Filter out conflicts that came along for the ride. */
00712         if (depName != NULL && strcmp(depName, Name))
00713             continue;
00714 
00715         /* Ignore colored conflicts not in our rainbow. */
00716         dscolor = rpmdsColor(conflicts);
00717         if (tscolor && dscolor && !(tscolor & dscolor))
00718             continue;
00719 
00720         rc = unsatisfiedDepend(ts, conflicts, adding);
00721 
00722         /* 1 == unsatisfied, 0 == satsisfied */
00723         switch (rc) {
00724         case 0:         /* conflicts exist. */
00725             rpmdsProblem(ts->probs, pkgNEVRA, conflicts, NULL, adding);
00726             /*@switchbreak@*/ break;
00727         case 1:         /* conflicts don't exist. */
00728             /*@switchbreak@*/ break;
00729         case 2:         /* something went wrong! */
00730         default:
00731             ourrc = 1;
00732             /*@switchbreak@*/ break;
00733         }
00734     }
00735 
00736     return ourrc;
00737 }
00738 
00749 static int checkPackageSet(rpmts ts, const char * dep,
00750                 /*@only@*/ /*@null@*/ rpmdbMatchIterator mi, int adding)
00751         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00752         /*@modifies ts, mi, rpmGlobalMacroContext, fileSystem, internalState @*/
00753 {
00754     int scareMem = 1;
00755     Header h;
00756     int ec = 0;
00757 
00758     (void) rpmdbPruneIterator(mi,
00759                 ts->removedPackages, ts->numRemovedPackages, 1);
00760     while ((h = rpmdbNextIterator(mi)) != NULL) {
00761         const char * pkgNEVRA;
00762         rpmds requires, conflicts;
00763         int rc;
00764 
00765         pkgNEVRA = hGetNEVRA(h, NULL);
00766         requires = rpmdsNew(h, RPMTAG_REQUIRENAME, scareMem);
00767         (void) rpmdsSetNoPromote(requires, _rpmds_nopromote);
00768         conflicts = rpmdsNew(h, RPMTAG_CONFLICTNAME, scareMem);
00769         (void) rpmdsSetNoPromote(conflicts, _rpmds_nopromote);
00770         rc = checkPackageDeps(ts, pkgNEVRA, requires, conflicts, dep, 0, adding);
00771         conflicts = rpmdsFree(conflicts);
00772         requires = rpmdsFree(requires);
00773         pkgNEVRA = _free(pkgNEVRA);
00774 
00775         if (rc) {
00776             ec = 1;
00777             break;
00778         }
00779     }
00780     mi = rpmdbFreeIterator(mi);
00781 
00782     return ec;
00783 }
00784 
00791 static int checkDependentPackages(rpmts ts, const char * dep)
00792         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00793         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
00794 {
00795     rpmdbMatchIterator mi;
00796     mi = rpmtsInitIterator(ts, RPMTAG_REQUIRENAME, dep, 0);
00797     return checkPackageSet(ts, dep, mi, 0);
00798 }
00799 
00806 static int checkDependentConflicts(rpmts ts, const char * dep)
00807         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00808         /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
00809 {
00810     int rc = 0;
00811 
00812     if (rpmtsGetRdb(ts) != NULL) {      /* XXX is this necessary? */
00813         rpmdbMatchIterator mi;
00814         mi = rpmtsInitIterator(ts, RPMTAG_CONFLICTNAME, dep, 0);
00815         rc = checkPackageSet(ts, dep, mi, 1);
00816     }
00817 
00818     return rc;
00819 }
00820 
00821 struct badDeps_s {
00822 /*@observer@*/ /*@owned@*/ /*@null@*/
00823     const char * pname;
00824 /*@observer@*/ /*@dependent@*/ /*@null@*/
00825     const char * qname;
00826 };
00827 
00828 #ifdef REFERENCE
00829 static struct badDeps_s {
00830 /*@observer@*/ /*@null@*/ const char * pname;
00831 /*@observer@*/ /*@null@*/ const char * qname;
00832 } badDeps[] = {
00833     { NULL, NULL }
00834 };
00835 #else
00836 /*@unchecked@*/
00837 static int badDepsInitialized = 0;
00838 
00839 /*@unchecked@*/ /*@only@*/ /*@null@*/
00840 static struct badDeps_s * badDeps = NULL;
00841 #endif
00842 
00845 /*@-modobserver -observertrans @*/
00846 static void freeBadDeps(void)
00847         /*@globals badDeps, badDepsInitialized @*/
00848         /*@modifies badDeps, badDepsInitialized @*/
00849 {
00850     if (badDeps) {
00851         struct badDeps_s * bdp;
00852         for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++)
00853             bdp->pname = _free(bdp->pname);
00854         badDeps = _free(badDeps);
00855     }
00856     badDepsInitialized = 0;
00857 }
00858 /*@=modobserver =observertrans @*/
00859 
00868 /*@-boundsread@*/
00869 static int ignoreDep(const rpmts ts, const rpmte p, const rpmte q)
00870         /*@globals badDeps, badDepsInitialized,
00871                 rpmGlobalMacroContext, h_errno @*/
00872         /*@modifies badDeps, badDepsInitialized,
00873                 rpmGlobalMacroContext @*/
00874 {
00875     struct badDeps_s * bdp;
00876 
00877     if (!badDepsInitialized) {
00878         char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
00879         const char ** av = NULL;
00880         int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
00881         int msglvl = (anaconda || (rpmtsFlags(ts) & RPMTRANS_FLAG_DEPLOOPS))
00882                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
00883         int ac = 0;
00884         int i;
00885 
00886         if (s != NULL && *s != '\0'
00887         && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
00888         && ac > 0 && av != NULL)
00889         {
00890             bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
00891             for (i = 0; i < ac; i++, bdp++) {
00892                 char * pname, * qname;
00893 
00894                 if (av[i] == NULL)
00895                     break;
00896                 pname = xstrdup(av[i]);
00897                 if ((qname = strchr(pname, '>')) != NULL)
00898                     *qname++ = '\0';
00899                 bdp->pname = pname;
00900                 /*@-usereleased@*/
00901                 bdp->qname = qname;
00902                 /*@=usereleased@*/
00903                 rpmMessage(msglvl,
00904                         _("ignore package name relation(s) [%d]\t%s -> %s\n"),
00905                         i, bdp->pname, (bdp->qname ? bdp->qname : "???"));
00906             }
00907             bdp->pname = NULL;
00908             bdp->qname = NULL;
00909         }
00910         av = _free(av);
00911         s = _free(s);
00912         badDepsInitialized++;
00913     }
00914 
00915     /*@-compdef@*/
00916     if (badDeps != NULL)
00917     for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
00918         if (!strcmp(rpmteN(p), bdp->pname) && !strcmp(rpmteN(q), bdp->qname))
00919             return 1;
00920     }
00921     return 0;
00922     /*@=compdef@*/
00923 }
00924 /*@=boundsread@*/
00925 
00931 static void markLoop(/*@special@*/ tsortInfo tsi, rpmte q)
00932         /*@globals internalState @*/
00933         /*@uses tsi @*/
00934         /*@modifies internalState @*/
00935 {
00936     rpmte p;
00937 
00938     /*@-branchstate@*/ /* FIX: q is kept */
00939     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
00940         tsi = tsi->tsi_next;
00941         if (rpmteTSI(p)->tsi_chain != NULL)
00942             continue;
00943         /*@-assignexpose -temptrans@*/
00944         rpmteTSI(p)->tsi_chain = q;
00945         /*@=assignexpose =temptrans@*/
00946         if (rpmteTSI(p)->tsi_next != NULL)
00947             markLoop(rpmteTSI(p)->tsi_next, p);
00948     }
00949     /*@=branchstate@*/
00950 }
00951 
00952 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
00953         /*@*/
00954 {
00955     f = _notpre(f);
00956     if (f & RPMSENSE_SCRIPT_PRE)
00957         return "Requires(pre):";
00958     if (f & RPMSENSE_SCRIPT_POST)
00959         return "Requires(post):";
00960     if (f & RPMSENSE_SCRIPT_PREUN)
00961         return "Requires(preun):";
00962     if (f & RPMSENSE_SCRIPT_POSTUN)
00963         return "Requires(postun):";
00964     if (f & RPMSENSE_SCRIPT_VERIFY)
00965         return "Requires(verify):";
00966     if (f & RPMSENSE_FIND_REQUIRES)
00967         return "Requires(auto):";
00968     return "Requires:";
00969 }
00970 
00984 /*@-boundswrite@*/
00985 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
00986 static /*@owned@*/ /*@null@*/ const char *
00987 zapRelation(rpmte q, rpmte p,
00988                 /*@null@*/ rpmds requires,
00989                 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl)
00990         /*@modifies q, p, requires, *nzaps @*/
00991 {
00992     tsortInfo tsi_prev;
00993     tsortInfo tsi;
00994     const char *dp = NULL;
00995 
00996     for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
00997          tsi != NULL;
00998         /* XXX Note: the loop traverses "not found", break on "found". */
00999         /*@-nullderef@*/
01000          tsi_prev = tsi, tsi = tsi->tsi_next)
01001         /*@=nullderef@*/
01002     {
01003         int_32 Flags;
01004 
01005         /*@-abstractcompare@*/
01006         if (tsi->tsi_suc != p)
01007             continue;
01008         /*@=abstractcompare@*/
01009 
01010         if (requires == NULL) continue;         /* XXX can't happen */
01011 
01012         (void) rpmdsSetIx(requires, tsi->tsi_reqx);
01013 
01014         Flags = rpmdsFlags(requires);
01015 
01016         dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
01017 
01018         /*
01019          * Attempt to unravel a dependency loop by eliminating Requires's.
01020          */
01021         /*@-branchstate@*/
01022         if (zap && !(isErasePreReq(Flags) || isInstallPreReq(Flags))) {
01023             rpmMessage(msglvl,
01024                         _("removing %s \"%s\" from tsort relations.\n"),
01025                         (rpmteNEVRA(p) ?  rpmteNEVRA(p) : "???"), dp);
01026             rpmteTSI(p)->tsi_count--;
01027             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01028             tsi->tsi_next = NULL;
01029             tsi->tsi_suc = NULL;
01030             tsi = _free(tsi);
01031             if (nzaps)
01032                 (*nzaps)++;
01033             if (zap)
01034                 zap--;
01035         }
01036         /*@=branchstate@*/
01037         /* XXX Note: the loop traverses "not found", get out now! */
01038         break;
01039     }
01040     return dp;
01041 }
01042 /*@=mustmod@*/
01043 /*@=boundswrite@*/
01044 
01053 /*@-mustmod@*/
01054 static inline int addRelation(rpmts ts,
01055                 /*@dependent@*/ rpmte p,
01056                 unsigned char * selected,
01057                 rpmds requires)
01058         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01059         /*@modifies ts, p, *selected, rpmGlobalMacroContext,
01060                 fileSystem, internalState @*/
01061 {
01062     rpmtsi qi; rpmte q;
01063     tsortInfo tsi;
01064     const char * Name;
01065     fnpyKey key;
01066     alKey pkgKey;
01067     int i = 0;
01068 
01069     if ((Name = rpmdsN(requires)) == NULL)
01070         return 0;
01071 
01072     /* Avoid rpmlib feature dependencies. */
01073     if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
01074         return 0;
01075 
01076     /* Avoid package config dependencies. */
01077     if (!strncmp(Name, "config(", sizeof("config(")-1))
01078         return 0;
01079 
01080     pkgKey = RPMAL_NOMATCH;
01081     key = rpmalSatisfiesDepend(ts->addedPackages, requires, &pkgKey);
01082 
01083     /* Ordering depends only on added package relations. */
01084     if (pkgKey == RPMAL_NOMATCH)
01085         return 0;
01086 
01087 /* XXX Set q to the added package that has pkgKey == q->u.addedKey */
01088 /* XXX FIXME: bsearch is possible/needed here */
01089     for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
01090 
01091         /* XXX Only added packages need be checked for matches. */
01092         if (rpmteType(q) == TR_REMOVED)
01093             continue;
01094 
01095         if (pkgKey == rpmteAddedKey(q))
01096             break;
01097     }
01098     qi = rpmtsiFree(qi);
01099     if (q == NULL || i == ts->orderCount)
01100         return 0;
01101 
01102     /* Avoid certain dependency relations. */
01103     if (ignoreDep(ts, p, q))
01104         return 0;
01105 
01106     /* Avoid redundant relations. */
01107     /* XXX TODO: add control bit. */
01108 /*@-boundsread@*/
01109     if (selected[i] != 0)
01110         return 0;
01111 /*@=boundsread@*/
01112 /*@-boundswrite@*/
01113     selected[i] = 1;
01114 /*@=boundswrite@*/
01115 
01116     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01117     rpmteTSI(p)->tsi_count++;                   /* bump p predecessor count */
01118 
01119     if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
01120         (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
01121     if (rpmteDepth(p) > ts->maxDepth)
01122         ts->maxDepth = rpmteDepth(p);
01123 
01124     tsi = xcalloc(1, sizeof(*tsi));
01125     tsi->tsi_suc = p;
01126 
01127     tsi->tsi_reqx = rpmdsIx(requires);
01128 
01129     tsi->tsi_next = rpmteTSI(q)->tsi_next;
01130     rpmteTSI(q)->tsi_next = tsi;
01131     rpmteTSI(q)->tsi_qcnt++;                    /* bump q successor count */
01132     return 0;
01133 }
01134 /*@=mustmod@*/
01135 
01142 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01143 {
01144     /*@-castexpose@*/
01145     long a = (long) ((const orderListIndex)one)->pkgKey;
01146     long b = (long) ((const orderListIndex)two)->pkgKey;
01147     /*@=castexpose@*/
01148     return (a - b);
01149 }
01150 
01157 /*@-boundswrite@*/
01158 /*@-mustmod@*/
01159 static void addQ(/*@dependent@*/ rpmte p,
01160                 /*@in@*/ /*@out@*/ rpmte * qp,
01161                 /*@in@*/ /*@out@*/ rpmte * rp,
01162                 uint_32 prefcolor)
01163         /*@modifies p, *qp, *rp @*/
01164 {
01165     rpmte q, qprev;
01166 
01167     /* Mark the package as queued. */
01168     rpmteTSI(p)->tsi_reqx = 1;
01169 
01170     if ((*rp) == NULL) {        /* 1st element */
01171         /*@-dependenttrans@*/ /* FIX: double indirection */
01172         (*rp) = (*qp) = p;
01173         /*@=dependenttrans@*/
01174         return;
01175     }
01176 
01177     /* Find location in queue using metric tsi_qcnt. */
01178     for (qprev = NULL, q = (*qp);
01179          q != NULL;
01180          qprev = q, q = rpmteTSI(q)->tsi_suc)
01181     {
01182         /* XXX Insure preferred color first. */
01183         if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
01184             continue;
01185 
01186         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01187             break;
01188     }
01189 
01190     if (qprev == NULL) {        /* insert at beginning of list */
01191         rpmteTSI(p)->tsi_suc = q;
01192         /*@-dependenttrans@*/
01193         (*qp) = p;              /* new head */
01194         /*@=dependenttrans@*/
01195     } else if (q == NULL) {     /* insert at end of list */
01196         rpmteTSI(qprev)->tsi_suc = p;
01197         /*@-dependenttrans@*/
01198         (*rp) = p;              /* new tail */
01199         /*@=dependenttrans@*/
01200     } else {                    /* insert between qprev and q */
01201         rpmteTSI(p)->tsi_suc = q;
01202         rpmteTSI(qprev)->tsi_suc = p;
01203     }
01204 }
01205 /*@=mustmod@*/
01206 /*@=boundswrite@*/
01207 
01208 /*@-bounds@*/
01209 int rpmtsOrder(rpmts ts)
01210 {
01211     rpmds requires;
01212     int_32 Flags;
01213     int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
01214     uint_32 prefcolor = rpmtsPrefColor(ts);
01215     rpmtsi pi; rpmte p;
01216     rpmtsi qi; rpmte q;
01217     rpmtsi ri; rpmte r;
01218     tsortInfo tsi;
01219     tsortInfo tsi_next;
01220     alKey * ordering;
01221     int orderingCount = 0;
01222     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01223     int loopcheck;
01224     rpmte * newOrder;
01225     int newOrderCount = 0;
01226     orderListIndex orderList;
01227     int numOrderList;
01228     int npeer = 128;    /* XXX more than deep enough for now. */
01229     int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
01230     int nrescans = 0;
01231     int _printed = 0;
01232     char deptypechar;
01233     size_t tsbytes;
01234     int oType = 0;
01235     int treex;
01236     int depth;
01237     int breadth;
01238     int qlen;
01239     int i, j;
01240 
01241     /*
01242      * XXX FIXME: this gets needlesly called twice on normal usage patterns,
01243      * should track the need for generating the index somewhere
01244      */
01245     rpmalMakeIndex(ts->addedPackages);
01246 
01247     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01248 
01249     /* T1. Initialize. */
01250     if (oType == 0)
01251         numOrderList = ts->orderCount;
01252     else {
01253         numOrderList = 0;
01254         if (oType & TR_ADDED)
01255             numOrderList += ts->numAddedPackages;
01256         if (oType & TR_REMOVED)
01257             numOrderList += ts->numRemovedPackages;
01258      }
01259     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01260     loopcheck = numOrderList;
01261     tsbytes = 0;
01262 
01263     pi = rpmtsiInit(ts);
01264     while ((p = rpmtsiNext(pi, oType)) != NULL)
01265         rpmteNewTSI(p);
01266     pi = rpmtsiFree(pi);
01267 
01268     /* Record all relations. */
01269     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01270     pi = rpmtsiInit(ts);
01271     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01272 
01273         if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
01274             continue;
01275 
01276         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01277 
01278         /* Avoid narcisstic relations. */
01279         selected[rpmtsiOc(pi)] = 1;
01280 
01281         /* T2. Next "q <- p" relation. */
01282 
01283         /* First, do pre-requisites. */
01284         requires = rpmdsInit(requires);
01285         if (requires != NULL)
01286         while (rpmdsNext(requires) >= 0) {
01287 
01288             Flags = rpmdsFlags(requires);
01289 
01290             switch (rpmteType(p)) {
01291             case TR_REMOVED:
01292                 /* Skip if not %preun/%postun requires or legacy prereq. */
01293                 if (!( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01294                     /*@innercontinue@*/ continue;
01295                 /*@switchbreak@*/ break;
01296             case TR_ADDED:
01297                 /* Skip if not %pre/%post requires or legacy prereq. */
01298                 if (!( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01299                     /*@innercontinue@*/ continue;
01300                 /*@switchbreak@*/ break;
01301             }
01302 
01303             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01304             (void) addRelation(ts, p, selected, requires);
01305 
01306         }
01307 
01308         /* Then do co-requisites. */
01309         requires = rpmdsInit(requires);
01310         if (requires != NULL)
01311         while (rpmdsNext(requires) >= 0) {
01312 
01313             Flags = rpmdsFlags(requires);
01314 
01315             switch (rpmteType(p)) {
01316             case TR_REMOVED:
01317                 /* Skip if %preun/%postun requires or legacy prereq. */
01318                 if (isInstallPreReq(Flags)
01319                  ||  ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01320                     /*@innercontinue@*/ continue;
01321                 /*@switchbreak@*/ break;
01322             case TR_ADDED:
01323                 /* Skip if %pre/%post requires or legacy prereq. */
01324                 if (isErasePreReq(Flags)
01325                  ||  ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01326                     /*@innercontinue@*/ continue;
01327                 /*@switchbreak@*/ break;
01328             }
01329 
01330             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01331             (void) addRelation(ts, p, selected, requires);
01332 
01333         }
01334     }
01335     pi = rpmtsiFree(pi);
01336 
01337     /* Save predecessor count and mark tree roots. */
01338     treex = 0;
01339     pi = rpmtsiInit(ts);
01340     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01341         int npreds;
01342 
01343         npreds = rpmteTSI(p)->tsi_count;
01344 
01345         (void) rpmteSetNpreds(p, npreds);
01346         (void) rpmteSetDepth(p, 1);
01347 
01348         if (npreds == 0)
01349             (void) rpmteSetTree(p, treex++);
01350         else
01351             (void) rpmteSetTree(p, -1);
01352 #ifdef  UNNECESSARY
01353         (void) rpmteSetParent(p, NULL);
01354 #endif
01355 
01356     }
01357     pi = rpmtsiFree(pi);
01358     ts->ntrees = treex;
01359 
01360     /* T4. Scan for zeroes. */
01361     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth)\n"));
01362 
01363 rescan:
01364     if (pi != NULL) pi = rpmtsiFree(pi);
01365     q = r = NULL;
01366     qlen = 0;
01367     pi = rpmtsiInit(ts);
01368     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01369 
01370         /* Prefer packages in chainsaw or anaconda presentation order. */
01371         if (anaconda)
01372             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
01373 
01374         if (rpmteTSI(p)->tsi_count != 0)
01375             continue;
01376         rpmteTSI(p)->tsi_suc = NULL;
01377         addQ(p, &q, &r, prefcolor);
01378         qlen++;
01379     }
01380     pi = rpmtsiFree(pi);
01381 
01382     /* T5. Output front of queue (T7. Remove from queue.) */
01383     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
01384 
01385         /* Mark the package as unqueued. */
01386         rpmteTSI(q)->tsi_reqx = 0;
01387 
01388         if (oType != 0)
01389         switch (rpmteType(q)) {
01390         case TR_ADDED:
01391             if (!(oType & TR_ADDED))
01392                 continue;
01393             /*@switchbreak@*/ break;
01394         case TR_REMOVED:
01395             if (!(oType & TR_REMOVED))
01396                 continue;
01397             /*@switchbreak@*/ break;
01398         default:
01399             continue;
01400             /*@notreached@*/ /*@switchbreak@*/ break;
01401         }
01402         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
01403 
01404         treex = rpmteTree(q);
01405         depth = rpmteDepth(q);
01406         breadth = ((depth < npeer) ? peer[depth]++ : 0);
01407         (void) rpmteSetBreadth(q, breadth);
01408 
01409         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
01410                         orderingCount, rpmteNpreds(q),
01411                         rpmteTSI(q)->tsi_qcnt,
01412                         treex, depth, breadth,
01413                         (2 * depth), "",
01414                         deptypechar,
01415                         (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
01416 
01417         (void) rpmteSetDegree(q, 0);
01418         tsbytes += rpmtePkgFileSize(q);
01419 
01420         switch (rpmteType(q)) {
01421         case TR_ADDED:
01422             ordering[orderingCount] = rpmteAddedKey(q);
01423             /*@switchbreak@*/ break;
01424         case TR_REMOVED:
01425             ordering[orderingCount] = RPMAL_NOMATCH;
01426             /*@switchbreak@*/ break;
01427         }
01428         orderingCount++;
01429         qlen--;
01430         loopcheck--;
01431 
01432         /* T6. Erase relations. */
01433         tsi_next = rpmteTSI(q)->tsi_next;
01434         rpmteTSI(q)->tsi_next = NULL;
01435         while ((tsi = tsi_next) != NULL) {
01436             tsi_next = tsi->tsi_next;
01437             tsi->tsi_next = NULL;
01438             p = tsi->tsi_suc;
01439             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
01440 
01441                 (void) rpmteSetTree(p, treex);
01442                 (void) rpmteSetDepth(p, depth+1);
01443                 (void) rpmteSetParent(p, q);
01444                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
01445 
01446                 /* XXX TODO: add control bit. */
01447                 rpmteTSI(p)->tsi_suc = NULL;
01448                 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
01449                 qlen++;
01450             }
01451             tsi = _free(tsi);
01452         }
01453         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
01454             _printed++;
01455             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
01456             rpmMessage(RPMMESS_DEBUG,
01457                 _("========== successors only (%d bytes)\n"), (int)tsbytes);
01458 
01459             /* Relink the queue in presentation order. */
01460             tsi = rpmteTSI(q);
01461             pi = rpmtsiInit(ts);
01462             while ((p = rpmtsiNext(pi, oType)) != NULL) {
01463                 /* Is this element in the queue? */
01464                 if (rpmteTSI(p)->tsi_reqx == 0)
01465                     /*@innercontinue@*/ continue;
01466                 tsi->tsi_suc = p;
01467                 tsi = rpmteTSI(p);
01468             }
01469             pi = rpmtsiFree(pi);
01470             tsi->tsi_suc = NULL;
01471         }
01472     }
01473 
01474     /* T8. End of process. Check for loops. */
01475     if (loopcheck != 0) {
01476         int nzaps;
01477 
01478         /* T9. Initialize predecessor chain. */
01479         nzaps = 0;
01480         qi = rpmtsiInit(ts);
01481         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01482             rpmteTSI(q)->tsi_chain = NULL;
01483             rpmteTSI(q)->tsi_reqx = 0;
01484             /* Mark packages already sorted. */
01485             if (rpmteTSI(q)->tsi_count == 0)
01486                 rpmteTSI(q)->tsi_count = -1;
01487         }
01488         qi = rpmtsiFree(qi);
01489 
01490         /* T10. Mark all packages with their predecessors. */
01491         qi = rpmtsiInit(ts);
01492         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01493             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
01494                 continue;
01495             rpmteTSI(q)->tsi_next = NULL;
01496             markLoop(tsi, q);
01497             rpmteTSI(q)->tsi_next = tsi;
01498         }
01499         qi = rpmtsiFree(qi);
01500 
01501         /* T11. Print all dependency loops. */
01502         ri = rpmtsiInit(ts);
01503         while ((r = rpmtsiNext(ri, oType)) != NULL)
01504         {
01505             int printed;
01506 
01507             printed = 0;
01508 
01509             /* T12. Mark predecessor chain, looking for start of loop. */
01510             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
01511                  q = rpmteTSI(q)->tsi_chain)
01512             {
01513                 if (rpmteTSI(q)->tsi_reqx)
01514                     /*@innerbreak@*/ break;
01515                 rpmteTSI(q)->tsi_reqx = 1;
01516             }
01517 
01518             /* T13. Print predecessor chain from start of loop. */
01519             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
01520                 const char * dp;
01521                 char buf[4096];
01522                 int msglvl = (anaconda || (rpmtsFlags(ts) & RPMTRANS_FLAG_DEPLOOPS))
01523                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01524 ;
01525 
01526                 /* Unchain predecessor loop. */
01527                 rpmteTSI(p)->tsi_chain = NULL;
01528 
01529                 if (!printed) {
01530                     rpmMessage(msglvl, _("LOOP:\n"));
01531                     printed = 1;
01532                 }
01533 
01534                 /* Find (and destroy if co-requisite) "q <- p" relation. */
01535                 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
01536                 requires = rpmdsInit(requires);
01537                 if (requires == NULL)
01538                     /*@innercontinue@*/ continue;       /* XXX can't happen */
01539                 dp = zapRelation(q, p, requires, 1, &nzaps, msglvl);
01540 
01541                 /* Print next member of loop. */
01542                 buf[0] = '\0';
01543                 if (rpmteNEVRA(p) != NULL)
01544                     (void) stpcpy(buf, rpmteNEVRA(p));
01545                 rpmMessage(msglvl, "    %-40s %s\n", buf,
01546                         (dp ? dp : "not found!?!"));
01547 
01548                 dp = _free(dp);
01549             }
01550 
01551             /* Walk (and erase) linear part of predecessor chain as well. */
01552             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
01553                  p = q, q = rpmteTSI(q)->tsi_chain)
01554             {
01555                 /* Unchain linear part of predecessor loop. */
01556                 rpmteTSI(p)->tsi_chain = NULL;
01557                 rpmteTSI(p)->tsi_reqx = 0;
01558             }
01559         }
01560         ri = rpmtsiFree(ri);
01561 
01562         /* If a relation was eliminated, then continue sorting. */
01563         /* XXX TODO: add control bit. */
01564         if (nzaps > 0) {
01565             rpmMessage(RPMMESS_DEBUG, 
01566                        _("========== continuing tsort ... (rescan %d)\n"),
01567                        ++nrescans);
01568             goto rescan;
01569         }
01570 
01571         /* Return no. of packages that could not be ordered. */
01572         rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
01573                         loopcheck);
01574         return loopcheck;
01575     }
01576 
01577     /* Clean up tsort remnants (if any). */
01578     pi = rpmtsiInit(ts);
01579     while ((p = rpmtsiNext(pi, 0)) != NULL)
01580         rpmteFreeTSI(p);
01581     pi = rpmtsiFree(pi);
01582 
01583     /*
01584      * The order ends up as installed packages followed by removed packages,
01585      * with removes for upgrades immediately following the installation of
01586      * the new package. This would be easier if we could sort the
01587      * addedPackages array, but we store indexes into it in various places.
01588      */
01589     orderList = xcalloc(numOrderList, sizeof(*orderList));
01590     j = 0;
01591     pi = rpmtsiInit(ts);
01592     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01593         /* Prepare added package ordering permutation. */
01594         switch (rpmteType(p)) {
01595         case TR_ADDED:
01596             orderList[j].pkgKey = rpmteAddedKey(p);
01597             /*@switchbreak@*/ break;
01598         case TR_REMOVED:
01599             orderList[j].pkgKey = RPMAL_NOMATCH;
01600             /*@switchbreak@*/ break;
01601         }
01602         orderList[j].orIndex = rpmtsiOc(pi);
01603         j++;
01604     }
01605     pi = rpmtsiFree(pi);
01606 
01607     qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
01608 
01609 /*@-type@*/
01610     newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
01611 /*@=type@*/
01612     /*@-branchstate@*/
01613     for (i = 0, newOrderCount = 0; i < orderingCount; i++)
01614     {
01615         struct orderListIndex_s key;
01616         orderListIndex needle;
01617 
01618         key.pkgKey = ordering[i];
01619         needle = bsearch(&key, orderList, numOrderList,
01620                                 sizeof(key), orderListIndexCmp);
01621         /* bsearch should never, ever fail */
01622         if (needle == NULL)
01623             continue;
01624 
01625         j = needle->orIndex;
01626         if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
01627             continue;
01628 
01629         newOrder[newOrderCount++] = q;
01630         ts->order[j] = NULL;
01631         if (anaconda)
01632         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
01633             if ((q = ts->order[j]) == NULL)
01634                 /*@innerbreak@*/ break;
01635             if (rpmteType(q) == TR_REMOVED
01636              && rpmteDependsOnKey(q) == needle->pkgKey)
01637             {
01638                 newOrder[newOrderCount++] = q;
01639                 ts->order[j] = NULL;
01640             } else
01641                 /*@innerbreak@*/ break;
01642         }
01643     }
01644     /*@=branchstate@*/
01645 
01646     for (j = 0; j < ts->orderCount; j++) {
01647         if ((p = ts->order[j]) == NULL)
01648             continue;
01649         newOrder[newOrderCount++] = p;
01650         ts->order[j] = NULL;
01651     }
01652 assert(newOrderCount == ts->orderCount);
01653 
01654 /*@+voidabstract@*/
01655     ts->order = _free(ts->order);
01656 /*@=voidabstract@*/
01657     ts->order = newOrder;
01658     ts->orderAlloced = ts->orderCount;
01659     orderList = _free(orderList);
01660 
01661 #ifdef  DYING   /* XXX now done at the CLI level just before rpmtsRun(). */
01662     rpmtsClean(ts);
01663 #endif
01664     freeBadDeps();
01665 
01666     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01667 
01668     return 0;
01669 }
01670 /*@=bounds@*/
01671 
01672 int rpmtsCheck(rpmts ts)
01673 {
01674     uint_32 tscolor = rpmtsColor(ts);
01675     rpmdbMatchIterator mi = NULL;
01676     rpmtsi pi = NULL; rpmte p;
01677     int closeatexit = 0;
01678     int xx;
01679     int rc;
01680 
01681     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01682 
01683     /* Do lazy, readonly, open of rpm database. */
01684     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
01685         if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
01686             goto exit;
01687         closeatexit = 1;
01688     }
01689 
01690     ts->probs = rpmpsFree(ts->probs);
01691     ts->probs = rpmpsCreate();
01692 
01693     rpmalMakeIndex(ts->addedPackages);
01694 
01695     /*
01696      * Look at all of the added packages and make sure their dependencies
01697      * are satisfied.
01698      */
01699     pi = rpmtsiInit(ts);
01700     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01701         rpmds provides;
01702 
01703 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01704         rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
01705                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01706 /*@=nullpass@*/
01707         rc = checkPackageDeps(ts, rpmteNEVRA(p),
01708                         rpmteDS(p, RPMTAG_REQUIRENAME),
01709                         rpmteDS(p, RPMTAG_CONFLICTNAME),
01710                         NULL,
01711                         tscolor, 1);
01712         if (rc)
01713             goto exit;
01714 
01715         rc = 0;
01716         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01717         provides = rpmdsInit(provides);
01718         if (provides != NULL)
01719         while (rpmdsNext(provides) >= 0) {
01720             const char * Name;
01721 
01722             if ((Name = rpmdsN(provides)) == NULL)
01723                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01724 
01725             /* Adding: check provides key against conflicts matches. */
01726             if (!checkDependentConflicts(ts, Name))
01727                 /*@innercontinue@*/ continue;
01728             rc = 1;
01729             /*@innerbreak@*/ break;
01730         }
01731         if (rc)
01732             goto exit;
01733     }
01734     pi = rpmtsiFree(pi);
01735 
01736     /*
01737      * Look at the removed packages and make sure they aren't critical.
01738      */
01739     pi = rpmtsiInit(ts);
01740     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01741         rpmds provides;
01742         rpmfi fi;
01743 
01744 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01745         rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
01746                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01747 /*@=nullpass@*/
01748 
01749 #if defined(DYING) || defined(__LCLINT__)
01750         /* XXX all packages now have Provides: name = version-release */
01751         /* Erasing: check name against requiredby matches. */
01752         rc = checkDependentPackages(ts, rpmteN(p));
01753         if (rc)
01754                 goto exit;
01755 #endif
01756 
01757         rc = 0;
01758         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01759         provides = rpmdsInit(provides);
01760         if (provides != NULL)
01761         while (rpmdsNext(provides) >= 0) {
01762             const char * Name;
01763 
01764             if ((Name = rpmdsN(provides)) == NULL)
01765                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01766 
01767             /* Erasing: check provides against requiredby matches. */
01768             if (!checkDependentPackages(ts, Name))
01769                 /*@innercontinue@*/ continue;
01770             rc = 1;
01771             /*@innerbreak@*/ break;
01772         }
01773         if (rc)
01774             goto exit;
01775 
01776         rc = 0;
01777         fi = rpmteFI(p, RPMTAG_BASENAMES);
01778         fi = rpmfiInit(fi, 0);
01779         while (rpmfiNext(fi) >= 0) {
01780             const char * fn = rpmfiFN(fi);
01781 
01782             /* Erasing: check filename against requiredby matches. */
01783             if (!checkDependentPackages(ts, fn))
01784                 /*@innercontinue@*/ continue;
01785             rc = 1;
01786             /*@innerbreak@*/ break;
01787         }
01788         if (rc)
01789             goto exit;
01790     }
01791     pi = rpmtsiFree(pi);
01792 
01793     rc = 0;
01794 
01795 exit:
01796     mi = rpmdbFreeIterator(mi);
01797     pi = rpmtsiFree(pi);
01798 
01799     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01800 
01801     /*@-branchstate@*/
01802     if (closeatexit)
01803         xx = rpmtsCloseDB(ts);
01804     else if (_cacheDependsRC)
01805         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
01806     /*@=branchstate@*/
01807     return rc;
01808 }

Generated on Wed Jan 21 14:06:03 2009 for rpm by  doxygen 1.4.7