2 * \file lib/rpminstall.c
7 #include <rpm/rpmcli.h>
10 #include <rpm/rpmds.h>
11 #include <rpm/rpmts.h>
12 #include <rpm/rpmlog.h>
13 #include <rpm/rpmfileutil.h>
16 #include "lib/manifest.h"
19 int rpmcliPackagesTotal = 0;
20 int rpmcliHashesCurrent = 0;
21 int rpmcliHashesTotal = 0;
22 int rpmcliProgressCurrent = 0;
23 int rpmcliProgressTotal = 0;
26 * Print a CLI progress bar.
27 * @todo Unsnarl isatty(STDOUT_FILENO) from the control flow.
28 * @param amount current
31 static void printHash(const unsigned long amount, const unsigned long total)
35 rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
37 if (rpmcliHashesCurrent != rpmcliHashesTotal) {
38 float pct = (total ? (((float) amount) / total) : 1.0);
39 hashesNeeded = (rpmcliHashesTotal * pct) + 0.5;
40 while (hashesNeeded > rpmcliHashesCurrent) {
41 if (isatty (STDOUT_FILENO)) {
43 for (i = 0; i < rpmcliHashesCurrent; i++)
45 for (; i < rpmcliHashesTotal; i++)
47 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
48 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
49 (void) putchar ('\b');
53 rpmcliHashesCurrent++;
55 (void) fflush(stdout);
57 if (rpmcliHashesCurrent == rpmcliHashesTotal) {
59 rpmcliProgressCurrent++;
60 if (isatty(STDOUT_FILENO)) {
61 for (i = 1; i < rpmcliHashesCurrent; i++)
63 pct = (rpmcliProgressTotal
64 ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
66 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
68 fprintf(stdout, "\n");
70 (void) fflush(stdout);
74 void * rpmShowProgress(const void * arg,
75 const rpmCallbackType what,
76 const unsigned long amount,
77 const unsigned long total,
81 Header h = (Header) arg;
83 int flags = (int) ((long)data);
85 const char * filename = (const char *)key;
86 static FD_t fd = NULL;
90 case RPMCALLBACK_INST_OPEN_FILE:
91 if (filename == NULL || filename[0] == '\0')
93 fd = Fopen(filename, "r.ufdio");
94 /* FIX: still necessary? */
95 if (fd == NULL || Ferror(fd)) {
96 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
103 fd = fdLink(fd, RPMDBG_M("persist (showProgress)"));
107 case RPMCALLBACK_INST_CLOSE_FILE:
108 /* FIX: still necessary? */
109 fd = fdFree(fd, RPMDBG_M("persist (showProgress)"));
116 case RPMCALLBACK_INST_START:
117 rpmcliHashesCurrent = 0;
118 if (h == NULL || !(flags & INSTALL_LABEL))
120 /* @todo Remove headerSprintf() on a progress callback. */
121 if (flags & INSTALL_HASH) {
122 s = headerSprintf(h, "%{NAME}",
123 rpmTagTable, rpmHeaderFormats, NULL);
124 if (isatty (STDOUT_FILENO))
125 fprintf(stdout, "%4d:%-23.23s", rpmcliProgressCurrent + 1, s);
127 fprintf(stdout, "%-28.28s", s);
128 (void) fflush(stdout);
131 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
132 rpmTagTable, rpmHeaderFormats, NULL);
133 fprintf(stdout, "%s\n", s);
134 (void) fflush(stdout);
139 case RPMCALLBACK_TRANS_PROGRESS:
140 case RPMCALLBACK_INST_PROGRESS:
141 if (flags & INSTALL_PERCENT)
142 fprintf(stdout, "%%%% %f\n", (double) (total
143 ? ((((float) amount) / total) * 100)
145 else if (flags & INSTALL_HASH)
146 printHash(amount, total);
147 (void) fflush(stdout);
150 case RPMCALLBACK_TRANS_START:
151 rpmcliHashesCurrent = 0;
152 rpmcliProgressTotal = 1;
153 rpmcliProgressCurrent = 0;
154 if (!(flags & INSTALL_LABEL))
156 if (flags & INSTALL_HASH)
157 fprintf(stdout, "%-28s", _("Preparing..."));
159 fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
160 (void) fflush(stdout);
163 case RPMCALLBACK_TRANS_STOP:
164 if (flags & INSTALL_HASH)
165 printHash(1, 1); /* Fixes "preparing..." progress bar */
166 rpmcliProgressTotal = rpmcliPackagesTotal;
167 rpmcliProgressCurrent = 0;
170 case RPMCALLBACK_REPACKAGE_START:
171 rpmcliHashesCurrent = 0;
172 rpmcliProgressTotal = total;
173 rpmcliProgressCurrent = 0;
174 if (!(flags & INSTALL_LABEL))
176 if (flags & INSTALL_HASH)
177 fprintf(stdout, "%-28s\n", _("Repackaging..."));
179 fprintf(stdout, "%s\n", _("Repackaging erased files..."));
180 (void) fflush(stdout);
183 case RPMCALLBACK_REPACKAGE_PROGRESS:
184 if (amount && (flags & INSTALL_HASH))
185 printHash(1, 1); /* Fixes "preparing..." progress bar */
188 case RPMCALLBACK_REPACKAGE_STOP:
189 rpmcliProgressTotal = total;
190 rpmcliProgressCurrent = total;
191 if (flags & INSTALL_HASH)
192 printHash(1, 1); /* Fixes "preparing..." progress bar */
193 rpmcliProgressTotal = rpmcliPackagesTotal;
194 rpmcliProgressCurrent = 0;
195 if (!(flags & INSTALL_LABEL))
197 if (flags & INSTALL_HASH)
198 fprintf(stdout, "%-28s\n", _("Upgrading..."));
200 fprintf(stdout, "%s\n", _("Upgrading packages..."));
201 (void) fflush(stdout);
204 case RPMCALLBACK_UNINST_PROGRESS:
206 case RPMCALLBACK_UNINST_START:
208 case RPMCALLBACK_UNINST_STOP:
210 case RPMCALLBACK_UNPACK_ERROR:
212 case RPMCALLBACK_CPIO_ERROR:
214 case RPMCALLBACK_SCRIPT_ERROR:
216 case RPMCALLBACK_UNKNOWN:
224 typedef const char * str_t;
242 rpmRelocation * relocations;
246 /** @todo Generalize --freshen policies. */
247 int rpmInstall(rpmts ts,
248 struct rpmInstallArguments_s * ia,
249 const char ** fileArgv)
251 struct rpmEIU * eiu = memset(alloca(sizeof(*eiu)), 0, sizeof(*eiu));
253 rpmprobFilterFlags probFilter;
254 rpmRelocation * relocations;
255 char * fileURL = NULL;
258 rpmVSFlags vsflags, ovsflags, tvsflags;
264 if (fileArgv == NULL) goto exit;
266 rpmcliPackagesTotal = 0;
268 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
269 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
271 (void) rpmtsSetFlags(ts, ia->transFlags);
273 probFilter = ia->probFilter;
274 relocations = ia->relocations;
276 if (ia->installInterfaceFlags & INSTALL_UPGRADE)
277 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
279 vsflags = rpmExpandNumeric("%{?_vsflags_install}");
280 if (ia->qva_flags & VERIFY_DIGEST)
281 vsflags |= _RPMVSF_NODIGESTS;
282 if (ia->qva_flags & VERIFY_SIGNATURE)
283 vsflags |= _RPMVSF_NOSIGNATURES;
284 if (ia->qva_flags & VERIFY_HDRCHK)
285 vsflags |= RPMVSF_NOHDRCHK;
286 ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
289 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
290 xx = rpmtsSetNotifyCallback(ts,
291 rpmShowProgress, (void *) ((long)notifyFlags));
294 if ((eiu->relocations = relocations) != NULL) {
295 while (eiu->relocations->oldPath)
297 if (eiu->relocations->newPath == NULL)
298 eiu->relocations = NULL;
301 /* Build fully globbed list of arguments in argv[argc]. */
302 for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
304 av = _free(av); ac = 0;
305 fn = rpmEscapeSpaces(*eiu->fnp);
306 rc = rpmGlob(fn, &ac, &av);
309 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
313 eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
314 memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
316 eiu->argv[eiu->argc] = NULL;
318 av = _free(av); ac = 0;
321 /* Allocate sufficient storage for next set of args. */
322 if (eiu->pkgx >= eiu->numPkgs) {
323 eiu->numPkgs = eiu->pkgx + eiu->argc;
324 eiu->pkgURL = xrealloc(eiu->pkgURL,
325 (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
326 memset(eiu->pkgURL + eiu->pkgx, 0,
327 ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
328 eiu->pkgState = xrealloc(eiu->pkgState,
329 (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
330 memset(eiu->pkgState + eiu->pkgx, 0,
331 ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
334 /* Retrieve next set of args, cache on local storage. */
335 for (i = 0; i < eiu->argc; i++) {
336 fileURL = _free(fileURL);
337 fileURL = eiu->argv[i];
341 if (fileURL[0] == '=') {
342 rpmds this = rpmdsSingle(RPMTAG_REQUIRENAME, fileURL+1, NULL, 0);
344 xx = rpmtsSolve(ts, this, NULL);
345 if (ts->suggests && ts->nsuggests > 0) {
346 fileURL = _free(fileURL);
347 fileURL = ts->suggests[0];
348 ts->suggests[0] = NULL;
349 while (ts->nsuggests-- > 0) {
350 if (ts->suggests[ts->nsuggests] == NULL)
352 ts->suggests[ts->nsuggests] = _free(ts->suggests[ts->nsuggests]);
354 ts->suggests = _free(ts->suggests);
355 rpmlog(RPMLOG_DEBUG, _("Adding goal: %s\n"), fileURL);
356 eiu->pkgURL[eiu->pkgx] = fileURL;
360 this = rpmdsFree(this);
364 switch (urlIsURL(fileURL)) {
371 fprintf(stdout, _("Retrieving %s\n"), fileURL);
374 const char * rootDir = rpmtsRootDir(ts);
375 if (!(rootDir && * rootDir))
377 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
378 #if defined(HAVE_MKSTEMP)
379 (void) close(mkstemp(tfnbuf));
381 (void) mktemp(tfnbuf);
383 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
386 /* XXX undefined %{name}/%{version}/%{release} here */
387 /* XXX %{_tmpdir} does not exist */
388 rpmlog(RPMLOG_DEBUG, _(" ... as %s\n"), tfn);
389 rc = urlGetFile(fileURL, tfn);
392 _("skipping %s - transfer failed - %s\n"),
393 fileURL, ftpStrerror(rc));
395 eiu->pkgURL[eiu->pkgx] = NULL;
399 eiu->pkgState[eiu->pkgx] = 1;
400 eiu->pkgURL[eiu->pkgx] = tfn;
404 case URL_IS_DASH: /* WRONG WRONG WRONG */
405 case URL_IS_HKP: /* WRONG WRONG WRONG */
407 eiu->pkgURL[eiu->pkgx] = fileURL;
413 fileURL = _free(fileURL);
415 if (eiu->numFailed) goto exit;
417 /* Continue processing file arguments, building transaction set. */
418 for (eiu->fnp = (const char**) eiu->pkgURL+eiu->prevx;
420 eiu->fnp++, eiu->prevx++)
422 const char * fileName;
424 rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp);
425 (void) urlPath(*eiu->fnp, &fileName);
427 /* Try to read the header from a package file. */
428 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
429 if (eiu->fd == NULL || Ferror(eiu->fd)) {
430 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
432 if (eiu->fd != NULL) {
433 xx = Fclose(eiu->fd);
436 eiu->numFailed++; *eiu->fnp = NULL;
440 /* Read the header, verifying signatures (if present). */
441 tvsflags = rpmtsSetVSFlags(ts, vsflags);
442 eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
443 tvsflags = rpmtsSetVSFlags(ts, tvsflags);
444 xx = Fclose(eiu->fd);
447 switch (eiu->rpmrc) {
449 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp);
450 eiu->numFailed++; *eiu->fnp = NULL;
456 case RPMRC_NOTTRUSTED:
463 eiu->isSource = headerIsSource(eiu->h);
466 rpmlog(RPMLOG_DEBUG, _("\tadded source package [%d]\n"),
468 eiu->sourceURL = xrealloc(eiu->sourceURL,
469 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
470 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
473 eiu->sourceURL[eiu->numSRPMS] = NULL;
477 if (eiu->relocations) {
482 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
483 (rpm_data_t *) &paths, &c) && (c == 1))
485 eiu->relocations->oldPath = xstrdup(paths[0]);
486 paths = headerFreeData(paths, pft);
489 xx = headerNVR(eiu->h, &name, NULL, NULL);
491 _("package %s is not relocatable\n"), name);
497 /* On --freshen, verify package is installed and newer */
498 if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
499 rpmdbMatchIterator mi;
504 xx = headerNVR(eiu->h, &name, NULL, NULL);
505 mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
506 count = rpmdbGetIteratorCount(mi);
507 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
508 if (rpmVersionCompare(oldH, eiu->h) < 0)
510 /* same or newer package already installed */
514 mi = rpmdbFreeIterator(mi);
516 eiu->h = headerFree(eiu->h);
519 /* Package is newer than those currently installed. */
522 rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
523 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
526 /* XXX reference held by transaction set */
527 eiu->h = headerFree(eiu->h);
528 if (eiu->relocations)
529 eiu->relocations->oldPath = _constfree(eiu->relocations->oldPath);
533 rpmlog(RPMLOG_DEBUG, _("\tadded binary package [%d]\n"),
538 _("error reading from file %s\n"), *eiu->fnp);
544 _("file %s requires a newer version of RPM\n"),
559 /* Try to read a package manifest. */
560 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
561 if (eiu->fd == NULL || Ferror(eiu->fd)) {
562 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
564 if (eiu->fd != NULL) {
565 xx = Fclose(eiu->fd);
568 eiu->numFailed++; *eiu->fnp = NULL;
572 /* Read list of packages from manifest. */
573 /* FIX: *eiu->argv can be NULL */
574 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
576 rpmlog(RPMLOG_NOTICE, _("%s: not an rpm package (or package manifest): %s\n"),
577 *eiu->fnp, Fstrerror(eiu->fd));
578 xx = Fclose(eiu->fd);
581 /* If successful, restart the query loop. */
582 if (rc == RPMRC_OK) {
587 eiu->numFailed++; *eiu->fnp = NULL;
591 rpmlog(RPMLOG_DEBUG, _("found %d source and %d binary packages\n"),
592 eiu->numSRPMS, eiu->numRPMS);
594 if (eiu->numFailed) goto exit;
596 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
598 if (rpmtsCheck(ts)) {
599 eiu->numFailed = eiu->numPkgs;
603 ps = rpmtsProblems(ts);
604 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
605 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
606 rpmpsPrint(NULL, ps);
607 eiu->numFailed = eiu->numPkgs;
610 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST))
611 rpmtsPrintSuggests(ts);
617 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
618 if (rpmtsOrder(ts)) {
619 eiu->numFailed = eiu->numPkgs;
624 if (eiu->numRPMS && !stopInstall) {
626 rpmcliPackagesTotal += eiu->numSRPMS;
628 rpmlog(RPMLOG_DEBUG, _("installing binary packages\n"));
630 /* Drop added/available package indices and dependency sets. */
633 rc = rpmtsRun(ts, NULL, probFilter);
634 ps = rpmtsProblems(ts);
637 eiu->numFailed += eiu->numRPMS;
639 eiu->numFailed += rc;
640 if (rpmpsNumProblems(ps) > 0)
641 rpmpsPrint(stderr, ps);
646 if (eiu->numSRPMS && !stopInstall) {
647 if (eiu->sourceURL != NULL)
648 for (i = 0; i < eiu->numSRPMS; i++) {
650 if (eiu->sourceURL[i] == NULL) continue;
651 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
652 if (eiu->fd == NULL || Ferror(eiu->fd)) {
653 rpmlog(RPMLOG_ERR, _("cannot open file %s: %s\n"),
654 eiu->sourceURL[i], Fstrerror(eiu->fd));
655 if (eiu->fd != NULL) {
656 xx = Fclose(eiu->fd);
662 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
663 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
664 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
667 xx = Fclose(eiu->fd);
673 if (eiu->pkgURL != NULL)
674 for (i = 0; i < eiu->numPkgs; i++) {
675 if (eiu->pkgURL[i] == NULL) continue;
676 if (eiu->pkgState[i] == 1)
677 (void) unlink(eiu->pkgURL[i]);
678 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
680 eiu->pkgState = _free(eiu->pkgState);
681 eiu->pkgURL = _free(eiu->pkgURL);
682 eiu->argv = _free(eiu->argv);
686 return eiu->numFailed;
689 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
695 int stopUninstall = 0;
697 rpmVSFlags vsflags, ovsflags;
700 if (argv == NULL) return 0;
702 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
703 if (ia->qva_flags & VERIFY_DIGEST)
704 vsflags |= _RPMVSF_NODIGESTS;
705 if (ia->qva_flags & VERIFY_SIGNATURE)
706 vsflags |= _RPMVSF_NOSIGNATURES;
707 if (ia->qva_flags & VERIFY_HDRCHK)
708 vsflags |= RPMVSF_NOHDRCHK;
709 ovsflags = rpmtsSetVSFlags(ts, vsflags);
711 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
712 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
714 /* XXX suggest mechanism only meaningful when installing */
715 ia->transFlags |= RPMTRANS_FLAG_NOSUGGEST;
717 (void) rpmtsSetFlags(ts, ia->transFlags);
719 #ifdef NOTYET /* XXX no callbacks on erase yet */
720 { int notifyFlags, xx;
721 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
722 xx = rpmtsSetNotifyCallback(ts,
723 rpmShowProgress, (void *) ((long)notifyFlags));
727 for (arg = argv; *arg; arg++) {
728 rpmdbMatchIterator mi;
730 /* XXX HACK to get rpmdbFindByLabel out of the API */
731 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
733 rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
736 Header h; /* XXX iterator owns the reference */
738 while ((h = rpmdbNextIterator(mi)) != NULL) {
739 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
741 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
742 rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
748 (void) rpmtsAddEraseElement(ts, h, recOffset);
753 mi = rpmdbFreeIterator(mi);
756 if (numFailed) goto exit;
758 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
760 if (rpmtsCheck(ts)) {
761 numFailed = numPackages;
765 ps = rpmtsProblems(ts);
766 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
767 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
768 rpmpsPrint(NULL, ps);
769 numFailed += numPackages;
775 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
776 if (rpmtsOrder(ts)) {
777 numFailed += numPackages;
782 if (numPackages && !stopUninstall) {
783 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
785 /* Drop added/available package indices and dependency sets. */
788 numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
789 ps = rpmtsProblems(ts);
790 if (rpmpsNumProblems(ps) > 0)
791 rpmpsPrint(NULL, ps);
792 numFailed += numPackages;
803 int rpmInstallSource(rpmts ts, const char * arg,
804 char ** specFilePtr, char ** cookie)
810 fd = Fopen(arg, "r.ufdio");
811 if (fd == NULL || Ferror(fd)) {
812 rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
813 if (fd != NULL) (void) Fclose(fd);
818 fprintf(stdout, _("Installing %s\n"), arg);
821 rpmVSFlags ovsflags =
822 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
823 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
824 rc = (rpmrc == RPMRC_OK ? 0 : 1);
825 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
828 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
829 if (specFilePtr && *specFilePtr)
830 *specFilePtr = _free(*specFilePtr);
831 if (cookie && *cookie)
832 *cookie = _free(*cookie);
840 /** @todo Transaction handling, more, needs work. */
841 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
843 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
844 unsigned thistid = 0xffffffff;
854 int vsflags, ovsflags;
858 int _unsafe_rollbacks = 0;
859 rpmtransFlags transFlags = ia->transFlags;
861 if (argv != NULL && *argv != NULL) {
866 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
868 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
869 if (ia->qva_flags & VERIFY_DIGEST)
870 vsflags |= _RPMVSF_NODIGESTS;
871 if (ia->qva_flags & VERIFY_SIGNATURE)
872 vsflags |= _RPMVSF_NOSIGNATURES;
873 if (ia->qva_flags & VERIFY_HDRCHK)
874 vsflags |= RPMVSF_NOHDRCHK;
875 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
876 ovsflags = rpmtsSetVSFlags(ts, vsflags);
878 (void) rpmtsSetFlags(ts, transFlags);
880 /* Make the transaction a rollback transaction. In a rollback
881 * a best effort is what we want
883 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
885 itids = IDTXload(ts, RPMTAG_INSTALLTID);
894 { char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
895 if (globstr == NULL || *globstr == '%') {
896 globstr = _free(globstr);
900 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
909 globstr = _free(globstr);
912 { int notifyFlags, xx;
913 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
914 xx = rpmtsSetNotifyCallback(ts,
915 rpmShowProgress, (void *) ((long)notifyFlags));
918 /* Run transactions until rollback goal is achieved. */
922 rpmcliPackagesTotal = 0;
925 ia->installInterfaceFlags &= ~ifmask;
927 /* Find larger of the remaining install/erase transaction id's. */
929 if (ip != NULL && ip->val.u32 > thistid)
930 thistid = ip->val.u32;
931 if (rp != NULL && rp->val.u32 > thistid)
932 thistid = rp->val.u32;
934 /* If we've achieved the rollback goal, then we're done. */
935 if (thistid == 0 || thistid < ia->rbtid)
938 /* If we've reached the (configured) rollback goal, then we're done. */
939 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
943 (void) rpmtsSetFlags(ts, transFlags);
945 /* Install the previously erased packages for this transaction. */
946 while (rp != NULL && rp->val.u32 == thistid) {
948 rpmlog(RPMLOG_DEBUG, "\t+++ install %s\n",
949 (rp->key ? rp->key : "???"));
951 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
957 rpmcliPackagesTotal++;
958 if (!(ia->installInterfaceFlags & ifmask))
959 ia->installInterfaceFlags |= INSTALL_UPGRADE;
962 rp->h = headerFree(rp->h);
971 /* Erase the previously installed packages for this transaction. */
972 while (ip != NULL && ip->val.u32 == thistid) {
975 "\t--- erase h#%u\n", ip->instance);
977 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
983 if (_unsafe_rollbacks)
984 rpmcliPackagesTotal++;
986 if (!(ia->installInterfaceFlags & ifmask)) {
987 ia->installInterfaceFlags |= INSTALL_ERASE;
988 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1001 /* Anything to do? */
1002 if (rpmcliPackagesTotal <= 0)
1005 tid = (time_t)thistid;
1006 rpmlog(RPMLOG_NOTICE,
1007 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1008 numAdded, numRemoved, ctime(&tid), tid);
1010 rc = rpmtsCheck(ts);
1011 ps = rpmtsProblems(ts);
1012 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1013 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
1014 rpmpsPrint(NULL, ps);
1020 rc = rpmtsOrder(ts);
1024 /* Drop added/available package indices and dependency sets. */
1027 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1028 ps = rpmtsProblems(ts);
1029 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1030 rpmpsPrint(stderr, ps);
1035 /* Clean up after successful rollback. */
1036 if (rtids && !rpmIsDebug()) {
1038 rpmlog(RPMLOG_NOTICE, _("Cleaning up repackaged packages:\n"));
1040 for (i = 0; i < rtids->nidt; i++) {
1041 IDT rrp = rtids->idt + i;
1042 if (rrp->val.u32 != thistid)
1044 if (rrp->key) { /* XXX can't happen */
1045 rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
1046 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1055 rtids = IDTXfree(rtids);
1056 itids = IDTXfree(itids);
1059 (void) rpmtsSetFlags(ts, transFlags);