rpm 5.2.1

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