# lib/depends.c

Go to the documentation of this file.

    00001
    00005 /*@-exportheadervar@*/
    00006 /*@unused@*/ static int _depends_debug = 0;
    00007 /*@=exportheadervar@*/
    00008
    00009 #include "system.h"
    00010
    00011 #include <rpmlib.h>
    00012 #include <rpmmacro.h>           /* XXX for rpmExpand() */
    00013
    00014 #include "depends.h"
    00015 #include "rpmdb.h"              /* XXX response cache needs dbiOpen et al. */
    00016
    00017 #include "debug.h"
    00018
    00019 /*@access dbiIndex@*/           /* XXX compared with NULL */
    00020 /*@access dbiIndexSet@*/        /* XXX compared with NULL */
    00021 /*@access Header@*/             /* XXX compared with NULL */
    00022 /*@access FD_t@*/               /* XXX compared with NULL */
    00023 /*@access rpmdb@*/              /* XXX compared with NULL */
    00024 /*@access rpmdbMatchIterator@*/         /* XXX compared with NULL */
    00025 /*@access rpmTransactionSet@*/
    00026 /*@access rpmDependencyConflict@*/
    00027 /*@access availableList@*/
    00028
    00029 static int _cacheDependsRC = 1;
    00030
    00031 int headerNVR(Header h, const char **np, const char **vp, const char **rp)
    00032 {
    00033     int type;
    00034     int count;
    00035
    00036     if (np) {
    00037         if (!(headerGetEntry(h, RPMTAG_NAME, &type, (void **) np, &count)
    00038             && type == RPM_STRING_TYPE && count == 1))
    00039                 *np = NULL;
    00040     }
    00041     if (vp) {
    00042         if (!(headerGetEntry(h, RPMTAG_VERSION, &type, (void **) vp, &count)
    00043             && type == RPM_STRING_TYPE && count == 1))
    00044                 *vp = NULL;
    00045     }
    00046     if (rp) {
    00047         if (!(headerGetEntry(h, RPMTAG_RELEASE, &type, (void **) rp, &count)
    00048             && type == RPM_STRING_TYPE && count == 1))
    00049                 *rp = NULL;
    00050     }
    00051     return 0;
    00052 }
    00053
    00062 static /*@only@*/ char * printDepend(const char * depend, const char * key,
    00063                 const char * keyEVR, int keyFlags)
    00064         /*@*/
    00065 {
    00066     char * tbuf, * t;
    00067     size_t nb;
    00068
    00069     nb = 0;
    00070     if (depend) nb += strlen(depend) + 1;
    00071     if (key)    nb += strlen(key);
    00072     if (keyFlags & RPMSENSE_SENSEMASK) {
    00073         if (nb) nb++;
    00074         if (keyFlags & RPMSENSE_LESS)   nb++;
    00075         if (keyFlags & RPMSENSE_GREATER) nb++;
    00076         if (keyFlags & RPMSENSE_EQUAL)  nb++;
    00077     }
    00078     if (keyEVR && *keyEVR) {
    00079         if (nb) nb++;
    00080         nb += strlen(keyEVR);
    00081     }
    00082
    00083     t = tbuf = xmalloc(nb + 1);
    00084     if (depend) {
    00085         while(*depend != '\0')  *t++ = *depend++;
    00086         *t++ = ' ';
    00087     }
    00088     if (key)
    00089         while(*key != '\0')     *t++ = *key++;
    00090     if (keyFlags & RPMSENSE_SENSEMASK) {
    00091         if (t != tbuf)  *t++ = ' ';
    00092         if (keyFlags & RPMSENSE_LESS)   *t++ = '<';
    00093         if (keyFlags & RPMSENSE_GREATER) *t++ = '>';
    00094         if (keyFlags & RPMSENSE_EQUAL)  *t++ = '=';
    00095     }
    00096     if (keyEVR && *keyEVR) {
    00097         if (t != tbuf)  *t++ = ' ';
    00098         while(*keyEVR != '\0')  *t++ = *keyEVR++;
    00099     }
    00100     *t = '\0';
    00101     return tbuf;
    00102 }
    00103
    00104 #ifdef  UNUSED
    00105 static /*@only@*/ const char *buildEVR(int_32 *e, const char *v, const char *r)
    00106 {
    00107     const char *pEVR;
    00108     char *p;
    00109
    00110     pEVR = p = xmalloc(21 + strlen(v) + 1 + strlen(r) + 1);
    00111     *p = '\0';
    00112     if (e) {
    00113         sprintf(p, "%d:", *e);
    00114         while (*p)
    00115             p++;
    00116     }
    00117     (void) stpcpy( stpcpy( stpcpy(p, v) , "-") , r);
    00118     return pEVR;
    00119 }
    00120 #endif
    00121
    00122 struct orderListIndex {
    00123     int alIndex;
    00124     int orIndex;
    00125 };
    00126
    00131 static void alFreeIndex(availableList al)
    00132         /*@modifies al @*/
    00133 {
    00134     if (al->index.size) {
    00135         al->index.index = _free(al->index.index);
    00136         al->index.size = 0;
    00137     }
    00138 }
    00139
    00144 static void alCreate(availableList al)
    00145         /*@modifies al @*/
    00146 {
    00147     al->alloced = al->delta;
    00148     al->size = 0;
    00149     al->list = xcalloc(al->alloced, sizeof(*al->list));
    00150
    00151     al->index.index = NULL;
    00152     al->index.size = 0;
    00153
    00154     al->numDirs = 0;
    00155     al->dirs = NULL;
    00156 }
    00157
    00162 static void alFree(availableList al)
    00163         /*@modifies al @*/
    00164 {
    00165     HFD_t hfd = headerFreeData;
    00166     struct availablePackage * p;
    00167     rpmRelocation * r;
    00168     int i;
    00169
    00170     if ((p = al->list) != NULL)
    00171     for (i = 0; i < al->size; i++, p++) {
    00172
    00173         {   tsortInfo tsi;
    00174             while ((tsi = p->tsi.tsi_next) != NULL) {
    00175                 p->tsi.tsi_next = tsi->tsi_next;
    00176                 tsi->tsi_next = NULL;
    00177                 tsi = _free(tsi);
    00178             }
    00179         }
    00180
    00181         p->provides = hfd(p->provides, -1);
    00182         p->providesEVR = hfd(p->providesEVR, -1);
    00183         p->requires = hfd(p->requires, -1);
    00184         p->requiresEVR = hfd(p->requiresEVR, -1);
    00185         p->baseNames = hfd(p->baseNames, -1);
    00186         p->h = headerFree(p->h);
    00187
    00188         if (p->relocs) {
    00189             for (r = p->relocs; (r->oldPath || r->newPath); r++) {
    00190                 r->oldPath = _free(r->oldPath);
    00191                 r->newPath = _free(r->newPath);
    00192             }
    00193             p->relocs = _free(p->relocs);
    00194         }
    00195         if (p->fd != NULL)
    00196             p->fd = fdFree(p->fd, "alAddPackage (alFree)");
    00197     }
    00198
    00199     if (al->dirs != NULL)
    00200     for (i = 0; i < al->numDirs; i++) {
    00201         al->dirs[i].dirName = _free(al->dirs[i].dirName);
    00202         al->dirs[i].files = _free(al->dirs[i].files);
    00203     }
    00204
    00205     al->dirs = _free(al->dirs);
    00206     al->numDirs = 0;
    00207     al->list = _free(al->list);
    00208     al->alloced = 0;
    00209     alFreeIndex(al);
    00210 }
    00211
    00218 static int dirInfoCompare(const void * one, const void * two)   /*@*/
    00219 {
    00220     const dirInfo a = (const dirInfo) one;
    00221     const dirInfo b = (const dirInfo) two;
    00222     int lenchk = a->dirNameLen - b->dirNameLen;
    00223
    00224     if (lenchk)
    00225         return lenchk;
    00226
    00227     /* XXX FIXME: this might do "backward" strcmp for speed */
    00228     return strcmp(a->dirName, b->dirName);
    00229 }
    00230
    00240 static /*@exposed@*/ struct availablePackage *
    00241 alAddPackage(availableList al,
    00242                 Header h, /*@null@*/ /*@dependent@*/ const void * key,
    00243                 /*@null@*/ FD_t fd, /*@null@*/ rpmRelocation * relocs)
    00244         /*@modifies al, h @*/
    00245 {
    00246     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00247     HFD_t hfd = headerFreeData;
    00248     rpmTagType dnt, bnt;
    00249     struct availablePackage * p;
    00250     rpmRelocation * r;
    00251     int i;
    00252     int_32 * dirIndexes;
    00253     const char ** dirNames;
    00254     int numDirs, dirNum;
    00255     int * dirMapping;
    00256     struct dirInfo_s dirNeedle;
    00257     dirInfo dirMatch;
    00258     int first, last, fileNum;
    00259     int origNumDirs;
    00260     int pkgNum;
    00261     uint_32 multiLibMask = 0;
    00262     uint_32 * fileFlags = NULL;
    00263     uint_32 * pp = NULL;
    00264
    00265     if (al->size == al->alloced) {
    00266         al->alloced += al->delta;
    00267         al->list = xrealloc(al->list, sizeof(*al->list) * al->alloced);
    00268     }
    00269
    00270     pkgNum = al->size++;
    00271     p = al->list + pkgNum;
    00272     p->h = headerLink(h);       /* XXX reference held by transaction set */
    00273     p->depth = p->npreds = 0;
    00274     memset(&p->tsi, 0, sizeof(p->tsi));
    00275     p->multiLib = 0;    /* MULTILIB */
    00276
    00277     (void) headerNVR(p->h, &p->name, &p->version, &p->release);
    00278
    00279     /* XXX This should be added always so that packages look alike.
    00280      * XXX However, there is logic in files.c/depends.c that checks for
    00281      * XXX existence (rather than value) that will need to change as well.
    00282      */
    00283     if (hge(p->h, RPMTAG_MULTILIBS, NULL, (void **) &pp, NULL))
    00284         multiLibMask = *pp;
    00285
    00286     if (multiLibMask) {
    00287         for (i = 0; i < pkgNum - 1; i++) {
    00288             if (!strcmp (p->name, al->list[i].name)
    00289                 && hge(al->list[i].h, RPMTAG_MULTILIBS, NULL,
    00290                                   (void **) &pp, NULL)
    00291                 && !rpmVersionCompare(p->h, al->list[i].h)
    00292                 && *pp && !(*pp & multiLibMask))
    00293                     p->multiLib = multiLibMask;
    00294         }
    00295     }
    00296
    00297     if (!hge(h, RPMTAG_EPOCH, NULL, (void **) &p->epoch, NULL))
    00298         p->epoch = NULL;
    00299
    00300     if (!hge(h, RPMTAG_PROVIDENAME, NULL, (void **) &p->provides,
    00301         &p->providesCount)) {
    00302         p->providesCount = 0;
    00303         p->provides = NULL;
    00304         p->providesEVR = NULL;
    00305         p->provideFlags = NULL;
    00306     } else {
    00307         if (!hge(h, RPMTAG_PROVIDEVERSION,
    00308                         NULL, (void **) &p->providesEVR, NULL))
    00309             p->providesEVR = NULL;
    00310         if (!hge(h, RPMTAG_PROVIDEFLAGS,
    00311                         NULL, (void **) &p->provideFlags, NULL))
    00312             p->provideFlags = NULL;
    00313     }
    00314
    00315     if (!hge(h, RPMTAG_REQUIRENAME, NULL, (void **) &p->requires,
    00316         &p->requiresCount)) {
    00317         p->requiresCount = 0;
    00318         p->requires = NULL;
    00319         p->requiresEVR = NULL;
    00320         p->requireFlags = NULL;
    00321     } else {
    00322         if (!hge(h, RPMTAG_REQUIREVERSION,
    00323                         NULL, (void **) &p->requiresEVR, NULL))
    00324             p->requiresEVR = NULL;
    00325         if (!hge(h, RPMTAG_REQUIREFLAGS,
    00326                         NULL, (void **) &p->requireFlags, NULL))
    00327             p->requireFlags = NULL;
    00328     }
    00329
    00330     if (!hge(h, RPMTAG_BASENAMES, &bnt, (void **)&p->baseNames, &p->filesCount))
    00331     {
    00332         p->filesCount = 0;
    00333         p->baseNames = NULL;
    00334     } else {
    00335         (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, &numDirs);
    00336         (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes, NULL);
    00337         (void) hge(h, RPMTAG_FILEFLAGS, NULL, (void **) &fileFlags, NULL);
    00338
    00339         /* XXX FIXME: We ought to relocate the directory list here */
    00340
    00341         dirMapping = alloca(sizeof(*dirMapping) * numDirs);
    00342
    00343         /* allocated enough space for all the directories we could possible
    00344            need to add */
    00345         al->dirs = xrealloc(al->dirs,
    00346                             sizeof(*al->dirs) * (al->numDirs + numDirs));
    00347         origNumDirs = al->numDirs;
    00348
    00349         for (dirNum = 0; dirNum < numDirs; dirNum++) {
    00350             dirNeedle.dirName = (char *) dirNames[dirNum];
    00351             dirNeedle.dirNameLen = strlen(dirNames[dirNum]);
    00352             dirMatch = bsearch(&dirNeedle, al->dirs, origNumDirs,
    00353                                sizeof(dirNeedle), dirInfoCompare);
    00354             if (dirMatch) {
    00355                 dirMapping[dirNum] = dirMatch - al->dirs;
    00356             } else {
    00357                 dirMapping[dirNum] = al->numDirs;
    00358                 al->dirs[al->numDirs].dirName = xstrdup(dirNames[dirNum]);
    00359                 al->dirs[al->numDirs].dirNameLen = strlen(dirNames[dirNum]);
    00360                 al->dirs[al->numDirs].files = NULL;
    00361                 al->dirs[al->numDirs].numFiles = 0;
    00362                 al->numDirs++;
    00363             }
    00364         }
    00365
    00366         dirNames = hfd(dirNames, dnt);
    00367
    00368         first = 0;
    00369         while (first < p->filesCount) {
    00370             last = first;
    00371             while ((last + 1) < p->filesCount) {
    00372                 if (dirIndexes[first] != dirIndexes[last + 1])
    00373                     /*@innerbreak@*/ break;
    00374                 last++;
    00375             }
    00376
    00377             dirMatch = al->dirs + dirMapping[dirIndexes[first]];
    00378             dirMatch->files = xrealloc(dirMatch->files,
    00379                 sizeof(*dirMatch->files) *
    00380                     (dirMatch->numFiles + last - first + 1));
    00381             if (p->baseNames != NULL)   /* XXX can't happen */
    00382             for (fileNum = first; fileNum <= last; fileNum++) {
    00383                 dirMatch->files[dirMatch->numFiles].baseName =
    00384                     p->baseNames[fileNum];
    00385                 dirMatch->files[dirMatch->numFiles].pkgNum = pkgNum;
    00386                 dirMatch->files[dirMatch->numFiles].fileFlags =
    00387                                 fileFlags[fileNum];
    00388                 dirMatch->numFiles++;
    00389             }
    00390
    00391             first = last + 1;
    00392         }
    00393
    00394         if (origNumDirs + al->numDirs)
    00395             qsort(al->dirs, al->numDirs, sizeof(dirNeedle), dirInfoCompare);
    00396
    00397     }
    00398
    00399     p->key = key;
    00400     p->fd = (fd != NULL ? fdLink(fd, "alAddPackage") : NULL);
    00401
    00402     if (relocs) {
    00403         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++)
    00404             {};
    00405         p->relocs = xmalloc((i + 1) * sizeof(*p->relocs));
    00406
    00407         for (i = 0, r = relocs; r->oldPath || r->newPath; i++, r++) {
    00408             p->relocs[i].oldPath = r->oldPath ? xstrdup(r->oldPath) : NULL;
    00409             p->relocs[i].newPath = r->newPath ? xstrdup(r->newPath) : NULL;
    00410         }
    00411         p->relocs[i].oldPath = NULL;
    00412         p->relocs[i].newPath = NULL;
    00413     } else {
    00414         p->relocs = NULL;
    00415     }
    00416
    00417     alFreeIndex(al);
    00418
    00419     return p;
    00420 }
    00421
    00428 static int indexcmp(const void * one, const void * two)         /*@*/
    00429 {
    00430     const struct availableIndexEntry * a = one;
    00431     const struct availableIndexEntry * b = two;
    00432     int lenchk = a->entryLen - b->entryLen;
    00433
    00434     if (lenchk)
    00435         return lenchk;
    00436
    00437     return strcmp(a->entry, b->entry);
    00438 }
    00439
    00444 static void alMakeIndex(availableList al)
    00445         /*@modifies al @*/
    00446 {
    00447     struct availableIndex * ai = &al->index;
    00448     int i, j, k;
    00449
    00450     if (ai->size || al->list == NULL) return;
    00451
    00452     for (i = 0; i < al->size; i++)
    00453         ai->size += al->list[i].providesCount;
    00454
    00455     if (ai->size) {
    00456         ai->index = xcalloc(ai->size, sizeof(*ai->index));
    00457
    00458         k = 0;
    00459         for (i = 0; i < al->size; i++) {
    00460             for (j = 0; j < al->list[i].providesCount; j++) {
    00461
    00462                 /* If multilib install, skip non-multilib provides. */
    00463                 if (al->list[i].multiLib &&
    00464                     !isDependsMULTILIB(al->list[i].provideFlags[j])) {
    00465                         ai->size--;
    00466                         continue;
    00467                 }
    00468
    00469                 ai->index[k].package = al->list + i;
    00470                 ai->index[k].entry = al->list[i].provides[j];
    00471                 ai->index[k].entryLen = strlen(al->list[i].provides[j]);
    00472                 ai->index[k].entryIx = j;
    00473                 ai->index[k].type = IET_PROVIDES;
    00474                 k++;
    00475             }
    00476         }
    00477
    00478         qsort(ai->index, ai->size, sizeof(*ai->index), indexcmp);
    00479     }
    00480 }
    00481
    00489 static void parseEVR(char * evr,
    00490                 /*@exposed@*/ /*@out@*/ const char ** ep,
    00491                 /*@exposed@*/ /*@out@*/ const char ** vp,
    00492                 /*@exposed@*/ /*@out@*/ const char ** rp)
    00493         /*@modifies *ep, *vp, *rp @*/
    00494 {
    00495     const char *epoch;
    00496     const char *version;                /* assume only version is present */
    00497     const char *release;
    00498     char *s, *se;
    00499
    00500     s = evr;
    00501     while (*s && xisdigit(*s)) s++;     /* s points to epoch terminator */
    00502     se = strrchr(s, '-');               /* se points to version terminator */
    00503
    00504     if (*s == ':') {
    00505         epoch = evr;
    00506         *s++ = '\0';
    00507         version = s;
    00508         if (*epoch == '\0') epoch = "0";
    00509     } else {
    00510         epoch = NULL;   /* XXX disable epoch compare if missing */
    00511         version = evr;
    00512     }
    00513     if (se) {
    00514         *se++ = '\0';
    00515         release = se;
    00516     } else {
    00517         release = NULL;
    00518     }
    00519
    00520     if (ep) *ep = epoch;
    00521     if (vp) *vp = version;
    00522     if (rp) *rp = release;
    00523 }
    00524
    00525 const char *rpmNAME = PACKAGE;
    00526 const char *rpmEVR = VERSION;
    00527 int rpmFLAGS = RPMSENSE_EQUAL;
    00528
    00529 int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
    00530         const char * BName, const char * BEVR, int BFlags)
    00531 {
    00532     const char *aDepend = printDepend(NULL, AName, AEVR, AFlags);
    00533     const char *bDepend = printDepend(NULL, BName, BEVR, BFlags);
    00534     char *aEVR, *bEVR;
    00535     const char *aE, *aV, *aR, *bE, *bV, *bR;
    00536     int result;
    00537     int sense;
    00538
    00539     /* Different names don't overlap. */
    00540     if (strcmp(AName, BName)) {
    00541         result = 0;
    00542         goto exit;
    00543     }
    00544
    00545     /* Same name. If either A or B is an existence test, always overlap. */
    00546     if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
    00547         result = 1;
    00548         goto exit;
    00549     }
    00550
    00551     /* If either EVR is non-existent or empty, always overlap. */
    00552     if (!(AEVR && *AEVR && BEVR && *BEVR)) {
    00553         result = 1;
    00554         goto exit;
    00555     }
    00556
    00557     /* Both AEVR and BEVR exist. */
    00558     aEVR = xstrdup(AEVR);
    00559     parseEVR(aEVR, &aE, &aV, &aR);
    00560     bEVR = xstrdup(BEVR);
    00561     parseEVR(bEVR, &bE, &bV, &bR);
    00562
    00563     /* Compare {A,B} [epoch:]version[-release] */
    00564     sense = 0;
    00565     if (aE && *aE && bE && *bE)
    00566         sense = rpmvercmp(aE, bE);
    00567     else if (aE && *aE && atol(aE) > 0) {
    00568         /* XXX legacy epoch-less requires/conflicts compatibility */
    00569         rpmMessage(RPMMESS_DEBUG, _("the \"B\" dependency needs an epoch (assuming same as \"A\")\n\tA %s\tB %s\n"),
    00570                 aDepend, bDepend);
    00571         sense = 0;
    00572     } else if (bE && *bE && atol(bE) > 0)
    00573         sense = -1;
    00574
    00575     if (sense == 0) {
    00576         sense = rpmvercmp(aV, bV);
    00577         if (sense == 0 && aR && *aR && bR && *bR) {
    00578             sense = rpmvercmp(aR, bR);
    00579         }
    00580     }
    00581     aEVR = _free(aEVR);
    00582     bEVR = _free(bEVR);
    00583
    00584     /* Detect overlap of {A,B} range. */
    00585     result = 0;
    00586     if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
    00587         result = 1;
    00588     } else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
    00589         result = 1;
    00590     } else if (sense == 0 &&
    00591         (((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
    00592          ((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
    00593          ((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
    00594         result = 1;
    00595     }
    00596
    00597 exit:
    00598     rpmMessage(RPMMESS_DEBUG, _("  %s    A %s\tB %s\n"),
    00599         (result ? _("YES") : _("NO ")), aDepend, bDepend);
    00600     aDepend = _free(aDepend);
    00601     bDepend = _free(bDepend);
    00602     return result;
    00603 }
    00604
    00605 /*@-typeuse@*/
    00606 typedef int (*dbrecMatch_t) (Header h, const char *reqName, const char * reqEVR, int reqFlags);
    00607 /*@=typeuse@*/
    00608
    00609 static int rangeMatchesDepFlags (Header h,
    00610                 const char * reqName, const char * reqEVR, int reqFlags)
    00611         /*@*/
    00612 {
    00613     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00614     HFD_t hfd = headerFreeData;
    00615     rpmTagType pnt, pvt;
    00616     const char ** provides;
    00617     const char ** providesEVR;
    00618     int_32 * provideFlags;
    00619     int providesCount;
    00620     int result;
    00621     int i;
    00622
    00623     if (!(reqFlags & RPMSENSE_SENSEMASK) || !reqEVR || !strlen(reqEVR))
    00624         return 1;
    00625
    00626     /* Get provides information from header */
    00627     /*
    00628      * Rpm prior to 3.0.3 does not have versioned provides.
    00629      * If no provides version info is available, match any requires.
    00630      */
    00631     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt,
    00632                 (void **) &providesEVR, &providesCount))
    00633         return 1;
    00634
    00635     (void) hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
    00636
    00637     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
    00638     {
    00639         providesEVR = hfd(providesEVR, pvt);
    00640         return 0;       /* XXX should never happen */
    00641     }
    00642
    00643     result = 0;
    00644     for (i = 0; i < providesCount; i++) {
    00645
    00646         /* Filter out provides that came along for the ride. */
    00647         if (strcmp(provides[i], reqName))
    00648             continue;
    00649
    00650         result = rpmRangesOverlap(provides[i], providesEVR[i], provideFlags[i],
    00651                         reqName, reqEVR, reqFlags);
    00652
    00653         /* If this provide matches the require, we're done. */
    00654         if (result)
    00655             break;
    00656     }
    00657
    00658     provides = hfd(provides, pnt);
    00659     providesEVR = hfd(providesEVR, pvt);
    00660
    00661     return result;
    00662 }
    00663
    00664 int headerMatchesDepFlags(Header h,
    00665                 const char * reqName, const char * reqEVR, int reqFlags)
    00666 {
    00667     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00668     const char *name, *version, *release;
    00669     int_32 * epoch;
    00670     const char *pkgEVR;
    00671     char *p;
    00672     int pkgFlags = RPMSENSE_EQUAL;
    00673
    00674     if (!((reqFlags & RPMSENSE_SENSEMASK) && reqEVR && *reqEVR))
    00675         return 1;
    00676
    00677     /* Get package information from header */
    00678     (void) headerNVR(h, &name, &version, &release);
    00679
    00680     pkgEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
    00681     *p = '\0';
    00682     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
    00683         sprintf(p, "%d:", *epoch);
    00684         while (*p != '\0')
    00685             p++;
    00686     }
    00687     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
    00688
    00689     return rpmRangesOverlap(name, pkgEVR, pkgFlags, reqName, reqEVR, reqFlags);
    00690 }
    00691
    00692 rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir)
    00693 {
    00694     rpmTransactionSet ts;
    00695     int rootLen;
    00696
    00697     if (!rootDir) rootDir = "";
    00698
    00699     ts = xcalloc(1, sizeof(*ts));
    00700     ts->filesystemCount = 0;
    00701     ts->filesystems = NULL;
    00702     ts->di = NULL;
    00703     /*@-assignexpose@*/
    00704     ts->rpmdb = rpmdb;
    00705     /*@=assignexpose@*/
    00706     ts->scriptFd = NULL;
    00707     ts->id = 0;
    00708     ts->delta = 5;
    00709
    00710     ts->numRemovedPackages = 0;
    00711     ts->allocedRemovedPackages = ts->delta;
    00712     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
    00713                         sizeof(*ts->removedPackages));
    00714
    00715     /* This canonicalizes the root */
    00716     rootLen = strlen(rootDir);
    00717     if (!(rootLen && rootDir[rootLen - 1] == '/')) {
    00718         char * t;
    00719
    00720         t = alloca(rootLen + 2);
    00721         *t = '\0';
    00722         (void) stpcpy( stpcpy(t, rootDir), "/");
    00723         rootDir = t;
    00724     }
    00725
    00726     ts->rootDir = xstrdup(rootDir);
    00727     ts->currDir = NULL;
    00728     ts->chrootDone = 0;
    00729
    00730     ts->addedPackages.delta = ts->delta;
    00731     alCreate(&ts->addedPackages);
    00732     ts->availablePackages.delta = ts->delta;
    00733     alCreate(&ts->availablePackages);
    00734
    00735     ts->orderAlloced = ts->delta;
    00736     ts->orderCount = 0;
    00737     ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order));
    00738
    00739     return ts;
    00740 }
    00741
    00748 static int intcmp(const void * a, const void * b)       /*@*/
    00749 {
    00750     const int * aptr = a;
    00751     const int * bptr = b;
    00752     int rc = (*aptr - *bptr);
    00753     return rc;
    00754 }
    00755
    00763 static int removePackage(rpmTransactionSet ts, int dboffset, int depends)
    00764         /*@modifies ts @*/
    00765 {
    00766
    00767     /* Filter out duplicate erasures. */
    00768     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
    00769         if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
    00770                         sizeof(int), intcmp) != NULL)
    00771             return 0;
    00772     }
    00773
    00774     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
    00775         ts->allocedRemovedPackages += ts->delta;
    00776         ts->removedPackages = xrealloc(ts->removedPackages,
    00777                 sizeof(int *) * ts->allocedRemovedPackages);
    00778     }
    00779
    00780     if (ts->removedPackages != NULL) {  /* XXX can't happen. */
    00781         ts->removedPackages[ts->numRemovedPackages++] = dboffset;
    00782         qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp);
    00783     }
    00784
    00785     if (ts->orderCount == ts->orderAlloced) {
    00786         ts->orderAlloced += ts->delta;
    00787         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
    00788     }
    00789
    00790     ts->order[ts->orderCount].type = TR_REMOVED;
    00791     ts->order[ts->orderCount].u.removed.dboffset = dboffset;
    00792     ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends;
    00793
    00794     return 0;
    00795 }
    00796
    00797 int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
    00798                         const void * key, int upgrade, rpmRelocation * relocs)
    00799 {
    00800     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    00801     HFD_t hfd = headerFreeData;
    00802     rpmTagType ont, ovt;
    00803     /* this is an install followed by uninstalls */
    00804     const char * name;
    00805     int count;
    00806     const char ** obsoletes;
    00807     int alNum;
    00808
    00809     /*
    00810      * FIXME: handling upgrades like this is *almost* okay. It doesn't
    00811      * check to make sure we're upgrading to a newer version, and it
    00812      * makes it difficult to generate a return code based on the number of
    00813      * packages which failed.
    00814      */
    00815     if (ts->orderCount == ts->orderAlloced) {
    00816         ts->orderAlloced += ts->delta;
    00817         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
    00818     }
    00819     ts->order[ts->orderCount].type = TR_ADDED;
    00820     if (ts->addedPackages.list == NULL)
    00821         return 0;
    00822
    00823     alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
    00824                 ts->addedPackages.list;
    00825     ts->order[ts->orderCount++].u.addedIndex = alNum;
    00826
    00827     if (!upgrade || ts->rpmdb == NULL)
    00828         return 0;
    00829
    00830     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
    00831     if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
    00832         return 0;
    00833
    00834     (void) headerNVR(h, &name, NULL, NULL);
    00835
    00836     {   rpmdbMatchIterator mi;
    00837         Header h2;
    00838
    00839         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
    00840         while((h2 = rpmdbNextIterator(mi)) != NULL) {
    00841             if (rpmVersionCompare(h, h2))
    00842                 (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
    00843             else {
    00844                 uint_32 *p, multiLibMask = 0, oldmultiLibMask = 0;
    00845
    00846                 if (hge(h2, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
    00847                     oldmultiLibMask = *p;
    00848                 if (hge(h, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
    00849                     multiLibMask = *p;
    00850                 if (oldmultiLibMask && multiLibMask
    00851                     && !(oldmultiLibMask & multiLibMask)) {
    00852                     ts->addedPackages.list[alNum].multiLib = multiLibMask;
    00853                 }
    00854             }
    00855         }
    00856         mi = rpmdbFreeIterator(mi);
    00857     }
    00858
    00859     if (hge(h, RPMTAG_OBSOLETENAME, &ont, (void **) &obsoletes, &count)) {
    00860         const char ** obsoletesEVR;
    00861         int_32 * obsoletesFlags;
    00862         int j;
    00863
    00864         (void) hge(h, RPMTAG_OBSOLETEVERSION, &ovt, (void **) &obsoletesEVR,
    00865                         NULL);
    00866         (void) hge(h, RPMTAG_OBSOLETEFLAGS, NULL, (void **) &obsoletesFlags,
    00867                         NULL);
    00868
    00869         for (j = 0; j < count; j++) {
    00870
    00871             /* XXX avoid self-obsoleting packages. */
    00872             if (!strcmp(name, obsoletes[j]))
    00873                 continue;
    00874
    00875           { rpmdbMatchIterator mi;
    00876             Header h2;
    00877
    00878             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, obsoletes[j], 0);
    00879
    00880             (void) rpmdbPruneIterator(mi,
    00881                 ts->removedPackages, ts->numRemovedPackages, 1);
    00882
    00883             while((h2 = rpmdbNextIterator(mi)) != NULL) {
    00884                 /*
    00885                  * Rpm prior to 3.0.3 does not have versioned obsoletes.
    00886                  * If no obsoletes version info is available, match all names.
    00887                  */
    00888                 if (obsoletesEVR == NULL ||
    00889                     headerMatchesDepFlags(h2,
    00890                         obsoletes[j], obsoletesEVR[j], obsoletesFlags[j]))
    00891                 {
    00892                     (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
    00893                 }
    00894             }
    00895             mi = rpmdbFreeIterator(mi);
    00896           }
    00897         }
    00898
    00899         obsoletesEVR = hfd(obsoletesEVR, ovt);
    00900         obsoletes = hfd(obsoletes, ont);
    00901     }
    00902
    00903     return 0;
    00904 }
    00905
    00906 void rpmtransAvailablePackage(rpmTransactionSet ts, Header h, const void * key)
    00907 {
    00908     struct availablePackage * al;
    00909     al = alAddPackage(&ts->availablePackages, h, key, NULL, NULL);
    00910 }
    00911
    00912 int rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
    00913 {
    00914     return removePackage(ts, dboffset, -1);
    00915 }
    00916
    00917 rpmTransactionSet rpmtransFree(rpmTransactionSet ts)
    00918 {
    00919     if (ts) {
    00920         alFree(&ts->addedPackages);
    00921         alFree(&ts->availablePackages);
    00922         ts->di = _free(ts->di);
    00923         ts->removedPackages = _free(ts->removedPackages);
    00924         ts->order = _free(ts->order);
    00925         if (ts->scriptFd != NULL)
    00926             ts->scriptFd =
    00927                 fdFree(ts->scriptFd, "rpmtransSetScriptFd (rpmtransFree");
    00928         ts->rootDir = _free(ts->rootDir);
    00929         ts->currDir = _free(ts->currDir);
    00930
    00931         ts = _free(ts);
    00932     }
    00933     return NULL;
    00934 }
    00935
    00936 rpmDependencyConflict rpmdepFreeConflicts(rpmDependencyConflict conflicts,
    00937                 int numConflicts)
    00938 {
    00939     int i;
    00940
    00941     if (conflicts)
    00942     for (i = 0; i < numConflicts; i++) {
    00943         conflicts[i].byHeader = headerFree(conflicts[i].byHeader);
    00944         conflicts[i].byName = _free(conflicts[i].byName);
    00945         conflicts[i].byVersion = _free(conflicts[i].byVersion);
    00946         conflicts[i].byRelease = _free(conflicts[i].byRelease);
    00947         conflicts[i].needsName = _free(conflicts[i].needsName);
    00948         conflicts[i].needsVersion = _free(conflicts[i].needsVersion);
    00949         conflicts[i].suggestedPackages = _free(conflicts[i].suggestedPackages);
    00950     }
    00951
    00952     return (conflicts = _free(conflicts));
    00953 }
    00954
    00962 static /*@only@*/ /*@null@*/ struct availablePackage **
    00963 alAllFileSatisfiesDepend(const availableList al,
    00964                 const char * keyType, const char * fileName)
    00965         /*@*/
    00966 {
    00967     int i, found;
    00968     const char * dirName;
    00969     const char * baseName;
    00970     struct dirInfo_s dirNeedle;
    00971     dirInfo dirMatch;
    00972     struct availablePackage ** ret;
    00973
    00974     /* Solaris 2.6 bsearch sucks down on this. */
    00975     if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
    00976         return NULL;
    00977
    00978     {   char * t;
    00979         dirName = t = xstrdup(fileName);
    00980         if ((t = strrchr(t, '/')) != NULL) {
    00981             t++;                /* leave the trailing '/' */
    00982             *t = '\0';
    00983         }
    00984     }
    00985
    00986     dirNeedle.dirName = (char *) dirName;
    00987     dirNeedle.dirNameLen = strlen(dirName);
    00988     dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs,
    00989                        sizeof(dirNeedle), dirInfoCompare);
    00990     if (dirMatch == NULL) {
    00991         dirName = _free(dirName);
    00992         return NULL;
    00993     }
    00994
    00995     /* rewind to the first match */
    00996     while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, &dirNeedle) == 0)
    00997         dirMatch--;
    00998
    00999     /*@-nullptrarith@*/         /* FIX: fileName NULL ??? */
    01000     baseName = strrchr(fileName, '/') + 1;
    01001     /*@=nullptrarith@*/
    01002
    01003     for (found = 0, ret = NULL;
    01004          dirMatch <= al->dirs + al->numDirs &&
    01005                 dirInfoCompare(dirMatch, &dirNeedle) == 0;
    01006          dirMatch++)
    01007     {
    01008         /* XXX FIXME: these file lists should be sorted and bsearched */
    01009         for (i = 0; i < dirMatch->numFiles; i++) {
    01010             if (dirMatch->files[i].baseName == NULL ||
    01011                         strcmp(dirMatch->files[i].baseName, baseName))
    01012                 continue;
    01013
    01014             /*
    01015              * If a file dependency would be satisfied by a file
    01016              * we are not going to install, skip it.
    01017              */
    01018             if (al->list[dirMatch->files[i].pkgNum].multiLib &&
    01019                         !isFileMULTILIB(dirMatch->files[i].fileFlags))
    01020                 continue;
    01021
    01022             if (keyType)
    01023                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
    01024                         keyType, fileName);
    01025
    01026             ret = xrealloc(ret, (found+2) * sizeof(*ret));
    01027             if (ret)    /* can't happen */
    01028                 ret[found++] = al->list + dirMatch->files[i].pkgNum;
    01029             /*@innerbreak@*/ break;
    01030         }
    01031     }
    01032
    01033     dirName = _free(dirName);
    01034     /*@-mods@*/         /* FIX: al->list might be modified. */
    01035     if (ret)
    01036         ret[found] = NULL;
    01037     /*@=mods@*/
    01038     return ret;
    01039 }
    01040
    01041 #ifdef  DYING
    01042
    01049 /*@unused@*/ static /*@dependent@*/ /*@null@*/ struct availablePackage *
    01050 alFileSatisfiesDepend(const availableList al,
    01051                 const char * keyType, const char * fileName)
    01052         /*@*/
    01053 {
    01054     struct availablePackage * ret;
    01055     struct availablePackage ** tmp =
    01056                 alAllFileSatisfiesDepend(al, keyType, fileName);
    01057
    01058     if (tmp) {
    01059         ret = tmp[0];
    01060         tmp = _free(tmp);
    01061         return ret;
    01062     }
    01063     return NULL;
    01064 }
    01065 #endif  /* DYING */
    01066
    01077 static /*@only@*/ /*@null@*/ struct availablePackage **
    01078 alAllSatisfiesDepend(const availableList al,
    01079                 const char * keyType, const char * keyDepend,
    01080                 const char * keyName, const char * keyEVR, int keyFlags)
    01081         /*@*/
    01082 {
    01083     struct availableIndexEntry needle, * match;
    01084     struct availablePackage * p, ** ret = NULL;
    01085     int i, rc, found;
    01086
    01087     if (*keyName == '/') {
    01088         ret = alAllFileSatisfiesDepend(al, keyType, keyName);
    01089         /* XXX Provides: /path was broken with added packages (#52183). */
    01090         if (ret != NULL && *ret != NULL)
    01091             return ret;
    01092     }
    01093
    01094     if (!al->index.size || al->index.index == NULL) return NULL;
    01095
    01096     needle.entry = keyName;
    01097     needle.entryLen = strlen(keyName);
    01098     match = bsearch(&needle, al->index.index, al->index.size,
    01099                     sizeof(*al->index.index), indexcmp);
    01100
    01101     if (match == NULL) return NULL;
    01102
    01103     /* rewind to the first match */
    01104     while (match > al->index.index && indexcmp(match-1, &needle) == 0)
    01105         match--;
    01106
    01107     for (ret = NULL, found = 0;
    01108          match <= al->index.index + al->index.size &&
    01109                 indexcmp(match, &needle) == 0;
    01110          match++)
    01111     {
    01112
    01113         p = match->package;
    01114         rc = 0;
    01115         switch (match->type) {
    01116         case IET_PROVIDES:
    01117             i = match->entryIx;
    01118             {   const char * proEVR;
    01119                 int proFlags;
    01120
    01121                 proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
    01122                 proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
    01123                 rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
    01124                                 keyName, keyEVR, keyFlags);
    01125                 if (rc)
    01126                     /*@switchbreak@*/ break;
    01127             }
    01128             if (keyType && keyDepend && rc)
    01129                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
    01130                                 keyType, keyDepend+2);
    01131             break;
    01132         }
    01133
    01134         if (rc) {
    01135             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
    01136             if (ret)    /* can't happen */
    01137                 ret[found++] = p;
    01138         }
    01139     }
    01140
    01141     if (ret)
    01142         ret[found] = NULL;
    01143
    01144     return ret;
    01145 }
    01146
    01158 static inline /*@only@*/ /*@null@*/ struct availablePackage *
    01159 alSatisfiesDepend(const availableList al,
    01160                 const char * keyType, const char * keyDepend,
    01161                 const char * keyName, const char * keyEVR, int keyFlags)
    01162         /*@*/
    01163 {
    01164     struct availablePackage * ret;
    01165     struct availablePackage ** tmp =
    01166         alAllSatisfiesDepend(al, keyType, keyDepend, keyName, keyEVR, keyFlags);
    01167
    01168     if (tmp) {
    01169         ret = tmp[0];
    01170         tmp = _free(tmp);
    01171         return ret;
    01172     }
    01173     return NULL;
    01174 }
    01175
    01188 static int unsatisfiedDepend(rpmTransactionSet ts,
    01189                 const char * keyType, const char * keyDepend,
    01190                 const char * keyName, const char * keyEVR, int keyFlags,
    01191                 /*@null@*/ /*@out@*/ struct availablePackage *** suggestion)
    01192         /*@modifies ts, *suggestion @*/
    01193 {
    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 struct badDeps_s {
    01615 /*@observer@*/ /*@null@*/ const char * pname;
    01616 /*@observer@*/ /*@null@*/ const char * qname;
    01617 };
    01618
    01619 #ifdef  DYING
    01620 static struct badDeps_s {
    01621 /*@observer@*/ /*@null@*/ const char * pname;
    01622 /*@observer@*/ /*@null@*/ const char * qname;
    01623 } badDeps[] = {
    01624     { "libtermcap", "bash" },
    01625     { "modutils", "vixie-cron" },
    01626     { "ypbind", "yp-tools" },
    01627     { "ghostscript-fonts", "ghostscript" },
    01628     /* 7.2 only */
    01629     { "libgnomeprint15", "gnome-print" },
    01630     { "nautilus", "nautilus-mozilla" },
    01631     /* 7.1 only */
    01632     { "arts", "kdelibs-sound" },
    01633     /* 7.0 only */
    01634     { "pango-gtkbeta-devel", "pango-gtkbeta" },
    01635     { "XFree86", "Mesa" },
    01636     { "compat-glibc", "db2" },
    01637     { "compat-glibc", "db1" },
    01638     { "pam", "initscripts" },
    01639     { "initscripts", "sysklogd" },
    01640     /* 6.2 */
    01641     { "egcs-c++", "libstdc++" },
    01642     /* 6.1 */
    01643     { "pilot-link-devel", "pilot-link" },
    01644     /* 5.2 */
    01645     { "pam", "pamconfig" },
    01646     { NULL, NULL }
    01647 };
    01648 #else
    01649 static struct badDeps_s * badDeps = NULL;
    01650 #endif
    01651
    01659 static int ignoreDep(const struct availablePackage * p,
    01660                 const struct availablePackage * q)
    01661         /*@*/
    01662 {
    01663     struct badDeps_s * bdp;
    01664     static int _initialized = 0;
    01665     const char ** av = NULL;
    01666     int ac = 0;
    01667
    01668     if (!_initialized) {
    01669         char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
    01670         int i;
    01671
    01672         if (s != NULL && *s != '\0'
    01673         && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
    01674         && ac > 0 && av != NULL)
    01675         {
    01676             bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
    01677             for (i = 0; i < ac; i++, bdp++) {
    01678                 char * p, * q;
    01679
    01680                 if (av[i] == NULL)
    01681                     break;
    01682                 p = xstrdup(av[i]);
    01683                 if ((q = strchr(p, '>')) != NULL)
    01684                     *q++ = '\0';
    01685                 bdp->pname = p;
    01686                 bdp->qname = q;
    01687                 rpmMessage(RPMMESS_DEBUG,
    01688                         _("ignore package name relation(s) [%d]\t%s -> %s\n"),
    01689                         i, bdp->pname, bdp->qname);
    01690             }
    01691             bdp->pname = bdp->qname = NULL;
    01692         }
    01693         av = _free(av);
    01694         s = _free(s);
    01695         _initialized++;
    01696     }
    01697
    01698     if (badDeps != NULL)
    01699     for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
    01700         if (!strcmp(p->name, bdp->pname) && !strcmp(q->name, bdp->qname))
    01701             return 1;
    01702     }
    01703     return 0;
    01704 }
    01705
    01711 static void markLoop(/*@special@*/ tsortInfo tsi,
    01712                 struct availablePackage * q)
    01713         /*@uses tsi @*/
    01714         /*@modifies internalState @*/
    01715 {
    01716     struct availablePackage * p;
    01717
    01718     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
    01719         tsi = tsi->tsi_next;
    01720         if (p->tsi.tsi_pkg != NULL)
    01721             continue;
    01722         p->tsi.tsi_pkg = q;
    01723         if (p->tsi.tsi_next != NULL)
    01724             markLoop(p->tsi.tsi_next, p);
    01725     }
    01726 }
    01727
    01728 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
    01729 {
    01730     if (isLegacyPreReq(f))
    01731         return "PreReq:";
    01732     f = _notpre(f);
    01733     if (f & RPMSENSE_SCRIPT_PRE)
    01734         return "Requires(pre):";
    01735     if (f & RPMSENSE_SCRIPT_POST)
    01736         return "Requires(post):";
    01737     if (f & RPMSENSE_SCRIPT_PREUN)
    01738         return "Requires(preun):";
    01739     if (f & RPMSENSE_SCRIPT_POSTUN)
    01740         return "Requires(postun):";
    01741     if (f & RPMSENSE_SCRIPT_VERIFY)
    01742         return "Requires(verify):";
    01743     if (f & RPMSENSE_FIND_REQUIRES)
    01744         return "Requires(auto):";
    01745     return "Requires:";
    01746 }
    01747
    01759 static /*@owned@*/ /*@null@*/ const char *
    01760 zapRelation(struct availablePackage * q, struct availablePackage * p,
    01761                 int zap, /*@in@*/ /*@out@*/ int * nzaps)
    01762         /*@modifies q, p, *nzaps @*/
    01763 {
    01764     tsortInfo tsi_prev;
    01765     tsortInfo tsi;
    01766     const char *dp = NULL;
    01767
    01768     for (tsi_prev = &q->tsi, tsi = q->tsi.tsi_next;
    01769          tsi != NULL;
    01770         /* XXX Note: the loop traverses "not found", break on "found". */
    01771         /*@-nullderef@*/
    01772          tsi_prev = tsi, tsi = tsi->tsi_next)
    01773         /*@=nullderef@*/
    01774     {
    01775         int j;
    01776
    01777         if (tsi->tsi_suc != p)
    01778             continue;
    01779         if (p->requires == NULL) continue;      /* XXX can't happen */
    01780         if (p->requireFlags == NULL) continue;  /* XXX can't happen */
    01781         if (p->requiresEVR == NULL) continue;   /* XXX can't happen */
    01782
    01783         j = tsi->tsi_reqx;
    01784         dp = printDepend( identifyDepend(p->requireFlags[j]),
    01785                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
    01786
    01787         /*
    01788          * Attempt to unravel a dependency loop by eliminating Requires's.
    01789          */
    01790         if (zap && !(p->requireFlags[j] & RPMSENSE_PREREQ)) {
    01791             rpmMessage(RPMMESS_DEBUG,
    01792                         _("removing %s-%s-%s \"%s\" from tsort relations.\n"),
    01793                         p->name, p->version, p->release, dp);
    01794             p->tsi.tsi_count--;
    01795             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
    01796             tsi->tsi_next = NULL;
    01797             tsi->tsi_suc = NULL;
    01798             tsi = _free(tsi);
    01799             if (nzaps)
    01800                 (*nzaps)++;
    01801             if (zap)
    01802                 zap--;
    01803         }
    01804         /* XXX Note: the loop traverses "not found", get out now! */
    01805         break;
    01806     }
    01807     return dp;
    01808 }
    01809
    01818 static inline int addRelation( const rpmTransactionSet ts,
    01819                 struct availablePackage * p, unsigned char * selected, int j)
    01820         /*@modifies p->tsi.tsi_u.count, p->depth, *selected @*/
    01821 {
    01822     struct availablePackage * q;
    01823     tsortInfo tsi;
    01824     int matchNum;
    01825
    01826     if (!p->requires || !p->requiresEVR || !p->requireFlags)
    01827         return 0;
    01828
    01829     q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL,
    01830                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
    01831
    01832     /* Ordering depends only on added package relations. */
    01833     if (q == NULL)
    01834         return 0;
    01835
    01836     /* Avoid rpmlib feature dependencies. */
    01837     if (!strncmp(p->requires[j], "rpmlib(", sizeof("rpmlib(")-1))
    01838         return 0;
    01839
    01840     /* Avoid certain dependency relations. */
    01841     if (ignoreDep(p, q))
    01842         return 0;
    01843
    01844     /* Avoid redundant relations. */
    01845     /* XXX TODO: add control bit. */
    01846     matchNum = q - ts->addedPackages.list;
    01847     if (selected[matchNum] != 0)
    01848         return 0;
    01849     selected[matchNum] = 1;
    01850
    01851     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
    01852     p->tsi.tsi_count++;                 /* bump p predecessor count */
    01853     if (p->depth <= q->depth)           /* Save max. depth in dependency tree */
    01854         p->depth = q->depth + 1;
    01855
    01856     tsi = xmalloc(sizeof(*tsi));
    01857     tsi->tsi_suc = p;
    01858     tsi->tsi_reqx = j;
    01859     tsi->tsi_next = q->tsi.tsi_next;
    01860     q->tsi.tsi_next = tsi;
    01861     q->tsi.tsi_qcnt++;                  /* bump q successor count */
    01862     return 0;
    01863 }
    01864
    01871 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
    01872 {
    01873     int a = ((const struct orderListIndex *)one)->alIndex;
    01874     int b = ((const struct orderListIndex *)two)->alIndex;
    01875     return (a - b);
    01876 }
    01877
    01884 static void addQ(struct availablePackage * p,
    01885                 /*@in@*/ /*@out@*/ struct availablePackage ** qp,
    01886                 /*@in@*/ /*@out@*/ struct availablePackage ** rp)
    01887         /*@modifies p->tsi, *qp, *rp @*/
    01888 {
    01889     struct availablePackage *q, *qprev;
    01890
    01891     /* Mark the package as queued. */
    01892     p->tsi.tsi_reqx = 1;
    01893
    01894     if ((*rp) == NULL) {        /* 1st element */
    01895         (*rp) = (*qp) = p;
    01896         return;
    01897     }
    01898     for (qprev = NULL, q = (*qp); q != NULL; qprev = q, q = q->tsi.tsi_suc) {
    01899         if (q->tsi.tsi_qcnt <= p->tsi.tsi_qcnt)
    01900             break;
    01901     }
    01902     if (qprev == NULL) {        /* insert at beginning of list */
    01903         p->tsi.tsi_suc = q;
    01904         (*qp) = p;              /* new head */
    01905     } else if (q == NULL) {     /* insert at end of list */
    01906         qprev->tsi.tsi_suc = p;
    01907         (*rp) = p;              /* new tail */
    01908     } else {                    /* insert between qprev and q */
    01909         p->tsi.tsi_suc = q;
    01910         qprev->tsi.tsi_suc = p;
    01911     }
    01912 }
    01913
    01914 int rpmdepOrder(rpmTransactionSet ts)
    01915 {
    01916     int npkgs = ts->addedPackages.size;
    01917 #ifdef  DYING
    01918     int chainsaw = ts->transFlags & RPMTRANS_FLAG_CHAINSAW;
    01919 #else
    01920     int chainsaw = 1;
    01921 #endif
    01922     struct availablePackage * p;
    01923     struct availablePackage * q;
    01924     struct availablePackage * r;
    01925     tsortInfo tsi;
    01926     tsortInfo tsi_next;
    01927     int * ordering = alloca(sizeof(*ordering) * (npkgs + 1));
    01928     int orderingCount = 0;
    01929     unsigned char * selected = alloca(sizeof(*selected) * (npkgs + 1));
    01930     int loopcheck;
    01931     transactionElement newOrder;
    01932     int newOrderCount = 0;
    01933     struct orderListIndex * orderList;
    01934     int nrescans = 10;
    01935     int _printed = 0;
    01936     int treex;
    01937     int depth;
    01938     int qlen;
    01939     int i, j;
    01940
    01941     alMakeIndex(&ts->addedPackages);
    01942     alMakeIndex(&ts->availablePackages);
    01943
    01944     /* T1. Initialize. */
    01945     loopcheck = npkgs;
    01946
    01947     /* Record all relations. */
    01948     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
    01949     if ((p = ts->addedPackages.list) != NULL)
    01950     for (i = 0; i < npkgs; i++, p++) {
    01951         int matchNum;
    01952
    01953         if (p->requiresCount <= 0)
    01954             continue;
    01955
    01956         memset(selected, 0, sizeof(*selected) * npkgs);
    01957
    01958         /* Avoid narcisstic relations. */
    01959         matchNum = p - ts->addedPackages.list;
    01960         selected[matchNum] = 1;
    01961
    01962         /* T2. Next "q <- p" relation. */
    01963
    01964         /* First, do pre-requisites. */
    01965         for (j = 0; j < p->requiresCount; j++) {
    01966
    01967             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
    01968
    01969             /* Skip if not %pre/%post requires or legacy prereq. */
    01970
    01971             if (isErasePreReq(p->requireFlags[j]) ||
    01972                 !( isInstallPreReq(p->requireFlags[j]) ||
    01973                    isLegacyPreReq(p->requireFlags[j]) ))
    01974                 continue;
    01975
    01976             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
    01977             (void) addRelation(ts, p, selected, j);
    01978
    01979         }
    01980
    01981         /* Then do co-requisites. */
    01982         for (j = 0; j < p->requiresCount; j++) {
    01983
    01984             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
    01985
    01986             /* Skip if %pre/%post requires or legacy prereq. */
    01987
    01988             if (isErasePreReq(p->requireFlags[j]) ||
    01989                  ( isInstallPreReq(p->requireFlags[j]) ||
    01990                    isLegacyPreReq(p->requireFlags[j]) ))
    01991                 continue;
    01992
    01993             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
    01994             (void) addRelation(ts, p, selected, j);
    01995
    01996         }
    01997     }
    01998
    01999     /* Save predecessor count and mark tree roots. */
    02000     treex = 0;
    02001     if ((p = ts->addedPackages.list) != NULL)
    02002     for (i = 0; i < npkgs; i++, p++) {
    02003         p->npreds = p->tsi.tsi_count;
    02004         p->tree = (p->npreds == 0 ? treex++ : -1);
    02005     }
    02006
    02007     /* T4. Scan for zeroes. */
    02008     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
    02009
    02010 rescan:
    02011     q = r = NULL;
    02012     qlen = 0;
    02013     if ((p = ts->addedPackages.list) != NULL)
    02014     for (i = 0; i < npkgs; i++, p++) {
    02015
    02016         /* Prefer packages in chainsaw or presentation order. */
    02017         if (!chainsaw)
    02018             p->tsi.tsi_qcnt = (npkgs - i);
    02019
    02020         if (p->tsi.tsi_count != 0)
    02021             continue;
    02022         p->tsi.tsi_suc = NULL;
    02023         addQ(p, &q, &r);
    02024         qlen++;
    02025     }
    02026
    02027     /* T5. Output front of queue (T7. Remove from queue.) */
    02028     for (; q != NULL; q = q->tsi.tsi_suc) {
    02029
    02030         /* Mark the package as unqueued. */
    02031         q->tsi.tsi_reqx = 0;
    02032
    02033         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s %s-%s-%s\n",
    02034                         orderingCount, q->npreds, q->tsi.tsi_qcnt,
    02035                         q->tree, q->depth,
    02036                         2*q->depth, "",
    02037                         q->name, q->version, q->release);
    02038
    02039         treex = q->tree;
    02040         depth = q->depth;
    02041         q->degree = 0;
    02042
    02043         ordering[orderingCount++] = q - ts->addedPackages.list;
    02044         qlen--;
    02045         loopcheck--;
    02046
    02047         /* T6. Erase relations. */
    02048         tsi_next = q->tsi.tsi_next;
    02049         q->tsi.tsi_next = NULL;
    02050         while ((tsi = tsi_next) != NULL) {
    02051             tsi_next = tsi->tsi_next;
    02052             tsi->tsi_next = NULL;
    02053             p = tsi->tsi_suc;
    02054             if (p && (--p->tsi.tsi_count) <= 0) {
    02055
    02056                 p->tree = treex;
    02057                 p->depth = depth + 1;
    02058                 p->parent = q;
    02059                 q->degree++;
    02060
    02061                 /* XXX TODO: add control bit. */
    02062                 p->tsi.tsi_suc = NULL;
    02063                 /*@-nullstate@*/        /* FIX: q->tsi.tsi_u.suc may be NULL */
    02064                 addQ(p, &q->tsi.tsi_suc, &r);
    02065                 /*@=nullstate@*/
    02066                 qlen++;
    02067             }
    02068             tsi = _free(tsi);
    02069         }
    02070         if (!_printed && loopcheck == qlen && q->tsi.tsi_suc != NULL) {
    02071             _printed++;
    02072             rpmMessage(RPMMESS_DEBUG,
    02073                 _("========== successors only (presentation order)\n"));
    02074
    02075             /* Relink the queue in presentation order. */
    02076             tsi = &q->tsi;
    02077             if ((p = ts->addedPackages.list) != NULL)
    02078             for (i = 0; i < npkgs; i++, p++) {
    02079                 /* Is this element in the queue? */
    02080                 if (p->tsi.tsi_reqx == 0)
    02081                     /*@innercontinue@*/ continue;
    02082                 tsi->tsi_suc = p;
    02083                 tsi = &p->tsi;
    02084             }
    02085             tsi->tsi_suc = NULL;
    02086         }
    02087     }
    02088
    02089     /* T8. End of process. Check for loops. */
    02090     if (loopcheck != 0) {
    02091         int nzaps;
    02092
    02093         /* T9. Initialize predecessor chain. */
    02094         nzaps = 0;
    02095         if ((q = ts->addedPackages.list) != NULL)
    02096         for (i = 0; i < npkgs; i++, q++) {
    02097             q->tsi.tsi_pkg = NULL;
    02098             q->tsi.tsi_reqx = 0;
    02099             /* Mark packages already sorted. */
    02100             if (q->tsi.tsi_count == 0)
    02101                 q->tsi.tsi_count = -1;
    02102         }
    02103
    02104         /* T10. Mark all packages with their predecessors. */
    02105         if ((q = ts->addedPackages.list) != NULL)
    02106         for (i = 0; i < npkgs; i++, q++) {
    02107             if ((tsi = q->tsi.tsi_next) == NULL)
    02108                 continue;
    02109             q->tsi.tsi_next = NULL;
    02110             markLoop(tsi, q);
    02111             q->tsi.tsi_next = tsi;
    02112         }
    02113
    02114         /* T11. Print all dependency loops. */
    02115         if ((r = ts->addedPackages.list) != NULL)
    02116         for (i = 0; i < npkgs; i++, r++) {
    02117             int printed;
    02118
    02119             printed = 0;
    02120
    02121             /* T12. Mark predecessor chain, looking for start of loop. */
    02122             for (q = r->tsi.tsi_pkg; q != NULL; q = q->tsi.tsi_pkg) {
    02123                 if (q->tsi.tsi_reqx)
    02124                     /*@innerbreak@*/ break;
    02125                 q->tsi.tsi_reqx = 1;
    02126             }
    02127
    02128             /* T13. Print predecessor chain from start of loop. */
    02129             while ((p = q) != NULL && (q = p->tsi.tsi_pkg) != NULL) {
    02130                 const char * dp;
    02131                 char buf[4096];
    02132
    02133                 /* Unchain predecessor loop. */
    02134                 p->tsi.tsi_pkg = NULL;
    02135
    02136                 if (!printed) {
    02137                     rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
    02138                     printed = 1;
    02139                 }
    02140
    02141                 /* Find (and destroy if co-requisite) "q <- p" relation. */
    02142                 dp = zapRelation(q, p, 1, &nzaps);
    02143
    02144                 /* Print next member of loop. */
    02145                 sprintf(buf, "%s-%s-%s", p->name, p->version, p->release);
    02146                 rpmMessage(RPMMESS_DEBUG, "    %-40s %s\n", buf,
    02147                         (dp ? dp : "not found!?!"));
    02148
    02149                 dp = _free(dp);
    02150             }
    02151
    02152             /* Walk (and erase) linear part of predecessor chain as well. */
    02153             for (p = r, q = r->tsi.tsi_pkg;
    02154                  q != NULL;
    02155                  p = q, q = q->tsi.tsi_pkg)
    02156             {
    02157                 /* Unchain linear part of predecessor loop. */
    02158                 p->tsi.tsi_pkg = NULL;
    02159                 p->tsi.tsi_reqx = 0;
    02160             }
    02161         }
    02162
    02163         /* If a relation was eliminated, then continue sorting. */
    02164         /* XXX TODO: add control bit. */
    02165         if (nzaps && nrescans-- > 0) {
    02166             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
    02167             goto rescan;
    02168         }
    02169         return 1;
    02170     }
    02171
    02172     /*
    02173      * The order ends up as installed packages followed by removed packages,
    02174      * with removes for upgrades immediately following the installation of
    02175      * the new package. This would be easier if we could sort the
    02176      * addedPackages array, but we store indexes into it in various places.
    02177      */
    02178     orderList = xmalloc(npkgs * sizeof(*orderList));
    02179     for (i = 0, j = 0; i < ts->orderCount; i++) {
    02180         if (ts->order[i].type == TR_ADDED) {
    02181             orderList[j].alIndex = ts->order[i].u.addedIndex;
    02182             orderList[j].orIndex = i;
    02183             j++;
    02184         }
    02185     }
    02186     assert(j <= npkgs);
    02187
    02188     qsort(orderList, npkgs, sizeof(*orderList), orderListIndexCmp);
    02189
    02190     newOrder = xmalloc(ts->orderCount * sizeof(*newOrder));
    02191     for (i = 0, newOrderCount = 0; i < orderingCount; i++) {
    02192         struct orderListIndex * needle, key;
    02193
    02194         key.alIndex = ordering[i];
    02195         needle = bsearch(&key, orderList, npkgs, sizeof(key),orderListIndexCmp);
    02196         /* bsearch should never, ever fail */
    02197         if (needle == NULL) continue;
    02198
    02199         newOrder[newOrderCount++] = ts->order[needle->orIndex];
    02200         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
    02201             if (ts->order[j].type == TR_REMOVED &&
    02202                 ts->order[j].u.removed.dependsOnIndex == needle->alIndex) {
    02203                 newOrder[newOrderCount++] = ts->order[j];
    02204             } else
    02205                 /*@innerbreak@*/ break;
    02206         }
    02207     }
    02208
    02209     for (i = 0; i < ts->orderCount; i++) {
    02210         if (ts->order[i].type == TR_REMOVED &&
    02211             ts->order[i].u.removed.dependsOnIndex == -1)  {
    02212             newOrder[newOrderCount++] = ts->order[i];
    02213         }
    02214     }
    02215     assert(newOrderCount == ts->orderCount);
    02216
    02217     ts->order = _free(ts->order);
    02218     ts->order = newOrder;
    02219     ts->orderAlloced = ts->orderCount;
    02220     orderList = _free(orderList);
    02221
    02222     return 0;
    02223 }
    02224
    02231 static int rpmdbCloseDBI(/*@null@*/ rpmdb db, int rpmtag)
    02232         /*@ modifies db, fileSystem @*/
    02233 {
    02234     int dbix;
    02235     int rc = 0;
    02236
    02237     if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
    02238         return 0;
    02239
    02240     for (dbix = 0; dbix < dbiTagsMax; dbix++) {
    02241         if (dbiTags[dbix] != rpmtag)
    02242             continue;
    02243         if (db->_dbi[dbix] != NULL) {
    02244             int xx;
    02245             /*@-unqualifiedtrans@*/             /* FIX: double indirection. */
    02246             xx = dbiClose(db->_dbi[dbix], 0);
    02247             if (xx && rc == 0) rc = xx;
    02248             db->_dbi[dbix] = NULL;
    02249             /*@=unqualifiedtrans@*/
    02250         }
    02251         break;
    02252     }
    02253     return rc;
    02254 }
    02255
    02256 int rpmdepCheck(rpmTransactionSet ts,
    02257                 rpmDependencyConflict * conflicts, int * numConflicts)
    02258 {
    02259     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
    02260     HFD_t hfd = headerFreeData;
    02261     rpmdbMatchIterator mi = NULL;
    02262     Header h = NULL;
    02263     struct availablePackage * p;
    02264     problemsSet ps;
    02265     int npkgs;
    02266     int i, j;
    02267     int rc;
    02268
    02269     npkgs = ts->addedPackages.size;
    02270
    02271     ps = xcalloc(1, sizeof(*ps));
    02272     ps->alloced = 5;
    02273     ps->num = 0;
    02274     ps->problems = xcalloc(ps->alloced, sizeof(*ps->problems));
    02275
    02276     *conflicts = NULL;
    02277     *numConflicts = 0;
    02278
    02279     alMakeIndex(&ts->addedPackages);
    02280     alMakeIndex(&ts->availablePackages);
    02281
    02282     /*
    02283      * Look at all of the added packages and make sure their dependencies
    02284      * are satisfied.
    02285      */
    02286     if ((p = ts->addedPackages.list) != NULL)
    02287     for (i = 0; i < npkgs; i++, p++)
    02288     {
    02289
    02290         rpmMessage(RPMMESS_DEBUG,  "========== +++ %s-%s-%s\n" ,
    02291                 p->name, p->version, p->release);
    02292         rc = checkPackageDeps(ts, ps, p->h, NULL, p->multiLib);
    02293         if (rc)
    02294             goto exit;
    02295
    02296         /* Adding: check name against conflicts matches. */
    02297         rc = checkDependentConflicts(ts, ps, p->name);
    02298         if (rc)
    02299             goto exit;
    02300
    02301         if (p->providesCount == 0 || p->provides == NULL)
    02302             continue;
    02303
    02304         rc = 0;
    02305         for (j = 0; j < p->providesCount; j++) {
    02306             /* Adding: check provides key against conflicts matches. */
    02307             if (!checkDependentConflicts(ts, ps, p->provides[j]))
    02308                 continue;
    02309             rc = 1;
    02310             /*@innerbreak@*/ break;
    02311         }
    02312         if (rc)
    02313             goto exit;
    02314     }
    02315
    02316     /*
    02317      * Look at the removed packages and make sure they aren't critical.
    02318      */
    02319     if (ts->numRemovedPackages > 0) {
    02320       mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
    02321       (void) rpmdbAppendIterator(mi,
    02322                         ts->removedPackages, ts->numRemovedPackages);
    02323       while ((h = rpmdbNextIterator(mi)) != NULL) {
    02324
    02325         {   const char * name, * version, * release;
    02326             (void) headerNVR(h, &name, &version, &release);
    02327             rpmMessage(RPMMESS_DEBUG,  "========== --- %s-%s-%s\n" ,
    02328                 name, version, release);
    02329
    02330             /* Erasing: check name against requiredby matches. */
    02331             rc = checkDependentPackages(ts, ps, name);
    02332             if (rc)
    02333                 goto exit;
    02334         }
    02335
    02336         {   const char ** provides;
    02337             int providesCount;
    02338             rpmTagType pnt;
    02339
    02340             if (hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides,
    02341                                 &providesCount))
    02342             {
    02343                 rc = 0;
    02344                 for (j = 0; j < providesCount; j++) {
    02345                     /* Erasing: check provides against requiredby matches. */
    02346                     if (!checkDependentPackages(ts, ps, provides[j]))
    02347                         continue;
    02348                     rc = 1;
    02349                     /*@innerbreak@*/ break;
    02350                 }
    02351                 provides = hfd(provides, pnt);
    02352                 if (rc)
    02353                     goto exit;
    02354             }
    02355         }
    02356
    02357         {   const char ** baseNames, ** dirNames;
    02358             int_32 * dirIndexes;
    02359             rpmTagType dnt, bnt;
    02360             int fileCount;
    02361             char * fileName = NULL;
    02362             int fileAlloced = 0;
    02363             int len;
    02364
    02365             if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
    02366             {
    02367                 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
    02368                 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes,
    02369                                 NULL);
    02370                 rc = 0;
    02371                 for (j = 0; j < fileCount; j++) {
    02372                     len = strlen(baseNames[j]) + 1 +
    02373                           strlen(dirNames[dirIndexes[j]]);
    02374                     if (len > fileAlloced) {
    02375                         fileAlloced = len * 2;
    02376                         fileName = xrealloc(fileName, fileAlloced);
    02377                     }
    02378                     *fileName = '\0';
    02379                     (void) stpcpy( stpcpy(fileName, dirNames[dirIndexes[j]]) , baseNames[j]);
    02380                     /* Erasing: check filename against requiredby matches. */
    02381                     if (!checkDependentPackages(ts, ps, fileName))
    02382                         continue;
    02383                     rc = 1;
    02384                     /*@innerbreak@*/ break;
    02385                 }
    02386
    02387                 fileName = _free(fileName);
    02388                 baseNames = hfd(baseNames, bnt);
    02389                 dirNames = hfd(dirNames, dnt);
    02390                 if (rc)
    02391                     goto exit;
    02392             }
    02393         }
    02394
    02395       }
    02396       mi = rpmdbFreeIterator(mi);
    02397     }
    02398
    02399     if (ps->num) {
    02400         *conflicts = ps->problems;
    02401         ps->problems = NULL;
    02402         *numConflicts = ps->num;
    02403     }
    02404     rc = 0;
    02405
    02406 exit:
    02407     mi = rpmdbFreeIterator(mi);
    02408     ps->problems = _free(ps->problems);
    02409     ps = _free(ps);
    02410     if (_cacheDependsRC)
    02411         (void) rpmdbCloseDBI(ts->rpmdb, RPMDBI_DEPENDS);
    02412     return rc;
    02413 }