lib/depends.c

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

Generated on Tue Feb 19 22:26:56 2008 for rpm by  doxygen 1.5.1