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;
608 /* Try to read a package manifest. */
609 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
610 if (eiu->fd == NULL || Ferror(eiu->fd)) {
611 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
613 if (eiu->fd != NULL) {
614 xx = Fclose(eiu->fd);
617 eiu->numFailed++; *eiu->fnp = NULL;
621 /* Read list of packages from manifest. */
622 /*@-nullstate@*/ /* FIX: *eiu->argv can be NULL */
623 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
626 rpmError(RPMERR_MANIFEST, _("%s: not an rpm package (or package manifest): %s\n"),
627 *eiu->fnp, Fstrerror(eiu->fd));
628 xx = Fclose(eiu->fd);
631 /* If successful, restart the query loop. */
632 if (rc == RPMRC_OK) {
637 eiu->numFailed++; *eiu->fnp = NULL;
641 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
642 eiu->numSRPMS, eiu->numRPMS);
644 if (eiu->numFailed) goto exit;
646 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
648 if (rpmtsCheck(ts)) {
649 eiu->numFailed = eiu->numPkgs;
653 ps = rpmtsProblems(ts);
654 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
655 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
656 rpmpsPrint(NULL, ps);
657 eiu->numFailed = eiu->numPkgs;
661 if (ts->suggests != NULL && ts->nsuggests > 0) {
662 rpmMessage(RPMMESS_NORMAL, _(" Suggested resolutions:\n"));
663 for (i = 0; i < ts->nsuggests; i++) {
664 const char * str = ts->suggests[i];
669 rpmMessage(RPMMESS_NORMAL, "\t%s\n", str);
671 ts->suggests[i] = NULL;
674 ts->suggests = _free(ts->suggests);
681 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
682 if (rpmtsOrder(ts)) {
683 eiu->numFailed = eiu->numPkgs;
688 if (eiu->numRPMS && !stopInstall) {
690 rpmcliPackagesTotal += eiu->numSRPMS;
692 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
694 /* Drop added/available package indices and dependency sets. */
697 rc = rpmtsRun(ts, NULL, probFilter);
698 ps = rpmtsProblems(ts);
701 eiu->numFailed += eiu->numRPMS;
703 eiu->numFailed += rc;
704 if (rpmpsNumProblems(ps) > 0)
705 rpmpsPrint(stderr, ps);
710 if (eiu->numSRPMS && !stopInstall) {
711 if (eiu->sourceURL != NULL)
712 for (i = 0; i < eiu->numSRPMS; i++) {
713 if (eiu->sourceURL[i] == NULL) continue;
714 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
715 if (eiu->fd == NULL || Ferror(eiu->fd)) {
716 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
717 eiu->sourceURL[i], Fstrerror(eiu->fd));
718 if (eiu->fd != NULL) {
719 xx = Fclose(eiu->fd);
725 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
726 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
727 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
730 xx = Fclose(eiu->fd);
736 if (eiu->pkgURL != NULL)
737 for (i = 0; i < eiu->numPkgs; i++) {
738 if (eiu->pkgURL[i] == NULL) continue;
739 if (eiu->pkgState[i] == 1)
740 (void) Unlink(eiu->pkgURL[i]);
741 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
743 eiu->pkgState = _free(eiu->pkgState);
744 eiu->pkgURL = _free(eiu->pkgURL);
745 eiu->argv = _free(eiu->argv);
749 return eiu->numFailed;
753 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
759 int stopUninstall = 0;
761 rpmVSFlags vsflags, ovsflags;
764 if (argv == NULL) return 0;
766 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
767 if (ia->qva_flags & VERIFY_DIGEST)
768 vsflags |= _RPMVSF_NODIGESTS;
769 if (ia->qva_flags & VERIFY_SIGNATURE)
770 vsflags |= _RPMVSF_NOSIGNATURES;
771 if (ia->qva_flags & VERIFY_HDRCHK)
772 vsflags |= RPMVSF_NOHDRCHK;
773 ovsflags = rpmtsSetVSFlags(ts, vsflags);
775 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
776 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
778 (void) rpmtsSetFlags(ts, ia->transFlags);
780 #ifdef NOTYET /* XXX no callbacks on erase yet */
782 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
783 xx = rpmtsSetNotifyCallback(ts,
784 rpmShowProgress, (void *) ((long)notifyFlags)
788 ts->goal = TSM_ERASE;
790 for (arg = argv; *arg; arg++) {
791 rpmdbMatchIterator mi;
793 /* XXX HACK to get rpmdbFindByLabel out of the API */
794 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
796 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
799 Header h; /* XXX iterator owns the reference */
801 while ((h = rpmdbNextIterator(mi)) != NULL) {
802 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
804 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
805 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
808 /*@innerbreak@*/ break;
811 (void) rpmtsAddEraseElement(ts, h, recOffset);
816 mi = rpmdbFreeIterator(mi);
819 if (numFailed) goto exit;
821 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
823 if (rpmtsCheck(ts)) {
824 numFailed = numPackages;
828 ps = rpmtsProblems(ts);
829 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
830 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
831 rpmpsPrint(NULL, ps);
832 numFailed += numPackages;
839 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
840 if (rpmtsOrder(ts)) {
841 numFailed += numPackages;
847 if (!stopUninstall) {
848 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
850 /* Drop added/available package indices and dependency sets. */
853 numPackages = rpmtsRun(ts, NULL, ia->probFilter & (RPMPROB_FILTER_DISKSPACE|RPMPROB_FILTER_DISKNODES));
854 ps = rpmtsProblems(ts);
855 if (rpmpsNumProblems(ps) > 0)
856 rpmpsPrint(NULL, ps);
857 numFailed += numPackages;
868 int rpmInstallSource(rpmts ts, const char * arg,
869 const char ** specFilePtr, const char ** cookie)
875 fd = Fopen(arg, "r.ufdio");
876 if (fd == NULL || Ferror(fd)) {
877 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
878 if (fd != NULL) (void) Fclose(fd);
883 fprintf(stdout, _("Installing %s\n"), arg);
886 rpmVSFlags ovsflags =
887 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
888 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
889 rc = (rpmrc == RPMRC_OK ? 0 : 1);
890 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
893 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
894 /*@-unqualifiedtrans@*/
895 if (specFilePtr && *specFilePtr)
896 *specFilePtr = _free(*specFilePtr);
897 if (cookie && *cookie)
898 *cookie = _free(*cookie);
899 /*@=unqualifiedtrans@*/
908 static int reverse = -1;
912 static int IDTintcmp(const void * a, const void * b)
916 return ( reverse * (((IDT)a)->val.u32 - ((IDT)b)->val.u32) );
920 IDTX IDTXfree(IDTX idtx)
925 for (i = 0; i < idtx->nidt; i++) {
926 IDT idt = idtx->idt + i;
927 idt->h = headerFree(idt->h);
928 idt->key = _free(idt->key);
930 idtx->idt = _free(idtx->idt);
938 IDTX idtx = xcalloc(1, sizeof(*idtx));
940 idtx->size = sizeof(*((IDT)0));
944 IDTX IDTXgrow(IDTX idtx, int need)
946 if (need < 0) return NULL;
949 if (need == 0) return idtx;
951 if ((idtx->nidt + need) > idtx->alloced) {
953 idtx->alloced += idtx->delta;
956 idtx->idt = xrealloc(idtx->idt, (idtx->alloced * idtx->size) );
961 IDTX IDTXsort(IDTX idtx)
963 if (idtx != NULL && idtx->idt != NULL && idtx->nidt > 0)
964 qsort(idtx->idt, idtx->nidt, idtx->size, IDTintcmp);
968 IDTX IDTXload(rpmts ts, rpmTag tag)
971 rpmdbMatchIterator mi;
972 HGE_t hge = (HGE_t) headerGetEntry;
976 mi = rpmtsInitIterator(ts, tag, NULL, 0);
978 (void) rpmdbSetIteratorRE(mi, RPMTAG_NAME, RPMMIRE_DEFAULT, '!gpg-pubkey');
980 while ((h = rpmdbNextIterator(mi)) != NULL) {
981 rpmTagType type = RPM_NULL_TYPE;
986 if (!hge(h, tag, &type, (void **)&tidp, &count) || tidp == NULL)
989 if (type == RPM_INT32_TYPE && (*tidp == 0 || *tidp == -1))
992 idtx = IDTXgrow(idtx, 1);
995 if (idtx->idt == NULL)
1000 idt = idtx->idt + idtx->nidt;
1002 idt->h = headerLink(h);
1004 idt->instance = rpmdbGetIteratorOffset(mi);
1005 idt->val.u32 = *tidp;
1009 mi = rpmdbFreeIterator(mi);
1012 return IDTXsort(idtx);
1015 IDTX IDTXglob(rpmts ts, const char * globstr, rpmTag tag)
1018 HGE_t hge = (HGE_t) headerGetEntry;
1022 const char ** av = NULL;
1029 xx = rpmGlob(globstr, &ac, &av);
1032 for (i = 0; i < ac; i++) {
1037 fd = Fopen(av[i], "r.ufdio");
1038 if (fd == NULL || Ferror(fd)) {
1039 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), av[i],
1041 if (fd != NULL) (void) Fclose(fd);
1045 rpmrc = rpmReadPackageFile(ts, fd, av[i], &h);
1050 /*@notreached@*/ /*@switchbreak@*/ break;
1051 case RPMRC_NOTTRUSTED:
1054 isSource = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
1057 /*@switchbreak@*/ break;
1062 if (hge(h, tag, &type, (void **) &tidp, &count) && tidp != NULL) {
1064 idtx = IDTXgrow(idtx, 1);
1065 if (idtx == NULL || idtx->idt == NULL)
1069 idt = idtx->idt + idtx->nidt;
1070 idt->h = headerLink(h);
1074 idt->val.u32 = *tidp;
1083 for (i = 0; i < ac; i++)
1084 av[i] = _free(av[i]);
1085 av = _free(av); ac = 0;
1087 return IDTXsort(idtx);
1090 /** @todo Transaction handling, more, needs work. */
1091 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
1093 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
1094 unsigned thistid = 0xffffffff;
1104 int vsflags, ovsflags;
1108 int _unsafe_rollbacks = 0;
1109 rpmtransFlags transFlags = ia->transFlags;
1111 if (argv != NULL && *argv != NULL) {
1116 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
1118 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
1119 if (ia->qva_flags & VERIFY_DIGEST)
1120 vsflags |= _RPMVSF_NODIGESTS;
1121 if (ia->qva_flags & VERIFY_SIGNATURE)
1122 vsflags |= _RPMVSF_NOSIGNATURES;
1123 if (ia->qva_flags & VERIFY_HDRCHK)
1124 vsflags |= RPMVSF_NOHDRCHK;
1125 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
1126 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1128 (void) rpmtsSetFlags(ts, transFlags);
1130 /* Make the transaction a rollback transaction. In a rollback
1131 * a best effort is what we want
1133 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
1135 itids = IDTXload(ts, RPMTAG_INSTALLTID);
1136 if (itids != NULL) {
1138 niids = itids->nidt;
1144 { const char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
1145 if (globstr == NULL || *globstr == '%') {
1146 globstr = _free(globstr);
1150 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
1152 if (rtids != NULL) {
1154 nrids = rtids->nidt;
1159 globstr = _free(globstr);
1162 { int notifyFlags, xx;
1163 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
1164 xx = rpmtsSetNotifyCallback(ts,
1165 rpmShowProgress, (void *) ((long)notifyFlags));
1168 /* Run transactions until rollback goal is achieved. */
1172 rpmcliPackagesTotal = 0;
1175 ia->installInterfaceFlags &= ~ifmask;
1177 /* Find larger of the remaining install/erase transaction id's. */
1179 if (ip != NULL && ip->val.u32 > thistid)
1180 thistid = ip->val.u32;
1181 if (rp != NULL && rp->val.u32 > thistid)
1182 thistid = rp->val.u32;
1184 /* If we've achieved the rollback goal, then we're done. */
1185 if (thistid == 0 || thistid < ia->rbtid)
1188 /* If we've reached the (configured) rollback goal, then we're done. */
1189 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
1193 (void) rpmtsSetFlags(ts, transFlags);
1195 /* Install the previously erased packages for this transaction. */
1196 while (rp != NULL && rp->val.u32 == thistid) {
1198 rpmMessage(RPMMESS_DEBUG, "\t+++ install %s\n",
1199 (rp->key ? rp->key : "???"));
1202 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
1203 0, ia->relocations);
1209 rpmcliPackagesTotal++;
1210 if (!(ia->installInterfaceFlags & ifmask))
1211 ia->installInterfaceFlags |= INSTALL_UPGRADE;
1214 rp->h = headerFree(rp->h);
1223 /* Erase the previously installed packages for this transaction. */
1224 while (ip != NULL && ip->val.u32 == thistid) {
1226 rpmMessage(RPMMESS_DEBUG,
1227 "\t--- erase h#%u\n", ip->instance);
1229 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
1235 if (_unsafe_rollbacks)
1236 rpmcliPackagesTotal++;
1238 if (!(ia->installInterfaceFlags & ifmask)) {
1239 ia->installInterfaceFlags |= INSTALL_ERASE;
1240 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1253 /* Anything to do? */
1254 if (rpmcliPackagesTotal <= 0)
1257 tid = (time_t)thistid;
1258 rpmMessage(RPMMESS_NORMAL,
1259 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1260 numAdded, numRemoved, ctime(&tid), tid);
1262 rc = rpmtsCheck(ts);
1263 ps = rpmtsProblems(ts);
1264 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1265 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
1266 rpmpsPrint(NULL, ps);
1272 rc = rpmtsOrder(ts);
1276 /* Drop added/available package indices and dependency sets. */
1279 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1280 ps = rpmtsProblems(ts);
1281 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1282 rpmpsPrint(stderr, ps);
1287 /* Clean up after successful rollback. */
1288 if (rtids && !rpmIsDebug()) {
1290 rpmMessage(RPMMESS_NORMAL, _("Cleaning up repackaged packages:\n"));
1292 for (i = 0; i < rtids->nidt; i++) {
1293 IDT rrp = rtids->idt + i;
1294 if (rrp->val.u32 != thistid)
1295 /*@innercontinue@*/ continue;
1296 if (rrp->key) { /* XXX can't happen */
1297 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), rrp->key);
1298 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1307 rtids = IDTXfree(rtids);
1308 itids = IDTXfree(itids);
1311 (void) rpmtsSetFlags(ts, transFlags);