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 
01045 /* Find the transaction element associated with key. */
01046 static rpmte findElem(rpmts ts, fnpyKey key, int *index)
01047 {
01048     rpmtsi qi;
01049     rpmte q, elem = NULL;
01050     int i;
01051 
01052     for (qi = rpmtsiInit(ts), i = 0; (q = rpmtsiNext(qi, 0)) != NULL; i++) {
01053         /* XXX Only added packages need be checked for matches. */
01054         if (rpmteType(q) == TR_REMOVED)
01055             continue;
01056 
01057         if (key == rpmteKey(q)) {
01058             elem = q;
01059             *index = i;
01060             break;
01061         }
01062     }
01063     qi = rpmtsiFree(qi);
01064     return elem;
01065 }
01066 
01075 /*@-mustmod@*/
01076 static inline int addRelation(rpmts ts,
01077                 /*@dependent@*/ rpmte p,
01078                 unsigned char * selected,
01079                 rpmds requires)
01080         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01081         /*@modifies ts, p, *selected, rpmGlobalMacroContext,
01082                 fileSystem, internalState @*/
01083 {
01084     rpmte q = NULL;
01085     tsortInfo tsi;
01086     const char * Name;
01087     fnpyKey *key, *keys = NULL;
01088     int i = 0;
01089 
01090     if ((Name = rpmdsN(requires)) == NULL)
01091         return 0;
01092 
01093     /* Avoid rpmlib feature dependencies. */
01094     if (!strncmp(Name, "rpmlib(", sizeof("rpmlib(")-1))
01095         return 0;
01096 
01097     /* Avoid package config dependencies. */
01098     if (!strncmp(Name, "config(", sizeof("config(")-1))
01099         return 0;
01100 
01101     keys = rpmalAllSatisfiesDepend(ts->addedPackages, requires, NULL);
01102 
01103     /* Ordering depends only on added package relations. */
01104     if (keys) {
01105         rpmte best = NULL;
01106 
01107         /*
01108          * On colored transactions, try to find the best provider for
01109          * a dependency based on color. Just picking up whatever comes first
01110          * can create bogus relations between packages, causing unresolvable
01111          * dependency loops and messing up ordering badly.
01112          */
01113         if (rpmtsColor(ts)) {
01114             int dscolor = rpmdsColor(requires);
01115             int prefcolor = rpmtsPrefColor(ts);
01116             for (key = keys; key && *key; key ++) {
01117                 rpmte z = findElem(ts, *key, &i);
01118                 int tecolor = rpmteColor(z);
01119                 if (dscolor) {
01120                     if (dscolor == tecolor) best = z;
01121                 } else if (prefcolor) {
01122                     if (prefcolor == tecolor) best = z;
01123                 };
01124                 if (best) break;
01125             }
01126         }
01127         /* If not decided by now, just pick first match */
01128         q = best ? best : findElem(ts, keys[0], &i);
01129 
01130         free(keys);
01131     }
01132 
01133     if (q == NULL)
01134         return 0;
01135 
01136     /* Avoid certain dependency relations. */
01137     if (ignoreDep(ts, p, q))
01138         return 0;
01139 
01140     /* Avoid redundant relations. */
01141     /* XXX TODO: add control bit. */
01142 /*@-boundsread@*/
01143     if (selected[i] != 0)
01144         return 0;
01145 /*@=boundsread@*/
01146 /*@-boundswrite@*/
01147     selected[i] = 1;
01148 /*@=boundswrite@*/
01149 
01150     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01151     rpmteTSI(p)->tsi_count++;                   /* bump p predecessor count */
01152 
01153     if (rpmteDepth(p) <= rpmteDepth(q)) /* Save max. depth in dependency tree */
01154         (void) rpmteSetDepth(p, (rpmteDepth(q) + 1));
01155     if (rpmteDepth(p) > ts->maxDepth)
01156         ts->maxDepth = rpmteDepth(p);
01157 
01158     tsi = xcalloc(1, sizeof(*tsi));
01159     tsi->tsi_suc = p;
01160 
01161     tsi->tsi_reqx = rpmdsIx(requires);
01162 
01163     tsi->tsi_next = rpmteTSI(q)->tsi_next;
01164     rpmteTSI(q)->tsi_next = tsi;
01165     rpmteTSI(q)->tsi_qcnt++;                    /* bump q successor count */
01166     return 0;
01167 }
01168 /*@=mustmod@*/
01169 
01176 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01177 {
01178     /*@-castexpose@*/
01179     long a = (long) ((const orderListIndex)one)->pkgKey;
01180     long b = (long) ((const orderListIndex)two)->pkgKey;
01181     /*@=castexpose@*/
01182     return (a - b);
01183 }
01184 
01191 /*@-boundswrite@*/
01192 /*@-mustmod@*/
01193 static void addQ(/*@dependent@*/ rpmte p,
01194                 /*@in@*/ /*@out@*/ rpmte * qp,
01195                 /*@in@*/ /*@out@*/ rpmte * rp,
01196                 uint_32 prefcolor)
01197         /*@modifies p, *qp, *rp @*/
01198 {
01199     rpmte q, qprev;
01200 
01201     /* Mark the package as queued. */
01202     rpmteTSI(p)->tsi_reqx = 1;
01203 
01204     if ((*rp) == NULL) {        /* 1st element */
01205         /*@-dependenttrans@*/ /* FIX: double indirection */
01206         (*rp) = (*qp) = p;
01207         /*@=dependenttrans@*/
01208         return;
01209     }
01210 
01211     /* Find location in queue using metric tsi_qcnt. */
01212     for (qprev = NULL, q = (*qp);
01213          q != NULL;
01214          qprev = q, q = rpmteTSI(q)->tsi_suc)
01215     {
01216         /* XXX Insure preferred color first. */
01217         if (rpmteColor(p) != prefcolor && rpmteColor(p) != rpmteColor(q))
01218             continue;
01219 
01220         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01221             break;
01222     }
01223 
01224     if (qprev == NULL) {        /* insert at beginning of list */
01225         rpmteTSI(p)->tsi_suc = q;
01226         /*@-dependenttrans@*/
01227         (*qp) = p;              /* new head */
01228         /*@=dependenttrans@*/
01229     } else if (q == NULL) {     /* insert at end of list */
01230         rpmteTSI(qprev)->tsi_suc = p;
01231         /*@-dependenttrans@*/
01232         (*rp) = p;              /* new tail */
01233         /*@=dependenttrans@*/
01234     } else {                    /* insert between qprev and q */
01235         rpmteTSI(p)->tsi_suc = q;
01236         rpmteTSI(qprev)->tsi_suc = p;
01237     }
01238 }
01239 /*@=mustmod@*/
01240 /*@=boundswrite@*/
01241 
01242 /*@-bounds@*/
01243 int rpmtsOrder(rpmts ts)
01244 {
01245     rpmds requires;
01246     int_32 Flags;
01247     int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
01248     uint_32 prefcolor = rpmtsPrefColor(ts);
01249     rpmtsi pi; rpmte p;
01250     rpmtsi qi; rpmte q;
01251     rpmtsi ri; rpmte r;
01252     tsortInfo tsi;
01253     tsortInfo tsi_next;
01254     alKey * ordering;
01255     int orderingCount = 0;
01256     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01257     int loopcheck;
01258     rpmte * newOrder;
01259     int newOrderCount = 0;
01260     orderListIndex orderList;
01261     int numOrderList;
01262     int npeer = 128;    /* XXX more than deep enough for now. */
01263     int * peer = memset(alloca(npeer*sizeof(*peer)), 0, (npeer*sizeof(*peer)));
01264     int nrescans = 0;
01265     int _printed = 0;
01266     char deptypechar;
01267     size_t tsbytes;
01268     int oType = 0;
01269     int treex;
01270     int depth;
01271     int breadth;
01272     int qlen;
01273     int i, j;
01274 
01275     /*
01276      * XXX FIXME: this gets needlesly called twice on normal usage patterns,
01277      * should track the need for generating the index somewhere
01278      */
01279     rpmalMakeIndex(ts->addedPackages);
01280 
01281     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01282 
01283     /* T1. Initialize. */
01284     if (oType == 0)
01285         numOrderList = ts->orderCount;
01286     else {
01287         numOrderList = 0;
01288         if (oType & TR_ADDED)
01289             numOrderList += ts->numAddedPackages;
01290         if (oType & TR_REMOVED)
01291             numOrderList += ts->numRemovedPackages;
01292      }
01293     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01294     loopcheck = numOrderList;
01295     tsbytes = 0;
01296 
01297     pi = rpmtsiInit(ts);
01298     while ((p = rpmtsiNext(pi, oType)) != NULL)
01299         rpmteNewTSI(p);
01300     pi = rpmtsiFree(pi);
01301 
01302     /* Record all relations. */
01303     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01304     pi = rpmtsiInit(ts);
01305     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01306 
01307         if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
01308             continue;
01309 
01310         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01311 
01312         /* Avoid narcisstic relations. */
01313         selected[rpmtsiOc(pi)] = 1;
01314 
01315         /* T2. Next "q <- p" relation. */
01316 
01317         /* First, do pre-requisites. */
01318         requires = rpmdsInit(requires);
01319         if (requires != NULL)
01320         while (rpmdsNext(requires) >= 0) {
01321 
01322             Flags = rpmdsFlags(requires);
01323 
01324             switch (rpmteType(p)) {
01325             case TR_REMOVED:
01326                 /* Skip if not %preun/%postun requires or legacy prereq. */
01327                 if (!( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01328                     /*@innercontinue@*/ continue;
01329                 /*@switchbreak@*/ break;
01330             case TR_ADDED:
01331                 /* Skip if not %pre/%post requires or legacy prereq. */
01332                 if (!( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01333                     /*@innercontinue@*/ continue;
01334                 /*@switchbreak@*/ break;
01335             }
01336 
01337             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01338             (void) addRelation(ts, p, selected, requires);
01339 
01340         }
01341 
01342         /* Then do co-requisites. */
01343         requires = rpmdsInit(requires);
01344         if (requires != NULL)
01345         while (rpmdsNext(requires) >= 0) {
01346 
01347             Flags = rpmdsFlags(requires);
01348 
01349             switch (rpmteType(p)) {
01350             case TR_REMOVED:
01351                 /* Skip if %preun/%postun requires or legacy prereq. */
01352                 if (isInstallPreReq(Flags)
01353                  ||  ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01354                     /*@innercontinue@*/ continue;
01355                 /*@switchbreak@*/ break;
01356             case TR_ADDED:
01357                 /* Skip if %pre/%post requires or legacy prereq. */
01358                 if (isErasePreReq(Flags)
01359                  ||  ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01360                     /*@innercontinue@*/ continue;
01361                 /*@switchbreak@*/ break;
01362             }
01363 
01364             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01365             (void) addRelation(ts, p, selected, requires);
01366 
01367         }
01368     }
01369     pi = rpmtsiFree(pi);
01370 
01371     /* Save predecessor count and mark tree roots. */
01372     treex = 0;
01373     pi = rpmtsiInit(ts);
01374     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01375         int npreds;
01376 
01377         npreds = rpmteTSI(p)->tsi_count;
01378 
01379         (void) rpmteSetNpreds(p, npreds);
01380         (void) rpmteSetDepth(p, 1);
01381 
01382         if (npreds == 0)
01383             (void) rpmteSetTree(p, treex++);
01384         else
01385             (void) rpmteSetTree(p, -1);
01386 #ifdef  UNNECESSARY
01387         (void) rpmteSetParent(p, NULL);
01388 #endif
01389 
01390     }
01391     pi = rpmtsiFree(pi);
01392     ts->ntrees = treex;
01393 
01394     /* T4. Scan for zeroes. */
01395     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth, breadth)\n"));
01396 
01397 rescan:
01398     if (pi != NULL) pi = rpmtsiFree(pi);
01399     q = r = NULL;
01400     qlen = 0;
01401     pi = rpmtsiInit(ts);
01402     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01403 
01404         /* Prefer packages in chainsaw or anaconda presentation order. */
01405         if (anaconda)
01406             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
01407 
01408         if (rpmteTSI(p)->tsi_count != 0)
01409             continue;
01410         rpmteTSI(p)->tsi_suc = NULL;
01411         addQ(p, &q, &r, prefcolor);
01412         qlen++;
01413     }
01414     pi = rpmtsiFree(pi);
01415 
01416     /* T5. Output front of queue (T7. Remove from queue.) */
01417     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
01418 
01419         /* Mark the package as unqueued. */
01420         rpmteTSI(q)->tsi_reqx = 0;
01421 
01422         if (oType != 0)
01423         switch (rpmteType(q)) {
01424         case TR_ADDED:
01425             if (!(oType & TR_ADDED))
01426                 continue;
01427             /*@switchbreak@*/ break;
01428         case TR_REMOVED:
01429             if (!(oType & TR_REMOVED))
01430                 continue;
01431             /*@switchbreak@*/ break;
01432         default:
01433             continue;
01434             /*@notreached@*/ /*@switchbreak@*/ break;
01435         }
01436         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
01437 
01438         treex = rpmteTree(q);
01439         depth = rpmteDepth(q);
01440         breadth = ((depth < npeer) ? peer[depth]++ : 0);
01441         (void) rpmteSetBreadth(q, breadth);
01442 
01443         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d%5d %*s%c%s\n",
01444                         orderingCount, rpmteNpreds(q),
01445                         rpmteTSI(q)->tsi_qcnt,
01446                         treex, depth, breadth,
01447                         (2 * depth), "",
01448                         deptypechar,
01449                         (rpmteNEVRA(q) ? rpmteNEVRA(q) : "???"));
01450 
01451         (void) rpmteSetDegree(q, 0);
01452         tsbytes += rpmtePkgFileSize(q);
01453 
01454         switch (rpmteType(q)) {
01455         case TR_ADDED:
01456             ordering[orderingCount] = rpmteAddedKey(q);
01457             /*@switchbreak@*/ break;
01458         case TR_REMOVED:
01459             ordering[orderingCount] = RPMAL_NOMATCH;
01460             /*@switchbreak@*/ break;
01461         }
01462         orderingCount++;
01463         qlen--;
01464         loopcheck--;
01465 
01466         /* T6. Erase relations. */
01467         tsi_next = rpmteTSI(q)->tsi_next;
01468         rpmteTSI(q)->tsi_next = NULL;
01469         while ((tsi = tsi_next) != NULL) {
01470             tsi_next = tsi->tsi_next;
01471             tsi->tsi_next = NULL;
01472             p = tsi->tsi_suc;
01473             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
01474 
01475                 (void) rpmteSetTree(p, treex);
01476                 (void) rpmteSetDepth(p, depth+1);
01477                 (void) rpmteSetParent(p, q);
01478                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
01479 
01480                 /* XXX TODO: add control bit. */
01481                 rpmteTSI(p)->tsi_suc = NULL;
01482                 addQ(p, &rpmteTSI(q)->tsi_suc, &r, prefcolor);
01483                 qlen++;
01484             }
01485             tsi = _free(tsi);
01486         }
01487         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
01488             _printed++;
01489             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
01490             rpmMessage(RPMMESS_DEBUG,
01491                 _("========== successors only (%d bytes)\n"), (int)tsbytes);
01492 
01493             /* Relink the queue in presentation order. */
01494             tsi = rpmteTSI(q);
01495             pi = rpmtsiInit(ts);
01496             while ((p = rpmtsiNext(pi, oType)) != NULL) {
01497                 /* Is this element in the queue? */
01498                 if (rpmteTSI(p)->tsi_reqx == 0)
01499                     /*@innercontinue@*/ continue;
01500                 tsi->tsi_suc = p;
01501                 tsi = rpmteTSI(p);
01502             }
01503             pi = rpmtsiFree(pi);
01504             tsi->tsi_suc = NULL;
01505         }
01506     }
01507 
01508     /* T8. End of process. Check for loops. */
01509     if (loopcheck != 0) {
01510         int nzaps;
01511 
01512         /* T9. Initialize predecessor chain. */
01513         nzaps = 0;
01514         qi = rpmtsiInit(ts);
01515         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01516             rpmteTSI(q)->tsi_chain = NULL;
01517             rpmteTSI(q)->tsi_reqx = 0;
01518             /* Mark packages already sorted. */
01519             if (rpmteTSI(q)->tsi_count == 0)
01520                 rpmteTSI(q)->tsi_count = -1;
01521         }
01522         qi = rpmtsiFree(qi);
01523 
01524         /* T10. Mark all packages with their predecessors. */
01525         qi = rpmtsiInit(ts);
01526         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01527             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
01528                 continue;
01529             rpmteTSI(q)->tsi_next = NULL;
01530             markLoop(tsi, q);
01531             rpmteTSI(q)->tsi_next = tsi;
01532         }
01533         qi = rpmtsiFree(qi);
01534 
01535         /* T11. Print all dependency loops. */
01536         ri = rpmtsiInit(ts);
01537         while ((r = rpmtsiNext(ri, oType)) != NULL)
01538         {
01539             int printed;
01540 
01541             printed = 0;
01542 
01543             /* T12. Mark predecessor chain, looking for start of loop. */
01544             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
01545                  q = rpmteTSI(q)->tsi_chain)
01546             {
01547                 if (rpmteTSI(q)->tsi_reqx)
01548                     /*@innerbreak@*/ break;
01549                 rpmteTSI(q)->tsi_reqx = 1;
01550             }
01551 
01552             /* T13. Print predecessor chain from start of loop. */
01553             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
01554                 const char * dp;
01555                 char buf[4096];
01556                 int msglvl = (anaconda || (rpmtsFlags(ts) & RPMTRANS_FLAG_DEPLOOPS))
01557                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01558 ;
01559 
01560                 /* Unchain predecessor loop. */
01561                 rpmteTSI(p)->tsi_chain = NULL;
01562 
01563                 if (!printed) {
01564                     rpmMessage(msglvl, _("LOOP:\n"));
01565                     printed = 1;
01566                 }
01567 
01568                 /* Find (and destroy if co-requisite) "q <- p" relation. */
01569                 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
01570                 requires = rpmdsInit(requires);
01571                 if (requires == NULL)
01572                     /*@innercontinue@*/ continue;       /* XXX can't happen */
01573                 dp = zapRelation(q, p, requires, 1, &nzaps, msglvl);
01574 
01575                 /* Print next member of loop. */
01576                 buf[0] = '\0';
01577                 if (rpmteNEVRA(p) != NULL)
01578                     (void) stpcpy(buf, rpmteNEVRA(p));
01579                 rpmMessage(msglvl, "    %-40s %s\n", buf,
01580                         (dp ? dp : "not found!?!"));
01581 
01582                 dp = _free(dp);
01583             }
01584 
01585             /* Walk (and erase) linear part of predecessor chain as well. */
01586             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
01587                  p = q, q = rpmteTSI(q)->tsi_chain)
01588             {
01589                 /* Unchain linear part of predecessor loop. */
01590                 rpmteTSI(p)->tsi_chain = NULL;
01591                 rpmteTSI(p)->tsi_reqx = 0;
01592             }
01593         }
01594         ri = rpmtsiFree(ri);
01595 
01596         /* If a relation was eliminated, then continue sorting. */
01597         /* XXX TODO: add control bit. */
01598         if (nzaps > 0) {
01599             rpmMessage(RPMMESS_DEBUG, 
01600                        _("========== continuing tsort ... (rescan %d)\n"),
01601                        ++nrescans);
01602             goto rescan;
01603         }
01604 
01605         /* Return no. of packages that could not be ordered. */
01606         rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
01607                         loopcheck);
01608         return loopcheck;
01609     }
01610 
01611     /* Clean up tsort remnants (if any). */
01612     pi = rpmtsiInit(ts);
01613     while ((p = rpmtsiNext(pi, 0)) != NULL)
01614         rpmteFreeTSI(p);
01615     pi = rpmtsiFree(pi);
01616 
01617     /*
01618      * The order ends up as installed packages followed by removed packages,
01619      * with removes for upgrades immediately following the installation of
01620      * the new package. This would be easier if we could sort the
01621      * addedPackages array, but we store indexes into it in various places.
01622      */
01623     orderList = xcalloc(numOrderList, sizeof(*orderList));
01624     j = 0;
01625     pi = rpmtsiInit(ts);
01626     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01627         /* Prepare added package ordering permutation. */
01628         switch (rpmteType(p)) {
01629         case TR_ADDED:
01630             orderList[j].pkgKey = rpmteAddedKey(p);
01631             /*@switchbreak@*/ break;
01632         case TR_REMOVED:
01633             orderList[j].pkgKey = RPMAL_NOMATCH;
01634             /*@switchbreak@*/ break;
01635         }
01636         orderList[j].orIndex = rpmtsiOc(pi);
01637         j++;
01638     }
01639     pi = rpmtsiFree(pi);
01640 
01641     qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
01642 
01643 /*@-type@*/
01644     newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
01645 /*@=type@*/
01646     /*@-branchstate@*/
01647     for (i = 0, newOrderCount = 0; i < orderingCount; i++)
01648     {
01649         struct orderListIndex_s key;
01650         orderListIndex needle;
01651 
01652         key.pkgKey = ordering[i];
01653         needle = bsearch(&key, orderList, numOrderList,
01654                                 sizeof(key), orderListIndexCmp);
01655         /* bsearch should never, ever fail */
01656         if (needle == NULL)
01657             continue;
01658 
01659         j = needle->orIndex;
01660         if ((q = ts->order[j]) == NULL || needle->pkgKey == RPMAL_NOMATCH)
01661             continue;
01662 
01663         newOrder[newOrderCount++] = q;
01664         ts->order[j] = NULL;
01665         if (anaconda)
01666         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
01667             if ((q = ts->order[j]) == NULL)
01668                 /*@innerbreak@*/ break;
01669             if (rpmteType(q) == TR_REMOVED
01670              && rpmteDependsOnKey(q) == needle->pkgKey)
01671             {
01672                 newOrder[newOrderCount++] = q;
01673                 ts->order[j] = NULL;
01674             } else
01675                 /*@innerbreak@*/ break;
01676         }
01677     }
01678     /*@=branchstate@*/
01679 
01680     for (j = 0; j < ts->orderCount; j++) {
01681         if ((p = ts->order[j]) == NULL)
01682             continue;
01683         newOrder[newOrderCount++] = p;
01684         ts->order[j] = NULL;
01685     }
01686 assert(newOrderCount == ts->orderCount);
01687 
01688 /*@+voidabstract@*/
01689     ts->order = _free(ts->order);
01690 /*@=voidabstract@*/
01691     ts->order = newOrder;
01692     ts->orderAlloced = ts->orderCount;
01693     orderList = _free(orderList);
01694 
01695 #ifdef  DYING   /* XXX now done at the CLI level just before rpmtsRun(). */
01696     rpmtsClean(ts);
01697 #endif
01698     freeBadDeps();
01699 
01700     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01701 
01702     return 0;
01703 }
01704 /*@=bounds@*/
01705 
01706 int rpmtsCheck(rpmts ts)
01707 {
01708     uint_32 tscolor = rpmtsColor(ts);
01709     rpmdbMatchIterator mi = NULL;
01710     rpmtsi pi = NULL; rpmte p;
01711     int closeatexit = 0;
01712     int xx;
01713     int rc;
01714 
01715     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01716 
01717     /* Do lazy, readonly, open of rpm database. */
01718     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
01719         if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
01720             goto exit;
01721         closeatexit = 1;
01722     }
01723 
01724     ts->probs = rpmpsFree(ts->probs);
01725     ts->probs = rpmpsCreate();
01726 
01727     rpmalMakeIndex(ts->addedPackages);
01728 
01729     /*
01730      * Look at all of the added packages and make sure their dependencies
01731      * are satisfied.
01732      */
01733     pi = rpmtsiInit(ts);
01734     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01735         rpmds provides;
01736 
01737 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01738         rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
01739                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01740 /*@=nullpass@*/
01741         rc = checkPackageDeps(ts, rpmteNEVRA(p),
01742                         rpmteDS(p, RPMTAG_REQUIRENAME),
01743                         rpmteDS(p, RPMTAG_CONFLICTNAME),
01744                         NULL,
01745                         tscolor, 1);
01746         if (rc)
01747             goto exit;
01748 
01749         rc = 0;
01750         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01751         provides = rpmdsInit(provides);
01752         if (provides != NULL)
01753         while (rpmdsNext(provides) >= 0) {
01754             const char * Name;
01755 
01756             if ((Name = rpmdsN(provides)) == NULL)
01757                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01758 
01759             /* Adding: check provides key against conflicts matches. */
01760             if (!checkDependentConflicts(ts, Name))
01761                 /*@innercontinue@*/ continue;
01762             rc = 1;
01763             /*@innerbreak@*/ break;
01764         }
01765         if (rc)
01766             goto exit;
01767     }
01768     pi = rpmtsiFree(pi);
01769 
01770     /*
01771      * Look at the removed packages and make sure they aren't critical.
01772      */
01773     pi = rpmtsiInit(ts);
01774     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01775         rpmds provides;
01776         rpmfi fi;
01777 
01778 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01779         rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
01780                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01781 /*@=nullpass@*/
01782 
01783 #if defined(DYING) || defined(__LCLINT__)
01784         /* XXX all packages now have Provides: name = version-release */
01785         /* Erasing: check name against requiredby matches. */
01786         rc = checkDependentPackages(ts, rpmteN(p));
01787         if (rc)
01788                 goto exit;
01789 #endif
01790 
01791         rc = 0;
01792         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01793         provides = rpmdsInit(provides);
01794         if (provides != NULL)
01795         while (rpmdsNext(provides) >= 0) {
01796             const char * Name;
01797 
01798             if ((Name = rpmdsN(provides)) == NULL)
01799                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01800 
01801             /* Erasing: check provides against requiredby matches. */
01802             if (!checkDependentPackages(ts, Name))
01803                 /*@innercontinue@*/ continue;
01804             rc = 1;
01805             /*@innerbreak@*/ break;
01806         }
01807         if (rc)
01808             goto exit;
01809 
01810         rc = 0;
01811         fi = rpmteFI(p, RPMTAG_BASENAMES);
01812         fi = rpmfiInit(fi, 0);
01813         while (rpmfiNext(fi) >= 0) {
01814             const char * fn = rpmfiFN(fi);
01815 
01816             /* Erasing: check filename against requiredby matches. */
01817             if (!checkDependentPackages(ts, fn))
01818                 /*@innercontinue@*/ continue;
01819             rc = 1;
01820             /*@innerbreak@*/ break;
01821         }
01822         if (rc)
01823             goto exit;
01824     }
01825     pi = rpmtsiFree(pi);
01826 
01827     rc = 0;
01828 
01829 exit:
01830     mi = rpmdbFreeIterator(mi);
01831     pi = rpmtsiFree(pi);
01832 
01833     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01834 
01835     /*@-branchstate@*/
01836     if (closeatexit)
01837         xx = rpmtsCloseDB(ts);
01838     else if (_cacheDependsRC)
01839         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
01840     /*@=branchstate@*/
01841     return rc;
01842 }

Generated on Thu Feb 23 17:00:14 2012 for rpm by  doxygen 1.4.7