rpm  5.2.1
rpminstall.c
Go to the documentation of this file.
1 
5 #include "system.h"
6 
7 #include <rpmio.h>
8 #include <rpmiotypes.h>
9 #include <poptIO.h>
10 
11 #include <rpmtag.h>
12 #include <rpmevr.h>
13 #include "rpmdb.h"
14 #ifdef NOTYET
15 #include "rpmds.h" /* XXX ts->suggests, +foo -foo =foo args */
16 #endif
17 
18 #include "rpmte.h" /* XXX rpmtsPrint() */
19 #define _RPMTS_INTERNAL /* XXX ts->suggests */
20 #include <rpmts.h>
21 
22 #include "manifest.h"
23 #define _RPMGI_INTERNAL /* XXX "+bing" args need gi->h. */
24 #include "rpmgi.h"
25 
26 #include <rpmlib.h>
27 
28 #include <rpmcli.h>
29 #define _RPMROLLBACK_INTERNAL
30 #include <rpmrollback.h>
31 
32 #include "debug.h"
33 
34 /*@access FD_t @*/ /* XXX void * arg */
35 /*@access rpmts @*/ /* XXX ts->suggests */
36 /*@access rpmgi @*/ /* XXX gi->h */
37 /*@access fnpyKey @*/ /* XXX cast */
38 
39 /*@unchecked@*/
41 /*@unchecked@*/
43 /*@unchecked@*/
45 /*@unchecked@*/
47 /*@unchecked@*/
49 
56 static void printHash(const rpmuint64_t amount, const rpmuint64_t total)
57  /*@globals rpmcliHashesCurrent, rpmcliHashesTotal,
58  rpmcliProgressCurrent, fileSystem @*/
59  /*@modifies rpmcliHashesCurrent, rpmcliHashesTotal,
60  rpmcliProgressCurrent, fileSystem @*/
61 {
62  int hashesNeeded;
63 
64  rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
65 
67  float pct = (float) (total ? (((float) amount) / total) : 1);
68  hashesNeeded = (int)((rpmcliHashesTotal * pct) + 0.5);
69  while (hashesNeeded > rpmcliHashesCurrent) {
70  if (isatty (STDOUT_FILENO)) {
71  int i;
72  for (i = 0; i < rpmcliHashesCurrent; i++)
73  (void) putchar ('#');
74  for (; i < rpmcliHashesTotal; i++)
75  (void) putchar (' ');
76  fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
77  for (i = 0; i < (rpmcliHashesTotal + 6); i++)
78  (void) putchar ('\b');
79  } else
80  fprintf(stdout, "#");
81 
83  }
84  (void) fflush(stdout);
85 
87  int i;
89  if (isatty(STDOUT_FILENO)) {
90  for (i = 1; i < rpmcliHashesCurrent; i++)
91  (void) putchar ('#');
92  pct = (float) (rpmcliProgressTotal
94  : 1);
95  fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
96  }
97  fprintf(stdout, "\n");
98  }
99  (void) fflush(stdout);
100  }
101 }
102 
103 void * rpmShowProgress(/*@null@*/ const void * arg,
104  const rpmCallbackType what,
105  const rpmuint64_t amount,
106  const rpmuint64_t total,
107  /*@null@*/ fnpyKey key,
108  /*@null@*/ void * data)
109  /*@globals rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
110  rpmGlobalMacroContext, fileSystem @*/
111  /*@modifies rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
112  rpmGlobalMacroContext, fileSystem @*/
113 {
114 /*@-abstract -castexpose @*/
115  Header h = (Header) arg;
116 /*@=abstract =castexpose @*/
117  const char * s;
118  int flags = (int) ((long)data);
119  void * rc = NULL;
120 /*@-abstract -assignexpose @*/
121  const char * filename = (const char *)key;
122 /*@=abstract =assignexpose @*/
123  static FD_t fd = NULL;
124  int xx;
125 
126  switch (what) {
128  if (filename == NULL || filename[0] == '\0')
129  return NULL;
130  fd = Fopen(filename, "r%{?_rpmgio}");
131 
132  /* XXX Retry once to handle http:// server timeout reopen's. */
133  if (Ferror(fd)) {
134  int ut = urlPath(filename, NULL);
135  if (ut == URL_IS_HTTP || ut == URL_IS_HTTPS) {
136  /* XXX HACK: Fclose(fd) no workie here. */
137  fd = Fopen(filename, "r%{?_rpmgio}");
138  }
139  }
140 
141  /*@-type@*/ /* FIX: still necessary? */
142  if (fd == NULL || Ferror(fd)) {
143  rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
144  Fstrerror(fd));
145  if (fd != NULL) {
146  xx = Fclose(fd);
147  fd = NULL;
148  }
149  } else
150  fd = fdLink(fd, "persist (showProgress)");
151  /*@=type@*/
152 /*@+voidabstract@*/
153  return (void *)fd;
154 /*@=voidabstract@*/
155  /*@notreached@*/ break;
156 
158  /*@-type@*/ /* FIX: still necessary? */
159  fd = fdFree(fd, "persist (showProgress)");
160  /*@=type@*/
161  if (fd != NULL) {
162  xx = Fclose(fd);
163  fd = NULL;
164  }
165  break;
166 
169  if (h == NULL || !(flags & INSTALL_LABEL))
170  break;
171  /* @todo Remove headerSprintf() on a progress callback. */
172  if (flags & INSTALL_HASH) {
173  s = headerSprintf(h, "%{NAME}",
174  NULL, rpmHeaderFormats, NULL);
175  if (isatty (STDOUT_FILENO))
176  fprintf(stdout, "%4d:%-23.23s", (int)rpmcliProgressCurrent + 1, s);
177  else
178  fprintf(stdout, "%-28.28s", s);
179  (void) fflush(stdout);
180  s = _free(s);
181  } else {
182  char * t = rpmExpand("%{?___NVRA}%{!?___NVRA:%%{NAME}-%%{VERSION}-%%{RELEASE}}", NULL);
183  s = headerSprintf(h, t, NULL, rpmHeaderFormats, NULL);
184  fprintf(stdout, "%s\n", s);
185  (void) fflush(stdout);
186  s = _free(s);
187  t = _free(t);
188  }
189  break;
190 
193 /*@+relaxtypes@*/
194  if (flags & INSTALL_PERCENT)
195  fprintf(stdout, "%%%% %f\n", (double) (total
196  ? ((((float) amount) / total) * 100)
197  : 100.0));
198  else if (flags & INSTALL_HASH)
199  printHash(amount, total);
200 /*@=relaxtypes@*/
201  (void) fflush(stdout);
202  break;
203 
208  if (!(flags & INSTALL_LABEL))
209  break;
210  if (flags & INSTALL_HASH)
211  fprintf(stdout, "%-28s", _("Preparing..."));
212  else
213  fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
214  (void) fflush(stdout);
215  break;
216 
218  if (flags & INSTALL_HASH)
219  printHash(1, 1); /* Fixes "preparing..." progress bar */
222  break;
223 
226  rpmcliProgressTotal = total;
228  if (!(flags & INSTALL_LABEL))
229  break;
230  if (flags & INSTALL_HASH)
231  fprintf(stdout, "%-28s\n", _("Repackaging..."));
232  else
233  fprintf(stdout, "%s\n", _("Repackaging erased files..."));
234  (void) fflush(stdout);
235  break;
236 
238  if (amount && (flags & INSTALL_HASH))
239  printHash(1, 1); /* Fixes "preparing..." progress bar */
240  break;
241 
243  rpmcliProgressTotal = total;
244  rpmcliProgressCurrent = total;
245  if (flags & INSTALL_HASH)
246  printHash(1, 1); /* Fixes "preparing..." progress bar */
249  if (!(flags & INSTALL_LABEL))
250  break;
251  if (flags & INSTALL_HASH)
252  fprintf(stdout, "%-28s\n", _("Upgrading..."));
253  else
254  fprintf(stdout, "%s\n", _("Upgrading packages..."));
255  (void) fflush(stdout);
256  break;
257 
259  break;
261  break;
263  break;
265  break;
267  break;
269  break;
270  case RPMCALLBACK_UNKNOWN:
271  default:
272  break;
273  }
274 
275  return rc;
276 }
277 
278 int rpmcliInstallProblems(rpmts ts, const char * msg, int rc)
279  /*@globals fileSystem @*/
280  /*@modifies ts, fileSystem @*/
281 {
282  rpmps ps = rpmtsProblems(ts);
283 
284  if (rc && rpmpsNumProblems(ps) > 0) {
285  if (msg)
286  rpmlog(RPMLOG_ERR, "%s:\n", msg);
287  rpmpsPrint(NULL, ps);
288  }
289  ps = rpmpsFree(ps);
290  return rc;
291 }
292 
294 {
295  if (ts->suggests != NULL && ts->nsuggests > 0) {
296  const char * s;
297  int i;
298 
299  rpmlog(RPMLOG_NOTICE, _(" Suggested resolutions:\n"));
300  for (i = 0; i < ts->nsuggests && (s = ts->suggests[i]) != NULL;
301  ts->suggests[i++] = s = _free(s))
302  {
303  rpmlog(RPMLOG_NOTICE, "\t%s\n", s);
304  }
305  ts->suggests = _free(ts->suggests);
306  }
307  return 0;
308 }
309 
311 {
312 /*@-evalorder@*/
313  return rpmcliInstallProblems(ts, _("Failed dependencies"), rpmtsCheck(ts));
314 /*@=evalorder@*/
315 }
316 
318 {
319 /*@-evalorder@*/
320  return rpmcliInstallProblems(ts, _("Ordering problems"), rpmtsOrder(ts));
321 /*@=evalorder@*/
322 }
323 
324 int rpmcliInstallRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
325 {
326 /*@-evalorder@*/
327  return rpmcliInstallProblems(ts, _("Install/Erase problems"),
328  rpmtsRun(ts, okProbs, ignoreSet));
329 /*@=evalorder@*/
330 }
331 
332 static rpmRC rpmcliEraseElement(rpmts ts, const char * arg)
333  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
334  /*@modifies ts, rpmGlobalMacroContext, fileSystem, internalState @*/
335 {
336  rpmmi mi;
337  Header h;
338  rpmRC rc = RPMRC_OK;
339  int xx;
340 
341  mi = rpmtsInitIterator(ts, RPMDBI_LABEL, arg, 0);
342  if (mi == NULL)
343  return RPMRC_NOTFOUND;
344 
345  while ((h = rpmmiNext(mi)) != NULL) {
346  unsigned int recOffset = rpmmiInstance(mi);
347 
348  if (recOffset == 0) { /* XXX can't happen. */
349  rc = RPMRC_FAIL;
350  break;
351  }
352  xx = rpmtsAddEraseElement(ts, h, recOffset);
353  }
354  mi = rpmmiFree(mi);
355 
356  return 0;
357 }
358 
359 static const char * rpmcliWalkFirst(ARGV_t av, miRE mire)
360  /*@globals fileSystem, internalState @*/
361  /*@modifies mire, fileSystem, internalState @*/
362 {
363  /* XXX use global ftsOpts? */
364  /* XXX changing FTS_LOGICAL to FTS_PHYSICAL prevents symlink follow. */
365  /* XXX FTS_NOCHDIR is automatically assumed for URI's */
366  int _ftsOpts = (FTS_COMFOLLOW | FTS_LOGICAL | FTS_NOSTAT);
367  FTS * ftsp = NULL;
368  FTSENT * fts;
369  const char * fn = NULL;
370  int fts_level = 1;
371  int xx;
372 
373  if (av != NULL && av[0] != NULL)
374  ftsp = Fts_open((char *const *)av, _ftsOpts, NULL);
375  if (ftsp != NULL)
376  while((fts = Fts_read(ftsp)) != NULL) {
377  switch (fts->fts_info) {
378  /* No-op conditions. */
379  case FTS_D: /* preorder directory */
380  case FTS_DP: /* postorder directory */
381  /* XXX Don't recurse downwards, all elements should be files. */
382  if (fts_level > 0 && fts->fts_level >= fts_level)
383  xx = Fts_set(ftsp, fts, FTS_SKIP);
384  /*@fallthrough@*/
385  case FTS_DOT: /* dot or dot-dot */
386  continue;
387  /*@notreached@*/ /*@switchbreak@*/ break;
388  case FTS_F: /* regular file */
389  if (mireRegexec(mire, fts->fts_accpath, 0) < 0)
390  continue;
391  /*@switchbreak@*/ break;
392  /* Error conditions. */
393  case FTS_NS: /* stat(2) failed */
394  case FTS_DNR: /* unreadable directory */
395  case FTS_ERR: /* error; errno is set */
396  case FTS_DC: /* directory that causes cycles */
397  case FTS_DEFAULT: /* none of the above */
398  case FTS_INIT: /* initialized only */
399  case FTS_NSOK: /* no stat(2) requested */
400  case FTS_SL: /* symbolic link */
401  case FTS_SLNONE: /* symbolic link without target */
402  case FTS_W: /* whiteout object */
403  default:
404  goto exit;
405  /*@notreached@*/ /*@switchbreak@*/ break;
406  }
407 
408  /* Stop on first file that matches. */
409  fn = xstrdup(fts->fts_accpath);
410  break;
411  }
412 
413 exit:
414  xx = Fts_close(ftsp);
415  return fn;
416 }
417 
418 static const char * rpmcliInstallElementPath(/*@unused@*/ rpmts ts,
419  const char * arg)
420  /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
421  /*@modifies rpmGlobalMacroContext, fileSystem, internalState @*/
422 {
423  /* A glob pattern list to match repository directories. */
424  const char * fn = rpmExpand(
425  "%{?_rpmgi_pattern_glob}"
426  "%{!?_rpmgi_pattern_glob:.}",
427  NULL
428  );
429  /* A regex pattern list to match candidate *.rpm files. */
430  const char * mirePattern = rpmExpand(
431  "%{?_rpmgi_pattern_regex:%{_rpmgi_pattern_regex ", arg, "}}"
432  "%{!?_rpmgi_pattern_regex:", arg, "-[^-]+-[^-]+\\.[^.]+\\.rpm$}",
433  NULL
434  );
435  miRE mire = mireNew(RPMMIRE_REGEX, 0);
436  ARGV_t dav = NULL;
437  int dac = 0;
438  ARGV_t av = NULL;
439  int xx = mireRegcomp(mire, mirePattern);
440  int i;
441 
442  /* Get list of candidate repository patterns. */
443  xx = argvSplit(&dav, fn, ":");
444  fn = _free(fn);
445  if (xx || dav == NULL)
446  goto exit;
447 
448  dac = argvCount(dav);
449  for (i = 0; i < dac; i++) {
450  ARGV_t nav = NULL;
451  int nac = 0;
452 
453  /* Insure only directory paths are matched. */
454  fn = rpmGetPath(dav[i], "/", NULL);
455  xx = rpmGlob(fn, &nac, &nav);
456 
457  /* Insure that final directory paths have trailing '/' */
458  if (nav != NULL)
459  for (i = 0; i < nac; i++) {
460  char * t = rpmExpand(nav[i], "/", NULL);
461  nav[i] = _free(nav[i]);
462  nav[i] = t;
463  }
464 
465  /* Append matches to list of repository directories. */
466  if (nac > 0 && nav != NULL)
467  xx = argvAppend(&av, nav);
468  nav = argvFree(nav);
469  nac = 0;
470  fn = _free(fn);
471  }
472 
473  /* Walk (possibly multi-root'd) directories, until 1st match is found. */
474  fn = rpmcliWalkFirst(av, mire);
475 
476 exit:
477  av = argvFree(av);
478  dav = argvFree(dav);
479  mire = mireFree(mire);
480  mirePattern = _free(mirePattern);
481 
482  return fn;
483 }
484 
485 /*@-redef@*/ /* XXX Add rpmfi methods to make rpmRelocation opaque. */
486 struct rpmRelocation_s {
487 /*@only@*/ /*@null@*/
488  const char * oldPath;
489 /*@only@*/ /*@null@*/
490  const char * newPath;
491 };
492 /*@=redef@*/
493 
495 int rpmcliInstall(rpmts ts, QVA_t ia, const char ** argv)
496 {
497  HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
498  ARGV_t avfn = NULL;
499  int acfn = 0;
500  int numFailed = 0;
501  int numRPMS = 0;
502  rpmRelocation relocations = NULL;
503  rpmVSFlags vsflags, ovsflags;
504  rpmRC rpmrc;
505  int rc;
506  int xx;
507 
508  if (argv == NULL) goto exit;
509 
510  (void) rpmtsSetGoal(ts, TSM_INSTALL);
512 
513  if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
515 
516  (void) rpmtsSetFlags(ts, ia->transFlags);
517  (void) rpmtsSetDFlags(ts, ia->depFlags);
518 
519  /* Display and set autorollback goal. */
520  if (rpmExpandNumeric("%{?_rollback_transaction_on_failure}")) {
521  if (ia->arbtid) {
522  time_t ttid = (time_t)ia->arbtid;
523  rpmlog(RPMLOG_DEBUG, D_("Autorollback Goal: %-24.24s (0x%08x)\n"),
524  ctime(&ttid), ia->arbtid);
525  rpmtsSetARBGoal(ts, ia->arbtid);
526  }
527  }
528 
530  vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
531  else
532  vsflags = rpmExpandNumeric("%{?_vsflags_install}");
533  if (ia->qva_flags & VERIFY_DIGEST)
534  vsflags |= _RPMVSF_NODIGESTS;
535  if (ia->qva_flags & VERIFY_SIGNATURE)
536  vsflags |= _RPMVSF_NOSIGNATURES;
537  if (ia->qva_flags & VERIFY_HDRCHK)
538  vsflags |= RPMVSF_NOHDRCHK;
539  ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
540 
541  { int notifyFlags;
542  notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
543  xx = rpmtsSetNotifyCallback(ts,
544  rpmShowProgress, (void *) ((long)notifyFlags));
545  }
546 
547  if ((relocations = ia->relocations) != NULL) {
548  while (relocations->oldPath)
549  relocations++;
550  if (relocations->newPath == NULL)
551  relocations = NULL;
552  }
553 
554  { /* start-of-transaction-build */
555  int tag = (ia->qva_source == RPMQV_FTSWALK)
557  rpmgi gi = rpmgiNew(ts, tag, NULL, 0);
558  rpmgiFlags _giFlags = RPMGI_NONE;
559  const char * fn = NULL;;
560 
561 /*@-mods@*/
562  if (rpmioFtsOpts == 0)
564 /*@=mods@*/
565  rc = rpmgiSetArgs(gi, argv, rpmioFtsOpts, _giFlags);
566  while ((rpmrc = rpmgiNext(gi)) == RPMRC_OK) {
567  Header h;
568 
569  fn = _free(fn);
570  fn = xstrdup(rpmgiHdrPath(gi));
571 
572  /* === Check for "+bing" lookaside paths within install transaction. */
573  if (fn[0] == '+') {
574  const char * nfn;
575  addMacro(NULL, "NEVRA", NULL, &fn[1], RMIL_GLOBAL);
576  nfn = rpmcliInstallElementPath(ts, &fn[1]);
577  delMacro(NULL, "NEVRA");
578  if (nfn == NULL) {
579  rpmlog(RPMLOG_ERR, _("package \"%s\" cannot be found\n"), fn);
580  numFailed++; /* XXX multiple erasures? */
581  continue;
582  }
583  fn = _free(fn);
584  fn = nfn;
585  /* XXX hack into rpmgi innards for now ... */
586  h = rpmgiReadHeader(gi, fn);
587  if (h != NULL)
588  gi->h = headerLink(h);
589  (void)headerFree(h);
590  h = NULL;
591  }
592 
593  /* === Check for "-bang" erasures within install transaction. */
594  if (fn[0] == '-') {
595  switch (rpmcliEraseElement(ts, &fn[1])) {
596  case RPMRC_OK:
597  numRPMS++; /* XXX multiple erasures? */
598  /*@switchbreak@*/ break;
599  case RPMRC_NOTFOUND:
600  default:
601  rpmlog(RPMLOG_ERR, _("package \"%s\" cannot be erased\n"), fn);
602  numFailed++; /* XXX multiple erasures? */
603  goto exit;
604  /*@notreached@*/ /*@switchbreak@*/ break;
605  }
606  continue;
607  }
608 
609  h = rpmgiHeader(gi);
610  if (h == NULL) {
611  numFailed++;
612  continue;
613  }
614 
615  /* === Check for relocatable package. */
616  if (relocations) {
617  he->tag = RPMTAG_PREFIXES;
618  xx = headerGet(h, he, 0);
619  if (xx && he->c == 1) {
620  relocations->oldPath = xstrdup(he->p.argv[0]);
621  he->p.ptr = _free(he->p.ptr);
622  } else {
623  he->p.ptr = _free(he->p.ptr);
624  he->tag = RPMTAG_NVRA;
625  xx = headerGet(h, he, 0);
627  _("package %s is not relocatable\n"), he->p.str);
628  he->p.ptr = _free(he->p.ptr);
629  numFailed++;
630  goto exit;
631  /*@notreached@*/
632  }
633  }
634 
635  /* === On --freshen, verify package is installed and newer. */
637  rpmmi mi;
638  Header oldH;
639  int count;
640 
641  he->tag = RPMTAG_NAME;
642  xx = headerGet(h, he, 0);
643 assert(xx != 0 && he->p.str != NULL);
644  mi = rpmtsInitIterator(ts, RPMTAG_NAME, he->p.str, 0);
645  he->p.ptr = _free(he->p.ptr);
646  count = rpmmiCount(mi);
647  while ((oldH = rpmmiNext(mi)) != NULL) {
648  if (rpmVersionCompare(oldH, h) < 0)
649  /*@innercontinue@*/ continue;
650  /* same or newer package already installed */
651  count = 0;
652  /*@innerbreak@*/ break;
653  }
654  mi = rpmmiFree(mi);
655  if (count == 0)
656  continue;
657  /* Package is newer than those currently installed. */
658  }
659 
660  /* === Add binary package to transaction set. */
661  xx = argvAdd(&avfn, fn);
662  rc = rpmtsAddInstallElement(ts, h, (fnpyKey)avfn[acfn++],
664  ia->relocations);
665 
666  if (relocations)
667  relocations->oldPath = _free(relocations->oldPath);
668 
669  numRPMS++;
670  }
671 
672  fn = _free(fn);
673  gi = rpmgiFree(gi);
674 
675  } /* end-of-transaction-build */
676 
677  /* XXX exit if the iteration failed. */
678  if (rpmrc == RPMRC_FAIL) numFailed = numRPMS;
679  if (numFailed) goto exit;
680 
681  if (numRPMS) {
683  && (rc = rpmcliInstallCheck(ts)) != 0) {
684  numFailed = numRPMS;
685  (void) rpmcliInstallSuggests(ts);
686  }
687 
689  && (rc = rpmcliInstallOrder(ts)) != 0)
690  numFailed = numRPMS;
691 
692  /* Drop added/available package indices and dependency sets. */
693  rpmtsClean(ts);
694 
695  /* XXX Avoid empty transaction msg, run iff there are elements. */
696  if (numFailed == 0 && rpmtsNElements(ts) > 0
697  && (rc = rpmcliInstallRun(ts, NULL, ia->probFilter)) != 0)
698  numFailed += (rc < 0 ? numRPMS : rc);
699  }
700 
701  if (numFailed) goto exit;
702 
703 exit:
704  avfn = argvFree(avfn);
705 
706 #ifdef NOTYET /* XXX grrr, segfault in selabel_close */
709 #endif
710 
711  rpmtsEmpty(ts);
712 
713  return numFailed;
714 }
715 
716 int rpmErase(rpmts ts, QVA_t ia, const char ** argv)
717 {
718  int count;
719  const char ** arg;
720  int numFailed = 0;
721  int numRPMS = 0;
722  rpmVSFlags vsflags, ovsflags;
723  int rc;
724 
725  if (argv == NULL) return 0;
726 
727  vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
728  if (ia->qva_flags & VERIFY_DIGEST)
729  vsflags |= _RPMVSF_NODIGESTS;
730  if (ia->qva_flags & VERIFY_SIGNATURE)
731  vsflags |= _RPMVSF_NOSIGNATURES;
732  if (ia->qva_flags & VERIFY_HDRCHK)
733  vsflags |= RPMVSF_NOHDRCHK;
734  ovsflags = rpmtsSetVSFlags(ts, vsflags);
735 
736  if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
738 
739  (void) rpmtsSetFlags(ts, ia->transFlags);
740  (void) rpmtsSetDFlags(ts, ia->depFlags);
741 
742  /* Display and set autorollback goal. */
743  if (rpmExpandNumeric("%{?_rollback_transaction_on_failure}")) {
744  if (ia->arbtid) {
745  time_t ttid = (time_t)ia->arbtid;
746  rpmlog(RPMLOG_DEBUG, D_("Autorollback Goal: %-24.24s (0x%08x)\n"),
747  ctime(&ttid), ia->arbtid);
748  rpmtsSetARBGoal(ts, ia->arbtid);
749  }
750  }
751 
752 #ifdef NOTYET /* XXX no callbacks on erase yet */
753  { int notifyFlags;
754  notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
755  xx = rpmtsSetNotifyCallback(ts,
756  rpmShowProgress, (void *) ((long)notifyFlags));
757  }
758 #endif
759 
760  (void) rpmtsSetGoal(ts, TSM_ERASE);
761 
762  for (arg = argv; *arg; arg++) {
763  rpmmi mi;
764 
765  /* XXX HACK to get rpmdbFindByLabel out of the API */
766  mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
767  if (mi == NULL) {
768  rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
769  numFailed++;
770  } else {
771  Header h; /* XXX iterator owns the reference */
772  count = 0;
773  while ((h = rpmmiNext(mi)) != NULL) {
774  unsigned int recOffset = rpmmiInstance(mi);
775 
776  if (!(count++ == 0 || (ia->installInterfaceFlags & INSTALL_ALLMATCHES))) {
777  rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
778  *arg);
779  numFailed++;
780  /*@innerbreak@*/ break;
781  }
782  if (recOffset) {
783  (void) rpmtsAddEraseElement(ts, h, recOffset);
784  numRPMS++;
785  }
786  }
787  }
788  mi = rpmmiFree(mi);
789  }
790 
791  if (numFailed == 0 && numRPMS > 0) {
793  && (rc = rpmcliInstallCheck(ts)) != 0)
794  numFailed = numRPMS;
795 
796  if (numFailed == 0
798  && (rc = rpmcliInstallOrder(ts)) != 0)
799  numFailed = numRPMS;
800 
801  /* Drop added/available package indices and dependency sets. */
802  rpmtsClean(ts);
803 
804  if (numFailed == 0
806  numFailed += (rc < 0 ? numRPMS : rc);
807 
808  }
809 
810  rpmtsEmpty(ts);
811 
812  return numFailed;
813 }
814 
815 int rpmInstallSource(rpmts ts, const char * arg,
816  const char ** specFilePtr, const char ** cookie)
817 {
818  FD_t fd;
819  int rc;
820 
821  fd = Fopen(arg, "r%{?_rpmgio}");
822  if (fd == NULL || Ferror(fd)) {
823  rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
824  if (fd != NULL) (void) Fclose(fd);
825  return 1;
826  }
827 
828  if (rpmIsVerbose())
829  fprintf(stdout, _("Installing %s\n"), arg);
830 
831  {
832  rpmVSFlags ovsflags =
834  rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
835  rc = (rpmrc == RPMRC_OK ? 0 : 1);
836  ovsflags = rpmtsSetVSFlags(ts, ovsflags);
837  }
838  if (rc != 0) {
839  rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
840  /*@-unqualifiedtrans@*/
841  if (specFilePtr && *specFilePtr)
842  *specFilePtr = _free(*specFilePtr);
843  if (cookie && *cookie)
844  *cookie = _free(*cookie);
845  /*@=unqualifiedtrans@*/
846  }
847 
848  (void) Fclose(fd);
849 
850  return rc;
851 }