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     if (isLegacyPreReq(f))
00956         return "PreReq:";
00957     f = _notpre(f);
00958     if (f & RPMSENSE_SCRIPT_PRE)
00959         return "Requires(pre):";
00960     if (f & RPMSENSE_SCRIPT_POST)
00961         return "Requires(post):";
00962     if (f & RPMSENSE_SCRIPT_PREUN)
00963         return "Requires(preun):";
00964     if (f & RPMSENSE_SCRIPT_POSTUN)
00965         return "Requires(postun):";
00966     if (f & RPMSENSE_SCRIPT_VERIFY)
00967         return "Requires(verify):";
00968     if (f & RPMSENSE_FIND_REQUIRES)
00969         return "Requires(auto):";
00970     return "Requires:";
00971 }
00972 
00986 /*@-boundswrite@*/
00987 /*@-mustmod@*/ /* FIX: hack modifies, but -type disables */
00988 static /*@owned@*/ /*@null@*/ const char *
00989 zapRelation(rpmte q, rpmte p,
00990                 /*@null@*/ rpmds requires,
00991                 int zap, /*@in@*/ /*@out@*/ int * nzaps, int msglvl)
00992         /*@modifies q, p, requires, *nzaps @*/
00993 {
00994     tsortInfo tsi_prev;
00995     tsortInfo tsi;
00996     const char *dp = NULL;
00997 
00998     for (tsi_prev = rpmteTSI(q), tsi = rpmteTSI(q)->tsi_next;
00999          tsi != NULL;
01000         /* XXX Note: the loop traverses "not found", break on "found". */
01001         /*@-nullderef@*/
01002          tsi_prev = tsi, tsi = tsi->tsi_next)
01003         /*@=nullderef@*/
01004     {
01005         int_32 Flags;
01006 
01007         /*@-abstractcompare@*/
01008         if (tsi->tsi_suc != p)
01009             continue;
01010         /*@=abstractcompare@*/
01011 
01012         if (requires == NULL) continue;         /* XXX can't happen */
01013 
01014         (void) rpmdsSetIx(requires, tsi->tsi_reqx);
01015 
01016         Flags = rpmdsFlags(requires);
01017 
01018         dp = rpmdsNewDNEVR( identifyDepend(Flags), requires);
01019 
01020         /*
01021          * Attempt to unravel a dependency loop by eliminating Requires's.
01022          */
01023         /*@-branchstate@*/
01024         if (zap && !(Flags & RPMSENSE_PREREQ)) {
01025             rpmMessage(msglvl,
01026                         _("removing %s \"%s\" from tsort relations.\n"),
01027                         (rpmteNEVRA(p) ?  rpmteNEVRA(p) : "???"), dp);
01028             rpmteTSI(p)->tsi_count--;
01029             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01030             tsi->tsi_next = NULL;
01031             tsi->tsi_suc = NULL;
01032             tsi = _free(tsi);
01033             if (nzaps)
01034                 (*nzaps)++;
01035             if (zap)
01036                 zap--;
01037         }
01038         /*@=branchstate@*/
01039         /* XXX Note: the loop traverses "not found", get out now! */
01040         break;
01041     }
01042     return dp;
01043 }
01044 /*@=mustmod@*/
01045 /*@=boundswrite@*/
01046 
01055 /*@-mustmod@*/
01056 static inline int addRelation(rpmts ts,
01057                 /*@dependent@*/ rpmte p,
01058                 unsigned char * selected,
01059                 rpmds requires)
01060         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01061         /*@modifies ts, p, *selected, rpmGlobalMacroContext,
01062                 fileSystem, internalState @*/
01063 {
01064     rpmtsi qi; rpmte q;
01065     tsortInfo tsi;
01066     const char * Name;
01067     fnpyKey key;
01068     alKey pkgKey;
01069     int i = 0;
01070 
01071     if ((Name = rpmdsN(requires)) == NULL)
01072         return 0;
01073 
01074     /* Avoid rpmlib feature dependencies. */
01075     if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
01076         return 0;
01077 
01078     /* Avoid package config dependencies. */
01079     if (!strncmp(Name, "config(", sizeof("config(")-1))
01080         return 0;
01081 
01082     pkgKey = RPMAL_NOMATCH;
01083     key = rpmalSatisfiesDepend(ts->addedPackages, requires, &pkgKey);
01084 
01085     /* Ordering depends only on added package relations. */
01086     if (pkgKey == RPMAL_NOMATCH)
01087         return 0;
01088 
01089 /* XXX Set q to the added package that has pkgKey == q->u.addedKey */
01090 /* XXX FIXME: bsearch is possible/needed here */
01091     for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
01092 
01093         /* XXX Only added packages need be checked for matches. */
01094         if (rpmteType(q) == TR_REMOVED)
01095             continue;
01096 
01097         if (pkgKey == rpmteAddedKey(q))
01098             break;
01099     }
01100     qi = rpmtsiFree(qi);
01101     if (q == NULL || i == ts->orderCount)
01102         return 0;
01103 
01104     /* Avoid certain dependency relations. */
01105     if (ignoreDep(ts, p, q))
01106         return 0;
01107 
01108     /* Avoid redundant relations. */
01109     /* XXX TODO: add control bit. */
01110 /*@-boundsread@*/
01111     if (selected[i] != 0)
01112         return 0;
01113 /*@=boundsread@*/
01114 /*@-boundswrite@*/
01115     selected[i] = 1;
01116 /*@=boundswrite@*/
01117 
01118     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01119     rpmteTSI(p)->tsi_count++;                   /* bump p predecessor count */
01120 
01121     if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
01122         (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
01123     if (rpmteDepth(p) > ts->maxDepth)
01124         ts->maxDepth = rpmteDepth(p);
01125 
01126     tsi = xcalloc(1, sizeof(*tsi));
01127     tsi->tsi_suc = p;
01128 
01129     tsi->tsi_reqx = rpmdsIx(requires);
01130 
01131     tsi->tsi_next = rpmteTSI(q)->tsi_next;
01132     rpmteTSI(q)->tsi_next = tsi;
01133     rpmteTSI(q)->tsi_qcnt++;                    /* bump q successor count */
01134     return 0;
01135 }
01136 /*@=mustmod@*/
01137 
01144 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01145 {
01146     /*@-castexpose@*/
01147     long a = (long) ((const orderListIndex)one)->pkgKey;
01148     long b = (long) ((const orderListIndex)two)->pkgKey;
01149     /*@=castexpose@*/
01150     return (a - b);
01151 }
01152 
01159 /*@-boundswrite@*/
01160 /*@-mustmod@*/
01161 static void addQ(/*@dependent@*/ rpmte p,
01162                 /*@in@*/ /*@out@*/ rpmte * qp,
01163                 /*@in@*/ /*@out@*/ rpmte * rp,
01164                 uint_32 prefcolor)
01165         /*@modifies p, *qp, *rp @*/
01166 {
01167     rpmte q, qprev;
01168 
01169     /* Mark the package as queued. */
01170     rpmteTSI(p)->tsi_reqx = 1;
01171 
01172     if ((*rp) == NULL) {        /* 1st element */
01173         /*@-dependenttrans@*/ /* FIX: double indirection */
01174         (*rp) = (*qp) = p;
01175         /*@=dependenttrans@*/
01176         return;
01177     }
01178 
01179     /* Find location in queue using metric tsi_qcnt. */
01180     for (qprev = NULL, q = (*qp);
01181          q != NULL;
01182          qprev = q, q = rpmteTSI(q)->tsi_suc)
01183     {
01184         /* XXX Insure preferred color first. */
01185         if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
01186             continue;
01187 
01188         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01189             break;
01190     }
01191 
01192     if (qprev == NULL) {        /* insert at beginning of list */
01193         rpmteTSI(p)->tsi_suc = q;
01194         /*@-dependenttrans@*/
01195         (*qp) = p;              /* new head */
01196         /*@=dependenttrans@*/
01197     } else if (q == NULL) {     /* insert at end of list */
01198         rpmteTSI(qprev)->tsi_suc = p;
01199         /*@-dependenttrans@*/
01200         (*rp) = p;              /* new tail */
01201         /*@=dependenttrans@*/
01202     } else {                    /* insert between qprev and q */
01203         rpmteTSI(p)->tsi_suc = q;
01204         rpmteTSI(qprev)->tsi_suc = p;
01205     }
01206 }
01207 /*@=mustmod@*/
01208 /*@=boundswrite@*/
01209 
01210 /*@-bounds@*/
01211 int rpmtsOrder(rpmts ts)
01212 {
01213     rpmds requires;
01214     int_32 Flags;
01215     int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
01216     uint_32 prefcolor = rpmtsPrefColor(ts);
01217     rpmtsi pi; rpmte p;
01218     rpmtsi qi; rpmte q;
01219     rpmtsi ri; rpmte r;
01220     tsortInfo tsi;
01221     tsortInfo tsi_next;
01222     alKey * ordering;
01223     int orderingCount = 0;
01224     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01225     int loopcheck;
01226     rpmte * newOrder;
01227     int newOrderCount = 0;
01228     orderListIndex orderList;
01229     int numOrderList;
01230     int npeer = 128;    /* XXX more than deep enough for now. */
01231     int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
01232     int nrescans = 10;
01233     int _printed = 0;
01234     char deptypechar;
01235     size_t tsbytes;
01236     int oType = 0;
01237     int treex;
01238     int depth;
01239     int breadth;
01240     int qlen;
01241     int i, j;
01242 
01243     /*
01244      * XXX FIXME: this gets needlesly called twice on normal usage patterns,
01245      * should track the need for generating the index somewhere
01246      */
01247     rpmalMakeIndex(ts->addedPackages);
01248 
01249     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01250 
01251     /* T1. Initialize. */
01252     if (oType == 0)
01253         numOrderList = ts->orderCount;
01254     else {
01255         numOrderList = 0;
01256         if (oType & TR_ADDED)
01257             numOrderList += ts->numAddedPackages;
01258         if (oType & TR_REMOVED)
01259             numOrderList += ts->numRemovedPackages;
01260      }
01261     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01262     loopcheck = numOrderList;
01263     tsbytes = 0;
01264 
01265     pi = rpmtsiInit(ts);
01266     while ((p = rpmtsiNext(pi, oType)) != NULL)
01267         rpmteNewTSI(p);
01268     pi = rpmtsiFree(pi);
01269 
01270     /* Record all relations. */
01271     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01272     pi = rpmtsiInit(ts);
01273     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01274 
01275         if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
01276             continue;
01277 
01278         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01279 
01280         /* Avoid narcisstic relations. */
01281         selected[rpmtsiOc(pi)] = 1;
01282 
01283         /* T2. Next "q <- p" relation. */
01284 
01285         /* First, do pre-requisites. */
01286         requires = rpmdsInit(requires);
01287         if (requires != NULL)
01288         while (rpmdsNext(requires) >= 0) {
01289 
01290             Flags = rpmdsFlags(requires);
01291 
01292             switch (rpmteType(p)) {
01293             case TR_REMOVED:
01294                 /* Skip if not %preun/%postun requires or legacy prereq. */
01295                 if (!( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01296                     /*@innercontinue@*/ continue;
01297                 /*@switchbreak@*/ break;
01298             case TR_ADDED:
01299                 /* Skip if not %pre/%post requires or legacy prereq. */
01300                 if (!( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01301                     /*@innercontinue@*/ continue;
01302                 /*@switchbreak@*/ break;
01303             }
01304 
01305             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01306             (void) addRelation(ts, p, selected, requires);
01307 
01308         }
01309 
01310         /* Then do co-requisites. */
01311         requires = rpmdsInit(requires);
01312         if (requires != NULL)
01313         while (rpmdsNext(requires) >= 0) {
01314 
01315             Flags = rpmdsFlags(requires);
01316 
01317             switch (rpmteType(p)) {
01318             case TR_REMOVED:
01319                 /* Skip if %preun/%postun requires or legacy prereq. */
01320                 if (isInstallPreReq(Flags)
01321                  ||  ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01322                     /*@innercontinue@*/ continue;
01323                 /*@switchbreak@*/ break;
01324             case TR_ADDED:
01325                 /* Skip if %pre/%post requires or legacy prereq. */
01326                 if (isErasePreReq(Flags)
01327                  ||  ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01328                     /*@innercontinue@*/ continue;
01329                 /*@switchbreak@*/ break;
01330             }
01331 
01332             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01333             (void) addRelation(ts, p, selected, requires);
01334 
01335         }
01336     }
01337     pi = rpmtsiFree(pi);
01338 
01339     /* Save predecessor count and mark tree roots. */
01340     treex = 0;
01341     pi = rpmtsiInit(ts);
01342     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01343         int npreds;
01344 
01345         npreds = rpmteTSI(p)->tsi_count;
01346 
01347         (void) rpmteSetNpreds(p, npreds);
01348         (void) rpmteSetDepth(p, 1);
01349 
01350         if (npreds == 0)
01351             (void) rpmteSetTree(p, treex++);
01352         else
01353             (void) rpmteSetTree(p, -1);
01354 #ifdef  UNNECESSARY
01355         (void) rpmteSetParent(p, NULL);
01356 #endif
01357 
01358     }
01359     pi = rpmtsiFree(pi);
01360     ts->ntrees = treex;
01361 
01362     /* T4. Scan for zeroes. */
01363     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth)\n"));
01364 
01365 rescan:
01366     if (pi != NULL) pi = rpmtsiFree(pi);
01367     q = r = NULL;
01368     qlen = 0;
01369     pi = rpmtsiInit(ts);
01370     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01371 
01372         /* Prefer packages in chainsaw or anaconda presentation order. */
01373         if (anaconda)
01374             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
01375 
01376         if (rpmteTSI(p)->tsi_count != 0)
01377             continue;
01378         rpmteTSI(p)->tsi_suc = NULL;
01379         addQ(p, &q, &r, prefcolor);
01380         qlen++;
01381     }
01382     pi = rpmtsiFree(pi);
01383 
01384     /* T5. Output front of queue (T7. Remove from queue.) */
01385     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
01386 
01387         /* Mark the package as unqueued. */
01388         rpmteTSI(q)->tsi_reqx = 0;
01389 
01390         if (oType != 0)
01391         switch (rpmteType(q)) {
01392         case TR_ADDED:
01393             if (!(oType & TR_ADDED))
01394                 continue;
01395             /*@switchbreak@*/ break;
01396         case TR_REMOVED:
01397             if (!(oType & TR_REMOVED))
01398                 continue;
01399             /*@switchbreak@*/ break;
01400         default:
01401             continue;
01402             /*@notreached@*/ /*@switchbreak@*/ break;
01403         }
01404         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
01405 
01406         treex = rpmteTree(q);
01407         depth = rpmteDepth(q);
01408         breadth = ((depth < npeer) ? peer[depth]++ : 0);
01409         (void) rpmteSetBreadth(q, breadth);
01410 
01411         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
01412                         orderingCount, rpmteNpreds(q),
01413                         rpmteTSI(q)->tsi_qcnt,
01414                         treex, depth, breadth,
01415                         (2 * depth), "",
01416                         deptypechar,
01417                         (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
01418 
01419         (void) rpmteSetDegree(q, 0);
01420         tsbytes += rpmtePkgFileSize(q);
01421 
01422         switch (rpmteType(q)) {
01423         case TR_ADDED:
01424             ordering[orderingCount] = rpmteAddedKey(q);
01425             /*@switchbreak@*/ break;
01426         case TR_REMOVED:
01427             ordering[orderingCount] = RPMAL_NOMATCH;
01428             /*@switchbreak@*/ break;
01429         }
01430         orderingCount++;
01431         qlen--;
01432         loopcheck--;
01433 
01434         /* T6. Erase relations. */
01435         tsi_next = rpmteTSI(q)->tsi_next;
01436         rpmteTSI(q)->tsi_next = NULL;
01437         while ((tsi = tsi_next) != NULL) {
01438             tsi_next = tsi->tsi_next;
01439             tsi->tsi_next = NULL;
01440             p = tsi->tsi_suc;
01441             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
01442 
01443                 (void) rpmteSetTree(p, treex);
01444                 (void) rpmteSetDepth(p, depth+1);
01445                 (void) rpmteSetParent(p, q);
01446                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
01447 
01448                 /* XXX TODO: add control bit. */
01449                 rpmteTSI(p)->tsi_suc = NULL;
01450                 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
01451                 qlen++;
01452             }
01453             tsi = _free(tsi);
01454         }
01455         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
01456             _printed++;
01457             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
01458             rpmMessage(RPMMESS_DEBUG,
01459                 _("========== successors only (%d bytes)\n"), (int)tsbytes);
01460 
01461             /* Relink the queue in presentation order. */
01462             tsi = rpmteTSI(q);
01463             pi = rpmtsiInit(ts);
01464             while ((p = rpmtsiNext(pi, oType)) != NULL) {
01465                 /* Is this element in the queue? */
01466                 if (rpmteTSI(p)->tsi_reqx == 0)
01467                     /*@innercontinue@*/ continue;
01468                 tsi->tsi_suc = p;
01469                 tsi = rpmteTSI(p);
01470             }
01471             pi = rpmtsiFree(pi);
01472             tsi->tsi_suc = NULL;
01473         }
01474     }
01475 
01476     /* T8. End of process. Check for loops. */
01477     if (loopcheck != 0) {
01478         int nzaps;
01479 
01480         /* T9. Initialize predecessor chain. */
01481         nzaps = 0;
01482         qi = rpmtsiInit(ts);
01483         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01484             rpmteTSI(q)->tsi_chain = NULL;
01485             rpmteTSI(q)->tsi_reqx = 0;
01486             /* Mark packages already sorted. */
01487             if (rpmteTSI(q)->tsi_count == 0)
01488                 rpmteTSI(q)->tsi_count = -1;
01489         }
01490         qi = rpmtsiFree(qi);
01491 
01492         /* T10. Mark all packages with their predecessors. */
01493         qi = rpmtsiInit(ts);
01494         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01495             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
01496                 continue;
01497             rpmteTSI(q)->tsi_next = NULL;
01498             markLoop(tsi, q);
01499             rpmteTSI(q)->tsi_next = tsi;
01500         }
01501         qi = rpmtsiFree(qi);
01502 
01503         /* T11. Print all dependency loops. */
01504         ri = rpmtsiInit(ts);
01505         while ((r = rpmtsiNext(ri, oType)) != NULL)
01506         {
01507             int printed;
01508 
01509             printed = 0;
01510 
01511             /* T12. Mark predecessor chain, looking for start of loop. */
01512             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
01513                  q = rpmteTSI(q)->tsi_chain)
01514             {
01515                 if (rpmteTSI(q)->tsi_reqx)
01516                     /*@innerbreak@*/ break;
01517                 rpmteTSI(q)->tsi_reqx = 1;
01518             }
01519 
01520             /* T13. Print predecessor chain from start of loop. */
01521             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
01522                 const char * dp;
01523                 char buf[4096];
01524                 int msglvl = (anaconda || (rpmtsFlags(ts) & RPMTRANS_FLAG_DEPLOOPS))
01525                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01526 ;
01527 
01528                 /* Unchain predecessor loop. */
01529                 rpmteTSI(p)->tsi_chain = NULL;
01530 
01531                 if (!printed) {
01532                     rpmMessage(msglvl, _("LOOP:\n"));
01533                     printed = 1;
01534                 }
01535 
01536                 /* Find (and destroy if co-requisite) "q <- p" relation. */
01537                 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
01538                 requires = rpmdsInit(requires);
01539                 if (requires == NULL)
01540                     /*@innercontinue@*/ continue;       /* XXX can't happen */
01541                 dp = zapRelation(q, p, requires, 1, &nzaps, msglvl);
01542 
01543                 /* Print next member of loop. */
01544                 buf[0] = '\0';
01545                 if (rpmteNEVRA(p) != NULL)
01546                     (void) stpcpy(buf, rpmteNEVRA(p));
01547                 rpmMessage(msglvl, "    %-40s %s\n", buf,
01548                         (dp ? dp : "not found!?!"));
01549 
01550                 dp = _free(dp);
01551             }
01552 
01553             /* Walk (and erase) linear part of predecessor chain as well. */
01554             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
01555                  p = q, q = rpmteTSI(q)->tsi_chain)
01556             {
01557                 /* Unchain linear part of predecessor loop. */
01558                 rpmteTSI(p)->tsi_chain = NULL;
01559                 rpmteTSI(p)->tsi_reqx = 0;
01560             }
01561         }
01562         ri = rpmtsiFree(ri);
01563 
01564         /* If a relation was eliminated, then continue sorting. */
01565         /* XXX TODO: add control bit. */
01566         if (nzaps && nrescans-- > 0) {
01567             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
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 Fri Oct 12 08:44:53 2007 for rpm by  doxygen 1.5.2