rpm 5.3.12
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         switch (rpmrc) {
00135         case RPMRC_NOTFOUND:
00136         case RPMRC_FAIL:
00137         default:
00138             gi->rc = rpmrc;
00139             break;
00140         case RPMRC_NOTTRUSTED:
00141         case RPMRC_NOKEY:
00142         case RPMRC_OK:
00143             /* XXX manifest tried after *.rpm forces a reset. here? */
00144             if (gi->rc == RPMRC_NOTFOUND)
00145                 gi->rc = 0;
00146             break;
00147     }
00148     } else {
00149         gi->rc = RPMRC_NOTFOUND;        /* XXX other failures? */
00150     }
00151 
00152     return rpmrc;
00153 }
00154 
00155 Header rpmgiReadHeader(rpmgi gi, const char * path)
00156 {
00157     FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
00158     Header h = NULL;
00159 
00160     if (fd != NULL) {
00161         /* XXX what if path needs expansion? */
00162         rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
00163 
00164         (void) Fclose(fd);
00165 
00166         switch (rpmrc) {
00167         case RPMRC_NOTFOUND:
00168             /* XXX Read a package manifest. Restart ftswalk on success. */
00169         case RPMRC_FAIL:
00170         default:
00171             (void)headerFree(h);
00172             h = NULL;
00173             gi->rc = rpmrc;
00174             break;
00175         case RPMRC_NOTTRUSTED:
00176         case RPMRC_NOKEY:
00177         case RPMRC_OK:
00178             break;
00179         }
00180     } else {
00181         gi->rc = RPMRC_NOTFOUND;        /* XXX other failures? */
00182     }
00183 
00184     return h;
00185 }
00186 
00192 static rpmRC rpmgiLoadNextKey(rpmgi gi)
00193         /*@modifies gi @*/
00194 {
00195     rpmRC rpmrc = RPMRC_NOTFOUND;
00196     if (gi->argv != NULL && gi->argv[gi->i] != NULL) {
00197         gi->keyp = gi->argv[gi->i];
00198         gi->keylen = 0;
00199         rpmrc = RPMRC_OK;
00200     } else {
00201         gi->i = -1;
00202         gi->keyp = NULL;
00203         gi->keylen = 0;
00204     }
00205     return rpmrc;
00206 }
00207 
00216 static rpmRC rpmgiLoadReadHeader(rpmgi gi)
00217         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00218         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
00219 {
00220     rpmRC rpmrc = RPMRC_NOTFOUND;
00221     Header h = NULL;
00222 
00223     if (gi->argv != NULL && gi->argv[gi->i] != NULL)
00224     do {
00225         const char * fn;        /* XXX gi->hdrPath? */
00226 
00227         fn = gi->argv[gi->i];
00228         /* XXX Skip +bing -bang =boom special arguments. */
00229         if (strchr("-+=", *fn) == NULL && !(gi->flags & RPMGI_NOHEADER)) {
00230             h = rpmgiReadHeader(gi, fn);
00231             if (h != NULL)
00232                 rpmrc = RPMRC_OK;
00233         } else
00234             rpmrc = RPMRC_OK;
00235 
00236         if (rpmrc == RPMRC_OK || gi->flags & RPMGI_NOMANIFEST)
00237             break;
00238         if (errno == ENOENT)
00239             break;
00240 
00241         /* Not a header, so try for a manifest. */
00242         gi->argv[gi->i] = NULL;         /* Mark the insertion point */
00243         rpmrc = rpmgiLoadManifest(gi, fn);
00244         /* XXX its unclear if RPMRC_NOTFOUND should fail or continue here. */
00245         if (rpmrc != RPMRC_OK) {
00246             gi->argv[gi->i] = fn;       /* Manifest failed, restore fn */
00247             break;
00248         }
00249         fn = _free(fn);
00250         rpmrc = RPMRC_NOTFOUND;
00251     } while (1);
00252 
00253     if (rpmrc == RPMRC_OK && h != NULL)
00254         gi->h = headerLink(h);
00255     (void)headerFree(h);
00256     h = NULL;
00257 
00258     return rpmrc;
00259 }
00260 
00266 /*@null@*/
00267 static rpmRC rpmgiWalkPathFilter(rpmgi gi)
00268         /*@*/
00269 {
00270     FTSENT * fts = gi->fts;
00271     rpmRC rpmrc = RPMRC_NOTFOUND;
00272     const char * s;
00273 
00274 if (_rpmgi_debug < 0)
00275 rpmlog(RPMLOG_DEBUG, "FTS_%s\t%*s %s%s\n", ftsInfoStr(fts->fts_info),
00276                 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
00277                 fts->fts_name,
00278         ((fts->fts_info == FTS_D || fts->fts_info == FTS_DP) ? "/" : ""));
00279 
00280     switch (fts->fts_info) {
00281     case FTS_D:         /* preorder directory */
00282         break;
00283     case FTS_DP:        /* postorder directory */
00284         break;
00285     case FTS_F:         /* regular file */
00286         if ((size_t)fts->fts_namelen <= sizeof(".rpm"))
00287             break;
00288         /* Ignore all but *.rpm files. */
00289         s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
00290         if (strcmp(s, ".rpm"))
00291             break;
00292         rpmrc = RPMRC_OK;
00293         break;
00294     case FTS_NS:        /* stat(2) failed */
00295     case FTS_DNR:       /* unreadable directory */
00296     case FTS_ERR:       /* error; errno is set */
00297         break;
00298     case FTS_DC:        /* directory that causes cycles */
00299     case FTS_DEFAULT:   /* none of the above */
00300     case FTS_DOT:       /* dot or dot-dot */
00301     case FTS_INIT:      /* initialized only */
00302     case FTS_NSOK:      /* no stat(2) requested */
00303     case FTS_SL:        /* symbolic link */
00304     case FTS_SLNONE:    /* symbolic link without target */
00305     case FTS_W:         /* whiteout object */
00306     default:
00307         break;
00308     }
00309     return rpmrc;
00310 }
00311 
00317 /*@null@*/
00318 static rpmRC rpmgiWalkReadHeader(rpmgi gi)
00319         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00320         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
00321 {
00322     rpmRC rpmrc = RPMRC_NOTFOUND;
00323 
00324     if (gi->ftsp != NULL)
00325     while ((gi->fts = Fts_read(gi->ftsp)) != NULL) {
00326         if (gi->walkPathFilter)
00327             rpmrc = (*gi->walkPathFilter) (gi);
00328         else
00329             rpmrc = rpmgiWalkPathFilter(gi);
00330         if (rpmrc == RPMRC_OK)
00331             break;
00332     }
00333 
00334     if (rpmrc == RPMRC_OK) {
00335         Header h = NULL;
00336         if (!(gi->flags & RPMGI_NOHEADER)) {
00337             /* XXX rpmrc = rpmgiLoadReadHeader(gi); */
00338             if (gi->fts != NULL)        /* XXX can't happen */
00339                 h = rpmgiReadHeader(gi, gi->fts->fts_path);
00340         }
00341         if (h != NULL) {
00342             gi->h = headerLink(h);
00343             (void)headerFree(h);
00344             h = NULL;
00345 /*@-noeffectuncon@*/
00346             if (gi->stash != NULL)
00347                 (void) (*gi->stash) (gi, gi->h);
00348 /*@=noeffectuncon@*/
00349         }
00350     }
00351 
00352     return rpmrc;
00353 }
00354 
00355 const char * rpmgiEscapeSpaces(const char * s)
00356 {
00357     const char * se;
00358     const char * t;
00359     char * te;
00360     size_t nb = 0;
00361 
00362     for (se = s; *se; se++) {
00363         if (isspace(*se))
00364             nb++;
00365         nb++;
00366     }
00367     nb++;
00368 
00369     t = te = xmalloc(nb);
00370     for (se = s; *se; se++) {
00371         if (isspace(*se))
00372             *te++ = '\\';
00373         *te++ = *se;
00374     }
00375     *te = '\0';
00376     return t;
00377 }
00378 
00385 static rpmRC rpmgiGlobArgv(rpmgi gi, /*@null@*/ ARGV_t argv)
00386         /*@globals internalState @*/
00387         /*@modifies gi, internalState @*/
00388 {
00389     const char * arg;
00390     rpmRC rpmrc = RPMRC_OK;
00391     int ac = 0;
00392     int xx;
00393 
00394     /* XXX Expand globs only if requested or for gi specific tags */
00395     if ((gi->flags & RPMGI_NOGLOB)
00396      || !(gi->tag == RPMDBI_HDLIST || gi->tag == RPMDBI_ARGLIST || gi->tag == RPMDBI_FTSWALK))
00397     {
00398         if (argv != NULL) {
00399             while (argv[ac] != NULL)
00400                 ac++;
00401 /*@-nullstate@*/ /* XXX argv is not NULL */
00402             xx = argvAppend(&gi->argv, argv);
00403 /*@=nullstate@*/
00404         }
00405         gi->argc = ac;
00406         return rpmrc;
00407     }
00408 
00409     if (argv != NULL)
00410     while ((arg = *argv++) != NULL) {
00411         const char * t = rpmgiEscapeSpaces(arg);
00412         ARGV_t av = NULL;
00413 
00414         xx = rpmGlob(t, &ac, &av);
00415         xx = argvAppend(&gi->argv, av);
00416         gi->argc += ac;
00417         av = argvFree(av);
00418         t = _free(t);
00419         ac = 0;
00420     }
00421     return rpmrc;
00422 }
00423 
00429 static rpmRC rpmgiInitFilter(rpmgi gi)
00430         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00431         /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
00432 {
00433     rpmRC rpmrc = RPMRC_OK;
00434     ARGV_t av;
00435     int res = 0;
00436 
00437     gi->mi = rpmtsInitIterator(gi->ts, gi->tag, gi->keyp, gi->keylen);
00438 
00439 if (_rpmgi_debug < 0)
00440 fprintf(stderr, "*** gi %p key %p[%d]\tmi %p\n", gi, gi->keyp, (int)gi->keylen, gi->mi);
00441 
00442     if (gi->argv != NULL)
00443     for (av = (const char **) gi->argv; *av != NULL; av++) {
00444         if (gi->tag == RPMDBI_PACKAGES) {
00445             int tag = RPMTAG_NAME;
00446             const char * pat;
00447             char * a, * ae;
00448 
00449             pat = a = xstrdup(*av);
00450             tag = RPMTAG_NAME;
00451 
00452             /* Parse for "tag=pattern" args. */
00453             if ((ae = strchr(a, '=')) != NULL) {
00454                 *ae++ = '\0';
00455                 if (*a != '\0') {       /* XXX HACK: permit '=foo' */
00456                     tag = tagValue(a);
00457                     if (tag < 0) {
00458                         rpmlog(RPMLOG_NOTICE, _("unknown tag: \"%s\"\n"), a);
00459                         res = 1;
00460                     }
00461                 }
00462                 pat = ae;
00463             }
00464             if (!res) {
00465 if (_rpmgi_debug  < 0)
00466 fprintf(stderr, "\tav %p[%d]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (int)(av - gi->argv), *av, tagName(tag), pat);
00467                 res = rpmmiAddPattern(gi->mi, tag, RPMMIRE_DEFAULT, pat);
00468             }
00469             a = _free(a);
00470         }
00471 
00472         if (res == 0)
00473             continue;
00474 
00475         gi->mi = rpmmiFree(gi->mi);     /* XXX odd side effect? */
00476         rpmrc = RPMRC_FAIL;
00477         break;
00478     }
00479 
00480     return rpmrc;
00481 }
00482 
00483 /*@-mustmod@*/
00484 static void rpmgiFini(void * _gi)
00485         /*@modifies _gi @*/
00486 {
00487     rpmgi gi = _gi;
00488     int xx;
00489 
00490     gi->hdrPath = _free(gi->hdrPath);
00491     (void)headerFree(gi->h);
00492     gi->h = NULL;
00493 
00494     gi->argv = argvFree(gi->argv);
00495 
00496     if (gi->ftsp != NULL) {
00497         xx = Fts_close(gi->ftsp);
00498         gi->ftsp = NULL;
00499         gi->fts = NULL;
00500     }
00501     if (gi->fd != NULL) {
00502         xx = Fclose(gi->fd);
00503         gi->fd = NULL;
00504     }
00505     gi->tsi = rpmtsiFree(gi->tsi);
00506     gi->mi = rpmmiFree(gi->mi);
00507     (void)rpmtsFree(gi->ts); 
00508     gi->ts = NULL;
00509 }
00510 /*@=mustmod@*/
00511 
00512 /*@unchecked@*/ /*@only@*/ /*@null@*/
00513 rpmioPool _rpmgiPool;
00514 
00515 static rpmgi rpmgiGetPool(/*@null@*/ rpmioPool pool)
00516         /*@globals _rpmgiPool, fileSystem, internalState @*/
00517         /*@modifies pool, _rpmgiPool, fileSystem, internalState @*/
00518 {
00519     rpmgi gi;
00520 
00521     if (_rpmgiPool == NULL) {
00522         _rpmgiPool = rpmioNewPool("gi", sizeof(*gi), -1, _rpmgi_debug,
00523                         NULL, NULL, rpmgiFini);
00524         pool = _rpmgiPool;
00525     }
00526     gi = (rpmgi) rpmioGetPool(pool, sizeof(*gi));
00527     memset(((char *)gi)+sizeof(gi->_item), 0, sizeof(*gi)-sizeof(gi->_item));
00528     return gi;
00529 }
00530 
00531 rpmgi rpmgiNew(rpmts ts, int tag, const void * keyp, size_t keylen)
00532 {
00533     rpmgi gi = rpmgiGetPool(_rpmgiPool);
00534 
00535     if (gi == NULL)     /* XXX can't happen */
00536         return NULL;
00537 
00538 /*@-assignexpose -castexpose @*/
00539     gi->ts = rpmtsLink(ts, "rpmgiNew");
00540 /*@=assignexpose =castexpose @*/
00541     gi->tsOrder = rpmcliInstallOrder;
00542     gi->tag = (rpmTag) tag;
00543 /*@-assignexpose@*/
00544     gi->keyp = keyp;
00545 /*@=assignexpose@*/
00546     gi->keylen = keylen;
00547 
00548     gi->flags = 0;
00549     gi->active = 0;
00550     gi->i = -1;
00551     gi->hdrPath = NULL;
00552     gi->h = NULL;
00553     gi->rc = 0;
00554 
00555     gi->tsi = NULL;
00556     gi->mi = NULL;
00557     gi->fd = NULL;
00558     gi->argv = xcalloc(1, sizeof(*gi->argv));
00559     gi->argc = 0;
00560     gi->ftsOpts = 0;
00561     gi->ftsp = NULL;
00562     gi->fts = NULL;
00563     gi->walkPathFilter = NULL;
00564     gi->stash = NULL;
00565 
00566     return rpmgiLink(gi, "rpmgiNew");
00567 }
00568 
00569 /*@observer@*/ /*@unchecked@*/
00570 static const char * _query_hdlist_path  = "/usr/share/comps/%{_arch}/hdlist";
00571 
00572 rpmRC rpmgiNext(/*@null@*/ rpmgi gi)
00573 {
00574     char hnum[32];
00575     rpmRC rpmrc = RPMRC_NOTFOUND;
00576     int xx;
00577 
00578     if (gi == NULL)
00579         return rpmrc;
00580 
00581 if (_rpmgi_debug)
00582 fprintf(stderr, "--> %s(%p) tag %s\n", __FUNCTION__, gi, tagName(gi->tag));
00583 
00584     /* Free header from previous iteration. */
00585     (void)headerFree(gi->h);
00586     gi->h = NULL;
00587     gi->hdrPath = _free(gi->hdrPath);
00588     hnum[0] = '\0';
00589 
00590     if (++gi->i >= 0)
00591     switch (gi->tag) {
00592     default:
00593         if (!gi->active) {
00594 nextkey:
00595             rpmrc = rpmgiLoadNextKey(gi);
00596             if (rpmrc != RPMRC_OK)
00597                 goto enditer;
00598             rpmrc = rpmgiInitFilter(gi);
00599             if (rpmrc != RPMRC_OK || gi->mi == NULL) {
00600                 gi->mi = rpmmiFree(gi->mi);     /* XXX unnecessary */
00601                 gi->i++;
00602                 goto nextkey;
00603             }
00604             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
00605             gi->active = 1;
00606         }
00607         if (gi->mi != NULL) {   /* XXX unnecessary */
00608             Header h = rpmmiNext(gi->mi);
00609             if (h != NULL) {
00610                 if (!(gi->flags & RPMGI_NOHEADER))
00611                     gi->h = headerLink(h);
00612                 /* XXX use h->origin instead. */
00613                 sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
00614                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
00615                 rpmrc = RPMRC_OK;
00616                 /* XXX header reference held by iterator, so no headerFree */
00617             }
00618         }
00619         if (rpmrc != RPMRC_OK) {
00620             gi->mi = rpmmiFree(gi->mi);
00621             goto nextkey;
00622         }
00623         break;
00624     case RPMDBI_PACKAGES:
00625         if (!gi->active) {
00626             rpmrc = rpmgiInitFilter(gi);
00627             if (rpmrc != RPMRC_OK) {
00628                 gi->mi = rpmmiFree(gi->mi);     /* XXX unnecessary */
00629                 goto enditer;
00630             }
00631             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
00632             gi->active = 1;
00633         }
00634         if (gi->mi != NULL) {   /* XXX unnecessary */
00635             Header h = rpmmiNext(gi->mi);
00636             if (h != NULL) {
00637                 if (!(gi->flags & RPMGI_NOHEADER))
00638                     gi->h = headerLink(h);
00639                 /* XXX use h->origin instead. */
00640                 sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
00641                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
00642                 rpmrc = RPMRC_OK;
00643                 /* XXX header reference held by iterator, so no headerFree */
00644             }
00645         }
00646         if (rpmrc != RPMRC_OK) {
00647             gi->mi = rpmmiFree(gi->mi);
00648             goto enditer;
00649         }
00650         break;
00651     case RPMDBI_REMOVED:
00652     case RPMDBI_ADDED:
00653     {   rpmte p;
00654         int teType = 0;
00655         const char * teTypeString = NULL;
00656 
00657         if (!gi->active) {
00658             gi->tsi = rpmtsiInit(gi->ts);
00659             gi->active = 1;
00660         }
00661         if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) {
00662             Header h = rpmteHeader(p);
00663             if (h != NULL)
00664                 if (!(gi->flags & RPMGI_NOHEADER)) {
00665                     gi->h = headerLink(h);
00666                 switch(rpmteType(p)) {
00667                 case TR_ADDED:  teTypeString = "+++";   /*@switchbreak@*/break;
00668                 case TR_REMOVED: teTypeString = "---";  /*@switchbreak@*/break;
00669                 }
00670                 sprintf(hnum, "%u", (unsigned)gi->i);
00671                 gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL);
00672                 rpmrc = RPMRC_OK;
00673                 (void)headerFree(h);
00674                 h = NULL;
00675             }
00676         }
00677         if (rpmrc != RPMRC_OK) {
00678             gi->tsi = rpmtsiFree(gi->tsi);
00679             goto enditer;
00680         }
00681     }   break;
00682     case RPMDBI_HDLIST:
00683         if (!gi->active) {
00684             const char * path = rpmExpand("%{?_query_hdlist_path}", NULL);
00685             if (path == NULL || *path == '\0') {
00686                 path = _free(path);
00687                 path = rpmExpand(_query_hdlist_path, NULL);
00688             }
00689             gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}");
00690             gi->active = 1;
00691             path = _free(path);
00692         }
00693         if (gi->fd != NULL) {
00694             Header h = NULL;
00695             const char item[] = "Header";
00696             const char * msg = NULL;
00697 /*@+voidabstract@*/
00698             rpmrc = rpmpkgRead(item, gi->fd, &h, &msg);
00699 /*@=voidabstract@*/
00700             switch(rpmrc) {
00701                 default:
00702                     rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg);
00703                 case RPMRC_NOTFOUND:
00704                     h = NULL;
00705                 case RPMRC_OK:
00706                     break;
00707             }
00708             msg = _free(msg);
00709             if (h != NULL) {
00710                 if (!(gi->flags & RPMGI_NOHEADER))
00711                     gi->h = headerLink(h);
00712                 sprintf(hnum, "%u", (unsigned)gi->i);
00713                 gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
00714                 rpmrc = RPMRC_OK;
00715                 (void)headerFree(h);
00716                 h = NULL;
00717             }
00718         }
00719         if (rpmrc != RPMRC_OK) {
00720             if (gi->fd != NULL) (void) Fclose(gi->fd);
00721             gi->fd = NULL;
00722             goto enditer;
00723         }
00724         break;
00725     case RPMDBI_ARGLIST:
00726         /* XXX gi->active initialize? */
00727 if (_rpmgi_debug  < 0)
00728 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
00729         /* Read next header, lazily expanding manifests as found. */
00730         rpmrc = rpmgiLoadReadHeader(gi);
00731 
00732         if (rpmrc != RPMRC_OK)  /* XXX check this */
00733             goto enditer;
00734 
00735         gi->hdrPath = xstrdup(gi->argv[gi->i]);
00736         break;
00737     case RPMDBI_FTSWALK:
00738         if (gi->argv == NULL || gi->argv[0] == NULL)            /* HACK */
00739             goto enditer;
00740 
00741         if (!gi->active) {
00742             gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
00743             /* XXX NULL with open(2)/malloc(3) errno set */
00744             gi->active = 1;
00745         }
00746 
00747         /* Read next header, lazily walking file tree. */
00748         rpmrc = rpmgiWalkReadHeader(gi);
00749 
00750         if (rpmrc != RPMRC_OK) {
00751             xx = Fts_close(gi->ftsp);
00752             gi->ftsp = NULL;
00753             goto enditer;
00754         }
00755 
00756         if (gi->fts != NULL)
00757             gi->hdrPath = xstrdup(gi->fts->fts_path);
00758         break;
00759     }
00760 
00761     if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
00762         /* XXX rpmgi hack: Save header in transaction element. */
00763         if (gi->flags & RPMGI_ERASING) {
00764             uint32_t hdrNum = headerGetInstance(gi->h);
00765             xx = rpmtsAddEraseElement(gi->ts, gi->h, hdrNum);
00766         } else
00767             xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
00768     }
00769     goto exit;
00770 
00771 enditer:
00772     if (gi->flags & RPMGI_TSORDER) {
00773         rpmts ts = gi->ts;
00774 
00775         /* Block access to indices used for depsolving. */
00776         if (!(gi->flags & RPMGI_ERASING)) {
00777             (void) rpmtsSetGoal(ts, TSM_INSTALL);
00778             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMDBI_DEPENDS);
00779             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_BASENAMES);
00780             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_PROVIDENAME);
00781         } else {
00782             (void) rpmtsSetGoal(ts, TSM_ERASE);
00783         }
00784 
00785         /* XXX query/verify will need the glop added to a buffer instead. */
00786         xx = rpmcliInstallCheck(ts);
00787         xx = rpmcliInstallSuggests(ts);
00788 
00789         /* Permit access to indices used for depsolving. */
00790         if (!(gi->flags & RPMGI_ERASING)) {
00791             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_PROVIDENAME);
00792             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_BASENAMES);
00793             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMDBI_DEPENDS);
00794         }
00795 
00796         /* XXX Display dependency loops with rpm -qvT. */
00797         if (rpmIsVerbose())
00798             (void) rpmtsSetDFlags(ts, (rpmtsDFlags(ts) | RPMDEPS_FLAG_DEPLOOPS));
00799 
00800         xx = (*gi->tsOrder) (ts);
00801 
00802         /* XXX hackery alert! */
00803         gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
00804         gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER);
00805 
00806     }
00807 
00808     (void)headerFree(gi->h);
00809     gi->h = NULL;
00810     gi->hdrPath = _free(gi->hdrPath);
00811     gi->i = -1;
00812     gi->active = 0;
00813 
00814 exit:
00815 if (_rpmgi_debug)
00816 fprintf(stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, gi, rpmrc);
00817     return rpmrc;
00818 }
00819 
00820 rpmgiFlags rpmgiGetFlags(rpmgi gi)
00821 {
00822     return (gi != NULL ? gi->flags : RPMGI_NONE);
00823 }
00824 
00825 const char * rpmgiHdrPath(rpmgi gi)
00826 {
00827     return (gi != NULL ? gi->hdrPath : NULL);
00828 }
00829 
00830 Header rpmgiHeader(rpmgi gi)
00831 {
00832 /*@-compdef -refcounttrans -retexpose -usereleased@*/
00833     return (gi != NULL ? gi->h : NULL);
00834 /*@=compdef =refcounttrans =retexpose =usereleased@*/
00835 }
00836 
00837 rpmts rpmgiTs(rpmgi gi)
00838 {
00839 /*@-compdef -refcounttrans -retexpose -usereleased@*/
00840     return (gi != NULL ? gi->ts : NULL);
00841 /*@=compdef =refcounttrans =retexpose =usereleased@*/
00842 }
00843 
00844 int rpmgiRc(rpmgi gi)
00845 {
00846     return (gi != NULL ? gi->rc : RPMRC_OK);
00847 }
00848 
00849 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
00850 {
00851     if (gi == NULL) return RPMRC_FAIL;
00852     gi->ftsOpts = ftsOpts;
00853     gi->flags = flags;
00854     return rpmgiGlobArgv(gi, argv);
00855 }
00856 
00857 /*@=modfilesys@*/