6 #include <rpm/rpmtypes.h>
7 #include <rpm/rpmlib.h> /* rpmReadPackageFile */
8 #include <rpm/rpmte.h> /* XXX rpmElementType */
10 #include <rpm/rpmgi.h>
11 #include <rpm/rpmdb.h>
12 #include <rpm/rpmmacro.h> /* XXX rpmExpand */
13 #include <rpm/rpmfileutil.h>
14 #include <rpm/rpmlog.h>
16 #include "rpmio/fts.h"
17 #include "lib/manifest.h"
23 rpmgiFlags giFlags = RPMGI_NONE;
28 rpmts ts; /*!< Iterator transaction set. */
29 rpmTag tag; /*!< Iterator type. */
30 const void * keyp; /*!< Iterator key. */
31 size_t keylen; /*!< Iterator key length. */
33 rpmgiFlags flags; /*!< Iterator control bits. */
34 int active; /*!< Iterator is active? */
35 int i; /*!< Element index. */
37 char * hdrPath; /*!< Path to current iterator header. */
38 Header h; /*!< Current iterator header. */
42 rpmdbMatchIterator mi;
53 int nrefs; /*!< Reference count. */
56 static const char * const ftsInfoStrings[] = {
74 static const char * ftsInfoStr(int fts_info)
77 if (!(fts_info >= 1 && fts_info <= 14))
79 return ftsInfoStrings[ fts_info ];
83 * Open a file after macro expanding path.
84 * @todo There are two error messages printed on header, then manifest failures.
85 * @param path file path
86 * @param fmode open mode
89 static FD_t rpmgiOpen(const char * path, const char * fmode)
91 char * fn = rpmExpand(path, NULL);
92 FD_t fd = Fopen(fn, fmode);
94 if (fd == NULL || Ferror(fd)) {
95 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), fn, Fstrerror(fd));
96 if (fd != NULL) (void) Fclose(fd);
105 * Load manifest into iterator arg list.
106 * @param gi generalized iterator
107 * @param path file path
108 * @return RPMRC_OK on success
110 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
112 FD_t fd = rpmgiOpen(path, "r.ufdio");
113 rpmRC rpmrc = RPMRC_FAIL;
116 rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
123 * Return header from package.
124 * @param gi generalized iterator
125 * @param path file path
126 * @return header (NULL on failure)
128 static Header rpmgiReadHeader(rpmgi gi, const char * path)
130 FD_t fd = rpmgiOpen(path, "r.ufdio");
134 /* XXX what if path needs expansion? */
135 rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
141 /* XXX Read a package manifest. Restart ftswalk on success. */
146 case RPMRC_NOTTRUSTED:
157 * Read next header from package, lazily expanding manifests as found.
158 * @todo An empty file read as manifest truncates argv returning RPMRC_NOTFOUND.
159 * @todo Chained manifests lose an arg someplace.
160 * @param gi generalized iterator
161 * @return RPMRC_OK on success
163 static rpmRC rpmgiLoadReadHeader(rpmgi gi)
165 rpmRC rpmrc = RPMRC_NOTFOUND;
168 if (gi->argv != NULL && gi->argv[gi->i] != NULL)
170 char * fn; /* XXX gi->hdrPath? */
172 fn = gi->argv[gi->i];
173 if (!(gi->flags & RPMGI_NOHEADER)) {
174 h = rpmgiReadHeader(gi, fn);
180 if (rpmrc == RPMRC_OK || gi->flags & RPMGI_NOMANIFEST)
182 if (errno == ENOENT) {
186 /* Not a header, so try for a manifest. */
187 gi->argv[gi->i] = NULL; /* Mark the insertion point */
188 rpmrc = rpmgiLoadManifest(gi, fn);
189 if (rpmrc != RPMRC_OK) {
190 gi->argv[gi->i] = fn; /* Manifest failed, restore fn */
192 _("%s: not an rpm package (or package manifest)\n"), fn);
196 rpmrc = RPMRC_NOTFOUND;
199 if (rpmrc == RPMRC_OK && h != NULL)
200 gi->h = headerLink(h);
207 * Filter file tree walk path.
208 * @param gi generalized iterator
209 * @return RPMRC_OK on success
211 static rpmRC rpmgiWalkPathFilter(rpmgi gi)
213 FTSENT * fts = gi->fts;
214 rpmRC rpmrc = RPMRC_NOTFOUND;
215 static const int indent = 2;
218 if (_rpmgi_debug < 0)
219 rpmlog(RPMLOG_DEBUG, "FTS_%s\t%*s %s%s\n", ftsInfoStr(fts->fts_info),
220 indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
222 ((fts->fts_info == FTS_D || fts->fts_info == FTS_DP) ? "/" : ""));
224 switch (fts->fts_info) {
226 /* Ignore all but *.rpm files. */
227 if (!rpmFileHasSuffix(fts->fts_name, ".rpm"))
238 * Read header from next package, lazily walking file tree.
239 * @param gi generalized iterator
240 * @return RPMRC_OK on success
242 static rpmRC rpmgiWalkReadHeader(rpmgi gi)
244 rpmRC rpmrc = RPMRC_NOTFOUND;
246 if (gi->ftsp != NULL)
247 while ((gi->fts = Fts_read(gi->ftsp)) != NULL) {
248 rpmrc = rpmgiWalkPathFilter(gi);
249 if (rpmrc == RPMRC_OK)
253 if (rpmrc == RPMRC_OK) {
255 if (!(gi->flags & RPMGI_NOHEADER)) {
256 /* XXX rpmrc = rpmgiLoadReadHeader(gi); */
257 if (gi->fts != NULL) /* XXX can't happen */
258 h = rpmgiReadHeader(gi, gi->fts->fts_path);
261 gi->h = headerLink(h);
269 * Append globbed arg list to iterator.
270 * @param gi generalized iterator
271 * @param argv arg list to be globbed (or NULL)
272 * @returns RPMRC_OK on success
274 static rpmRC rpmgiGlobArgv(rpmgi gi, ARGV_const_t argv)
277 rpmRC rpmrc = RPMRC_OK;
281 /* XXX Expand globs only if requested or for gi specific tags */
282 if ((gi->flags & RPMGI_NOGLOB)
283 || !(gi->tag == RPMDBI_HDLIST || gi->tag == RPMDBI_ARGLIST || gi->tag == RPMDBI_FTSWALK))
286 while (argv[ac] != NULL)
288 /* XXX argv is not NULL */
289 xx = argvAppend(&gi->argv, argv);
296 while ((arg = *argv++) != NULL) {
297 char * t = rpmEscapeSpaces(arg);
300 xx = rpmGlob(t, &ac, &av);
301 xx = argvAppend(&gi->argv, av);
311 * Return rpmdb match iterator with filters (if any) set.
312 * @param gi generalized iterator
313 * @returns RPMRC_OK on success
315 static rpmRC rpmgiInitFilter(rpmgi gi)
317 rpmRC rpmrc = RPMRC_OK;
321 gi->mi = rpmtsInitIterator(gi->ts, gi->tag, gi->keyp, gi->keylen);
323 if (_rpmgi_debug < 0)
324 fprintf(stderr, "*** gi %p\tmi %p\n", gi, gi->mi);
326 if (gi->argv != NULL)
327 for (av = gi->argv; *av != NULL; av++) {
328 rpmTag tag = RPMTAG_NAME;
332 pat = a = xstrdup(*av);
335 /* Parse for "tag=pattern" args. */
336 if ((ae = strchr(a, '=')) != NULL) {
338 tag = rpmTagGetValue(a);
339 if (tag == RPMTAG_NOT_FOUND) {
340 rpmlog(RPMLOG_ERR, _("unknown tag: \"%s\"\n"), a);
347 if (_rpmgi_debug < 0)
348 fprintf(stderr, "\tav %p[%ld]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (long) (av - gi->argv), *av, rpmTagGetName(tag), pat);
349 res = rpmdbSetIteratorRE(gi->mi, tag, RPMMIRE_DEFAULT, pat);
363 rpmgi rpmgiUnlink(rpmgi gi, const char * msg)
365 if (gi == NULL) return NULL;
367 if (_rpmgi_debug && msg != NULL)
368 fprintf(stderr, "--> gi %p -- %d: %s\n", gi, gi->nrefs, msg);
374 rpmgi rpmgiLink(rpmgi gi, const char * msg)
376 if (gi == NULL) return NULL;
379 if (_rpmgi_debug && msg != NULL)
380 fprintf(stderr, "--> gi %p ++ %d: %s\n", gi, gi->nrefs, msg);
385 rpmgi rpmgiFree(rpmgi gi)
391 return rpmgiUnlink(gi, __FUNCTION__);
393 (void) rpmgiUnlink(gi, __FUNCTION__);
396 gi->hdrPath = _free(gi->hdrPath);
397 gi->h = headerFree(gi->h);
399 gi->argv = argvFree(gi->argv);
401 if (gi->ftsp != NULL) {
403 xx = Fts_close(gi->ftsp);
407 if (gi->fd != NULL) {
408 (void) Fclose(gi->fd);
411 gi->tsi = rpmtsiFree(gi->tsi);
412 gi->mi = rpmdbFreeIterator(gi->mi);
413 gi->ts = rpmtsFree(gi->ts);
415 memset(gi, 0, sizeof(*gi)); /* XXX trash and burn */
420 rpmgi rpmgiNew(rpmts ts, rpmTag tag, const void * keyp, size_t keylen)
422 rpmgi gi = xcalloc(1, sizeof(*gi));
427 gi->ts = rpmtsLink(ts, __FUNCTION__);
442 gi->argv = argvNew();
448 gi = rpmgiLink(gi, __FUNCTION__);
453 rpmRC rpmgiNext(rpmgi gi)
456 rpmRC rpmrc = RPMRC_NOTFOUND;
462 /* Free header from previous iteration. */
463 gi->h = headerFree(gi->h);
464 gi->hdrPath = _free(gi->hdrPath);
470 case RPMDBI_PACKAGES:
472 rpmrc = rpmgiInitFilter(gi);
473 if (rpmrc != RPMRC_OK)
477 if (gi->mi != NULL) { /* XXX unnecessary */
478 Header h = rpmdbNextIterator(gi->mi);
480 if (!(gi->flags & RPMGI_NOHEADER))
481 gi->h = headerLink(h);
482 sprintf(hnum, "%u", rpmdbGetIteratorOffset(gi->mi));
483 gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
485 /* XXX header reference held by iterator, so no headerFree */
487 rpmrc = RPMRC_NOTFOUND;
489 if (rpmrc != RPMRC_OK) {
497 gi->tsi = rpmtsiInit(gi->ts);
500 if ((p = rpmtsiNext(gi->tsi, TR_ADDED)) != NULL) {
501 Header h = rpmteHeader(p);
503 if (!(gi->flags & RPMGI_NOHEADER)) {
504 gi->h = headerLink(h);
505 sprintf(hnum, "%u", (unsigned)gi->i);
506 gi->hdrPath = rpmExpand("added h# ", hnum, NULL);
511 if (rpmrc != RPMRC_OK) {
512 gi->tsi = rpmtsiFree(gi->tsi);
518 const char * path = "/usr/share/comps/%{_arch}/hdlist";
519 gi->fd = rpmgiOpen(path, "r.ufdio");
522 if (gi->fd != NULL) {
523 Header h = headerRead(gi->fd, HEADER_MAGIC_YES);
525 if (!(gi->flags & RPMGI_NOHEADER))
526 gi->h = headerLink(h);
527 sprintf(hnum, "%u", (unsigned)gi->i);
528 gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
533 if (rpmrc != RPMRC_OK) {
534 if (gi->fd != NULL) (void) Fclose(gi->fd);
540 /* XXX gi->active initialize? */
541 if (_rpmgi_debug < 0)
542 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
545 * Read next header, lazily expanding manifests as found,
546 * count + skip errors.
548 rpmrc = RPMRC_NOTFOUND;
549 while (gi->i < gi->argc) {
550 if ((rpmrc = rpmgiLoadReadHeader(gi)) == RPMRC_OK)
556 if (rpmrc != RPMRC_OK) /* XXX check this */
559 gi->hdrPath = xstrdup(gi->argv[gi->i]);
562 if (gi->argv == NULL) /* HACK */
566 gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
567 /* XXX NULL with open(2)/malloc(3) errno set */
571 /* Read next header, lazily walking file tree. */
572 rpmrc = rpmgiWalkReadHeader(gi);
574 if (rpmrc != RPMRC_OK) {
575 xx = Fts_close(gi->ftsp);
581 gi->hdrPath = xstrdup(gi->fts->fts_path);
585 if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
586 /* XXX rpmgi hack: Save header in transaction element. */
587 xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
593 gi->mi = rpmdbFreeIterator(gi->mi);
594 if (gi->flags & RPMGI_TSORDER) {
598 /* XXX installed database needs close here. */
599 xx = rpmtsCloseDB(ts);
600 xx = rpmtsSetDBMode(ts, -1); /* XXX disable lazy opens */
604 /* XXX query/verify will need the glop added to a buffer instead. */
605 ps = rpmtsProblems(ts);
606 if (rpmpsNumProblems(ps) > 0) {
607 /* XXX rpminstall will need RPMLOG_ERR */
608 rpmlog(RPMLOG_INFO, _("Failed dependencies:\n"));
610 rpmpsPrint(NULL, ps);
613 rpmtsCleanProblems(ts);
617 gi->tag = RPMDBI_ADDED; /* XXX hackery */
618 gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER);
622 gi->h = headerFree(gi->h);
623 gi->hdrPath = _free(gi->hdrPath);
629 const char * rpmgiHdrPath(rpmgi gi)
631 return (gi != NULL ? gi->hdrPath : NULL);
634 Header rpmgiHeader(rpmgi gi)
636 return (gi != NULL ? gi->h : NULL);
639 rpmts rpmgiTs(rpmgi gi)
641 return (gi != NULL ? gi->ts : NULL);
644 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_const_t argv, int ftsOpts, rpmgiFlags flags)
646 gi->ftsOpts = ftsOpts;
648 return rpmgiGlobArgv(gi, argv);
651 rpmgiFlags rpmgiGetFlags(rpmgi gi)
653 return (gi != NULL ? gi->flags : RPMGI_NONE);
656 int rpmgiNumErrors(rpmgi gi)
658 return (gi != NULL ? gi->errors : -1);