2 * \file lib/rpminstall.c
7 #include <rpm/rpmcli.h>
9 #include <rpm/rpmtag.h>
10 #include <rpm/rpmlib.h> /* rpmReadPackageFile, vercmp etc */
11 #include <rpm/rpmdb.h>
12 #include <rpm/rpmds.h>
13 #include <rpm/rpmts.h>
14 #include <rpm/rpmlog.h>
15 #include <rpm/rpmfileutil.h>
18 #include "lib/manifest.h"
21 int rpmcliPackagesTotal = 0;
22 int rpmcliHashesCurrent = 0;
23 int rpmcliHashesTotal = 0;
24 int rpmcliProgressCurrent = 0;
25 int rpmcliProgressTotal = 0;
28 * Print a CLI progress bar.
29 * @todo Unsnarl isatty(STDOUT_FILENO) from the control flow.
30 * @param amount current
33 static void printHash(const unsigned long amount, const unsigned long total)
37 rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
39 if (rpmcliHashesCurrent != rpmcliHashesTotal) {
40 float pct = (total ? (((float) amount) / total) : 1.0);
41 hashesNeeded = (rpmcliHashesTotal * pct) + 0.5;
42 while (hashesNeeded > rpmcliHashesCurrent) {
43 if (isatty (STDOUT_FILENO)) {
45 for (i = 0; i < rpmcliHashesCurrent; i++)
47 for (; i < rpmcliHashesTotal; i++)
49 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
50 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
51 (void) putchar ('\b');
55 rpmcliHashesCurrent++;
57 (void) fflush(stdout);
59 if (rpmcliHashesCurrent == rpmcliHashesTotal) {
61 rpmcliProgressCurrent++;
62 if (isatty(STDOUT_FILENO)) {
63 for (i = 1; i < rpmcliHashesCurrent; i++)
65 pct = (rpmcliProgressTotal
66 ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
68 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
70 fprintf(stdout, "\n");
72 (void) fflush(stdout);
76 void * rpmShowProgress(const void * arg,
77 const rpmCallbackType what,
78 const unsigned long amount,
79 const unsigned long total,
83 Header h = (Header) arg;
85 int flags = (int) ((long)data);
87 const char * filename = (const char *)key;
88 static FD_t fd = NULL;
92 case RPMCALLBACK_INST_OPEN_FILE:
93 if (filename == NULL || filename[0] == '\0')
95 fd = Fopen(filename, "r.ufdio");
96 /* FIX: still necessary? */
97 if (fd == NULL || Ferror(fd)) {
98 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), filename,
105 fd = fdLink(fd, RPMDBG_M("persist (showProgress)"));
109 case RPMCALLBACK_INST_CLOSE_FILE:
110 /* FIX: still necessary? */
111 fd = fdFree(fd, RPMDBG_M("persist (showProgress)"));
118 case RPMCALLBACK_INST_START:
119 rpmcliHashesCurrent = 0;
120 if (h == NULL || !(flags & INSTALL_LABEL))
122 /* @todo Remove headerSprintf() on a progress callback. */
123 if (flags & INSTALL_HASH) {
124 s = headerSprintf(h, "%{NAME}",
125 rpmTagTable, rpmHeaderFormats, NULL);
126 if (isatty (STDOUT_FILENO))
127 fprintf(stdout, "%4d:%-23.23s", rpmcliProgressCurrent + 1, s);
129 fprintf(stdout, "%-28.28s", s);
130 (void) fflush(stdout);
133 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
134 rpmTagTable, rpmHeaderFormats, NULL);
135 fprintf(stdout, "%s\n", s);
136 (void) fflush(stdout);
141 case RPMCALLBACK_TRANS_PROGRESS:
142 case RPMCALLBACK_INST_PROGRESS:
143 if (flags & INSTALL_PERCENT)
144 fprintf(stdout, "%%%% %f\n", (double) (total
145 ? ((((float) amount) / total) * 100)
147 else if (flags & INSTALL_HASH)
148 printHash(amount, total);
149 (void) fflush(stdout);
152 case RPMCALLBACK_TRANS_START:
153 rpmcliHashesCurrent = 0;
154 rpmcliProgressTotal = 1;
155 rpmcliProgressCurrent = 0;
156 if (!(flags & INSTALL_LABEL))
158 if (flags & INSTALL_HASH)
159 fprintf(stdout, "%-28s", _("Preparing..."));
161 fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
162 (void) fflush(stdout);
165 case RPMCALLBACK_TRANS_STOP:
166 if (flags & INSTALL_HASH)
167 printHash(1, 1); /* Fixes "preparing..." progress bar */
168 rpmcliProgressTotal = rpmcliPackagesTotal;
169 rpmcliProgressCurrent = 0;
172 case RPMCALLBACK_REPACKAGE_START:
173 rpmcliHashesCurrent = 0;
174 rpmcliProgressTotal = total;
175 rpmcliProgressCurrent = 0;
176 if (!(flags & INSTALL_LABEL))
178 if (flags & INSTALL_HASH)
179 fprintf(stdout, "%-28s\n", _("Repackaging..."));
181 fprintf(stdout, "%s\n", _("Repackaging erased files..."));
182 (void) fflush(stdout);
185 case RPMCALLBACK_REPACKAGE_PROGRESS:
186 if (amount && (flags & INSTALL_HASH))
187 printHash(1, 1); /* Fixes "preparing..." progress bar */
190 case RPMCALLBACK_REPACKAGE_STOP:
191 rpmcliProgressTotal = total;
192 rpmcliProgressCurrent = total;
193 if (flags & INSTALL_HASH)
194 printHash(1, 1); /* Fixes "preparing..." progress bar */
195 rpmcliProgressTotal = rpmcliPackagesTotal;
196 rpmcliProgressCurrent = 0;
197 if (!(flags & INSTALL_LABEL))
199 if (flags & INSTALL_HASH)
200 fprintf(stdout, "%-28s\n", _("Upgrading..."));
202 fprintf(stdout, "%s\n", _("Upgrading packages..."));
203 (void) fflush(stdout);
206 case RPMCALLBACK_UNINST_PROGRESS:
208 case RPMCALLBACK_UNINST_START:
210 case RPMCALLBACK_UNINST_STOP:
212 case RPMCALLBACK_UNPACK_ERROR:
214 case RPMCALLBACK_CPIO_ERROR:
216 case RPMCALLBACK_SCRIPT_ERROR:
218 case RPMCALLBACK_UNKNOWN:
226 typedef const char * str_t;
244 rpmRelocation * relocations;
248 /** @todo Generalize --freshen policies. */
249 int rpmInstall(rpmts ts,
250 struct rpmInstallArguments_s * ia,
251 const char ** fileArgv)
253 struct rpmEIU * eiu = memset(alloca(sizeof(*eiu)), 0, sizeof(*eiu));
255 rpmprobFilterFlags probFilter;
256 rpmRelocation * relocations;
257 char * fileURL = NULL;
260 rpmVSFlags vsflags, ovsflags, tvsflags;
266 if (fileArgv == NULL) goto exit;
268 rpmcliPackagesTotal = 0;
270 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
271 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
273 (void) rpmtsSetFlags(ts, ia->transFlags);
275 probFilter = ia->probFilter;
276 relocations = ia->relocations;
278 if (ia->installInterfaceFlags & INSTALL_UPGRADE)
279 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
281 vsflags = rpmExpandNumeric("%{?_vsflags_install}");
282 if (ia->qva_flags & VERIFY_DIGEST)
283 vsflags |= _RPMVSF_NODIGESTS;
284 if (ia->qva_flags & VERIFY_SIGNATURE)
285 vsflags |= _RPMVSF_NOSIGNATURES;
286 if (ia->qva_flags & VERIFY_HDRCHK)
287 vsflags |= RPMVSF_NOHDRCHK;
288 ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
291 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
292 xx = rpmtsSetNotifyCallback(ts,
293 rpmShowProgress, (void *) ((long)notifyFlags));
296 if ((eiu->relocations = relocations) != NULL) {
297 while (eiu->relocations->oldPath)
299 if (eiu->relocations->newPath == NULL)
300 eiu->relocations = NULL;
303 /* Build fully globbed list of arguments in argv[argc]. */
304 for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
306 av = _free(av); ac = 0;
307 fn = rpmEscapeSpaces(*eiu->fnp);
308 rc = rpmGlob(fn, &ac, &av);
311 rpmlog(RPMLOG_ERR, _("File not found by glob: %s\n"), *eiu->fnp);
315 eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
316 memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
318 eiu->argv[eiu->argc] = NULL;
320 av = _free(av); ac = 0;
323 /* Allocate sufficient storage for next set of args. */
324 if (eiu->pkgx >= eiu->numPkgs) {
325 eiu->numPkgs = eiu->pkgx + eiu->argc;
326 eiu->pkgURL = xrealloc(eiu->pkgURL,
327 (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
328 memset(eiu->pkgURL + eiu->pkgx, 0,
329 ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
330 eiu->pkgState = xrealloc(eiu->pkgState,
331 (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
332 memset(eiu->pkgState + eiu->pkgx, 0,
333 ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
336 /* Retrieve next set of args, cache on local storage. */
337 for (i = 0; i < eiu->argc; i++) {
338 fileURL = _free(fileURL);
339 fileURL = eiu->argv[i];
343 if (fileURL[0] == '=') {
344 rpmds this = rpmdsSingle(RPMTAG_REQUIRENAME, fileURL+1, NULL, 0);
346 xx = rpmtsSolve(ts, this, NULL);
347 if (ts->suggests && ts->nsuggests > 0) {
348 fileURL = _free(fileURL);
349 fileURL = ts->suggests[0];
350 ts->suggests[0] = NULL;
351 while (ts->nsuggests-- > 0) {
352 if (ts->suggests[ts->nsuggests] == NULL)
354 ts->suggests[ts->nsuggests] = _free(ts->suggests[ts->nsuggests]);
356 ts->suggests = _free(ts->suggests);
357 rpmlog(RPMLOG_DEBUG, _("Adding goal: %s\n"), fileURL);
358 eiu->pkgURL[eiu->pkgx] = fileURL;
362 this = rpmdsFree(this);
366 switch (urlIsURL(fileURL)) {
373 fprintf(stdout, _("Retrieving %s\n"), fileURL);
376 const char * rootDir = rpmtsRootDir(ts);
377 if (!(rootDir && * rootDir))
379 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
380 #if defined(HAVE_MKSTEMP)
381 (void) close(mkstemp(tfnbuf));
383 (void) mktemp(tfnbuf);
385 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
388 /* XXX undefined %{name}/%{version}/%{release} here */
389 /* XXX %{_tmpdir} does not exist */
390 rpmlog(RPMLOG_DEBUG, _(" ... as %s\n"), tfn);
391 rc = urlGetFile(fileURL, tfn);
394 _("skipping %s - transfer failed - %s\n"),
395 fileURL, ftpStrerror(rc));
397 eiu->pkgURL[eiu->pkgx] = NULL;
401 eiu->pkgState[eiu->pkgx] = 1;
402 eiu->pkgURL[eiu->pkgx] = tfn;
406 case URL_IS_DASH: /* WRONG WRONG WRONG */
407 case URL_IS_HKP: /* WRONG WRONG WRONG */
409 eiu->pkgURL[eiu->pkgx] = fileURL;
415 fileURL = _free(fileURL);
417 if (eiu->numFailed) goto exit;
419 /* Continue processing file arguments, building transaction set. */
420 for (eiu->fnp = (const char**) eiu->pkgURL+eiu->prevx;
422 eiu->fnp++, eiu->prevx++)
424 const char * fileName;
426 rpmlog(RPMLOG_DEBUG, "============== %s\n", *eiu->fnp);
427 (void) urlPath(*eiu->fnp, &fileName);
429 /* Try to read the header from a package file. */
430 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
431 if (eiu->fd == NULL || Ferror(eiu->fd)) {
432 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
434 if (eiu->fd != NULL) {
435 xx = Fclose(eiu->fd);
438 eiu->numFailed++; *eiu->fnp = NULL;
442 /* Read the header, verifying signatures (if present). */
443 tvsflags = rpmtsSetVSFlags(ts, vsflags);
444 eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
445 tvsflags = rpmtsSetVSFlags(ts, tvsflags);
446 xx = Fclose(eiu->fd);
449 switch (eiu->rpmrc) {
451 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), *eiu->fnp);
452 eiu->numFailed++; *eiu->fnp = NULL;
458 case RPMRC_NOTTRUSTED:
465 eiu->isSource = headerIsSource(eiu->h);
468 rpmlog(RPMLOG_DEBUG, _("\tadded source package [%d]\n"),
470 eiu->sourceURL = xrealloc(eiu->sourceURL,
471 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
472 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
475 eiu->sourceURL[eiu->numSRPMS] = NULL;
479 if (eiu->relocations) {
484 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
485 (rpm_data_t *) &paths, &c) && (c == 1))
487 eiu->relocations->oldPath = xstrdup(paths[0]);
488 paths = headerFreeData(paths, pft);
491 xx = headerNVR(eiu->h, &name, NULL, NULL);
493 _("package %s is not relocatable\n"), name);
499 /* On --freshen, verify package is installed and newer */
500 if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
501 rpmdbMatchIterator mi;
506 xx = headerNVR(eiu->h, &name, NULL, NULL);
507 mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
508 count = rpmdbGetIteratorCount(mi);
509 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
510 if (rpmVersionCompare(oldH, eiu->h) < 0)
512 /* same or newer package already installed */
516 mi = rpmdbFreeIterator(mi);
518 eiu->h = headerFree(eiu->h);
521 /* Package is newer than those currently installed. */
524 rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
525 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
528 /* XXX reference held by transaction set */
529 eiu->h = headerFree(eiu->h);
530 if (eiu->relocations)
531 eiu->relocations->oldPath = _constfree(eiu->relocations->oldPath);
535 rpmlog(RPMLOG_DEBUG, _("\tadded binary package [%d]\n"),
540 _("error reading from file %s\n"), *eiu->fnp);
546 _("file %s requires a newer version of RPM\n"),
561 /* Try to read a package manifest. */
562 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
563 if (eiu->fd == NULL || Ferror(eiu->fd)) {
564 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), *eiu->fnp,
566 if (eiu->fd != NULL) {
567 xx = Fclose(eiu->fd);
570 eiu->numFailed++; *eiu->fnp = NULL;
574 /* Read list of packages from manifest. */
575 /* FIX: *eiu->argv can be NULL */
576 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
578 rpmlog(RPMLOG_NOTICE, _("%s: not an rpm package (or package manifest): %s\n"),
579 *eiu->fnp, Fstrerror(eiu->fd));
580 xx = Fclose(eiu->fd);
583 /* If successful, restart the query loop. */
584 if (rc == RPMRC_OK) {
589 eiu->numFailed++; *eiu->fnp = NULL;
593 rpmlog(RPMLOG_DEBUG, _("found %d source and %d binary packages\n"),
594 eiu->numSRPMS, eiu->numRPMS);
596 if (eiu->numFailed) goto exit;
598 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
600 if (rpmtsCheck(ts)) {
601 eiu->numFailed = eiu->numPkgs;
605 ps = rpmtsProblems(ts);
606 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
607 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
608 rpmpsPrint(NULL, ps);
609 eiu->numFailed = eiu->numPkgs;
612 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOSUGGEST))
613 rpmtsPrintSuggests(ts);
619 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
620 if (rpmtsOrder(ts)) {
621 eiu->numFailed = eiu->numPkgs;
626 if (eiu->numRPMS && !stopInstall) {
628 rpmcliPackagesTotal += eiu->numSRPMS;
630 rpmlog(RPMLOG_DEBUG, _("installing binary packages\n"));
632 /* Drop added/available package indices and dependency sets. */
635 rc = rpmtsRun(ts, NULL, probFilter);
636 ps = rpmtsProblems(ts);
639 eiu->numFailed += eiu->numRPMS;
641 eiu->numFailed += rc;
642 if (rpmpsNumProblems(ps) > 0)
643 rpmpsPrint(stderr, ps);
648 if (eiu->numSRPMS && !stopInstall) {
649 if (eiu->sourceURL != NULL)
650 for (i = 0; i < eiu->numSRPMS; i++) {
652 if (eiu->sourceURL[i] == NULL) continue;
653 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
654 if (eiu->fd == NULL || Ferror(eiu->fd)) {
655 rpmlog(RPMLOG_ERR, _("cannot open file %s: %s\n"),
656 eiu->sourceURL[i], Fstrerror(eiu->fd));
657 if (eiu->fd != NULL) {
658 xx = Fclose(eiu->fd);
664 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
665 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
666 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
669 xx = Fclose(eiu->fd);
675 if (eiu->pkgURL != NULL)
676 for (i = 0; i < eiu->numPkgs; i++) {
677 if (eiu->pkgURL[i] == NULL) continue;
678 if (eiu->pkgState[i] == 1)
679 (void) unlink(eiu->pkgURL[i]);
680 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
682 eiu->pkgState = _free(eiu->pkgState);
683 eiu->pkgURL = _free(eiu->pkgURL);
684 eiu->argv = _free(eiu->argv);
688 return eiu->numFailed;
691 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
697 int stopUninstall = 0;
699 rpmVSFlags vsflags, ovsflags;
702 if (argv == NULL) return 0;
704 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
705 if (ia->qva_flags & VERIFY_DIGEST)
706 vsflags |= _RPMVSF_NODIGESTS;
707 if (ia->qva_flags & VERIFY_SIGNATURE)
708 vsflags |= _RPMVSF_NOSIGNATURES;
709 if (ia->qva_flags & VERIFY_HDRCHK)
710 vsflags |= RPMVSF_NOHDRCHK;
711 ovsflags = rpmtsSetVSFlags(ts, vsflags);
713 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
714 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
716 /* XXX suggest mechanism only meaningful when installing */
717 ia->transFlags |= RPMTRANS_FLAG_NOSUGGEST;
719 (void) rpmtsSetFlags(ts, ia->transFlags);
721 #ifdef NOTYET /* XXX no callbacks on erase yet */
722 { int notifyFlags, xx;
723 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
724 xx = rpmtsSetNotifyCallback(ts,
725 rpmShowProgress, (void *) ((long)notifyFlags));
729 for (arg = argv; *arg; arg++) {
730 rpmdbMatchIterator mi;
732 /* XXX HACK to get rpmdbFindByLabel out of the API */
733 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
735 rpmlog(RPMLOG_ERR, _("package %s is not installed\n"), *arg);
738 Header h; /* XXX iterator owns the reference */
740 while ((h = rpmdbNextIterator(mi)) != NULL) {
741 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
743 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
744 rpmlog(RPMLOG_ERR, _("\"%s\" specifies multiple packages\n"),
750 (void) rpmtsAddEraseElement(ts, h, recOffset);
755 mi = rpmdbFreeIterator(mi);
758 if (numFailed) goto exit;
760 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
762 if (rpmtsCheck(ts)) {
763 numFailed = numPackages;
767 ps = rpmtsProblems(ts);
768 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
769 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
770 rpmpsPrint(NULL, ps);
771 numFailed += numPackages;
777 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
778 if (rpmtsOrder(ts)) {
779 numFailed += numPackages;
784 if (numPackages && !stopUninstall) {
785 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
787 /* Drop added/available package indices and dependency sets. */
790 numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
791 ps = rpmtsProblems(ts);
792 if (rpmpsNumProblems(ps) > 0)
793 rpmpsPrint(NULL, ps);
794 numFailed += numPackages;
805 int rpmInstallSource(rpmts ts, const char * arg,
806 char ** specFilePtr, char ** cookie)
812 fd = Fopen(arg, "r.ufdio");
813 if (fd == NULL || Ferror(fd)) {
814 rpmlog(RPMLOG_ERR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
815 if (fd != NULL) (void) Fclose(fd);
820 fprintf(stdout, _("Installing %s\n"), arg);
823 rpmVSFlags ovsflags =
824 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
825 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
826 rc = (rpmrc == RPMRC_OK ? 0 : 1);
827 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
830 rpmlog(RPMLOG_ERR, _("%s cannot be installed\n"), arg);
831 if (specFilePtr && *specFilePtr)
832 *specFilePtr = _free(*specFilePtr);
833 if (cookie && *cookie)
834 *cookie = _free(*cookie);
842 /** @todo Transaction handling, more, needs work. */
843 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
845 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
846 unsigned thistid = 0xffffffff;
856 int vsflags, ovsflags;
860 int _unsafe_rollbacks = 0;
861 rpmtransFlags transFlags = ia->transFlags;
863 if (argv != NULL && *argv != NULL) {
868 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
870 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
871 if (ia->qva_flags & VERIFY_DIGEST)
872 vsflags |= _RPMVSF_NODIGESTS;
873 if (ia->qva_flags & VERIFY_SIGNATURE)
874 vsflags |= _RPMVSF_NOSIGNATURES;
875 if (ia->qva_flags & VERIFY_HDRCHK)
876 vsflags |= RPMVSF_NOHDRCHK;
877 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
878 ovsflags = rpmtsSetVSFlags(ts, vsflags);
880 (void) rpmtsSetFlags(ts, transFlags);
882 /* Make the transaction a rollback transaction. In a rollback
883 * a best effort is what we want
885 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
887 itids = IDTXload(ts, RPMTAG_INSTALLTID);
896 { char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
897 if (globstr == NULL || *globstr == '%') {
898 globstr = _free(globstr);
902 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
911 globstr = _free(globstr);
914 { int notifyFlags, xx;
915 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
916 xx = rpmtsSetNotifyCallback(ts,
917 rpmShowProgress, (void *) ((long)notifyFlags));
920 /* Run transactions until rollback goal is achieved. */
924 rpmcliPackagesTotal = 0;
927 ia->installInterfaceFlags &= ~ifmask;
929 /* Find larger of the remaining install/erase transaction id's. */
931 if (ip != NULL && ip->val.u32 > thistid)
932 thistid = ip->val.u32;
933 if (rp != NULL && rp->val.u32 > thistid)
934 thistid = rp->val.u32;
936 /* If we've achieved the rollback goal, then we're done. */
937 if (thistid == 0 || thistid < ia->rbtid)
940 /* If we've reached the (configured) rollback goal, then we're done. */
941 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
945 (void) rpmtsSetFlags(ts, transFlags);
947 /* Install the previously erased packages for this transaction. */
948 while (rp != NULL && rp->val.u32 == thistid) {
950 rpmlog(RPMLOG_DEBUG, "\t+++ install %s\n",
951 (rp->key ? rp->key : "???"));
953 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
959 rpmcliPackagesTotal++;
960 if (!(ia->installInterfaceFlags & ifmask))
961 ia->installInterfaceFlags |= INSTALL_UPGRADE;
964 rp->h = headerFree(rp->h);
973 /* Erase the previously installed packages for this transaction. */
974 while (ip != NULL && ip->val.u32 == thistid) {
977 "\t--- erase h#%u\n", ip->instance);
979 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
985 if (_unsafe_rollbacks)
986 rpmcliPackagesTotal++;
988 if (!(ia->installInterfaceFlags & ifmask)) {
989 ia->installInterfaceFlags |= INSTALL_ERASE;
990 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1003 /* Anything to do? */
1004 if (rpmcliPackagesTotal <= 0)
1007 tid = (time_t)thistid;
1008 rpmlog(RPMLOG_NOTICE,
1009 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1010 numAdded, numRemoved, ctime(&tid), tid);
1012 rc = rpmtsCheck(ts);
1013 ps = rpmtsProblems(ts);
1014 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1015 rpmlog(RPMLOG_ERR, _("Failed dependencies:\n"));
1016 rpmpsPrint(NULL, ps);
1022 rc = rpmtsOrder(ts);
1026 /* Drop added/available package indices and dependency sets. */
1029 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1030 ps = rpmtsProblems(ts);
1031 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1032 rpmpsPrint(stderr, ps);
1037 /* Clean up after successful rollback. */
1038 if (rtids && !rpmIsDebug()) {
1040 rpmlog(RPMLOG_NOTICE, _("Cleaning up repackaged packages:\n"));
1042 for (i = 0; i < rtids->nidt; i++) {
1043 IDT rrp = rtids->idt + i;
1044 if (rrp->val.u32 != thistid)
1046 if (rrp->key) { /* XXX can't happen */
1047 rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
1048 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1057 rtids = IDTXfree(rtids);
1058 itids = IDTXfree(itids);
1061 (void) rpmtsSetFlags(ts, transFlags);