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         /*@modifies p, *qp, *rp @*/
01118 {
01119     rpmte q, qprev;
01120 
01121     /* Mark the package as queued. */
01122     rpmteTSI(p)->tsi_reqx = 1;
01123 
01124     if ((*rp) == NULL) {        /* 1st element */
01125         /*@-dependenttrans@*/ /* FIX: double indirection */
01126         (*rp) = (*qp) = p;
01127         /*@=dependenttrans@*/
01128         return;
01129     }
01130 
01131     /* Find location in queue using metric tsi_qcnt. */
01132     for (qprev = NULL, q = (*qp);
01133          q != NULL;
01134          qprev = q, q = rpmteTSI(q)->tsi_suc)
01135     {
01136         if (rpmteTSI(q)->tsi_qcnt <= rpmteTSI(p)->tsi_qcnt)
01137             break;
01138     }
01139 
01140     if (qprev == NULL) {        /* insert at beginning of list */
01141         rpmteTSI(p)->tsi_suc = q;
01142         /*@-dependenttrans@*/
01143         (*qp) = p;              /* new head */
01144         /*@=dependenttrans@*/
01145     } else if (q == NULL) {     /* insert at end of list */
01146         rpmteTSI(qprev)->tsi_suc = p;
01147         /*@-dependenttrans@*/
01148         (*rp) = p;              /* new tail */
01149         /*@=dependenttrans@*/
01150     } else {                    /* insert between qprev and q */
01151         rpmteTSI(p)->tsi_suc = q;
01152         rpmteTSI(qprev)->tsi_suc = p;
01153     }
01154 }
01155 /*@=mustmod@*/
01156 /*@=boundswrite@*/
01157 
01158 /*@-bounds@*/
01159 int rpmtsOrder(rpmts ts)
01160 {
01161     rpmds requires;
01162     int_32 Flags;
01163     int anaconda = rpmtsFlags(ts) & RPMTRANS_FLAG_ANACONDA;
01164     rpmtsi pi; rpmte p;
01165     rpmtsi qi; rpmte q;
01166     rpmtsi ri; rpmte r;
01167     tsortInfo tsi;
01168     tsortInfo tsi_next;
01169     alKey * ordering;
01170     int orderingCount = 0;
01171     unsigned char * selected = alloca(sizeof(*selected) * (ts->orderCount + 1));
01172     int loopcheck;
01173     rpmte * newOrder;
01174     int newOrderCount = 0;
01175     orderListIndex orderList;
01176     int numOrderList;
01177     int nrescans = 10;
01178     int _printed = 0;
01179     char deptypechar;
01180     size_t tsbytes;
01181     int oType = 0;
01182     int treex;
01183     int depth;
01184     int qlen;
01185     int i, j;
01186 
01187 #ifdef  DYING
01188     rpmalMakeIndex(ts->addedPackages);
01189 #endif
01190 
01191     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01192 
01193     /* T1. Initialize. */
01194     if (oType == 0)
01195         numOrderList = ts->orderCount;
01196     else {
01197         numOrderList = 0;
01198         if (oType & TR_ADDED)
01199             numOrderList += ts->numAddedPackages;
01200         if (oType & TR_REMOVED)
01201             numOrderList += ts->numRemovedPackages;
01202      }
01203     ordering = alloca(sizeof(*ordering) * (numOrderList + 1));
01204     loopcheck = numOrderList;
01205     tsbytes = 0;
01206 
01207     pi = rpmtsiInit(ts);
01208     while ((p = rpmtsiNext(pi, oType)) != NULL)
01209         rpmteNewTSI(p);
01210     pi = rpmtsiFree(pi);
01211 
01212     /* Record all relations. */
01213     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01214     pi = rpmtsiInit(ts);
01215     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01216 
01217         if ((requires = rpmteDS(p, RPMTAG_REQUIRENAME)) == NULL)
01218             continue;
01219 
01220         memset(selected, 0, sizeof(*selected) * ts->orderCount);
01221 
01222         /* Avoid narcisstic relations. */
01223         selected[rpmtsiOc(pi)] = 1;
01224 
01225         /* T2. Next "q <- p" relation. */
01226 
01227         /* First, do pre-requisites. */
01228         requires = rpmdsInit(requires);
01229         if (requires != NULL)
01230         while (rpmdsNext(requires) >= 0) {
01231 
01232             Flags = rpmdsFlags(requires);
01233 
01234             switch (rpmteType(p)) {
01235             case TR_REMOVED:
01236                 /* Skip if not %preun/%postun requires or legacy prereq. */
01237                 if (isInstallPreReq(Flags)
01238                  || !( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01239                     /*@innercontinue@*/ continue;
01240                 /*@switchbreak@*/ break;
01241             case TR_ADDED:
01242                 /* Skip if not %pre/%post requires or legacy prereq. */
01243                 if (isErasePreReq(Flags)
01244                  || !( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01245                     /*@innercontinue@*/ continue;
01246                 /*@switchbreak@*/ break;
01247             }
01248 
01249             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01250             (void) addRelation(ts, p, selected, requires);
01251 
01252         }
01253 
01254         /* Then do co-requisites. */
01255         requires = rpmdsInit(requires);
01256         if (requires != NULL)
01257         while (rpmdsNext(requires) >= 0) {
01258 
01259             Flags = rpmdsFlags(requires);
01260 
01261             switch (rpmteType(p)) {
01262             case TR_REMOVED:
01263                 /* Skip if %preun/%postun requires or legacy prereq. */
01264                 if (isInstallPreReq(Flags)
01265                  ||  ( isErasePreReq(Flags) || isLegacyPreReq(Flags) ) )
01266                     /*@innercontinue@*/ continue;
01267                 /*@switchbreak@*/ break;
01268             case TR_ADDED:
01269                 /* Skip if %pre/%post requires or legacy prereq. */
01270                 if (isErasePreReq(Flags)
01271                  ||  ( isInstallPreReq(Flags) || isLegacyPreReq(Flags) ) )
01272                     /*@innercontinue@*/ continue;
01273                 /*@switchbreak@*/ break;
01274             }
01275 
01276             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01277             (void) addRelation(ts, p, selected, requires);
01278 
01279         }
01280     }
01281     pi = rpmtsiFree(pi);
01282 
01283     /* Save predecessor count and mark tree roots. */
01284     treex = 0;
01285     pi = rpmtsiInit(ts);
01286     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01287         int npreds;
01288 
01289         npreds = rpmteTSI(p)->tsi_count;
01290 
01291         (void) rpmteSetNpreds(p, npreds);
01292 
01293         if (npreds == 0)
01294             (void) rpmteSetTree(p, treex++);
01295         else
01296             (void) rpmteSetTree(p, -1);
01297 #ifdef  UNNECESSARY
01298         (void) rpmteSetParent(p, NULL);
01299 #endif
01300 
01301     }
01302     pi = rpmtsiFree(pi);
01303 
01304     /* T4. Scan for zeroes. */
01305     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
01306 
01307 rescan:
01308     if (pi != NULL) pi = rpmtsiFree(pi);
01309     q = r = NULL;
01310     qlen = 0;
01311     pi = rpmtsiInit(ts);
01312     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01313 
01314         /* Prefer packages in chainsaw or anaconda presentation order. */
01315         if (anaconda)
01316             rpmteTSI(p)->tsi_qcnt = (ts->orderCount - rpmtsiOc(pi));
01317 
01318         if (rpmteTSI(p)->tsi_count != 0)
01319             continue;
01320         rpmteTSI(p)->tsi_suc = NULL;
01321         addQ(p, &q, &r);
01322         qlen++;
01323     }
01324     pi = rpmtsiFree(pi);
01325 
01326     /* T5. Output front of queue (T7. Remove from queue.) */
01327     for (; q != NULL; q = rpmteTSI(q)->tsi_suc) {
01328 
01329         /* Mark the package as unqueued. */
01330         rpmteTSI(q)->tsi_reqx = 0;
01331 
01332         if (oType != 0)
01333         switch (rpmteType(q)) {
01334         case TR_ADDED:
01335             if (!(oType & TR_ADDED))
01336                 continue;
01337             /*@switchbreak@*/ break;
01338         case TR_REMOVED:
01339             if (!(oType & TR_REMOVED))
01340                 continue;
01341             /*@switchbreak@*/ break;
01342         default:
01343             continue;
01344             /*@notreached@*/ /*@switchbreak@*/ break;
01345         }
01346         deptypechar = (rpmteType(q) == TR_REMOVED ? '-' : '+');
01347 
01348         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s%c%s\n",
01349                         orderingCount, rpmteNpreds(q),
01350                         rpmteTSI(q)->tsi_qcnt, rpmteTree(q), rpmteDepth(q),
01351                         (2 * rpmteDepth(q)), "",
01352                         deptypechar,
01353                         (rpmteNEVR(q) ? rpmteNEVR(q) : "???"));
01354 
01355         treex = rpmteTree(q);
01356         depth = rpmteDepth(q);
01357         (void) rpmteSetDegree(q, 0);
01358         tsbytes += rpmtePkgFileSize(q);
01359 
01360         ordering[orderingCount] = rpmteAddedKey(q);
01361         orderingCount++;
01362         qlen--;
01363         loopcheck--;
01364 
01365         /* T6. Erase relations. */
01366         tsi_next = rpmteTSI(q)->tsi_next;
01367         rpmteTSI(q)->tsi_next = NULL;
01368         while ((tsi = tsi_next) != NULL) {
01369             tsi_next = tsi->tsi_next;
01370             tsi->tsi_next = NULL;
01371             p = tsi->tsi_suc;
01372             if (p && (--rpmteTSI(p)->tsi_count) <= 0) {
01373 
01374                 (void) rpmteSetTree(p, treex);
01375                 (void) rpmteSetDepth(p, depth+1);
01376                 (void) rpmteSetParent(p, q);
01377                 (void) rpmteSetDegree(q, rpmteDegree(q)+1);
01378 
01379                 /* XXX TODO: add control bit. */
01380                 rpmteTSI(p)->tsi_suc = NULL;
01381                 addQ(p, &rpmteTSI(q)->tsi_suc, &r);
01382                 qlen++;
01383             }
01384             tsi = _free(tsi);
01385         }
01386         if (!_printed && loopcheck == qlen && rpmteTSI(q)->tsi_suc != NULL) {
01387             _printed++;
01388             (void) rpmtsUnorderedSuccessors(ts, orderingCount);
01389             rpmMessage(RPMMESS_DEBUG,
01390                 _("========== successors only (%d bytes)\n"), (int)tsbytes);
01391 
01392             /* Relink the queue in presentation order. */
01393             tsi = rpmteTSI(q);
01394             pi = rpmtsiInit(ts);
01395             while ((p = rpmtsiNext(pi, oType)) != NULL) {
01396                 /* Is this element in the queue? */
01397                 if (rpmteTSI(p)->tsi_reqx == 0)
01398                     /*@innercontinue@*/ continue;
01399                 tsi->tsi_suc = p;
01400                 tsi = rpmteTSI(p);
01401             }
01402             pi = rpmtsiFree(pi);
01403             tsi->tsi_suc = NULL;
01404         }
01405     }
01406 
01407     /* T8. End of process. Check for loops. */
01408     if (loopcheck != 0) {
01409         int nzaps;
01410 
01411         /* T9. Initialize predecessor chain. */
01412         nzaps = 0;
01413         qi = rpmtsiInit(ts);
01414         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01415             rpmteTSI(q)->tsi_chain = NULL;
01416             rpmteTSI(q)->tsi_reqx = 0;
01417             /* Mark packages already sorted. */
01418             if (rpmteTSI(q)->tsi_count == 0)
01419                 rpmteTSI(q)->tsi_count = -1;
01420         }
01421         qi = rpmtsiFree(qi);
01422 
01423         /* T10. Mark all packages with their predecessors. */
01424         qi = rpmtsiInit(ts);
01425         while ((q = rpmtsiNext(qi, oType)) != NULL) {
01426             if ((tsi = rpmteTSI(q)->tsi_next) == NULL)
01427                 continue;
01428             rpmteTSI(q)->tsi_next = NULL;
01429             markLoop(tsi, q);
01430             rpmteTSI(q)->tsi_next = tsi;
01431         }
01432         qi = rpmtsiFree(qi);
01433 
01434         /* T11. Print all dependency loops. */
01435         ri = rpmtsiInit(ts);
01436         while ((r = rpmtsiNext(ri, oType)) != NULL)
01437         {
01438             int printed;
01439 
01440             printed = 0;
01441 
01442             /* T12. Mark predecessor chain, looking for start of loop. */
01443             for (q = rpmteTSI(r)->tsi_chain; q != NULL;
01444                  q = rpmteTSI(q)->tsi_chain)
01445             {
01446                 if (rpmteTSI(q)->tsi_reqx)
01447                     /*@innerbreak@*/ break;
01448                 rpmteTSI(q)->tsi_reqx = 1;
01449             }
01450 
01451             /* T13. Print predecessor chain from start of loop. */
01452             while ((p = q) != NULL && (q = rpmteTSI(p)->tsi_chain) != NULL) {
01453                 const char * dp;
01454                 char buf[4096];
01455                 int msglvl = (anaconda || (rpmtsFlags(ts) & RPMTRANS_FLAG_DEPLOOPS))
01456                         ? RPMMESS_WARNING : RPMMESS_DEBUG;
01457 ;
01458 
01459                 /* Unchain predecessor loop. */
01460                 rpmteTSI(p)->tsi_chain = NULL;
01461 
01462                 if (!printed) {
01463                     rpmMessage(msglvl, _("LOOP:\n"));
01464                     printed = 1;
01465                 }
01466 
01467                 /* Find (and destroy if co-requisite) "q <- p" relation. */
01468                 requires = rpmteDS(p, RPMTAG_REQUIRENAME);
01469                 requires = rpmdsInit(requires);
01470                 if (requires == NULL)
01471                     /*@innercontinue@*/ continue;       /* XXX can't happen */
01472                 dp = zapRelation(q, p, requires, 1, &nzaps, msglvl);
01473 
01474                 /* Print next member of loop. */
01475                 buf[0] = '\0';
01476                 if (rpmteNEVR(p) != NULL)
01477                     (void) stpcpy(buf, rpmteNEVR(p));
01478                 rpmMessage(msglvl, "    %-40s %s\n", buf,
01479                         (dp ? dp : "not found!?!"));
01480 
01481                 dp = _free(dp);
01482             }
01483 
01484             /* Walk (and erase) linear part of predecessor chain as well. */
01485             for (p = r, q = rpmteTSI(r)->tsi_chain; q != NULL;
01486                  p = q, q = rpmteTSI(q)->tsi_chain)
01487             {
01488                 /* Unchain linear part of predecessor loop. */
01489                 rpmteTSI(p)->tsi_chain = NULL;
01490                 rpmteTSI(p)->tsi_reqx = 0;
01491             }
01492         }
01493         ri = rpmtsiFree(ri);
01494 
01495         /* If a relation was eliminated, then continue sorting. */
01496         /* XXX TODO: add control bit. */
01497         if (nzaps && nrescans-- > 0) {
01498             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
01499             goto rescan;
01500         }
01501 
01502         /* Return no. of packages that could not be ordered. */
01503         rpmMessage(RPMMESS_ERROR, _("rpmtsOrder failed, %d elements remain\n"),
01504                         loopcheck);
01505         return loopcheck;
01506     }
01507 
01508     /* Clean up tsort remnants (if any). */
01509     pi = rpmtsiInit(ts);
01510     while ((p = rpmtsiNext(pi, 0)) != NULL)
01511         rpmteFreeTSI(p);
01512     pi = rpmtsiFree(pi);
01513 
01514     /*
01515      * The order ends up as installed packages followed by removed packages,
01516      * with removes for upgrades immediately following the installation of
01517      * the new package. This would be easier if we could sort the
01518      * addedPackages array, but we store indexes into it in various places.
01519      */
01520     orderList = xcalloc(numOrderList, sizeof(*orderList));
01521     j = 0;
01522     pi = rpmtsiInit(ts);
01523     while ((p = rpmtsiNext(pi, oType)) != NULL) {
01524         /* Prepare added package ordering permutation. */
01525         switch (rpmteType(p)) {
01526         case TR_ADDED:
01527             orderList[j].pkgKey = rpmteAddedKey(p);
01528             /*@switchbreak@*/ break;
01529         case TR_REMOVED:
01530             orderList[j].pkgKey = RPMAL_NOMATCH;
01531             /*@switchbreak@*/ break;
01532         }
01533         orderList[j].orIndex = rpmtsiOc(pi);
01534         j++;
01535     }
01536     pi = rpmtsiFree(pi);
01537 
01538     qsort(orderList, numOrderList, sizeof(*orderList), orderListIndexCmp);
01539 
01540 /*@-type@*/
01541     newOrder = xcalloc(ts->orderCount, sizeof(*newOrder));
01542 /*@=type@*/
01543     /*@-branchstate@*/
01544     for (i = 0, newOrderCount = 0; i < orderingCount; i++)
01545     {
01546         struct orderListIndex_s key;
01547         orderListIndex needle;
01548 
01549         key.pkgKey = ordering[i];
01550         needle = bsearch(&key, orderList, numOrderList,
01551                                 sizeof(key), orderListIndexCmp);
01552         /* bsearch should never, ever fail */
01553         if (needle == NULL)
01554             continue;
01555 
01556         j = needle->orIndex;
01557         if ((q = ts->order[j]) == NULL)
01558             continue;
01559 
01560         newOrder[newOrderCount++] = q;
01561         ts->order[j] = NULL;
01562         if (anaconda)
01563         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
01564             if ((q = ts->order[j]) == NULL)
01565                 /*@innerbreak@*/ break;
01566             if (rpmteType(q) == TR_REMOVED
01567              && rpmteDependsOnKey(q) == needle->pkgKey)
01568             {
01569                 newOrder[newOrderCount++] = q;
01570                 ts->order[j] = NULL;
01571             } else
01572                 /*@innerbreak@*/ break;
01573         }
01574     }
01575     /*@=branchstate@*/
01576 
01577     for (j = 0; j < ts->orderCount; j++) {
01578         if ((p = ts->order[j]) == NULL)
01579             continue;
01580         newOrder[newOrderCount++] = p;
01581         ts->order[j] = NULL;
01582     }
01583 assert(newOrderCount == ts->orderCount);
01584 
01585 /*@+voidabstract@*/
01586     ts->order = _free(ts->order);
01587 /*@=voidabstract@*/
01588     ts->order = newOrder;
01589     ts->orderAlloced = ts->orderCount;
01590     orderList = _free(orderList);
01591 
01592 #ifdef  DYING   /* XXX now done at the CLI level just before rpmtsRun(). */
01593     rpmtsClean(ts);
01594 #endif
01595     freeBadDeps();
01596 
01597     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ORDER), 0);
01598 
01599     return 0;
01600 }
01601 /*@=bounds@*/
01602 
01603 int rpmtsCheck(rpmts ts)
01604 {
01605     uint_32 tscolor = rpmtsColor(ts);
01606     rpmdbMatchIterator mi = NULL;
01607     rpmtsi pi = NULL; rpmte p;
01608     int closeatexit = 0;
01609     int xx;
01610     int rc;
01611 
01612     (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01613 
01614     /* Do lazy, readonly, open of rpm database. */
01615     if (rpmtsGetRdb(ts) == NULL && ts->dbmode != -1) {
01616         if ((rc = rpmtsOpenDB(ts, ts->dbmode)) != 0)
01617             goto exit;
01618         closeatexit = 1;
01619     }
01620 
01621     ts->probs = rpmpsFree(ts->probs);
01622     ts->probs = rpmpsCreate();
01623 
01624     rpmalMakeIndex(ts->addedPackages);
01625 
01626     /*
01627      * Look at all of the added packages and make sure their dependencies
01628      * are satisfied.
01629      */
01630     pi = rpmtsiInit(ts);
01631     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01632         rpmds provides;
01633 
01634 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01635         rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s/%s 0x%x\n",
01636                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01637 /*@=nullpass@*/
01638         rc = checkPackageDeps(ts, rpmteNEVRA(p),
01639                         rpmteDS(p, RPMTAG_REQUIRENAME),
01640                         rpmteDS(p, RPMTAG_CONFLICTNAME),
01641                         NULL,
01642                         tscolor, 1);
01643         if (rc)
01644             goto exit;
01645 
01646         rc = 0;
01647         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01648         provides = rpmdsInit(provides);
01649         if (provides != NULL)
01650         while (rpmdsNext(provides) >= 0) {
01651             const char * Name;
01652 
01653             if ((Name = rpmdsN(provides)) == NULL)
01654                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01655 
01656             /* Adding: check provides key against conflicts matches. */
01657             if (!checkDependentConflicts(ts, Name))
01658                 /*@innercontinue@*/ continue;
01659             rc = 1;
01660             /*@innerbreak@*/ break;
01661         }
01662         if (rc)
01663             goto exit;
01664     }
01665     pi = rpmtsiFree(pi);
01666 
01667     /*
01668      * Look at the removed packages and make sure they aren't critical.
01669      */
01670     pi = rpmtsiInit(ts);
01671     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01672         rpmds provides;
01673         rpmfi fi;
01674 
01675 /*@-nullpass@*/ /* FIX: rpmts{A,O} can return null. */
01676         rpmMessage(RPMMESS_DEBUG, "========== --- %s %s/%s 0x%x\n",
01677                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01678 /*@=nullpass@*/
01679 
01680 #if defined(DYING) || defined(__LCLINT__)
01681         /* XXX all packages now have Provides: name = version-release */
01682         /* Erasing: check name against requiredby matches. */
01683         rc = checkDependentPackages(ts, rpmteN(p));
01684         if (rc)
01685                 goto exit;
01686 #endif
01687 
01688         rc = 0;
01689         provides = rpmteDS(p, RPMTAG_PROVIDENAME);
01690         provides = rpmdsInit(provides);
01691         if (provides != NULL)
01692         while (rpmdsNext(provides) >= 0) {
01693             const char * Name;
01694 
01695             if ((Name = rpmdsN(provides)) == NULL)
01696                 /*@innercontinue@*/ continue;   /* XXX can't happen */
01697 
01698             /* Erasing: check provides against requiredby matches. */
01699             if (!checkDependentPackages(ts, Name))
01700                 /*@innercontinue@*/ continue;
01701             rc = 1;
01702             /*@innerbreak@*/ break;
01703         }
01704         if (rc)
01705             goto exit;
01706 
01707         rc = 0;
01708         fi = rpmteFI(p, RPMTAG_BASENAMES);
01709         fi = rpmfiInit(fi, 0);
01710         while (rpmfiNext(fi) >= 0) {
01711             const char * fn = rpmfiFN(fi);
01712 
01713             /* Erasing: check filename against requiredby matches. */
01714             if (!checkDependentPackages(ts, fn))
01715                 /*@innercontinue@*/ continue;
01716             rc = 1;
01717             /*@innerbreak@*/ break;
01718         }
01719         if (rc)
01720             goto exit;
01721     }
01722     pi = rpmtsiFree(pi);
01723 
01724     rc = 0;
01725 
01726 exit:
01727     mi = rpmdbFreeIterator(mi);
01728     pi = rpmtsiFree(pi);
01729 
01730     (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_CHECK), 0);
01731 
01732     /*@-branchstate@*/
01733     if (closeatexit)
01734         xx = rpmtsCloseDB(ts);
01735     else if (_cacheDependsRC)
01736         xx = rpmdbCloseDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
01737     /*@=branchstate@*/
01738     return rc;
01739 }

Generated on Mon Sep 26 13:35:15 2005 for rpm by  doxygen 1.3.9.1