rpm  5.4.15
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  /*@fallthrough@*/
716  case RPMRC_NOTFOUND:
717  h = NULL;
718  /*@fallthrough@*/
719  case RPMRC_OK:
720  break;
721  }
722  msg = _free(msg);
723  if (h != NULL) {
724  if (!(gi->flags & RPMGI_NOHEADER))
725  gi->h = headerLink(h);
726  sprintf(hnum, "%u", (unsigned)gi->i);
727  gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
728  rpmrc = RPMRC_OK;
729  (void)headerFree(h);
730  h = NULL;
731  }
732  }
733  if (rpmrc != RPMRC_OK) {
734  if (gi->fd != NULL) (void) Fclose(gi->fd);
735  gi->fd = NULL;
736  goto enditer;
737  }
738  break;
739  case RPMDBI_ARGLIST:
740  /* XXX gi->active initialize? */
741 if (_rpmgi_debug < 0)
742 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
743  /* Read next header, lazily expanding manifests as found. */
744  rpmrc = rpmgiLoadReadHeader(gi);
745 
746  if (rpmrc != RPMRC_OK) /* XXX check this */
747  goto enditer;
748 
749  gi->hdrPath = xstrdup(gi->argv[gi->i]);
750  break;
751  case RPMDBI_FTSWALK:
752  if (gi->argv == NULL || gi->argv[0] == NULL) /* HACK */
753  goto enditer;
754 
755  if (!gi->active) {
756  gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
757  /* XXX NULL with open(2)/malloc(3) errno set */
758  gi->active = 1;
759  }
760 
761  /* Read next header, lazily walking file tree. */
762  rpmrc = rpmgiWalkReadHeader(gi);
763 
764  if (rpmrc != RPMRC_OK) {
765  xx = Fts_close(gi->ftsp);
766  gi->ftsp = NULL;
767  goto enditer;
768  }
769 
770  if (gi->fts != NULL)
771  gi->hdrPath = xstrdup(gi->fts->fts_path);
772  break;
773  }
774 
775  if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
776  /* XXX rpmgi hack: Save header in transaction element. */
777  if (gi->flags & RPMGI_ERASING) {
778  uint32_t hdrNum = headerGetInstance(gi->h);
779  xx = rpmtsAddEraseElement(gi->ts, gi->h, hdrNum);
780  } else
781  xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
782  }
783  goto exit;
784 
785 enditer:
786  if (gi->flags & RPMGI_TSORDER) {
787  rpmts ts = gi->ts;
788 
789  /* Block access to indices used for depsolving. */
790  if (!(gi->flags & RPMGI_ERASING)) {
791  (void) rpmtsSetGoal(ts, TSM_INSTALL);
795  } else {
796  (void) rpmtsSetGoal(ts, TSM_ERASE);
797  }
798 
799  /* XXX query/verify will need the glop added to a buffer instead. */
800  xx = rpmcliInstallCheck(ts);
801  xx = rpmcliInstallSuggests(ts);
802 
803  /* Permit access to indices used for depsolving. */
804  if (!(gi->flags & RPMGI_ERASING)) {
808  }
809 
810  /* XXX Display dependency loops with rpm -qvT. */
811  if (rpmIsVerbose()) {
812  rpmdepFlags _depflags = (rpmdepFlags)
814  (void) rpmtsSetDFlags(ts, _depflags);
815  }
816 
817  xx = (*gi->tsOrder) (ts);
818 
819  /* XXX hackery alert! */
820  gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
821  gi->flags = (rpmgiFlags) (gi->flags & ~(RPMGI_TSADD|RPMGI_TSORDER));
822 
823  }
824 
825  (void)headerFree(gi->h);
826  gi->h = NULL;
827  gi->hdrPath = _free(gi->hdrPath);
828  gi->i = -1;
829  gi->active = 0;
830 
831 exit:
832 if (_rpmgi_debug)
833 fprintf(stderr, "<-- %s(%p) rc %d\n", __FUNCTION__, gi, rpmrc);
834  return rpmrc;
835 }
836 
838 {
839  return (gi != NULL ? gi->flags : RPMGI_NONE);
840 }
841 
842 const char * rpmgiHdrPath(rpmgi gi)
843 {
844  return (gi != NULL ? gi->hdrPath : NULL);
845 }
846 
848 {
849 /*@-compdef -refcounttrans -retexpose -usereleased@*/
850  return (gi != NULL ? gi->h : NULL);
851 /*@=compdef =refcounttrans =retexpose =usereleased@*/
852 }
853 
855 {
856 /*@-compdef -refcounttrans -retexpose -usereleased@*/
857  return (gi != NULL ? gi->ts : NULL);
858 /*@=compdef =refcounttrans =retexpose =usereleased@*/
859 }
860 
861 int rpmgiRc(rpmgi gi)
862 {
863  return (gi != NULL ? gi->rc : RPMRC_OK);
864 }
865 
867 {
868  if (gi == NULL) return RPMRC_FAIL;
869  gi->ftsOpts = ftsOpts;
870  gi->flags = flags;
871  return rpmgiGlobArgv(gi, argv);
872 }
873 
874 /*@=modfilesys@*/
#define FTS_SLNONE
Definition: fts.h:141
int rpmgiRc(rpmgi gi)
Return current iteration item(s) exit code.
Definition: rpmgi.c:861
FTS * Fts_open(char *const *argv, int options, int(*compar)(const FTSENT **, const FTSENT **))
Create a handle for file hierarchy traversal.
Definition: fts.c:207
const char bson_timestamp_t * ts
Definition: bson.h:1004
rpmgiFlags rpmgiGetFlags(rpmgi gi)
Return current iteration flags.
Definition: rpmgi.c:837
uint32_t rpmmiInstance(rpmmi mi)
Return header instance for current position of rpmdb iterator.
Definition: rpmdb.c:1747
Structures used for an "rpmte" transaction element.
char * xstrdup(const char *str)
Definition: rpmmalloc.c:321
FD_t Fopen(const char *path, const char *_fmode)
fopen(3) clone.
Definition: rpmio.c:2840
int rpmtsAddInstallElement(rpmts ts, Header h, fnpyKey key, int upgrade, rpmRelocation relocs)
Add package to be installed to transaction set.
Definition: depends.c:547
#define FTS_W
Definition: fts.h:142
The Header data structure.
#define RPMDBI_REMOVED
Definition: rpmtag.h:483
rpmgi rpmgiLink(rpmgi gi, const char *msg)
Reference a generalized iterator instance.
int argvAppend(ARGV_t *argvp, ARGV_t av)
Append one argv array to another.
Definition: argv.c:216
#define FTS_SL
Definition: fts.h:140
Header rpmgiHeader(rpmgi gi)
Return current iteration header.
Definition: rpmgi.c:847
int errno
u_short fts_namelen
Definition: fts.h:119
#define FTS_NS
Definition: fts.h:138
static const char * ftsInfoStrings[]
Definition: rpmgi.c:52
short fts_level
Definition: fts.h:127
int Fadvise(FD_t fd, off_t offset, off_t length, int advice)
posix_fadvise(2) clone.
Definition: rpmrpc.c:1495
rpmtsi rpmtsiFree(rpmtsi tsi)
Destroy transaction element iterator.
static void rpmlog(int code, const char *fmt,...)
Definition: rpmlog.h:299
rpmElementType rpmteType(rpmte te)
Retrieve type of transaction element.
Definition: rpmte.c:311
const char * rpmgiEscapeSpaces(const char *s)
Escape isspace(3) characters in string.
Definition: rpmgi.c:364
rpmts rpmtsLink(rpmts ts, const char *msg)
Reference a transaction set instance.
static rpmRC rpmgiGlobArgv(rpmgi gi, ARGV_t argv)
Append globbed arg list to iterator.
Definition: rpmgi.c:394
struct rpmte_s * rpmte
An element of a transaction set, i.e.
Definition: rpmtypes.h:38
rpmTag tagValue(const char *tagstr)
Return tag value from name.
Definition: tagname.c:446
enum rpmElementType_e rpmElementType
Transaction element type.
u_short fts_info
Definition: fts.h:143
int rpmGlob(const char *patterns, int *argcPtr, const char ***argvPtr)
Return URL path(s) from a (URL prefixed) pattern glob.
Definition: macro.c:2611
#define FTS_D
Definition: fts.h:129
static const char * ftsInfoStr(int fts_info)
Definition: rpmgi.c:73
const char * Fstrerror(FD_t fd)
strerror(3) clone.
Definition: rpmio.c:2401
void * xcalloc(size_t nmemb, size_t size)
Definition: rpmmalloc.c:300
rpmgi rpmgiNew(rpmts ts, int tag, const void *keyp, size_t keylen)
Return a generalized iterator.
Definition: rpmgi.c:543
rpmioItem rpmioGetPool(rpmioPool pool, size_t size)
Get unused item from pool, or alloc a new item.
Definition: rpmmalloc.c:220
#define FTS_NSOK
Definition: fts.h:139
static const char * _query_hdlist_path
Definition: rpmgi.c:582
int rpmcliInstallOrder(rpmts ts)
Order package elements in a transaction set, reporting problems.
Definition: rpminstall.c:350
enum rpmgiFlags_e rpmgiFlags
rpmgiFlags giFlags
Definition: rpmgi.c:42
rpmioPool _rpmgiPool
Definition: rpmgi.c:525
static rpmRC rpmgiInitFilter(rpmgi gi)
Return rpmdb match iterator with filters (if any) set.
Definition: rpmgi.c:438
enum rpmdepFlags_e rpmdepFlags
Bit(s) to control rpmtsCheck() and rpmtsOrder() operation.
ARGV_t argvFree(ARGV_t argv)
Destroy an argv array.
Definition: argv.c:44
const char * tagName(rpmTag tag)
Return tag name from value.
Definition: tagname.c:436
#define FTS_DEFAULT
Definition: fts.h:131
#define FTS_DC
Definition: fts.h:130
Routines to expand a manifest containing glob expressions into an argv list.
rpmRC rpmReadPackageFile(rpmts ts, FD_t fd, const char *fn, Header *hdrp)
Return package header from file handle, verifying digests/signatures.
Definition: package.c:114
#define RPMDBI_FTSWALK
Definition: rpmtag.h:487
#define FTS_DOT
Definition: fts.h:133
rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
Load iterator args.
Definition: rpmgi.c:866
The FD_t File Handle data structure.
rpmmi rpmtsInitIterator(const rpmts ts, rpmTag rpmtag, const void *keyp, size_t keylen)
Return transaction database iterator.
Definition: rpmts.c:212
Header headerFree(Header h)
Dereference a header instance.
FTSENT * Fts_read(FTS *sp)
Return next node in the file hierarchy traversal.
Definition: fts.c:467
char * rpmExpand(const char *arg,...)
Return (malloc'ed) concatenated macro expansion(s).
Definition: macro.c:3252
static rpmRC rpmgiWalkPathFilter(rpmgi gi)
Filter file tree walk path.
Definition: rpmgi.c:276
static rpmgi rpmgiGetPool(rpmioPool pool)
Definition: rpmgi.c:527
rpmRC rpmReadPackageManifest(FD_t fd, int *argcPtr, const char ***argvPtr)
Read manifest, glob items, and append to existing args.
Definition: manifest.c:63
const char const char int arg
Definition: mongo.h:777
int rpmcliInstallSuggests(rpmts ts)
Report packages(if any) that satisfy unresolved dependencies.
Definition: rpminstall.c:326
rpmmi rpmmiFree(rpmmi mi)
Destroy rpm database iterator.
int Fclose(FD_t fd)
fclose(3) clone.
Definition: rpmio.c:2534
#define RPMDBI_DEPCACHE
Definition: rpmtag.h:480
const char const bson int mongo_write_concern int flags
Definition: mongo.h:485
rpmte rpmtsiNext(rpmtsi tsi, rpmElementType type)
Return next transaction element of type.
Definition: rpmte.c:831
int rpmcliInstallCheck(rpmts ts)
Check package element dependencies in a transaction set, reporting problems.
Definition: rpminstall.c:343
#define FTS_DNR
Definition: fts.h:132
Header rpmteHeader(rpmte te)
Retrieve header from transaction element.
Definition: rpmte.c:291
static FD_t rpmgiOpen(const char *path, const char *fmode)
Open a file after macro expanding path.
Definition: rpmgi.c:92
Header headerLink(Header h)
Reference a header instance.
char fts_name[1]
Definition: fts.h:157
#define RPMDBI_HDLIST
Definition: rpmtag.h:485
rpmdb rpmtsGetRdb(rpmts ts)
Get transaction set database handle.
Definition: pkgio.c:151
#define FTS_INIT
Definition: fts.h:137
struct rpmgi_s * rpmgi
Generalized iterator.
Definition: rpmtypes.h:53
enum rpmRC_e rpmRC
RPM return codes.
#define RPMDBI_ARGLIST
Definition: rpmtag.h:486
int Ferror(FD_t fd)
ferror(3) clone.
Definition: rpmio.c:2951
int rpmmiAddPattern(rpmmi mi, rpmTag tag, rpmMireMode mode, const char *pattern)
Add pattern to iterator selector.
Definition: rpmdb.c:1910
Definition: rpmte.h:37
rpmdepFlags rpmtsDFlags(rpmts ts)
Get dependency flags, i.e.
Definition: rpmts.c:1363
Definition: fts.h:102
rpmdepFlags rpmtsSetDFlags(rpmts ts, rpmdepFlags depFlags)
Set dependency flags, i.e.
Definition: rpmts.c:1368
static void rpmgiFini(void *_gi)
Definition: rpmgi.c:496
rpmts rpmtsFree(rpmts ts)
Destroy transaction set, closing the database as well.
static rpmRC rpmgiLoadReadHeader(rpmgi gi)
Read next header from package, lazily expanding manifests as found.
Definition: rpmgi.c:218
Methods to handle package elements.
rpmioPool rpmioNewPool(const char *name, size_t size, int limit, int flags, char *(*dbg)(void *item), void(*init)(void *item), void(*fini)(void *item))
Create a memory pool.
Definition: rpmmalloc.c:109
rpmts rpmgiTs(rpmgi gi)
Return current iteration transaction set.
Definition: rpmgi.c:854
struct rpmts_s * rpmts
The RPM Transaction Set.
Definition: rpmtypes.h:14
static rpmRC rpmgiLoadNextKey(rpmgi gi)
Load next key from argv list.
Definition: rpmgi.c:194
static void * _free(const void *p)
Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
Definition: rpmiotypes.h:756
const void * fnpyKey
Definition: rpmiotypes.h:134
Header rpmmiNext(rpmmi mi)
Return next package header from iteration.
Definition: rpmdb.c:2252
int rpmtsAddEraseElement(rpmts ts, Header h, uint32_t hdrNum)
Add package to be erased to transaction set.
Definition: depends.c:834
#define rpmIsVerbose()
Definition: rpmcb.h:21
int Fts_close(FTS *sp)
Destroy a file hierarchy traversal handle.
Definition: fts.c:380
rpmRC rpmgiNext(rpmgi gi)
Perform next iteration step.
Definition: rpmgi.c:584
static int indent
Definition: rpmgi.c:47
#define FTS_F
Definition: fts.h:136
Header rpmgiReadHeader(rpmgi gi, const char *path)
Return header from package.
Definition: rpmgi.c:156
#define _(Text)
Definition: system.h:29
const char * rpmgiHdrPath(rpmgi gi)
Return current header path.
Definition: rpmgi.c:842
#define xmalloc
Definition: system.h:32
rpmRC rpmpkgRead(const char *fn, FD_t fd, void *ptr, const char **msg)
Read item from file descriptor.
Definition: pkgio.c:1674
#define FTS_DP
Definition: fts.h:134
rpmtsi rpmtsiInit(rpmts ts)
Create transaction element iterator.
ARGstr_t * ARGV_t
Definition: argv.h:12
Access RPM indices using Berkeley DB interface(s).
enum rpmTag_e rpmTag
Definition: rpmtag.h:470
static rpmRC rpmgiLoadManifest(rpmgi gi, const char *path)
Load manifest into iterator arg list.
Definition: rpmgi.c:124
int rpmdbBlockDBI(rpmdb db, int tag)
Block access to a single database index.
Definition: rpmdb.c:825
uint32_t headerGetInstance(Header h)
Return header instance (if from rpmdb).
Definition: header.c:1275
#define FTS_ERR
Definition: fts.h:135
#define RPMDBI_PACKAGES
Pseudo-tags used by the rpmdb and rpmgi iterator API's.
Definition: rpmtag.h:479
tsmStage rpmtsSetGoal(rpmts ts, tsmStage goal)
Set goal of transaction set.
Definition: rpmts.c:1415
#define RPMDBI_ADDED
Definition: rpmtag.h:482
static rpmRC rpmgiWalkReadHeader(rpmgi gi)
Read header from next package, lazily walking file tree.
Definition: rpmgi.c:327
int _rpmgi_debug
Definition: rpmgi.c:37