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