rpm  5.4.10
rpmgi.c
Go to the documentation of this file.
1 /*@-modfilesys@*/
5 #include "system.h"
6 
7 #include <rpmio.h>
8 #include <rpmiotypes.h> /* XXX fnpyKey */
9 #include <rpmcb.h>
10 #include <rpmmacro.h> /* XXX rpmExpand */
11 #include <rpmtypes.h>
12 #include <rpmtag.h>
13 #include <rpmdb.h>
14 
15 #include <rpmte.h> /* XXX rpmElementType */
16 #include <pkgio.h> /* XXX rpmElementType */
17 
18 #define _RPMGI_INTERNAL
19 #define _RPMTS_INTERNAL /* XXX ts->probs et al */
20 #include <rpmgi.h>
21 
22 #include "manifest.h"
23 
24 #include <rpmcli.h> /* XXX rpmcliInstallFoo() */
25 
26 #include "debug.h"
27 
28 /*@access FD_t @*/ /* XXX void * arg */
29 /*@access fnpyKey @*/
30 /*@access rpmmi @*/
31 /*@access rpmts @*/
32 /*@access rpmps @*/
33 
36 /*@unchecked@*/
37 int _rpmgi_debug = 0;
38 
41 /*@unchecked@*/
43 
46 /*@unchecked@*/
47 static int indent = 2;
48 
51 /*@unchecked@*/ /*@observer@*/
52 static const char * ftsInfoStrings[] = {
53  "UNKNOWN",
54  "D",
55  "DC",
56  "DEFAULT",
57  "DNR",
58  "DOT",
59  "DP",
60  "ERR",
61  "F",
62  "INIT",
63  "NS",
64  "NSOK",
65  "SL",
66  "SLNONE",
67  "W",
68 };
69 
72 /*@observer@*/
73 static const char * ftsInfoStr(int fts_info)
74  /*@*/
75 {
76 
77  if (!(fts_info >= 1 && fts_info <= 14))
78  fts_info = 0;
79 /*@-compmempass@*/
80  return ftsInfoStrings[ fts_info ];
81 /*@=compmempass@*/
82 }
83 
91 /*@null@*/
92 static FD_t rpmgiOpen(const char * path, const char * fmode)
93  /*@globals rpmGlobalMacroContext, h_errno, errno, internalState @*/
94  /*@modifies rpmGlobalMacroContext, h_errno, errno, internalState @*/
95 {
96  const char * fn = rpmExpand(path, NULL);
97  FD_t fd;
98 
99  /* FIXME (see http://rpm5.org/community/rpm-devel/0523.html) */
100  errno = 0;
101  fd = Fopen(fn, fmode);
102 
103  if (fd == NULL || Ferror(fd)) {
104  rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), fn, Fstrerror(fd));
105  if (fd != NULL) (void) Fclose(fd);
106  fd = NULL;
107  }
108  fn = _free(fn);
109 
110 #if defined(POSIX_FADV_WILLNEED)
111  if(fd != NULL)
112  (void) Fadvise(fd, 0, 0, POSIX_FADV_WILLNEED);
113 #endif
114 
115  return fd;
116 }
117 
124 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
125  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
126  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
127 {
128  FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
129  rpmRC rpmrc = RPMRC_FAIL;
130 
131  if (fd != NULL) {
132  rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
133  (void) Fclose(fd);
134  switch (rpmrc) {
135  case RPMRC_NOTFOUND:
136  case RPMRC_FAIL:
137  default:
138  gi->rc = rpmrc;
139  break;
140  case RPMRC_NOTTRUSTED:
141  case RPMRC_NOKEY:
142  case RPMRC_NOSIG:
143  case RPMRC_OK:
144  /* XXX manifest tried after *.rpm forces a reset. here? */
145  if (gi->rc == RPMRC_NOTFOUND)
146  gi->rc = RPMRC_OK;
147  break;
148  }
149  } else {
150  gi->rc = RPMRC_NOTFOUND; /* XXX other failures? */
151  }
152 
153  return rpmrc;
154 }
155 
156 Header rpmgiReadHeader(rpmgi gi, const char * path)
157 {
158  FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
159  Header h = NULL;
160 
161  if (fd != NULL) {
162  /* XXX what if path needs expansion? */
163  rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
164 
165  (void) Fclose(fd);
166 
167  switch (rpmrc) {
168  case RPMRC_NOTFOUND:
169  /* XXX Read a package manifest. Restart ftswalk on success. */
170  case RPMRC_FAIL:
171  default:
172  (void)headerFree(h);
173  h = NULL;
174  gi->rc = rpmrc;
175  break;
176  case RPMRC_NOSIG: /* XXX FIXME */
177  case RPMRC_NOTTRUSTED:
178  case RPMRC_NOKEY:
179  case RPMRC_OK:
180  break;
181  }
182  } else {
183  gi->rc = RPMRC_NOTFOUND; /* XXX other failures? */
184  }
185 
186  return h;
187 }
188 
195  /*@modifies gi @*/
196 {
197  rpmRC rpmrc = RPMRC_NOTFOUND;
198  if (gi->argv != NULL && gi->argv[gi->i] != NULL) {
199  gi->keyp = gi->argv[gi->i];
200  gi->keylen = 0;
201  rpmrc = RPMRC_OK;
202  } else {
203  gi->i = -1;
204  gi->keyp = NULL;
205  gi->keylen = 0;
206  }
207  return rpmrc;
208 }
209 
219  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
220  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
221 {
222  rpmRC rpmrc = RPMRC_NOTFOUND;
223  Header h = NULL;
224 
225  if (gi->argv != NULL && gi->argv[gi->i] != NULL)
226  do {
227  const char * fn; /* XXX gi->hdrPath? */
228 
229  fn = gi->argv[gi->i];
230  /* XXX Skip +bing -bang =boom special arguments. */
231  if (strchr("-+=", *fn) == NULL && !(gi->flags & RPMGI_NOHEADER)) {
232  h = rpmgiReadHeader(gi, fn);
233  if (h != NULL)
234  rpmrc = RPMRC_OK;
235  else
236  rpmrc = (rpmRC) gi->rc;
237  } else
238  rpmrc = RPMRC_OK;
239 
240  if (rpmrc == RPMRC_OK || gi->flags & RPMGI_NOMANIFEST)
241  break;
242  if (rpmrc == RPMRC_NOSIG) {
243  /* XXX move error message to caller. */
244  rpmlog(RPMLOG_NOTICE, _("not signed: %s\n"), fn);
245  break;
246  }
247  if (errno == ENOENT)
248  break;
249 
250  /* Not a header, so try for a manifest. */
251  gi->argv[gi->i] = NULL; /* Mark the insertion point */
252  rpmrc = rpmgiLoadManifest(gi, fn);
253  /* XXX its unclear if RPMRC_NOTFOUND should fail or continue here. */
254  if (rpmrc != RPMRC_OK) {
255  gi->argv[gi->i] = fn; /* Manifest failed, restore fn */
256  break;
257  }
258  fn = _free(fn);
259  rpmrc = RPMRC_NOTFOUND;
260  } while (1);
261 
262  if (rpmrc == RPMRC_OK && h != NULL)
263  gi->h = headerLink(h);
264  (void)headerFree(h);
265  h = NULL;
266 
267  return rpmrc;
268 }
269 
275 /*@null@*/
277  /*@*/
278 {
279  FTSENT * fts = gi->fts;
280  rpmRC rpmrc = RPMRC_NOTFOUND;
281  const char * s;
282 
283 if (_rpmgi_debug < 0)
284 rpmlog(RPMLOG_DEBUG, "FTS_%s\t%*s %s%s\n", ftsInfoStr(fts->fts_info),
285  indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
286  fts->fts_name,
287  ((fts->fts_info == FTS_D || fts->fts_info == FTS_DP) ? "/" : ""));
288 
289  switch (fts->fts_info) {
290  case FTS_D: /* preorder directory */
291  break;
292  case FTS_DP: /* postorder directory */
293  break;
294  case FTS_F: /* regular file */
295  if ((size_t)fts->fts_namelen <= sizeof(".rpm"))
296  break;
297  /* Ignore all but *.rpm files. */
298  s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
299  if (strcmp(s, ".rpm"))
300  break;
301  rpmrc = RPMRC_OK;
302  break;
303  case FTS_NS: /* stat(2) failed */
304  case FTS_DNR: /* unreadable directory */
305  case FTS_ERR: /* error; errno is set */
306  break;
307  case FTS_DC: /* directory that causes cycles */
308  case FTS_DEFAULT: /* none of the above */
309  case FTS_DOT: /* dot or dot-dot */
310  case FTS_INIT: /* initialized only */
311  case FTS_NSOK: /* no stat(2) requested */
312  case FTS_SL: /* symbolic link */
313  case FTS_SLNONE: /* symbolic link without target */
314  case FTS_W: /* whiteout object */
315  default:
316  break;
317  }
318  return rpmrc;
319 }
320 
326 /*@null@*/
328  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
329  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
330 {
331  rpmRC rpmrc = RPMRC_NOTFOUND;
332 
333  if (gi->ftsp != NULL)
334  while ((gi->fts = Fts_read(gi->ftsp)) != NULL) {
335  if (gi->walkPathFilter)
336  rpmrc = (*gi->walkPathFilter) (gi);
337  else
338  rpmrc = rpmgiWalkPathFilter(gi);
339  if (rpmrc == RPMRC_OK)
340  break;
341  }
342 
343  if (rpmrc == RPMRC_OK) {
344  Header h = NULL;
345  if (!(gi->flags & RPMGI_NOHEADER)) {
346  /* XXX rpmrc = rpmgiLoadReadHeader(gi); */
347  if (gi->fts != NULL) /* XXX can't happen */
348  h = rpmgiReadHeader(gi, gi->fts->fts_path);
349  }
350  if (h != NULL) {
351  gi->h = headerLink(h);
352  (void)headerFree(h);
353  h = NULL;
354 /*@-noeffectuncon@*/
355  if (gi->stash != NULL)
356  (void) (*gi->stash) (gi, gi->h);
357 /*@=noeffectuncon@*/
358  }
359  }
360 
361  return rpmrc;
362 }
363 
364 const char * rpmgiEscapeSpaces(const char * s)
365 {
366  const char * se;
367  const char * t;
368  char * te;
369  size_t nb = 0;
370 
371  for (se = s; *se; se++) {
372  if (isspace(*se))
373  nb++;
374  nb++;
375  }
376  nb++;
377 
378  t = te = (char *) xmalloc(nb);
379  for (se = s; *se; se++) {
380  if (isspace(*se))
381  *te++ = '\\';
382  *te++ = *se;
383  }
384  *te = '\0';
385  return t;
386 }
387 
394 static rpmRC rpmgiGlobArgv(rpmgi gi, /*@null@*/ ARGV_t argv)
395  /*@globals internalState @*/
396  /*@modifies gi, internalState @*/
397 {
398  const char * arg;
399  rpmRC rpmrc = RPMRC_OK;
400  int ac = 0;
401  int xx;
402 
403  /* XXX Expand globs only if requested or for gi specific tags */
404  if ((gi->flags & RPMGI_NOGLOB)
405  || !(gi->tag == RPMDBI_HDLIST || gi->tag == RPMDBI_ARGLIST || gi->tag == RPMDBI_FTSWALK))
406  {
407  if (argv != NULL) {
408  while (argv[ac] != NULL)
409  ac++;
410 /*@-nullstate@*/ /* XXX argv is not NULL */
411  xx = argvAppend(&gi->argv, argv);
412 /*@=nullstate@*/
413  }
414  gi->argc = ac;
415  return rpmrc;
416  }
417 
418  if (argv != NULL)
419  while ((arg = *argv++) != NULL) {
420  const char * t = rpmgiEscapeSpaces(arg);
421  ARGV_t av = NULL;
422 
423  xx = rpmGlob(t, &ac, &av);
424  xx = argvAppend(&gi->argv, av);
425  gi->argc += ac;
426  av = argvFree(av);
427  t = _free(t);
428  ac = 0;
429  }
430  return rpmrc;
431 }
432 
439  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
440  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
441 {
442  rpmRC rpmrc = RPMRC_OK;
443  ARGV_t av;
444  int got = 0;
445 
446  gi->mi = rpmtsInitIterator(gi->ts, gi->tag, gi->keyp, gi->keylen);
447 
448 if (_rpmgi_debug < 0)
449 fprintf(stderr, "*** gi %p key %p[%d]\tmi %p\n", gi, gi->keyp, (int)gi->keylen, gi->mi);
450 
451  if (gi->argv != NULL)
452  for (av = (const char **) gi->argv; *av != NULL; av++) {
453  if (gi->tag == RPMDBI_PACKAGES) {
454  int tag = RPMTAG_NAME;
455  const char * pat;
456  char * a, * ae;
457 
458  pat = a = xstrdup(*av);
459  tag = RPMTAG_NAME;
460 
461  /* Parse for "tag=pattern" args. */
462  if ((ae = strchr(a, '=')) != NULL) {
463  *ae++ = '\0';
464  if (*a != '\0') { /* XXX HACK: permit '=foo' */
465  tag = tagValue(a);
466 #ifdef DYING /* XXX arbitrary tags always have a return value */
467  if (tag < 0) {
468  rpmlog(RPMLOG_NOTICE, _("unknown tag: \"%s\"\n"), a);
469  got = -1;
470  }
471 #endif
472  }
473  pat = ae;
474  got++;
475  }
476  if (got >= 0) {
477 if (_rpmgi_debug < 0)
478 fprintf(stderr, "\tav %p[%d]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (int)(av - gi->argv), *av, tagName((rpmTag)tag), pat);
479  got = rpmmiAddPattern(gi->mi, (rpmTag)tag, RPMMIRE_DEFAULT, pat);
480  }
481  a = _free(a);
482  }
483 
484  if (got >= 0)
485  continue;
486 
487  gi->mi = rpmmiFree(gi->mi); /* XXX odd side effect? */
488  rpmrc = RPMRC_FAIL;
489  break;
490  }
491 
492  return rpmrc;
493 }
494 
495 /*@-mustmod@*/
496 static void rpmgiFini(void * _gi)
497  /*@modifies _gi @*/
498 {
499  rpmgi gi = (rpmgi) _gi;
500  int xx;
501 
502  gi->hdrPath = _free(gi->hdrPath);
503  (void)headerFree(gi->h);
504  gi->h = NULL;
505 
506  gi->argv = argvFree(gi->argv);
507 
508  if (gi->ftsp != NULL) {
509  xx = Fts_close(gi->ftsp);
510  gi->ftsp = NULL;
511  gi->fts = NULL;
512  }
513  if (gi->fd != NULL) {
514  xx = Fclose(gi->fd);
515  gi->fd = NULL;
516  }
517  gi->tsi = rpmtsiFree(gi->tsi);
518  gi->mi = rpmmiFree(gi->mi);
519  (void)rpmtsFree(gi->ts);
520  gi->ts = NULL;
521 }
522 /*@=mustmod@*/
523 
524 /*@unchecked@*/ /*@only@*/ /*@null@*/
526 
527 static rpmgi rpmgiGetPool(/*@null@*/ rpmioPool pool)
528  /*@globals _rpmgiPool, fileSystem, internalState @*/
529  /*@modifies pool, _rpmgiPool, fileSystem, internalState @*/
530 {
531  rpmgi gi;
532 
533  if (_rpmgiPool == NULL) {
534  _rpmgiPool = rpmioNewPool("gi", sizeof(*gi), -1, _rpmgi_debug,
535  NULL, NULL, rpmgiFini);
536  pool = _rpmgiPool;
537  }
538  gi = (rpmgi) rpmioGetPool(pool, sizeof(*gi));
539  memset(((char *)gi)+sizeof(gi->_item), 0, sizeof(*gi)-sizeof(gi->_item));
540  return gi;
541 }
542 
543 rpmgi rpmgiNew(rpmts ts, int tag, const void * keyp, size_t keylen)
544 {
545  rpmgi gi = rpmgiGetPool(_rpmgiPool);
546 
547  if (gi == NULL) /* XXX can't happen */
548  return NULL;
549 
550 /*@-assignexpose -castexpose @*/
551  gi->ts = rpmtsLink(ts, "rpmgiNew");
552 /*@=assignexpose =castexpose @*/
553  gi->tsOrder = rpmcliInstallOrder;
554  gi->tag = (rpmTag) tag;
555 /*@-assignexpose@*/
556  gi->keyp = keyp;
557 /*@=assignexpose@*/
558  gi->keylen = keylen;
559 
560  gi->flags = (rpmgiFlags)0;
561  gi->active = 0;
562  gi->i = -1;
563  gi->hdrPath = NULL;
564  gi->h = NULL;
565  gi->rc = 0;
566 
567  gi->tsi = NULL;
568  gi->mi = NULL;
569  gi->fd = NULL;
570  gi->argv = (ARGV_t) xcalloc(1, sizeof(*gi->argv));
571  gi->argc = 0;
572  gi->ftsOpts = 0;
573  gi->ftsp = NULL;
574  gi->fts = NULL;
575  gi->walkPathFilter = NULL;
576  gi->stash = NULL;
577 
578  return rpmgiLink(gi, "rpmgiNew");
579 }
580 
581 /*@observer@*/ /*@unchecked@*/
582 static const char * _query_hdlist_path = "/usr/share/comps/%{_arch}/hdlist";
583 
584 rpmRC rpmgiNext(/*@null@*/ rpmgi gi)
585 {
586  char hnum[32];
587  rpmRC rpmrc = RPMRC_NOTFOUND;
588  int xx;
589 
590  if (gi == NULL)
591  return rpmrc;
592 
593 if (_rpmgi_debug)
594 fprintf(stderr, "--> %s(%p) tag %s\n", __FUNCTION__, gi, tagName(gi->tag));
595 
596  /* Free header from previous iteration. */
597  (void)headerFree(gi->h);
598  gi->h = NULL;
599  gi->hdrPath = _free(gi->hdrPath);
600  hnum[0] = '\0';
601 
602  if (++gi->i >= 0)
603  switch (gi->tag) {
604  default:
605  if (!gi->active) {
606 nextkey:
607  rpmrc = rpmgiLoadNextKey(gi);
608  if (rpmrc != RPMRC_OK)
609  goto enditer;
610  rpmrc = rpmgiInitFilter(gi);
611  if (rpmrc != RPMRC_OK || gi->mi == NULL) {
612  gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */
613  gi->i++;
614  goto nextkey;
615  }
616  rpmrc = RPMRC_NOTFOUND; /* XXX hack */
617  gi->active = 1;
618  }
619  if (gi->mi != NULL) { /* XXX unnecessary */
620  Header h = rpmmiNext(gi->mi);
621  if (h != NULL) {
622  if (!(gi->flags & RPMGI_NOHEADER))
623  gi->h = headerLink(h);
624  /* XXX use h->origin instead. */
625  sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
626  gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
627  rpmrc = RPMRC_OK;
628  /* XXX header reference held by iterator, so no headerFree */
629  }
630  }
631  if (rpmrc != RPMRC_OK) {
632  gi->mi = rpmmiFree(gi->mi);
633  goto nextkey;
634  }
635  break;
636  case RPMDBI_PACKAGES:
637  if (!gi->active) {
638  rpmrc = rpmgiInitFilter(gi);
639  if (rpmrc != RPMRC_OK) {
640  gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */
641  goto enditer;
642  }
643  rpmrc = RPMRC_NOTFOUND; /* XXX hack */
644  gi->active = 1;
645  }
646  if (gi->mi != NULL) { /* XXX unnecessary */
647  Header h = rpmmiNext(gi->mi);
648  if (h != NULL) {
649  if (!(gi->flags & RPMGI_NOHEADER))
650  gi->h = headerLink(h);
651  /* XXX use h->origin instead. */
652  sprintf(hnum, "%u", (unsigned)rpmmiInstance(gi->mi));
653  gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
654  rpmrc = RPMRC_OK;
655  /* XXX header reference held by iterator, so no headerFree */
656  }
657  }
658  if (rpmrc != RPMRC_OK) {
659  gi->mi = rpmmiFree(gi->mi);
660  goto enditer;
661  }
662  break;
663  case RPMDBI_REMOVED:
664  case RPMDBI_ADDED:
665  { rpmte p;
666  rpmElementType teType = (rpmElementType)0;
667  const char * teTypeString = NULL;
668 
669  if (!gi->active) {
670  gi->tsi = rpmtsiInit(gi->ts);
671  gi->active = 1;
672  }
673  if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) {
674  Header h = rpmteHeader(p);
675  if (h != NULL)
676  if (!(gi->flags & RPMGI_NOHEADER)) {
677  gi->h = headerLink(h);
678  switch(rpmteType(p)) {
679  case TR_ADDED: teTypeString = "+++"; /*@switchbreak@*/break;
680  case TR_REMOVED: teTypeString = "---"; /*@switchbreak@*/break;
681  }
682  sprintf(hnum, "%u", (unsigned)gi->i);
683  gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL);
684  rpmrc = RPMRC_OK;
685  (void)headerFree(h);
686  h = NULL;
687  }
688  }
689  if (rpmrc != RPMRC_OK) {
690  gi->tsi = rpmtsiFree(gi->tsi);
691  goto enditer;
692  }
693  } break;
694  case RPMDBI_HDLIST:
695  if (!gi->active) {
696  const char * path = rpmExpand("%{?_query_hdlist_path}", NULL);
697  if (path == NULL || *path == '\0') {
698  path = _free(path);
699  path = rpmExpand(_query_hdlist_path, NULL);
700  }
701  gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}");
702  gi->active = 1;
703  path = _free(path);
704  }
705  if (gi->fd != NULL) {
706  Header h = NULL;
707  const char item[] = "Header";
708  const char * msg = NULL;
709 /*@+voidabstract@*/
710  rpmrc = rpmpkgRead(item, gi->fd, &h, &msg);
711 /*@=voidabstract@*/
712  switch(rpmrc) {
713  default:
714  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg);
715  case RPMRC_NOTFOUND:
716  h = NULL;
717  case RPMRC_OK:
718  break;
719  }
720  msg = _free(msg);
721  if (h != NULL) {
722  if (!(gi->flags & RPMGI_NOHEADER))
723  gi->h = headerLink(h);
724  sprintf(hnum, "%u", (unsigned)gi->i);
725  gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
726  rpmrc = RPMRC_OK;
727  (void)headerFree(h);
728  h = NULL;
729  }
730  }
731  if (rpmrc != RPMRC_OK) {
732  if (gi->fd != NULL) (void) Fclose(gi->fd);
733  gi->fd = NULL;
734  goto enditer;
735  }
736  break;
737  case RPMDBI_ARGLIST:
738  /* XXX gi->active initialize? */
739 if (_rpmgi_debug < 0)
740 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
741  /* Read next header, lazily expanding manifests as found. */
742  rpmrc = rpmgiLoadReadHeader(gi);
743 
744  if (rpmrc != RPMRC_OK) /* XXX check this */
745  goto enditer;
746 
747  gi->hdrPath = xstrdup(gi->argv[gi->i]);
748  break;
749  case RPMDBI_FTSWALK:
750  if (gi->argv == NULL || gi->argv[0] == NULL) /* HACK */
751  goto enditer;
752 
753  if (!gi->active) {
754  gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
755  /* XXX NULL with open(2)/malloc(3) errno set */
756  gi->active = 1;
757  }
758 
759  /* Read next header, lazily walking file tree. */
760  rpmrc = rpmgiWalkReadHeader(gi);
761 
762  if (rpmrc != RPMRC_OK) {
763  xx = Fts_close(gi->ftsp);
764  gi->ftsp = NULL;
765  goto enditer;
766  }
767 
768  if (gi->fts != NULL)
769  gi->hdrPath = xstrdup(gi->fts->fts_path);
770  break;
771  }
772 
773  if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
774  /* XXX rpmgi hack: Save header in transaction element. */
775  if (gi->flags & RPMGI_ERASING) {
776  uint32_t hdrNum = headerGetInstance(gi->h);
777  xx = rpmtsAddEraseElement(gi->ts, gi->h, hdrNum);
778  } else
779  xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
780  }
781  goto exit;
782 
783 enditer:
784  if (gi->flags & RPMGI_TSORDER) {
785  rpmts ts = gi->ts;
786 
787  /* Block access to indices used for depsolving. */
788  if (!(gi->flags & RPMGI_ERASING)) {
789  (void) rpmtsSetGoal(ts, TSM_INSTALL);
793  } else {
794  (void) rpmtsSetGoal(ts, TSM_ERASE);
795  }
796 
797  /* XXX query/verify will need the glop added to a buffer instead. */
798  xx = rpmcliInstallCheck(ts);
799  xx = rpmcliInstallSuggests(ts);
800 
801  /* Permit access to indices used for depsolving. */
802  if (!(gi->flags & RPMGI_ERASING)) {
806  }
807 
808  /* XXX Display dependency loops with rpm -qvT. */
809  if (rpmIsVerbose()) {
810  rpmdepFlags _depflags = (rpmdepFlags)
812  (void) rpmtsSetDFlags(ts, _depflags);
813  }
814 
815  xx = (*gi->tsOrder) (ts);
816 
817  /* XXX hackery alert! */
818  gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
819  gi->flags = (rpmgiFlags) (gi->flags & ~(RPMGI_TSADD|RPMGI_TSORDER));
820 
821  }
822 
823  (void)headerFree(gi->h);
824  gi->h = NULL;
825  gi->hdrPath = _free(gi->hdrPath);
826  gi->i = -1;
827  gi->active = 0;
828 
829 exit:
830 if (_rpmgi_debug)
831 fprintf(stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, gi, rpmrc);
832  return rpmrc;
833 }
834 
836 {
837  return (gi != NULL ? gi->flags : RPMGI_NONE);
838 }
839 
840 const char * rpmgiHdrPath(rpmgi gi)
841 {
842  return (gi != NULL ? gi->hdrPath : NULL);
843 }
844 
846 {
847 /*@-compdef -refcounttrans -retexpose -usereleased@*/
848  return (gi != NULL ? gi->h : NULL);
849 /*@=compdef =refcounttrans =retexpose =usereleased@*/
850 }
851 
853 {
854 /*@-compdef -refcounttrans -retexpose -usereleased@*/
855  return (gi != NULL ? gi->ts : NULL);
856 /*@=compdef =refcounttrans =retexpose =usereleased@*/
857 }
858 
859 int rpmgiRc(rpmgi gi)
860 {
861  return (gi != NULL ? gi->rc : RPMRC_OK);
862 }
863 
864 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
865 {
866  if (gi == NULL) return RPMRC_FAIL;
867  gi->ftsOpts = ftsOpts;
868  gi->flags = flags;
869  return rpmgiGlobArgv(gi, argv);
870 }
871 
872 /*@=modfilesys@*/