2 * \file lib/rpminstall.c
15 /*@access rpmTransactionSet@*/ /* XXX compared with NULL */
16 /*@access Header@*/ /* XXX compared with NULL */
17 /*@access FD_t@*/ /* XXX compared with NULL */
20 * Wrapper to free(3), hides const compilation noise, permit NULL, return NULL.
21 * @param this memory to free
24 static /*@null@*/ void * _free(/*@only@*/ /*@null@*/ const void * this) {
25 if (this) free((void *)this);
29 /* Define if you want percentage progress in the hash bars when
30 * writing to a tty (ordinary hash bars otherwise) --claudio
34 static int hashesPrinted = 0;
37 static int packagesTotal = 0;
38 static int progressTotal = 0;
39 static int progressCurrent = 0;
44 static void printHash(const unsigned long amount, const unsigned long total)
50 if (isatty (STDOUT_FILENO))
54 if (hashesPrinted != hashesTotal) {
55 hashesNeeded = hashesTotal * (total ? (((float) amount) / total) : 1);
56 while (hashesNeeded > hashesPrinted) {
58 if (isatty (STDOUT_FILENO)) {
60 for (i = 0; i < hashesPrinted; i++) putchar ('#');
61 for (; i < hashesTotal; i++) putchar (' ');
63 (int)(100 * (total ? (((float) amount) / total) : 1)));
64 for (i = 0; i < (hashesTotal + 6); i++) putchar ('\b');
72 hashesPrinted = hashesNeeded;
74 if (hashesPrinted == hashesTotal) {
78 for (i = 1; i < hashesPrinted; i++) putchar ('#');
79 printf (" [%3d%%]\n", (int)(100 * (progressTotal ?
80 (((float) progressCurrent) / progressTotal) : 1)));
82 fprintf (stdout, "\n");
91 static void * showProgress(const void * arg, const rpmCallbackType what,
92 const unsigned long amount,
93 const unsigned long total,
94 const void * pkgKey, void * data)
96 Header h = (Header) arg;
98 int flags = (int) ((long)data);
100 const char * filename = pkgKey;
104 case RPMCALLBACK_INST_OPEN_FILE:
105 fd = Fopen(filename, "r.ufdio");
107 fd = fdLink(fd, "persist (showProgress)");
109 /*@notreached@*/ break;
111 case RPMCALLBACK_INST_CLOSE_FILE:
112 fd = fdFree(fd, "persist (showProgress)");
119 case RPMCALLBACK_INST_START:
121 if (!(flags & INSTALL_LABEL))
123 if (flags & INSTALL_HASH) {
124 s = headerSprintf(h, "%{NAME}", rpmTagTable, rpmHeaderFormats,NULL);
126 if (isatty (STDOUT_FILENO))
127 fprintf(stdout, "%4d:%-23.23s", progressCurrent + 1, s);
130 fprintf(stdout, "%-28s", s);
134 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
135 rpmTagTable, rpmHeaderFormats, NULL);
136 fprintf(stdout, "%s\n", s);
142 case RPMCALLBACK_TRANS_PROGRESS:
143 case RPMCALLBACK_INST_PROGRESS:
144 if (flags & INSTALL_PERCENT)
145 fprintf(stdout, "%%%% %f\n", (total
146 ? ((float) ((((float) amount) / total) * 100))
148 else if (flags & INSTALL_HASH)
149 printHash(amount, total);
153 case RPMCALLBACK_TRANS_START:
159 if (!(flags & INSTALL_LABEL))
161 if (flags & INSTALL_HASH)
162 fprintf(stdout, "%-28s", _("Preparing..."));
164 printf("%s\n", _("Preparing packages for installation..."));
168 case RPMCALLBACK_TRANS_STOP:
169 if (flags & INSTALL_HASH)
170 printHash(1, 1); /* Fixes "preparing..." progress bar */
172 progressTotal = packagesTotal;
177 case RPMCALLBACK_UNINST_PROGRESS:
178 case RPMCALLBACK_UNINST_START:
179 case RPMCALLBACK_UNINST_STOP:
187 /** @todo Generalize --freshen policies. */
188 int rpmInstall(const char * rootdir, const char ** fileArgv,
189 rpmtransFlags transFlags,
190 rpmInstallInterfaceFlags interfaceFlags,
191 rpmprobFilterFlags probFilter,
192 rpmRelocation * relocations)
194 rpmTransactionSet ts = NULL;
195 int notifyFlags = interfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
197 const char ** pkgURL = NULL;
198 char * pkgState = NULL;
200 const char * fileURL = NULL;
207 rpmRelocation * defaultReloc = relocations;
208 const char ** sourceURL = NULL;
211 const char ** argv = NULL;
213 const char ** av = NULL;
220 while (defaultReloc && defaultReloc->oldPath)
222 if (defaultReloc && !defaultReloc->newPath) defaultReloc = NULL;
224 /* Build fully globbed list of arguments in argv[argc]. */
225 for (fnp = fileArgv; *fnp; fnp++) {
228 rc = rpmGlob(*fnp, &ac, &av);
229 if (rc || ac == 0) continue;
232 argv = xmalloc((argc+2) * sizeof(*argv));
234 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
235 memcpy(argv+argc, av, ac * sizeof(*av));
246 /* Allocate sufficient storage for next set of args. */
247 if (pkgx >= numPkgs) {
248 numPkgs = pkgx + argc;
249 pkgURL = (pkgURL == NULL)
250 ? xmalloc( (numPkgs + 1) * sizeof(*pkgURL))
251 : xrealloc(pkgURL, (numPkgs + 1) * sizeof(*pkgURL));
252 memset(pkgURL + pkgx, 0, ((argc + 1) * sizeof(*pkgURL)));
253 pkgState = (pkgState == NULL)
254 ? xmalloc( (numPkgs + 1) * sizeof(*pkgState))
255 : xrealloc(pkgState, (numPkgs + 1) * sizeof(*pkgState));
256 memset(pkgState + pkgx, 0, ((argc + 1) * sizeof(*pkgState)));
259 /* Retrieve next set of args, cache on local storage. */
260 for (i = 0; i < argc; i++) {
261 fileURL = _free(fileURL);
265 switch (urlIsURL(fileURL)) {
271 fprintf(stdout, _("Retrieving %s\n"), fileURL);
274 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
275 /*@-unrecog@*/ mktemp(tfnbuf) /*@=unrecog@*/;
276 tfn = rpmGenPath(rootdir, "%{_tmppath}/", tfnbuf);
279 /* XXX undefined %{name}/%{version}/%{release} here */
280 /* XXX %{_tmpdir} does not exist */
281 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
282 rc = urlGetFile(fileURL, tfn);
284 rpmMessage(RPMMESS_ERROR,
285 _("skipping %s - transfer failed - %s\n"),
286 fileURL, ftpStrerror(rc));
298 pkgURL[pkgx] = fileURL;
304 fileURL = _free(fileURL);
306 if (numFailed) goto exit;
308 /* Continue processing file arguments, building transaction set. */
309 for (fnp = pkgURL+prevx; *fnp; fnp++, prevx++) {
310 const char * fileName;
314 rpmMessage(RPMMESS_DEBUG, "============== %s\n", *fnp);
315 (void) urlPath(*fnp, &fileName);
317 /* Try to read the header from a package file. */
318 fd = Fopen(*fnp, "r.ufdio");
319 if (fd == NULL || Ferror(fd)) {
320 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
323 numFailed++; *fnp = NULL;
327 rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
330 if (rpmrc == RPMRC_FAIL || rpmrc == RPMRC_SHORTREAD) {
331 numFailed++; *fnp = NULL;
334 if ((rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE) && isSource) {
335 rpmMessage(RPMMESS_DEBUG, "\tadded source rpm[%d]\n", numSRPMS);
336 sourceURL = (sourceURL == NULL)
337 ? xmalloc( (numSRPMS + 2) * sizeof(*sourceURL))
338 : xrealloc(sourceURL, (numSRPMS + 2) * sizeof(*sourceURL));
339 sourceURL[numSRPMS++] = *fnp;
343 if (rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE) {
345 int mode = (transFlags & RPMTRANS_FLAG_TEST)
346 ? O_RDONLY : (O_RDWR | O_CREAT);
348 if (rpmdbOpen(rootdir, &db, mode, 0644)) {
350 dn = rpmGetPath( (rootdir ? rootdir : ""),
352 rpmMessage(RPMMESS_ERROR,
353 _("cannot open Packages database in %s\n"), dn);
355 numFailed++; *fnp = NULL;
358 ts = rpmtransCreateSet(db, rootdir);
367 if (headerGetEntry(h, RPMTAG_PREFIXES, &pft,
368 (void **) &paths, &c) && (c == 1)) {
369 defaultReloc->oldPath = xstrdup(paths[0]);
370 paths = headerFreeData(paths, pft);
373 headerNVR(h, &name, NULL, NULL);
374 rpmMessage(RPMMESS_ERROR,
375 _("package %s is not relocateable\n"), name);
382 /* On --freshen, verify package is installed and newer */
383 if (interfaceFlags & INSTALL_FRESHEN) {
384 rpmdbMatchIterator mi;
389 headerNVR(h, &name, NULL, NULL);
390 mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
391 count = rpmdbGetIteratorCount(mi);
392 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
393 if (rpmVersionCompare(oldH, h) < 0)
395 /* same or newer package already installed */
399 rpmdbFreeIterator(mi);
403 break; /* XXX out of switch */
405 /* Package is newer than those currently installed. */
408 rc = rpmtransAddPackage(ts, h, NULL, fileName,
409 (interfaceFlags & INSTALL_UPGRADE) != 0,
411 headerFree(h); /* XXX reference held by transaction set */
413 defaultReloc->oldPath = _free(defaultReloc->oldPath);
417 rpmMessage(RPMMESS_DEBUG, "\tadded binary rpm[%d]\n", numRPMS);
420 rpmMessage(RPMMESS_ERROR,
421 _("error reading from file %s\n"), *fnp);
424 /*@notreached@*/ break;
426 rpmMessage(RPMMESS_ERROR,
427 _("file %s requires a newer version of RPM\n"),
431 /*@notreached@*/ break;
438 if (rpmrc != RPMRC_BADMAGIC) {
439 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *fnp);
440 numFailed++; *fnp = NULL;
444 /* Try to read a package manifest. */
445 fd = Fopen(*fnp, "r.fpio");
446 if (fd == NULL || Ferror(fd)) {
447 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
450 numFailed++; *fnp = NULL;
454 /* Read list of packages from manifest. */
455 rc = rpmReadPackageManifest(fd, &argc, &argv);
457 rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"),
458 fileURL, Fstrerror(fd));
461 /* If successful, restart the query loop. */
467 numFailed++; *fnp = NULL;
471 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
474 if (numFailed) goto exit;
476 if (numRPMS && !(interfaceFlags & INSTALL_NODEPS)) {
477 struct rpmDependencyConflict * conflicts;
480 if (rpmdepCheck(ts, &conflicts, &numConflicts)) {
485 if (!stopInstall && conflicts) {
486 rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
487 printDepProblems(stderr, conflicts, numConflicts);
488 rpmdepFreeConflicts(conflicts, numConflicts);
494 if (numRPMS && !(interfaceFlags & INSTALL_NOORDER)) {
495 if (rpmdepOrder(ts)) {
501 if (numRPMS && !stopInstall) {
502 rpmProblemSet probs = NULL;
505 packagesTotal = numRPMS;
507 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
508 rc = rpmRunTransactions(ts, showProgress, (void *) ((long)notifyFlags),
509 NULL, &probs, transFlags, probFilter);
512 numFailed += numRPMS;
515 rpmProblemSetPrint(stderr, probs);
518 if (probs) rpmProblemSetFree(probs);
521 if (numSRPMS && !stopInstall) {
522 for (i = 0; i < numSRPMS; i++) {
523 fd = Fopen(sourceURL[i], "r.ufdio");
524 if (fd == NULL || Ferror(fd)) {
525 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
526 sourceURL[i], Fstrerror(fd));
531 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
532 rpmRC rpmrc = rpmInstallSourcePackage(rootdir, fd, NULL,
533 showProgress, (void *) ((long)notifyFlags), NULL);
534 if (rpmrc != RPMRC_OK) numFailed++;
542 if (ts) rpmtransFree(ts);
543 for (i = 0; i < numPkgs; i++) {
544 if (pkgState[i] == 1)
546 pkgURL[i] = _free(pkgURL[i]);
548 pkgState = _free(pkgState);
549 pkgURL = _free(pkgURL);
550 if (dbIsOpen) rpmdbClose(db);
554 int rpmErase(const char * rootdir, const char ** argv,
555 rpmtransFlags transFlags,
556 rpmEraseInterfaceFlags interfaceFlags)
563 rpmTransactionSet ts;
564 struct rpmDependencyConflict * conflicts;
566 int stopUninstall = 0;
570 if (transFlags & RPMTRANS_FLAG_TEST)
573 mode = O_RDWR | O_EXCL;
575 if (rpmdbOpen(rootdir, &db, mode, 0644)) {
577 dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
578 rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
583 ts = rpmtransCreateSet(db, rootdir);
584 for (arg = argv; *arg; arg++) {
585 rpmdbMatchIterator mi;
587 /* XXX HACK to get rpmdbFindByLabel out of the API */
588 mi = rpmdbInitIterator(db, RPMDBI_LABEL, *arg, 0);
589 count = rpmdbGetIteratorCount(mi);
591 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
593 } else if (!(count == 1 || (interfaceFlags & UNINSTALL_ALLMATCHES))) {
594 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
598 Header h; /* XXX iterator owns the reference */
599 while ((h = rpmdbNextIterator(mi)) != NULL) {
600 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
602 rpmtransRemovePackage(ts, recOffset);
607 rpmdbFreeIterator(mi);
610 if (!(interfaceFlags & UNINSTALL_NODEPS)) {
611 if (rpmdepCheck(ts, &conflicts, &numConflicts)) {
612 numFailed = numPackages;
616 if (!stopUninstall && conflicts) {
617 rpmMessage(RPMMESS_ERROR, _("removing these packages would break "
619 printDepProblems(stderr, conflicts, numConflicts);
620 rpmdepFreeConflicts(conflicts, numConflicts);
621 numFailed += numPackages;
626 if (!stopUninstall) {
627 transFlags |= RPMTRANS_FLAG_REVERSE;
628 numFailed += rpmRunTransactions(ts, NULL, NULL, NULL, &probs,
638 int rpmInstallSource(const char * rootdir, const char * arg,
639 const char ** specFile, char ** cookie)
644 fd = Fopen(arg, "r.ufdio");
645 if (fd == NULL || Ferror(fd)) {
646 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
652 fprintf(stdout, _("Installing %s\n"), arg);
654 { rpmRC rpmrc = rpmInstallSourcePackage(rootdir, fd, specFile, NULL, NULL,
656 rc = (rpmrc == RPMRC_OK ? 0 : 1);
659 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
660 if (specFile && *specFile)
661 *specFile = _free(*specFile);
662 if (cookie && *cookie)
663 *cookie = _free(*cookie);