2 * \file lib/rpminstall.c
7 #include <rpm/rpmcli.h>
8 #include <rpm/rpmtag.h>
9 #include <rpm/rpmlib.h> /* rpmReadPackageFile, vercmp etc */
10 #include <rpm/rpmdb.h>
11 #include <rpm/rpmds.h>
12 #include <rpm/rpmts.h>
13 #include <rpm/rpmlog.h>
14 #include <rpm/rpmfileutil.h>
17 #include "lib/manifest.h"
20 int rpmcliPackagesTotal = 0;
21 int rpmcliHashesCurrent = 0;
22 int rpmcliHashesTotal = 0;
23 int rpmcliProgressCurrent = 0;
24 int rpmcliProgressTotal = 0;
27 * Print a CLI progress bar.
28 * @todo Unsnarl isatty(STDOUT_FILENO) from the control flow.
29 * @param amount current
32 static void printHash(const rpm_off_t amount, const rpm_off_t total)
36 rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
38 if (rpmcliHashesCurrent != rpmcliHashesTotal) {
39 float pct = (total ? (((float) amount) / total) : 1.0);
40 hashesNeeded = (rpmcliHashesTotal * pct) + 0.5;
41 while (hashesNeeded > rpmcliHashesCurrent) {
42 if (isatty (STDOUT_FILENO)) {
44 for (i = 0; i < rpmcliHashesCurrent; i++)
46 for (; i < rpmcliHashesTotal; i++)
48 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
49 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
50 (void) putchar ('\b');
54 rpmcliHashesCurrent++;
56 (void) fflush(stdout);
58 if (rpmcliHashesCurrent == rpmcliHashesTotal) {
60 rpmcliProgressCurrent++;
61 if (isatty(STDOUT_FILENO)) {
62 for (i = 1; i < rpmcliHashesCurrent; i++)
64 pct = (rpmcliProgressTotal
65 ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
67 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
69 fprintf(stdout, "\n");
71 (void) fflush(stdout);
75 void * rpmShowProgress(const void * arg,
76 const rpmCallbackType what,
77 const rpm_off_t amount,
78 const rpm_off_t total,
82 Header h = (Header) arg;
84 int flags = (int) ((long)data);
86 const char * filename = (const char *)key;
87 static FD_t fd = NULL;
91 case RPMCALLBACK_INST_OPEN_FILE:
92 if (filename == NULL || filename[0] == '\0')
94 fd = Fopen(filename, "r.ufdio");
95 /* FIX: still necessary? */
96 if (fd == NULL || Ferror(fd)) {
97 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
104 fd = fdLink(fd, RPMDBG_M("persist (showProgress)"));
108 case RPMCALLBACK_INST_CLOSE_FILE:
109 /* FIX: still necessary? */
110 fd = fdFree(fd, RPMDBG_M("persist (showProgress)"));
117 case RPMCALLBACK_INST_START:
118 rpmcliHashesCurrent = 0;
119 if (h == NULL || !(flags & INSTALL_LABEL))
121 /* @todo Remove headerSprintf() on a progress callback. */
122 if (flags & INSTALL_HASH) {
123 s = headerSprintf(h, "%{NAME}",
124 rpmTagTable, rpmHeaderFormats, NULL);
125 if (isatty (STDOUT_FILENO))
126 fprintf(stdout, "%4d:%-23.23s", rpmcliProgressCurrent + 1, s);
128 fprintf(stdout, "%-28.28s", s);
129 (void) fflush(stdout);
132 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
133 rpmTagTable, rpmHeaderFormats, NULL);
134 fprintf(stdout, "%s\n", s);
135 (void) fflush(stdout);
140 case RPMCALLBACK_TRANS_PROGRESS:
141 case RPMCALLBACK_INST_PROGRESS:
142 if (flags & INSTALL_PERCENT)
143 fprintf(stdout, "%%%% %f\n", (double) (total
144 ? ((((float) amount) / total) * 100)
146 else if (flags & INSTALL_HASH)
147 printHash(amount, total);
148 (void) fflush(stdout);
151 case RPMCALLBACK_TRANS_START:
152 rpmcliHashesCurrent = 0;
153 rpmcliProgressTotal = 1;
154 rpmcliProgressCurrent = 0;
155 if (!(flags & INSTALL_LABEL))
157 if (flags & INSTALL_HASH)
158 fprintf(stdout, "%-28s", _("Preparing..."));
160 fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
161 (void) fflush(stdout);
164 case RPMCALLBACK_TRANS_STOP:
165 if (flags & INSTALL_HASH)
166 printHash(1, 1); /* Fixes "preparing..." progress bar */
167 rpmcliProgressTotal = rpmcliPackagesTotal;
168 rpmcliProgressCurrent = 0;
171 case RPMCALLBACK_REPACKAGE_START:
172 rpmcliHashesCurrent = 0;
173 rpmcliProgressTotal = total;
174 rpmcliProgressCurrent = 0;
175 if (!(flags & INSTALL_LABEL))
177 if (flags & INSTALL_HASH)
178 fprintf(stdout, "%-28s\n", _("Repackaging..."));
180 fprintf(stdout, "%s\n", _("Repackaging erased files..."));
181 (void) fflush(stdout);
184 case RPMCALLBACK_REPACKAGE_PROGRESS:
185 if (amount && (flags & INSTALL_HASH))
186 printHash(1, 1); /* Fixes "preparing..." progress bar */
189 case RPMCALLBACK_REPACKAGE_STOP:
190 rpmcliProgressTotal = total;
191 rpmcliProgressCurrent = total;
192 if (flags & INSTALL_HASH)
193 printHash(1, 1); /* Fixes "preparing..." progress bar */
194 rpmcliProgressTotal = rpmcliPackagesTotal;
195 rpmcliProgressCurrent = 0;
196 if (!(flags & INSTALL_LABEL))
198 if (flags & INSTALL_HASH)
199 fprintf(stdout, "%-28s\n", _("Upgrading..."));
201 fprintf(stdout, "%s\n", _("Upgrading packages..."));
202 (void) fflush(stdout);
205 case RPMCALLBACK_UNINST_PROGRESS:
207 case RPMCALLBACK_UNINST_START:
209 case RPMCALLBACK_UNINST_STOP:
211 case RPMCALLBACK_UNPACK_ERROR:
213 case RPMCALLBACK_CPIO_ERROR:
215 case RPMCALLBACK_SCRIPT_ERROR:
217 case RPMCALLBACK_UNKNOWN:
225 typedef const char * str_t;
243 rpmRelocation * relocations;
247 /** @todo Generalize --freshen policies. */
248 int rpmInstall(rpmts ts,
249 struct rpmInstallArguments_s * ia,
250 const char ** fileArgv)
252 struct rpmEIU * eiu = memset(alloca(sizeof(*eiu)), 0, sizeof(*eiu));
254 rpmprobFilterFlags probFilter;
255 rpmRelocation * relocations;
256 char * fileURL = NULL;
259 rpmVSFlags vsflags, ovsflags, tvsflags;
265 if (fileArgv == NULL) goto exit;
267 rpmcliPackagesTotal = 0;
269 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
270 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
272 (void) rpmtsSetFlags(ts, ia->transFlags);
274 probFilter = ia->probFilter;
275 relocations = ia->relocations;
277 if (ia->installInterfaceFlags & INSTALL_UPGRADE)
278 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
280 vsflags = rpmExpandNumeric("%{?_vsflags_install}");
281 if (ia->qva_flags & VERIFY_DIGEST)
282 vsflags |= _RPMVSF_NODIGESTS;
283 if (ia->qva_flags & VERIFY_SIGNATURE)
284 vsflags |= _RPMVSF_NOSIGNATURES;
285 if (ia->qva_flags & VERIFY_HDRCHK)
286 vsflags |= RPMVSF_NOHDRCHK;
287 ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
290 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
291 xx = rpmtsSetNotifyCallback(ts,
292 rpmShowProgress, (void *) ((long)notifyFlags));
295 if ((eiu->relocations = relocations) != NULL) {
296 while (eiu->relocations->oldPath)
298 if (eiu->relocations->newPath == NULL)
299 eiu->relocations = NULL;
302 /* Build fully globbed list of arguments in argv[argc]. */
303 for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
305 av = _free(av); ac = 0;
306 fn = rpmEscapeSpaces(*eiu->fnp);
307 rc = rpmGlob(fn, &ac, &av);
310 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
314 eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
315 memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
317 eiu->argv[eiu->argc] = NULL;
319 av = _free(av); ac = 0;
322 /* Allocate sufficient storage for next set of args. */
323 if (eiu->pkgx >= eiu->numPkgs) {
324 eiu->numPkgs = eiu->pkgx + eiu->argc;
325 eiu->pkgURL = xrealloc(eiu->pkgURL,
326 (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
327 memset(eiu->pkgURL + eiu->pkgx, 0,
328 ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
329 eiu->pkgState = xrealloc(eiu->pkgState,
330 (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
331 memset(eiu->pkgState + eiu->pkgx, 0,
332 ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
335 /* Retrieve next set of args, cache on local storage. */
336 for (i = 0; i < eiu->argc; i++) {
337 fileURL = _free(fileURL);
338 fileURL = eiu->argv[i];
342 if (fileURL[0] == '=') {
343 rpmds this = rpmdsSingle(RPMTAG_REQUIRENAME, fileURL+1, NULL, 0);
345 xx = rpmtsSolve(ts, this, NULL);
346 if (ts->suggests && ts->nsuggests > 0) {
347 fileURL = _free(fileURL);
348 fileURL = ts->suggests[0];
349 ts->suggests[0] = NULL;
350 while (ts->nsuggests-- > 0) {
351 if (ts->suggests[ts->nsuggests] == NULL)
353 ts->suggests[ts->nsuggests] = _free(ts->suggests[ts->nsuggests]);
355 ts->suggests = _free(ts->suggests);
356 rpmlog(RPMLOG_DEBUG, _("Adding goal: %s\n"), fileURL);
357 eiu->pkgURL[eiu->pkgx] = fileURL;
361 this = rpmdsFree(this);
365 switch (urlIsURL(fileURL)) {
372 fprintf(stdout, _("Retrieving %s\n"), fileURL);
375 const char * rootDir = rpmtsRootDir(ts);
376 if (!(rootDir && * rootDir))
378 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
379 #if defined(HAVE_MKSTEMP)
380 (void) close(mkstemp(tfnbuf));
382 (void) mktemp(tfnbuf);
384 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
387 /* XXX undefined %{name}/%{version}/%{release} here */
388 /* XXX %{_tmpdir} does not exist */
389 rpmlog(RPMLOG_DEBUG, _(" ... as %s\n"), tfn);
390 rc = urlGetFile(fileURL, tfn);
393 _("skipping %s - transfer failed - %s\n"),
394 fileURL, ftpStrerror(rc));
396 eiu->pkgURL[eiu->pkgx] = NULL;
400 eiu->pkgState[eiu->pkgx] = 1;
401 eiu->pkgURL[eiu->pkgx] = tfn;
405 case URL_IS_DASH: /* WRONG WRONG WRONG */
406 case URL_IS_HKP: /* WRONG WRONG WRONG */
408 eiu->pkgURL[eiu->pkgx] = fileURL;
414 fileURL = _free(fileURL);
416 if (eiu->numFailed) goto exit;
418 /* Continue processing file arguments, building transaction set. */
419 for (eiu->fnp = (const char**) eiu->pkgURL+eiu->prevx;
421 eiu->fnp++, eiu->prevx++)
423 const char * fileName;
425 rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp);
426 (void) urlPath(*eiu->fnp, &fileName);
428 /* Try to read the header from a package file. */
429 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
430 if (eiu->fd == NULL || Ferror(eiu->fd)) {
431 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
433 if (eiu->fd != NULL) {
434 xx = Fclose(eiu->fd);
437 eiu->numFailed++; *eiu->fnp = NULL;
441 /* Read the header, verifying signatures (if present). */
442 tvsflags = rpmtsSetVSFlags(ts, vsflags);
443 eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
444 tvsflags = rpmtsSetVSFlags(ts, tvsflags);
445 xx = Fclose(eiu->fd);
448 switch (eiu->rpmrc) {
450 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp);
451 eiu->numFailed++; *eiu->fnp = NULL;
457 case RPMRC_NOTTRUSTED:
464 eiu->isSource = headerIsSource(eiu->h);
467 rpmlog(RPMLOG_DEBUG, _("\tadded source package [%d]\n"),
469 eiu->sourceURL = xrealloc(eiu->sourceURL,
470 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
471 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
474 eiu->sourceURL[eiu->numSRPMS] = NULL;
478 if (eiu->relocations) {
483 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
484 (rpm_data_t *) &paths, &c) && (c == 1))
486 eiu->relocations->oldPath = xstrdup(paths[0]);
487 paths = headerFreeData(paths, pft);
490 xx = headerNVR(eiu->h, &name, NULL, NULL);
492 _("package %s is not relocatable\n"), name);
498 /* On --freshen, verify package is installed and newer */
499 if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
500 rpmdbMatchIterator mi;
505 xx = headerNVR(eiu->h, &name, NULL, NULL);
506 mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
507 count = rpmdbGetIteratorCount(mi);
508 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
509 if (rpmVersionCompare(oldH, eiu->h) < 0)
511 /* same or newer package already installed */
515 mi = rpmdbFreeIterator(mi);
517 eiu->h = headerFree(eiu->h);
520 /* Package is newer than those currently installed. */
523 rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
524 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
527 /* XXX reference held by transaction set */
528 eiu->h = headerFree(eiu->h);
529 if (eiu->relocations)
530 eiu->relocations->oldPath = _constfree(eiu->relocations->oldPath);
534 rpmlog(RPMLOG_DEBUG, _("\tadded binary package [%d]\n"),
539 _("error reading from file %s\n"), *eiu->fnp);
545 _("file %s requires a newer version of RPM\n"),
560 /* Try to read a package manifest. */
561 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
562 if (eiu->fd == NULL || Ferror(eiu->fd)) {
563 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
565 if (eiu->fd != NULL) {
566 xx = Fclose(eiu->fd);
569 eiu->numFailed++; *eiu->fnp = NULL;
573 /* Read list of packages from manifest. */
574 /* FIX: *eiu->argv can be NULL */
575 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
577 rpmlog(RPMLOG_NOTICE, _("%s: not an rpm package (or package manifest): %s\n"),
578 *eiu->fnp, Fstrerror(eiu->fd));
579 xx = Fclose(eiu->fd);
582 /* If successful, restart the query loop. */
583 if (rc == RPMRC_OK) {
588 eiu->numFailed++; *eiu->fnp = NULL;
592 rpmlog(RPMLOG_DEBUG, _("found %d source and %d binary packages\n"),
593 eiu->numSRPMS, eiu->numRPMS);
595 if (eiu->numFailed) goto exit;
597 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
599 if (rpmtsCheck(ts)) {
600 eiu->numFailed = eiu->numPkgs;
604 ps = rpmtsProblems(ts);
605 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
606 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
607 rpmpsPrint(NULL, ps);
608 eiu->numFailed = eiu->numPkgs;
611 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST))
612 rpmtsPrintSuggests(ts);
618 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
619 if (rpmtsOrder(ts)) {
620 eiu->numFailed = eiu->numPkgs;
625 if (eiu->numRPMS && !stopInstall) {
627 rpmcliPackagesTotal += eiu->numSRPMS;
629 rpmlog(RPMLOG_DEBUG, _("installing binary packages\n"));
631 /* Drop added/available package indices and dependency sets. */
634 rc = rpmtsRun(ts, NULL, probFilter);
635 ps = rpmtsProblems(ts);
638 eiu->numFailed += eiu->numRPMS;
640 eiu->numFailed += rc;
641 if (rpmpsNumProblems(ps) > 0)
642 rpmpsPrint(stderr, ps);
647 if (eiu->numSRPMS && !stopInstall) {
648 if (eiu->sourceURL != NULL)
649 for (i = 0; i < eiu->numSRPMS; i++) {
651 if (eiu->sourceURL[i] == NULL) continue;
652 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
653 if (eiu->fd == NULL || Ferror(eiu->fd)) {
654 rpmlog(RPMLOG_ERR, _("cannot open file %s: %s\n"),
655 eiu->sourceURL[i], Fstrerror(eiu->fd));
656 if (eiu->fd != NULL) {
657 xx = Fclose(eiu->fd);
663 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
664 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
665 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
668 xx = Fclose(eiu->fd);
674 if (eiu->pkgURL != NULL)
675 for (i = 0; i < eiu->numPkgs; i++) {
676 if (eiu->pkgURL[i] == NULL) continue;
677 if (eiu->pkgState[i] == 1)
678 (void) unlink(eiu->pkgURL[i]);
679 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
681 eiu->pkgState = _free(eiu->pkgState);
682 eiu->pkgURL = _free(eiu->pkgURL);
683 eiu->argv = _free(eiu->argv);
687 return eiu->numFailed;
690 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
696 int stopUninstall = 0;
698 rpmVSFlags vsflags, ovsflags;
701 if (argv == NULL) return 0;
703 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
704 if (ia->qva_flags & VERIFY_DIGEST)
705 vsflags |= _RPMVSF_NODIGESTS;
706 if (ia->qva_flags & VERIFY_SIGNATURE)
707 vsflags |= _RPMVSF_NOSIGNATURES;
708 if (ia->qva_flags & VERIFY_HDRCHK)
709 vsflags |= RPMVSF_NOHDRCHK;
710 ovsflags = rpmtsSetVSFlags(ts, vsflags);
712 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
713 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
715 /* XXX suggest mechanism only meaningful when installing */
716 ia->transFlags |= RPMTRANS_FLAG_NOSUGGEST;
718 (void) rpmtsSetFlags(ts, ia->transFlags);
720 #ifdef NOTYET /* XXX no callbacks on erase yet */
721 { int notifyFlags, xx;
722 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
723 xx = rpmtsSetNotifyCallback(ts,
724 rpmShowProgress, (void *) ((long)notifyFlags));
728 for (arg = argv; *arg; arg++) {
729 rpmdbMatchIterator mi;
731 /* XXX HACK to get rpmdbFindByLabel out of the API */
732 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
734 rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
737 Header h; /* XXX iterator owns the reference */
739 while ((h = rpmdbNextIterator(mi)) != NULL) {
740 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
742 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
743 rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
749 (void) rpmtsAddEraseElement(ts, h, recOffset);
754 mi = rpmdbFreeIterator(mi);
757 if (numFailed) goto exit;
759 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
761 if (rpmtsCheck(ts)) {
762 numFailed = numPackages;
766 ps = rpmtsProblems(ts);
767 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
768 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
769 rpmpsPrint(NULL, ps);
770 numFailed += numPackages;
776 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
777 if (rpmtsOrder(ts)) {
778 numFailed += numPackages;
783 if (numPackages && !stopUninstall) {
784 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
786 /* Drop added/available package indices and dependency sets. */
789 numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
790 ps = rpmtsProblems(ts);
791 if (rpmpsNumProblems(ps) > 0)
792 rpmpsPrint(NULL, ps);
793 numFailed += numPackages;
804 int rpmInstallSource(rpmts ts, const char * arg,
805 char ** specFilePtr, char ** cookie)
811 fd = Fopen(arg, "r.ufdio");
812 if (fd == NULL || Ferror(fd)) {
813 rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
814 if (fd != NULL) (void) Fclose(fd);
819 fprintf(stdout, _("Installing %s\n"), arg);
822 rpmVSFlags ovsflags =
823 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
824 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
825 rc = (rpmrc == RPMRC_OK ? 0 : 1);
826 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
829 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
830 if (specFilePtr && *specFilePtr)
831 *specFilePtr = _free(*specFilePtr);
832 if (cookie && *cookie)
833 *cookie = _free(*cookie);
841 /** @todo Transaction handling, more, needs work. */
842 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
844 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
845 unsigned thistid = 0xffffffff;
855 int vsflags, ovsflags;
859 int _unsafe_rollbacks = 0;
860 rpmtransFlags transFlags = ia->transFlags;
862 if (argv != NULL && *argv != NULL) {
867 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
869 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
870 if (ia->qva_flags & VERIFY_DIGEST)
871 vsflags |= _RPMVSF_NODIGESTS;
872 if (ia->qva_flags & VERIFY_SIGNATURE)
873 vsflags |= _RPMVSF_NOSIGNATURES;
874 if (ia->qva_flags & VERIFY_HDRCHK)
875 vsflags |= RPMVSF_NOHDRCHK;
876 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
877 ovsflags = rpmtsSetVSFlags(ts, vsflags);
879 (void) rpmtsSetFlags(ts, transFlags);
881 /* Make the transaction a rollback transaction. In a rollback
882 * a best effort is what we want
884 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
886 itids = IDTXload(ts, RPMTAG_INSTALLTID);
895 { char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
896 if (globstr == NULL || *globstr == '%') {
897 globstr = _free(globstr);
901 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
910 globstr = _free(globstr);
913 { int notifyFlags, xx;
914 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
915 xx = rpmtsSetNotifyCallback(ts,
916 rpmShowProgress, (void *) ((long)notifyFlags));
919 /* Run transactions until rollback goal is achieved. */
923 rpmcliPackagesTotal = 0;
926 ia->installInterfaceFlags &= ~ifmask;
928 /* Find larger of the remaining install/erase transaction id's. */
930 if (ip != NULL && ip->val.u32 > thistid)
931 thistid = ip->val.u32;
932 if (rp != NULL && rp->val.u32 > thistid)
933 thistid = rp->val.u32;
935 /* If we've achieved the rollback goal, then we're done. */
936 if (thistid == 0 || thistid < ia->rbtid)
939 /* If we've reached the (configured) rollback goal, then we're done. */
940 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
944 (void) rpmtsSetFlags(ts, transFlags);
946 /* Install the previously erased packages for this transaction. */
947 while (rp != NULL && rp->val.u32 == thistid) {
949 rpmlog(RPMLOG_DEBUG, "\t+++ install %s\n",
950 (rp->key ? rp->key : "???"));
952 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
958 rpmcliPackagesTotal++;
959 if (!(ia->installInterfaceFlags & ifmask))
960 ia->installInterfaceFlags |= INSTALL_UPGRADE;
963 rp->h = headerFree(rp->h);
972 /* Erase the previously installed packages for this transaction. */
973 while (ip != NULL && ip->val.u32 == thistid) {
976 "\t--- erase h#%u\n", ip->instance);
978 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
984 if (_unsafe_rollbacks)
985 rpmcliPackagesTotal++;
987 if (!(ia->installInterfaceFlags & ifmask)) {
988 ia->installInterfaceFlags |= INSTALL_ERASE;
989 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1002 /* Anything to do? */
1003 if (rpmcliPackagesTotal <= 0)
1006 tid = (time_t)thistid;
1007 rpmlog(RPMLOG_NOTICE,
1008 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1009 numAdded, numRemoved, ctime(&tid), tid);
1011 rc = rpmtsCheck(ts);
1012 ps = rpmtsProblems(ts);
1013 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1014 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
1015 rpmpsPrint(NULL, ps);
1021 rc = rpmtsOrder(ts);
1025 /* Drop added/available package indices and dependency sets. */
1028 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1029 ps = rpmtsProblems(ts);
1030 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1031 rpmpsPrint(stderr, ps);
1036 /* Clean up after successful rollback. */
1037 if (rtids && !rpmIsDebug()) {
1039 rpmlog(RPMLOG_NOTICE, _("Cleaning up repackaged packages:\n"));
1041 for (i = 0; i < rtids->nidt; i++) {
1042 IDT rrp = rtids->idt + i;
1043 if (rrp->val.u32 != thistid)
1045 if (rrp->key) { /* XXX can't happen */
1046 rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
1047 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1056 rtids = IDTXfree(rtids);
1057 itids = IDTXfree(itids);
1060 (void) rpmtsSetFlags(ts, transFlags);