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

Generated at Wed Mar 27 03:56:48 2002 for rpm by doxygen1.2.8.1 written by Dimitri van Heesch, © 1997-2001