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

lib/depends.c

Go to the documentation of this file.
00001 
00005 /*@-exportheadervar@*/
00006 /*@unused@*/ static int _depends_debug = 0;
00007 /*@=exportheadervar@*/
00008 
00009 #include "system.h"
00010 
00011 #include <rpmlib.h>
00012 
00013 #include "depends.h"
00014 #include "rpmdb.h"              /* XXX response cache needs dbiOpen et al. */
00015 
00016 #include "debug.h"
00017 
00018 /*@access dbiIndex@*/           /* XXX compared with NULL */
00019 /*@access dbiIndexSet@*/        /* XXX compared with NULL */
00020 /*@access Header@*/             /* XXX compared with NULL */
00021 /*@access FD_t@*/               /* XXX compared with NULL */
00022 /*@access rpmdb@*/              /* XXX compared with NULL */
00023 /*@access rpmdbMatchIterator@*/         /* XXX compared with NULL */
00024 /*@access rpmTransactionSet@*/
00025 /*@access rpmDependencyConflict@*/
00026 /*@access availableList@*/
00027 
00028 static int _cacheDependsRC = 1;
00029 
00030 int headerNVR(Header h, const char **np, const char **vp, const char **rp)
00031 {
00032     int type;
00033     int count;
00034 
00035     if (np) {
00036         if (!(headerGetEntry(h, RPMTAG_NAME, &type, (void **) np, &count)
00037             && type == RPM_STRING_TYPE && count == 1))
00038                 *np = NULL;
00039     }
00040     if (vp) {
00041         if (!(headerGetEntry(h, RPMTAG_VERSION, &type, (void **) vp, &count)
00042             && type == RPM_STRING_TYPE && count == 1))
00043                 *vp = NULL;
00044     }
00045     if (rp) {
00046         if (!(headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) rp, &count)
00047             && type == RPM_STRING_TYPE && count == 1))
00048                 *rp = NULL;
00049     }
00050     return 0;
00051 }
00052 
00061 static /*@only@*/ char * printDepend(const char * depend, const char * key,
00062                 const char * keyEVR, int keyFlags)
00063         /*@*/
00064 {
00065     char * tbuf, * t;
00066     size_t nb;
00067 
00068     nb = 0;
00069     if (depend) nb += strlen(depend) + 1;
00070     if (key)    nb += strlen(key);
00071     if (keyFlags & RPMSENSE_SENSEMASK) {
00072         if (nb) nb++;
00073         if (keyFlags & RPMSENSE_LESS)   nb++;
00074         if (keyFlags & RPMSENSE_GREATER) nb++;
00075         if (keyFlags & RPMSENSE_EQUAL)  nb++;
00076     }
00077     if (keyEVR && *keyEVR) {
00078         if (nb) nb++;
00079         nb += strlen(keyEVR);
00080     }
00081 
00082     t = tbuf = xmalloc(nb + 1);
00083     if (depend) {
00084         while(*depend != '\0')  *t++ = *depend++;
00085         *t++ = ' ';
00086     }
00087     if (key)
00088         while(*key != '\0')     *t++ = *key++;
00089     if (keyFlags & RPMSENSE_SENSEMASK) {
00090         if (t != tbuf)  *t++ = ' ';
00091         if (keyFlags & RPMSENSE_LESS)   *t++ = '<';
00092         if (keyFlags & RPMSENSE_GREATER) *t++ = '>';
00093         if (keyFlags & RPMSENSE_EQUAL)  *t++ = '=';
00094     }
00095     if (keyEVR && *keyEVR) {
00096         if (t != tbuf)  *t++ = ' ';
00097         while(*keyEVR != '\0')  *t++ = *keyEVR++;
00098     }
00099     *t = '\0';
00100     return tbuf;
00101 }
00102 
00103 #ifdef  UNUSED
00104 static /*@only@*/ const char *buildEVR(int_32 *e, const char *v, const char *r)
00105 {
00106     const char *pEVR;
00107     char *p;
00108 
00109     pEVR = p = xmalloc(21 + strlen(v) + 1 + strlen(r) + 1);
00110     *p = '\0';
00111     if (e) {
00112         sprintf(p, "%d:", *e);
00113         while (*p)
00114             p++;
00115     }
00116     (void) stpcpy( stpcpy( stpcpy(p, v) , "-") , r);
00117     return pEVR;
00118 }
00119 #endif
00120 
00121 struct orderListIndex {
00122     int alIndex;
00123     int orIndex;
00124 };
00125 
00130 static void alFreeIndex(availableList al)
00131         /*@modifies al @*/
00132 {
00133     if (al->index.size) {
00134         al->index.index = _free(al->index.index);
00135         al->index.size = 0;
00136     }
00137 }
00138 
00143 static void alCreate(availableList al)
00144         /*@modifies al @*/
00145 {
00146     al->alloced = al->delta;
00147     al->size = 0;
00148     al->list = xcalloc(al->alloced, sizeof(*al->list));
00149 
00150     al->index.index = NULL;
00151     al->index.size = 0;
00152 
00153     al->numDirs = 0;
00154     al->dirs = NULL;
00155 }
00156 
00161 static void alFree(availableList al)
00162         /*@modifies al @*/
00163 {
00164     HFD_t hfd = headerFreeData;
00165     struct availablePackage * p;
00166     rpmRelocation * r;
00167     int i;
00168 
00169     if ((p = al->list) != NULL)
00170     for (i = 0; i < al->size; i++, p++) {
00171 
00172         {   struct tsortInfo * tsi;
00173             while ((tsi = p->tsi.tsi_next) != NULL) {
00174                 p->tsi.tsi_next = tsi->tsi_next;
00175                 tsi->tsi_next = NULL;
00176                 tsi = _free(tsi);
00177             }
00178         }
00179 
00180         p->provides = hfd(p->provides, -1);
00181         p->providesEVR = hfd(p->providesEVR, -1);
00182         p->requires = hfd(p->requires, -1);
00183         p->requiresEVR = hfd(p->requiresEVR, -1);
00184         p->baseNames = hfd(p->baseNames, -1);
00185         p->h = headerFree(p->h);
00186 
00187         if (p->relocs) {
00188             for (r = p->relocs; (r->oldPath || r->newPath); r++) {
00189                 r->oldPath = _free(r->oldPath);
00190                 r->newPath = _free(r->newPath);
00191             }
00192             p->relocs = _free(p->relocs);
00193         }
00194         if (p->fd != NULL)
00195             p->fd = fdFree(p->fd, "alAddPackage (alFree)");
00196     }
00197 
00198     if (al->dirs != NULL)
00199     for (i = 0; i < al->numDirs; i++) {
00200         al->dirs[i].dirName = _free(al->dirs[i].dirName);
00201         al->dirs[i].files = _free(al->dirs[i].files);
00202     }
00203 
00204     al->dirs = _free(al->dirs);
00205     al->numDirs = 0;
00206     al->list = _free(al->list);
00207     al->alloced = 0;
00208     alFreeIndex(al);
00209 }
00210 
00217 static int dirInfoCompare(const void * one, const void * two)   /*@*/
00218 {
00219     const dirInfo a = (const dirInfo) one;
00220     const dirInfo b = (const dirInfo) two;
00221     int lenchk = a->dirNameLen - b->dirNameLen;
00222 
00223     if (lenchk)
00224         return lenchk;
00225 
00226     /* XXX FIXME: this might do "backward" strcmp for speed */
00227     return strcmp(a->dirName, b->dirName);
00228 }
00229 
00239 static /*@exposed@*/ struct availablePackage *
00240 alAddPackage(availableList al,
00241                 Header h, /*@null@*/ /*@dependent@*/ const void * key,
00242                 /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs)
00243         /*@modifies al, h @*/
00244 {
00245     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00246     HFD_t hfd = headerFreeData;
00247     rpmTagType dnt, bnt;
00248     struct availablePackage * p;
00249     rpmRelocation * r;
00250     int i;
00251     int_32 * dirIndexes;
00252     const char ** dirNames;
00253     int numDirs, dirNum;
00254     int * dirMapping;
00255     struct dirInfo_s dirNeedle;
00256     dirInfo dirMatch;
00257     int first, last, fileNum;
00258     int origNumDirs;
00259     int pkgNum;
00260     uint_32 multiLibMask = 0;
00261     uint_32 * fileFlags = NULL;
00262     uint_32 * pp = NULL;
00263 
00264     if (al->size == al->alloced) {
00265         al->alloced += al->delta;
00266         al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00267     }
00268 
00269     pkgNum = al->size++;
00270     p = al->list + pkgNum;
00271     p->h = headerLink(h);       /* XXX reference held by transaction set */
00272     p->depth = p->npreds = 0;
00273     memset(&p->tsi, 0, sizeof(p->tsi));
00274     p->multiLib = 0;    /* MULTILIB */
00275 
00276     (void) headerNVR(p->h, &p->name, &p->version, &p->release);
00277 
00278     /* XXX This should be added always so that packages look alike.
00279      * XXX However, there is logic in files.c/depends.c that checks for
00280      * XXX existence (rather than value) that will need to change as well.
00281      */
00282     if (hge(p->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
00283         multiLibMask = *pp;
00284 
00285     if (multiLibMask) {
00286         for (i = 0; i < pkgNum - 1; i++) {
00287             if (!strcmp (p->name, al->list[i].name)
00288                 && hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
00289                                   (void **) &pp, NULL)
00290                 && !rpmVersionCompare(p->h, al->list[i].h)
00291                 && *pp && !(*pp & multiLibMask))
00292                     p->multiLib = multiLibMask;
00293         }
00294     }
00295 
00296     if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL))
00297         p->epoch = NULL;
00298 
00299     if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides,
00300         &p->providesCount)) {
00301         p->providesCount = 0;
00302         p->provides = NULL;
00303         p->providesEVR = NULL;
00304         p->provideFlags = NULL;
00305     } else {
00306         if (!hge(h, RPMTAG_PROVIDEVERSION,
00307                         NULL, (void **) &p->providesEVR, NULL))
00308             p->providesEVR = NULL;
00309         if (!hge(h, RPMTAG_PROVIDEFLAGS,
00310                         NULL, (void **) &p->provideFlags, NULL))
00311             p->provideFlags = NULL;
00312     }
00313 
00314     if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires,
00315         &p->requiresCount)) {
00316         p->requiresCount = 0;
00317         p->requires = NULL;
00318         p->requiresEVR = NULL;
00319         p->requireFlags = NULL;
00320     } else {
00321         if (!hge(h, RPMTAG_REQUIREVERSION,
00322                         NULL, (void **) &p->requiresEVR, NULL))
00323             p->requiresEVR = NULL;
00324         if (!hge(h, RPMTAG_REQUIREFLAGS,
00325                         NULL, (void **) &p->requireFlags, NULL))
00326             p->requireFlags = NULL;
00327     }
00328 
00329     if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **)&p->baseNames, &p->filesCount))
00330     {
00331         p->filesCount = 0;
00332         p->baseNames = NULL;
00333     } else {
00334         (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
00335         (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00336         (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
00337 
00338         /* XXX FIXME: We ought to relocate the directory list here */
00339 
00340         dirMapping = alloca(sizeof(*dirMapping) * numDirs);
00341 
00342         /* allocated enough space for all the directories we could possible
00343            need to add */
00344         al->dirs = xrealloc(al->dirs, 
00345                             sizeof(*al->dirs) * (al->numDirs + numDirs));
00346         origNumDirs = al->numDirs;
00347 
00348         for (dirNum = 0; dirNum < numDirs; dirNum++) {
00349             dirNeedle.dirName = (char *) dirNames[dirNum];
00350             dirNeedle.dirNameLen = strlen(dirNames[dirNum]);
00351             dirMatch = bsearch(&dirNeedle, al->dirs, origNumDirs,
00352                                sizeof(dirNeedle), dirInfoCompare);
00353             if (dirMatch) {
00354                 dirMapping[dirNum] = dirMatch - al->dirs;
00355             } else {
00356                 dirMapping[dirNum] = al->numDirs;
00357                 al->dirs[al->numDirs].dirName = xstrdup(dirNames[dirNum]);
00358                 al->dirs[al->numDirs].dirNameLen = strlen(dirNames[dirNum]);
00359                 al->dirs[al->numDirs].files = NULL;
00360                 al->dirs[al->numDirs].numFiles = 0;
00361                 al->numDirs++;
00362             }
00363         }
00364 
00365         dirNames = hfd(dirNames, dnt);
00366 
00367         first = 0;
00368         while (first < p->filesCount) {
00369             last = first;
00370             while ((last + 1) < p->filesCount) {
00371                 if (dirIndexes[first] != dirIndexes[last + 1])
00372                     /*@innerbreak@*/ break;
00373                 last++;
00374             }
00375 
00376             dirMatch = al->dirs + dirMapping[dirIndexes[first]];
00377             dirMatch->files = xrealloc(dirMatch->files,
00378                 sizeof(*dirMatch->files) * 
00379                     (dirMatch->numFiles + last - first + 1));
00380             if (p->baseNames != NULL)   /* XXX can't happen */
00381             for (fileNum = first; fileNum <= last; fileNum++) {
00382                 dirMatch->files[dirMatch->numFiles].baseName =
00383                     p->baseNames[fileNum];
00384                 dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum;
00385                 dirMatch->files[dirMatch->numFiles].fileFlags =
00386                                 fileFlags[fileNum];
00387                 dirMatch->numFiles++;
00388             }
00389 
00390             first = last + 1;
00391         }
00392 
00393         if (origNumDirs + al->numDirs)
00394             qsort(al->dirs, al->numDirs, sizeof(dirNeedle), dirInfoCompare);
00395 
00396     }
00397 
00398     p->key = key;
00399     p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL);
00400 
00401     if (relocs) {
00402         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++)
00403             {};
00404         p->relocs = xmalloc((i + 1) * sizeof(*p->relocs));
00405 
00406         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
00407             p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
00408             p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
00409         }
00410         p->relocs[i].oldPath = NULL;
00411         p->relocs[i].newPath = NULL;
00412     } else {
00413         p->relocs = NULL;
00414     }
00415 
00416     alFreeIndex(al);
00417 
00418     return p;
00419 }
00420 
00427 static int indexcmp(const void * one, const void * two)         /*@*/
00428 {
00429     const struct availableIndexEntry * a = one;
00430     const struct availableIndexEntry * b = two;
00431     int lenchk = a->entryLen - b->entryLen;
00432 
00433     if (lenchk)
00434         return lenchk;
00435 
00436     return strcmp(a->entry, b->entry);
00437 }
00438 
00443 static void alMakeIndex(availableList al)
00444         /*@modifies al @*/
00445 {
00446     struct availableIndex * ai = &al->index;
00447     int i, j, k;
00448 
00449     if (ai->size || al->list == NULL) return;
00450 
00451     for (i = 0; i < al->size; i++) 
00452         ai->size += al->list[i].providesCount;
00453 
00454     if (ai->size) {
00455         ai->index = xcalloc(ai->size, sizeof(*ai->index));
00456 
00457         k = 0;
00458         for (i = 0; i < al->size; i++) {
00459             for (j = 0; j < al->list[i].providesCount; j++) {
00460 
00461                 /* If multilib install, skip non-multilib provides. */
00462                 if (al->list[i].multiLib &&
00463                     !isDependsMULTILIB(al->list[i].provideFlags[j])) {
00464                         ai->size--;
00465                         continue;
00466                 }
00467 
00468                 ai->index[k].package = al->list + i;
00469                 ai->index[k].entry = al->list[i].provides[j];
00470                 ai->index[k].entryLen = strlen(al->list[i].provides[j]);
00471                 ai->index[k].entryIx = j;
00472                 ai->index[k].type = IET_PROVIDES;
00473                 k++;
00474             }
00475         }
00476 
00477         qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00478     }
00479 }
00480 
00488 static void parseEVR(char * evr,
00489                 /*@exposed@*/ /*@out@*/ const char ** ep,
00490                 /*@exposed@*/ /*@out@*/ const char ** vp,
00491                 /*@exposed@*/ /*@out@*/ const char ** rp)
00492         /*@modifies *ep, *vp, *rp @*/
00493 {
00494     const char *epoch;
00495     const char *version;                /* assume only version is present */
00496     const char *release;
00497     char *s, *se;
00498 
00499     s = evr;
00500     while (*s && xisdigit(*s)) s++;     /* s points to epoch terminator */
00501     se = strrchr(s, '-');               /* se points to version terminator */
00502 
00503     if (*s == ':') {
00504         epoch = evr;
00505         *s++ = '\0';
00506         version = s;
00507         if (*epoch == '\0') epoch = "0";
00508     } else {
00509         epoch = NULL;   /* XXX disable epoch compare if missing */
00510         version = evr;
00511     }
00512     if (se) {
00513         *se++ = '\0';
00514         release = se;
00515     } else {
00516         release = NULL;
00517     }
00518 
00519     if (ep) *ep = epoch;
00520     if (vp) *vp = version;
00521     if (rp) *rp = release;
00522 }
00523 
00524 /*@observer@*/ const char *rpmNAME = PACKAGE;
00525 /*@observer@*/ const char *rpmEVR = VERSION;
00526 int rpmFLAGS = RPMSENSE_EQUAL;
00527 
00528 int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
00529         const char * BName, const char * BEVR, int BFlags)
00530 {
00531     const char *aDepend = printDepend(NULL, AName, AEVR, AFlags);
00532     const char *bDepend = printDepend(NULL, BName, BEVR, BFlags);
00533     char *aEVR, *bEVR;
00534     const char *aE, *aV, *aR, *bE, *bV, *bR;
00535     int result;
00536     int sense;
00537 
00538     /* Different names don't overlap. */
00539     if (strcmp(AName, BName)) {
00540         result = 0;
00541         goto exit;
00542     }
00543 
00544     /* Same name. If either A or B is an existence test, always overlap. */
00545     if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
00546         result = 1;
00547         goto exit;
00548     }
00549 
00550     /* If either EVR is non-existent or empty, always overlap. */
00551     if (!(AEVR && *AEVR && BEVR && *BEVR)) {
00552         result = 1;
00553         goto exit;
00554     }
00555 
00556     /* Both AEVR and BEVR exist. */
00557     aEVR = xstrdup(AEVR);
00558     parseEVR(aEVR, &aE, &aV, &aR);
00559     bEVR = xstrdup(BEVR);
00560     parseEVR(bEVR, &bE, &bV, &bR);
00561 
00562     /* Compare {A,B} [epoch:]version[-release] */
00563     sense = 0;
00564     if (aE && *aE && bE && *bE)
00565         sense = rpmvercmp(aE, bE);
00566     else if (aE && *aE && atol(aE) > 0) {
00567         /* XXX legacy epoch-less requires/conflicts compatibility */
00568         rpmMessage(RPMMESS_DEBUG, _("the \"B\" dependency needs an epoch (assuming same as \"A\")\n\tA %s\tB %s\n"),
00569                 aDepend, bDepend);
00570         sense = 0;
00571     } else if (bE && *bE && atol(bE) > 0)
00572         sense = -1;
00573 
00574     if (sense == 0) {
00575         sense = rpmvercmp(aV, bV);
00576         if (sense == 0 && aR && *aR && bR && *bR) {
00577             sense = rpmvercmp(aR, bR);
00578         }
00579     }
00580     aEVR = _free(aEVR);
00581     bEVR = _free(bEVR);
00582 
00583     /* Detect overlap of {A,B} range. */
00584     result = 0;
00585     if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
00586         result = 1;
00587     } else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
00588         result = 1;
00589     } else if (sense == 0 &&
00590         (((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
00591          ((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
00592          ((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
00593         result = 1;
00594     }
00595 
00596 exit:
00597     rpmMessage(RPMMESS_DEBUG, _("  %s    A %s\tB %s\n"),
00598         (result ? _("YES") : _("NO ")), aDepend, bDepend);
00599     aDepend = _free(aDepend);
00600     bDepend = _free(bDepend);
00601     return result;
00602 }
00603 
00604 /*@-typeuse@*/
00605 typedef int (*dbrecMatch_t) (Header h, const char *reqName, const char * reqEVR, int reqFlags);
00606 /*@=typeuse@*/
00607 
00608 static int rangeMatchesDepFlags (Header h,
00609                 const char * reqName, const char * reqEVR, int reqFlags)
00610         /*@*/
00611 {
00612     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00613     HFD_t hfd = headerFreeData;
00614     rpmTagType pnt, pvt;
00615     const char ** provides;
00616     const char ** providesEVR;
00617     int_32 * provideFlags;
00618     int providesCount;
00619     int result;
00620     int i;
00621 
00622     if (!(reqFlags & RPMSENSE_SENSEMASK) || !reqEVR || !strlen(reqEVR))
00623         return 1;
00624 
00625     /* Get provides information from header */
00626     /*
00627      * Rpm prior to 3.0.3 does not have versioned provides.
00628      * If no provides version info is available, match any requires.
00629      */
00630     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt,
00631                 (void **) &providesEVR, &providesCount))
00632         return 1;
00633 
00634     (void) hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00635 
00636     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00637     {
00638         providesEVR = hfd(providesEVR, pvt);
00639         return 0;       /* XXX should never happen */
00640     }
00641 
00642     result = 0;
00643     for (i = 0; i < providesCount; i++) {
00644 
00645         /* Filter out provides that came along for the ride. */
00646         if (strcmp(provides[i], reqName))
00647             continue;
00648 
00649         result = rpmRangesOverlap(provides[i], providesEVR[i], provideFlags[i],
00650                         reqName, reqEVR, reqFlags);
00651 
00652         /* If this provide matches the require, we're done. */
00653         if (result)
00654             break;
00655     }
00656 
00657     provides = hfd(provides, pnt);
00658     providesEVR = hfd(providesEVR, pvt);
00659 
00660     return result;
00661 }
00662 
00663 int headerMatchesDepFlags(Header h,
00664                 const char * reqName, const char * reqEVR, int reqFlags)
00665 {
00666     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00667     const char *name, *version, *release;
00668     int_32 * epoch;
00669     const char *pkgEVR;
00670     char *p;
00671     int pkgFlags = RPMSENSE_EQUAL;
00672 
00673     if (!((reqFlags & RPMSENSE_SENSEMASK) && reqEVR && *reqEVR))
00674         return 1;
00675 
00676     /* Get package information from header */
00677     (void) headerNVR(h, &name, &version, &release);
00678 
00679     pkgEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00680     *p = '\0';
00681     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00682         sprintf(p, "%d:", *epoch);
00683         while (*p != '\0')
00684             p++;
00685     }
00686     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00687 
00688     return rpmRangesOverlap(name, pkgEVR, pkgFlags, reqName, reqEVR, reqFlags);
00689 }
00690 
00691 rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir)
00692 {
00693     rpmTransactionSet ts;
00694     int rootLen;
00695 
00696     if (!rootDir) rootDir = "";
00697 
00698     ts = xcalloc(1, sizeof(*ts));
00699     ts->filesystemCount = 0;
00700     ts->filesystems = NULL;
00701     ts->di = NULL;
00702     /*@-assignexpose@*/
00703     ts->rpmdb = rpmdb;
00704     /*@=assignexpose@*/
00705     ts->scriptFd = NULL;
00706     ts->id = 0;
00707     ts->delta = 5;
00708 
00709     ts->numRemovedPackages = 0;
00710     ts->allocedRemovedPackages = ts->delta;
00711     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
00712                         sizeof(*ts->removedPackages));
00713 
00714     /* This canonicalizes the root */
00715     rootLen = strlen(rootDir);
00716     if (!(rootLen && rootDir[rootLen - 1] == '/')) {
00717         char * t;
00718 
00719         t = alloca(rootLen + 2);
00720         *t = '\0';
00721         (void) stpcpy( stpcpy(t, rootDir), "/");
00722         rootDir = t;
00723     }
00724 
00725     ts->rootDir = xstrdup(rootDir);
00726     ts->currDir = NULL;
00727     ts->chrootDone = 0;
00728 
00729     ts->addedPackages.delta = ts->delta;
00730     alCreate(&ts->addedPackages);
00731     ts->availablePackages.delta = ts->delta;
00732     alCreate(&ts->availablePackages);
00733 
00734     ts->orderAlloced = ts->delta;
00735     ts->orderCount = 0;
00736     ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order));
00737 
00738     return ts;
00739 }
00740 
00747 static int intcmp(const void * a, const void * b)       /*@*/
00748 {
00749     const int * aptr = a;
00750     const int * bptr = b;
00751     int rc = (*aptr - *bptr);
00752     return rc;
00753 }
00754 
00762 static int removePackage(rpmTransactionSet ts, int dboffset, int depends)
00763         /*@modifies ts @*/
00764 {
00765 
00766     /* Filter out duplicate erasures. */
00767     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00768         if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00769                         sizeof(int), intcmp) != NULL)
00770             return 0;
00771     }
00772 
00773     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00774         ts->allocedRemovedPackages += ts->delta;
00775         ts->removedPackages = xrealloc(ts->removedPackages,
00776                 sizeof(int *) * ts->allocedRemovedPackages);
00777     }
00778 
00779     if (ts->removedPackages != NULL) {  /* XXX can't happen. */
00780         ts->removedPackages[ts->numRemovedPackages++] = dboffset;
00781         qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp);
00782     }
00783 
00784     if (ts->orderCount == ts->orderAlloced) {
00785         ts->orderAlloced += ts->delta;
00786         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00787     }
00788 
00789     ts->order[ts->orderCount].type = TR_REMOVED;
00790     ts->order[ts->orderCount].u.removed.dboffset = dboffset;
00791     ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends;
00792 
00793     return 0;
00794 }
00795 
00796 int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
00797                         const void * key, int upgrade, rpmRelocation * relocs)
00798 {
00799     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00800     HFD_t hfd = headerFreeData;
00801     rpmTagType ont, ovt;
00802     /* this is an install followed by uninstalls */
00803     const char * name;
00804     int count;
00805     const char ** obsoletes;
00806     int alNum;
00807 
00808     /*
00809      * FIXME: handling upgrades like this is *almost* okay. It doesn't
00810      * check to make sure we're upgrading to a newer version, and it
00811      * makes it difficult to generate a return code based on the number of
00812      * packages which failed.
00813      */
00814     if (ts->orderCount == ts->orderAlloced) {
00815         ts->orderAlloced += ts->delta;
00816         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00817     }
00818     ts->order[ts->orderCount].type = TR_ADDED;
00819     if (ts->addedPackages.list == NULL)
00820         return 0;
00821 
00822     alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
00823                 ts->addedPackages.list;
00824     ts->order[ts->orderCount++].u.addedIndex = alNum;
00825 
00826     if (!upgrade || ts->rpmdb == NULL)
00827         return 0;
00828 
00829     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00830     if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00831         return 0;
00832 
00833     (void) headerNVR(h, &name, NULL, NULL);
00834 
00835     {   rpmdbMatchIterator mi;
00836         Header h2;
00837 
00838         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
00839         while((h2 = rpmdbNextIterator(mi)) != NULL) {
00840             if (rpmVersionCompare(h, h2))
00841                 (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00842             else {
00843                 uint_32 *p, multiLibMask = 0, oldmultiLibMask = 0;
00844 
00845                 if (hge(h2, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00846                     oldmultiLibMask = *p;
00847                 if (hge(h, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00848                     multiLibMask = *p;
00849                 if (oldmultiLibMask && multiLibMask
00850                     && !(oldmultiLibMask & multiLibMask)) {
00851                     ts->addedPackages.list[alNum].multiLib = multiLibMask;
00852                 }
00853             }
00854         }
00855         mi = rpmdbFreeIterator(mi);
00856     }
00857 
00858     if (hge(h, RPMTAG_OBSOLETENAME, &ont, (void **) &obsoletes, &count)) {
00859         const char ** obsoletesEVR;
00860         int_32 * obsoletesFlags;
00861         int j;
00862 
00863         (void) hge(h, RPMTAG_OBSOLETEVERSION, &ovt, (void **) &obsoletesEVR,
00864                         NULL);
00865         (void) hge(h, RPMTAG_OBSOLETEFLAGS, NULL, (void **) &obsoletesFlags,
00866                         NULL);
00867 
00868         for (j = 0; j < count; j++) {
00869 
00870             /* XXX avoid self-obsoleting packages. */
00871             if (!strcmp(name, obsoletes[j]))
00872                 continue;
00873 
00874           { rpmdbMatchIterator mi;
00875             Header h2;
00876 
00877             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, obsoletes[j], 0);
00878 
00879             (void) rpmdbPruneIterator(mi,
00880                 ts->removedPackages, ts->numRemovedPackages, 1);
00881 
00882             while((h2 = rpmdbNextIterator(mi)) != NULL) {
00883                 /*
00884                  * Rpm prior to 3.0.3 does not have versioned obsoletes.
00885                  * If no obsoletes version info is available, match all names.
00886                  */
00887                 if (obsoletesEVR == NULL ||
00888                     headerMatchesDepFlags(h2,
00889                         obsoletes[j], obsoletesEVR[j], obsoletesFlags[j]))
00890                 {
00891                     (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00892                 }
00893             }
00894             mi = rpmdbFreeIterator(mi);
00895           }
00896         }
00897 
00898         obsoletesEVR = hfd(obsoletesEVR, ovt);
00899         obsoletes = hfd(obsoletes, ont);
00900     }
00901 
00902     return 0;
00903 }
00904 
00905 void rpmtransAvailablePackage(rpmTransactionSet ts, Header h, const void * key)
00906 {
00907     struct availablePackage * al;
00908     al = alAddPackage(&ts->availablePackages, h, key, NULL, NULL);
00909 }
00910 
00911 int rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
00912 {
00913     return removePackage(ts, dboffset, -1);
00914 }
00915 
00916 rpmTransactionSet rpmtransFree(rpmTransactionSet ts)
00917 {
00918     if (ts) {
00919         alFree(&ts->addedPackages);
00920         alFree(&ts->availablePackages);
00921         ts->di = _free(ts->di);
00922         ts->removedPackages = _free(ts->removedPackages);
00923         ts->order = _free(ts->order);
00924         if (ts->scriptFd != NULL)
00925             ts->scriptFd =
00926                 fdFree(ts->scriptFd, "rpmtransSetScriptFd (rpmtransFree");
00927         ts->rootDir = _free(ts->rootDir);
00928         ts->currDir = _free(ts->currDir);
00929 
00930         ts = _free(ts);
00931     }
00932     return NULL;
00933 }
00934 
00935 rpmDependencyConflict rpmdepFreeConflicts(rpmDependencyConflict conflicts,
00936                 int numConflicts)
00937 {
00938     int i;
00939 
00940     if (conflicts)
00941     for (i = 0; i < numConflicts; i++) {
00942         conflicts[i].byHeader = headerFree(conflicts[i].byHeader);
00943         conflicts[i].byName = _free(conflicts[i].byName);
00944         conflicts[i].byVersion = _free(conflicts[i].byVersion);
00945         conflicts[i].byRelease = _free(conflicts[i].byRelease);
00946         conflicts[i].needsName = _free(conflicts[i].needsName);
00947         conflicts[i].needsVersion = _free(conflicts[i].needsVersion);
00948         conflicts[i].suggestedPackages = _free(conflicts[i].suggestedPackages);
00949     }
00950 
00951     return (conflicts = _free(conflicts));
00952 }
00953 
00961 static /*@only@*/ /*@null@*/ struct availablePackage **
00962 alAllFileSatisfiesDepend(const availableList al,
00963                 const char * keyType, const char * fileName)
00964         /*@*/
00965 {
00966     int i, found;
00967     const char * dirName;
00968     const char * baseName;
00969     struct dirInfo_s dirNeedle;
00970     dirInfo dirMatch;
00971     struct availablePackage ** ret;
00972 
00973     /* Solaris 2.6 bsearch sucks down on this. */
00974     if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00975         return NULL;
00976 
00977     {   char * t;
00978         dirName = t = xstrdup(fileName);
00979         if ((t = strrchr(t, '/')) != NULL) {
00980             t++;                /* leave the trailing '/' */
00981             *t = '\0';
00982         }
00983     }
00984 
00985     dirNeedle.dirName = (char *) dirName;
00986     dirNeedle.dirNameLen = strlen(dirName);
00987     dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs,
00988                        sizeof(dirNeedle), dirInfoCompare);
00989     if (dirMatch == NULL) {
00990         dirName = _free(dirName);
00991         return NULL;
00992     }
00993 
00994     /* rewind to the first match */
00995     while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, &dirNeedle) == 0)
00996         dirMatch--;
00997 
00998     /*@-nullptrarith@*/         /* FIX: fileName NULL ??? */
00999     baseName = strrchr(fileName, '/') + 1;
01000     /*@=nullptrarith@*/
01001 
01002     for (found = 0, ret = NULL;
01003          dirMatch <= al->dirs + al->numDirs &&
01004                 dirInfoCompare(dirMatch, &dirNeedle) == 0;
01005          dirMatch++)
01006     {
01007         /* XXX FIXME: these file lists should be sorted and bsearched */
01008         for (i = 0; i < dirMatch->numFiles; i++) {
01009             if (dirMatch->files[i].baseName == NULL ||
01010                         strcmp(dirMatch->files[i].baseName, baseName))
01011                 continue;
01012 
01013             /*
01014              * If a file dependency would be satisfied by a file
01015              * we are not going to install, skip it.
01016              */
01017             if (al->list[dirMatch->files[i].pkgNum].multiLib &&
01018                         !isFileMULTILIB(dirMatch->files[i].fileFlags))
01019                 continue;
01020 
01021             if (keyType)
01022                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
01023                         keyType, fileName);
01024 
01025             ret = xrealloc(ret, (found+2) * sizeof(*ret));
01026             if (ret)    /* can't happen */
01027                 ret[found++] = al->list + dirMatch->files[i].pkgNum;
01028             /*@innerbreak@*/ break;
01029         }
01030     }
01031 
01032     dirName = _free(dirName);
01033     /*@-mods@*/         /* FIX: al->list might be modified. */
01034     if (ret)
01035         ret[found] = NULL;
01036     /*@=mods@*/
01037     return ret;
01038 }
01039 
01040 #ifdef  DYING
01041 
01048 /*@unused@*/ static /*@dependent@*/ /*@null@*/ struct availablePackage *
01049 alFileSatisfiesDepend(const availableList al,
01050                 const char * keyType, const char * fileName)
01051         /*@*/
01052 {
01053     struct availablePackage * ret;
01054     struct availablePackage ** tmp =
01055                 alAllFileSatisfiesDepend(al, keyType, fileName);
01056 
01057     if (tmp) {
01058         ret = tmp[0];
01059         tmp = _free(tmp);
01060         return ret;
01061     }
01062     return NULL;
01063 }
01064 #endif  /* DYING */
01065 
01076 static /*@only@*/ /*@null@*/ struct availablePackage **
01077 alAllSatisfiesDepend(const availableList al,
01078                 const char * keyType, const char * keyDepend,
01079                 const char * keyName, const char * keyEVR, int keyFlags)
01080         /*@*/
01081 {
01082     struct availableIndexEntry needle, * match;
01083     struct availablePackage * p, ** ret = NULL;
01084     int i, rc, found;
01085 
01086     if (*keyName == '/') {
01087         ret = alAllFileSatisfiesDepend(al, keyType, keyName);
01088         /* XXX Provides: /path was broken with added packages (#52183). */
01089         if (ret != NULL && *ret != NULL)
01090             return ret;
01091     }
01092 
01093     if (!al->index.size || al->index.index == NULL) return NULL;
01094 
01095     needle.entry = keyName;
01096     needle.entryLen = strlen(keyName);
01097     match = bsearch(&needle, al->index.index, al->index.size,
01098                     sizeof(*al->index.index), indexcmp);
01099 
01100     if (match == NULL) return NULL;
01101 
01102     /* rewind to the first match */
01103     while (match > al->index.index && indexcmp(match-1, &needle) == 0)
01104         match--;
01105 
01106     for (ret = NULL, found = 0;
01107          match <= al->index.index + al->index.size &&
01108                 indexcmp(match, &needle) == 0;
01109          match++)
01110     {
01111 
01112         p = match->package;
01113         rc = 0;
01114         switch (match->type) {
01115         case IET_PROVIDES:
01116             i = match->entryIx;
01117             {   const char * proEVR;
01118                 int proFlags;
01119 
01120                 proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
01121                 proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
01122                 rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
01123                                 keyName, keyEVR, keyFlags);
01124                 if (rc)
01125                     /*@innerbreak@*/ break;
01126             }
01127             if (keyType && keyDepend && rc)
01128                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
01129                                 keyType, keyDepend+2);
01130             break;
01131         }
01132 
01133         if (rc) {
01134             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
01135             if (ret)    /* can't happen */
01136                 ret[found++] = p;
01137         }
01138     }
01139 
01140     if (ret)
01141         ret[found] = NULL;
01142 
01143     return ret;
01144 }
01145 
01157 static inline /*@only@*/ /*@null@*/ struct availablePackage *
01158 alSatisfiesDepend(const availableList al,
01159                 const char * keyType, const char * keyDepend,
01160                 const char * keyName, const char * keyEVR, int keyFlags)
01161         /*@*/
01162 {
01163     struct availablePackage * ret;
01164     struct availablePackage ** tmp =
01165         alAllSatisfiesDepend(al, keyType, keyDepend, keyName, keyEVR, keyFlags);
01166 
01167     if (tmp) {
01168         ret = tmp[0];
01169         tmp = _free(tmp);
01170         return ret;
01171     }
01172     return NULL;
01173  }
01174 
01187 static int unsatisfiedDepend(rpmTransactionSet ts,
01188                 const char * keyType, const char * keyDepend,
01189                 const char * keyName, const char * keyEVR, int keyFlags,
01190                 /*@null@*/ /*@out@*/ struct availablePackage *** suggestion)
01191         /*@modifies ts, *suggestion @*/
01192 {
01193     rpmdbMatchIterator mi;
01194     Header h;
01195     int rc = 0; /* assume dependency is satisfied */
01196 
01197     if (suggestion) *suggestion = NULL;
01198 
01199     /*
01200      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
01201      */
01202     if (_cacheDependsRC) {
01203         dbiIndex dbi;
01204         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01205         if (dbi == NULL)
01206             _cacheDependsRC = 0;
01207         else {
01208             DBC * dbcursor = NULL;
01209             size_t keylen = strlen(keyDepend);
01210             void * datap = NULL;
01211             size_t datalen = 0;
01212             int xx;
01213             xx = dbiCopen(dbi, &dbcursor, 0);
01214             /*@-mods@*/         /* FIX: keyDepends mod undocumented. */
01215             xx = dbiGet(dbi, dbcursor, (void **)&keyDepend, &keylen, &datap, &datalen, 0);
01216             /*@=mods@*/
01217             if (xx == 0 && datap && datalen == 4) {
01218                 memcpy(&rc, datap, datalen);
01219                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s %-s (cached)\n"),
01220                         keyType, keyDepend, (rc ? _("NO ") : _("YES")));
01221                 xx = dbiCclose(dbi, NULL, 0);
01222 
01223                 if (suggestion && rc == 1)
01224                     *suggestion = alAllSatisfiesDepend(&ts->availablePackages,
01225                                 NULL, NULL, keyName, keyEVR, keyFlags);
01226 
01227                 return rc;
01228             }
01229             xx = dbiCclose(dbi, dbcursor, 0);
01230         }
01231     }
01232 
01233 #ifdef  DYING
01234   { static /*@observer@*/ const char noProvidesString[] = "nada";
01235     static /*@observer@*/ const char * rcProvidesString = noProvidesString;
01236     const char * start;
01237     int i;
01238 
01239     if (rcProvidesString == noProvidesString)
01240         rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
01241 
01242     if (rcProvidesString != NULL && !(keyFlags & RPMSENSE_SENSEMASK)) {
01243         i = strlen(keyName);
01244         /*@-observertrans -mayaliasunique@*/
01245         while ((start = strstr(rcProvidesString, keyName))) {
01246         /*@=observertrans =mayaliasunique@*/
01247             if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
01248                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmrc provides)\n"),
01249                         keyType, keyDepend+2);
01250                 goto exit;
01251             }
01252             rcProvidesString = start + 1;
01253         }
01254     }
01255   }
01256 #endif
01257 
01258     /*
01259      * New features in rpm packaging implicitly add versioned dependencies
01260      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
01261      * Check those dependencies now.
01262      */
01263     if (!strncmp(keyName, "rpmlib(", sizeof("rpmlib(")-1)) {
01264         if (rpmCheckRpmlibProvides(keyName, keyEVR, keyFlags)) {
01265             rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmlib provides)\n"),
01266                         keyType, keyDepend+2);
01267             goto exit;
01268         }
01269         goto unsatisfied;
01270     }
01271 
01272     if (alSatisfiesDepend(&ts->addedPackages, keyType, keyDepend,
01273                 keyName, keyEVR, keyFlags))
01274     {
01275         goto exit;
01276     }
01277 
01278     /* XXX only the installer does not have the database open here. */
01279     if (ts->rpmdb != NULL) {
01280         if (*keyName == '/') {
01281             /* keyFlags better be 0! */
01282 
01283             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_BASENAMES, keyName, 0);
01284 
01285             (void) rpmdbPruneIterator(mi,
01286                         ts->removedPackages, ts->numRemovedPackages, 1);
01287 
01288             while ((h = rpmdbNextIterator(mi)) != NULL) {
01289                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db files)\n"),
01290                         keyType, keyDepend+2);
01291                 mi = rpmdbFreeIterator(mi);
01292                 goto exit;
01293             }
01294             mi = rpmdbFreeIterator(mi);
01295         }
01296 
01297         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_PROVIDENAME, keyName, 0);
01298         (void) rpmdbPruneIterator(mi,
01299                         ts->removedPackages, ts->numRemovedPackages, 1);
01300         while ((h = rpmdbNextIterator(mi)) != NULL) {
01301             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01302                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db provides)\n"),
01303                         keyType, keyDepend+2);
01304                 mi = rpmdbFreeIterator(mi);
01305                 goto exit;
01306             }
01307         }
01308         mi = rpmdbFreeIterator(mi);
01309 
01310 #ifndef DYING
01311         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, keyName, 0);
01312         (void) rpmdbPruneIterator(mi,
01313                         ts->removedPackages, ts->numRemovedPackages, 1);
01314         while ((h = rpmdbNextIterator(mi)) != NULL) {
01315             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01316                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db package)\n"),
01317                         keyType, keyDepend+2);
01318                 mi = rpmdbFreeIterator(mi);
01319                 goto exit;
01320             }
01321         }
01322         mi = rpmdbFreeIterator(mi);
01323 #endif
01324 
01325     }
01326 
01327     if (suggestion)
01328         *suggestion = alAllSatisfiesDepend(&ts->availablePackages, NULL, NULL,
01329                                 keyName, keyEVR, keyFlags);
01330 
01331 unsatisfied:
01332     rpmMessage(RPMMESS_DEBUG, _("%s: %-45s NO\n"), keyType, keyDepend+2);
01333     rc = 1;     /* dependency is unsatisfied */
01334 
01335 exit:
01336     /*
01337      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01338      */
01339     if (_cacheDependsRC) {
01340         dbiIndex dbi;
01341         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01342         if (dbi == NULL) {
01343             _cacheDependsRC = 0;
01344         } else {
01345             DBC * dbcursor = NULL;
01346             int xx;
01347             xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
01348             xx = dbiPut(dbi, dbcursor, keyDepend, strlen(keyDepend), &rc, sizeof(rc), 0);
01349             if (xx)
01350                 _cacheDependsRC = 0;
01351 #if 0   /* XXX NOISY */
01352             else
01353                 rpmMessage(RPMMESS_DEBUG, _("%s: (%s, %s) added to Depends cache.\n"), keyType, keyDepend, (rc ? _("NO ") : _("YES")));
01354 #endif
01355             xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
01356         }
01357     }
01358     return rc;
01359 }
01360 
01370 static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp,
01371                 Header h, const char * keyName, uint_32 multiLib)
01372         /*@modifies ts, h, psp */
01373 {
01374     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01375     HFD_t hfd = headerFreeData;
01376     rpmTagType rnt, rvt;
01377     rpmTagType cnt, cvt;
01378     const char * name, * version, * release;
01379     const char ** requires;
01380     const char ** requiresEVR = NULL;
01381     int_32 * requireFlags = NULL;
01382     int requiresCount = 0;
01383     const char ** conflicts;
01384     const char ** conflictsEVR = NULL;
01385     int_32 * conflictFlags = NULL;
01386     int conflictsCount = 0;
01387     rpmTagType type;
01388     int i, rc;
01389     int ourrc = 0;
01390     struct availablePackage ** suggestion;
01391 
01392     (void) headerNVR(h, &name, &version, &release);
01393 
01394     if (!hge(h, RPMTAG_REQUIRENAME, &rnt, (void **) &requires, &requiresCount))
01395     {
01396         requiresCount = 0;
01397         rvt = RPM_STRING_ARRAY_TYPE;
01398     } else {
01399         (void)hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **) &requireFlags, NULL);
01400         (void)hge(h, RPMTAG_REQUIREVERSION, &rvt, (void **) &requiresEVR, NULL);
01401     }
01402 
01403     for (i = 0; i < requiresCount && !ourrc; i++) {
01404         const char * keyDepend;
01405 
01406         /* Filter out requires that came along for the ride. */
01407         if (keyName && strcmp(keyName, requires[i]))
01408             continue;
01409 
01410         /* If this requirement comes from the core package only, not libraries,
01411            then if we're installing the libraries only, don't count it in. */
01412         if (multiLib && !isDependsMULTILIB(requireFlags[i]))
01413             continue;
01414 
01415         keyDepend = printDepend("R",
01416                 requires[i], requiresEVR[i], requireFlags[i]);
01417 
01418         rc = unsatisfiedDepend(ts, " Requires", keyDepend,
01419                 requires[i], requiresEVR[i], requireFlags[i], &suggestion);
01420 
01421         switch (rc) {
01422         case 0:         /* requirements are satisfied. */
01423             break;
01424         case 1:         /* requirements are not satisfied. */
01425             rpmMessage(RPMMESS_DEBUG, _("package %s-%s-%s require not satisfied: %s\n"),
01426                     name, version, release, keyDepend+2);
01427 
01428             if (psp->num == psp->alloced) {
01429                 psp->alloced += 5;
01430                 psp->problems = xrealloc(psp->problems, sizeof(*psp->problems) *
01431                             psp->alloced);
01432             }
01433 
01434             {   rpmDependencyConflict pp = psp->problems + psp->num;
01435                 pp->byHeader = headerLink(h);
01436                 pp->byName = xstrdup(name);
01437                 pp->byVersion = xstrdup(version);
01438                 pp->byRelease = xstrdup(release);
01439                 pp->needsName = xstrdup(requires[i]);
01440                 pp->needsVersion = xstrdup(requiresEVR[i]);
01441                 pp->needsFlags = requireFlags[i];
01442                 pp->sense = RPMDEP_SENSE_REQUIRES;
01443 
01444                 if (suggestion) {
01445                     int j;
01446                     for (j = 0; suggestion[j]; j++)
01447                         {};
01448                     pp->suggestedPackages =
01449                         xmalloc( (j + 1) * sizeof(*pp->suggestedPackages) );
01450                     for (j = 0; suggestion[j]; j++)
01451                         pp->suggestedPackages[j] = suggestion[j]->key;
01452                     pp->suggestedPackages[j] = NULL;
01453                 } else {
01454                     pp->suggestedPackages = NULL;
01455                 }
01456             }
01457 
01458             psp->num++;
01459             break;
01460         case 2:         /* something went wrong! */
01461         default:
01462             ourrc = 1;
01463             break;
01464         }
01465         keyDepend = _free(keyDepend);
01466     }
01467 
01468     if (requiresCount) {
01469         requiresEVR = hfd(requiresEVR, rvt);
01470         requires = hfd(requires, rnt);
01471     }
01472 
01473     if (!hge(h, RPMTAG_CONFLICTNAME, &cnt, (void **)&conflicts, &conflictsCount))
01474     {
01475         conflictsCount = 0;
01476         cvt = RPM_STRING_ARRAY_TYPE;
01477     } else {
01478         (void) hge(h, RPMTAG_CONFLICTFLAGS, &type,
01479                 (void **) &conflictFlags, &conflictsCount);
01480         (void) hge(h, RPMTAG_CONFLICTVERSION, &cvt,
01481                 (void **) &conflictsEVR, &conflictsCount);
01482     }
01483 
01484     for (i = 0; i < conflictsCount && !ourrc; i++) {
01485         const char * keyDepend;
01486 
01487         /* Filter out conflicts that came along for the ride. */
01488         if (keyName && strcmp(keyName, conflicts[i]))
01489             continue;
01490 
01491         /* If this requirement comes from the core package only, not libraries,
01492            then if we're installing the libraries only, don't count it in. */
01493         if (multiLib && !isDependsMULTILIB(conflictFlags[i]))
01494             continue;
01495 
01496         keyDepend = printDepend("C", conflicts[i], conflictsEVR[i], conflictFlags[i]);
01497 
01498         rc = unsatisfiedDepend(ts, "Conflicts", keyDepend,
01499                 conflicts[i], conflictsEVR[i], conflictFlags[i], NULL);
01500 
01501         /* 1 == unsatisfied, 0 == satsisfied */
01502         switch (rc) {
01503         case 0:         /* conflicts exist. */
01504             rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"),
01505                     name, keyDepend+2);
01506 
01507             if (psp->num == psp->alloced) {
01508                 psp->alloced += 5;
01509                 psp->problems = xrealloc(psp->problems,
01510                                         sizeof(*psp->problems) * psp->alloced);
01511             }
01512 
01513             {   rpmDependencyConflict pp = psp->problems + psp->num;
01514                 pp->byHeader = headerLink(h);
01515                 pp->byName = xstrdup(name);
01516                 pp->byVersion = xstrdup(version);
01517                 pp->byRelease = xstrdup(release);
01518                 pp->needsName = xstrdup(conflicts[i]);
01519                 pp->needsVersion = xstrdup(conflictsEVR[i]);
01520                 pp->needsFlags = conflictFlags[i];
01521                 pp->sense = RPMDEP_SENSE_CONFLICTS;
01522                 pp->suggestedPackages = NULL;
01523             }
01524 
01525             psp->num++;
01526             break;
01527         case 1:         /* conflicts don't exist. */
01528             break;
01529         case 2:         /* something went wrong! */
01530         default:
01531             ourrc = 1;
01532             break;
01533         }
01534         keyDepend = _free(keyDepend);
01535     }
01536 
01537     if (conflictsCount) {
01538         conflictsEVR = hfd(conflictsEVR, cvt);
01539         conflicts = hfd(conflicts, cnt);
01540     }
01541 
01542     return ourrc;
01543 }
01544 
01555 static int checkPackageSet(rpmTransactionSet ts, problemsSet psp,
01556                 const char * key, /*@only@*/ /*@null@*/ rpmdbMatchIterator mi)
01557         /*@modifies ts, mi, psp @*/
01558 {
01559     Header h;
01560     int rc = 0;
01561 
01562     (void) rpmdbPruneIterator(mi,
01563                 ts->removedPackages, ts->numRemovedPackages, 1);
01564     while ((h = rpmdbNextIterator(mi)) != NULL) {
01565         if (checkPackageDeps(ts, psp, h, key, 0)) {
01566             rc = 1;
01567             break;
01568         }
01569     }
01570     mi = rpmdbFreeIterator(mi);
01571 
01572     return rc;
01573 }
01574 
01582 static int checkDependentPackages(rpmTransactionSet ts,
01583                         problemsSet psp, const char * key)
01584         /*@modifies ts, psp @*/
01585 {
01586     rpmdbMatchIterator mi;
01587     mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_REQUIRENAME, key, 0);
01588     return checkPackageSet(ts, psp, key, mi);
01589 }
01590 
01598 static int checkDependentConflicts(rpmTransactionSet ts,
01599                 problemsSet psp, const char * key)
01600         /*@modifies ts, psp @*/
01601 {
01602     int rc = 0;
01603 
01604     if (ts->rpmdb) {    /* XXX is this necessary? */
01605         rpmdbMatchIterator mi;
01606         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_CONFLICTNAME, key, 0);
01607         rc = checkPackageSet(ts, psp, key, mi);
01608     }
01609 
01610     return rc;
01611 }
01612 
01613 /*
01614  * XXX Hack to remove known Red Hat dependency loops, will be removed
01615  * as soon as rpm's legacy permits.
01616  */
01617 #define DEPENDENCY_WHITEOUT
01618 
01619 #if defined(DEPENDENCY_WHITEOUT)
01620 static struct badDeps_s {
01621 /*@observer@*/ /*@null@*/ const char * pname;
01622 /*@observer@*/ /*@null@*/ const char * qname;
01623 } badDeps[] = {
01624     { "libtermcap", "bash" },
01625     { "modutils", "vixie-cron" },
01626     { "ypbind", "yp-tools" },
01627     { "ghostscript-fonts", "ghostscript" },
01628     /* 7.2 only */
01629     { "libgnomeprint15", "gnome-print" },
01630     { "nautilus", "nautilus-mozilla" },
01631     /* 7.1 only */
01632     { "arts", "kdelibs-sound" },
01633     /* 7.0 only */
01634     { "pango-gtkbeta-devel", "pango-gtkbeta" },
01635     { "XFree86", "Mesa" },
01636     { "compat-glibc", "db2" },
01637     { "compat-glibc", "db1" },
01638     { "pam", "initscripts" },
01639     { "initscripts", "sysklogd" },
01640     /* 6.2 */
01641     { "egcs-c++", "libstdc++" },
01642     /* 6.1 */
01643     { "pilot-link-devel", "pilot-link" },
01644     /* 5.2 */
01645     { "pam", "pamconfig" },
01646     { NULL, NULL }
01647 };
01648     
01649 static int ignoreDep(const struct availablePackage * p,
01650                 const struct availablePackage * q)
01651         /*@*/
01652 {
01653     struct badDeps_s * bdp = badDeps;
01654 
01655     while (bdp->pname != NULL && bdp->qname != NULL) {
01656         if (!strcmp(p->name, bdp->pname) && !strcmp(q->name, bdp->qname))
01657             return 1;
01658         bdp++;
01659     }
01660     return 0;
01661 }
01662 #endif
01663 
01669 static void markLoop(/*@special@*/ struct tsortInfo * tsi,
01670                 struct availablePackage * q)
01671         /*@uses tsi @*/
01672         /*@modifies internalState @*/
01673 {
01674     struct availablePackage * p;
01675 
01676     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
01677         tsi = tsi->tsi_next;
01678         if (p->tsi.tsi_pkg != NULL)
01679             continue;
01680         p->tsi.tsi_pkg = q;
01681         if (p->tsi.tsi_next != NULL)
01682             markLoop(p->tsi.tsi_next, p);
01683     }
01684 }
01685 
01686 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
01687 {
01688     if (isLegacyPreReq(f))
01689         return "PreReq:";
01690     f = _notpre(f);
01691     if (f & RPMSENSE_SCRIPT_PRE)
01692         return "Requires(pre):";
01693     if (f & RPMSENSE_SCRIPT_POST)
01694         return "Requires(post):";
01695     if (f & RPMSENSE_SCRIPT_PREUN)
01696         return "Requires(preun):";
01697     if (f & RPMSENSE_SCRIPT_POSTUN)
01698         return "Requires(postun):";
01699     if (f & RPMSENSE_SCRIPT_VERIFY)
01700         return "Requires(verify):";
01701     if (f & RPMSENSE_FIND_REQUIRES)
01702         return "Requires(auto):";
01703     return "Requires:";
01704 }
01705 
01717 static /*@owned@*/ /*@null@*/ const char *
01718 zapRelation(struct availablePackage * q, struct availablePackage * p,
01719                 int zap, /*@in@*/ /*@out@*/ int * nzaps)
01720         /*@modifies q, p, *nzaps @*/
01721 {
01722     struct tsortInfo * tsi_prev;
01723     struct tsortInfo * tsi;
01724     const char *dp = NULL;
01725 
01726     for (tsi_prev = &q->tsi, tsi = q->tsi.tsi_next;
01727          tsi != NULL;
01728         /* XXX Note: the loop traverses "not found", break on "found". */
01729         /*@-nullderef@*/
01730          tsi_prev = tsi, tsi = tsi->tsi_next)
01731         /*@=nullderef@*/
01732     {
01733         int j;
01734 
01735         if (tsi->tsi_suc != p)
01736             continue;
01737         if (p->requires == NULL) continue;      /* XXX can't happen */
01738         if (p->requireFlags == NULL) continue;  /* XXX can't happen */
01739         if (p->requiresEVR == NULL) continue;   /* XXX can't happen */
01740 
01741         j = tsi->tsi_reqx;
01742         dp = printDepend( identifyDepend(p->requireFlags[j]),
01743                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01744 
01745         /*
01746          * Attempt to unravel a dependency loop by eliminating Requires's.
01747          */
01748         if (zap && !(p->requireFlags[j] & RPMSENSE_PREREQ)) {
01749             rpmMessage(RPMMESS_DEBUG,
01750                         _("removing %s-%s-%s \"%s\" from tsort relations.\n"),
01751                         p->name, p->version, p->release, dp);
01752             p->tsi.tsi_count--;
01753             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01754             tsi->tsi_next = NULL;
01755             tsi->tsi_suc = NULL;
01756             tsi = _free(tsi);
01757             if (nzaps)
01758                 (*nzaps)++;
01759             if (zap)
01760                 zap--;
01761         }
01762         /* XXX Note: the loop traverses "not found", get out now! */
01763         break;
01764     }
01765     return dp;
01766 }
01767 
01776 static inline int addRelation( const rpmTransactionSet ts,
01777                 struct availablePackage * p, unsigned char * selected, int j)
01778         /*@modifies p->tsi.tsi_u.count, p->depth, *selected @*/
01779 {
01780     struct availablePackage * q;
01781     struct tsortInfo * tsi;
01782     int matchNum;
01783 
01784     if (!p->requires || !p->requiresEVR || !p->requireFlags)
01785         return 0;
01786 
01787     q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL,
01788                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01789 
01790     /* Ordering depends only on added package relations. */
01791     if (q == NULL)
01792         return 0;
01793 
01794     /* Avoid rpmlib feature dependencies. */
01795     if (!strncmp(p->requires[j], "rpmlib(", sizeof("rpmlib(")-1))
01796         return 0;
01797 
01798 #if defined(DEPENDENCY_WHITEOUT)
01799     /* Avoid certain dependency relations. */
01800     if (ignoreDep(p, q))
01801         return 0;
01802 #endif
01803 
01804     /* Avoid redundant relations. */
01805     /* XXX TODO: add control bit. */
01806     matchNum = q - ts->addedPackages.list;
01807     if (selected[matchNum] != 0)
01808         return 0;
01809     selected[matchNum] = 1;
01810 
01811     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01812     p->tsi.tsi_count++;                 /* bump p predecessor count */
01813     if (p->depth <= q->depth)           /* Save max. depth in dependency tree */
01814         p->depth = q->depth + 1;
01815 
01816     tsi = xmalloc(sizeof(*tsi));
01817     tsi->tsi_suc = p;
01818     tsi->tsi_reqx = j;
01819     tsi->tsi_next = q->tsi.tsi_next;
01820     q->tsi.tsi_next = tsi;
01821     q->tsi.tsi_qcnt++;                  /* bump q successor count */
01822     return 0;
01823 }
01824 
01831 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01832 {
01833     int a = ((const struct orderListIndex *)one)->alIndex;
01834     int b = ((const struct orderListIndex *)two)->alIndex;
01835     return (a - b);
01836 }
01837 
01844 static void addQ(struct availablePackage * p,
01845                 /*@in@*/ /*@out@*/ struct availablePackage ** qp,
01846                 /*@in@*/ /*@out@*/ struct availablePackage ** rp)
01847         /*@modifies p->tsi, *qp, *rp @*/
01848 {
01849     struct availablePackage *q, *qprev;
01850 
01851     if ((*rp) == NULL) {        /* 1st element */
01852         (*rp) = (*qp) = p;
01853         return;
01854     }
01855     for (qprev = NULL, q = (*qp); q != NULL; qprev = q, q = q->tsi.tsi_suc) {
01856         if (q->tsi.tsi_qcnt <= p->tsi.tsi_qcnt)
01857             break;
01858     }
01859     if (qprev == NULL) {        /* insert at beginning of list */
01860         p->tsi.tsi_suc = q;
01861         (*qp) = p;              /* new head */
01862     } else if (q == NULL) {     /* insert at end of list */
01863         qprev->tsi.tsi_suc = p;
01864         (*rp) = p;              /* new tail */
01865     } else {                    /* insert between qprev and q */
01866         p->tsi.tsi_suc = q;
01867         qprev->tsi.tsi_suc = p;
01868     }
01869 }
01870 
01871 int rpmdepOrder(rpmTransactionSet ts)
01872 {
01873     int npkgs = ts->addedPackages.size;
01874     int chainsaw = ts->transFlags & RPMTRANS_FLAG_CHAINSAW;
01875     struct availablePackage * p;
01876     struct availablePackage * q;
01877     struct availablePackage * r;
01878     struct tsortInfo * tsi;
01879     struct tsortInfo * tsi_next;
01880     int * ordering = alloca(sizeof(*ordering) * (npkgs + 1));
01881     int orderingCount = 0;
01882     unsigned char * selected = alloca(sizeof(*selected) * (npkgs + 1));
01883     int loopcheck;
01884     struct transactionElement * newOrder;
01885     int newOrderCount = 0;
01886     struct orderListIndex * orderList;
01887     int nrescans = 10;
01888     int _printed = 0;
01889     int qlen;
01890     int i, j;
01891 
01892     alMakeIndex(&ts->addedPackages);
01893     alMakeIndex(&ts->availablePackages);
01894 
01895     /* T1. Initialize. */
01896     loopcheck = npkgs;
01897 
01898     /* Record all relations. */
01899     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01900     if ((p = ts->addedPackages.list) != NULL)
01901     for (i = 0; i < npkgs; i++, p++) {
01902         int matchNum;
01903 
01904         if (p->requiresCount <= 0)
01905             continue;
01906 
01907         memset(selected, 0, sizeof(*selected) * npkgs);
01908 
01909         /* Avoid narcisstic relations. */
01910         matchNum = p - ts->addedPackages.list;
01911         selected[matchNum] = 1;
01912 
01913         /* T2. Next "q <- p" relation. */
01914 
01915         /* First, do pre-requisites. */
01916         for (j = 0; j < p->requiresCount; j++) {
01917 
01918             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
01919 
01920             /* Skip if not %pre/%post requires or legacy prereq. */
01921 
01922             if (isErasePreReq(p->requireFlags[j]) ||
01923                 !( isInstallPreReq(p->requireFlags[j]) ||
01924                    isLegacyPreReq(p->requireFlags[j]) ))
01925                 continue;
01926 
01927             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01928             (void) addRelation(ts, p, selected, j);
01929 
01930         }
01931 
01932         /* Then do co-requisites. */
01933         for (j = 0; j < p->requiresCount; j++) {
01934 
01935             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
01936 
01937             /* Skip if %pre/%post requires or legacy prereq. */
01938 
01939             if (isErasePreReq(p->requireFlags[j]) ||
01940                  ( isInstallPreReq(p->requireFlags[j]) ||
01941                    isLegacyPreReq(p->requireFlags[j]) ))
01942                 continue;
01943 
01944             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01945             (void) addRelation(ts, p, selected, j);
01946 
01947         }
01948     }
01949 
01950     /* Save predecessor count. */
01951     if ((p = ts->addedPackages.list) != NULL)
01952     for (i = 0; i < npkgs; i++, p++) {
01953         p->npreds = p->tsi.tsi_count;
01954     }
01955 
01956     /* T4. Scan for zeroes. */
01957     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, depth)\n"));
01958 
01959 rescan:
01960     q = r = NULL;
01961     qlen = 0;
01962     if ((p = ts->addedPackages.list) != NULL)
01963     for (i = 0; i < npkgs; i++, p++) {
01964 
01965         /* Prefer packages in presentation order. */
01966         if (!chainsaw)
01967             p->tsi.tsi_qcnt = (npkgs - i);
01968 
01969         if (p->tsi.tsi_count != 0)
01970             continue;
01971         p->tsi.tsi_suc = NULL;
01972         addQ(p, &q, &r);
01973         qlen++;
01974     }
01975 
01976     /* T5. Output front of queue (T7. Remove from queue.) */
01977     for (; q != NULL; q = q->tsi.tsi_suc) {
01978 
01979         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%3d %*s %s-%s-%s\n",
01980                         orderingCount, q->npreds, q->tsi.tsi_qcnt, q->depth,
01981                         2*q->depth, "",
01982                         q->name, q->version, q->release);
01983         ordering[orderingCount++] = q - ts->addedPackages.list;
01984         qlen--;
01985         loopcheck--;
01986 
01987         /* T6. Erase relations. */
01988         tsi_next = q->tsi.tsi_next;
01989         q->tsi.tsi_next = NULL;
01990         while ((tsi = tsi_next) != NULL) {
01991             tsi_next = tsi->tsi_next;
01992             tsi->tsi_next = NULL;
01993             p = tsi->tsi_suc;
01994             if (p && (--p->tsi.tsi_count) <= 0) {
01995                 /* XXX TODO: add control bit. */
01996                 p->tsi.tsi_suc = NULL;
01997                 /*@-nullstate@*/        /* FIX: q->tsi.tsi_u.suc may be NULL */
01998                 addQ(p, &q->tsi.tsi_suc, &r);
01999                 /*@=nullstate@*/
02000                 qlen++;
02001             }
02002             tsi = _free(tsi);
02003         }
02004         if (!_printed && loopcheck == qlen && q->tsi.tsi_suc != NULL) {
02005             _printed++;
02006             rpmMessage(RPMMESS_DEBUG,
02007                 _("========== successors only (presentation order)\n"));
02008         }
02009     }
02010 
02011     /* T8. End of process. Check for loops. */
02012     if (loopcheck != 0) {
02013         int nzaps;
02014 
02015         /* T9. Initialize predecessor chain. */
02016         nzaps = 0;
02017         if ((q = ts->addedPackages.list) != NULL)
02018         for (i = 0; i < npkgs; i++, q++) {
02019             q->tsi.tsi_pkg = NULL;
02020             q->tsi.tsi_reqx = 0;
02021             /* Mark packages already sorted. */
02022             if (q->tsi.tsi_count == 0)
02023                 q->tsi.tsi_count = -1;
02024         }
02025 
02026         /* T10. Mark all packages with their predecessors. */
02027         if ((q = ts->addedPackages.list) != NULL)
02028         for (i = 0; i < npkgs; i++, q++) {
02029             if ((tsi = q->tsi.tsi_next) == NULL)
02030                 continue;
02031             q->tsi.tsi_next = NULL;
02032             markLoop(tsi, q);
02033             q->tsi.tsi_next = tsi;
02034         }
02035 
02036         /* T11. Print all dependency loops. */
02037         if ((r = ts->addedPackages.list) != NULL)
02038         for (i = 0; i < npkgs; i++, r++) {
02039             int printed;
02040 
02041             printed = 0;
02042 
02043             /* T12. Mark predecessor chain, looking for start of loop. */
02044             for (q = r->tsi.tsi_pkg; q != NULL; q = q->tsi.tsi_pkg) {
02045                 if (q->tsi.tsi_reqx)
02046                     /*@innerbreak@*/ break;
02047                 q->tsi.tsi_reqx = 1;
02048             }
02049 
02050             /* T13. Print predecessor chain from start of loop. */
02051             while ((p = q) != NULL && (q = p->tsi.tsi_pkg) != NULL) {
02052                 const char * dp;
02053                 char buf[4096];
02054 
02055                 /* Unchain predecessor loop. */
02056                 p->tsi.tsi_pkg = NULL;
02057 
02058                 if (!printed) {
02059                     rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
02060                     printed = 1;
02061                 }
02062 
02063                 /* Find (and destroy if co-requisite) "q <- p" relation. */
02064                 dp = zapRelation(q, p, 1, &nzaps);
02065 
02066                 /* Print next member of loop. */
02067                 sprintf(buf, "%s-%s-%s", p->name, p->version, p->release);
02068                 rpmMessage(RPMMESS_DEBUG, "    %-40s %s\n", buf,
02069                         (dp ? dp : "not found!?!"));
02070 
02071                 dp = _free(dp);
02072             }
02073 
02074             /* Walk (and erase) linear part of predecessor chain as well. */
02075             for (p = r, q = r->tsi.tsi_pkg;
02076                  q != NULL;
02077                  p = q, q = q->tsi.tsi_pkg)
02078             {
02079                 /* Unchain linear part of predecessor loop. */
02080                 p->tsi.tsi_pkg = NULL;
02081                 p->tsi.tsi_reqx = 0;
02082             }
02083         }
02084 
02085         /* If a relation was eliminated, then continue sorting. */
02086         /* XXX TODO: add control bit. */
02087         if (nzaps && nrescans-- > 0) {
02088             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
02089             goto rescan;
02090         }
02091         return 1;
02092     }
02093 
02094     /*
02095      * The order ends up as installed packages followed by removed packages,
02096      * with removes for upgrades immediately following the installation of
02097      * the new package. This would be easier if we could sort the
02098      * addedPackages array, but we store indexes into it in various places.
02099      */
02100     orderList = xmalloc(npkgs * sizeof(*orderList));
02101     for (i = 0, j = 0; i < ts->orderCount; i++) {
02102         if (ts->order[i].type == TR_ADDED) {
02103             orderList[j].alIndex = ts->order[i].u.addedIndex;
02104             orderList[j].orIndex = i;
02105             j++;
02106         }
02107     }
02108     assert(j <= npkgs);
02109 
02110     qsort(orderList, npkgs, sizeof(*orderList), orderListIndexCmp);
02111 
02112     newOrder = xmalloc(ts->orderCount * sizeof(*newOrder));
02113     for (i = 0, newOrderCount = 0; i < orderingCount; i++) {
02114         struct orderListIndex * needle, key;
02115 
02116         key.alIndex = ordering[i];
02117         needle = bsearch(&key, orderList, npkgs, sizeof(key),orderListIndexCmp);
02118         /* bsearch should never, ever fail */
02119         if (needle == NULL) continue;
02120 
02121         newOrder[newOrderCount++] = ts->order[needle->orIndex];
02122         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
02123             if (ts->order[j].type == TR_REMOVED &&
02124                 ts->order[j].u.removed.dependsOnIndex == needle->alIndex) {
02125                 newOrder[newOrderCount++] = ts->order[j];
02126             } else
02127                 /*@innerbreak@*/ break;
02128         }
02129     }
02130 
02131     for (i = 0; i < ts->orderCount; i++) {
02132         if (ts->order[i].type == TR_REMOVED &&
02133             ts->order[i].u.removed.dependsOnIndex == -1)  {
02134             newOrder[newOrderCount++] = ts->order[i];
02135         }
02136     }
02137     assert(newOrderCount == ts->orderCount);
02138 
02139     ts->order = _free(ts->order);
02140     ts->order = newOrder;
02141     ts->orderAlloced = ts->orderCount;
02142     orderList = _free(orderList);
02143 
02144     return 0;
02145 }
02146 
02153 static int rpmdbCloseDBI(/*@null@*/ rpmdb db, int rpmtag)
02154         /*@ modifies db, fileSystem @*/
02155 {
02156     int dbix;
02157     int rc = 0;
02158 
02159     if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
02160         return 0;
02161 
02162     for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02163         if (dbiTags[dbix] != rpmtag)
02164             continue;
02165         if (db->_dbi[dbix] != NULL) {
02166             int xx;
02167             /*@-unqualifiedtrans@*/             /* FIX: double indirection. */
02168             xx = dbiClose(db->_dbi[dbix], 0);
02169             if (xx && rc == 0) rc = xx;
02170             db->_dbi[dbix] = NULL;
02171             /*@=unqualifiedtrans@*/
02172         }
02173         break;
02174     }
02175     return rc;
02176 }
02177 
02178 int rpmdepCheck(rpmTransactionSet ts,
02179                 rpmDependencyConflict * conflicts, int * numConflicts)
02180 {
02181     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02182     HFD_t hfd = headerFreeData;
02183     rpmdbMatchIterator mi = NULL;
02184     Header h = NULL;
02185     struct availablePackage * p;
02186     problemsSet ps;
02187     int npkgs;
02188     int i, j;
02189     int rc;
02190 
02191     npkgs = ts->addedPackages.size;
02192 
02193     ps = xcalloc(1, sizeof(*ps));
02194     ps->alloced = 5;
02195     ps->num = 0;
02196     ps->problems = xcalloc(ps->alloced, sizeof(*ps->problems));
02197 
02198     *conflicts = NULL;
02199     *numConflicts = 0;
02200 
02201     alMakeIndex(&ts->addedPackages);
02202     alMakeIndex(&ts->availablePackages);
02203 
02204     /*
02205      * Look at all of the added packages and make sure their dependencies
02206      * are satisfied.
02207      */
02208     if ((p = ts->addedPackages.list) != NULL)
02209     for (i = 0; i < npkgs; i++, p++)
02210     {
02211 
02212         rpmMessage(RPMMESS_DEBUG,  "========== +++ %s-%s-%s\n" ,
02213                 p->name, p->version, p->release);
02214         rc = checkPackageDeps(ts, ps, p->h, NULL, p->multiLib);
02215         if (rc)
02216             goto exit;
02217 
02218         /* Adding: check name against conflicts matches. */
02219         rc = checkDependentConflicts(ts, ps, p->name);
02220         if (rc)
02221             goto exit;
02222 
02223         if (p->providesCount == 0 || p->provides == NULL)
02224             continue;
02225 
02226         rc = 0;
02227         for (j = 0; j < p->providesCount; j++) {
02228             /* Adding: check provides key against conflicts matches. */
02229             if (!checkDependentConflicts(ts, ps, p->provides[j]))
02230                 continue;
02231             rc = 1;
02232             /*@innerbreak@*/ break;
02233         }
02234         if (rc)
02235             goto exit;
02236     }
02237 
02238     /*
02239      * Look at the removed packages and make sure they aren't critical.
02240      */
02241     if (ts->numRemovedPackages > 0) {
02242       mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
02243       (void) rpmdbAppendIterator(mi,
02244                         ts->removedPackages, ts->numRemovedPackages);
02245       while ((h = rpmdbNextIterator(mi)) != NULL) {
02246 
02247         {   const char * name, * version, * release;
02248             (void) headerNVR(h, &name, &version, &release);
02249             rpmMessage(RPMMESS_DEBUG,  "========== --- %s-%s-%s\n" ,
02250                 name, version, release);
02251 
02252             /* Erasing: check name against requiredby matches. */
02253             rc = checkDependentPackages(ts, ps, name);
02254             if (rc)
02255                 goto exit;
02256         }
02257 
02258         {   const char ** provides;
02259             int providesCount;
02260             rpmTagType pnt;
02261 
02262             if (hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides,
02263                                 &providesCount))
02264             {
02265                 rc = 0;
02266                 for (j = 0; j < providesCount; j++) {
02267                     /* Erasing: check provides against requiredby matches. */
02268                     if (!checkDependentPackages(ts, ps, provides[j]))
02269                         continue;
02270                     rc = 1;
02271                     /*@innerbreak@*/ break;
02272                 }
02273                 provides = hfd(provides, pnt);
02274                 if (rc)
02275                     goto exit;
02276             }
02277         }
02278 
02279         {   const char ** baseNames, ** dirNames;
02280             int_32 * dirIndexes;
02281             rpmTagType dnt, bnt;
02282             int fileCount;
02283             char * fileName = NULL;
02284             int fileAlloced = 0;
02285             int len;
02286 
02287             if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
02288             {
02289                 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
02290                 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes,
02291                                 NULL);
02292                 rc = 0;
02293                 for (j = 0; j < fileCount; j++) {
02294                     len = strlen(baseNames[j]) + 1 + 
02295                           strlen(dirNames[dirIndexes[j]]);
02296                     if (len > fileAlloced) {
02297                         fileAlloced = len * 2;
02298                         fileName = xrealloc(fileName, fileAlloced);
02299                     }
02300                     *fileName = '\0';
02301                     (void) stpcpy( stpcpy(fileName, dirNames[dirIndexes[j]]) , baseNames[j]);
02302                     /* Erasing: check filename against requiredby matches. */
02303                     if (!checkDependentPackages(ts, ps, fileName))
02304                         continue;
02305                     rc = 1;
02306                     /*@innerbreak@*/ break;
02307                 }
02308 
02309                 fileName = _free(fileName);
02310                 baseNames = hfd(baseNames, bnt);
02311                 dirNames = hfd(dirNames, dnt);
02312                 if (rc)
02313                     goto exit;
02314             }
02315         }
02316 
02317       }
02318       mi = rpmdbFreeIterator(mi);
02319     }
02320 
02321     if (ps->num) {
02322         *conflicts = ps->problems;
02323         ps->problems = NULL;
02324         *numConflicts = ps->num;
02325     }
02326     rc = 0;
02327 
02328 exit:
02329     mi = rpmdbFreeIterator(mi);
02330     ps->problems = _free(ps->problems);
02331     ps = _free(ps);
02332     if (_cacheDependsRC)
02333         (void) rpmdbCloseDBI(ts->rpmdb, RPMDBI_DEPENDS);
02334     return rc;
02335 }

Generated on Wed Mar 13 15:34:47 2002 for rpm by doxygen1.2.14 written by Dimitri van Heesch, © 1997-2002