rpm  5.2.1
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 <rpmlib.h>
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  return fd;
111 }
112 
119 static rpmRC rpmgiLoadManifest(rpmgi gi, const char * path)
120  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
121  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
122 {
123  FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
124  rpmRC rpmrc = RPMRC_FAIL;
125 
126  if (fd != NULL) {
127  rpmrc = rpmReadPackageManifest(fd, &gi->argc, &gi->argv);
128  (void) Fclose(fd);
129  }
130  return rpmrc;
131 }
132 
133 Header rpmgiReadHeader(rpmgi gi, const char * path)
134 {
135  FD_t fd = rpmgiOpen(path, "r%{?_rpmgio}");
136  Header h = NULL;
137 
138  if (fd != NULL) {
139  /* XXX what if path needs expansion? */
140  rpmRC rpmrc = rpmReadPackageFile(gi->ts, fd, path, &h);
141 
142  (void) Fclose(fd);
143 
144  switch (rpmrc) {
145  case RPMRC_NOTFOUND:
146  /* XXX Read a package manifest. Restart ftswalk on success. */
147  case RPMRC_FAIL:
148  default:
149  (void)headerFree(h);
150  h = NULL;
151  break;
152  case RPMRC_NOTTRUSTED:
153  case RPMRC_NOKEY:
154  case RPMRC_OK:
155  break;
156  }
157  }
158 
159  return h;
160 }
161 
168  /*@modifies gi @*/
169 {
170  rpmRC rpmrc = RPMRC_NOTFOUND;
171  if (gi->argv != NULL && gi->argv[gi->i] != NULL) {
172  gi->keyp = gi->argv[gi->i];
173  gi->keylen = 0;
174  rpmrc = RPMRC_OK;
175  } else {
176  gi->i = -1;
177  gi->keyp = NULL;
178  gi->keylen = 0;
179  }
180  return rpmrc;
181 }
182 
192  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
193  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
194 {
195  rpmRC rpmrc = RPMRC_NOTFOUND;
196  Header h = NULL;
197 
198  if (gi->argv != NULL && gi->argv[gi->i] != NULL)
199  do {
200  const char * fn; /* XXX gi->hdrPath? */
201 
202  fn = gi->argv[gi->i];
203  /* XXX Skip +bing -bang =boom special arguments. */
204  if (strchr("-+=", *fn) == NULL && !(gi->flags & RPMGI_NOHEADER)) {
205  h = rpmgiReadHeader(gi, fn);
206  if (h != NULL)
207  rpmrc = RPMRC_OK;
208  } else
209  rpmrc = RPMRC_OK;
210 
211  if (rpmrc == RPMRC_OK || gi->flags & RPMGI_NOMANIFEST)
212  break;
213  if (errno == ENOENT)
214  break;
215 
216  /* Not a header, so try for a manifest. */
217  gi->argv[gi->i] = NULL; /* Mark the insertion point */
218  rpmrc = rpmgiLoadManifest(gi, fn);
219  /* XXX its unclear if RPMRC_NOTFOUND should fail or continue here. */
220  if (rpmrc != RPMRC_OK) {
221  gi->argv[gi->i] = fn; /* Manifest failed, restore fn */
222  break;
223  }
224  fn = _free(fn);
225  rpmrc = RPMRC_NOTFOUND;
226  } while (1);
227 
228  if (rpmrc == RPMRC_OK && h != NULL)
229  gi->h = headerLink(h);
230  (void)headerFree(h);
231  h = NULL;
232 
233  return rpmrc;
234 }
235 
241 /*@null@*/
243  /*@*/
244 {
245  FTSENT * fts = gi->fts;
246  rpmRC rpmrc = RPMRC_NOTFOUND;
247  const char * s;
248 
249 if (_rpmgi_debug < 0)
250 rpmlog(RPMLOG_DEBUG, "FTS_%s\t%*s %s%s\n", ftsInfoStr(fts->fts_info),
251  indent * (fts->fts_level < 0 ? 0 : fts->fts_level), "",
252  fts->fts_name,
253  ((fts->fts_info == FTS_D || fts->fts_info == FTS_DP) ? "/" : ""));
254 
255  switch (fts->fts_info) {
256  case FTS_D: /* preorder directory */
257  break;
258  case FTS_DP: /* postorder directory */
259  break;
260  case FTS_F: /* regular file */
261  if ((size_t)fts->fts_namelen <= sizeof(".rpm"))
262  break;
263  /* Ignore all but *.rpm files. */
264  s = fts->fts_name + fts->fts_namelen + 1 - sizeof(".rpm");
265  if (strcmp(s, ".rpm"))
266  break;
267  rpmrc = RPMRC_OK;
268  break;
269  case FTS_NS: /* stat(2) failed */
270  case FTS_DNR: /* unreadable directory */
271  case FTS_ERR: /* error; errno is set */
272  break;
273  case FTS_DC: /* directory that causes cycles */
274  case FTS_DEFAULT: /* none of the above */
275  case FTS_DOT: /* dot or dot-dot */
276  case FTS_INIT: /* initialized only */
277  case FTS_NSOK: /* no stat(2) requested */
278  case FTS_SL: /* symbolic link */
279  case FTS_SLNONE: /* symbolic link without target */
280  case FTS_W: /* whiteout object */
281  default:
282  break;
283  }
284  return rpmrc;
285 }
286 
292 /*@null@*/
294  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
295  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
296 {
297  rpmRC rpmrc = RPMRC_NOTFOUND;
298 
299  if (gi->ftsp != NULL)
300  while ((gi->fts = Fts_read(gi->ftsp)) != NULL) {
301  if (gi->walkPathFilter)
302  rpmrc = (*gi->walkPathFilter) (gi);
303  else
304  rpmrc = rpmgiWalkPathFilter(gi);
305  if (rpmrc == RPMRC_OK)
306  break;
307  }
308 
309  if (rpmrc == RPMRC_OK) {
310  Header h = NULL;
311  if (!(gi->flags & RPMGI_NOHEADER)) {
312  /* XXX rpmrc = rpmgiLoadReadHeader(gi); */
313  if (gi->fts != NULL) /* XXX can't happen */
314  h = rpmgiReadHeader(gi, gi->fts->fts_path);
315  }
316  if (h != NULL) {
317  gi->h = headerLink(h);
318  (void)headerFree(h);
319  h = NULL;
320 /*@-noeffectuncon@*/
321  if (gi->stash != NULL)
322  (void) (*gi->stash) (gi, gi->h);
323 /*@=noeffectuncon@*/
324  }
325  }
326 
327  return rpmrc;
328 }
329 
330 const char * rpmgiEscapeSpaces(const char * s)
331 {
332  const char * se;
333  const char * t;
334  char * te;
335  size_t nb = 0;
336 
337  for (se = s; *se; se++) {
338  if (isspace(*se))
339  nb++;
340  nb++;
341  }
342  nb++;
343 
344  t = te = xmalloc(nb);
345  for (se = s; *se; se++) {
346  if (isspace(*se))
347  *te++ = '\\';
348  *te++ = *se;
349  }
350  *te = '\0';
351  return t;
352 }
353 
360 static rpmRC rpmgiGlobArgv(rpmgi gi, /*@null@*/ ARGV_t argv)
361  /*@globals internalState @*/
362  /*@modifies gi, internalState @*/
363 {
364  const char * arg;
365  rpmRC rpmrc = RPMRC_OK;
366  int ac = 0;
367  int xx;
368 
369  /* XXX Expand globs only if requested or for gi specific tags */
370  if ((gi->flags & RPMGI_NOGLOB)
371  || !(gi->tag == RPMDBI_HDLIST || gi->tag == RPMDBI_ARGLIST || gi->tag == RPMDBI_FTSWALK))
372  {
373  if (argv != NULL) {
374  while (argv[ac] != NULL)
375  ac++;
376 /*@-nullstate@*/ /* XXX argv is not NULL */
377  xx = argvAppend(&gi->argv, argv);
378 /*@=nullstate@*/
379  }
380  gi->argc = ac;
381  return rpmrc;
382  }
383 
384  if (argv != NULL)
385  while ((arg = *argv++) != NULL) {
386  const char * t = rpmgiEscapeSpaces(arg);
387  ARGV_t av = NULL;
388 
389  xx = rpmGlob(t, &ac, &av);
390  xx = argvAppend(&gi->argv, av);
391  gi->argc += ac;
392  av = argvFree(av);
393  t = _free(t);
394  ac = 0;
395  }
396  return rpmrc;
397 }
398 
405  /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
406  /*@modifies gi, rpmGlobalMacroContext, h_errno, internalState @*/
407 {
408  rpmRC rpmrc = RPMRC_OK;
409  ARGV_t av;
410  int res = 0;
411 
412  gi->mi = rpmtsInitIterator(gi->ts, gi->tag, gi->keyp, gi->keylen);
413 
414 if (_rpmgi_debug < 0)
415 fprintf(stderr, "*** gi %p key %p[%d]\tmi %p\n", gi, gi->keyp, (int)gi->keylen, gi->mi);
416 
417  if (gi->argv != NULL)
418  for (av = (const char **) gi->argv; *av != NULL; av++) {
419  if (gi->tag == RPMDBI_PACKAGES) {
420  int tag = RPMTAG_NAME;
421  const char * pat;
422  char * a, * ae;
423 
424  pat = a = xstrdup(*av);
425  tag = RPMTAG_NAME;
426 
427  /* Parse for "tag=pattern" args. */
428  if ((ae = strchr(a, '=')) != NULL) {
429  *ae++ = '\0';
430  if (*a != '\0') { /* XXX HACK: permit '=foo' */
431  tag = tagValue(a);
432  if (tag < 0) {
433  rpmlog(RPMLOG_NOTICE, _("unknown tag: \"%s\"\n"), a);
434  res = 1;
435  }
436  }
437  pat = ae;
438  }
439  if (!res) {
440 if (_rpmgi_debug < 0)
441 fprintf(stderr, "\tav %p[%d]: \"%s\" -> %s ~= \"%s\"\n", gi->argv, (int)(av - gi->argv), *av, tagName(tag), pat);
442  res = rpmmiAddPattern(gi->mi, tag, RPMMIRE_DEFAULT, pat);
443  }
444  a = _free(a);
445  }
446 
447  if (res == 0)
448  continue;
449 
450  gi->mi = rpmmiFree(gi->mi); /* XXX odd side effect? */
451  rpmrc = RPMRC_FAIL;
452  break;
453  }
454 
455  return rpmrc;
456 }
457 
458 /*@-mustmod@*/
459 static void rpmgiFini(void * _gi)
460  /*@globals rpmGlobalMacroContext @*/
461  /*@modifies _gi, rpmGlobalMacroContext @*/
462 {
463  rpmgi gi = _gi;
464  int xx;
465 
466  gi->hdrPath = _free(gi->hdrPath);
467  (void)headerFree(gi->h);
468  gi->h = NULL;
469 
470  gi->argv = argvFree(gi->argv);
471 
472  if (gi->ftsp != NULL) {
473  xx = Fts_close(gi->ftsp);
474  gi->ftsp = NULL;
475  gi->fts = NULL;
476  }
477  if (gi->fd != NULL) {
478  xx = Fclose(gi->fd);
479  gi->fd = NULL;
480  }
481  gi->tsi = rpmtsiFree(gi->tsi);
482  gi->mi = rpmmiFree(gi->mi);
483  (void)rpmtsFree(gi->ts);
484  gi->ts = NULL;
485 }
486 /*@=mustmod@*/
487 
488 /*@unchecked@*/ /*@only@*/ /*@null@*/
490 
491 static rpmgi rpmgiGetPool(/*@null@*/ rpmioPool pool)
492  /*@globals _rpmgiPool, fileSystem, internalState @*/
493  /*@modifies pool, _rpmgiPool, fileSystem, internalState @*/
494 {
495  rpmgi gi;
496 
497  if (_rpmgiPool == NULL) {
498  _rpmgiPool = rpmioNewPool("gi", sizeof(*gi), -1, _rpmgi_debug,
499  NULL, NULL, rpmgiFini);
500  pool = _rpmgiPool;
501  }
502  return (rpmgi) rpmioGetPool(pool, sizeof(*gi));
503 }
504 
505 rpmgi rpmgiNew(rpmts ts, int tag, const void * keyp, size_t keylen)
506 {
507  rpmgi gi = rpmgiGetPool(_rpmgiPool);
508 
509  if (gi == NULL) /* XXX can't happen */
510  return NULL;
511 
512 /*@-assignexpose -castexpose @*/
513  gi->ts = rpmtsLink(ts, "rpmgiNew");
514 /*@=assignexpose =castexpose @*/
515  gi->tsOrder = rpmtsOrder;
516  gi->tag = (rpmTag) tag;
517 /*@-assignexpose@*/
518  gi->keyp = keyp;
519 /*@=assignexpose@*/
520  gi->keylen = keylen;
521 
522  gi->flags = 0;
523  gi->active = 0;
524  gi->i = -1;
525  gi->hdrPath = NULL;
526  gi->h = NULL;
527 
528  gi->tsi = NULL;
529  gi->mi = NULL;
530  gi->fd = NULL;
531  gi->argv = xcalloc(1, sizeof(*gi->argv));
532  gi->argc = 0;
533  gi->ftsOpts = 0;
534  gi->ftsp = NULL;
535  gi->fts = NULL;
536  gi->walkPathFilter = NULL;
537 
538  gi = rpmgiLink(gi, "rpmgiNew");
539 
540  return gi;
541 }
542 
543 /*@observer@*/ /*@unchecked@*/
544 static const char * _query_hdlist_path = "/usr/share/comps/%{_arch}/hdlist";
545 
546 rpmRC rpmgiNext(/*@null@*/ rpmgi gi)
547 {
548  char hnum[32];
549  rpmRC rpmrc = RPMRC_NOTFOUND;
550  int xx;
551 
552  if (gi == NULL)
553  return rpmrc;
554 
555 if (_rpmgi_debug)
556 fprintf(stderr, "*** rpmgiNext(%p) tag %s\n", gi, tagName(gi->tag));
557 
558  /* Free header from previous iteration. */
559  (void)headerFree(gi->h);
560  gi->h = NULL;
561  gi->hdrPath = _free(gi->hdrPath);
562  hnum[0] = '\0';
563 
564  if (++gi->i >= 0)
565  switch (gi->tag) {
566  default:
567  if (!gi->active) {
568 nextkey:
569  rpmrc = rpmgiLoadNextKey(gi);
570  if (rpmrc != RPMRC_OK)
571  goto enditer;
572  rpmrc = rpmgiInitFilter(gi);
573  if (rpmrc != RPMRC_OK || gi->mi == NULL) {
574  gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */
575  gi->i++;
576  goto nextkey;
577  }
578  rpmrc = RPMRC_NOTFOUND; /* XXX hack */
579  gi->active = 1;
580  }
581  if (gi->mi != NULL) { /* XXX unnecessary */
582  Header h = rpmmiNext(gi->mi);
583  if (h != NULL) {
584  if (!(gi->flags & RPMGI_NOHEADER))
585  gi->h = headerLink(h);
586  sprintf(hnum, "%u", rpmmiInstance(gi->mi));
587  gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
588  rpmrc = RPMRC_OK;
589  /* XXX header reference held by iterator, so no headerFree */
590  }
591  }
592  if (rpmrc != RPMRC_OK) {
593  gi->mi = rpmmiFree(gi->mi);
594  goto nextkey;
595  }
596  break;
597  case RPMDBI_PACKAGES:
598  if (!gi->active) {
599  rpmrc = rpmgiInitFilter(gi);
600  if (rpmrc != RPMRC_OK) {
601  gi->mi = rpmmiFree(gi->mi); /* XXX unnecessary */
602  goto enditer;
603  }
604  rpmrc = RPMRC_NOTFOUND; /* XXX hack */
605  gi->active = 1;
606  }
607  if (gi->mi != NULL) { /* XXX unnecessary */
608  Header h = rpmmiNext(gi->mi);
609  if (h != NULL) {
610  if (!(gi->flags & RPMGI_NOHEADER))
611  gi->h = headerLink(h);
612  sprintf(hnum, "%u", rpmmiInstance(gi->mi));
613  gi->hdrPath = rpmExpand("rpmdb h# ", hnum, NULL);
614  rpmrc = RPMRC_OK;
615  /* XXX header reference held by iterator, so no headerFree */
616  }
617  }
618  if (rpmrc != RPMRC_OK) {
619  gi->mi = rpmmiFree(gi->mi);
620  goto enditer;
621  }
622  break;
623  case RPMDBI_REMOVED:
624  case RPMDBI_ADDED:
625  { rpmte p;
626  int teType = 0;
627  const char * teTypeString = NULL;
628 
629  if (!gi->active) {
630  gi->tsi = rpmtsiInit(gi->ts);
631  gi->active = 1;
632  }
633  if ((p = rpmtsiNext(gi->tsi, teType)) != NULL) {
634  Header h = rpmteHeader(p);
635  if (h != NULL)
636  if (!(gi->flags & RPMGI_NOHEADER)) {
637  gi->h = headerLink(h);
638  switch(rpmteType(p)) {
639  case TR_ADDED: teTypeString = "+++"; /*@switchbreak@*/break;
640  case TR_REMOVED: teTypeString = "---"; /*@switchbreak@*/break;
641  }
642  sprintf(hnum, "%u", (unsigned)gi->i);
643  gi->hdrPath = rpmExpand("%s h# ", teTypeString, hnum, NULL);
644  rpmrc = RPMRC_OK;
645  (void)headerFree(h);
646  h = NULL;
647  }
648  }
649  if (rpmrc != RPMRC_OK) {
650  gi->tsi = rpmtsiFree(gi->tsi);
651  goto enditer;
652  }
653  } break;
654  case RPMDBI_HDLIST:
655  if (!gi->active) {
656  const char * path = rpmExpand("%{?_query_hdlist_path}", NULL);
657  if (path == NULL || *path == '\0') {
658  path = _free(path);
659  path = rpmExpand(_query_hdlist_path, NULL);
660  }
661  gi->fd = rpmgiOpen(path, "rm%{?_rpmgio}");
662  gi->active = 1;
663  path = _free(path);
664  }
665  if (gi->fd != NULL) {
666  Header h = NULL;
667  const char item[] = "Header";
668  const char * msg = NULL;
669 /*@+voidabstract@*/
670  rpmrc = rpmpkgRead(item, gi->fd, &h, &msg);
671 /*@=voidabstract@*/
672  if (rpmrc != RPMRC_OK) {
673  rpmlog(RPMLOG_ERR, "%s: %s: %s\n", "rpmpkgRead", item, msg);
674  h = NULL;
675  }
676  msg = _free(msg);
677  if (h != NULL) {
678  if (!(gi->flags & RPMGI_NOHEADER))
679  gi->h = headerLink(h);
680  sprintf(hnum, "%u", (unsigned)gi->i);
681  gi->hdrPath = rpmExpand("hdlist h# ", hnum, NULL);
682  rpmrc = RPMRC_OK;
683  (void)headerFree(h);
684  h = NULL;
685  }
686  }
687  if (rpmrc != RPMRC_OK) {
688  if (gi->fd != NULL) (void) Fclose(gi->fd);
689  gi->fd = NULL;
690  goto enditer;
691  }
692  break;
693  case RPMDBI_ARGLIST:
694  /* XXX gi->active initialize? */
695 if (_rpmgi_debug < 0)
696 fprintf(stderr, "*** gi %p\t%p[%d]: %s\n", gi, gi->argv, gi->i, gi->argv[gi->i]);
697  /* Read next header, lazily expanding manifests as found. */
698  rpmrc = rpmgiLoadReadHeader(gi);
699 
700  if (rpmrc != RPMRC_OK) /* XXX check this */
701  goto enditer;
702 
703  gi->hdrPath = xstrdup(gi->argv[gi->i]);
704  break;
705  case RPMDBI_FTSWALK:
706  if (gi->argv == NULL || gi->argv[0] == NULL) /* HACK */
707  goto enditer;
708 
709  if (!gi->active) {
710  gi->ftsp = Fts_open((char *const *)gi->argv, gi->ftsOpts, NULL);
711  /* XXX NULL with open(2)/malloc(3) errno set */
712  gi->active = 1;
713  }
714 
715  /* Read next header, lazily walking file tree. */
716  rpmrc = rpmgiWalkReadHeader(gi);
717 
718  if (rpmrc != RPMRC_OK) {
719  xx = Fts_close(gi->ftsp);
720  gi->ftsp = NULL;
721  goto enditer;
722  }
723 
724  if (gi->fts != NULL)
725  gi->hdrPath = xstrdup(gi->fts->fts_path);
726  break;
727  }
728 
729  if ((gi->flags & RPMGI_TSADD) && gi->h != NULL) {
730  /* XXX rpmgi hack: Save header in transaction element. */
731  if (gi->flags & RPMGI_ERASING) {
732  static int hdrx = 0;
733  int dboffset = headerGetInstance(gi->h);
734  if (dboffset <= 0)
735  dboffset = --hdrx;
736  xx = rpmtsAddEraseElement(gi->ts, gi->h, dboffset);
737  } else
738  xx = rpmtsAddInstallElement(gi->ts, gi->h, (fnpyKey)gi->hdrPath, 2, NULL);
739  }
740 
741  return rpmrc;
742 
743 enditer:
744  if (gi->flags & RPMGI_TSORDER) {
745  rpmts ts = gi->ts;
746  rpmps ps;
747  int i;
748 
749  /* Block access to indices used for depsolving. */
750  if (!(gi->flags & RPMGI_ERASING)) {
751  (void) rpmtsSetGoal(ts, TSM_INSTALL);
755  } else {
756  (void) rpmtsSetGoal(ts, TSM_ERASE);
757  }
758 
759  xx = rpmtsCheck(ts);
760 
761  /* Permit access to indices used for depsolving. */
762  if (!(gi->flags & RPMGI_ERASING)) {
766  }
767 
768  /* XXX query/verify will need the glop added to a buffer instead. */
769  ps = rpmtsProblems(ts);
770  if (rpmpsNumProblems(ps) > 0) {
771  /* XXX rpminstall will need RPMLOG_ERR */
772  rpmlog(RPMLOG_INFO, _("Failed dependencies:\n"));
773  if (rpmIsVerbose())
774  rpmpsPrint(NULL, ps);
775 
776  if (ts->suggests != NULL && ts->nsuggests > 0) {
777  rpmlog(RPMLOG_INFO, _(" Suggested resolutions:\n"));
778  for (i = 0; i < ts->nsuggests; i++) {
779  const char * str = ts->suggests[i];
780 
781  if (str == NULL)
782  break;
783 
784  rpmlog(RPMLOG_INFO, "\t%s\n", str);
785 
786  ts->suggests[i] = NULL;
787  str = _free(str);
788  }
789  ts->suggests = _free(ts->suggests);
790  }
791 
792  }
793  ps = rpmpsFree(ps);
794  ts->probs = rpmpsFree(ts->probs); /* XXX hackery */
795 
796  /* XXX Display dependency loops with rpm -qvT. */
797  if (rpmIsVerbose())
799 
800  xx = (*gi->tsOrder) (ts);
801 
802  /* XXX hackery alert! */
803  gi->tag = (!(gi->flags & RPMGI_ERASING) ? RPMDBI_ADDED : RPMDBI_REMOVED);
804  gi->flags &= ~(RPMGI_TSADD|RPMGI_TSORDER);
805 
806  }
807 
808  (void)headerFree(gi->h);
809  gi->h = NULL;
810  gi->hdrPath = _free(gi->hdrPath);
811  gi->i = -1;
812  gi->active = 0;
813  return rpmrc;
814 }
815 
817 {
818  return (gi != NULL ? gi->flags : RPMGI_NONE);
819 }
820 
821 const char * rpmgiHdrPath(rpmgi gi)
822 {
823  return (gi != NULL ? gi->hdrPath : NULL);
824 }
825 
827 {
828 /*@-compdef -refcounttrans -retexpose -usereleased@*/
829  return (gi != NULL ? gi->h : NULL);
830 /*@=compdef =refcounttrans =retexpose =usereleased@*/
831 }
832 
834 {
835 /*@-compdef -refcounttrans -retexpose -usereleased@*/
836  return (gi != NULL ? gi->ts : NULL);
837 /*@=compdef =refcounttrans =retexpose =usereleased@*/
838 }
839 
840 rpmRC rpmgiSetArgs(rpmgi gi, ARGV_t argv, int ftsOpts, rpmgiFlags flags)
841 {
842  if (gi == NULL) return RPMRC_FAIL;
843  gi->ftsOpts = ftsOpts;
844  gi->flags = flags;
845  return rpmgiGlobArgv(gi, argv);
846 }
847 
848 /*@=modfilesys@*/