Main Page   Modules   Compound List   File List   Compound Members   File Members   Related Pages  

lib/depends.c

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

Generated at Sun Apr 8 18:42:59 2001 for rpm by doxygen1.2.3 written by Dimitri van Heesch, © 1997-2000