rpm  5.4.4
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 got = 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 #ifdef  DYING   /* XXX arbitrary tags always have a return value */
00458                     if (tag < 0) {
00459                         rpmlog(RPMLOG_NOTICE, _("unknown tag: \"%s\"\n"), a);
00460                         got = -1;
00461                     }
00462 #endif
00463                 }
00464                 pat = ae;
00465                 got++;
00466             }
00467             if (got >= 0) {
00468 if (_rpmgi_debug  < 0)
00469 fprintf(stderr, "\tav %p[%d]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (int)(av - gi->argv), *av, tagName(tag), pat);
00470                 got = rpmmiAddPattern(gi->mi, tag, RPMMIRE_DEFAULT, pat);
00471             }
00472             a = _free(a);
00473         }
00474 
00475         if (got >= 0)
00476             continue;
00477 
00478         gi->mi = rpmmiFree(gi->mi);     /* XXX odd side effect? */
00479         rpmrc = RPMRC_FAIL;
00480         break;
00481     }
00482 
00483     return rpmrc;
00484 }
00485 
00486 /*@-mustmod@*/
00487 static void rpmgiFini(void * _gi)
00488         /*@modifies _gi @*/
00489 {
00490     rpmgi gi = _gi;
00491     int xx;
00492 
00493     gi->hdrPath = _free(gi->hdrPath);
00494     (void)headerFree(gi->h);
00495     gi->h = NULL;
00496 
00497     gi->argv = argvFree(gi->argv);
00498 
00499     if (gi->ftsp != NULL) {
00500         xx = Fts_close(gi->ftsp);
00501         gi->ftsp = NULL;
00502         gi->fts = NULL;
00503     }
00504     if (gi->fd != NULL) {
00505         xx = Fclose(gi->fd);
00506         gi->fd = NULL;
00507     }
00508     gi->tsi = rpmtsiFree(gi->tsi);
00509     gi->mi = rpmmiFree(gi->mi);
00510     (void)rpmtsFree(gi->ts); 
00511     gi->ts = NULL;
00512 }
00513 /*@=mustmod@*/
00514 
00515 /*@unchecked@*/ /*@only@*/ /*@null@*/
00516 rpmioPool _rpmgiPool;
00517 
00518 static rpmgi rpmgiGetPool(/*@null@*/ rpmioPool pool)
00519         /*@globals _rpmgiPool, fileSystem, internalState @*/
00520         /*@modifies pool, _rpmgiPool, fileSystem, internalState @*/
00521 {
00522     rpmgi gi;
00523 
00524     if (_rpmgiPool == NULL) {
00525         _rpmgiPool = rpmioNewPool("gi", sizeof(*gi), -1, _rpmgi_debug,
00526                         NULL, NULL, rpmgiFini);
00527         pool = _rpmgiPool;
00528     }
00529     gi = (rpmgi) rpmioGetPool(pool, sizeof(*gi));
00530     memset(((char *)gi)+sizeof(gi->_item), 0, sizeof(*gi)-sizeof(gi->_item));
00531     return gi;
00532 }
00533 
00534 rpmgi rpmgiNew(rpmts ts, int tag, const void * keyp, size_t keylen)
00535 {
00536     rpmgi gi = rpmgiGetPool(_rpmgiPool);
00537 
00538     if (gi == NULL)     /* XXX can't happen */
00539         return NULL;
00540 
00541 /*@-assignexpose -castexpose @*/
00542     gi->ts = rpmtsLink(ts, "rpmgiNew");
00543 /*@=assignexpose =castexpose @*/
00544     gi->tsOrder = rpmcliInstallOrder;
00545     gi->tag = (rpmTag) tag;
00546 /*@-assignexpose@*/
00547     gi->keyp = keyp;
00548 /*@=assignexpose@*/
00549     gi->keylen = keylen;
00550 
00551     gi->flags = 0;
00552     gi->active = 0;
00553     gi->i = -1;
00554     gi->hdrPath = NULL;
00555     gi->h = NULL;
00556     gi->rc = 0;
00557 
00558     gi->tsi = NULL;
00559     gi->mi = NULL;
00560     gi->fd = NULL;
00561     gi->argv = xcalloc(1, sizeof(*gi->argv));
00562     gi->argc = 0;
00563     gi->ftsOpts = 0;
00564     gi->ftsp = NULL;
00565     gi->fts = NULL;
00566     gi->walkPathFilter = NULL;
00567     gi->stash = NULL;
00568 
00569     return rpmgiLink(gi, "rpmgiNew");
00570 }
00571 
00572 /*@observer@*/ /*@unchecked@*/
00573 static const char * _query_hdlist_path  = "/usr/share/comps/%{_arch}/hdlist";
00574 
00575 rpmRC rpmgiNext(/*@null@*/ rpmgi gi)
00576 {
00577     char hnum[32];
00578     rpmRC rpmrc = RPMRC_NOTFOUND;
00579     int xx;
00580 
00581     if (gi == NULL)
00582         return rpmrc;
00583 
00584 if (_rpmgi_debug)
00585 fprintf(stderr, "--> %s(%p) tag %s\n", __FUNCTION__, gi, tagName(gi->tag));
00586 
00587     /* Free header from previous iteration. */
00588     (void)headerFree(gi->h);
00589     gi->h = NULL;
00590     gi->hdrPath = _free(gi->hdrPath);
00591     hnum[0] = '\0';
00592 
00593     if (++gi->i >= 0)
00594     switch (gi->tag) {
00595     default:
00596         if (!gi->active) {
00597 nextkey:
00598             rpmrc = rpmgiLoadNextKey(gi);
00599             if (rpmrc != RPMRC_OK)
00600                 goto enditer;
00601             rpmrc = rpmgiInitFilter(gi);
00602             if (rpmrc != RPMRC_OK || gi->mi == NULL) {
00603                 gi->mi = rpmmiFree(gi->mi);     /* XXX unnecessary */
00604                 gi->i++;
00605                 goto nextkey;
00606             }
00607             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
00608             gi->active = 1;
00609         }
00610         if (gi->mi != NULL) {   /* XXX unnecessary */
00611             Header h = rpmmiNext(gi->mi);
00612             if (h != NULL) {
00613                 if (!(gi->flags & RPMGI_NOHEADER))
00614                     gi->h = headerLink(h);
00615                 /* XXX use h->origin instead. */
00616                 sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
00617                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
00618                 rpmrc = RPMRC_OK;
00619                 /* XXX header reference held by iterator, so no headerFree */
00620             }
00621         }
00622         if (rpmrc != RPMRC_OK) {
00623             gi->mi = rpmmiFree(gi->mi);
00624             goto nextkey;
00625         }
00626         break;
00627     case RPMDBI_PACKAGES:
00628         if (!gi->active) {
00629             rpmrc = rpmgiInitFilter(gi);
00630             if (rpmrc != RPMRC_OK) {
00631                 gi->mi = rpmmiFree(gi->mi);     /* XXX unnecessary */
00632                 goto enditer;
00633             }
00634             rpmrc = RPMRC_NOTFOUND;     /* XXX hack */
00635             gi->active = 1;
00636         }
00637         if (gi->mi != NULL) {   /* XXX unnecessary */
00638             Header h = rpmmiNext(gi->mi);
00639             if (h != NULL) {
00640                 if (!(gi->flags & RPMGI_NOHEADER))
00641                     gi->h = headerLink(h);
00642                 /* XXX use h->origin instead. */
00643                 sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
00644                 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
00645                 rpmrc = RPMRC_OK;
00646                 /* XXX header reference held by iterator, so no headerFree */
00647             }
00648         }
00649         if (rpmrc != RPMRC_OK) {
00650             gi->mi = rpmmiFree(gi->mi);
00651             goto enditer;
00652         }
00653         break;
00654     case RPMDBI_REMOVED:
00655     case RPMDBI_ADDED:
00656     {   rpmte p;
00657         int teType = 0;
00658         const char * teTypeString = NULL;
00659 
00660         if (!gi->active) {
00661             gi->tsi = rpmtsiInit(gi->ts);
00662             gi->active = 1;
00663         }
00664         if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) {
00665             Header h = rpmteHeader(p);
00666             if (h != NULL)
00667                 if (!(gi->flags & RPMGI_NOHEADER)) {
00668                     gi->h = headerLink(h);
00669                 switch(rpmteType(p)) {
00670                 case TR_ADDED:  teTypeString = "+++";   /*@switchbreak@*/break;
00671                 case TR_REMOVED: teTypeString = "---";  /*@switchbreak@*/break;
00672                 }
00673                 sprintf(hnum, "%u", (unsigned)gi->i);
00674                 gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL);
00675                 rpmrc = RPMRC_OK;
00676                 (void)headerFree(h);
00677                 h = NULL;
00678             }
00679         }
00680         if (rpmrc != RPMRC_OK) {
00681             gi->tsi = rpmtsiFree(gi->tsi);
00682             goto enditer;
00683         }
00684     }   break;
00685     case RPMDBI_HDLIST:
00686         if (!gi->active) {
00687             const char * path = rpmExpand("%{?_query_hdlist_path}", NULL);
00688             if (path == NULL || *path == '\0') {
00689                 path = _free(path);
00690                 path = rpmExpand(_query_hdlist_path, NULL);
00691             }
00692             gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}");
00693             gi->active = 1;
00694             path = _free(path);
00695         }
00696         if (gi->fd != NULL) {
00697             Header h = NULL;
00698             const char item[] = "Header";
00699             const char * msg = NULL;
00700 /*@+voidabstract@*/
00701             rpmrc = rpmpkgRead(item, gi->fd, &h, &msg);
00702 /*@=voidabstract@*/
00703             switch(rpmrc) {
00704                 default:
00705                     rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg);
00706                 case RPMRC_NOTFOUND:
00707                     h = NULL;
00708                 case RPMRC_OK:
00709                     break;
00710             }
00711             msg = _free(msg);
00712             if (h != NULL) {
00713                 if (!(gi->flags & RPMGI_NOHEADER))
00714                     gi->h = headerLink(h);
00715                 sprintf(hnum, "%u", (unsigned)gi->i);
00716                 gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
00717                 rpmrc = RPMRC_OK;
00718                 (void)headerFree(h);
00719                 h = NULL;
00720             }
00721         }
00722         if (rpmrc != RPMRC_OK) {
00723             if (gi->fd != NULL) (void) Fclose(gi->fd);
00724             gi->fd = NULL;
00725             goto enditer;
00726         }
00727         break;
00728     case RPMDBI_ARGLIST:
00729         /* XXX gi->active initialize? */
00730 if (_rpmgi_debug  < 0)
00731 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
00732         /* Read next header, lazily expanding manifests as found. */
00733         rpmrc = rpmgiLoadReadHeader(gi);
00734 
00735         if (rpmrc != RPMRC_OK)  /* XXX check this */
00736             goto enditer;
00737 
00738         gi->hdrPath = xstrdup(gi->argv[gi->i]);
00739         break;
00740     case RPMDBI_FTSWALK:
00741         if (gi->argv == NULL || gi->argv[0] == NULL)            /* HACK */
00742             goto enditer;
00743 
00744         if (!gi->active) {
00745             gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
00746             /* XXX NULL with open(2)/malloc(3) errno set */
00747             gi->active = 1;
00748         }
00749 
00750         /* Read next header, lazily walking file tree. */
00751         rpmrc = rpmgiWalkReadHeader(gi);
00752 
00753         if (rpmrc != RPMRC_OK) {
00754             xx = Fts_close(gi->ftsp);
00755             gi->ftsp = NULL;
00756             goto enditer;
00757         }
00758 
00759         if (gi->fts != NULL)
00760             gi->hdrPath = xstrdup(gi->fts->fts_path);
00761         break;
00762     }
00763 
00764     if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
00765         /* XXX rpmgi hack: Save header in transaction element. */
00766         if (gi->flags & RPMGI_ERASING) {
00767             uint32_t hdrNum = headerGetInstance(gi->h);
00768             xx = rpmtsAddEraseElement(gi->ts, gi->h, hdrNum);
00769         } else
00770             xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
00771     }
00772     goto exit;
00773 
00774 enditer:
00775     if (gi->flags & RPMGI_TSORDER) {
00776         rpmts ts = gi->ts;
00777 
00778         /* Block access to indices used for depsolving. */
00779         if (!(gi->flags & RPMGI_ERASING)) {
00780             (void) rpmtsSetGoal(ts, TSM_INSTALL);
00781             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMDBI_DEPCACHE);
00782             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_BASENAMES);
00783             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), -RPMTAG_PROVIDENAME);
00784         } else {
00785             (void) rpmtsSetGoal(ts, TSM_ERASE);
00786         }
00787 
00788         /* XXX query/verify will need the glop added to a buffer instead. */
00789         xx = rpmcliInstallCheck(ts);
00790         xx = rpmcliInstallSuggests(ts);
00791 
00792         /* Permit access to indices used for depsolving. */
00793         if (!(gi->flags & RPMGI_ERASING)) {
00794             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_PROVIDENAME);
00795             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMTAG_BASENAMES);
00796             xx = rpmdbBlockDBI(rpmtsGetRdb(ts), RPMDBI_DEPCACHE);
00797         }
00798 
00799         /* XXX Display dependency loops with rpm -qvT. */
00800         if (rpmIsVerbose())
00801             (void) rpmtsSetDFlags(ts, (rpmtsDFlags(ts) | RPMDEPS_FLAG_DEPLOOPS));
00802 
00803         xx = (*gi->tsOrder) (ts);
00804 
00805         /* XXX hackery alert! */
00806         gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
00807         gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER);
00808 
00809     }
00810 
00811     (void)headerFree(gi->h);
00812     gi->h = NULL;
00813     gi->hdrPath = _free(gi->hdrPath);
00814     gi->i = -1;
00815     gi->active = 0;
00816 
00817 exit:
00818 if (_rpmgi_debug)
00819 fprintf(stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, gi, rpmrc);
00820     return rpmrc;
00821 }
00822 
00823 rpmgiFlags rpmgiGetFlags(rpmgi gi)
00824 {
00825     return (gi != NULL ? gi->flags : RPMGI_NONE);
00826 }
00827 
00828 const char * rpmgiHdrPath(rpmgi gi)
00829 {
00830     return (gi != NULL ? gi->hdrPath : NULL);
00831 }
00832 
00833 Header rpmgiHeader(rpmgi gi)
00834 {
00835 /*@-compdef -refcounttrans -retexpose -usereleased@*/
00836     return (gi != NULL ? gi->h : NULL);
00837 /*@=compdef =refcounttrans =retexpose =usereleased@*/
00838 }
00839 
00840 rpmts rpmgiTs(rpmgi gi)
00841 {
00842 /*@-compdef -refcounttrans -retexpose -usereleased@*/
00843     return (gi != NULL ? gi->ts : NULL);
00844 /*@=compdef =refcounttrans =retexpose =usereleased@*/
00845 }
00846 
00847 int rpmgiRc(rpmgi gi)
00848 {
00849     return (gi != NULL ? gi->rc : RPMRC_OK);
00850 }
00851 
00852 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
00853 {
00854     if (gi == NULL) return RPMRC_FAIL;
00855     gi->ftsOpts = ftsOpts;
00856     gi->flags = flags;
00857     return rpmgiGlobArgv(gi, argv);
00858 }
00859 
00860 /*@=modfilesys@*/