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 }

Generated on Mon Dec 3 21:51:52 2007 for rpm by  doxygen 1.5.2