rpm 5.3.7

lib/rpmgi.c

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