- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# lib/rpmgi.c

Go to the documentation of this file.

    00001 /*@-modfilesys@*/
    00005 #include "system.h"
    00006
    00007 #include <rpmio.h>
    00008 #include <rpmcb.h>              /* XXX fnpyKey */
    00009 #include <rpmmacro.h>           /* XXX rpmExpand */
    00010 #include <rpmlib.h>
    00011 #include <rpmte.h>              /* XXX rpmElementType */
    00012 #include <pkgio.h>              /* XXX rpmElementType */
    00013
    00014 #define _RPMGI_INTERNAL
    00015 #define _RPMTS_INTERNAL         /* XXX ts->probs et al */
    00016 #include <rpmgi.h>
    00017
    00018 #include <rpmdb.h>
    00019 #include "manifest.h"
    00020
    00021 #include "debug.h"
    00022
    00023 /*@access FD_t @*/              /* XXX void * arg */
    00024 /*@access fnpyKey @*/
    00025 /*@access rpmdbMatchIterator @*/
    00026 /*@access rpmts @*/
    00027 /*@access rpmps @*/
    00028
    00031 /*@unchecked@*/
    00032 int _rpmgi_debug = 0;
    00033
    00036 /*@unchecked@*/
    00037 rpmgiFlags giFlags = RPMGI_NONE;
    00038
    00041 /*@unchecked@*/
    00042 static int indent = 2;
    00043
    00046 /*@unchecked@*/ /*@observer@*/
    00047 static const char * ftsInfoStrings[] = {
    00048     "UNKNOWN",
    00049     "D",
    00050     "DC",
    00051     "DEFAULT",
    00052     "DNR",
    00053     "DOT",
    00054     "DP",
    00055     "ERR",
    00056     "F",
    00057     "INIT",
    00058     "NS",
    00059     "NSOK",
    00060     "SL",
    00061     "SLNONE",
    00062     "W",
    00063 };
    00064
    00067 /*@observer@*/
    00068 static const char * ftsInfoStr(int fts_info)
    00069         /*@*/
    00070 {
    00071
    00072     if (!(fts_info >= 1 && fts_info <= 14))
    00073         fts_info = 0;
    00074 /*@-compmempass@*/
    00075     return ftsInfoStrings[ fts_info ];
    00076 /*@=compmempass@*/
    00077 }
    00078
    00086 /*@null@*/
    00087 static FD_t rpmgiOpen(const char * path, const char * fmode)
    00088         /*@globals rpmGlobalMacroContext, h_errno, errno, internalState @*/
    00089         /*@modifies rpmGlobalMacroContext, h_errno, errno, internalState @*/
    00090 {
    00091     const char * fn = rpmExpand(path, NULL);
    00092     FD_t fd;
    00093
    00094     /* FIXME (see http://rpm5.org/community/rpm-devel/0523.html) */
    00095     errno = 0;
    00096     fd = Fopen(fn, fmode);
    00097
    00098     if (fd == NULL || Ferror(fd)) {
    00099         rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), fn, Fstrerror(fd));
    00100         if (fd != NULL) (void) Fclose(fd);
    00101         fd = NULL;
    00102     }
    00103     fn = _free(fn);
    00104
    00105     return fd;
    00106 }
    00107
    00114 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
    00115         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00116         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
    00117 {
    00118     FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
    00119     rpmRC rpmrc = RPMRC_FAIL;
    00120
    00121     if (fd != NULL) {
    00122         rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
    00123         (void) Fclose(fd);
    00124     }
    00125     return rpmrc;
    00126 }
    00127
    00134 /*@null@*/
    00135 static Header rpmgiReadHeader(rpmgi gi, const char * path)
    00136         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00137         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
    00138 {
    00139     FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
    00140     Header h = NULL;
    00141
    00142     if (fd != NULL) {
    00143         /* XXX what if path needs expansion? */
    00144         rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
    00145
    00146         (void) Fclose(fd);
    00147
    00148         switch (rpmrc) {
    00149         case RPMRC_NOTFOUND:
    00150             /* XXX Read a package manifest. Restart ftswalk on success. */
    00151         case RPMRC_FAIL:
    00152         default:
    00153             h = headerFree(h);
    00154             break;
    00155         case RPMRC_NOTTRUSTED:
    00156         case RPMRC_NOKEY:
    00157         case RPMRC_OK:
    00158             break;
    00159         }
    00160     }
    00161
    00162     return h;
    00163 }
    00164
    00170 static rpmRC rpmgiLoadNextKey(rpmgi gi)
    00171         /*@modifies gi @*/
    00172 {
    00173     rpmRC rpmrc = RPMRC_NOTFOUND;
    00174     if (gi->argv != NULL && gi->argv[gi->i] != NULL) {
    00175         gi->keyp = gi->argv[gi->i];
    00176         gi->keylen = 0;
    00177         rpmrc = RPMRC_OK;
    00178     } else {
    00179         gi->i = -1;
    00180         gi->keyp = NULL;
    00181         gi->keylen = 0;
    00182     }
    00183     return rpmrc;
    00184 }
    00185
    00194 static rpmRC rpmgiLoadReadHeader(rpmgi gi)
    00195         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00196         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
    00197 {
    00198     rpmRC rpmrc = RPMRC_NOTFOUND;
    00199     Header h = NULL;
    00200
    00201     if (gi->argv != NULL && gi->argv[gi->i] != NULL)
    00202     do {
    00203         const char * fn;        /* XXX gi->hdrPath? */
    00204
    00205         fn = gi->argv[gi->i];
    00206         if (!(gi->flags & RPMGI_NOHEADER)) {
    00207             h = rpmgiReadHeader(gi, fn);
    00208             if (h != NULL)
    00209                 rpmrc = RPMRC_OK;
    00210         } else
    00211             rpmrc = RPMRC_OK;
    00212
    00213         if (rpmrc == RPMRC_OK || gi->flags & RPMGI_NOMANIFEST)
    00214             break;
    00215         if (errno == ENOENT)
    00216             break;
    00217
    00218         /* Not a header, so try for a manifest. */
    00219         gi->argv[gi->i] = NULL;         /* Mark the insertion point */
    00220         rpmrc = rpmgiLoadManifest(gi, fn);
    00221         if (rpmrc != RPMRC_OK) {
    00222             gi->argv[gi->i] = fn;       /* Manifest failed, restore fn */
    00223             break;
    00224         }
    00225         fn = _free(fn);
    00226         rpmrc = RPMRC_NOTFOUND;
    00227     } while (1);
    00228
    00229     if (rpmrc == RPMRC_OK && h != NULL)
    00230         gi->h = headerLink(h);
    00231     h = headerFree(h);
    00232
    00233     return rpmrc;
    00234 }
    00235
    00241 /*@null@*/
    00242 static rpmRC rpmgiWalkPathFilter(rpmgi gi)
    00243         /*@*/
    00244 {
    00245     FTSENT * fts = gi->fts;
    00246     rpmRC rpmrc = RPMRC_NOTFOUND;
    00247     const char * s;
    00248
    00249 if (_rpmgi_debug < 0)
    00250 rpmlog(RPMLOG_DEBUG, "FTS_%s\t%*s %s%s\n", ftsInfoStr(fts->fts_info),
    00251                 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
    00252                 fts->fts_name,
    00253         ((fts->fts_info == FTS_D || fts->fts_info == FTS_DP) ? "/" : ""));
    00254
    00255     switch (fts->fts_info) {
    00256     case FTS_D:         /* preorder directory */
    00257         break;
    00258     case FTS_DP:        /* postorder directory */
    00259         break;
    00260     case FTS_F:         /* regular file */
    00261         /* Ignore all but *.rpm files. */
    00262         s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
    00263         if (strcmp(s, ".rpm"))
    00264             break;
    00265         rpmrc = RPMRC_OK;
    00266         break;
    00267     case FTS_NS:        /* stat(2) failed */
    00268     case FTS_DNR:       /* unreadable directory */
    00269     case FTS_ERR:       /* error; errno is set */
    00270         break;
    00271     case FTS_DC:        /* directory that causes cycles */
    00272     case FTS_DEFAULT:   /* none of the above */
    00273     case FTS_DOT:       /* dot or dot-dot */
    00274     case FTS_INIT:      /* initialized only */
    00275     case FTS_NSOK:      /* no stat(2) requested */
    00276     case FTS_SL:        /* symbolic link */
    00277     case FTS_SLNONE:    /* symbolic link without target */
    00278     case FTS_W:         /* whiteout object */
    00279     default:
    00280         break;
    00281     }
    00282     return rpmrc;
    00283 }
    00284
    00290 /*@null@*/
    00291 static rpmRC rpmgiWalkReadHeader(rpmgi gi)
    00292         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00293         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
    00294 {
    00295     rpmRC rpmrc = RPMRC_NOTFOUND;
    00296
    00297     if (gi->ftsp != NULL)
    00298     while ((gi->fts = Fts_read(gi->ftsp)) != NULL) {
    00299         if (gi->walkPathFilter)
    00300             rpmrc = (*gi->walkPathFilter) (gi);
    00301         else
    00302             rpmrc = rpmgiWalkPathFilter(gi);
    00303         if (rpmrc == RPMRC_OK)
    00304             break;
    00305     }
    00306
    00307     if (rpmrc == RPMRC_OK) {
    00308         Header h = NULL;
    00309         if (!(gi->flags & RPMGI_NOHEADER)) {
    00310             /* XXX rpmrc = rpmgiLoadReadHeader(gi); */
    00311             if (gi->fts != NULL)        /* XXX can't happen */
    00312                 h = rpmgiReadHeader(gi, gi->fts->fts_path);
    00313         }
    00314         if (h != NULL) {
    00315             gi->h = headerLink(h);
    00316             h = headerFree(h);
    00317 /*@-noeffectuncon@*/
    00318             if (gi->stash != NULL)
    00319                 (void) (*gi->stash) (gi, gi->h);
    00320 /*@=noeffectuncon@*/
    00321         }
    00322     }
    00323
    00324     return rpmrc;
    00325 }
    00326
    00327 const char * rpmgiEscapeSpaces(const char * s)
    00328 {
    00329     const char * se;
    00330     const char * t;
    00331     char * te;
    00332     size_t nb = 0;
    00333
    00334     for (se = s; *se; se++) {
    00335         if (isspace(*se))
    00336             nb++;
    00337         nb++;
    00338     }
    00339     nb++;
    00340
    00341     t = te = xmalloc(nb);
    00342     for (se = s; *se; se++) {
    00343         if (isspace(*se))
    00344             *te++ = '\\';
    00345         *te++ = *se;
    00346     }
    00347     *te = '\0';
    00348     return t;
    00349 }
    00350
    00357 static rpmRC rpmgiGlobArgv(rpmgi gi, /*@null@*/ ARGV_t argv)
    00358         /*@globals internalState @*/
    00359         /*@modifies gi, internalState @*/
    00360 {
    00361     const char * arg;
    00362     rpmRC rpmrc = RPMRC_OK;
    00363     int ac = 0;
    00364     int xx;
    00365
    00366     /* XXX Expand globs only if requested or for gi specific tags */
    00367     if ((gi->flags & RPMGI_NOGLOB)
    00368      || !(gi->tag == RPMDBI_HDLIST || gi->tag == RPMDBI_ARGLIST || gi->tag == RPMDBI_FTSWALK))
    00369     {
    00370         if (argv != NULL) {
    00371             while (argv[ac] != NULL)
    00372                 ac++;
    00373 /*@-nullstate@*/ /* XXX argv is not NULL */
    00374             xx = argvAppend(&gi->argv, argv);
    00375 /*@=nullstate@*/
    00376         }
    00377         gi->argc = ac;
    00378         return rpmrc;
    00379     }
    00380
    00381     if (argv != NULL)
    00382     while ((arg = *argv++) != NULL) {
    00383         const char * t = rpmgiEscapeSpaces(arg);
    00384         ARGV_t av = NULL;
    00385
    00386         xx = rpmGlob(t, &ac, &av);
    00387         xx = argvAppend(&gi->argv, av);
    00388         gi->argc += ac;
    00389         av = argvFree(av);
    00390         t = _free(t);
    00391         ac = 0;
    00392     }
    00393     return rpmrc;
    00394 }
    00395
    00401 static rpmRC rpmgiInitFilter(rpmgi gi)
    00402         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
    00403         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
    00404 {
    00405     rpmRC rpmrc = RPMRC_OK;
    00406     ARGV_t av;
    00407     int res = 0;
    00408
    00409     gi->mi = rpmtsInitIterator(gi->ts, gi->tag, gi->keyp, gi->keylen);
    00410
    00411 if (_rpmgi_debug < 0)
    00412 fprintf(stderr, "*** gi %p key %p[%d]\tmi %p\n", gi, gi->keyp, (int)gi->keylen, gi->mi);
    00413
    00414     if (gi->argv != NULL)
    00415     for (av = (const char **) gi->argv; *av != NULL; av++) {
    00416         if (gi->tag == RPMDBI_PACKAGES) {
    00417             int tag = RPMTAG_NAME;
    00418             const char * pat;
    00419             char * a, * ae;
    00420
    00421             pat = a = xstrdup(*av);
    00422             tag = RPMTAG_NAME;
    00423
    00424             /* Parse for "tag=pattern" args. */
    00425             if ((ae = strchr(a, '=')) != NULL) {
    00426                 *ae++ = '\0';
    00427                 if (*a != '\0') {       /* XXX HACK: permit '=foo' */
    00428                     tag = tagValue(a);
    00429                     if (tag < 0) {
    00430                         rpmlog(RPMLOG_NOTICE, _("unknown tag: \"%s\"\n"), a);
    00431                         res = 1;
    00432                     }
    00433                 }
    00434                 pat = ae;
    00435             }
    00436             if (!res) {
    00437 if (_rpmgi_debug  < 0)
    00438 fprintf(stderr, "\tav %p[%d]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (int)(av - gi->argv), *av, tagName(tag), pat);
    00439                 res = rpmdbSetIteratorRE(gi->mi, tag, RPMMIRE_DEFAULT, pat);
    00440             }
    00441             a = _free(a);
    00442         }
    00443
    00444         if (res == 0)
    00445             continue;
    00446
    00447         gi->mi = rpmdbFreeIterator(gi->mi);     /* XXX odd side effect? */
    00448         rpmrc = RPMRC_FAIL;
    00449         break;
    00450     }
    00451
    00452     return rpmrc;
    00453 }
    00454
    00455 rpmgi XrpmgiUnlink(rpmgi gi, const char * msg, const char * fn, unsigned ln)
    00456 {
    00457     if (gi == NULL) return NULL;
    00458
    00459 if (_rpmgi_debug && msg != NULL)
    00460 fprintf(stderr, "--> gi %p -- %d %s(%s) at %s:%u\n", gi, gi->nrefs, msg, tagName(gi->tag), fn, ln);
    00461
    00462     gi->nrefs--;
    00463     return NULL;
    00464 }
    00465
    00466 rpmgi XrpmgiLink(rpmgi gi, const char * msg, const char * fn, unsigned ln)
    00467 {
    00468     if (gi == NULL) return NULL;
    00469     gi->nrefs++;
    00470
    00471 if (_rpmgi_debug && msg != NULL)
    00472 fprintf(stderr, "--> gi %p ++ %d %s(%s) at %s:%u\n", gi, gi->nrefs, msg, tagName(gi->tag), fn, ln);
    00473
    00474     /*@-refcounttrans@*/ return gi; /*@=refcounttrans@*/
    00475 }
    00476
    00477 rpmgi rpmgiFree(rpmgi gi)
    00478 {
    00479     if (gi == NULL)
    00480         return NULL;
    00481
    00482     if (gi->nrefs > 1)
    00483         return rpmgiUnlink(gi, "rpmgiFree");
    00484
    00485     (void) rpmgiUnlink(gi, "rpmgiFree");
    00486
    00487 /*@-usereleased@*/
    00488
    00489     gi->hdrPath = _free(gi->hdrPath);
    00490     gi->h = headerFree(gi->h);
    00491
    00492     gi->argv = argvFree(gi->argv);
    00493
    00494     if (gi->ftsp != NULL) {
    00495         int xx;
    00496         xx = Fts_close(gi->ftsp);
    00497         gi->ftsp = NULL;
    00498         gi->fts = NULL;
    00499     }
    00500     if (gi->fd != NULL) {
    00501         (void) Fclose(gi->fd);
    00502         gi->fd = NULL;
    00503     }
    00504     gi->tsi = rpmtsiFree(gi->tsi);
    00505     gi->mi = rpmdbFreeIterator(gi->mi);
    00506     gi->ts = rpmtsFree(gi->ts);
    00507
    00508     memset(gi, 0, sizeof(*gi));         /* XXX trash and burn */
    00509 /*@-refcounttrans@*/
    00510     gi = _free(gi);
    00511 /*@=refcounttrans@*/
    00512 /*@=usereleased@*/
    00513     return NULL;
    00514 }
    00515
    00516 rpmgi rpmgiNew(rpmts ts, int tag, const void * keyp, size_t keylen)
    00517 {
    00518     rpmgi gi = xcalloc(1, sizeof(*gi));
    00519
    00520     if (gi == NULL)
    00521         return NULL;
    00522
    00523     gi->ts = rpmtsLink(ts, "rpmgiNew");
    00524     gi->tsOrder = rpmtsOrder;
    00525     gi->tag = tag;
    00526 /*@-assignexpose@*/
    00527     gi->keyp = keyp;
    00528 /*@=assignexpose@*/
    00529     gi->keylen = keylen;
    00530
    00531     gi->flags = 0;
    00532     gi->active = 0;
    00533     gi->i = -1;
    00534     gi->hdrPath = NULL;
    00535     gi->h = NULL;
    00536
    00537     gi->tsi = NULL;
    00538     gi->mi = NULL;
    00539     gi->fd = NULL;
    00540     gi->argv = xcalloc(1, sizeof(*gi->argv));
    00541     gi->argc = 0;
    00542     gi->ftsOpts = 0;
    00543     gi->ftsp = NULL;
    00544     gi->fts = NULL;
    00545     gi->walkPathFilter = NULL;
    00546
    00547     gi = rpmgiLink(gi, "rpmgiNew");
    00548
    00549     return gi;
    00550 }
    00551
    00552 /*@observer@*/ /*@unchecked@*/
    00553 static const char * _query_hdlist_path  = "/usr/share/comps/%{_arch}/hdlist";
    00554
    00555 rpmRC rpmgiNext(/*@null@*/ rpmgi gi)
    00556 {
    00557     char hnum[32];
    00558     rpmRC rpmrc = RPMRC_NOTFOUND;
    00559     int xx;
    00560
    00561     if (gi == NULL)
    00562         return rpmrc;
    00563
    00564 if (_rpmgi_debug)
    00565 fprintf(stderr, "*** rpmgiNext(%p) tag %s\n", gi, tagName(gi->tag));
    00566
    00567     /* Free header from previous iteration. */
    00568     gi->h = headerFree(gi->h);
    00569     gi->hdrPath = _free(gi->hdrPath);
    00570     hnum[0] = '\0';
    00571
    00572     if (++gi->i >= 0)
    00573     switch (gi->tag) {
    00574     default:
    00575         if (!gi->active) {
    00576 nextkey:
    00577             rpmrc = rpmgiLoadNextKey(gi);
    00578             if (rpmrc != RPMRC_OK)
    00579                 goto enditer;
    00580             rpmrc = rpmgiInitFilter(gi);
    00581             if (rpmrc != RPMRC_OK || gi->mi == NULL) {
    00582                 gi->mi = rpmdbFreeIterator(gi->mi);     /* XXX unnecessary */
    00583                 gi->i++;
    00584                 goto nextkey;
    00585             }
    00586             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
    00587             gi->active = 1;
    00588         }
    00589         if (gi->mi != NULL) {   /* XXX unnecessary */
    00590             Header h = rpmdbNextIterator(gi->mi);
    00591             if (h != NULL) {
    00592                 if (!(gi->flags & RPMGI_NOHEADER))
    00593                     gi->h = headerLink(h);
    00594                 sprintf(hnum, "%u", rpmdbGetIteratorOffset(gi->mi));
    00595                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
    00596                 rpmrc = RPMRC_OK;
    00597                 /* XXX header reference held by iterator, so no headerFree */
    00598             }
    00599         }
    00600         if (rpmrc != RPMRC_OK) {
    00601             gi->mi = rpmdbFreeIterator(gi->mi);
    00602             goto nextkey;
    00603         }
    00604         break;
    00605     case RPMDBI_PACKAGES:
    00606         if (!gi->active) {
    00607             rpmrc = rpmgiInitFilter(gi);
    00608             if (rpmrc != RPMRC_OK) {
    00609                 gi->mi = rpmdbFreeIterator(gi->mi);     /* XXX unnecessary */
    00610                 goto enditer;
    00611             }
    00612             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
    00613             gi->active = 1;
    00614         }
    00615         if (gi->mi != NULL) {   /* XXX unnecessary */
    00616             Header h = rpmdbNextIterator(gi->mi);
    00617             if (h != NULL) {
    00618                 if (!(gi->flags & RPMGI_NOHEADER))
    00619                     gi->h = headerLink(h);
    00620                 sprintf(hnum, "%u", rpmdbGetIteratorOffset(gi->mi));
    00621                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
    00622                 rpmrc = RPMRC_OK;
    00623                 /* XXX header reference held by iterator, so no headerFree */
    00624             }
    00625         }
    00626         if (rpmrc != RPMRC_OK) {
    00627             gi->mi = rpmdbFreeIterator(gi->mi);
    00628             goto enditer;
    00629         }
    00630         break;
    00631     case RPMDBI_REMOVED:
    00632     case RPMDBI_ADDED:
    00633     {   rpmte p;
    00634         int teType = 0;
    00635         const char * teTypeString = NULL;
    00636
    00637         if (!gi->active) {
    00638             gi->tsi = rpmtsiInit(gi->ts);
    00639             gi->active = 1;
    00640         }
    00641         if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) {
    00642             Header h = rpmteHeader(p);
    00643             if (h != NULL)
    00644                 if (!(gi->flags & RPMGI_NOHEADER)) {
    00645                     gi->h = headerLink(h);
    00646                 switch(rpmteType(p)) {
    00647                 case TR_ADDED:  teTypeString = "+++";   /*@switchbreak@*/break;
    00648                 case TR_REMOVED: teTypeString = "---";  /*@switchbreak@*/break;
    00649                 }
    00650                 sprintf(hnum, "%u", (unsigned)gi->i);
    00651                 gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL);
    00652                 rpmrc = RPMRC_OK;
    00653                 h = headerFree(h);
    00654             }
    00655         }
    00656         if (rpmrc != RPMRC_OK) {
    00657             gi->tsi = rpmtsiFree(gi->tsi);
    00658             goto enditer;
    00659         }
    00660     }   break;
    00661     case RPMDBI_HDLIST:
    00662         if (!gi->active) {
    00663             const char * path = rpmExpand("%{?_query_hdlist_path}", NULL);
    00664             if (path == NULL || *path == '\0') {
    00665                 path = _free(path);
    00666                 path = rpmExpand(_query_hdlist_path, NULL);
    00667             }
    00668             gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}");
    00669             gi->active = 1;
    00670             path = _free(path);
    00671         }
    00672         if (gi->fd != NULL) {
    00673             Header h = NULL;
    00674             const char item[] = "Header";
    00675             const char * msg = NULL;
    00676 /*@+voidabstract@*/
    00677             rpmrc = rpmpkgRead(item, gi->fd, &h, &msg);
    00678 /*@=voidabstract@*/
    00679             if (rpmrc != RPMRC_OK) {
    00680                 rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg);
    00681                 h = NULL;
    00682             }
    00683             msg = _free(msg);
    00684             if (h != NULL) {
    00685                 if (!(gi->flags & RPMGI_NOHEADER))
    00686                     gi->h = headerLink(h);
    00687                 sprintf(hnum, "%u", (unsigned)gi->i);
    00688                 gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
    00689                 rpmrc = RPMRC_OK;
    00690                 h = headerFree(h);
    00691             }
    00692         }
    00693         if (rpmrc != RPMRC_OK) {
    00694             if (gi->fd != NULL) (void) Fclose(gi->fd);
    00695             gi->fd = NULL;
    00696             goto enditer;
    00697         }
    00698         break;
    00699     case RPMDBI_ARGLIST:
    00700         /* XXX gi->active initialize? */
    00701 if (_rpmgi_debug  < 0)
    00702 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
    00703         /* Read next header, lazily expanding manifests as found. */
    00704         rpmrc = rpmgiLoadReadHeader(gi);
    00705
    00706         if (rpmrc != RPMRC_OK)  /* XXX check this */
    00707             goto enditer;
    00708
    00709         gi->hdrPath = xstrdup(gi->argv[gi->i]);
    00710         break;
    00711     case RPMDBI_FTSWALK:
    00712         if (gi->argv == NULL || gi->argv[0] == NULL)            /* HACK */
    00713             goto enditer;
    00714
    00715         if (!gi->active) {
    00716             gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
    00717             /* XXX NULL with open(2)/malloc(3) errno set */
    00718             gi->active = 1;
    00719         }
    00720
    00721         /* Read next header, lazily walking file tree. */
    00722         rpmrc = rpmgiWalkReadHeader(gi);
    00723
    00724         if (rpmrc != RPMRC_OK) {
    00725             xx = Fts_close(gi->ftsp);
    00726             gi->ftsp = NULL;
    00727             goto enditer;
    00728         }
    00729
    00730         if (gi->fts != NULL)
    00731             gi->hdrPath = xstrdup(gi->fts->fts_path);
    00732         break;
    00733     }
    00734
    00735     if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
    00736         /* XXX rpmgi hack: Save header in transaction element. */
    00737         if (gi->flags & RPMGI_ERASING) {
    00738             static int hdrx = 0;
    00739             int dboffset = headerGetInstance(gi->h);
    00740             if (dboffset <= 0)
    00741                 dboffset = --hdrx;
    00742             xx = rpmtsAddEraseElement(gi->ts, gi->h, dboffset);
    00743         } else
    00744             xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
    00745     }
    00746
    00747     return rpmrc;
    00748
    00749 enditer:
    00750     if (gi->flags & RPMGI_TSORDER) {
    00751         rpmts ts = gi->ts;
    00752         rpmps ps;
    00753         int i;
    00754
    00755         /* Block access to indices used for depsolving. */
    00756         if (!(gi->flags & RPMGI_ERASING)) {
    00757             (void) rpmtsSetGoal(ts, TSM_INSTALL);
    00758             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMDBI_DEPENDS);
    00759             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_BASENAMES);
    00760             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_PROVIDENAME);
    00761         } else {
    00762             (void) rpmtsSetGoal(ts, TSM_ERASE);
    00763         }
    00764
    00765         xx = rpmtsCheck(ts);
    00766
    00767         /* Permit access to indices used for depsolving. */
    00768         if (!(gi->flags & RPMGI_ERASING)) {
    00769             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), +RPMTAG_PROVIDENAME);
    00770             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), +RPMTAG_BASENAMES);
    00771             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), +RPMDBI_DEPENDS);
    00772         }
    00773
    00774         /* XXX query/verify will need the glop added to a buffer instead. */
    00775         ps = rpmtsProblems(ts);
    00776         if (rpmpsNumProblems(ps) > 0) {
    00777             /* XXX rpminstall will need RPMLOG_ERR */
    00778             rpmlog(RPMLOG_INFO, _("Failed dependencies:\n"));
    00779             if (rpmIsVerbose())
    00780                 rpmpsPrint(NULL, ps);
    00781
    00782             if (ts->suggests != NULL && ts->nsuggests > 0) {
    00783                 rpmlog(RPMLOG_INFO, _("    Suggested resolutions:\n"));
    00784                 for (i = 0; i < ts->nsuggests; i++) {
    00785                     const char * str = ts->suggests[i];
    00786
    00787                     if (str == NULL)
    00788                         break;
    00789
    00790                     rpmlog(RPMLOG_INFO, "\t%s\n", str);
    00791
    00792                     ts->suggests[i] = NULL;
    00793                     str = _free(str);
    00794                 }
    00795                 ts->suggests = _free(ts->suggests);
    00796             }
    00797
    00798         }
    00799         ps = rpmpsFree(ps);
    00800         ts->probs = rpmpsFree(ts->probs);       /* XXX hackery */
    00801
    00802         /* XXX Display dependency loops with rpm -qvT. */
    00803         if (rpmIsVerbose())
    00804             (void) rpmtsSetDFlags(ts, (rpmtsDFlags(ts) | RPMDEPS_FLAG_DEPLOOPS));
    00805
    00806         xx = (*gi->tsOrder) (ts);
    00807
    00808         /* XXX hackery alert! */
    00809         gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
    00810         gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER);
    00811
    00812     }
    00813
    00814     gi->h = headerFree(gi->h);
    00815     gi->hdrPath = _free(gi->hdrPath);
    00816     gi->i = -1;
    00817     gi->active = 0;
    00818     return rpmrc;
    00819 }
    00820
    00821 rpmgiFlags rpmgiGetFlags(rpmgi gi)
    00822 {
    00823     return (gi != NULL ? gi->flags : RPMGI_NONE);
    00824 }
    00825
    00826 const char * rpmgiHdrPath(rpmgi gi)
    00827 {
    00828     return (gi != NULL ? gi->hdrPath : NULL);
    00829 }
    00830
    00831 Header rpmgiHeader(rpmgi gi)
    00832 {
    00833 /*@-compdef -refcounttrans -retexpose -usereleased@*/
    00834     return (gi != NULL ? gi->h : NULL);
    00835 /*@=compdef =refcounttrans =retexpose =usereleased@*/
    00836 }
    00837
    00838 rpmts rpmgiTs(rpmgi gi)
    00839 {
    00840 /*@-compdef -refcounttrans -retexpose -usereleased@*/
    00841     return (gi != NULL ? gi->ts : NULL);
    00842 /*@=compdef =refcounttrans =retexpose =usereleased@*/
    00843 }
    00844
    00845 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
    00846 {
    00847     if (gi == NULL) return RPMRC_FAIL;
    00848     gi->ftsOpts = ftsOpts;
    00849     gi->flags = flags;
    00850     return rpmgiGlobArgv(gi, argv);
    00851 }
    00852
    00853 /*@=modfilesys@*/