Main Page | Modules | Data Structures | Directories | File List | Data Fields | Globals | Related Pages

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

Generated on Tue Oct 4 10:00:59 2011 for rpm by  doxygen 1.3.9.1