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

lib/depends.c

Go to the documentation of this file.
00001 
00005 /*@-exportheadervar@*/
00006 /*@unused@*/ static int _depends_debug = 0;
00007 /*@=exportheadervar@*/
00008 
00009 #include "system.h"
00010 
00011 #include "rpmlib.h"
00012 #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 
00482 /* parseEVR() moved to rpmvercmp.c */
00483 
00484 const char *rpmNAME = PACKAGE;
00485 const char *rpmEVR = VERSION;
00486 int rpmFLAGS = RPMSENSE_EQUAL;
00487 
00488 int rpmRangesOverlap(const char * AName, const char * AEVR, int AFlags,
00489         const char * BName, const char * BEVR, int BFlags)
00490 {
00491     const char *aDepend = printDepend(NULL, AName, AEVR, AFlags);
00492     const char *bDepend = printDepend(NULL, BName, BEVR, BFlags);
00493     char *aEVR, *bEVR;
00494     const char *aE, *aV, *aR, *bE, *bV, *bR;
00495     int result;
00496     int sense;
00497 
00498     /* Different names don't overlap. */
00499     if (strcmp(AName, BName)) {
00500         result = 0;
00501         goto exit;
00502     }
00503 
00504     /* Same name. If either A or B is an existence test, always overlap. */
00505     if (!((AFlags & RPMSENSE_SENSEMASK) && (BFlags & RPMSENSE_SENSEMASK))) {
00506         result = 1;
00507         goto exit;
00508     }
00509 
00510     /* If either EVR is non-existent or empty, always overlap. */
00511     if (!(AEVR && *AEVR && BEVR && *BEVR)) {
00512         result = 1;
00513         goto exit;
00514     }
00515 
00516     /* Both AEVR and BEVR exist. */
00517     aEVR = xstrdup(AEVR);
00518     parseEVR(aEVR, &aE, &aV, &aR);
00519     bEVR = xstrdup(BEVR);
00520     parseEVR(bEVR, &bE, &bV, &bR);
00521     /* rpmEVRcmp() is also shared; the code moved to rpmvercmp.c */
00522     sense = rpmEVRcmp(aE, aV, aR, aDepend, bE, bV, bR, bDepend);
00523     aEVR = _free(aEVR);
00524     bEVR = _free(bEVR);
00525 
00526     /* Detect overlap of {A,B} range. */
00527     result = 0;
00528     if (sense < 0 && ((AFlags & RPMSENSE_GREATER) || (BFlags & RPMSENSE_LESS))) {
00529         result = 1;
00530     } else if (sense > 0 && ((AFlags & RPMSENSE_LESS) || (BFlags & RPMSENSE_GREATER))) {
00531         result = 1;
00532     } else if (sense == 0 &&
00533         (((AFlags & RPMSENSE_EQUAL) && (BFlags & RPMSENSE_EQUAL)) ||
00534          ((AFlags & RPMSENSE_LESS) && (BFlags & RPMSENSE_LESS)) ||
00535          ((AFlags & RPMSENSE_GREATER) && (BFlags & RPMSENSE_GREATER)))) {
00536         result = 1;
00537     }
00538 
00539 exit:
00540     rpmMessage(RPMMESS_DEBUG, _("  %s    A %s\tB %s\n"),
00541         (result ? _("YES") : _("NO ")), aDepend, bDepend);
00542     aDepend = _free(aDepend);
00543     bDepend = _free(bDepend);
00544     return result;
00545 }
00546 
00547 /*@-typeuse@*/
00548 typedef int (*dbrecMatch_t) (Header h, const char *reqName, const char * reqEVR, int reqFlags);
00549 /*@=typeuse@*/
00550 
00551 static int rangeMatchesDepFlags (Header h,
00552                 const char * reqName, const char * reqEVR, int reqFlags)
00553         /*@*/
00554 {
00555     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00556     HFD_t hfd = headerFreeData;
00557     rpmTagType pnt, pvt;
00558     const char ** provides;
00559     const char ** providesEVR;
00560     int_32 * provideFlags;
00561     int providesCount;
00562     int result;
00563     int i;
00564 
00565     if (!(reqFlags & RPMSENSE_SENSEMASK) || !reqEVR || !strlen(reqEVR))
00566         return 1;
00567 
00568     /* Get provides information from header */
00569     /*
00570      * Rpm prior to 3.0.3 does not have versioned provides.
00571      * If no provides version info is available, match any requires.
00572      */
00573     if (!hge(h, RPMTAG_PROVIDEVERSION, &pvt,
00574                 (void **) &providesEVR, &providesCount))
00575         return 1;
00576 
00577     (void) hge(h, RPMTAG_PROVIDEFLAGS, NULL, (void **) &provideFlags, NULL);
00578 
00579     if (!hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides, &providesCount))
00580     {
00581         providesEVR = hfd(providesEVR, pvt);
00582         return 0;       /* XXX should never happen */
00583     }
00584 
00585     result = 0;
00586     for (i = 0; i < providesCount; i++) {
00587 
00588         /* Filter out provides that came along for the ride. */
00589         if (strcmp(provides[i], reqName))
00590             continue;
00591 
00592         result = rpmRangesOverlap(provides[i], providesEVR[i], provideFlags[i],
00593                         reqName, reqEVR, reqFlags);
00594 
00595         /* If this provide matches the require, we're done. */
00596         if (result)
00597             break;
00598     }
00599 
00600     provides = hfd(provides, pnt);
00601     providesEVR = hfd(providesEVR, pvt);
00602 
00603     return result;
00604 }
00605 
00606 int headerMatchesDepFlags(Header h,
00607                 const char * reqName, const char * reqEVR, int reqFlags)
00608 {
00609     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00610     const char *name, *version, *release;
00611     int_32 * epoch;
00612     const char *pkgEVR;
00613     char *p;
00614     int pkgFlags = RPMSENSE_EQUAL;
00615 
00616     if (!((reqFlags & RPMSENSE_SENSEMASK) && reqEVR && *reqEVR))
00617         return 1;
00618 
00619     /* Get package information from header */
00620     (void) headerNVR(h, &name, &version, &release);
00621 
00622     pkgEVR = p = alloca(21 + strlen(version) + 1 + strlen(release) + 1);
00623     *p = '\0';
00624     if (hge(h, RPMTAG_EPOCH, NULL, (void **) &epoch, NULL)) {
00625         sprintf(p, "%d:", *epoch);
00626         while (*p != '\0')
00627             p++;
00628     }
00629     (void) stpcpy( stpcpy( stpcpy(p, version) , "-") , release);
00630 
00631     return rpmRangesOverlap(name, pkgEVR, pkgFlags, reqName, reqEVR, reqFlags);
00632 }
00633 
00634 rpmTransactionSet rpmtransCreateSet(rpmdb rpmdb, const char * rootDir)
00635 {
00636     rpmTransactionSet ts;
00637     int rootLen;
00638 
00639     if (!rootDir) rootDir = "";
00640 
00641     ts = xcalloc(1, sizeof(*ts));
00642     ts->filesystemCount = 0;
00643     ts->filesystems = NULL;
00644     ts->di = NULL;
00645     /*@-assignexpose@*/
00646     ts->rpmdb = rpmdb;
00647     /*@=assignexpose@*/
00648     ts->scriptFd = NULL;
00649     ts->id = 0;
00650     ts->delta = 5;
00651 
00652     ts->numRemovedPackages = 0;
00653     ts->allocedRemovedPackages = ts->delta;
00654     ts->removedPackages = xcalloc(ts->allocedRemovedPackages,
00655                         sizeof(*ts->removedPackages));
00656 
00657     /* This canonicalizes the root */
00658     rootLen = strlen(rootDir);
00659     if (!(rootLen && rootDir[rootLen - 1] == '/')) {
00660         char * t;
00661 
00662         t = alloca(rootLen + 2);
00663         *t = '\0';
00664         (void) stpcpy( stpcpy(t, rootDir), "/");
00665         rootDir = t;
00666     }
00667 
00668     ts->rootDir = xstrdup(rootDir);
00669     ts->currDir = NULL;
00670     ts->chrootDone = 0;
00671 
00672     ts->addedPackages.delta = ts->delta;
00673     alCreate(&ts->addedPackages);
00674     ts->availablePackages.delta = ts->delta;
00675     alCreate(&ts->availablePackages);
00676 
00677     ts->orderAlloced = ts->delta;
00678     ts->orderCount = 0;
00679     ts->order = xcalloc(ts->orderAlloced, sizeof(*ts->order));
00680 
00681     return ts;
00682 }
00683 
00690 static int intcmp(const void * a, const void * b)       /*@*/
00691 {
00692     const int * aptr = a;
00693     const int * bptr = b;
00694     int rc = (*aptr - *bptr);
00695     return rc;
00696 }
00697 
00705 static int removePackage(rpmTransactionSet ts, int dboffset, int depends)
00706         /*@modifies ts @*/
00707 {
00708 
00709     /* Filter out duplicate erasures. */
00710     if (ts->numRemovedPackages > 0 && ts->removedPackages != NULL) {
00711         if (bsearch(&dboffset, ts->removedPackages, ts->numRemovedPackages,
00712                         sizeof(int), intcmp) != NULL)
00713             return 0;
00714     }
00715 
00716     if (ts->numRemovedPackages == ts->allocedRemovedPackages) {
00717         ts->allocedRemovedPackages += ts->delta;
00718         ts->removedPackages = xrealloc(ts->removedPackages,
00719                 sizeof(int *) * ts->allocedRemovedPackages);
00720     }
00721 
00722     if (ts->removedPackages != NULL) {  /* XXX can't happen. */
00723         ts->removedPackages[ts->numRemovedPackages++] = dboffset;
00724         qsort(ts->removedPackages, ts->numRemovedPackages, sizeof(int), intcmp);
00725     }
00726 
00727     if (ts->orderCount == ts->orderAlloced) {
00728         ts->orderAlloced += ts->delta;
00729         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00730     }
00731 
00732     ts->order[ts->orderCount].type = TR_REMOVED;
00733     ts->order[ts->orderCount].u.removed.dboffset = dboffset;
00734     ts->order[ts->orderCount++].u.removed.dependsOnIndex = depends;
00735 
00736     return 0;
00737 }
00738 
00739 int rpmtransAddPackage(rpmTransactionSet ts, Header h, FD_t fd,
00740                         const void * key, int upgrade, rpmRelocation * relocs)
00741 {
00742     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00743     HFD_t hfd = headerFreeData;
00744     rpmTagType ont, ovt;
00745     /* this is an install followed by uninstalls */
00746     const char * name;
00747     int count;
00748     const char ** obsoletes;
00749     int alNum;
00750 
00751     /*
00752      * FIXME: handling upgrades like this is *almost* okay. It doesn't
00753      * check to make sure we're upgrading to a newer version, and it
00754      * makes it difficult to generate a return code based on the number of
00755      * packages which failed.
00756      */
00757     if (ts->orderCount == ts->orderAlloced) {
00758         ts->orderAlloced += ts->delta;
00759         ts->order = xrealloc(ts->order, sizeof(*ts->order) * ts->orderAlloced);
00760     }
00761     ts->order[ts->orderCount].type = TR_ADDED;
00762     if (ts->addedPackages.list == NULL)
00763         return 0;
00764 
00765     alNum = alAddPackage(&ts->addedPackages, h, key, fd, relocs) -
00766                 ts->addedPackages.list;
00767     ts->order[ts->orderCount++].u.addedIndex = alNum;
00768 
00769     if (!upgrade || ts->rpmdb == NULL)
00770         return 0;
00771 
00772     /* XXX binary rpms always have RPMTAG_SOURCERPM, source rpms do not */
00773     if (headerIsEntry(h, RPMTAG_SOURCEPACKAGE))
00774         return 0;
00775 
00776     (void) headerNVR(h, &name, NULL, NULL);
00777 
00778     {   rpmdbMatchIterator mi;
00779         Header h2;
00780 
00781         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, name, 0);
00782         while((h2 = rpmdbNextIterator(mi)) != NULL) {
00783             if (rpmVersionCompare(h, h2))
00784                 (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00785             else {
00786                 uint_32 *p, multiLibMask = 0, oldmultiLibMask = 0;
00787 
00788                 if (hge(h2, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00789                     oldmultiLibMask = *p;
00790                 if (hge(h, RPMTAG_MULTILIBS, NULL, (void **) &p, NULL))
00791                     multiLibMask = *p;
00792                 if (oldmultiLibMask && multiLibMask
00793                     && !(oldmultiLibMask & multiLibMask)) {
00794                     ts->addedPackages.list[alNum].multiLib = multiLibMask;
00795                 }
00796             }
00797         }
00798         mi = rpmdbFreeIterator(mi);
00799     }
00800 
00801     if (hge(h, RPMTAG_OBSOLETENAME, &ont, (void **) &obsoletes, &count)) {
00802         const char ** obsoletesEVR;
00803         int_32 * obsoletesFlags;
00804         int j;
00805 
00806         (void) hge(h, RPMTAG_OBSOLETEVERSION, &ovt, (void **) &obsoletesEVR,
00807                         NULL);
00808         (void) hge(h, RPMTAG_OBSOLETEFLAGS, NULL, (void **) &obsoletesFlags,
00809                         NULL);
00810 
00811         for (j = 0; j < count; j++) {
00812 
00813             /* XXX avoid self-obsoleting packages. */
00814             if (!strcmp(name, obsoletes[j]))
00815                 continue;
00816 
00817           { rpmdbMatchIterator mi;
00818             Header h2;
00819 
00820             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, obsoletes[j], 0);
00821 
00822             (void) rpmdbPruneIterator(mi,
00823                 ts->removedPackages, ts->numRemovedPackages, 1);
00824 
00825             while((h2 = rpmdbNextIterator(mi)) != NULL) {
00826                 /*
00827                  * Rpm prior to 3.0.3 does not have versioned obsoletes.
00828                  * If no obsoletes version info is available, match all names.
00829                  */
00830                 if (obsoletesEVR == NULL ||
00831                     headerMatchesDepFlags(h2,
00832                         obsoletes[j], obsoletesEVR[j], obsoletesFlags[j]))
00833                 {
00834                     (void) removePackage(ts, rpmdbGetIteratorOffset(mi), alNum);
00835                 }
00836             }
00837             mi = rpmdbFreeIterator(mi);
00838           }
00839         }
00840 
00841         obsoletesEVR = hfd(obsoletesEVR, ovt);
00842         obsoletes = hfd(obsoletes, ont);
00843     }
00844 
00845     return 0;
00846 }
00847 
00848 void rpmtransAvailablePackage(rpmTransactionSet ts, Header h, const void * key)
00849 {
00850     struct availablePackage * al;
00851     al = alAddPackage(&ts->availablePackages, h, key, NULL, NULL);
00852 }
00853 
00854 int rpmtransRemovePackage(rpmTransactionSet ts, int dboffset)
00855 {
00856     return removePackage(ts, dboffset, -1);
00857 }
00858 
00859 rpmTransactionSet rpmtransFree(rpmTransactionSet ts)
00860 {
00861     if (ts) {
00862         alFree(&ts->addedPackages);
00863         alFree(&ts->availablePackages);
00864         ts->di = _free(ts->di);
00865         ts->removedPackages = _free(ts->removedPackages);
00866         ts->order = _free(ts->order);
00867         if (ts->scriptFd != NULL)
00868             ts->scriptFd =
00869                 fdFree(ts->scriptFd, "rpmtransSetScriptFd (rpmtransFree");
00870         ts->rootDir = _free(ts->rootDir);
00871         ts->currDir = _free(ts->currDir);
00872 
00873         ts = _free(ts);
00874     }
00875     return NULL;
00876 }
00877 
00878 rpmDependencyConflict rpmdepFreeConflicts(rpmDependencyConflict conflicts,
00879                 int numConflicts)
00880 {
00881     int i;
00882 
00883     if (conflicts)
00884     for (i = 0; i < numConflicts; i++) {
00885         conflicts[i].byHeader = headerFree(conflicts[i].byHeader);
00886         conflicts[i].byName = _free(conflicts[i].byName);
00887         conflicts[i].byVersion = _free(conflicts[i].byVersion);
00888         conflicts[i].byRelease = _free(conflicts[i].byRelease);
00889         conflicts[i].needsName = _free(conflicts[i].needsName);
00890         conflicts[i].needsVersion = _free(conflicts[i].needsVersion);
00891         conflicts[i].suggestedPackages = _free(conflicts[i].suggestedPackages);
00892     }
00893 
00894     return (conflicts = _free(conflicts));
00895 }
00896 
00904 static /*@only@*/ /*@null@*/ struct availablePackage **
00905 alAllFileSatisfiesDepend(const availableList al,
00906                 const char * keyType, const char * fileName)
00907         /*@*/
00908 {
00909     int i, found;
00910     const char * dirName;
00911     const char * baseName;
00912     struct dirInfo_s dirNeedle;
00913     dirInfo dirMatch;
00914     struct availablePackage ** ret;
00915 
00916     /* Solaris 2.6 bsearch sucks down on this. */
00917     if (al->numDirs == 0 || al->dirs == NULL || al->list == NULL)
00918         return NULL;
00919 
00920     {   char * t;
00921         dirName = t = xstrdup(fileName);
00922         if ((t = strrchr(t, '/')) != NULL) {
00923             t++;                /* leave the trailing '/' */
00924             *t = '\0';
00925         }
00926     }
00927 
00928     dirNeedle.dirName = (char *) dirName;
00929     dirNeedle.dirNameLen = strlen(dirName);
00930     dirMatch = bsearch(&dirNeedle, al->dirs, al->numDirs,
00931                        sizeof(dirNeedle), dirInfoCompare);
00932     if (dirMatch == NULL) {
00933         dirName = _free(dirName);
00934         return NULL;
00935     }
00936 
00937     /* rewind to the first match */
00938     while (dirMatch > al->dirs && dirInfoCompare(dirMatch-1, &dirNeedle) == 0)
00939         dirMatch--;
00940 
00941     /*@-nullptrarith@*/         /* FIX: fileName NULL ??? */
00942     baseName = strrchr(fileName, '/') + 1;
00943     /*@=nullptrarith@*/
00944 
00945     for (found = 0, ret = NULL;
00946          dirMatch <= al->dirs + al->numDirs &&
00947                 dirInfoCompare(dirMatch, &dirNeedle) == 0;
00948          dirMatch++)
00949     {
00950         /* XXX FIXME: these file lists should be sorted and bsearched */
00951         for (i = 0; i < dirMatch->numFiles; i++) {
00952             if (dirMatch->files[i].baseName == NULL ||
00953                         strcmp(dirMatch->files[i].baseName, baseName))
00954                 continue;
00955 
00956             /*
00957              * If a file dependency would be satisfied by a file
00958              * we are not going to install, skip it.
00959              */
00960             if (al->list[dirMatch->files[i].pkgNum].multiLib &&
00961                         !isFileMULTILIB(dirMatch->files[i].fileFlags))
00962                 continue;
00963 
00964             if (keyType)
00965                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added files)\n"),
00966                         keyType, fileName);
00967 
00968             ret = xrealloc(ret, (found+2) * sizeof(*ret));
00969             if (ret)    /* can't happen */
00970                 ret[found++] = al->list + dirMatch->files[i].pkgNum;
00971             /*@innerbreak@*/ break;
00972         }
00973     }
00974 
00975     dirName = _free(dirName);
00976     /*@-mods@*/         /* FIX: al->list might be modified. */
00977     if (ret)
00978         ret[found] = NULL;
00979     /*@=mods@*/
00980     return ret;
00981 }
00982 
00983 #ifdef  DYING
00984 
00991 /*@unused@*/ static /*@dependent@*/ /*@null@*/ struct availablePackage *
00992 alFileSatisfiesDepend(const availableList al,
00993                 const char * keyType, const char * fileName)
00994         /*@*/
00995 {
00996     struct availablePackage * ret;
00997     struct availablePackage ** tmp =
00998                 alAllFileSatisfiesDepend(al, keyType, fileName);
00999 
01000     if (tmp) {
01001         ret = tmp[0];
01002         tmp = _free(tmp);
01003         return ret;
01004     }
01005     return NULL;
01006 }
01007 #endif  /* DYING */
01008 
01019 static /*@only@*/ /*@null@*/ struct availablePackage **
01020 alAllSatisfiesDepend(const availableList al,
01021                 const char * keyType, const char * keyDepend,
01022                 const char * keyName, const char * keyEVR, int keyFlags)
01023         /*@*/
01024 {
01025     struct availableIndexEntry needle, * match;
01026     struct availablePackage * p, ** ret = NULL;
01027     int i, rc, found;
01028 
01029     if (*keyName == '/') {
01030         ret = alAllFileSatisfiesDepend(al, keyType, keyName);
01031         /* XXX Provides: /path was broken with added packages (#52183). */
01032         if (ret != NULL && *ret != NULL)
01033             return ret;
01034     }
01035 
01036     if (!al->index.size || al->index.index == NULL) return NULL;
01037 
01038     needle.entry = keyName;
01039     needle.entryLen = strlen(keyName);
01040     match = bsearch(&needle, al->index.index, al->index.size,
01041                     sizeof(*al->index.index), indexcmp);
01042 
01043     if (match == NULL) return NULL;
01044 
01045     /* rewind to the first match */
01046     while (match > al->index.index && indexcmp(match-1, &needle) == 0)
01047         match--;
01048 
01049     for (ret = NULL, found = 0;
01050          match < al->index.index + al->index.size &&
01051                 indexcmp(match, &needle) == 0;
01052          match++)
01053     {
01054 
01055         p = match->package;
01056         rc = 0;
01057         switch (match->type) {
01058         case IET_PROVIDES:
01059             i = match->entryIx;
01060             {   const char * proEVR;
01061                 int proFlags;
01062 
01063                 proEVR = (p->providesEVR ? p->providesEVR[i] : NULL);
01064                 proFlags = (p->provideFlags ? p->provideFlags[i] : 0);
01065                 rc = rpmRangesOverlap(p->provides[i], proEVR, proFlags,
01066                                 keyName, keyEVR, keyFlags);
01067                 if (rc)
01068                     /*@switchbreak@*/ break;
01069             }
01070             if (keyType && keyDepend && rc)
01071                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (added provide)\n"),
01072                                 keyType, keyDepend+2);
01073             break;
01074         }
01075 
01076         if (rc) {
01077             ret = xrealloc(ret, (found + 2) * sizeof(*ret));
01078             if (ret)    /* can't happen */
01079                 ret[found++] = p;
01080         }
01081     }
01082 
01083     if (ret)
01084         ret[found] = NULL;
01085 
01086     return ret;
01087 }
01088 
01100 static inline /*@only@*/ /*@null@*/ struct availablePackage *
01101 alSatisfiesDepend(const availableList al,
01102                 const char * keyType, const char * keyDepend,
01103                 const char * keyName, const char * keyEVR, int keyFlags)
01104         /*@*/
01105 {
01106     struct availablePackage * ret;
01107     struct availablePackage ** tmp =
01108         alAllSatisfiesDepend(al, keyType, keyDepend, keyName, keyEVR, keyFlags);
01109 
01110     if (tmp) {
01111         ret = tmp[0];
01112         tmp = _free(tmp);
01113         return ret;
01114     }
01115     return NULL;
01116 }
01117 
01130 static int unsatisfiedDepend(rpmTransactionSet ts,
01131                 const char * keyType, const char * keyDepend,
01132                 const char * keyName, const char * keyEVR, int keyFlags,
01133                 /*@null@*/ /*@out@*/ struct availablePackage *** suggestion)
01134         /*@modifies ts, *suggestion @*/
01135 {
01136     rpmdbMatchIterator mi;
01137     Header h;
01138     int rc = 0; /* assume dependency is satisfied */
01139 
01140     if (suggestion) *suggestion = NULL;
01141 
01142     /*
01143      * Check if dbiOpen/dbiPut failed (e.g. permissions), we can't cache.
01144      */
01145     if (_cacheDependsRC) {
01146         dbiIndex dbi;
01147         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01148         if (dbi == NULL)
01149             _cacheDependsRC = 0;
01150         else {
01151             DBC * dbcursor = NULL;
01152             size_t keylen = strlen(keyDepend);
01153             void * datap = NULL;
01154             size_t datalen = 0;
01155             int xx;
01156             xx = dbiCopen(dbi, &dbcursor, 0);
01157             /*@-mods@*/         /* FIX: keyDepends mod undocumented. */
01158             xx = dbiGet(dbi, dbcursor, (void **)&keyDepend, &keylen, &datap, &datalen, 0);
01159             /*@=mods@*/
01160             if (xx == 0 && datap && datalen == 4) {
01161                 memcpy(&rc, datap, datalen);
01162                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s %-s (cached)\n"),
01163                         keyType, keyDepend, (rc ? _("NO ") : _("YES")));
01164                 xx = dbiCclose(dbi, NULL, 0);
01165 
01166                 if (suggestion && rc == 1)
01167                     *suggestion = alAllSatisfiesDepend(&ts->availablePackages,
01168                                 NULL, NULL, keyName, keyEVR, keyFlags);
01169 
01170                 return rc;
01171             }
01172             xx = dbiCclose(dbi, dbcursor, 0);
01173         }
01174     }
01175 
01176 #ifdef  DYING
01177   { static /*@observer@*/ const char noProvidesString[] = "nada";
01178     static /*@observer@*/ const char * rcProvidesString = noProvidesString;
01179     const char * start;
01180     int i;
01181 
01182     if (rcProvidesString == noProvidesString)
01183         rcProvidesString = rpmGetVar(RPMVAR_PROVIDES);
01184 
01185     if (rcProvidesString != NULL && !(keyFlags & RPMSENSE_SENSEMASK)) {
01186         i = strlen(keyName);
01187         /*@-observertrans -mayaliasunique@*/
01188         while ((start = strstr(rcProvidesString, keyName))) {
01189         /*@=observertrans =mayaliasunique@*/
01190             if (xisspace(start[i]) || start[i] == '\0' || start[i] == ',') {
01191                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmrc provides)\n"),
01192                         keyType, keyDepend+2);
01193                 goto exit;
01194             }
01195             rcProvidesString = start + 1;
01196         }
01197     }
01198   }
01199 #endif
01200 
01201     /*
01202      * New features in rpm packaging implicitly add versioned dependencies
01203      * on rpmlib provides. The dependencies look like "rpmlib(YaddaYadda)".
01204      * Check those dependencies now.
01205      */
01206     if (!strncmp(keyName, "rpmlib(", sizeof("rpmlib(")-1)) {
01207         if (rpmCheckRpmlibProvides(keyName, keyEVR, keyFlags)) {
01208             rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (rpmlib provides)\n"),
01209                         keyType, keyDepend+2);
01210             goto exit;
01211         }
01212         goto unsatisfied;
01213     }
01214 
01215     if (alSatisfiesDepend(&ts->addedPackages, keyType, keyDepend,
01216                 keyName, keyEVR, keyFlags))
01217     {
01218         goto exit;
01219     }
01220 
01221     /* XXX only the installer does not have the database open here. */
01222     if (ts->rpmdb != NULL) {
01223         if (*keyName == '/') {
01224             /* keyFlags better be 0! */
01225 
01226             mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_BASENAMES, keyName, 0);
01227 
01228             (void) rpmdbPruneIterator(mi,
01229                         ts->removedPackages, ts->numRemovedPackages, 1);
01230 
01231             while ((h = rpmdbNextIterator(mi)) != NULL) {
01232                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db files)\n"),
01233                         keyType, keyDepend+2);
01234                 mi = rpmdbFreeIterator(mi);
01235                 goto exit;
01236             }
01237             mi = rpmdbFreeIterator(mi);
01238         }
01239 
01240         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_PROVIDENAME, keyName, 0);
01241         (void) rpmdbPruneIterator(mi,
01242                         ts->removedPackages, ts->numRemovedPackages, 1);
01243         while ((h = rpmdbNextIterator(mi)) != NULL) {
01244             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01245                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db provides)\n"),
01246                         keyType, keyDepend+2);
01247                 mi = rpmdbFreeIterator(mi);
01248                 goto exit;
01249             }
01250         }
01251         mi = rpmdbFreeIterator(mi);
01252 
01253 #ifndef DYING
01254         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_NAME, keyName, 0);
01255         (void) rpmdbPruneIterator(mi,
01256                         ts->removedPackages, ts->numRemovedPackages, 1);
01257         while ((h = rpmdbNextIterator(mi)) != NULL) {
01258             if (rangeMatchesDepFlags(h, keyName, keyEVR, keyFlags)) {
01259                 rpmMessage(RPMMESS_DEBUG, _("%s: %-45s YES (db package)\n"),
01260                         keyType, keyDepend+2);
01261                 mi = rpmdbFreeIterator(mi);
01262                 goto exit;
01263             }
01264         }
01265         mi = rpmdbFreeIterator(mi);
01266 #endif
01267 
01268     }
01269 
01270     if (suggestion)
01271         *suggestion = alAllSatisfiesDepend(&ts->availablePackages, NULL, NULL,
01272                                 keyName, keyEVR, keyFlags);
01273 
01274 unsatisfied:
01275     rpmMessage(RPMMESS_DEBUG, _("%s: %-45s NO\n"), keyType, keyDepend+2);
01276     rc = 1;     /* dependency is unsatisfied */
01277 
01278 exit:
01279     /*
01280      * If dbiOpen/dbiPut fails (e.g. permissions), we can't cache.
01281      */
01282     if (_cacheDependsRC) {
01283         dbiIndex dbi;
01284         dbi = dbiOpen(ts->rpmdb, RPMDBI_DEPENDS, 0);
01285         if (dbi == NULL) {
01286             _cacheDependsRC = 0;
01287         } else {
01288             DBC * dbcursor = NULL;
01289             int xx;
01290             xx = dbiCopen(dbi, &dbcursor, DBI_WRITECURSOR);
01291             xx = dbiPut(dbi, dbcursor, keyDepend, strlen(keyDepend), &rc, sizeof(rc), 0);
01292             if (xx)
01293                 _cacheDependsRC = 0;
01294 #if 0   /* XXX NOISY */
01295             else
01296                 rpmMessage(RPMMESS_DEBUG, _("%s: (%s, %s) added to Depends cache.\n"), keyType, keyDepend, (rc ? _("NO ") : _("YES")));
01297 #endif
01298             xx = dbiCclose(dbi, dbcursor, DBI_WRITECURSOR);
01299         }
01300     }
01301     return rc;
01302 }
01303 
01313 static int checkPackageDeps(rpmTransactionSet ts, problemsSet psp,
01314                 Header h, const char * keyName, uint_32 multiLib)
01315         /*@modifies ts, h, psp */
01316 {
01317     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
01318     HFD_t hfd = headerFreeData;
01319     rpmTagType rnt, rvt;
01320     rpmTagType cnt, cvt;
01321     const char * name, * version, * release;
01322     const char ** requires;
01323     const char ** requiresEVR = NULL;
01324     int_32 * requireFlags = NULL;
01325     int requiresCount = 0;
01326     const char ** conflicts;
01327     const char ** conflictsEVR = NULL;
01328     int_32 * conflictFlags = NULL;
01329     int conflictsCount = 0;
01330     rpmTagType type;
01331     int i, rc;
01332     int ourrc = 0;
01333     struct availablePackage ** suggestion;
01334 
01335     (void) headerNVR(h, &name, &version, &release);
01336 
01337     if (!hge(h, RPMTAG_REQUIRENAME, &rnt, (void **) &requires, &requiresCount))
01338     {
01339         requiresCount = 0;
01340         rvt = RPM_STRING_ARRAY_TYPE;
01341     } else {
01342         (void)hge(h, RPMTAG_REQUIREFLAGS, NULL, (void **) &requireFlags, NULL);
01343         (void)hge(h, RPMTAG_REQUIREVERSION, &rvt, (void **) &requiresEVR, NULL);
01344     }
01345 
01346     for (i = 0; i < requiresCount && !ourrc; i++) {
01347         const char * keyDepend;
01348 
01349         /* Filter out requires that came along for the ride. */
01350         if (keyName && strcmp(keyName, requires[i]))
01351             continue;
01352 
01353         /* If this requirement comes from the core package only, not libraries,
01354            then if we're installing the libraries only, don't count it in. */
01355         if (multiLib && !isDependsMULTILIB(requireFlags[i]))
01356             continue;
01357 
01358         keyDepend = printDepend("R",
01359                 requires[i], requiresEVR[i], requireFlags[i]);
01360 
01361         rc = unsatisfiedDepend(ts, " Requires", keyDepend,
01362                 requires[i], requiresEVR[i], requireFlags[i], &suggestion);
01363 
01364         switch (rc) {
01365         case 0:         /* requirements are satisfied. */
01366             break;
01367         case 1:         /* requirements are not satisfied. */
01368             rpmMessage(RPMMESS_DEBUG, _("package %s-%s-%s require not satisfied: %s\n"),
01369                     name, version, release, keyDepend+2);
01370 
01371             if (psp->num == psp->alloced) {
01372                 psp->alloced += 5;
01373                 psp->problems = xrealloc(psp->problems, sizeof(*psp->problems) *
01374                             psp->alloced);
01375             }
01376 
01377             {   rpmDependencyConflict pp = psp->problems + psp->num;
01378                 pp->byHeader = headerLink(h);
01379                 pp->byName = xstrdup(name);
01380                 pp->byVersion = xstrdup(version);
01381                 pp->byRelease = xstrdup(release);
01382                 pp->needsName = xstrdup(requires[i]);
01383                 pp->needsVersion = xstrdup(requiresEVR[i]);
01384                 pp->needsFlags = requireFlags[i];
01385                 pp->sense = RPMDEP_SENSE_REQUIRES;
01386 
01387                 if (suggestion) {
01388                     int j;
01389                     for (j = 0; suggestion[j]; j++)
01390                         {};
01391                     pp->suggestedPackages =
01392                         xmalloc( (j + 1) * sizeof(*pp->suggestedPackages) );
01393                     for (j = 0; suggestion[j]; j++)
01394                         pp->suggestedPackages[j] = suggestion[j]->key;
01395                     pp->suggestedPackages[j] = NULL;
01396                 } else {
01397                     pp->suggestedPackages = NULL;
01398                 }
01399             }
01400 
01401             psp->num++;
01402             break;
01403         case 2:         /* something went wrong! */
01404         default:
01405             ourrc = 1;
01406             break;
01407         }
01408         keyDepend = _free(keyDepend);
01409     }
01410 
01411     if (requiresCount) {
01412         requiresEVR = hfd(requiresEVR, rvt);
01413         requires = hfd(requires, rnt);
01414     }
01415 
01416     if (!hge(h, RPMTAG_CONFLICTNAME, &cnt, (void **)&conflicts, &conflictsCount))
01417     {
01418         conflictsCount = 0;
01419         cvt = RPM_STRING_ARRAY_TYPE;
01420     } else {
01421         (void) hge(h, RPMTAG_CONFLICTFLAGS, &type,
01422                 (void **) &conflictFlags, &conflictsCount);
01423         (void) hge(h, RPMTAG_CONFLICTVERSION, &cvt,
01424                 (void **) &conflictsEVR, &conflictsCount);
01425     }
01426 
01427     for (i = 0; i < conflictsCount && !ourrc; i++) {
01428         const char * keyDepend;
01429 
01430         /* Filter out conflicts that came along for the ride. */
01431         if (keyName && strcmp(keyName, conflicts[i]))
01432             continue;
01433 
01434         /* If this requirement comes from the core package only, not libraries,
01435            then if we're installing the libraries only, don't count it in. */
01436         if (multiLib && !isDependsMULTILIB(conflictFlags[i]))
01437             continue;
01438 
01439         keyDepend = printDepend("C", conflicts[i], conflictsEVR[i], conflictFlags[i]);
01440 
01441         rc = unsatisfiedDepend(ts, "Conflicts", keyDepend,
01442                 conflicts[i], conflictsEVR[i], conflictFlags[i], NULL);
01443 
01444         /* 1 == unsatisfied, 0 == satsisfied */
01445         switch (rc) {
01446         case 0:         /* conflicts exist. */
01447             rpmMessage(RPMMESS_DEBUG, _("package %s conflicts: %s\n"),
01448                     name, keyDepend+2);
01449 
01450             if (psp->num == psp->alloced) {
01451                 psp->alloced += 5;
01452                 psp->problems = xrealloc(psp->problems,
01453                                         sizeof(*psp->problems) * psp->alloced);
01454             }
01455 
01456             {   rpmDependencyConflict pp = psp->problems + psp->num;
01457                 pp->byHeader = headerLink(h);
01458                 pp->byName = xstrdup(name);
01459                 pp->byVersion = xstrdup(version);
01460                 pp->byRelease = xstrdup(release);
01461                 pp->needsName = xstrdup(conflicts[i]);
01462                 pp->needsVersion = xstrdup(conflictsEVR[i]);
01463                 pp->needsFlags = conflictFlags[i];
01464                 pp->sense = RPMDEP_SENSE_CONFLICTS;
01465                 pp->suggestedPackages = NULL;
01466             }
01467 
01468             psp->num++;
01469             break;
01470         case 1:         /* conflicts don't exist. */
01471             break;
01472         case 2:         /* something went wrong! */
01473         default:
01474             ourrc = 1;
01475             break;
01476         }
01477         keyDepend = _free(keyDepend);
01478     }
01479 
01480     if (conflictsCount) {
01481         conflictsEVR = hfd(conflictsEVR, cvt);
01482         conflicts = hfd(conflicts, cnt);
01483     }
01484 
01485     return ourrc;
01486 }
01487 
01498 static int checkPackageSet(rpmTransactionSet ts, problemsSet psp,
01499                 const char * key, /*@only@*/ /*@null@*/ rpmdbMatchIterator mi)
01500         /*@modifies ts, mi, psp @*/
01501 {
01502     Header h;
01503     int rc = 0;
01504 
01505     (void) rpmdbPruneIterator(mi,
01506                 ts->removedPackages, ts->numRemovedPackages, 1);
01507     while ((h = rpmdbNextIterator(mi)) != NULL) {
01508         if (checkPackageDeps(ts, psp, h, key, 0)) {
01509             rc = 1;
01510             break;
01511         }
01512     }
01513     mi = rpmdbFreeIterator(mi);
01514 
01515     return rc;
01516 }
01517 
01525 static int checkDependentPackages(rpmTransactionSet ts,
01526                         problemsSet psp, const char * key)
01527         /*@modifies ts, psp @*/
01528 {
01529     rpmdbMatchIterator mi;
01530     mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_REQUIRENAME, key, 0);
01531     return checkPackageSet(ts, psp, key, mi);
01532 }
01533 
01541 static int checkDependentConflicts(rpmTransactionSet ts,
01542                 problemsSet psp, const char * key)
01543         /*@modifies ts, psp @*/
01544 {
01545     int rc = 0;
01546 
01547     if (ts->rpmdb) {    /* XXX is this necessary? */
01548         rpmdbMatchIterator mi;
01549         mi = rpmdbInitIterator(ts->rpmdb, RPMTAG_CONFLICTNAME, key, 0);
01550         rc = checkPackageSet(ts, psp, key, mi);
01551     }
01552 
01553     return rc;
01554 }
01555 
01556 struct badDeps_s {
01557 /*@observer@*/ /*@null@*/ const char * pname;
01558 /*@observer@*/ /*@null@*/ const char * qname;
01559 };
01560 
01561 #ifdef  DYING
01562 static struct badDeps_s {
01563 /*@observer@*/ /*@null@*/ const char * pname;
01564 /*@observer@*/ /*@null@*/ const char * qname;
01565 } badDeps[] = {
01566     { "libtermcap", "bash" },
01567     { "modutils", "vixie-cron" },
01568     { "ypbind", "yp-tools" },
01569     { "ghostscript-fonts", "ghostscript" },
01570     /* 7.2 only */
01571     { "libgnomeprint15", "gnome-print" },
01572     { "nautilus", "nautilus-mozilla" },
01573     /* 7.1 only */
01574     { "arts", "kdelibs-sound" },
01575     /* 7.0 only */
01576     { "pango-gtkbeta-devel", "pango-gtkbeta" },
01577     { "XFree86", "Mesa" },
01578     { "compat-glibc", "db2" },
01579     { "compat-glibc", "db1" },
01580     { "pam", "initscripts" },
01581     { "initscripts", "sysklogd" },
01582     /* 6.2 */
01583     { "egcs-c++", "libstdc++" },
01584     /* 6.1 */
01585     { "pilot-link-devel", "pilot-link" },
01586     /* 5.2 */
01587     { "pam", "pamconfig" },
01588     { NULL, NULL }
01589 };
01590 #else
01591 static struct badDeps_s * badDeps = NULL;
01592 #endif
01593 
01601 static int ignoreDep(const struct availablePackage * p,
01602                 const struct availablePackage * q)
01603         /*@*/
01604 {
01605     struct badDeps_s * bdp;
01606     static int _initialized = 0;
01607     const char ** av = NULL;
01608     int ac = 0;
01609 
01610     if (!_initialized) {
01611         char * s = rpmExpand("%{?_dependency_whiteout}", NULL);
01612         int i;
01613 
01614         if (s != NULL && *s != '\0'
01615         && !(i = poptParseArgvString(s, &ac, (const char ***)&av))
01616         && ac > 0 && av != NULL)
01617         {
01618             bdp = badDeps = xcalloc(ac+1, sizeof(*badDeps));
01619             for (i = 0; i < ac; i++, bdp++) {
01620                 char * p, * q;
01621 
01622                 if (av[i] == NULL)
01623                     break;
01624                 p = xstrdup(av[i]);
01625                 if ((q = strchr(p, '>')) != NULL)
01626                     *q++ = '\0';
01627                 bdp->pname = p;
01628                 bdp->qname = q;
01629                 rpmMessage(RPMMESS_DEBUG,
01630                         _("ignore package name relation(s) [%d]\t%s -> %s\n"),
01631                         i, bdp->pname, bdp->qname);
01632             }
01633             bdp->pname = bdp->qname = NULL;
01634         }
01635         av = _free(av);
01636         s = _free(s);
01637         _initialized++;
01638     }
01639 
01640     if (badDeps != NULL)
01641     for (bdp = badDeps; bdp->pname != NULL && bdp->qname != NULL; bdp++) {
01642         if (!strcmp(p->name, bdp->pname) && !strcmp(q->name, bdp->qname))
01643             return 1;
01644     }
01645     return 0;
01646 }
01647 
01653 static void markLoop(/*@special@*/ tsortInfo tsi,
01654                 struct availablePackage * q)
01655         /*@uses tsi @*/
01656         /*@modifies internalState @*/
01657 {
01658     struct availablePackage * p;
01659 
01660     while (tsi != NULL && (p = tsi->tsi_suc) != NULL) {
01661         tsi = tsi->tsi_next;
01662         if (p->tsi.tsi_pkg != NULL)
01663             continue;
01664         p->tsi.tsi_pkg = q;
01665         if (p->tsi.tsi_next != NULL)
01666             markLoop(p->tsi.tsi_next, p);
01667     }
01668 }
01669 
01670 static inline /*@observer@*/ const char * const identifyDepend(int_32 f)
01671 {
01672     if (isLegacyPreReq(f))
01673         return "PreReq:";
01674     f = _notpre(f);
01675     if (f & RPMSENSE_SCRIPT_PRE)
01676         return "Requires(pre):";
01677     if (f & RPMSENSE_SCRIPT_POST)
01678         return "Requires(post):";
01679     if (f & RPMSENSE_SCRIPT_PREUN)
01680         return "Requires(preun):";
01681     if (f & RPMSENSE_SCRIPT_POSTUN)
01682         return "Requires(postun):";
01683     if (f & RPMSENSE_SCRIPT_VERIFY)
01684         return "Requires(verify):";
01685     if (f & RPMSENSE_FIND_REQUIRES)
01686         return "Requires(auto):";
01687     return "Requires:";
01688 }
01689 
01701 static /*@owned@*/ /*@null@*/ const char *
01702 zapRelation(struct availablePackage * q, struct availablePackage * p,
01703                 int zap, /*@in@*/ /*@out@*/ int * nzaps)
01704         /*@modifies q, p, *nzaps @*/
01705 {
01706     tsortInfo tsi_prev;
01707     tsortInfo tsi;
01708     const char *dp = NULL;
01709 
01710     for (tsi_prev = &q->tsi, tsi = q->tsi.tsi_next;
01711          tsi != NULL;
01712         /* XXX Note: the loop traverses "not found", break on "found". */
01713         /*@-nullderef@*/
01714          tsi_prev = tsi, tsi = tsi->tsi_next)
01715         /*@=nullderef@*/
01716     {
01717         int j;
01718 
01719         if (tsi->tsi_suc != p)
01720             continue;
01721         if (p->requires == NULL) continue;      /* XXX can't happen */
01722         if (p->requireFlags == NULL) continue;  /* XXX can't happen */
01723         if (p->requiresEVR == NULL) continue;   /* XXX can't happen */
01724 
01725         j = tsi->tsi_reqx;
01726         dp = printDepend( identifyDepend(p->requireFlags[j]),
01727                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01728 
01729         /*
01730          * Attempt to unravel a dependency loop by eliminating Requires's.
01731          */
01732         if (zap && !(p->requireFlags[j] & RPMSENSE_PREREQ)) {
01733             rpmMessage(RPMMESS_DEBUG,
01734                         _("removing %s-%s-%s \"%s\" from tsort relations.\n"),
01735                         p->name, p->version, p->release, dp);
01736             p->tsi.tsi_count--;
01737             if (tsi_prev) tsi_prev->tsi_next = tsi->tsi_next;
01738             tsi->tsi_next = NULL;
01739             tsi->tsi_suc = NULL;
01740             tsi = _free(tsi);
01741             if (nzaps)
01742                 (*nzaps)++;
01743             if (zap)
01744                 zap--;
01745         }
01746         /* XXX Note: the loop traverses "not found", get out now! */
01747         break;
01748     }
01749     return dp;
01750 }
01751 
01760 static inline int addRelation( const rpmTransactionSet ts,
01761                 struct availablePackage * p, unsigned char * selected, int j)
01762         /*@modifies p->tsi.tsi_u.count, p->depth, *selected @*/
01763 {
01764     struct availablePackage * q;
01765     tsortInfo tsi;
01766     int matchNum;
01767 
01768     if (!p->requires || !p->requiresEVR || !p->requireFlags)
01769         return 0;
01770 
01771     q = alSatisfiesDepend(&ts->addedPackages, NULL, NULL,
01772                 p->requires[j], p->requiresEVR[j], p->requireFlags[j]);
01773 
01774     /* Ordering depends only on added package relations. */
01775     if (q == NULL)
01776         return 0;
01777 
01778     /* Avoid rpmlib feature dependencies. */
01779     if (!strncmp(p->requires[j], "rpmlib(", sizeof("rpmlib(")-1))
01780         return 0;
01781 
01782     /* Avoid certain dependency relations. */
01783     if (ignoreDep(p, q))
01784         return 0;
01785 
01786     /* Avoid redundant relations. */
01787     /* XXX TODO: add control bit. */
01788     matchNum = q - ts->addedPackages.list;
01789     if (selected[matchNum] != 0)
01790         return 0;
01791     selected[matchNum] = 1;
01792 
01793     /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01794     p->tsi.tsi_count++;                 /* bump p predecessor count */
01795     if (p->depth <= q->depth)           /* Save max. depth in dependency tree */
01796         p->depth = q->depth + 1;
01797 
01798     tsi = xmalloc(sizeof(*tsi));
01799     tsi->tsi_suc = p;
01800     tsi->tsi_reqx = j;
01801     tsi->tsi_next = q->tsi.tsi_next;
01802     q->tsi.tsi_next = tsi;
01803     q->tsi.tsi_qcnt++;                  /* bump q successor count */
01804     return 0;
01805 }
01806 
01813 static int orderListIndexCmp(const void * one, const void * two)        /*@*/
01814 {
01815     int a = ((const struct orderListIndex *)one)->alIndex;
01816     int b = ((const struct orderListIndex *)two)->alIndex;
01817     return (a - b);
01818 }
01819 
01826 static void addQ(struct availablePackage * p,
01827                 /*@in@*/ /*@out@*/ struct availablePackage ** qp,
01828                 /*@in@*/ /*@out@*/ struct availablePackage ** rp)
01829         /*@modifies p->tsi, *qp, *rp @*/
01830 {
01831     struct availablePackage *q, *qprev;
01832 
01833     /* Mark the package as queued. */
01834     p->tsi.tsi_reqx = 1;
01835 
01836     if ((*rp) == NULL) {        /* 1st element */
01837         (*rp) = (*qp) = p;
01838         return;
01839     }
01840     for (qprev = NULL, q = (*qp); q != NULL; qprev = q, q = q->tsi.tsi_suc) {
01841         if (q->tsi.tsi_qcnt <= p->tsi.tsi_qcnt)
01842             break;
01843     }
01844     if (qprev == NULL) {        /* insert at beginning of list */
01845         p->tsi.tsi_suc = q;
01846         (*qp) = p;              /* new head */
01847     } else if (q == NULL) {     /* insert at end of list */
01848         qprev->tsi.tsi_suc = p;
01849         (*rp) = p;              /* new tail */
01850     } else {                    /* insert between qprev and q */
01851         p->tsi.tsi_suc = q;
01852         qprev->tsi.tsi_suc = p;
01853     }
01854 }
01855 
01856 int rpmdepOrder(rpmTransactionSet ts)
01857 {
01858     int npkgs = ts->addedPackages.size;
01859 #ifdef  DYING
01860     int chainsaw = ts->transFlags & RPMTRANS_FLAG_CHAINSAW;
01861 #else
01862     int chainsaw = 0;
01863 #endif
01864     struct availablePackage * p;
01865     struct availablePackage * q;
01866     struct availablePackage * r;
01867     tsortInfo tsi;
01868     tsortInfo tsi_next;
01869     int * ordering = alloca(sizeof(*ordering) * (npkgs + 1));
01870     int orderingCount = 0;
01871     unsigned char * selected = alloca(sizeof(*selected) * (npkgs + 1));
01872     int loopcheck;
01873     transactionElement newOrder;
01874     int newOrderCount = 0;
01875     struct orderListIndex * orderList;
01876     int nrescans = 10;
01877     int _printed = 0;
01878     int treex;
01879     int depth;
01880     int qlen;
01881     int i, j;
01882 
01883     alMakeIndex(&ts->addedPackages);
01884     alMakeIndex(&ts->availablePackages);
01885 
01886     /* T1. Initialize. */
01887     loopcheck = npkgs;
01888 
01889     /* Record all relations. */
01890     rpmMessage(RPMMESS_DEBUG, _("========== recording tsort relations\n"));
01891     if ((p = ts->addedPackages.list) != NULL)
01892     for (i = 0; i < npkgs; i++, p++) {
01893         int matchNum;
01894 
01895         if (p->requiresCount <= 0)
01896             continue;
01897 
01898         memset(selected, 0, sizeof(*selected) * npkgs);
01899 
01900         /* Avoid narcisstic relations. */
01901         matchNum = p - ts->addedPackages.list;
01902         selected[matchNum] = 1;
01903 
01904         /* T2. Next "q <- p" relation. */
01905 
01906         /* First, do pre-requisites. */
01907         for (j = 0; j < p->requiresCount; j++) {
01908 
01909             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
01910 
01911             /* Skip if not %pre/%post requires or legacy prereq. */
01912 
01913             if (isErasePreReq(p->requireFlags[j]) ||
01914                 !( isInstallPreReq(p->requireFlags[j]) ||
01915                    isLegacyPreReq(p->requireFlags[j]) ))
01916                 continue;
01917 
01918             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01919             (void) addRelation(ts, p, selected, j);
01920 
01921         }
01922 
01923         /* Then do co-requisites. */
01924         for (j = 0; j < p->requiresCount; j++) {
01925 
01926             if (p->requireFlags == NULL) continue;      /* XXX can't happen */
01927 
01928             /* Skip if %pre/%post requires or legacy prereq. */
01929 
01930             if (isErasePreReq(p->requireFlags[j]) ||
01931                  ( isInstallPreReq(p->requireFlags[j]) ||
01932                    isLegacyPreReq(p->requireFlags[j]) ))
01933                 continue;
01934 
01935             /* T3. Record next "q <- p" relation (i.e. "p" requires "q"). */
01936             (void) addRelation(ts, p, selected, j);
01937 
01938         }
01939     }
01940 
01941     /* Save predecessor count and mark tree roots. */
01942     treex = 0;
01943     if ((p = ts->addedPackages.list) != NULL)
01944     for (i = 0; i < npkgs; i++, p++) {
01945         p->npreds = p->tsi.tsi_count;
01946         p->tree = (p->npreds == 0 ? treex++ : -1);
01947     }
01948 
01949     /* T4. Scan for zeroes. */
01950     rpmMessage(RPMMESS_DEBUG, _("========== tsorting packages (order, #predecessors, #succesors, tree, depth)\n"));
01951 
01952 rescan:
01953     q = r = NULL;
01954     qlen = 0;
01955     if ((p = ts->addedPackages.list) != NULL)
01956     for (i = 0; i < npkgs; i++, p++) {
01957 
01958         /* Prefer packages in chainsaw or presentation order. */
01959         if (!chainsaw)
01960             p->tsi.tsi_qcnt = (npkgs - i);
01961 
01962         if (p->tsi.tsi_count != 0)
01963             continue;
01964         p->tsi.tsi_suc = NULL;
01965         addQ(p, &q, &r);
01966         qlen++;
01967     }
01968 
01969     /* T5. Output front of queue (T7. Remove from queue.) */
01970     for (; q != NULL; q = q->tsi.tsi_suc) {
01971 
01972         /* Mark the package as unqueued. */
01973         q->tsi.tsi_reqx = 0;
01974 
01975         rpmMessage(RPMMESS_DEBUG, "%5d%5d%5d%5d%5d %*s %s-%s-%s\n",
01976                         orderingCount, q->npreds, q->tsi.tsi_qcnt,
01977                         q->tree, q->depth,
01978                         2*q->depth, "",
01979                         q->name, q->version, q->release);
01980 
01981         treex = q->tree;
01982         depth = q->depth;
01983         q->degree = 0;
01984 
01985         ordering[orderingCount++] = q - ts->addedPackages.list;
01986         qlen--;
01987         loopcheck--;
01988 
01989         /* T6. Erase relations. */
01990         tsi_next = q->tsi.tsi_next;
01991         q->tsi.tsi_next = NULL;
01992         while ((tsi = tsi_next) != NULL) {
01993             tsi_next = tsi->tsi_next;
01994             tsi->tsi_next = NULL;
01995             p = tsi->tsi_suc;
01996             if (p && (--p->tsi.tsi_count) <= 0) {
01997 
01998                 p->tree = treex;
01999                 p->depth = depth + 1;
02000                 p->parent = q;
02001                 q->degree++;
02002 
02003                 /* XXX TODO: add control bit. */
02004                 p->tsi.tsi_suc = NULL;
02005                 /*@-nullstate@*/        /* FIX: q->tsi.tsi_u.suc may be NULL */
02006                 addQ(p, &q->tsi.tsi_suc, &r);
02007                 /*@=nullstate@*/
02008                 qlen++;
02009             }
02010             tsi = _free(tsi);
02011         }
02012         if (!_printed && loopcheck == qlen && q->tsi.tsi_suc != NULL) {
02013             _printed++;
02014             rpmMessage(RPMMESS_DEBUG,
02015                 _("========== successors only (presentation order)\n"));
02016 
02017             /* Relink the queue in presentation order. */
02018             tsi = &q->tsi;
02019             if ((p = ts->addedPackages.list) != NULL)
02020             for (i = 0; i < npkgs; i++, p++) {
02021                 /* Is this element in the queue? */
02022                 if (p->tsi.tsi_reqx == 0)
02023                     /*@innercontinue@*/ continue;
02024                 tsi->tsi_suc = p;
02025                 tsi = &p->tsi;
02026             }
02027             tsi->tsi_suc = NULL;
02028         }
02029     }
02030 
02031     /* T8. End of process. Check for loops. */
02032     if (loopcheck != 0) {
02033         int nzaps;
02034 
02035         /* T9. Initialize predecessor chain. */
02036         nzaps = 0;
02037         if ((q = ts->addedPackages.list) != NULL)
02038         for (i = 0; i < npkgs; i++, q++) {
02039             q->tsi.tsi_pkg = NULL;
02040             q->tsi.tsi_reqx = 0;
02041             /* Mark packages already sorted. */
02042             if (q->tsi.tsi_count == 0)
02043                 q->tsi.tsi_count = -1;
02044         }
02045 
02046         /* T10. Mark all packages with their predecessors. */
02047         if ((q = ts->addedPackages.list) != NULL)
02048         for (i = 0; i < npkgs; i++, q++) {
02049             if ((tsi = q->tsi.tsi_next) == NULL)
02050                 continue;
02051             q->tsi.tsi_next = NULL;
02052             markLoop(tsi, q);
02053             q->tsi.tsi_next = tsi;
02054         }
02055 
02056         /* T11. Print all dependency loops. */
02057         if ((r = ts->addedPackages.list) != NULL)
02058         for (i = 0; i < npkgs; i++, r++) {
02059             int printed;
02060 
02061             printed = 0;
02062 
02063             /* T12. Mark predecessor chain, looking for start of loop. */
02064             for (q = r->tsi.tsi_pkg; q != NULL; q = q->tsi.tsi_pkg) {
02065                 if (q->tsi.tsi_reqx)
02066                     /*@innerbreak@*/ break;
02067                 q->tsi.tsi_reqx = 1;
02068             }
02069 
02070             /* T13. Print predecessor chain from start of loop. */
02071             while ((p = q) != NULL && (q = p->tsi.tsi_pkg) != NULL) {
02072                 const char * dp;
02073                 char buf[4096];
02074 
02075                 /* Unchain predecessor loop. */
02076                 p->tsi.tsi_pkg = NULL;
02077 
02078                 if (!printed) {
02079                     rpmMessage(RPMMESS_DEBUG, _("LOOP:\n"));
02080                     printed = 1;
02081                 }
02082 
02083                 /* Find (and destroy if co-requisite) "q <- p" relation. */
02084                 dp = zapRelation(q, p, 1, &nzaps);
02085 
02086                 /* Print next member of loop. */
02087                 sprintf(buf, "%s-%s-%s", p->name, p->version, p->release);
02088                 rpmMessage(RPMMESS_DEBUG, "    %-40s %s\n", buf,
02089                         (dp ? dp : "not found!?!"));
02090 
02091                 dp = _free(dp);
02092             }
02093 
02094             /* Walk (and erase) linear part of predecessor chain as well. */
02095             for (p = r, q = r->tsi.tsi_pkg;
02096                  q != NULL;
02097                  p = q, q = q->tsi.tsi_pkg)
02098             {
02099                 /* Unchain linear part of predecessor loop. */
02100                 p->tsi.tsi_pkg = NULL;
02101                 p->tsi.tsi_reqx = 0;
02102             }
02103         }
02104 
02105         /* If a relation was eliminated, then continue sorting. */
02106         /* XXX TODO: add control bit. */
02107         if (nzaps && nrescans-- > 0) {
02108             rpmMessage(RPMMESS_DEBUG, _("========== continuing tsort ...\n"));
02109             goto rescan;
02110         }
02111         return 1;
02112     }
02113 
02114     /*
02115      * The order ends up as installed packages followed by removed packages,
02116      * with removes for upgrades immediately following the installation of
02117      * the new package. This would be easier if we could sort the
02118      * addedPackages array, but we store indexes into it in various places.
02119      */
02120     orderList = xmalloc(npkgs * sizeof(*orderList));
02121     for (i = 0, j = 0; i < ts->orderCount; i++) {
02122         if (ts->order[i].type == TR_ADDED) {
02123             orderList[j].alIndex = ts->order[i].u.addedIndex;
02124             orderList[j].orIndex = i;
02125             j++;
02126         }
02127     }
02128     assert(j <= npkgs);
02129 
02130     qsort(orderList, npkgs, sizeof(*orderList), orderListIndexCmp);
02131 
02132     newOrder = xmalloc(ts->orderCount * sizeof(*newOrder));
02133     for (i = 0, newOrderCount = 0; i < orderingCount; i++) {
02134         struct orderListIndex * needle, key;
02135 
02136         key.alIndex = ordering[i];
02137         needle = bsearch(&key, orderList, npkgs, sizeof(key),orderListIndexCmp);
02138         /* bsearch should never, ever fail */
02139         if (needle == NULL) continue;
02140 
02141         newOrder[newOrderCount++] = ts->order[needle->orIndex];
02142         for (j = needle->orIndex + 1; j < ts->orderCount; j++) {
02143             if (ts->order[j].type == TR_REMOVED &&
02144                 ts->order[j].u.removed.dependsOnIndex == needle->alIndex) {
02145                 newOrder[newOrderCount++] = ts->order[j];
02146             } else
02147                 /*@innerbreak@*/ break;
02148         }
02149     }
02150 
02151     for (i = 0; i < ts->orderCount; i++) {
02152         if (ts->order[i].type == TR_REMOVED &&
02153             ts->order[i].u.removed.dependsOnIndex == -1)  {
02154             newOrder[newOrderCount++] = ts->order[i];
02155         }
02156     }
02157     assert(newOrderCount == ts->orderCount);
02158 
02159     ts->order = _free(ts->order);
02160     ts->order = newOrder;
02161     ts->orderAlloced = ts->orderCount;
02162     orderList = _free(orderList);
02163 
02164     return 0;
02165 }
02166 
02173 static int rpmdbCloseDBI(/*@null@*/ rpmdb db, int rpmtag)
02174         /*@ modifies db, fileSystem @*/
02175 {
02176     int dbix;
02177     int rc = 0;
02178 
02179     if (db == NULL || db->_dbi == NULL || dbiTags == NULL)
02180         return 0;
02181 
02182     for (dbix = 0; dbix < dbiTagsMax; dbix++) {
02183         if (dbiTags[dbix] != rpmtag)
02184             continue;
02185         if (db->_dbi[dbix] != NULL) {
02186             int xx;
02187             /*@-unqualifiedtrans@*/             /* FIX: double indirection. */
02188             xx = dbiClose(db->_dbi[dbix], 0);
02189             if (xx && rc == 0) rc = xx;
02190             db->_dbi[dbix] = NULL;
02191             /*@=unqualifiedtrans@*/
02192         }
02193         break;
02194     }
02195     return rc;
02196 }
02197 
02198 int rpmdepCheck(rpmTransactionSet ts,
02199                 rpmDependencyConflict * conflicts, int * numConflicts)
02200 {
02201     HGE_t hge = (HGE_t)headerGetEntryMinMemory;
02202     HFD_t hfd = headerFreeData;
02203     rpmdbMatchIterator mi = NULL;
02204     Header h = NULL;
02205     struct availablePackage * p;
02206     problemsSet ps;
02207     int npkgs;
02208     int i, j;
02209     int rc;
02210 
02211     npkgs = ts->addedPackages.size;
02212 
02213     ps = xcalloc(1, sizeof(*ps));
02214     ps->alloced = 5;
02215     ps->num = 0;
02216     ps->problems = xcalloc(ps->alloced, sizeof(*ps->problems));
02217 
02218     *conflicts = NULL;
02219     *numConflicts = 0;
02220 
02221     alMakeIndex(&ts->addedPackages);
02222     alMakeIndex(&ts->availablePackages);
02223 
02224     /*
02225      * Look at all of the added packages and make sure their dependencies
02226      * are satisfied.
02227      */
02228     if ((p = ts->addedPackages.list) != NULL)
02229     for (i = 0; i < npkgs; i++, p++)
02230     {
02231 
02232         rpmMessage(RPMMESS_DEBUG,  "========== +++ %s-%s-%s\n" ,
02233                 p->name, p->version, p->release);
02234         rc = checkPackageDeps(ts, ps, p->h, NULL, p->multiLib);
02235         if (rc)
02236             goto exit;
02237 
02238         /* Adding: check name against conflicts matches. */
02239         rc = checkDependentConflicts(ts, ps, p->name);
02240         if (rc)
02241             goto exit;
02242 
02243         if (p->providesCount == 0 || p->provides == NULL)
02244             continue;
02245 
02246         rc = 0;
02247         for (j = 0; j < p->providesCount; j++) {
02248             /* Adding: check provides key against conflicts matches. */
02249             if (!checkDependentConflicts(ts, ps, p->provides[j]))
02250                 continue;
02251             rc = 1;
02252             /*@innerbreak@*/ break;
02253         }
02254         if (rc)
02255             goto exit;
02256     }
02257 
02258     /*
02259      * Look at the removed packages and make sure they aren't critical.
02260      */
02261     if (ts->numRemovedPackages > 0) {
02262       mi = rpmdbInitIterator(ts->rpmdb, RPMDBI_PACKAGES, NULL, 0);
02263       (void) rpmdbAppendIterator(mi,
02264                         ts->removedPackages, ts->numRemovedPackages);
02265       while ((h = rpmdbNextIterator(mi)) != NULL) {
02266 
02267         {   const char * name, * version, * release;
02268             (void) headerNVR(h, &name, &version, &release);
02269             rpmMessage(RPMMESS_DEBUG,  "========== --- %s-%s-%s\n" ,
02270                 name, version, release);
02271 
02272             /* Erasing: check name against requiredby matches. */
02273             rc = checkDependentPackages(ts, ps, name);
02274             if (rc)
02275                 goto exit;
02276         }
02277 
02278         {   const char ** provides;
02279             int providesCount;
02280             rpmTagType pnt;
02281 
02282             if (hge(h, RPMTAG_PROVIDENAME, &pnt, (void **) &provides,
02283                                 &providesCount))
02284             {
02285                 rc = 0;
02286                 for (j = 0; j < providesCount; j++) {
02287                     /* Erasing: check provides against requiredby matches. */
02288                     if (!checkDependentPackages(ts, ps, provides[j]))
02289                         continue;
02290                     rc = 1;
02291                     /*@innerbreak@*/ break;
02292                 }
02293                 provides = hfd(provides, pnt);
02294                 if (rc)
02295                     goto exit;
02296             }
02297         }
02298 
02299         {   const char ** baseNames, ** dirNames;
02300             int_32 * dirIndexes;
02301             rpmTagType dnt, bnt;
02302             int fileCount;
02303             char * fileName = NULL;
02304             int fileAlloced = 0;
02305             int len;
02306 
02307             if (hge(h, RPMTAG_BASENAMES, &bnt, (void **) &baseNames, &fileCount))
02308             {
02309                 (void) hge(h, RPMTAG_DIRNAMES, &dnt, (void **) &dirNames, NULL);
02310                 (void) hge(h, RPMTAG_DIRINDEXES, NULL, (void **) &dirIndexes,
02311                                 NULL);
02312                 rc = 0;
02313                 for (j = 0; j < fileCount; j++) {
02314                     len = strlen(baseNames[j]) + 1 + 
02315                           strlen(dirNames[dirIndexes[j]]);
02316                     if (len > fileAlloced) {
02317                         fileAlloced = len * 2;
02318                         fileName = xrealloc(fileName, fileAlloced);
02319                     }
02320                     *fileName = '\0';
02321                     (void) stpcpy( stpcpy(fileName, dirNames[dirIndexes[j]]) , baseNames[j]);
02322                     /* Erasing: check filename against requiredby matches. */
02323                     if (!checkDependentPackages(ts, ps, fileName))
02324                         continue;
02325                     rc = 1;
02326                     /*@innerbreak@*/ break;
02327                 }
02328 
02329                 fileName = _free(fileName);
02330                 baseNames = hfd(baseNames, bnt);
02331                 dirNames = hfd(dirNames, dnt);
02332                 if (rc)
02333                     goto exit;
02334             }
02335         }
02336 
02337       }
02338       mi = rpmdbFreeIterator(mi);
02339     }
02340 
02341     if (ps->num) {
02342         *conflicts = ps->problems;
02343         ps->problems = NULL;
02344         *numConflicts = ps->num;
02345     }
02346     rc = 0;
02347 
02348 exit:
02349     mi = rpmdbFreeIterator(mi);
02350     ps->problems = _free(ps->problems);
02351     ps = _free(ps);
02352     if (_cacheDependsRC)
02353         (void) rpmdbCloseDBI(ts->rpmdb, RPMDBI_DEPENDS);
02354     return rc;
02355 }

Generated on Sun Feb 2 23:32:00 2003 for rpm by doxygen1.2.18