00001
00005 #include "system.h"
00006
00007 #include <rpmlib.h>
00008 #include <rpmmacro.h>
00009 #include <rpmurl.h>
00010
00011 #include "manifest.h"
00012 #include "misc.h"
00013 #include "debug.h"
00014
00015
00016
00017
00018
00024 static void * _free( const void * this) {
00025 if (this) free((void *)this);
00026 return NULL;
00027 }
00028
00029
00030
00031
00032 #define FANCY_HASH
00033
00034 static int hashesPrinted = 0;
00035
00036 #ifdef FANCY_HASH
00037 static int packagesTotal = 0;
00038 static int progressTotal = 0;
00039 static int progressCurrent = 0;
00040 #endif
00041
00044 static void printHash(const unsigned long amount, const unsigned long total)
00045 {
00046 int hashesNeeded;
00047 int hashesTotal = 50;
00048
00049 #ifdef FANCY_HASH
00050 if (isatty (STDOUT_FILENO))
00051 hashesTotal = 44;
00052 #endif
00053
00054 if (hashesPrinted != hashesTotal) {
00055 hashesNeeded = hashesTotal * (total ? (((float) amount) / total) : 1);
00056 while (hashesNeeded > hashesPrinted) {
00057 #ifdef FANCY_HASH
00058 if (isatty (STDOUT_FILENO)) {
00059 int i;
00060 for (i = 0; i < hashesPrinted; i++) putchar ('#');
00061 for (; i < hashesTotal; i++) putchar (' ');
00062 printf ("(%3d%%)",
00063 (int)(100 * (total ? (((float) amount) / total) : 1)));
00064 for (i = 0; i < (hashesTotal + 6); i++) putchar ('\b');
00065 } else
00066 #endif
00067 fprintf(stdout, "#");
00068
00069 hashesPrinted++;
00070 }
00071 fflush(stdout);
00072 hashesPrinted = hashesNeeded;
00073
00074 if (hashesPrinted == hashesTotal) {
00075 #ifdef FANCY_HASH
00076 int i;
00077 progressCurrent++;
00078 for (i = 1; i < hashesPrinted; i++) putchar ('#');
00079 printf (" [%3d%%]\n", (int)(100 * (progressTotal ?
00080 (((float) progressCurrent) / progressTotal) : 1)));
00081 #else
00082 fprintf (stdout, "\n");
00083 #endif
00084 }
00085 fflush(stdout);
00086 }
00087 }
00088
00091 static void * showProgress(const void * arg, const rpmCallbackType what,
00092 const unsigned long amount,
00093 const unsigned long total,
00094 const void * pkgKey, void * data)
00095 {
00096 Header h = (Header) arg;
00097 char * s;
00098 int flags = (int) ((long)data);
00099 void * rc = NULL;
00100 const char * filename = pkgKey;
00101 static FD_t fd;
00102
00103 switch (what) {
00104 case RPMCALLBACK_INST_OPEN_FILE:
00105 fd = Fopen(filename, "r.ufdio");
00106 if (fd)
00107 fd = fdLink(fd, "persist (showProgress)");
00108 return fd;
00109 break;
00110
00111 case RPMCALLBACK_INST_CLOSE_FILE:
00112 fd = fdFree(fd, "persist (showProgress)");
00113 if (fd) {
00114 Fclose(fd);
00115 fd = NULL;
00116 }
00117 break;
00118
00119 case RPMCALLBACK_INST_START:
00120 hashesPrinted = 0;
00121 if (!(flags & INSTALL_LABEL))
00122 break;
00123 if (flags & INSTALL_HASH) {
00124 s = headerSprintf(h, "%{NAME}", rpmTagTable, rpmHeaderFormats,NULL);
00125 #ifdef FANCY_HASH
00126 if (isatty (STDOUT_FILENO))
00127 fprintf(stdout, "%4d:%-23.23s", progressCurrent + 1, s);
00128 else
00129 #else
00130 fprintf(stdout, "%-28s", s);
00131 #endif
00132 fflush(stdout);
00133 } else {
00134 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
00135 rpmTagTable, rpmHeaderFormats, NULL);
00136 fprintf(stdout, "%s\n", s);
00137 fflush(stdout);
00138 }
00139 s = _free(s);
00140 break;
00141
00142 case RPMCALLBACK_TRANS_PROGRESS:
00143 case RPMCALLBACK_INST_PROGRESS:
00144 if (flags & INSTALL_PERCENT)
00145 fprintf(stdout, "%%%% %f\n", (total
00146 ? ((float) ((((float) amount) / total) * 100))
00147 : 100.0));
00148 else if (flags & INSTALL_HASH)
00149 printHash(amount, total);
00150 fflush(stdout);
00151 break;
00152
00153 case RPMCALLBACK_TRANS_START:
00154 hashesPrinted = 0;
00155 #ifdef FANCY_HASH
00156 progressTotal = 1;
00157 progressCurrent = 0;
00158 #endif
00159 if (!(flags & INSTALL_LABEL))
00160 break;
00161 if (flags & INSTALL_HASH)
00162 fprintf(stdout, "%-28s", _("Preparing..."));
00163 else
00164 printf("%s\n", _("Preparing packages for installation..."));
00165 fflush(stdout);
00166 break;
00167
00168 case RPMCALLBACK_TRANS_STOP:
00169 if (flags & INSTALL_HASH)
00170 printHash(1, 1);
00171 #ifdef FANCY_HASH
00172 progressTotal = packagesTotal;
00173 progressCurrent = 0;
00174 #endif
00175 break;
00176
00177 case RPMCALLBACK_UNINST_PROGRESS:
00178 case RPMCALLBACK_UNINST_START:
00179 case RPMCALLBACK_UNINST_STOP:
00180
00181 break;
00182 }
00183
00184 return rc;
00185 }
00186
00188 int rpmInstall(const char * rootdir, const char ** fileArgv,
00189 rpmtransFlags transFlags,
00190 rpmInstallInterfaceFlags interfaceFlags,
00191 rpmprobFilterFlags probFilter,
00192 rpmRelocation * relocations)
00193 {
00194 rpmTransactionSet ts = NULL;
00195 int notifyFlags = interfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00196 rpmdb db = NULL;
00197 const char ** pkgURL = NULL;
00198 char * pkgState = NULL;
00199 const char ** fnp;
00200 const char * fileURL = NULL;
00201 int numPkgs = 0;
00202 int numRPMS = 0;
00203 int numSRPMS = 0;
00204 int numFailed = 0;
00205 int stopInstall = 0;
00206 int dbIsOpen = 0;
00207 rpmRelocation * defaultReloc = relocations;
00208 const char ** sourceURL = NULL;
00209 int prevx;
00210 int pkgx;
00211 const char ** argv = NULL;
00212 int argc = 0;
00213 const char ** av = NULL;
00214 int ac = 0;
00215 Header h;
00216 FD_t fd;
00217 int rc;
00218 int i;
00219
00220 while (defaultReloc && defaultReloc->oldPath)
00221 defaultReloc++;
00222 if (defaultReloc && !defaultReloc->newPath) defaultReloc = NULL;
00223
00224
00225 for (fnp = fileArgv; *fnp; fnp++) {
00226 av = _free(av);
00227 ac = 0;
00228 rc = rpmGlob(*fnp, &ac, &av);
00229 if (rc || ac == 0) continue;
00230
00231 if (argc == 0)
00232 argv = xmalloc((argc+2) * sizeof(*argv));
00233 else
00234 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
00235 memcpy(argv+argc, av, ac * sizeof(*av));
00236 argc += ac;
00237 argv[argc] = NULL;
00238 }
00239 av = _free(av);
00240
00241 numPkgs = 0;
00242 prevx = 0;
00243 pkgx = 0;
00244
00245 restart:
00246
00247 if (pkgx >= numPkgs) {
00248 numPkgs = pkgx + argc;
00249 pkgURL = (pkgURL == NULL)
00250 ? xmalloc( (numPkgs + 1) * sizeof(*pkgURL))
00251 : xrealloc(pkgURL, (numPkgs + 1) * sizeof(*pkgURL));
00252 memset(pkgURL + pkgx, 0, ((argc + 1) * sizeof(*pkgURL)));
00253 pkgState = (pkgState == NULL)
00254 ? xmalloc( (numPkgs + 1) * sizeof(*pkgState))
00255 : xrealloc(pkgState, (numPkgs + 1) * sizeof(*pkgState));
00256 memset(pkgState + pkgx, 0, ((argc + 1) * sizeof(*pkgState)));
00257 }
00258
00259
00260 for (i = 0; i < argc; i++) {
00261 fileURL = _free(fileURL);
00262 fileURL = argv[i];
00263 argv[i] = NULL;
00264
00265 switch (urlIsURL(fileURL)) {
00266 case URL_IS_FTP:
00267 case URL_IS_HTTP:
00268 { const char *tfn;
00269
00270 if (rpmIsVerbose())
00271 fprintf(stdout, _("Retrieving %s\n"), fileURL);
00272
00273 { char tfnbuf[64];
00274 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
00275 mktemp(tfnbuf) ;
00276 tfn = rpmGenPath(rootdir, "%{_tmppath}/", tfnbuf);
00277 }
00278
00279
00280
00281 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
00282 rc = urlGetFile(fileURL, tfn);
00283 if (rc < 0) {
00284 rpmMessage(RPMMESS_ERROR,
00285 _("skipping %s - transfer failed - %s\n"),
00286 fileURL, ftpStrerror(rc));
00287 numFailed++;
00288 pkgURL[pkgx] = NULL;
00289 tfn = _free(tfn);
00290 break;
00291 }
00292 pkgState[pkgx] = 1;
00293 pkgURL[pkgx] = tfn;
00294 pkgx++;
00295 } break;
00296 case URL_IS_PATH:
00297 default:
00298 pkgURL[pkgx] = fileURL;
00299 fileURL = NULL;
00300 pkgx++;
00301 break;
00302 }
00303 }
00304 fileURL = _free(fileURL);
00305
00306 if (numFailed) goto exit;
00307
00308
00309 for (fnp = pkgURL+prevx; *fnp; fnp++, prevx++) {
00310 const char * fileName;
00311 rpmRC rpmrc;
00312 int isSource;
00313
00314 rpmMessage(RPMMESS_DEBUG, "============== %s\n", *fnp);
00315 (void) urlPath(*fnp, &fileName);
00316
00317
00318 fd = Fopen(*fnp, "r.ufdio");
00319 if (fd == NULL || Ferror(fd)) {
00320 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
00321 Fstrerror(fd));
00322 if (fd) Fclose(fd);
00323 numFailed++; *fnp = NULL;
00324 continue;
00325 }
00326
00327 rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
00328 Fclose(fd);
00329
00330 if (rpmrc == RPMRC_FAIL || rpmrc == RPMRC_SHORTREAD) {
00331 numFailed++; *fnp = NULL;
00332 continue;
00333 }
00334 if ((rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE) && isSource) {
00335 rpmMessage(RPMMESS_DEBUG, "\tadded source rpm[%d]\n", numSRPMS);
00336 sourceURL = (sourceURL == NULL)
00337 ? xmalloc( (numSRPMS + 2) * sizeof(*sourceURL))
00338 : xrealloc(sourceURL, (numSRPMS + 2) * sizeof(*sourceURL));
00339 sourceURL[numSRPMS++] = *fnp;
00340 *fnp = NULL;
00341 continue;
00342 }
00343 if (rpmrc == RPMRC_OK || rpmrc == RPMRC_BADSIZE) {
00344 if (!dbIsOpen) {
00345 int mode = (transFlags & RPMTRANS_FLAG_TEST)
00346 ? O_RDONLY : (O_RDWR | O_CREAT);
00347
00348 if (rpmdbOpen(rootdir, &db, mode, 0644)) {
00349 const char *dn;
00350 dn = rpmGetPath( (rootdir ? rootdir : ""),
00351 "%{_dbpath}", NULL);
00352 rpmMessage(RPMMESS_ERROR,
00353 _("cannot open Packages database in %s\n"), dn);
00354 dn = _free(dn);
00355 numFailed++; *fnp = NULL;
00356 break;
00357 }
00358 ts = rpmtransCreateSet(db, rootdir);
00359 dbIsOpen = 1;
00360 }
00361
00362 if (defaultReloc) {
00363 const char ** paths;
00364 int pft;
00365 int c;
00366
00367 if (headerGetEntry(h, RPMTAG_PREFIXES, &pft,
00368 (void **) &paths, &c) && (c == 1)) {
00369 defaultReloc->oldPath = xstrdup(paths[0]);
00370 paths = headerFreeData(paths, pft);
00371 } else {
00372 const char * name;
00373 headerNVR(h, &name, NULL, NULL);
00374 rpmMessage(RPMMESS_ERROR,
00375 _("package %s is not relocateable\n"), name);
00376 numFailed++;
00377 goto exit;
00378
00379 }
00380 }
00381
00382
00383 if (interfaceFlags & INSTALL_FRESHEN) {
00384 rpmdbMatchIterator mi;
00385 const char * name;
00386 Header oldH;
00387 int count;
00388
00389 headerNVR(h, &name, NULL, NULL);
00390 mi = rpmdbInitIterator(db, RPMTAG_NAME, name, 0);
00391 count = rpmdbGetIteratorCount(mi);
00392 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
00393 if (rpmVersionCompare(oldH, h) < 0)
00394 continue;
00395
00396 count = 0;
00397 break;
00398 }
00399 rpmdbFreeIterator(mi);
00400 if (count == 0) {
00401 headerFree(h);
00402 continue;
00403 break;
00404 }
00405
00406 }
00407
00408 rc = rpmtransAddPackage(ts, h, NULL, fileName,
00409 (interfaceFlags & INSTALL_UPGRADE) != 0,
00410 relocations);
00411 headerFree(h);
00412 if (defaultReloc)
00413 defaultReloc->oldPath = _free(defaultReloc->oldPath);
00414
00415 switch(rc) {
00416 case 0:
00417 rpmMessage(RPMMESS_DEBUG, "\tadded binary rpm[%d]\n", numRPMS);
00418 break;
00419 case 1:
00420 rpmMessage(RPMMESS_ERROR,
00421 _("error reading from file %s\n"), *fnp);
00422 numFailed++;
00423 goto exit;
00424 break;
00425 case 2:
00426 rpmMessage(RPMMESS_ERROR,
00427 _("file %s requires a newer version of RPM\n"),
00428 *fnp);
00429 numFailed++;
00430 goto exit;
00431 break;
00432 }
00433
00434 numRPMS++;
00435 continue;
00436 }
00437
00438 if (rpmrc != RPMRC_BADMAGIC) {
00439 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *fnp);
00440 numFailed++; *fnp = NULL;
00441 break;
00442 }
00443
00444
00445 fd = Fopen(*fnp, "r.fpio");
00446 if (fd == NULL || Ferror(fd)) {
00447 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *fnp,
00448 Fstrerror(fd));
00449 if (fd) Fclose(fd);
00450 numFailed++; *fnp = NULL;
00451 break;
00452 }
00453
00454
00455 rc = rpmReadPackageManifest(fd, &argc, &argv);
00456 if (rc)
00457 rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"),
00458 fileURL, Fstrerror(fd));
00459 Fclose(fd);
00460
00461
00462 if (rc == 0) {
00463 prevx++;
00464 goto restart;
00465 }
00466
00467 numFailed++; *fnp = NULL;
00468 break;
00469 }
00470
00471 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
00472 numSRPMS, numRPMS);
00473
00474 if (numFailed) goto exit;
00475
00476 if (numRPMS && !(interfaceFlags & INSTALL_NODEPS)) {
00477 struct rpmDependencyConflict * conflicts;
00478 int numConflicts;
00479
00480 if (rpmdepCheck(ts, &conflicts, &numConflicts)) {
00481 numFailed = numPkgs;
00482 stopInstall = 1;
00483 }
00484
00485 if (!stopInstall && conflicts) {
00486 rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
00487 printDepProblems(stderr, conflicts, numConflicts);
00488 rpmdepFreeConflicts(conflicts, numConflicts);
00489 numFailed = numPkgs;
00490 stopInstall = 1;
00491 }
00492 }
00493
00494 if (numRPMS && !(interfaceFlags & INSTALL_NOORDER)) {
00495 if (rpmdepOrder(ts)) {
00496 numFailed = numPkgs;
00497 stopInstall = 1;
00498 }
00499 }
00500
00501 if (numRPMS && !stopInstall) {
00502 rpmProblemSet probs = NULL;
00503
00504 #ifdef FANCY_HASH
00505 packagesTotal = numRPMS;
00506 #endif
00507 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
00508 rc = rpmRunTransactions(ts, showProgress, (void *) ((long)notifyFlags),
00509 NULL, &probs, transFlags, probFilter);
00510
00511 if (rc < 0) {
00512 numFailed += numRPMS;
00513 } else if (rc > 0) {
00514 numFailed += rc;
00515 rpmProblemSetPrint(stderr, probs);
00516 }
00517
00518 if (probs) rpmProblemSetFree(probs);
00519 }
00520
00521 if (numSRPMS && !stopInstall) {
00522 for (i = 0; i < numSRPMS; i++) {
00523 fd = Fopen(sourceURL[i], "r.ufdio");
00524 if (fd == NULL || Ferror(fd)) {
00525 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
00526 sourceURL[i], Fstrerror(fd));
00527 if (fd) Fclose(fd);
00528 continue;
00529 }
00530
00531 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
00532 rpmRC rpmrc = rpmInstallSourcePackage(rootdir, fd, NULL,
00533 showProgress, (void *) ((long)notifyFlags), NULL);
00534 if (rpmrc != RPMRC_OK) numFailed++;
00535 }
00536
00537 Fclose(fd);
00538 }
00539 }
00540
00541 exit:
00542 if (ts) rpmtransFree(ts);
00543 for (i = 0; i < numPkgs; i++) {
00544 if (pkgState[i] == 1)
00545 Unlink(pkgURL[i]);
00546 pkgURL[i] = _free(pkgURL[i]);
00547 }
00548 pkgState = _free(pkgState);
00549 pkgURL = _free(pkgURL);
00550 argv = _free(argv);
00551 if (dbIsOpen) rpmdbClose(db);
00552 return numFailed;
00553 }
00554
00555 int rpmErase(const char * rootdir, const char ** argv,
00556 rpmtransFlags transFlags,
00557 rpmEraseInterfaceFlags interfaceFlags)
00558 {
00559 rpmdb db;
00560 int mode;
00561 int count;
00562 const char ** arg;
00563 int numFailed = 0;
00564 rpmTransactionSet ts;
00565 struct rpmDependencyConflict * conflicts;
00566 int numConflicts;
00567 int stopUninstall = 0;
00568 int numPackages = 0;
00569 rpmProblemSet probs;
00570
00571 if (transFlags & RPMTRANS_FLAG_TEST)
00572 mode = O_RDONLY;
00573 else
00574 mode = O_RDWR | O_EXCL;
00575
00576 if (rpmdbOpen(rootdir, &db, mode, 0644)) {
00577 const char *dn;
00578 dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
00579 rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
00580 dn = _free(dn);
00581 return -1;
00582 }
00583
00584 ts = rpmtransCreateSet(db, rootdir);
00585 for (arg = argv; *arg; arg++) {
00586 rpmdbMatchIterator mi;
00587
00588
00589 mi = rpmdbInitIterator(db, RPMDBI_LABEL, *arg, 0);
00590 count = rpmdbGetIteratorCount(mi);
00591 if (count <= 0) {
00592 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
00593 numFailed++;
00594 } else if (!(count == 1 || (interfaceFlags & UNINSTALL_ALLMATCHES))) {
00595 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
00596 *arg);
00597 numFailed++;
00598 } else {
00599 Header h;
00600 while ((h = rpmdbNextIterator(mi)) != NULL) {
00601 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
00602 if (recOffset) {
00603 rpmtransRemovePackage(ts, recOffset);
00604 numPackages++;
00605 }
00606 }
00607 }
00608 rpmdbFreeIterator(mi);
00609 }
00610
00611 if (!(interfaceFlags & UNINSTALL_NODEPS)) {
00612 if (rpmdepCheck(ts, &conflicts, &numConflicts)) {
00613 numFailed = numPackages;
00614 stopUninstall = 1;
00615 }
00616
00617 if (!stopUninstall && conflicts) {
00618 rpmMessage(RPMMESS_ERROR, _("removing these packages would break "
00619 "dependencies:\n"));
00620 printDepProblems(stderr, conflicts, numConflicts);
00621 rpmdepFreeConflicts(conflicts, numConflicts);
00622 numFailed += numPackages;
00623 stopUninstall = 1;
00624 }
00625 }
00626
00627 if (!stopUninstall) {
00628 transFlags |= RPMTRANS_FLAG_REVERSE;
00629 numFailed += rpmRunTransactions(ts, NULL, NULL, NULL, &probs,
00630 transFlags, 0);
00631 }
00632
00633 rpmtransFree(ts);
00634 rpmdbClose(db);
00635
00636 return numFailed;
00637 }
00638
00639 int rpmInstallSource(const char * rootdir, const char * arg,
00640 const char ** specFile, char ** cookie)
00641 {
00642 FD_t fd;
00643 int rc;
00644
00645 fd = Fopen(arg, "r.ufdio");
00646 if (fd == NULL || Ferror(fd)) {
00647 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
00648 if (fd) Fclose(fd);
00649 return 1;
00650 }
00651
00652 if (rpmIsVerbose())
00653 fprintf(stdout, _("Installing %s\n"), arg);
00654
00655 { rpmRC rpmrc = rpmInstallSourcePackage(rootdir, fd, specFile, NULL, NULL,
00656 cookie);
00657 rc = (rpmrc == RPMRC_OK ? 0 : 1);
00658 }
00659 if (rc != 0) {
00660 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
00661 if (specFile && *specFile)
00662 *specFile = _free(*specFile);
00663 if (cookie && *cookie)
00664 *cookie = _free(*cookie);
00665 }
00666
00667 Fclose(fd);
00668
00669 return rc;
00670 }