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)) {
424 fprintf(stdout, _("Retrieving %s\n"), fileURL);
427 const char * rootDir = rpmtsRootDir(ts);
428 if (!(rootDir && * rootDir))
430 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
431 (void) mktemp(tfnbuf);
432 tfn = rpmGenPath(rootDir, "%{_tmppath}/", tfnbuf);
435 /* XXX undefined %{name}/%{version}/%{release} here */
436 /* XXX %{_tmpdir} does not exist */
437 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
438 rc = urlGetFile(fileURL, tfn);
440 rpmMessage(RPMMESS_ERROR,
441 _("skipping %s - transfer failed - %s\n"),
442 fileURL, ftpStrerror(rc));
444 eiu->pkgURL[eiu->pkgx] = NULL;
446 /*@switchbreak@*/ break;
448 eiu->pkgState[eiu->pkgx] = 1;
449 eiu->pkgURL[eiu->pkgx] = tfn;
451 } /*@switchbreak@*/ break;
454 eiu->pkgURL[eiu->pkgx] = fileURL;
457 /*@switchbreak@*/ break;
460 fileURL = _free(fileURL);
462 if (eiu->numFailed) goto exit;
464 /* Continue processing file arguments, building transaction set. */
465 for (eiu->fnp = eiu->pkgURL+eiu->prevx;
467 eiu->fnp++, eiu->prevx++)
469 const char * fileName;
471 rpmMessage(RPMMESS_DEBUG, "============== %s\n", *eiu->fnp);
472 (void) urlPath(*eiu->fnp, &fileName);
474 /* Try to read the header from a package file. */
475 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
476 if (eiu->fd == NULL || Ferror(eiu->fd)) {
477 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
479 if (eiu->fd != NULL) {
480 xx = Fclose(eiu->fd);
483 eiu->numFailed++; *eiu->fnp = NULL;
487 /* Read the header, verifying signatures (if present). */
488 tvsflags = rpmtsSetVSFlags(ts, vsflags);
489 eiu->rpmrc = rpmReadPackageFile(ts, eiu->fd, *eiu->fnp, &eiu->h);
490 tvsflags = rpmtsSetVSFlags(ts, tvsflags);
491 xx = Fclose(eiu->fd);
494 switch (eiu->rpmrc) {
496 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *eiu->fnp);
497 eiu->numFailed++; *eiu->fnp = NULL;
499 /*@notreached@*/ /*@switchbreak@*/ break;
502 /*@notreached@*/ /*@switchbreak@*/ break;
503 case RPMRC_NOTTRUSTED:
507 /*@switchbreak@*/ break;
510 eiu->isSource = headerIsEntry(eiu->h, RPMTAG_SOURCEPACKAGE);
513 rpmMessage(RPMMESS_DEBUG, _("\tadded source package [%d]\n"),
515 eiu->sourceURL = xrealloc(eiu->sourceURL,
516 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
517 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
520 eiu->sourceURL[eiu->numSRPMS] = NULL;
524 if (eiu->relocations) {
529 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
530 (void **) &paths, &c) && (c == 1))
532 eiu->relocations->oldPath = xstrdup(paths[0]);
533 paths = headerFreeData(paths, pft);
536 xx = headerNVR(eiu->h, &name, NULL, NULL);
537 rpmMessage(RPMMESS_ERROR,
538 _("package %s is not relocatable\n"), name);
545 /* On --freshen, verify package is installed and newer */
546 if (ia->installInterfaceFlags & INSTALL_FRESHEN) {
547 rpmdbMatchIterator mi;
552 xx = headerNVR(eiu->h, &name, NULL, NULL);
553 mi = rpmtsInitIterator(ts, RPMTAG_NAME, name, 0);
554 count = rpmdbGetIteratorCount(mi);
555 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
556 if (rpmVersionCompare(oldH, eiu->h) < 0)
557 /*@innercontinue@*/ continue;
558 /* same or newer package already installed */
560 /*@innerbreak@*/ break;
562 mi = rpmdbFreeIterator(mi);
564 eiu->h = headerFree(eiu->h);
567 /* Package is newer than those currently installed. */
571 rc = rpmtsAddInstallElement(ts, eiu->h, (fnpyKey)fileName,
572 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
576 /* XXX reference held by transaction set */
577 eiu->h = headerFree(eiu->h);
578 if (eiu->relocations)
579 eiu->relocations->oldPath = _free(eiu->relocations->oldPath);
583 rpmMessage(RPMMESS_DEBUG, _("\tadded binary package [%d]\n"),
585 /*@switchbreak@*/ break;
587 rpmMessage(RPMMESS_ERROR,
588 _("error reading from file %s\n"), *eiu->fnp);
591 /*@notreached@*/ /*@switchbreak@*/ break;
593 rpmMessage(RPMMESS_ERROR,
594 _("file %s requires a newer version of RPM\n"),
598 /*@notreached@*/ /*@switchbreak@*/ break;
605 /* Try to read a package manifest. */
606 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
607 if (eiu->fd == NULL || Ferror(eiu->fd)) {
608 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
610 if (eiu->fd != NULL) {
611 xx = Fclose(eiu->fd);
614 eiu->numFailed++; *eiu->fnp = NULL;
618 /* Read list of packages from manifest. */
619 /*@-nullstate@*/ /* FIX: *eiu->argv can be NULL */
620 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
623 rpmError(RPMERR_MANIFEST, _("%s: not an rpm package (or package manifest): %s\n"),
624 *eiu->fnp, Fstrerror(eiu->fd));
625 xx = Fclose(eiu->fd);
628 /* If successful, restart the query loop. */
629 if (rc == RPMRC_OK) {
634 eiu->numFailed++; *eiu->fnp = NULL;
638 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
639 eiu->numSRPMS, eiu->numRPMS);
641 if (eiu->numFailed) goto exit;
643 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NODEPS)) {
645 if (rpmtsCheck(ts)) {
646 eiu->numFailed = eiu->numPkgs;
650 ps = rpmtsProblems(ts);
651 if (!stopInstall && rpmpsNumProblems(ps) > 0) {
652 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
653 rpmpsPrint(NULL, ps);
654 eiu->numFailed = eiu->numPkgs;
658 if (ts->suggests != NULL && ts->nsuggests > 0) {
659 rpmMessage(RPMMESS_NORMAL, _(" Suggested resolutions:\n"));
660 for (i = 0; i < ts->nsuggests; i++) {
661 const char * str = ts->suggests[i];
666 rpmMessage(RPMMESS_NORMAL, "\t%s\n", str);
668 ts->suggests[i] = NULL;
671 ts->suggests = _free(ts->suggests);
678 if (eiu->numRPMS && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
679 if (rpmtsOrder(ts)) {
680 eiu->numFailed = eiu->numPkgs;
685 if (eiu->numRPMS && !stopInstall) {
687 rpmcliPackagesTotal += eiu->numSRPMS;
689 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
691 /* Drop added/available package indices and dependency sets. */
694 rc = rpmtsRun(ts, NULL, probFilter);
695 ps = rpmtsProblems(ts);
698 eiu->numFailed += eiu->numRPMS;
700 eiu->numFailed += rc;
701 if (rpmpsNumProblems(ps) > 0)
702 rpmpsPrint(stderr, ps);
707 if (eiu->numSRPMS && !stopInstall) {
708 if (eiu->sourceURL != NULL)
709 for (i = 0; i < eiu->numSRPMS; i++) {
710 if (eiu->sourceURL[i] == NULL) continue;
711 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
712 if (eiu->fd == NULL || Ferror(eiu->fd)) {
713 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
714 eiu->sourceURL[i], Fstrerror(eiu->fd));
715 if (eiu->fd != NULL) {
716 xx = Fclose(eiu->fd);
722 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
723 eiu->rpmrc = rpmInstallSourcePackage(ts, eiu->fd, NULL, NULL);
724 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
727 xx = Fclose(eiu->fd);
733 if (eiu->pkgURL != NULL)
734 for (i = 0; i < eiu->numPkgs; i++) {
735 if (eiu->pkgURL[i] == NULL) continue;
736 if (eiu->pkgState[i] == 1)
737 (void) Unlink(eiu->pkgURL[i]);
738 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
740 eiu->pkgState = _free(eiu->pkgState);
741 eiu->pkgURL = _free(eiu->pkgURL);
742 eiu->argv = _free(eiu->argv);
746 return eiu->numFailed;
750 int rpmErase(rpmts ts, struct rpmInstallArguments_s * ia,
756 int stopUninstall = 0;
758 rpmVSFlags vsflags, ovsflags;
761 if (argv == NULL) return 0;
763 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
764 if (ia->qva_flags & VERIFY_DIGEST)
765 vsflags |= _RPMVSF_NODIGESTS;
766 if (ia->qva_flags & VERIFY_SIGNATURE)
767 vsflags |= _RPMVSF_NOSIGNATURES;
768 if (ia->qva_flags & VERIFY_HDRCHK)
769 vsflags |= RPMVSF_NOHDRCHK;
770 ovsflags = rpmtsSetVSFlags(ts, vsflags);
772 if (rpmExpandNumeric("%{?_repackage_all_erasures}"))
773 ia->transFlags |= RPMTRANS_FLAG_REPACKAGE;
775 (void) rpmtsSetFlags(ts, ia->transFlags);
777 #ifdef NOTYET /* XXX no callbacks on erase yet */
779 notifyFlags = ia->eraseInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
780 xx = rpmtsSetNotifyCallback(ts,
781 rpmShowProgress, (void *) ((long)notifyFlags)
785 ts->goal = TSM_ERASE;
787 for (arg = argv; *arg; arg++) {
788 rpmdbMatchIterator mi;
790 /* XXX HACK to get rpmdbFindByLabel out of the API */
791 mi = rpmtsInitIterator(ts, RPMDBI_LABEL, *arg, 0);
793 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
796 Header h; /* XXX iterator owns the reference */
798 while ((h = rpmdbNextIterator(mi)) != NULL) {
799 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
801 if (!(count++ == 0 || (ia->eraseInterfaceFlags & UNINSTALL_ALLMATCHES))) {
802 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
805 /*@innerbreak@*/ break;
808 (void) rpmtsAddEraseElement(ts, h, recOffset);
813 mi = rpmdbFreeIterator(mi);
816 if (numFailed) goto exit;
818 if (!(ia->eraseInterfaceFlags & UNINSTALL_NODEPS)) {
820 if (rpmtsCheck(ts)) {
821 numFailed = numPackages;
825 ps = rpmtsProblems(ts);
826 if (!stopUninstall && rpmpsNumProblems(ps) > 0) {
827 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
828 rpmpsPrint(NULL, ps);
829 numFailed += numPackages;
836 if (!stopUninstall && !(ia->installInterfaceFlags & INSTALL_NOORDER)) {
837 if (rpmtsOrder(ts)) {
838 numFailed += numPackages;
844 if (!stopUninstall) {
845 (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_REVERSE));
847 /* Drop added/available package indices and dependency sets. */
850 numPackages = rpmtsRun(ts, NULL, 0);
851 ps = rpmtsProblems(ts);
852 if (rpmpsNumProblems(ps) > 0)
853 rpmpsPrint(NULL, ps);
854 numFailed += numPackages;
865 int rpmInstallSource(rpmts ts, const char * arg,
866 const char ** specFilePtr, const char ** cookie)
872 fd = Fopen(arg, "r.ufdio");
873 if (fd == NULL || Ferror(fd)) {
874 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
875 if (fd != NULL) (void) Fclose(fd);
880 fprintf(stdout, _("Installing %s\n"), arg);
883 rpmVSFlags ovsflags =
884 rpmtsSetVSFlags(ts, (rpmtsVSFlags(ts) | RPMVSF_NEEDPAYLOAD));
885 rpmRC rpmrc = rpmInstallSourcePackage(ts, fd, specFilePtr, cookie);
886 rc = (rpmrc == RPMRC_OK ? 0 : 1);
887 ovsflags = rpmtsSetVSFlags(ts, ovsflags);
890 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
891 /*@-unqualifiedtrans@*/
892 if (specFilePtr && *specFilePtr)
893 *specFilePtr = _free(*specFilePtr);
894 if (cookie && *cookie)
895 *cookie = _free(*cookie);
896 /*@=unqualifiedtrans@*/
905 static int reverse = -1;
909 static int IDTintcmp(const void * a, const void * b)
913 return ( reverse * (((IDT)a)->val.u32 - ((IDT)b)->val.u32) );
917 IDTX IDTXfree(IDTX idtx)
922 for (i = 0; i < idtx->nidt; i++) {
923 IDT idt = idtx->idt + i;
924 idt->h = headerFree(idt->h);
925 idt->key = _free(idt->key);
927 idtx->idt = _free(idtx->idt);
935 IDTX idtx = xcalloc(1, sizeof(*idtx));
937 idtx->size = sizeof(*((IDT)0));
941 IDTX IDTXgrow(IDTX idtx, int need)
943 if (need < 0) return NULL;
946 if (need == 0) return idtx;
948 if ((idtx->nidt + need) > idtx->alloced) {
950 idtx->alloced += idtx->delta;
953 idtx->idt = xrealloc(idtx->idt, (idtx->alloced * idtx->size) );
958 IDTX IDTXsort(IDTX idtx)
960 if (idtx != NULL && idtx->idt != NULL && idtx->nidt > 0)
961 qsort(idtx->idt, idtx->nidt, idtx->size, IDTintcmp);
965 IDTX IDTXload(rpmts ts, rpmTag tag)
968 rpmdbMatchIterator mi;
969 HGE_t hge = (HGE_t) headerGetEntry;
973 mi = rpmtsInitIterator(ts, tag, NULL, 0);
975 (void) rpmdbSetIteratorRE(mi, RPMTAG_NAME, RPMMIRE_DEFAULT, '!gpg-pubkey');
977 while ((h = rpmdbNextIterator(mi)) != NULL) {
978 rpmTagType type = RPM_NULL_TYPE;
983 if (!hge(h, tag, &type, (void **)&tidp, &count) || tidp == NULL)
986 if (type == RPM_INT32_TYPE && (*tidp == 0 || *tidp == -1))
989 idtx = IDTXgrow(idtx, 1);
992 if (idtx->idt == NULL)
997 idt = idtx->idt + idtx->nidt;
999 idt->h = headerLink(h);
1001 idt->instance = rpmdbGetIteratorOffset(mi);
1002 idt->val.u32 = *tidp;
1006 mi = rpmdbFreeIterator(mi);
1009 return IDTXsort(idtx);
1012 IDTX IDTXglob(rpmts ts, const char * globstr, rpmTag tag)
1015 HGE_t hge = (HGE_t) headerGetEntry;
1019 const char ** av = NULL;
1026 xx = rpmGlob(globstr, &ac, &av);
1029 for (i = 0; i < ac; i++) {
1034 fd = Fopen(av[i], "r.ufdio");
1035 if (fd == NULL || Ferror(fd)) {
1036 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), av[i],
1038 if (fd != NULL) (void) Fclose(fd);
1042 rpmrc = rpmReadPackageFile(ts, fd, av[i], &h);
1047 /*@notreached@*/ /*@switchbreak@*/ break;
1048 case RPMRC_NOTTRUSTED:
1051 isSource = headerIsEntry(h, RPMTAG_SOURCEPACKAGE);
1054 /*@switchbreak@*/ break;
1059 if (hge(h, tag, &type, (void **) &tidp, &count) && tidp != NULL) {
1061 idtx = IDTXgrow(idtx, 1);
1062 if (idtx == NULL || idtx->idt == NULL)
1066 idt = idtx->idt + idtx->nidt;
1067 idt->h = headerLink(h);
1071 idt->val.u32 = *tidp;
1080 for (i = 0; i < ac; i++)
1081 av[i] = _free(av[i]);
1082 av = _free(av); ac = 0;
1084 return IDTXsort(idtx);
1087 /** @todo Transaction handling, more, needs work. */
1088 int rpmRollback(rpmts ts, struct rpmInstallArguments_s * ia, const char ** argv)
1090 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
1091 unsigned thistid = 0xffffffff;
1101 int vsflags, ovsflags;
1105 int _unsafe_rollbacks = 0;
1106 rpmtransFlags transFlags = ia->transFlags;
1108 if (argv != NULL && *argv != NULL) {
1113 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
1115 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
1116 if (ia->qva_flags & VERIFY_DIGEST)
1117 vsflags |= _RPMVSF_NODIGESTS;
1118 if (ia->qva_flags & VERIFY_SIGNATURE)
1119 vsflags |= _RPMVSF_NOSIGNATURES;
1120 if (ia->qva_flags & VERIFY_HDRCHK)
1121 vsflags |= RPMVSF_NOHDRCHK;
1122 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */
1123 ovsflags = rpmtsSetVSFlags(ts, vsflags);
1125 (void) rpmtsSetFlags(ts, transFlags);
1127 /* Make the transaction a rollback transaction. In a rollback
1128 * a best effort is what we want
1130 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
1132 itids = IDTXload(ts, RPMTAG_INSTALLTID);
1133 if (itids != NULL) {
1135 niids = itids->nidt;
1141 { const char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
1142 if (globstr == NULL || *globstr == '%') {
1143 globstr = _free(globstr);
1147 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID);
1149 if (rtids != NULL) {
1151 nrids = rtids->nidt;
1156 globstr = _free(globstr);
1159 { int notifyFlags, xx;
1160 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
1161 xx = rpmtsSetNotifyCallback(ts,
1162 rpmShowProgress, (void *) ((long)notifyFlags));
1165 /* Run transactions until rollback goal is achieved. */
1169 rpmcliPackagesTotal = 0;
1172 ia->installInterfaceFlags &= ~ifmask;
1174 /* Find larger of the remaining install/erase transaction id's. */
1176 if (ip != NULL && ip->val.u32 > thistid)
1177 thistid = ip->val.u32;
1178 if (rp != NULL && rp->val.u32 > thistid)
1179 thistid = rp->val.u32;
1181 /* If we've achieved the rollback goal, then we're done. */
1182 if (thistid == 0 || thistid < ia->rbtid)
1185 /* If we've reached the (configured) rollback goal, then we're done. */
1186 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
1190 (void) rpmtsSetFlags(ts, transFlags);
1192 /* Install the previously erased packages for this transaction. */
1193 while (rp != NULL && rp->val.u32 == thistid) {
1195 rpmMessage(RPMMESS_DEBUG, "\t+++ install %s\n",
1196 (rp->key ? rp->key : "???"));
1199 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
1200 0, ia->relocations);
1206 rpmcliPackagesTotal++;
1207 if (!(ia->installInterfaceFlags & ifmask))
1208 ia->installInterfaceFlags |= INSTALL_UPGRADE;
1211 rp->h = headerFree(rp->h);
1220 /* Erase the previously installed packages for this transaction. */
1221 while (ip != NULL && ip->val.u32 == thistid) {
1223 rpmMessage(RPMMESS_DEBUG,
1224 "\t--- erase h#%u\n", ip->instance);
1226 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
1232 if (_unsafe_rollbacks)
1233 rpmcliPackagesTotal++;
1235 if (!(ia->installInterfaceFlags & ifmask)) {
1236 ia->installInterfaceFlags |= INSTALL_ERASE;
1237 (void) rpmtsSetFlags(ts, (transFlags | RPMTRANS_FLAG_REVERSE));
1250 /* Anything to do? */
1251 if (rpmcliPackagesTotal <= 0)
1254 tid = (time_t)thistid;
1255 rpmMessage(RPMMESS_NORMAL,
1256 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
1257 numAdded, numRemoved, ctime(&tid), tid);
1259 rc = rpmtsCheck(ts);
1260 ps = rpmtsProblems(ts);
1261 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
1262 rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
1263 rpmpsPrint(NULL, ps);
1269 rc = rpmtsOrder(ts);
1273 /* Drop added/available package indices and dependency sets. */
1276 rc = rpmtsRun(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
1277 ps = rpmtsProblems(ts);
1278 if (rc > 0 && rpmpsNumProblems(ps) > 0)
1279 rpmpsPrint(stderr, ps);
1284 /* Clean up after successful rollback. */
1285 if (rtids && !rpmIsDebug()) {
1287 rpmMessage(RPMMESS_NORMAL, _("Cleaning up repackaged packages:\n"));
1289 for (i = 0; i < rtids->nidt; i++) {
1290 IDT rrp = rtids->idt + i;
1291 if (rrp->val.u32 != thistid)
1292 /*@innercontinue@*/ continue;
1293 if (rrp->key) { /* XXX can't happen */
1294 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), rrp->key);
1295 (void) unlink(rrp->key); /* XXX: Should check rc??? */
1304 rtids = IDTXfree(rtids);
1305 itids = IDTXfree(itids);
1308 (void) rpmtsSetFlags(ts, transFlags);