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