2 * \file lib/rpminstall.c
12 #include "rpmte.h" /* XXX: rpmts.h needs this for rpmtsScoreEntries */
13 #define _RPMTS_INTERNAL /* ts->goal, ts->dbmode, ts->suggests */
17 #include "misc.h" /* XXX for rpmGlob() */
20 /*@access rpmts @*/ /* XXX ts->goal, ts->dbmode */
25 int rpmcliPackagesTotal = 0;
27 int rpmcliHashesCurrent = 0;
29 int rpmcliHashesTotal = 0;
31 int rpmcliProgressCurrent = 0;
33 int rpmcliProgressTotal = 0;
36 * Print a CLI progress bar.
37 * @todo Unsnarl isatty(STDOUT_FILENO) from the control flow.
38 * @param amount current
41 static void printHash(const unsigned long amount, const unsigned long total)
42 /*@globals rpmcliHashesCurrent, rpmcliHashesTotal,
43 rpmcliProgressCurrent, fileSystem @*/
44 /*@modifies rpmcliHashesCurrent, rpmcliHashesTotal,
45 rpmcliProgressCurrent, fileSystem @*/
49 rpmcliHashesTotal = (isatty (STDOUT_FILENO) ? 44 : 50);
51 if (rpmcliHashesCurrent != rpmcliHashesTotal) {
53 float pct = (total ? (((float) amount) / total) : 1.0);
54 hashesNeeded = (rpmcliHashesTotal * pct) + 0.5;
56 while (hashesNeeded > rpmcliHashesCurrent) {
57 if (isatty (STDOUT_FILENO)) {
59 for (i = 0; i < rpmcliHashesCurrent; i++)
61 for (; i < rpmcliHashesTotal; i++)
63 fprintf(stdout, "(%3d%%)", (int)((100 * pct) + 0.5));
64 for (i = 0; i < (rpmcliHashesTotal + 6); i++)
65 (void) putchar ('\b');
69 rpmcliHashesCurrent++;
71 (void) fflush(stdout);
73 if (rpmcliHashesCurrent == rpmcliHashesTotal) {
75 rpmcliProgressCurrent++;
76 if (isatty(STDOUT_FILENO)) {
77 for (i = 1; i < rpmcliHashesCurrent; i++)
80 pct = (rpmcliProgressTotal
81 ? (((float) rpmcliProgressCurrent) / rpmcliProgressTotal)
84 fprintf(stdout, " [%3d%%]", (int)((100 * pct) + 0.5));
86 fprintf(stdout, "\n");
88 (void) fflush(stdout);
92 void * rpmShowProgress(/*@null@*/ const void * arg,
93 const rpmCallbackType what,
94 const unsigned long amount,
95 const unsigned long total,
96 /*@null@*/ fnpyKey key,
97 /*@null@*/ void * data)
98 /*@globals rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
100 /*@modifies rpmcliHashesCurrent, rpmcliProgressCurrent, rpmcliProgressTotal,
103 /*@-abstract -castexpose @*/
104 Header h = (Header) arg;
105 /*@=abstract =castexpose @*/
107 int flags = (int) ((long)data);
109 /*@-abstract -assignexpose @*/
110 const char * filename = (const char *)key;
111 /*@=abstract =assignexpose @*/
112 static FD_t fd = NULL;
116 case RPMCALLBACK_INST_OPEN_FILE:
118 if (filename == NULL || filename[0] == '\0')
121 fd = Fopen(filename, "r.ufdio");
122 /*@-type@*/ /* FIX: still necessary? */
123 if (fd == NULL || Ferror(fd)) {
124 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), filename,
131 fd = fdLink(fd, "persist (showProgress)");
136 /*@notreached@*/ break;
138 case RPMCALLBACK_INST_CLOSE_FILE:
139 /*@-type@*/ /* FIX: still necessary? */
140 fd = fdFree(fd, "persist (showProgress)");
148 case RPMCALLBACK_INST_START:
149 rpmcliHashesCurrent = 0;
150 if (h == NULL || !(flags & INSTALL_LABEL))
152 /* @todo Remove headerSprintf() on a progress callback. */
153 if (flags & INSTALL_HASH) {
154 s = headerSprintf(h, "%{NAME}",
155 rpmTagTable, rpmHeaderFormats, NULL);
156 if (isatty (STDOUT_FILENO))
157 fprintf(stdout, "%4d:%-23.23s", rpmcliProgressCurrent + 1, s);
159 fprintf(stdout, "%-28.28s", s);
160 (void) fflush(stdout);
163 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
164 rpmTagTable, rpmHeaderFormats, NULL);
165 fprintf(stdout, "%s\n", s);
166 (void) fflush(stdout);
171 case RPMCALLBACK_TRANS_PROGRESS:
172 case RPMCALLBACK_INST_PROGRESS:
174 if (flags & INSTALL_PERCENT)
175 fprintf(stdout, "%%%% %f\n", (double) (total
176 ? ((((float) amount) / total) * 100)
178 else if (flags & INSTALL_HASH)
179 printHash(amount, total);
181 (void) fflush(stdout);
184 case RPMCALLBACK_TRANS_START:
185 rpmcliHashesCurrent = 0;
186 rpmcliProgressTotal = 1;
187 rpmcliProgressCurrent = 0;
188 if (!(flags & INSTALL_LABEL))
190 if (flags & INSTALL_HASH)
191 fprintf(stdout, "%-28s", _("Preparing..."));
193 fprintf(stdout, "%s\n", _("Preparing packages for installation..."));
194 (void) fflush(stdout);
197 case RPMCALLBACK_TRANS_STOP:
198 if (flags & INSTALL_HASH)
199 printHash(1, 1); /* Fixes "preparing..." progress bar */
200 rpmcliProgressTotal = rpmcliPackagesTotal;
201 rpmcliProgressCurrent = 0;
204 case RPMCALLBACK_REPACKAGE_START:
205 rpmcliHashesCurrent = 0;
206 rpmcliProgressTotal = total;
207 rpmcliProgressCurrent = 0;
208 if (!(flags & INSTALL_LABEL))
210 if (flags & INSTALL_HASH)
211 fprintf(stdout, "%-28s\n", _("Repackaging..."));
213 fprintf(stdout, "%s\n", _("Repackaging erased files..."));
214 (void) fflush(stdout);
217 case RPMCALLBACK_REPACKAGE_PROGRESS:
218 if (amount && (flags & INSTALL_HASH))
219 printHash(1, 1); /* Fixes "preparing..." progress bar */
222 case RPMCALLBACK_REPACKAGE_STOP:
223 rpmcliProgressTotal = total;
224 rpmcliProgressCurrent = total;
225 if (flags & INSTALL_HASH)
226 printHash(1, 1); /* Fixes "preparing..." progress bar */
227 rpmcliProgressTotal = rpmcliPackagesTotal;
228 rpmcliProgressCurrent = 0;
229 if (!(flags & INSTALL_LABEL))
231 if (flags & INSTALL_HASH)
232 fprintf(stdout, "%-28s\n", _("Upgrading..."));
234 fprintf(stdout, "%s\n", _("Upgrading packages..."));
235 (void) fflush(stdout);
238 case RPMCALLBACK_UNINST_PROGRESS:
240 case RPMCALLBACK_UNINST_START:
242 case RPMCALLBACK_UNINST_STOP:
244 case RPMCALLBACK_UNPACK_ERROR:
246 case RPMCALLBACK_CPIO_ERROR:
248 case RPMCALLBACK_UNKNOWN:
256 typedef /*@only@*/ /*@null@*/ const char * str_t;
265 /*@dependent@*/ /*@null@*/
273 /*@only@*/ /*@null@*/
277 /*@only@*/ /*@null@*/
280 rpmRelocation * relocations;
284 /** @todo Generalize --freshen policies. */
286 int rpmInstall(rpmts ts,
287 struct rpmInstallArguments_s * ia,
288 const char ** fileArgv)
290 struct rpmEIU * eiu = memset(alloca(sizeof(*eiu)), 0, sizeof(*eiu));
292 rpmprobFilterFlags probFilter;
293 rpmRelocation * relocations;
294 /*@only@*/ /*@null@*/ const char * fileURL = NULL;
296 const char ** av = NULL;
297 rpmVSFlags vsflags, ovsflags, tvsflags;
303 if (fileArgv == NULL) goto exit;
305 ts->goal = TSM_INSTALL;
306 rpmcliPackagesTotal = 0;
308 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
309 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
311 /* Initialize security context patterns (if not already done). */
312 if (!(ia->transFlags & RPMTRANS_FLAG_NOCONTEXTS)) {
313 rpmsx sx = rpmtsREContext(ts);
315 const char *fn = rpmGetPath("%{?_install_file_context_path}", NULL);
316 if (fn != NULL && *fn != '\0') {
318 (void) rpmtsSetREContext(ts, sx);
324 (void) rpmtsSetFlags(ts, ia->transFlags);
326 probFilter = ia->probFilter;
327 relocations = ia->relocations;
329 if (ia->installInterfaceFlags & INSTALL_UPGRADE)
330 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
332 vsflags = rpmExpandNumeric("%{?_vsflags_install}");
333 if (ia->qva_flags & VERIFY_DIGEST)
334 vsflags |= _RPMVSF_NODIGESTS;
335 if (ia->qva_flags & VERIFY_SIGNATURE)
336 vsflags |= _RPMVSF_NOSIGNATURES;
337 if (ia->qva_flags & VERIFY_HDRCHK)
338 vsflags |= RPMVSF_NOHDRCHK;
339 ovsflags = rpmtsSetVSFlags(ts, (vsflags | RPMVSF_NEEDPAYLOAD));
342 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
343 xx = rpmtsSetNotifyCallback(ts,
344 rpmShowProgress, (void *) ((long)notifyFlags));
347 if ((eiu->relocations = relocations) != NULL) {
348 while (eiu->relocations->oldPath)
350 if (eiu->relocations->newPath == NULL)
351 eiu->relocations = NULL;
354 /* Build fully globbed list of arguments in argv[argc]. */
357 for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
359 av = _free(av); ac = 0;
360 rc = rpmGlob(*eiu->fnp, &ac, &av);
362 rpmError(RPMERR_OPEN, _("File not found by glob: %s\n"), *eiu->fnp);
366 eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
367 memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
369 eiu->argv[eiu->argc] = NULL;
372 av = _free(av); ac = 0;
375 /* Allocate sufficient storage for next set of args. */
376 if (eiu->pkgx >= eiu->numPkgs) {
377 eiu->numPkgs = eiu->pkgx + eiu->argc;
378 eiu->pkgURL = xrealloc(eiu->pkgURL,
379 (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
380 memset(eiu->pkgURL + eiu->pkgx, 0,
381 ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
382 eiu->pkgState = xrealloc(eiu->pkgState,
383 (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
384 memset(eiu->pkgState + eiu->pkgx, 0,
385 ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
388 /* Retrieve next set of args, cache on local storage. */
389 for (i = 0; i < eiu->argc; i++) {
390 fileURL = _free(fileURL);
391 fileURL = eiu->argv[i];
395 if (fileURL[0] == '=') {
396 rpmds this = rpmdsSingle(RPMTAG_REQUIRENAME, fileURL+1, NULL, 0);
398 xx = rpmtsSolve(ts, this, NULL);
399 if (ts->suggests && ts->nsuggests > 0) {
400 fileURL = _free(fileURL);
401 fileURL = ts->suggests[0];
402 ts->suggests[0] = NULL;
403 while (ts->nsuggests-- > 0) {
404 if (ts->suggests[ts->nsuggests] == NULL)
406 ts->suggests[ts->nsuggests] = _free(ts->suggests[ts->nsuggests]);
408 ts->suggests = _free(ts->suggests);
409 rpmMessage(RPMMESS_DEBUG, _("Adding goal: %s\n"), fileURL);
410 eiu->pkgURL[eiu->pkgx] = fileURL;
414 this = rpmdsFree(this);
418 switch (urlIsURL(fileURL)) {
425 fprintf(stdout, _("Retrieving %s\n"), fileURL);
428 const char * rootDir = rpmtsRootDir(ts);
429 if (!(rootDir && * rootDir))
431 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
432 (void) mktemp(tfnbuf);
433 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
436 /* XXX undefined %{name}/%{version}/%{release} here */
437 /* XXX %{_tmpdir} does not exist */
438 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
439 rc = urlGetFile(fileURL, tfn);
441 rpmMessage(RPMMESS_ERROR,
442 _("skipping %s - transfer failed - %s\n"),
443 fileURL, ftpStrerror(rc));
445 eiu->pkgURL[eiu->pkgx] = NULL;
447 /*@switchbreak@*/ break;
449 eiu->pkgState[eiu->pkgx] = 1;
450 eiu->pkgURL[eiu->pkgx] = tfn;
452 } /*@switchbreak@*/ break;
454 case URL_IS_DASH: /* WRONG WRONG WRONG */
455 case URL_IS_HKP: /* WRONG WRONG WRONG */
457 eiu->pkgURL[eiu->pkgx] = fileURL;
460 /*@switchbreak@*/ break;
463 fileURL = _free(fileURL);
465 if (eiu->numFailed) goto exit;
467 /* Continue processing file arguments, building transaction set. */
468 for (eiu->fnp = eiu->pkgURL+eiu->prevx;
470 eiu->fnp++, eiu->prevx++)
472 const char * fileName;
474 rpmMessage(RPMMESS_DEBUG, "============== %s\n", *eiu->fnp);
475 (void) urlPath(*eiu->fnp, &fileName);
477 /* Try to read the header from a package file. */
478 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
479 if (eiu->fd == NULL || Ferror(eiu->fd)) {
480 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
482 if (eiu->fd != NULL) {
483 xx = Fclose(eiu->fd);
486 eiu->numFailed++; *eiu->fnp = NULL;
490 /* Read the header, verifying signatures (if present). */
491 tvsflags = rpmtsSetVSFlags(ts, vsflags);
492 eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
493 tvsflags = rpmtsSetVSFlags(ts, tvsflags);
494 xx = Fclose(eiu->fd);
497 switch (eiu->rpmrc) {
499 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *eiu->fnp);
500 eiu->numFailed++; *eiu->fnp = NULL;
502 /*@notreached@*/ /*@switchbreak@*/ break;
505 /*@notreached@*/ /*@switchbreak@*/ break;
506 case RPMRC_NOTTRUSTED:
510 /*@switchbreak@*/ break;
513 eiu->isSource = headerIsEntry(eiu->h, RPMTAG_SOURCEPACKAGE);
516 rpmMessage(RPMMESS_DEBUG, _("\tadded source package [%d]\n"),
518 eiu->sourceURL = xrealloc(eiu->sourceURL,
519 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
520 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
523 eiu->sourceURL[eiu->numSRPMS] = NULL;
527 if (eiu->relocations) {
532 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
533 (void **) &paths, &c) && (c == 1))
535 eiu->relocations->oldPath = xstrdup(paths[0]);
536 paths = headerFreeData(paths, pft);
539 xx = headerNVR(eiu->h, &name, NULL, NULL);
540 rpmMessage(RPMMESS_ERROR,
541 _("package %s is not relocatable\n"), name);
548 /* On --freshen, verify package is installed and newer */
549 if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
550 rpmdbMatchIterator mi;
555 xx = headerNVR(eiu->h, &name, NULL, NULL);
556 mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
557 count = rpmdbGetIteratorCount(mi);
558 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
559 if (rpmVersionCompare(oldH, eiu->h) < 0)
560 /*@innercontinue@*/ continue;
561 /* same or newer package already installed */
563 /*@innerbreak@*/ break;
565 mi = rpmdbFreeIterator(mi);
567 eiu->h = headerFree(eiu->h);
570 /* Package is newer than those currently installed. */
574 rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
575 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
579 /* XXX reference held by transaction set */
580 eiu->h = headerFree(eiu->h);
581 if (eiu->relocations)
582 eiu->relocations->oldPath = _free(eiu->relocations->oldPath);
586 rpmMessage(RPMMESS_DEBUG, _("\tadded binary package [%d]\n"),
588 /*@switchbreak@*/ break;
590 rpmMessage(RPMMESS_ERROR,
591 _("error reading from file %s\n"), *eiu->fnp);
594 /*@notreached@*/ /*@switchbreak@*/ break;
596 rpmMessage(RPMMESS_ERROR,
597 _("file %s requires a newer version of RPM\n"),
601 /*@notreached@*/ /*@switchbreak@*/ break;
605 /*@notreached@*/ /*@switchbreak@*/ break;
612 /* Try to read a package manifest. */
613 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
614 if (eiu->fd == NULL || Ferror(eiu->fd)) {
615 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
617 if (eiu->fd != NULL) {
618 xx = Fclose(eiu->fd);
621 eiu->numFailed++; *eiu->fnp = NULL;
625 /* Read list of packages from manifest. */
626 /*@-nullstate@*/ /* FIX: *eiu->argv can be NULL */
627 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
630 rpmError(RPMERR_MANIFEST, _("%s: not an rpm package (or package manifest): %s\n"),
631 *eiu->fnp, Fstrerror(eiu->fd));
632 xx = Fclose(eiu->fd);
635 /* If successful, restart the query loop. */
636 if (rc == RPMRC_OK) {
641 eiu->numFailed++; *eiu->fnp = NULL;
645 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
646 eiu->numSRPMS, eiu->numRPMS);
648 if (eiu->numFailed) goto exit;
650 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
652 if (rpmtsCheck(ts)) {
653 eiu->numFailed = eiu->numPkgs;
657 ps = rpmtsProblems(ts);
658 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
659 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
660 rpmpsPrint(NULL, ps);
661 eiu->numFailed = eiu->numPkgs;
665 if (ts->suggests != NULL && ts->nsuggests > 0) {
666 rpmMessage(RPMMESS_NORMAL, _(" Suggested resolutions:\n"));
667 for (i = 0; i < ts->nsuggests; i++) {
668 const char * str = ts->suggests[i];
673 rpmMessage(RPMMESS_NORMAL, "\t%s\n", str);
675 ts->suggests[i] = NULL;
678 ts->suggests = _free(ts->suggests);
685 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
686 if (rpmtsOrder(ts)) {
687 eiu->numFailed = eiu->numPkgs;
692 if (eiu->numRPMS && !stopInstall) {
694 rpmcliPackagesTotal += eiu->numSRPMS;
696 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
698 /* Drop added/available package indices and dependency sets. */
701 rc = rpmtsRun(ts, NULL, probFilter);
702 ps = rpmtsProblems(ts);
705 eiu->numFailed += eiu->numRPMS;
707 eiu->numFailed += rc;
708 if (rpmpsNumProblems(ps) > 0)
709 rpmpsPrint(stderr, ps);
714 if (eiu->numSRPMS && !stopInstall) {
715 if (eiu->sourceURL != NULL)
716 for (i = 0; i < eiu->numSRPMS; i++) {
717 if (eiu->sourceURL[i] == NULL) continue;
718 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
719 if (eiu->fd == NULL || Ferror(eiu->fd)) {
720 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
721 eiu->sourceURL[i], Fstrerror(eiu->fd));
722 if (eiu->fd != NULL) {
723 xx = Fclose(eiu->fd);
729 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
730 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
731 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
734 xx = Fclose(eiu->fd);
740 if (eiu->pkgURL != NULL)
741 for (i = 0; i < eiu->numPkgs; i++) {
742 if (eiu->pkgURL[i] == NULL) continue;
743 if (eiu->pkgState[i] == 1)
744 (void) Unlink(eiu->pkgURL[i]);
745 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
747 eiu->pkgState = _free(eiu->pkgState);
748 eiu->pkgURL = _free(eiu->pkgURL);
749 eiu->argv = _free(eiu->argv);
753 return eiu->numFailed;
757 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
763 int stopUninstall = 0;
765 rpmVSFlags vsflags, ovsflags;
768 if (argv == NULL) return 0;
770 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
771 if (ia->qva_flags & VERIFY_DIGEST)
772 vsflags |= _RPMVSF_NODIGESTS;
773 if (ia->qva_flags & VERIFY_SIGNATURE)
774 vsflags |= _RPMVSF_NOSIGNATURES;
775 if (ia->qva_flags & VERIFY_HDRCHK)
776 vsflags |= RPMVSF_NOHDRCHK;
777 ovsflags = rpmtsSetVSFlags(ts, vsflags);
779 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
780 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
782 (void) rpmtsSetFlags(ts, ia->transFlags);
784 #ifdef NOTYET /* XXX no callbacks on erase yet */
786 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
787 xx = rpmtsSetNotifyCallback(ts,
788 rpmShowProgress, (void *) ((long)notifyFlags)
792 ts->goal = TSM_ERASE;
794 for (arg = argv; *arg; arg++) {
795 rpmdbMatchIterator mi;
797 /* XXX HACK to get rpmdbFindByLabel out of the API */
798 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
800 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
803 Header h; /* XXX iterator owns the reference */
805 while ((h = rpmdbNextIterator(mi)) != NULL) {
806 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
808 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
809 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
812 /*@innerbreak@*/ break;
815 (void) rpmtsAddEraseElement(ts, h, recOffset);
820 mi = rpmdbFreeIterator(mi);
823 if (numFailed) goto exit;
825 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
827 if (rpmtsCheck(ts)) {
828 numFailed = numPackages;
832 ps = rpmtsProblems(ts);
833 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
834 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
835 rpmpsPrint(NULL, ps);
836 numFailed += numPackages;
842 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
843 if (rpmtsOrder(ts)) {
844 numFailed += numPackages;
849 if (numPackages && !stopUninstall) {
850 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
852 /* Drop added/available package indices and dependency sets. */
855 numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
856 ps = rpmtsProblems(ts);
857 if (rpmpsNumProblems(ps) > 0)
858 rpmpsPrint(NULL, ps);
859 numFailed += numPackages;
870 int rpmInstallSource(rpmts ts, const char * arg,
871 const char ** specFilePtr, const char ** cookie)
877 fd = Fopen(arg, "r.ufdio");
878 if (fd == NULL || Ferror(fd)) {
879 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
880 if (fd != NULL) (void) Fclose(fd);
885 fprintf(stdout, _("Installing %s\n"), arg);
888 rpmVSFlags ovsflags =
889 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
890 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
891 rc = (rpmrc == RPMRC_OK ? 0 : 1);
892 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
895 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
896 /*@-unqualifiedtrans@*/
897 if (specFilePtr && *specFilePtr)
898 *specFilePtr = _free(*specFilePtr);
899 if (cookie && *cookie)
900 *cookie = _free(*cookie);
901 /*@=unqualifiedtrans@*/
909 /** @todo Transaction handling, more, needs work. */
910 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
912 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
913 unsigned thistid = 0xffffffff;
923 int vsflags, ovsflags;
927 int _unsafe_rollbacks = 0;
928 rpmtransFlags transFlags = ia->transFlags;
930 if (argv != NULL && *argv != NULL) {
935 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
937 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
938 if (ia->qva_flags & VERIFY_DIGEST)
939 vsflags |= _RPMVSF_NODIGESTS;
940 if (ia->qva_flags & VERIFY_SIGNATURE)
941 vsflags |= _RPMVSF_NOSIGNATURES;
942 if (ia->qva_flags & VERIFY_HDRCHK)
943 vsflags |= RPMVSF_NOHDRCHK;
944 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
945 ovsflags = rpmtsSetVSFlags(ts, vsflags);
947 (void) rpmtsSetFlags(ts, transFlags);
949 /* Make the transaction a rollback transaction. In a rollback
950 * a best effort is what we want
952 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
954 itids = IDTXload(ts, RPMTAG_INSTALLTID);
963 { const char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
964 if (globstr == NULL || *globstr == '%') {
965 globstr = _free(globstr);
969 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
978 globstr = _free(globstr);
981 { int notifyFlags, xx;
982 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
983 xx = rpmtsSetNotifyCallback(ts,
984 rpmShowProgress, (void *) ((long)notifyFlags));
987 /* Run transactions until rollback goal is achieved. */
991 rpmcliPackagesTotal = 0;
994 ia->installInterfaceFlags &= ~ifmask;
996 /* Find larger of the remaining install/erase transaction id's. */
998 if (ip != NULL && ip->val.u32 > thistid)
999 thistid = ip->val.u32;
1000 if (rp != NULL && rp->val.u32 > thistid)
1001 thistid = rp->val.u32;
1003 /* If we've achieved the rollback goal, then we're done. */
1004 if (thistid == 0 || thistid < ia->rbtid)
1007 /* If we've reached the (configured) rollback goal, then we're done. */
1008 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
1012 (void) rpmtsSetFlags(ts, transFlags);
1014 /* Install the previously erased packages for this transaction. */
1015 while (rp != NULL && rp->val.u32 == thistid) {
1017 rpmMessage(RPMMESS_DEBUG, "\t+++ install %s\n",
1018 (rp->key ? rp->key : "???"));
1021 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
1022 0, ia->relocations);
1028 rpmcliPackagesTotal++;
1029 if (!(ia->installInterfaceFlags & ifmask))
1030 ia->installInterfaceFlags |= INSTALL_UPGRADE;
1033 rp->h = headerFree(rp->h);
1042 /* Erase the previously installed packages for this transaction. */
1043 while (ip != NULL && ip->val.u32 == thistid) {
1045 rpmMessage(RPMMESS_DEBUG,
1046 "\t--- erase h#%u\n", ip->instance);
1048 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
1054 if (_unsafe_rollbacks)
1055 rpmcliPackagesTotal++;
1057 if (!(ia->installInterfaceFlags & ifmask)) {
1058 ia->installInterfaceFlags |= INSTALL_ERASE;
1059 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1072 /* Anything to do? */
1073 if (rpmcliPackagesTotal <= 0)
1076 tid = (time_t)thistid;
1077 rpmMessage(RPMMESS_NORMAL,
1078 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1079 numAdded, numRemoved, ctime(&tid), tid);
1081 rc = rpmtsCheck(ts);
1082 ps = rpmtsProblems(ts);
1083 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1084 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
1085 rpmpsPrint(NULL, ps);
1091 rc = rpmtsOrder(ts);
1095 /* Drop added/available package indices and dependency sets. */
1098 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1099 ps = rpmtsProblems(ts);
1100 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1101 rpmpsPrint(stderr, ps);
1106 /* Clean up after successful rollback. */
1107 if (rtids && !rpmIsDebug()) {
1109 rpmMessage(RPMMESS_NORMAL, _("Cleaning up repackaged packages:\n"));
1111 for (i = 0; i < rtids->nidt; i++) {
1112 IDT rrp = rtids->idt + i;
1113 if (rrp->val.u32 != thistid)
1114 /*@innercontinue@*/ continue;
1115 if (rrp->key) { /* XXX can't happen */
1116 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), rrp->key);
1117 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1126 rtids = IDTXfree(rtids);
1127 itids = IDTXfree(itids);
1130 (void) rpmtsSetFlags(ts, transFlags);