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

lib/depends.c

Go to the documentation of this file.
00001 
00005 int _depends_debug = 0;
00006 
00007 #include "system.h"
00008 
00009 #include <rpmlib.h>
00010 
00011 #include "depends.h"
00012 #include "rpmdb.h"
00013 #include "misc.h"
00014 #include "debug.h"
00015 
00016 /*@access dbiIndex@*/           /* XXX compared with NULL */
00017 /*@access dbiIndexSet@*/        /* XXX compared with NULL */
00018 /*@access Header@*/             /* XXX compared with NULL */
00019 /*@access rpmdb@*/              /* XXX compared with NULL */
00020 /*@access rpmTransactionSet@*/
00021 
00027 static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
00028     if (this)   free((void *)this);
00029     return NULL;
00030 }
00031 
00032 int headerNVR(Header h, const char **np, const char **vp, const char **rp)
00033 {
00034     int type, count;
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     char *tbuf, *t;
00065     size_t nb;
00066 
00067     nb = 0;
00068     if (depend) nb += strlen(depend) + 1;
00069     if (key)    nb += strlen(key);
00070     if (keyFlags & RPMSENSE_SENSEMASK) {
00071         if (nb) nb++;
00072         if (keyFlags & RPMSENSE_LESS)   nb++;
00073         if (keyFlags & RPMSENSE_GREATER) nb++;
00074         if (keyFlags & RPMSENSE_EQUAL)  nb++;
00075     }
00076     if (keyEVR && *keyEVR) {
00077         if (nb) nb++;
00078         nb += strlen(keyEVR);
00079     }
00080 
00081     t = tbuf = xmalloc(nb + 1);
00082     if (depend) {
00083         while(*depend)  *t++ = *depend++;
00084         *t++ = ' ';
00085     }
00086     if (key)
00087         while(*key)     *t++ = *key++;
00088     if (keyFlags & RPMSENSE_SENSEMASK) {
00089         if (t != tbuf)  *t++ = ' ';
00090         if (keyFlags & RPMSENSE_LESS)   *t++ = '<';
00091         if (keyFlags & RPMSENSE_GREATER) *t++ = '>';
00092         if (keyFlags & RPMSENSE_EQUAL)  *t++ = '=';
00093     }
00094     if (keyEVR && *keyEVR) {
00095         if (t != tbuf)  *t++ = ' ';
00096         while(*keyEVR)  *t++ = *keyEVR++;
00097     }
00098     *t = '\0';
00099     return tbuf;
00100 }
00101 
00102 #ifdef  UNUSED
00103 static /*@only@*/ const char *buildEVR(int_32 *e, const char *v, const char *r)
00104 {
00105     const char *pEVR;
00106     char *p;
00107 
00108     pEVR = p = xmalloc(21 + strlen(v) + 1 + strlen(r) + 1);
00109     *p = '\0';
00110     if (e) {
00111         sprintf(p, "%d:", *e);
00112         while (*p)
00113             p++;
00114     }
00115     (void) stpcpy( stpcpy( stpcpy(p, v) , "-") , r);
00116     return pEVR;
00117 }
00118 #endif
00119 
00120 struct orderListIndex {
00121     int alIndex;
00122     int orIndex;
00123 };
00124 
00129 static void alFreeIndex(struct availableList * al)
00130         /*@modifies al->index @*/
00131 {
00132     if (al->index.size) {
00133         al->index.index = _free(al->index.index);
00134         al->index.size = 0;
00135     }
00136 }
00137 
00142 static void alCreate(struct availableList * al)
00143         /*@modifies *al @*/
00144 {
00145     al->alloced = al->delta;
00146     al->size = 0;
00147     al->list = xcalloc(al->alloced, sizeof(*al->list));
00148 
00149     al->index.index = NULL;
00150     al->index.size = 0;
00151 
00152     al->numDirs = 0;
00153     al->dirs = NULL;
00154 }
00155 
00160 static void alFree(struct availableList * al)
00161 {
00162     HFD_t hfd = headerFreeData;
00163     struct availablePackage * p;
00164     rpmRelocation * r;
00165     int i;
00166 
00167     for (i = 0, p = al->list; i < al->size; i++, p++) {
00168 
00169         {   struct tsortInfo * tsi;
00170             while ((tsi = p->tsi.tsi_next) != NULL) {
00171                 p->tsi.tsi_next = tsi->tsi_next;
00172                 tsi->tsi_next = NULL;
00173                 tsi = _free(tsi);
00174             }
00175         }
00176 
00177         p->provides = hfd(p->provides, -1);
00178         p->providesEVR = hfd(p->providesEVR, -1);
00179         p->requires = hfd(p->requires, -1);
00180         p->requiresEVR = hfd(p->requiresEVR, -1);
00181         p->baseNames = hfd(p->baseNames, -1);
00182         if (p->h)               headerFree(p->h);
00183 
00184         if (p->relocs) {
00185             for (r = p->relocs; (r->oldPath || r->newPath); r++) {
00186                 r->oldPath = _free(r->oldPath);
00187                 r->newPath = _free(r->newPath);
00188             }
00189             p->relocs = _free(p->relocs);
00190         }
00191         if (p->fd)
00192             p->fd = fdFree(p->fd, "alAddPackage (alFree)");
00193     }
00194 
00195     for (i = 0; i < al->numDirs; i++) {
00196         al->dirs[i].dirName = _free(al->dirs[i].dirName);
00197         al->dirs[i].files = _free(al->dirs[i].files);
00198     }
00199 
00200     if (al->numDirs && al->dirs)
00201         al->dirs = _free(al->dirs);
00202     if (al->alloced && al->list)
00203         al->list = _free(al->list);
00204     alFreeIndex(al);
00205 }
00206 
00213 static int dirInfoCompare(const void * one, const void * two)   /*@*/
00214 {
00215     const struct dirInfo * a = one;
00216     const struct dirInfo * b = two;
00217     int lenchk = a->dirNameLen - b->dirNameLen;
00218 
00219     if (lenchk)
00220         return lenchk;
00221 
00222     /* XXX FIXME: this might do "backward" strcmp for speed */
00223     return strcmp(a->dirName, b->dirName);
00224 }
00225 
00235 static /*@exposed@*/ struct availablePackage * alAddPackage(struct availableList * al,
00236                 Header h, /*@dependent@*/ const void * key,
00237                 FD_t fd, rpmRelocation * relocs)
00238 {
00239     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00240     HFD_t hfd = headerFreeData;
00241     int dnt, bnt;
00242     struct availablePackage * p;
00243     rpmRelocation * r;
00244     int i;
00245     int_32 * dirIndexes;
00246     const char ** dirNames;
00247     int numDirs, dirNum;
00248     int * dirMapping;
00249     struct dirInfo dirNeedle;
00250     struct dirInfo * dirMatch;
00251     int first, last, fileNum;
00252     int origNumDirs;
00253     int pkgNum;
00254     uint_32 multiLibMask = 0;
00255     uint_32 * fileFlags = NULL;
00256     uint_32 * pp = NULL;
00257 
00258     if (al->size == al->alloced) {
00259         al->alloced += al->delta;
00260         al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
00261     }
00262 
00263     pkgNum = al->size++;
00264     p = al->list + pkgNum;
00265     p->h = headerLink(h);       /* XXX reference held by transaction set */
00266     p->depth = p->npreds = 0;
00267     memset(&p->tsi, 0, sizeof(p->tsi));
00268     p->multiLib = 0;    /* MULTILIB */
00269 
00270     headerNVR(p->h, &p->name, &p->version, &p->release);
00271 
00272     /* XXX This should be added always so that packages look alike.
00273      * XXX However, there is logic in files.c/depends.c that checks for
00274      * XXX existence (rather than value) that will need to change as well.
00275      */
00276     if (hge(p->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
00277         multiLibMask = *pp;
00278 
00279     if (multiLibMask) {
00280         for (i = 0; i < pkgNum - 1; i++) {
00281             if (!strcmp (p->name, al->list[i].name)
00282                 && hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
00283                                   (void **) &pp, NULL)
00284                 && !rpmVersionCompare(p->h, al->list[i].h)
00285                 && *pp && !(*pp & multiLibMask))
00286                 p->multiLib = multiLibMask;
00287         }
00288     }
00289 
00290     if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL))
00291         p->epoch = NULL;
00292 
00293     if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides,
00294         &p->providesCount)) {
00295         p->providesCount = 0;
00296         p->provides = NULL;
00297         p->providesEVR = NULL;
00298         p->provideFlags = NULL;
00299     } else {
00300         if (!hge(h, RPMTAG_PROVIDEVERSION,
00301                         NULL, (void **) &p->providesEVR, NULL))
00302             p->providesEVR = NULL;
00303         if (!hge(h, RPMTAG_PROVIDEFLAGS,
00304                         NULL, (void **) &p->provideFlags, NULL))
00305             p->provideFlags = NULL;
00306     }
00307 
00308     if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires,
00309         &p->requiresCount)) {
00310         p->requiresCount = 0;
00311         p->requires = NULL;
00312         p->requiresEVR = NULL;
00313         p->requireFlags = NULL;
00314     } else {
00315         if (!hge(h, RPMTAG_REQUIREVERSION,
00316                         NULL, (void **) &p->requiresEVR, NULL))
00317             p->requiresEVR = NULL;
00318         if (!hge(h, RPMTAG_REQUIREFLAGS,
00319                         NULL, (void **) &p->requireFlags, NULL))
00320             p->requireFlags = NULL;
00321     }
00322 
00323     if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **) &p->baseNames, &p->filesCount))
00324     {
00325         p->filesCount = 0;
00326         p->baseNames = NULL;
00327     } else {
00328         hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
00329         hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
00330         hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
00331 
00332         /* XXX FIXME: We ought to relocate the directory list here */
00333 
00334         dirMapping = alloca(sizeof(*dirMapping) * numDirs);
00335 
00336         /* allocated enough space for all the directories we could possible
00337            need to add */
00338         al->dirs = xrealloc(al->dirs, 
00339                             sizeof(*al->dirs) * (al->numDirs + numDirs));
00340         origNumDirs = al->numDirs;
00341 
00342         for (dirNum = 0; dirNum < numDirs; dirNum++) {
00343             dirNeedle.dirName = (char *) dirNames[dirNum];
00344             dirNeedle.dirNameLen = strlen(dirNames[dirNum]);
00345             dirMatch = bsearch(&dirNeedle, al->dirs, origNumDirs,
00346                                sizeof(dirNeedle), dirInfoCompare);
00347             if (dirMatch) {
00348                 dirMapping[dirNum] = dirMatch - al->dirs;
00349             } else {
00350                 dirMapping[dirNum] = al->numDirs;
00351                 al->dirs[al->numDirs].dirName = xstrdup(dirNames[dirNum]);
00352                 al->dirs[al->numDirs].dirNameLen = strlen(dirNames[dirNum]);
00353                 al->dirs[al->numDirs].files = NULL;
00354                 al->dirs[al->numDirs].numFiles = 0;
00355                 al->numDirs++;
00356             }
00357         }
00358 
00359         dirNames = hfd(dirNames, dnt);
00360 
00361         first = 0;
00362         while (first < p->filesCount) {
00363             last = first;
00364             while ((last + 1) < p->filesCount) {
00365                 if (dirIndexes[first] != dirIndexes[last + 1]) break;
00366                 last++;
00367             }
00368 
00369             dirMatch = al->dirs + dirMapping[dirIndexes[first]];
00370             dirMatch->files = xrealloc(dirMatch->files,
00371                 sizeof(*dirMatch->files) * 
00372                     (dirMatch->numFiles + last - first + 1));
00373             for (fileNum = first; fileNum <= last; fileNum++) {
00374                 dirMatch->files[dirMatch->numFiles].baseName =
00375                     p->baseNames[fileNum];
00376                 dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum;
00377                 dirMatch->files[dirMatch->numFiles].fileFlags =
00378                                 fileFlags[fileNum];
00379                 dirMatch->numFiles++;
00380             }
00381 
00382             first = last + 1;
00383         }
00384 
00385         if (origNumDirs + al->numDirs)
00386             qsort(al->dirs, al->numDirs, sizeof(dirNeedle), dirInfoCompare);
00387 
00388     }
00389 
00390     p->key = key;
00391     p->fd = (fd ? fdLink(fd, "alAddPackage") : NULL);
00392 
00393     if (relocs) {
00394         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++);
00395         p->relocs = xmalloc(sizeof(*p->relocs) * (i + 1));
00396 
00397         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
00398             p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
00399             p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
00400         }
00401         p->relocs[i].oldPath = NULL;
00402         p->relocs[i].newPath = NULL;
00403     } else {
00404         p->relocs = NULL;
00405     }
00406 
00407     alFreeIndex(al);
00408 
00409     return p;
00410 }
00411 
00418 static int indexcmp(const void * one, const void * two)
00419 {
00420     const struct availableIndexEntry * a = one;
00421     const struct availableIndexEntry * b = two;
00422     int lenchk = a->entryLen - b->entryLen;
00423 
00424     if (lenchk)
00425         return lenchk;
00426 
00427     return strcmp(a->entry, b->entry);
00428 }
00429 
00434 static void alMakeIndex(struct availableList * al)
00435         /*@modifies al->index @*/
00436 {
00437     struct availableIndex * ai = &al->index;
00438     int i, j, k;
00439 
00440     if (ai->size) return;
00441 
00442     for (i = 0; i < al->size; i++) 
00443         ai->size += al->list[i].providesCount;
00444 
00445     if (ai->size) {
00446         ai->index = xcalloc(ai->size, sizeof(*ai->index));
00447 
00448         k = 0;
00449         for (i = 0; i < al->size; i++) {
00450             for (j = 0; j < al->list[i].providesCount; j++) {
00451 
00452                 /* If multilib install, skip non-multilib provides. */
00453                 if (al->list[i].multiLib &&
00454                     !isDependsMULTILIB(al->list[i].provideFlags[j])) {
00455                         ai->size--;
00456                         continue;
00457                 }
00458 
00459                 ai->index[k].package = al->list + i;
00460                 ai->index[k].entry = al->list[i].provides[j];
00461                 ai->index[k].entryLen = strlen(al->list[i].provides[j]);
00462                 ai->index[k].type = IET_PROVIDES;
00463                 k++;
00464             }
00465         }
00466 
00467         qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
00468     }
00469 }
00470 
00477 static int intcmp(const void * a, const void *b)
00478 {
00479     const int * aptr = a;
00480     const int * bptr = b;
00481     int rc = (*aptr - *bptr);
00482     return rc;
00483 }
00484 
00492 static void parseEVR(char *evr,
00493         /*@exposed@*/ /*@out@*/ const char **ep,
00494         /*@exposed@*/ /*@out@*/ const char **vp,
00495         /*@exposed@*/ /*@out@*/const char **rp) /*@modifies evr,*ep,*vp,*rp @*/
00496 {
00497     const char *epoch;
00498     const char *version;                /* assume only version is present */
00499     const char *release;
00500     char *s, *se;
00501 
00502     s = evr;
00503     while (*s && isdigit(*s)) s++;      /* s points to epoch terminator */
00504     se = strrchr(s, '-');               /* se points to version terminator */
00505 
00506     if (*s == ':') {
00507         epoch = evr;
00508         *s++ = '\0';
00509         version = s;
00510         if (*epoch == '\0') epoch = "0";
00511     } else {
00512         epoch = NULL;   /* XXX disable epoch compare if missing */
00513         version = evr;
00514     }
00515     if (se) {
00516         *se++ = '\0';
00517         release = se;
00518     } else {
00519         release = NULL;
00520     }
00521 
00522     if (ep) *ep = epoch;
00523     if (vp) *vp = version;
00524     if (rp) *rp = release;
00525 }
00526 
00527 const char *rpmNAME = PACKAGE;
00528 const char *rpmEVR = VERSION;
00529 int rpmFLAGS = RPMSENSE_EQUAL;
00530 
00531 int rpmRangesOverlap(const char *AName, const char *AEVR, int AFlags,
00532         const char *BName, const char *BEVR, int BFlags)
00533 {
00534     const char *aDepend = printDepend(NULL, AName, AEVR, AFlags);
00535     const char *bDepend = printDepend(NULL, BName, BEVR, BFlags);
00536     char *aEVR, *bEVR;
00537     const char *aE, *aV, *aR, *bE, *bV, *bR;
00538     int result;
00539     int sense;
00540 
00541     /* Different names don't overlap. */
00542     if (strcmp(AName, BName)) {
00543         result = 0;
00544         goto exit;
00545     }
00546 
00547     /* Same name. If either A or B is an existence test, always overlap. */
00548     if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
00549         result = 1;
00550         goto exit;
00551     }
00552 
00553     /* If either EVR is non-existent or empty, always overlap. */
00554     if (!(AEVR && *AEVR && BEVR && *BEVR)) {
00555         result = 1;
00556         goto exit;
00557     }
00558 
00559     /* Both AEVR and BEVR exist. */
00560     aEVR = xstrdup(AEVR);
00561     parseEVR(aEVR, &aE, &aV, &aR);
00562     bEVR = xstrdup(BEVR);
00563     parseEVR(bEVR, &bE, &bV, &bR);
00564 
00565     /* Compare {A,B} [epoch:]version[-release] */
00566     sense = 0;
00567     if (aE && *aE && bE && *bE)
00568         sense = rpmvercmp(aE, bE);
00569     else if (aE && *aE && atol(aE) > 0) {
00570         /* XXX legacy epoch-less requires/conflicts compatibility */
00571         rpmMessage(RPMMESS_DEBUG, _("the \"B\" dependency needs an epoch (assuming same as \"A\")\n\tA %s\tB %s\n"),
00572                 aDepend, bDepend);
00573         sense = 0;
00574     } else if (bE && *bE && atol(bE) > 0)
00575         sense = -1;
00576 
00577     if (sense == 0) {
00578         sense = rpmvercmp(aV, bV);
00579         if (sense == 0 && aR && *aR && bR && *bR) {
00580             sense = rpmvercmp(aR, bR);
00581         }
00582     }
00583     aEVR = _free(aEVR);
00584     bEVR = _free(bEVR);
00585 
00586     /* Detect overlap of {A,B} range. */
00587     result = 0;
00588     if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
00589         result = 1;
00590     } else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
00591         result = 1;
00592     } else if (sense == 0 &&
00593         (((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
00594          ((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
00595          ((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
00596         result = 1;
00597     }
00598 
00599 exit:
00600     rpmMessage(RPMMESS_DEBUG, _("  %s    A %s\tB %s\n"),
00601         (result ? "YES" : "NO "), aDepend, bDepend);
00602     aDepend = _free(aDepend);
00603     bDepend = _free(bDepend);
00604     return result;
00605 }
00606 
00607 typedef int (*dbrecMatch_t) (Header h, const char *reqName, const char * reqEVR, int reqFlags);
00608 
00609 static int rangeMatchesDepFlags (Header h, const char *reqName, const char * reqEVR, int reqFlags)
00610 {
00611     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00612     HFD_t hfd = headerFreeData;
00613     int pnt, pvt;
00614     const char ** provides;
00615     const char ** providesEVR;
00616     int_32 * provideFlags;
00617     int providesCount;
00618     int result;
00619     int type;
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     hge(h, RPMTAG_PROVIDEFLAGS, &type, (void **) &provideFlags, &providesCount);
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     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)
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     ts->rpmdb = rpmdb;
00703     ts->scriptFd = NULL;
00704     ts->id = 0;
00705     ts->delta = 5;
00706 
00707     ts->numRemovedPackages = 0;
00708     ts->allocedRemovedPackages = ts->delta;
00709     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
00710                         sizeof(*ts->removedPackages));
00711 
00712     /* This canonicalizes the root */
00713     rootLen = strlen(rootDir);
00714     if (!(rootLen && rootDir[rootLen - 1] == '/')) {
00715         char * t;
00716 
00717         t = alloca(rootLen + 2);
00718         *t = '\0';
00719         (void) stpcpy( stpcpy(t, rootDir), "/");
00720         rootDir = t;
00721     }
00722 
00723     ts->rootDir = xstrdup(rootDir);
00724     ts->currDir = NULL;
00725     ts->chrootDone = 0;
00726 
00727     ts->addedPackages.delta = ts->delta;
00728     alCreate(&ts->addedPackages);
00729     ts->availablePackages.delta = ts->delta;
00730     alCreate(&ts->availablePackages);
00731 
00732     ts->orderAlloced = ts->delta;
00733     ts->orderCount = 0;
00734     ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order));
00735 
00736     return ts;
00737 }
00738 
00745 static void removePackage(rpmTransactionSet ts, int dboffset, int depends)
00746         /*@modifies ts @*/
00747 {
00748     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00749         ts->allocedRemovedPackages += ts->delta;
00750         ts->removedPackages = xrealloc(ts->removedPackages,
00751                 sizeof(int *) * ts->allocedRemovedPackages);
00752     }
00753 
00754     ts->removedPackages[ts->numRemovedPackages++] = dboffset;
00755 
00756     if (ts->orderCount == ts->orderAlloced) {
00757         ts->orderAlloced += ts->delta;
00758         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00759     }
00760 
00761     ts->order[ts->orderCount].type = TR_REMOVED;
00762     ts->order[ts->orderCount].u.removed.dboffset = dboffset;
00763     ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends;
00764 }
00765 
00766 int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
00767                         const void * key, int upgrade, rpmRelocation * relocs)
00768 {
00769     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00770     HFD_t hfd = headerFreeData;
00771     int ont, ovt;
00772     /* this is an install followed by uninstalls */
00773     const char * name;
00774     int count;
00775     const char ** obsoletes;
00776     int alNum;
00777 
00778     /*
00779      * FIXME: handling upgrades like this is *almost* okay. It doesn't
00780      * check to make sure we're upgrading to a newer version, and it
00781      * makes it difficult to generate a return code based on the number of
00782      * packages which failed.
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     ts->order[ts->orderCount].type = TR_ADDED;
00789     alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
00790                 ts->addedPackages.list;
00791     ts->order[ts->orderCount++].u.addedIndex = alNum;
00792 
00793     if (!upgrade || ts->rpmdb == NULL)
00794         return 0;
00795 
00796     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00797     if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00798         return 0;
00799 
00800     headerNVR(h, &name, NULL, NULL);
00801 
00802     {   rpmdbMatchIterator mi;
00803         Header h2;
00804 
00805         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
00806         while((h2 = rpmdbNextIterator(mi)) != NULL) {
00807             if (rpmVersionCompare(h, h2))
00808                 removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00809             else {
00810                 uint_32 *p, multiLibMask = 0, oldmultiLibMask = 0;
00811 
00812                 if (hge(h2, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00813                     oldmultiLibMask = *p;
00814                 if (hge(h, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00815                     multiLibMask = *p;
00816                 if (oldmultiLibMask && multiLibMask
00817                     && !(oldmultiLibMask & multiLibMask)) {
00818                     ts->addedPackages.list[alNum].multiLib = multiLibMask;
00819                 }
00820             }
00821         }
00822         rpmdbFreeIterator(mi);
00823     }
00824 
00825     if (hge(h, RPMTAG_OBSOLETENAME, &ont, (void **) &obsoletes, &count)) {
00826         const char **obsoletesEVR;
00827         int_32 *obsoletesFlags;
00828         int j;
00829 
00830         hge(h, RPMTAG_OBSOLETEVERSION, &ovt, (void **) &obsoletesEVR, NULL);
00831         hge(h, RPMTAG_OBSOLETEFLAGS, NULL, (void **) &obsoletesFlags, NULL);
00832 
00833         for (j = 0; j < count; j++) {
00834 
00835             /* XXX avoid self-obsoleting packages. */
00836             if (!strcmp(name, obsoletes[j]))
00837                 continue;
00838 
00839           { rpmdbMatchIterator mi;
00840             Header h2;
00841 
00842             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, obsoletes[j], 0);
00843 
00844             rpmdbPruneIterator(mi,
00845                 ts->removedPackages, ts->numRemovedPackages, 1);
00846 
00847             while((h2 = rpmdbNextIterator(mi)) != NULL) {
00848                 /*
00849                  * Rpm prior to 3.0.3 does not have versioned obsoletes.
00850                  * If no obsoletes version info is available, match all names.
00851                  */
00852                 if (obsoletesEVR == NULL ||
00853                     headerMatchesDepFlags(h2,
00854                         obsoletes[j], obsoletesEVR[j], obsoletesFlags[j]))
00855                 {
00856                     removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00857                 }
00858             }
00859             rpmdbFreeIterator(mi);
00860           }
00861         }
00862 
00863         obsoletesEVR = hfd(obsoletesEVR, ovt);
00864         obsoletes = hfd(obsoletes, ont);
00865     }
00866 
00867     return 0;
00868 }
00869 
00870 void rpmtransAvailablePackage(rpmTransactionSet ts, Header h, const void * key)
00871 {
00872     struct availablePackage * al;
00873     al = alAddPackage(&ts->availablePackages, h, key, NULL, NULL);
00874 }
00875 
00876 void rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
00877 {
00878     removePackage(ts, dboffset, -1);
00879 }
00880 
00881 void rpmtransFree(rpmTransactionSet ts)
00882 {
00883     alFree(&ts->addedPackages);
00884     alFree(&ts->availablePackages);
00885     ts->di = _free(ts->di);
00886     ts->removedPackages = _free(ts->removedPackages);
00887     ts->order = _free(ts->order);
00888     if (ts->scriptFd)
00889         ts->scriptFd = fdFree(ts->scriptFd, "rpmtransSetScriptFd (rpmtransFree");
00890     ts->rootDir = _free(ts->rootDir);
00891     ts->currDir = _free(ts->currDir);
00892 
00893     ts = _free(ts);
00894 }
00895 
00896 void rpmdepFreeConflicts(struct rpmDependencyConflict * conflicts,
00897                         int numConflicts)
00898 {
00899     int i;
00900 
00901     for (i = 0; i < numConflicts; i++) {
00902         headerFree(conflicts[i].byHeader);
00903         conflicts[i].byName = _free(conflicts[i].byName);
00904         conflicts[i].byVersion = _free(conflicts[i].byVersion);
00905         conflicts[i].byRelease = _free(conflicts[i].byRelease);
00906         conflicts[i].needsName = _free(conflicts[i].needsName);
00907         conflicts[i].needsVersion = _free(conflicts[i].needsVersion);
00908     }
00909 
00910     conflicts = _free(conflicts);
00911 }
00912 
00920 /*@dependent@*/ /*@null@*/ static struct availablePackage *
00921 alFileSatisfiesDepend(struct availableList * al,
00922         const char * keyType, const char * fileName)
00923 {
00924     int i;
00925     const char * dirName;
00926     const char * baseName;
00927     struct dirInfo dirNeedle;
00928     struct dirInfo * dirMatch;
00929 
00930     if (al->numDirs == 0)       /* Solaris 2.6 bsearch sucks down on this. */
00931         return NULL;
00932 
00933     {   char * chptr = xstrdup(fileName);
00934         dirName = chptr;
00935         chptr = strrchr(chptr, '/');
00936         chptr++;
00937         *chptr = '\0';
00938     }
00939 
00940     dirNeedle.dirName = (char *) dirName;
00941     dirNeedle.dirNameLen = strlen(dirName);
00942     dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs,
00943                        sizeof(dirNeedle), dirInfoCompare);
00944     dirName = _free(dirName);
00945     if (!dirMatch) return NULL;
00946 
00947     baseName = strrchr(fileName, '/') + 1;
00948 
00949     /* XXX FIXME: these file lists should be sorted and bsearched */
00950     for (i = 0; i < dirMatch->numFiles; i++) {
00951         if (!strcmp(dirMatch->files[i].baseName, baseName)) {
00952 
00953             /* If a file dependency would be satisfied by a file
00954                we are not going to install, skip it. */
00955             if (al->list[dirMatch->files[i].pkgNum].multiLib &&
00956                 !isFileMULTILIB(dirMatch->files[i].fileFlags))
00957                 continue;
00958 
00959             if (keyType)
00960                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
00961                             keyType, fileName);
00962             return al->list + dirMatch->files[i].pkgNum;
00963         }
00964     }
00965 
00966     return NULL;
00967 }
00968 
00979 /*@dependent@*/ /*@null@*/ static struct availablePackage * alSatisfiesDepend(
00980         struct availableList * al,
00981         const char * keyType, const char * keyDepend,
00982         const char * keyName, const char * keyEVR, int keyFlags)
00983 {
00984     struct availableIndexEntry needle, * match;
00985     struct availablePackage * p;
00986     int i, rc;
00987 
00988     if (*keyName == '/')
00989         return alFileSatisfiesDepend(al, keyType, keyName);
00990 
00991     if (!al->index.size) return NULL;
00992 
00993     needle.entry = keyName;
00994     needle.entryLen = strlen(keyName);
00995     match = bsearch(&needle, al->index.index, al->index.size,
00996                     sizeof(*al->index.index), indexcmp);
00997 
00998     if (match == NULL) return NULL;
00999 
01000     p = match->package;
01001     rc = 0;
01002     switch (match->type) {
01003     case IET_PROVIDES:
01004         for (i = 0; i < p->providesCount; i++) {
01005             const char *proEVR;
01006             int proFlags;
01007 
01008             /* Filter out provides that came along for the ride. */
01009             if (strcmp(p->provides[i], keyName))
01010                 continue;
01011 
01012             proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
01013             proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
01014             rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
01015                         keyName, keyEVR, keyFlags);
01016             if (rc) break;
01017         }
01018         if (keyType && keyDepend && rc)
01019             rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
01020                         keyType, keyDepend+2);
01021         break;
01022     }
01023 
01024     if (rc)
01025         return p;
01026 
01027     return NULL;
01028 }
01029 
01041 static int unsatisfiedDepend(rpmTransactionSet ts,
01042         const char * keyType, const char * keyDepend,
01043         const char * keyName, const char * keyEVR, int keyFlags,
01044         /*@out@*/ struct availablePackage ** suggestion)
01045 {
01046     static int _cacheDependsRC = 1;
01047     rpmdbMatchIterator mi;
01048     Header h;
01049     int rc = 0; /* assume dependency is satisfied */
01050 
01051     if (suggestion) *suggestion = NULL;
01052 
01053     /*
01054      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
01055      */
01056     if (_cacheDependsRC) {
01057         dbiIndex dbi;
01058         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01059         if (dbi == NULL)
01060             _cacheDependsRC = 0;
01061         else {
01062             DBC * dbcursor = NULL;
01063             size_t keylen = strlen(keyDepend);
01064             void * datap = NULL;
01065             size_t datalen = 0;
01066             int xx;
01067             xx = dbiCopen(dbi, &dbcursor, 0);
01068             xx = dbiGet(dbi, dbcursor, (void **)&keyDepend, &keylen, &datap, &datalen, 0);
01069             if (xx == 0 && datap && datalen == 4) {
01070                 memcpy(&rc, datap, datalen);
01071                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s %-3s (cached)\n"),
01072                         keyType, keyDepend, (rc ? "NO" : "YES"));
01073                 xx = dbiCclose(dbi, NULL, 0);
01074                 return rc;
01075             }
01076             xx = dbiCclose(dbi, dbcursor, 0);
01077         }
01078     }
01079 
01080 #ifndef DYING
01081   { const char * rcProvidesString;
01082     const char * start;
01083     int i;
01084 
01085     if (!(keyFlags & RPMSENSE_SENSEMASK) &&
01086         (rcProvidesString = rpmGetVar(RPMVAR_PROVIDES))) {
01087         i = strlen(keyName);
01088         while ((start = strstr(rcProvidesString, keyName))) {
01089             if (isspace(start[i]) || start[i] == '\0' || start[i] == ',') {
01090                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmrc provides)\n"),
01091                         keyType, keyDepend+2);
01092                 goto exit;
01093             }
01094             rcProvidesString = start + 1;
01095         }
01096     }
01097   }
01098 #endif
01099 
01100     /*
01101      * New features in rpm packaging implicitly add versioned dependencies
01102      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
01103      * Check those dependencies now.
01104      */
01105     if (!strncmp(keyName, "rpmlib(", sizeof("rpmlib(")-1)) {
01106         if (rpmCheckRpmlibProvides(keyName, keyEVR, keyFlags)) {
01107             rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmlib provides)\n"),
01108                         keyType, keyDepend+2);
01109             goto exit;
01110         }
01111         goto unsatisfied;
01112     }
01113 
01114     if (alSatisfiesDepend(&ts->addedPackages, keyType, keyDepend, keyName, keyEVR, keyFlags)) {
01115         goto exit;
01116     }
01117 
01118     /* XXX only the installer does not have the database open here. */
01119     if (ts->rpmdb != NULL) {
01120         if (*keyName == '/') {
01121             /* keyFlags better be 0! */
01122 
01123             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_BASENAMES, keyName, 0);
01124 
01125             rpmdbPruneIterator(mi,
01126                         ts->removedPackages, ts->numRemovedPackages, 1);
01127 
01128             while ((h = rpmdbNextIterator(mi)) != NULL) {
01129                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db files)\n"),
01130                         keyType, keyDepend+2);
01131                 rpmdbFreeIterator(mi);
01132                 goto exit;
01133             }
01134             rpmdbFreeIterator(mi);
01135         }
01136 
01137         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_PROVIDENAME, keyName, 0);
01138         rpmdbPruneIterator(mi,
01139                         ts->removedPackages, ts->numRemovedPackages, 1);
01140         while ((h = rpmdbNextIterator(mi)) != NULL) {
01141             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01142                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db provides)\n"),
01143                         keyType, keyDepend+2);
01144                 rpmdbFreeIterator(mi);
01145                 goto exit;
01146             }
01147         }
01148         rpmdbFreeIterator(mi);
01149 
01150 #ifndef DYING
01151         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, keyName, 0);
01152         rpmdbPruneIterator(mi,
01153                         ts->removedPackages, ts->numRemovedPackages, 1);
01154         while ((h = rpmdbNextIterator(mi)) != NULL) {
01155             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01156                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db package)\n"),
01157                         keyType, keyDepend+2);
01158                 rpmdbFreeIterator(mi);
01159                 goto exit;
01160             }
01161         }
01162         rpmdbFreeIterator(mi);
01163 #endif
01164 
01165     }
01166 
01167     if (suggestion)
01168         *suggestion = alSatisfiesDepend(&ts->availablePackages, NULL, NULL,
01169                                 keyName, keyEVR, keyFlags);
01170 
01171 unsatisfied:
01172     rpmMessage(RPMMESS_DEBUG, _("%s: %-45s NO\n"), keyType, keyDepend+2);
01173     rc = 1;     /* dependency is unsatisfied */
01174 
01175 exit:
01176     /*
01177      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01178      */
01179     if (_cacheDependsRC) {
01180         dbiIndex dbi;
01181         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01182         if (dbi == NULL) {
01183             _cacheDependsRC = 0;
01184         } else {
01185             DBC * dbcursor = NULL;
01186             int xx;
01187             xx = dbiCopen(dbi, &dbcursor, 0);
01188             xx = dbiPut(dbi, dbcursor, keyDepend, strlen(keyDepend), &rc, sizeof(rc), 0);
01189             if (xx)
01190                 _cacheDependsRC = 0;
01191 #if 0   /* XXX NOISY */
01192             else
01193                 rpmMessage(RPMMESS_DEBUG, _("%s: (%s, %s) added to Depends cache.\n"), keyType, keyDepend, (rc ? "NO" : "YES"));
01194 #endif
01195             xx = dbiCclose(dbi, dbcursor, 0);
01196         }
01197     }
01198     return rc;
01199 }
01200 
01201 static int checkPackageDeps(rpmTransactionSet ts, struct problemsSet * psp,
01202                 Header h, const char * keyName, uint_32 multiLib)
01203 {
01204     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01205     HFD_t hfd = headerFreeData;
01206     int rnt, rvt;
01207     int cnt, cvt;
01208     const char * name, * version, * release;
01209     const char ** requires;
01210     const char ** requiresEVR = NULL;
01211     int_32 * requireFlags = NULL;
01212     int requiresCount = 0;
01213     const char ** conflicts;
01214     const char ** conflictsEVR = NULL;
01215     int_32 * conflictFlags = NULL;
01216     int conflictsCount = 0;
01217     int type;
01218     int i, rc;
01219     int ourrc = 0;
01220     struct availablePackage * suggestion;
01221 
01222     headerNVR(h, &name, &version, &release);
01223 
01224     if (!hge(h, RPMTAG_REQUIRENAME, &rnt, (void **) &requires, &requiresCount)) {
01225         requiresCount = 0;
01226     } else {
01227         hge(h, RPMTAG_REQUIREFLAGS, &type, (void **) &requireFlags,
01228                  &requiresCount);
01229         hge(h, RPMTAG_REQUIREVERSION, &rvt,
01230                 (void **) &requiresEVR, &requiresCount);
01231     }
01232 
01233     for (i = 0; i < requiresCount && !ourrc; i++) {
01234         const char * keyDepend;
01235 
01236         /* Filter out requires that came along for the ride. */
01237         if (keyName && strcmp(keyName, requires[i]))
01238             continue;
01239 
01240         /* If this requirement comes from the core package only, not libraries,
01241            then if we're installing the libraries only, don't count it in. */
01242         if (multiLib && !isDependsMULTILIB(requireFlags[i]))
01243             continue;
01244 
01245         keyDepend = printDepend("R", requires[i], requiresEVR[i], requireFlags[i]);
01246 
01247         rc = unsatisfiedDepend(ts, " Requires", keyDepend,
01248                 requires[i], requiresEVR[i], requireFlags[i], &suggestion);
01249 
01250         switch (rc) {
01251         case 0:         /* requirements are satisfied. */
01252             break;
01253         case 1:         /* requirements are not satisfied. */
01254             rpmMessage(RPMMESS_DEBUG, _("package %s-%s-%s require not satisfied: %s\n"),
01255                     name, version, release, keyDepend+2);
01256 
01257             if (psp->num == psp->alloced) {
01258                 psp->alloced += 5;
01259                 psp->problems = xrealloc(psp->problems, sizeof(*psp->problems) *
01260                             psp->alloced);
01261             }
01262             psp->problems[psp->num].byHeader = headerLink(h);
01263             psp->problems[psp->num].byName = xstrdup(name);
01264             psp->problems[psp->num].byVersion = xstrdup(version);
01265             psp->problems[psp->num].byRelease = xstrdup(release);
01266             psp->problems[psp->num].needsName = xstrdup(requires[i]);
01267             psp->problems[psp->num].needsVersion = xstrdup(requiresEVR[i]);
01268             psp->problems[psp->num].needsFlags = requireFlags[i];
01269             psp->problems[psp->num].sense = RPMDEP_SENSE_REQUIRES;
01270 
01271             if (suggestion)
01272                 psp->problems[psp->num].suggestedPackage = suggestion->key;
01273             else
01274                 psp->problems[psp->num].suggestedPackage = NULL;
01275 
01276             psp->num++;
01277             break;
01278         case 2:         /* something went wrong! */
01279         default:
01280             ourrc = 1;
01281             break;
01282         }
01283         keyDepend = _free(keyDepend);
01284     }
01285 
01286     if (requiresCount) {
01287         requiresEVR = hfd(requiresEVR, rvt);
01288         requires = hfd(requires, rnt);
01289     }
01290 
01291     if (!hge(h, RPMTAG_CONFLICTNAME, &cnt, (void **)&conflicts, &conflictsCount))
01292     {
01293         conflictsCount = 0;
01294     } else {
01295         hge(h, RPMTAG_CONFLICTFLAGS, &type,
01296                 (void **) &conflictFlags, &conflictsCount);
01297         hge(h, RPMTAG_CONFLICTVERSION, &cvt,
01298                 (void **) &conflictsEVR, &conflictsCount);
01299     }
01300 
01301     for (i = 0; i < conflictsCount && !ourrc; i++) {
01302         const char * keyDepend;
01303 
01304         /* Filter out conflicts that came along for the ride. */
01305         if (keyName && strcmp(keyName, conflicts[i]))
01306             continue;
01307 
01308         /* If this requirement comes from the core package only, not libraries,
01309            then if we're installing the libraries only, don't count it in. */
01310         if (multiLib && !isDependsMULTILIB(conflictFlags[i]))
01311             continue;
01312 
01313         keyDepend = printDepend("C", conflicts[i], conflictsEVR[i], conflictFlags[i]);
01314 
01315         rc = unsatisfiedDepend(ts, "Conflicts", keyDepend,
01316                 conflicts[i], conflictsEVR[i], conflictFlags[i], NULL);
01317 
01318         /* 1 == unsatisfied, 0 == satsisfied */
01319         switch (rc) {
01320         case 0:         /* conflicts exist. */
01321             rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"),
01322                     name, keyDepend+2);
01323 
01324             if (psp->num == psp->alloced) {
01325                 psp->alloced += 5;
01326                 psp->problems = xrealloc(psp->problems,
01327                                         sizeof(*psp->problems) * psp->alloced);
01328             }
01329             psp->problems[psp->num].byHeader = headerLink(h);
01330             psp->problems[psp->num].byName = xstrdup(name);
01331             psp->problems[psp->num].byVersion = xstrdup(version);
01332             psp->problems[psp->num].byRelease = xstrdup(release);
01333             psp->problems[psp->num].needsName = xstrdup(conflicts[i]);
01334             psp->problems[psp->num].needsVersion = xstrdup(conflictsEVR[i]);
01335             psp->problems[psp->num].needsFlags = conflictFlags[i];
01336             psp->problems[psp->num].sense = RPMDEP_SENSE_CONFLICTS;
01337             psp->problems[psp->num].suggestedPackage = NULL;
01338 
01339             psp->num++;
01340             break;
01341         case 1:         /* conflicts don't exist. */
01342             break;
01343         case 2:         /* something went wrong! */
01344         default:
01345             ourrc = 1;
01346             break;
01347         }
01348         keyDepend = _free(keyDepend);
01349     }
01350 
01351     if (conflictsCount) {
01352         conflictsEVR = hfd(conflictsEVR, cvt);
01353         conflicts = hfd(conflicts, cnt);
01354     }
01355 
01356     return ourrc;
01357 }
01358 
01363 static int checkPackageSet(rpmTransactionSet ts, struct problemsSet * psp,
01364         const char * key, /*@only@*/ rpmdbMatchIterator mi)
01365 {
01366     Header h;
01367     int rc = 0;
01368 
01369     rpmdbPruneIterator(mi, ts->removedPackages, ts->numRemovedPackages, 1);
01370     while ((h = rpmdbNextIterator(mi)) != NULL) {
01371         if (checkPackageDeps(ts, psp, h, key, 0)) {
01372             rc = 1;
01373             break;
01374         }
01375     }
01376     rpmdbFreeIterator(mi);
01377 
01378     return rc;
01379 }
01380 
01384 static int checkDependentPackages(rpmTransactionSet ts,
01385                         struct problemsSet * psp, const char * key)
01386 {
01387     rpmdbMatchIterator mi;
01388     mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_REQUIRENAME, key, 0);
01389     return checkPackageSet(ts, psp, key, mi);
01390 }
01391 
01395 static int checkDependentConflicts(rpmTransactionSet ts,
01396                 struct problemsSet * psp, const char * key)
01397 {
01398     int rc = 0;
01399 
01400     if (ts->rpmdb) {    /* XXX is this necessary? */
01401         rpmdbMatchIterator mi;
01402         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_CONFLICTNAME, key, 0);
01403         rc = checkPackageSet(ts, psp, key, mi);
01404     }
01405 
01406     return rc;
01407 }
01408 
01409 /*
01410  * XXX Hack to remove known Red Hat dependency loops, will be removed
01411  * as soon as rpm's legacy permits.
01412  */
01413 #define DEPENDENCY_WHITEOUT
01414 
01415 #if defined(DEPENDENCY_WHITEOUT)
01416 static struct badDeps_s {
01417     const char * pname;
01418     const char * qname;
01419 } badDeps[] = {
01420     { "libtermcap", "bash" },
01421     { "modutils", "vixie-cron" },
01422     { "ypbind", "yp-tools" },
01423     { "ghostscript-fonts", "ghostscript" },
01424     /* 7.1 only */
01425     { "arts", "kdelibs-sound" },
01426     /* 7.0 only */
01427     { "pango-gtkbeta-devel", "pango-gtkbeta" },
01428     { "XFree86", "Mesa" },
01429     { "compat-glibc", "db2" },
01430     { "compat-glibc", "db1" },
01431     { "pam", "initscripts" },
01432     { "kernel", "initscripts" },
01433     { "initscripts", "sysklogd" },
01434     /* 6.2 */
01435     { "egcs-c++", "libstdc++" },
01436     /* 6.1 */
01437     { "pilot-link-devel", "pilot-link" },
01438     /* 5.2 */
01439     { "pam", "pamconfig" },
01440     { NULL, NULL }
01441 };
01442     
01443 static int ignoreDep(struct availablePackage * p, struct availablePackage * q)
01444 {
01445     struct badDeps_s *bdp;
01446 
01447     for (bdp = badDeps; bdp->pname != NULL; bdp++) {
01448         if (!strcmp(p->name, bdp->pname) && !strcmp(q->name, bdp->qname))
01449             return 1;
01450     }
01451     return 0;
01452 }
01453 #endif
01454 
01460 static void markLoop(struct tsortInfo * tsi, struct availablePackage * q)
01461 {
01462     struct availablePackage * p;
01463 
01464     while (tsi != NULL) {
01465         p = tsi->tsi_suc;
01466         tsi = tsi->tsi_next;
01467         if (p->tsi.tsi_pkg != NULL)
01468             continue;
01469         p->tsi.tsi_pkg = q;
01470         markLoop(p->tsi.tsi_next, p);
01471     }
01472 }
01473 
01474 static inline /*@observer@*/ const char * const identifyDepend(int_32 f) {
01475     if (isLegacyPreReq(f))
01476         return "PreReq:";
01477     f = _notpre(f);
01478     if (f & RPMSENSE_SCRIPT_PRE)
01479         return "Requires(pre):";
01480     if (f & RPMSENSE_SCRIPT_POST)
01481         return "Requires(post):";
01482     if (f & RPMSENSE_SCRIPT_PREUN)
01483         return "Requires(preun):";
01484     if (f & RPMSENSE_SCRIPT_POSTUN)
01485         return "Requires(postun):";
01486     if (f & RPMSENSE_SCRIPT_VERIFY)
01487         return "Requires(verify):";
01488     if (f & RPMSENSE_FIND_REQUIRES)
01489         return "Requires(auto):";
01490     return "Requires:";
01491 }
01492 
01504 static /*@owned@*/ /*@null@*/ const char *
01505 zapRelation(struct availablePackage * q, struct availablePackage * p,
01506         int zap, int * nzaps)
01507 {
01508     struct tsortInfo * tsi_prev;
01509     struct tsortInfo * tsi;
01510     const char *dp = NULL;
01511 
01512     if (q == NULL)
01513         return dp;
01514     for (tsi_prev = &q->tsi, tsi = q->tsi.tsi_next;
01515          tsi != NULL;
01516          tsi_prev = tsi, tsi = tsi->tsi_next)
01517     {
01518         int j;
01519 
01520         if (tsi->tsi_suc != p)
01521             continue;
01522         j = tsi->tsi_reqx;
01523         dp = printDepend( identifyDepend(p->requireFlags[j]),
01524                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01525 
01526         /*
01527          * XXX Attempt to unravel a dependency loop by eliminating PreReq's.
01528          * This hack "works" for the (relatively) more important autogenerated
01529          *      Requires: lib*.so.*
01530          * but may cause package %pre/%post scriptlets with, for example,
01531          *      PreReq: /bin/sh
01532          * to fail.
01533          */
01534         if (zap && !(p->requireFlags[j] & RPMSENSE_PREREQ)) {
01535             rpmMessage(RPMMESS_WARNING,
01536                         _("removing %s-%s-%s \"%s\" from tsort relations.\n"),
01537                         p->name, p->version, p->release, dp);
01538             p->tsi.tsi_count--;
01539             tsi_prev->tsi_next = tsi->tsi_next;
01540             tsi->tsi_next = NULL;
01541             tsi->tsi_suc = NULL;
01542             tsi = _free(tsi);
01543             if (nzaps)
01544                 (*nzaps)++;
01545             if (zap)
01546                 zap--;
01547         }
01548         break;
01549     }
01550     return dp;
01551 }
01552 
01561 static inline int addRelation( const rpmTransactionSet ts,
01562                 struct availablePackage * p, unsigned char * selected, int j)
01563 {
01564     struct availablePackage * q;
01565     struct tsortInfo * tsi;
01566     int matchNum;
01567 
01568     q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL,
01569                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01570 
01571     /* Ordering depends only on added package relations. */
01572     if (q == NULL)
01573         return 0;
01574 
01575     /* Avoid rpmlib feature dependencies. */
01576     if (!strncmp(p->requires[j], "rpmlib(", sizeof("rpmlib(")-1))
01577         return 0;
01578 
01579 #if defined(DEPENDENCY_WHITEOUT)
01580     /* Avoid certain dependency relations. */
01581     if (ignoreDep(p, q))
01582         return 0;
01583 #endif
01584 
01585     /* Avoid redundant relations. */
01586     /* XXX FIXME: add control bit. */
01587     matchNum = q - ts->addedPackages.list;
01588     if (selected[matchNum])
01589         return 0;
01590     selected[matchNum] = 1;
01591 
01592     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01593     p->tsi.tsi_count++;                 /* bump p predecessor count */
01594     if (p->depth <= q->depth)           /* Save max. depth in dependency tree */
01595         p->depth = q->depth + 1;
01596 
01597     tsi = xmalloc(sizeof(*tsi));
01598     tsi->tsi_suc = p;
01599     tsi->tsi_reqx = j;
01600     tsi->tsi_next = q->tsi.tsi_next;
01601     q->tsi.tsi_next = tsi;
01602     q->tsi.tsi_qcnt++;                  /* bump q successor count */
01603     return 0;
01604 }
01605 
01612 static int orderListIndexCmp(const void * one, const void * two)
01613 {
01614     int a = ((const struct orderListIndex *)one)->alIndex;
01615     int b = ((const struct orderListIndex *)two)->alIndex;
01616     return (a - b);
01617 }
01618 
01625 static void addQ(/*@kept@*/ struct availablePackage * p,
01626         /*@out@*/ struct availablePackage ** qp,
01627         /*@out@*/ struct availablePackage ** rp)
01628 {
01629     struct availablePackage *q, *qprev;
01630 
01631     if ((*rp) == NULL) {        /* 1st element */
01632         (*rp) = (*qp) = p;
01633         return;
01634     }
01635     for (qprev = NULL, q = (*qp); q != NULL; qprev = q, q = q->tsi.tsi_suc) {
01636         if (q->tsi.tsi_qcnt <= p->tsi.tsi_qcnt)
01637             break;
01638     }
01639     if (qprev == NULL) {        /* insert at beginning of list */
01640         p->tsi.tsi_suc = q;
01641         (*qp) = p;              /* new head */
01642     } else if (q == NULL) {     /* insert at end of list */
01643         qprev->tsi.tsi_suc = p;
01644         (*rp) = p;              /* new tail */
01645     } else {                    /* insert between qprev and q */
01646         p->tsi.tsi_suc = q;
01647         qprev->tsi.tsi_suc = p;
01648     }
01649 }
01650 
01651 int rpmdepOrder(rpmTransactionSet ts)
01652 {
01653     int npkgs = ts->addedPackages.size;
01654     int chainsaw = ts->transFlags & RPMTRANS_FLAG_CHAINSAW;
01655     struct availablePackage * p;
01656     struct availablePackage * q;
01657     struct availablePackage * r;
01658     struct tsortInfo * tsi;
01659     struct tsortInfo * tsi_next;
01660     int * ordering = alloca(sizeof(*ordering) * (npkgs + 1));
01661     int orderingCount = 0;
01662     unsigned char * selected = alloca(sizeof(*selected) * (npkgs + 1));
01663     int loopcheck;
01664     struct transactionElement * newOrder;
01665     int newOrderCount = 0;
01666     struct orderListIndex * orderList;
01667     int nrescans = 10;
01668     int _printed = 0;
01669     int qlen;
01670     int i, j;
01671 
01672     alMakeIndex(&ts->addedPackages);
01673     alMakeIndex(&ts->availablePackages);
01674 
01675     /* T1. Initialize. */
01676     loopcheck = npkgs;
01677 
01678     /* Record all relations. */
01679     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01680     for (i = 0, p = ts->addedPackages.list; i < npkgs; i++, p++) {
01681         int matchNum;
01682 
01683         if (p->requiresCount <= 0)
01684             continue;
01685 
01686         memset(selected, 0, sizeof(*selected) * npkgs);
01687 
01688         /* Avoid narcisstic relations. */
01689         matchNum = p - ts->addedPackages.list;
01690         selected[matchNum] = 1;
01691 
01692         /* T2. Next "q <- p" relation. */
01693 
01694         /* First, do pre-requisites. */
01695         for (j = 0; j < p->requiresCount; j++) {
01696 
01697             /* Skip if not %pre/%post requires or legacy prereq. */
01698 
01699             if (isErasePreReq(p->requireFlags[j]) ||
01700                 !( isInstallPreReq(p->requireFlags[j]) ||
01701                    isLegacyPreReq(p->requireFlags[j]) ))
01702                 continue;
01703 
01704             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01705             (void) addRelation(ts, p, selected, j);
01706 
01707         }
01708 
01709         /* Then do co-requisites. */
01710         for (j = 0; j < p->requiresCount; j++) {
01711 
01712             /* Skip if %pre/%post requires or legacy prereq. */
01713 
01714             if (isErasePreReq(p->requireFlags[j]) ||
01715                  ( isInstallPreReq(p->requireFlags[j]) ||
01716                    isLegacyPreReq(p->requireFlags[j]) ))
01717                 continue;
01718 
01719             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01720             (void) addRelation(ts, p, selected, j);
01721 
01722         }
01723     }
01724 
01725     /* Save predecessor count. */
01726     for (i = 0, p = ts->addedPackages.list; i < npkgs; i++, p++) {
01727         p->npreds = p->tsi.tsi_count;
01728     }
01729 
01730     /* T4. Scan for zeroes. */
01731     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages\n"));
01732 
01733 rescan:
01734     q = r = NULL;
01735     qlen = 0;
01736     for (i = 0, p = ts->addedPackages.list; i < npkgs; i++, p++) {
01737 
01738         /* Prefer packages in presentation order. */
01739         if (!chainsaw)
01740             p->tsi.tsi_qcnt = (npkgs - i);
01741 
01742         if (p->tsi.tsi_count != 0)
01743             continue;
01744         p->tsi.tsi_suc = NULL;
01745         addQ(p, &q, &r);
01746         qlen++;
01747     }
01748 
01749     /* T5. Output front of queue (T7. Remove from queue.) */
01750     for (; q != NULL; q = q->tsi.tsi_suc) {
01751 
01752        rpmMessage(RPMMESS_DEBUG, "%4d%4d%4d%4d %*s %s-%s-%s\n",
01753                         orderingCount, q->npreds, q->tsi.tsi_qcnt, q->depth,
01754                         2*q->depth, "",
01755                         q->name, q->version, q->release);
01756         ordering[orderingCount++] = q - ts->addedPackages.list;
01757         qlen--;
01758         loopcheck--;
01759 
01760         /* T6. Erase relations. */
01761         tsi_next = q->tsi.tsi_next;
01762         q->tsi.tsi_next = NULL;
01763         while ((tsi = tsi_next) != NULL) {
01764             tsi_next = tsi->tsi_next;
01765             tsi->tsi_next = NULL;
01766             p = tsi->tsi_suc;
01767             if ((--p->tsi.tsi_count) <= 0) {
01768                 /* XXX FIXME: add control bit. */
01769                 p->tsi.tsi_suc = NULL;
01770                 addQ(p, &q->tsi.tsi_suc, &r);
01771                 qlen++;
01772             }
01773             tsi = _free(tsi);
01774         }
01775         if (!_printed && loopcheck == qlen && q->tsi.tsi_suc != NULL) {
01776             _printed++;
01777             rpmMessage(RPMMESS_DEBUG,
01778                 _("========== successors only (presentation order)\n"));
01779         }
01780     }
01781 
01782     /* T8. End of process. Check for loops. */
01783     if (loopcheck != 0) {
01784         int nzaps;
01785 
01786         /* T9. Initialize predecessor chain. */
01787         nzaps = 0;
01788         for (i = 0, q = ts->addedPackages.list; i < npkgs; i++, q++) {
01789             q->tsi.tsi_pkg = NULL;
01790             q->tsi.tsi_reqx = 0;
01791             /* Mark packages already sorted. */
01792             if (q->tsi.tsi_count == 0)
01793                 q->tsi.tsi_count = -1;
01794         }
01795 
01796         /* T10. Mark all packages with their predecessors. */
01797         for (i = 0, q = ts->addedPackages.list; i < npkgs; i++, q++) {
01798             if ((tsi = q->tsi.tsi_next) == NULL)
01799                 continue;
01800             q->tsi.tsi_next = NULL;
01801             markLoop(tsi, q);
01802             q->tsi.tsi_next = tsi;
01803         }
01804 
01805         /* T11. Print all dependency loops. */
01806         for (i = 0, r = ts->addedPackages.list; i < npkgs; i++, r++) {
01807             int printed;
01808 
01809             printed = 0;
01810 
01811             /* T12. Mark predecessor chain, looking for start of loop. */
01812             for (q = r->tsi.tsi_pkg; q != NULL; q = q->tsi.tsi_pkg) {
01813                 if (q->tsi.tsi_reqx)
01814                     break;
01815                 q->tsi.tsi_reqx = 1;
01816             }
01817 
01818             /* T13. Print predecessor chain from start of loop. */
01819             while ((p = q) != NULL && (q = p->tsi.tsi_pkg) != NULL) {
01820                 const char * dp;
01821                 char buf[4096];
01822 
01823                 /* Unchain predecessor loop. */
01824                 p->tsi.tsi_pkg = NULL;
01825 
01826                 if (!printed) {
01827                     rpmMessage(RPMMESS_WARNING, _("LOOP:\n"));
01828                     printed = 1;
01829                 }
01830 
01831                 /* Find (and destroy if co-requisite) "q <- p" relation. */
01832                 dp = zapRelation(q, p, 1, &nzaps);
01833 
01834                 /* Print next member of loop. */
01835                 sprintf(buf, "%s-%s-%s", p->name, p->version, p->release);
01836                 rpmMessage(RPMMESS_WARNING, "    %-40s %s\n", buf, dp);
01837 
01838                 dp = _free((void *)dp);
01839             }
01840 
01841             /* Walk (and erase) linear part of predecessor chain as well. */
01842             for (p = r, q = r->tsi.tsi_pkg;
01843                  q != NULL;
01844                  p = q, q = q->tsi.tsi_pkg)
01845             {
01846                 /* Unchain linear part of predecessor loop. */
01847                 p->tsi.tsi_pkg = NULL;
01848                 p->tsi.tsi_reqx = 0;
01849             }
01850         }
01851 
01852         /* If a relation was eliminated, then continue sorting. */
01853         /* XXX FIXME: add control bit. */
01854         if (nzaps && nrescans-- > 0) {
01855             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
01856             goto rescan;
01857         }
01858         return 1;
01859     }
01860 
01861     /*
01862      * The order ends up as installed packages followed by removed packages,
01863      * with removes for upgrades immediately following the installation of
01864      * the new package. This would be easier if we could sort the
01865      * addedPackages array, but we store indexes into it in various places.
01866      */
01867     orderList = xmalloc(sizeof(*orderList) * npkgs);
01868     for (i = 0, j = 0; i < ts->orderCount; i++) {
01869         if (ts->order[i].type == TR_ADDED) {
01870             orderList[j].alIndex = ts->order[i].u.addedIndex;
01871             orderList[j].orIndex = i;
01872             j++;
01873         }
01874     }
01875     assert(j <= npkgs);
01876 
01877     qsort(orderList, npkgs, sizeof(*orderList), orderListIndexCmp);
01878 
01879     newOrder = xmalloc(sizeof(*newOrder) * ts->orderCount);
01880     for (i = 0, newOrderCount = 0; i < orderingCount; i++) {
01881         struct orderListIndex * needle, key;
01882 
01883         key.alIndex = ordering[i];
01884         needle = bsearch(&key, orderList, npkgs, sizeof(key),orderListIndexCmp);
01885         /* bsearch should never, ever fail */
01886 
01887         newOrder[newOrderCount++] = ts->order[needle->orIndex];
01888         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
01889             if (ts->order[j].type == TR_REMOVED &&
01890                 ts->order[j].u.removed.dependsOnIndex == needle->alIndex) {
01891                 newOrder[newOrderCount++] = ts->order[j];
01892             } else {
01893                 break;
01894             }
01895         }
01896     }
01897 
01898     for (i = 0; i < ts->orderCount; i++) {
01899         if (ts->order[i].type == TR_REMOVED &&
01900             ts->order[i].u.removed.dependsOnIndex == -1)  {
01901             newOrder[newOrderCount++] = ts->order[i];
01902         }
01903     }
01904     assert(newOrderCount == ts->orderCount);
01905 
01906     ts->order = _free(ts->order);
01907     ts->order = newOrder;
01908     ts->orderAlloced = ts->orderCount;
01909     orderList = _free(orderList);
01910 
01911     return 0;
01912 }
01913 
01914 int rpmdepCheck(rpmTransactionSet ts,
01915                 struct