00001
00005 #include "system.h"
00006
00007 #include "rpmcli.h"
00008
00009 #include "manifest.h"
00010 #include "misc.h"
00011 #include "debug.h"
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <sys/ioctl.h>
00022
00023 int fancyPercents = 0;
00024
00025
00026 static int hashesPrinted = 0;
00027
00028
00029 int packagesTotal = 0;
00030
00031 static int progressTotal = 0;
00032
00033 static int progressCurrent = 0;
00034
00035 static int checkedTTY = 0;
00036 static int countWidth = 0;
00037 static int nameWidth = 29;
00038 static int hashesTotal = 50;
00039
00040 static void checkTTY( void )
00041 {
00042 struct winsize ws;
00043
00044 if ( checkedTTY )
00045 return;
00046
00047 checkedTTY = 1;
00048
00049 if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, (char *)&ws ) < 0 )
00050 {
00051 fancyPercents = 0;
00052 }
00053 else
00054 {
00055 int w = ws.ws_col;
00056 int i;
00057 if ( w <= 2 )
00058 w = 80;
00059
00060 if ( w < 39 )
00061 {
00062 fancyPercents = 0;
00063 nameWidth = w - 2;
00064 hashesTotal = 1;
00065 return;
00066 }
00067
00068 if ( fancyPercents )
00069 {
00070 w -= 6;
00071
00072 for ( i = packagesTotal; i > 0; i /= 10 )
00073 ++countWidth;
00074
00075 nameWidth -= countWidth + 2;
00076 }
00077
00078 hashesTotal = w - 30;
00079 if ( hashesTotal > 100 )
00080 {
00081 nameWidth += (hashesTotal - 100 );
00082 hashesTotal = 100;
00083 }
00084 }
00085 }
00086
00089 static void printHash(const unsigned long amount, const unsigned long total)
00090
00091
00092 {
00093 checkTTY();
00094 if ( hashesPrinted <= hashesTotal )
00095 {
00096 int hashesNeeded = hashesTotal * (total ? (((float) amount) / total) : 1);
00097 while ( hashesNeeded > hashesPrinted )
00098 {
00099 if ( fancyPercents )
00100 {
00101 int i;
00102 for ( i = 0; i < hashesPrinted; ++i )
00103 putchar( '#' );
00104 for ( ; i < hashesTotal; ++i )
00105 putchar( ' ' );
00106 printf( "(%3d%%)", (int)(100 * (total ? (((float) amount) / total) : 1)) );
00107 for ( i = 0; i < (hashesTotal + 6); ++i )
00108 putchar( '\b' );
00109 } else
00110 putchar( '#' );
00111
00112 fflush( stdout );
00113 ++hashesPrinted;
00114 }
00115
00116 fflush( stdout );
00117 hashesPrinted = hashesNeeded;
00118
00119 if ( hashesPrinted >= hashesTotal )
00120 {
00121 if ( fancyPercents )
00122 {
00123 int i;
00124 ++progressCurrent;
00125 for ( i = 1; i < hashesPrinted; ++i )
00126 putchar( '#' );
00127 printf( " [%3d%%]\n", (int)(100 * (progressTotal ?
00128 (((float) progressCurrent) / progressTotal) : 1))) ;
00129 } else
00130 putchar( '\n' );
00131 }
00132
00133 fflush( stdout );
00134 }
00135 }
00136
00137 void * rpmShowProgress( const void * arg,
00138 const rpmCallbackType what,
00139 const unsigned long amount,
00140 const unsigned long total,
00141 const void * pkgKey,
00142 void * data)
00143
00144
00145
00146
00147 {
00148
00149 Header h = (Header) arg;
00150
00151 char * s;
00152 int flags = (int) ((long)data);
00153 void * rc = NULL;
00154 const char * filename = pkgKey;
00155 static FD_t fd = NULL;
00156
00157 switch (what) {
00158 case RPMCALLBACK_INST_OPEN_FILE:
00159 if (filename == NULL || filename[0] == '\0')
00160 return NULL;
00161 fd = Fopen(filename, "r.ufdio");
00162 if (fd)
00163 fd = fdLink(fd, "persist (showProgress)");
00164 return fd;
00165 break;
00166
00167 case RPMCALLBACK_INST_CLOSE_FILE:
00168 fd = fdFree(fd, "persist (showProgress)");
00169 if (fd) {
00170 (void) Fclose(fd);
00171 fd = NULL;
00172 }
00173 break;
00174
00175 case RPMCALLBACK_INST_START:
00176 hashesPrinted = 0;
00177 if (h == NULL || !(flags & INSTALL_LABEL))
00178 break;
00179 if (flags & INSTALL_HASH) {
00180 s = headerSprintf(h, "%{NAME}",
00181 rpmTagTable, rpmHeaderFormats, NULL);
00182 if ( fancyPercents )
00183 printf( "%*d: %-*.*s", countWidth, progressCurrent + 1, nameWidth, nameWidth, s );
00184 else
00185 printf("%-*.*s", nameWidth, nameWidth, s);
00186 (void) fflush(stdout);
00187 s = _free(s);
00188 } else {
00189 s = headerSprintf(h, "%{NAME}-%{VERSION}-%{RELEASE}",
00190 rpmTagTable, rpmHeaderFormats, NULL);
00191 fprintf(stdout, "%s\n", s);
00192 (void) fflush(stdout);
00193 s = _free(s);
00194 }
00195 break;
00196
00197 case RPMCALLBACK_TRANS_PROGRESS:
00198 case RPMCALLBACK_INST_PROGRESS:
00199 if (flags & INSTALL_PERCENT)
00200 fprintf(stdout, "%%%% %f\n", (double) (total
00201 ? ((((float) amount) / total) * 100)
00202 : 100.0));
00203 else if (flags & INSTALL_HASH)
00204 printHash(amount, total);
00205 (void) fflush(stdout);
00206 break;
00207
00208 case RPMCALLBACK_TRANS_START:
00209 hashesPrinted = 0;
00210 progressTotal = 1;
00211 progressCurrent = 0;
00212 if (!(flags & INSTALL_LABEL))
00213 break;
00214 if (flags & INSTALL_HASH) {
00215 int width;
00216 checkTTY();
00217 if ( fancyPercents )
00218 width = countWidth + 2 + nameWidth;
00219 else
00220 width = nameWidth;
00221 printf( "%-*.*s", width, width, _("Preparing...") );
00222 } else
00223 printf("%s\n", _("Preparing packages for installation..."));
00224 (void) fflush(stdout);
00225 break;
00226
00227 case RPMCALLBACK_TRANS_STOP:
00228 if (flags & INSTALL_HASH)
00229 printHash(1, 1);
00230 progressTotal = packagesTotal;
00231 progressCurrent = 0;
00232 break;
00233
00234 case RPMCALLBACK_UNINST_PROGRESS:
00235 case RPMCALLBACK_UNINST_START:
00236 case RPMCALLBACK_UNINST_STOP:
00237 case RPMCALLBACK_UNPACK_ERROR:
00238 case RPMCALLBACK_CPIO_ERROR:
00239 default:
00240
00241 break;
00242 }
00243
00244 return rc;
00245 }
00246
00247 typedef const char * str_t;
00248
00249 struct rpmEIU {
00250 rpmTransactionSet ts;
00251 rpmdb db;
00252 Header h;
00253 FD_t fd;
00254 int numFailed;
00255 int numPkgs;
00256 str_t * pkgURL;
00257 str_t * fnp;
00258 char * pkgState;
00259 int prevx;
00260 int pkgx;
00261 int numRPMS;
00262 int numSRPMS;
00263 str_t * sourceURL;
00264 int isSource;
00265 int argc;
00266 str_t * argv;
00267 rpmRelocation * relocations;
00268 rpmRC rpmrc;
00269 };
00270
00272 int rpmInstall(const char * rootdir, const char ** fileArgv,
00273 rpmtransFlags transFlags,
00274 rpmInstallInterfaceFlags interfaceFlags,
00275 rpmprobFilterFlags probFilter,
00276 rpmRelocation * relocations)
00277 {
00278 struct rpmEIU * eiu = alloca(sizeof(*eiu));
00279 int notifyFlags = interfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00280 const char * fileURL = NULL;
00281 int stopInstall = 0;
00282 const char ** av = NULL;
00283 int ac = 0;
00284 int rc;
00285 int xx;
00286 int i;
00287
00288 if (fileArgv == NULL) return 0;
00289
00290 memset(eiu, 0, sizeof(*eiu));
00291 eiu->numPkgs = 0;
00292 eiu->prevx = 0;
00293 eiu->pkgx = 0;
00294
00295 if ((eiu->relocations = relocations) != NULL) {
00296 while (eiu->relocations->oldPath)
00297 eiu->relocations++;
00298 if (eiu->relocations->newPath == NULL)
00299 eiu->relocations = NULL;
00300 }
00301
00302
00303
00304
00305 for (eiu->fnp = fileArgv; *eiu->fnp != NULL; eiu->fnp++) {
00306
00307 av = _free(av); ac = 0;
00308 rc = rpmGlob(*eiu->fnp, &ac, &av);
00309 if (rc || ac == 0) continue;
00310
00311 eiu->argv = xrealloc(eiu->argv, (eiu->argc+ac+1) * sizeof(*eiu->argv));
00312 memcpy(eiu->argv+eiu->argc, av, ac * sizeof(*av));
00313 eiu->argc += ac;
00314 eiu->argv[eiu->argc] = NULL;
00315 }
00316
00317 av = _free(av); ac = 0;
00318
00319 restart:
00320
00321 if (eiu->pkgx >= eiu->numPkgs) {
00322 eiu->numPkgs = eiu->pkgx + eiu->argc;
00323 eiu->pkgURL = xrealloc(eiu->pkgURL,
00324 (eiu->numPkgs + 1) * sizeof(*eiu->pkgURL));
00325 memset(eiu->pkgURL + eiu->pkgx, 0,
00326 ((eiu->argc + 1) * sizeof(*eiu->pkgURL)));
00327 eiu->pkgState = xrealloc(eiu->pkgState,
00328 (eiu->numPkgs + 1) * sizeof(*eiu->pkgState));
00329 memset(eiu->pkgState + eiu->pkgx, 0,
00330 ((eiu->argc + 1) * sizeof(*eiu->pkgState)));
00331 }
00332
00333
00334 for (i = 0; i < eiu->argc; i++) {
00335 fileURL = _free(fileURL);
00336 fileURL = eiu->argv[i];
00337 eiu->argv[i] = NULL;
00338
00339 switch (urlIsURL(fileURL)) {
00340 case URL_IS_FTP:
00341 case URL_IS_HTTP:
00342 { const char *tfn;
00343
00344 if (rpmIsVerbose())
00345 fprintf(stdout, _("Retrieving %s\n"), fileURL);
00346
00347 { char tfnbuf[64];
00348 strcpy(tfnbuf, "rpm-xfer.XXXXXX");
00349 (void) mktemp(tfnbuf);
00350 tfn = rpmGenPath(rootdir, "%{_tmppath}/", tfnbuf);
00351 }
00352
00353
00354
00355 rpmMessage(RPMMESS_DEBUG, _(" ... as %s\n"), tfn);
00356 rc = urlGetFile(fileURL, tfn);
00357 if (rc < 0) {
00358 rpmMessage(RPMMESS_ERROR,
00359 _("skipping %s - transfer failed - %s\n"),
00360 fileURL, ftpStrerror(rc));
00361 eiu->numFailed++;
00362 eiu->pkgURL[eiu->pkgx] = NULL;
00363 tfn = _free(tfn);
00364 break;
00365 }
00366 eiu->pkgState[eiu->pkgx] = 1;
00367 eiu->pkgURL[eiu->pkgx] = tfn;
00368 eiu->pkgx++;
00369 } break;
00370 case URL_IS_PATH:
00371 default:
00372 eiu->pkgURL[eiu->pkgx] = fileURL;
00373 fileURL = NULL;
00374 eiu->pkgx++;
00375 break;
00376 }
00377 }
00378 fileURL = _free(fileURL);
00379
00380 if (eiu->numFailed) goto exit;
00381
00382
00383 for (eiu->fnp = eiu->pkgURL+eiu->prevx;
00384 *eiu->fnp != NULL;
00385 eiu->fnp++, eiu->prevx++)
00386 {
00387 const char * fileName;
00388
00389 rpmMessage(RPMMESS_DEBUG, "============== %s\n", *eiu->fnp);
00390 (void) urlPath(*eiu->fnp, &fileName);
00391
00392
00393 eiu->fd = Fopen(*eiu->fnp, "r.ufdio");
00394 if (eiu->fd == NULL || Ferror(eiu->fd)) {
00395 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
00396 Fstrerror(eiu->fd));
00397 if (eiu->fd) {
00398 xx = Fclose(eiu->fd);
00399 eiu->fd = NULL;
00400 }
00401 eiu->numFailed++; *eiu->fnp = NULL;
00402 continue;
00403 }
00404
00405
00406 eiu->rpmrc = rpmReadPackageHeader(eiu->fd, &eiu->h,
00407 &eiu->isSource, NULL, NULL);
00408
00409 xx = Fclose(eiu->fd);
00410 eiu->fd = NULL;
00411
00412 if (eiu->rpmrc == RPMRC_FAIL || eiu->rpmrc == RPMRC_SHORTREAD) {
00413 eiu->numFailed++; *eiu->fnp = NULL;
00414 continue;
00415 }
00416
00417 if (eiu->isSource &&
00418 (eiu->rpmrc == RPMRC_OK || eiu->rpmrc == RPMRC_BADSIZE))
00419 {
00420 rpmMessage(RPMMESS_DEBUG, "\tadded source package [%d]\n",
00421 eiu->numSRPMS);
00422 eiu->sourceURL = xrealloc(eiu->sourceURL,
00423 (eiu->numSRPMS + 2) * sizeof(*eiu->sourceURL));
00424 eiu->sourceURL[eiu->numSRPMS] = *eiu->fnp;
00425 *eiu->fnp = NULL;
00426 eiu->numSRPMS++;
00427 eiu->sourceURL[eiu->numSRPMS] = NULL;
00428 continue;
00429 }
00430
00431 if (eiu->rpmrc == RPMRC_OK || eiu->rpmrc == RPMRC_BADSIZE) {
00432 if (eiu->db == NULL) {
00433 int mode = (transFlags & RPMTRANS_FLAG_TEST)
00434 ? O_RDONLY : (O_RDWR | O_CREAT);
00435
00436 if (rpmdbOpen(rootdir, &eiu->db, mode, 0644)) {
00437 const char *dn;
00438 dn = rpmGetPath( (rootdir ? rootdir : ""),
00439 "%{_dbpath}", NULL);
00440 rpmMessage(RPMMESS_ERROR,
00441 _("cannot open Packages database in %s\n"), dn);
00442 dn = _free(dn);
00443 eiu->numFailed++; *eiu->fnp = NULL;
00444 break;
00445 }
00446
00447 eiu->ts = rpmtransCreateSet(eiu->db, rootdir);
00448
00449 }
00450
00451 if (eiu->relocations) {
00452 const char ** paths;
00453 int pft;
00454 int c;
00455
00456 if (headerGetEntry(eiu->h, RPMTAG_PREFIXES, &pft,
00457 (void **) &paths, &c) && (c == 1)) {
00458 eiu->relocations->oldPath = xstrdup(paths[0]);
00459 paths = headerFreeData(paths, pft);
00460 } else {
00461 const char * name;
00462 xx = headerNVR(eiu->h, &name, NULL, NULL);
00463 rpmMessage(RPMMESS_ERROR,
00464 _("package %s is not relocateable\n"), name);
00465 eiu->numFailed++;
00466 goto exit;
00467
00468 }
00469 }
00470
00471
00472 if (interfaceFlags & INSTALL_FRESHEN) {
00473 rpmdbMatchIterator mi;
00474 const char * name;
00475 Header oldH;
00476 int count;
00477
00478 xx = headerNVR(eiu->h, &name, NULL, NULL);
00479
00480 mi = rpmdbInitIterator(eiu->db, RPMTAG_NAME, name, 0);
00481
00482 count = rpmdbGetIteratorCount(mi);
00483 while ((oldH = rpmdbNextIterator(mi)) != NULL) {
00484 if (rpmVersionCompare(oldH, eiu->h) < 0)
00485 continue;
00486
00487 count = 0;
00488 break;
00489 }
00490 mi = rpmdbFreeIterator(mi);
00491 if (count == 0) {
00492 eiu->h = headerFree(eiu->h);
00493 continue;
00494 }
00495
00496 }
00497
00498 rc = rpmtransAddPackage(eiu->ts, eiu->h, NULL, fileName,
00499 (interfaceFlags & INSTALL_UPGRADE) != 0,
00500 relocations);
00501
00502 eiu->h = headerFree(eiu->h);
00503 if (eiu->relocations)
00504 eiu->relocations->oldPath = _free(eiu->relocations->oldPath);
00505
00506 switch(rc) {
00507 case 0:
00508 rpmMessage(RPMMESS_DEBUG, "\tadded binary package [%d]\n",
00509 eiu->numRPMS);
00510 break;
00511 case 1:
00512 rpmMessage(RPMMESS_ERROR,
00513 _("error reading from file %s\n"), *eiu->fnp);
00514 eiu->numFailed++;
00515 goto exit;
00516 break;
00517 case 2:
00518 rpmMessage(RPMMESS_ERROR,
00519 _("file %s requires a newer version of RPM\n"),
00520 *eiu->fnp);
00521 eiu->numFailed++;
00522 goto exit;
00523 break;
00524 }
00525
00526 eiu->numRPMS++;
00527 continue;
00528 }
00529
00530 if (eiu->rpmrc != RPMRC_BADMAGIC) {
00531 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), *eiu->fnp);
00532 eiu->numFailed++; *eiu->fnp = NULL;
00533 break;
00534 }
00535
00536
00537 eiu->fd = Fopen(*eiu->fnp, "r.fpio");
00538 if (eiu->fd == NULL || Ferror(eiu->fd)) {
00539 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), *eiu->fnp,
00540 Fstrerror(eiu->fd));
00541 if (eiu->fd) {
00542 xx = Fclose(eiu->fd);
00543 eiu->fd = NULL;
00544 }
00545 eiu->numFailed++; *eiu->fnp = NULL;
00546 break;
00547 }
00548
00549
00550 rc = rpmReadPackageManifest(eiu->fd, &eiu->argc, &eiu->argv);
00551 if (rc)
00552 rpmError(RPMERR_MANIFEST, _("%s: read manifest failed: %s\n"),
00553 *eiu->fnp, Fstrerror(eiu->fd));
00554 xx = Fclose(eiu->fd);
00555 eiu->fd = NULL;
00556
00557
00558 if (rc == 0) {
00559 eiu->prevx++;
00560 goto restart;
00561 }
00562
00563 eiu->numFailed++; *eiu->fnp = NULL;
00564 break;
00565 }
00566
00567 rpmMessage(RPMMESS_DEBUG, _("found %d source and %d binary packages\n"),
00568 eiu->numSRPMS, eiu->numRPMS);
00569
00570 if (eiu->numFailed) goto exit;
00571
00572 if (eiu->numRPMS && !(interfaceFlags & INSTALL_NODEPS)) {
00573 rpmDependencyConflict conflicts;
00574 int numConflicts;
00575
00576 if (rpmdepCheck(eiu->ts, &conflicts, &numConflicts)) {
00577 eiu->numFailed = eiu->numPkgs;
00578 stopInstall = 1;
00579 }
00580
00581
00582 if (!stopInstall && conflicts) {
00583 rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
00584 printDepProblems(stderr, conflicts, numConflicts);
00585 conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
00586 eiu->numFailed = eiu->numPkgs;
00587 stopInstall = 1;
00588 }
00589
00590 }
00591
00592 if (eiu->numRPMS && !(interfaceFlags & INSTALL_NOORDER)) {
00593 if (rpmdepOrder(eiu->ts)) {
00594 eiu->numFailed = eiu->numPkgs;
00595 stopInstall = 1;
00596 }
00597 }
00598
00599 if (eiu->numRPMS && !stopInstall) {
00600 rpmProblemSet probs = NULL;
00601
00602 packagesTotal = eiu->numRPMS + eiu->numSRPMS;
00603
00604 rpmMessage(RPMMESS_DEBUG, _("installing binary packages\n"));
00605 rc = rpmRunTransactions(eiu->ts, rpmShowProgress,
00606 (void *) ((long)notifyFlags),
00607 NULL, &probs, transFlags, probFilter);
00608
00609 if (rc < 0) {
00610 eiu->numFailed += eiu->numRPMS;
00611 } else if (rc > 0) {
00612 eiu->numFailed += rc;
00613 rpmProblemSetPrint(stderr, probs);
00614 }
00615
00616 if (probs != NULL) rpmProblemSetFree(probs);
00617 }
00618
00619 if (eiu->numSRPMS && !stopInstall) {
00620 if (eiu->sourceURL != NULL)
00621 for (i = 0; i < eiu->numSRPMS; i++) {
00622 if (eiu->sourceURL[i] == NULL) continue;
00623 eiu->fd = Fopen(eiu->sourceURL[i], "r.ufdio");
00624 if (eiu->fd == NULL || Ferror(eiu->fd)) {
00625 rpmMessage(RPMMESS_ERROR, _("cannot open file %s: %s\n"),
00626 eiu->sourceURL[i], Fstrerror(eiu->fd));
00627 if (eiu->fd) {
00628 xx = Fclose(eiu->fd);
00629 eiu->fd = NULL;
00630 }
00631 continue;
00632 }
00633
00634 if (!(transFlags & RPMTRANS_FLAG_TEST)) {
00635 eiu->rpmrc = rpmInstallSourcePackage(rootdir, eiu->fd, NULL,
00636 rpmShowProgress, (void *) ((long)notifyFlags), NULL);
00637 if (eiu->rpmrc != RPMRC_OK) eiu->numFailed++;
00638 }
00639
00640 xx = Fclose(eiu->fd);
00641 eiu->fd = NULL;
00642 }
00643 }
00644
00645 exit:
00646 eiu->ts = rpmtransFree(eiu->ts);
00647 if (eiu->pkgURL != NULL)
00648 for (i = 0; i < eiu->numPkgs; i++) {
00649 if (eiu->pkgURL[i] == NULL) continue;
00650 if (eiu->pkgState[i] == 1)
00651 (void) Unlink(eiu->pkgURL[i]);
00652 eiu->pkgURL[i] = _free(eiu->pkgURL[i]);
00653 }
00654 eiu->pkgState = _free(eiu->pkgState);
00655 eiu->pkgURL = _free(eiu->pkgURL);
00656 eiu->argv = _free(eiu->argv);
00657 if (eiu->db != NULL) {
00658 xx = rpmdbClose(eiu->db);
00659 eiu->db = NULL;
00660 }
00661 return eiu->numFailed;
00662 }
00663
00664 int rpmErase(const char * rootdir, const char ** argv,
00665 rpmtransFlags transFlags,
00666 rpmEraseInterfaceFlags interfaceFlags)
00667 {
00668 rpmdb db;
00669 int mode;
00670 int count;
00671 const char ** arg;
00672 int numFailed = 0;
00673 rpmTransactionSet ts;
00674 rpmDependencyConflict conflicts;
00675 int numConflicts;
00676 int stopUninstall = 0;
00677 int numPackages = 0;
00678 rpmProblemSet probs;
00679
00680 if (argv == NULL) return 0;
00681
00682 if (transFlags & RPMTRANS_FLAG_TEST)
00683 mode = O_RDONLY;
00684 else
00685 mode = O_RDWR | O_EXCL;
00686
00687 if (rpmdbOpen(rootdir, &db, mode, 0644)) {
00688 const char *dn;
00689 dn = rpmGetPath( (rootdir ? rootdir : ""), "%{_dbpath}", NULL);
00690 rpmMessage(RPMMESS_ERROR, _("cannot open %s/packages.rpm\n"), dn);
00691 dn = _free(dn);
00692 return -1;
00693 }
00694
00695 ts = rpmtransCreateSet(db, rootdir);
00696 for (arg = argv; *arg; arg++) {
00697 rpmdbMatchIterator mi;
00698
00699
00700 mi = rpmdbInitIterator(db, RPMDBI_LABEL, *arg, 0);
00701 count = rpmdbGetIteratorCount(mi);
00702 if (count <= 0) {
00703 rpmMessage(RPMMESS_ERROR, _("package %s is not installed\n"), *arg);
00704 numFailed++;
00705 } else if (!(count == 1 || (interfaceFlags & UNINSTALL_ALLMATCHES))) {
00706 rpmMessage(RPMMESS_ERROR, _("\"%s\" specifies multiple packages\n"),
00707 *arg);
00708 numFailed++;
00709 } else {
00710 Header h;
00711 while ((h = rpmdbNextIterator(mi)) != NULL) {
00712 unsigned int recOffset = rpmdbGetIteratorOffset(mi);
00713 if (recOffset) {
00714 (void) rpmtransRemovePackage(ts, recOffset);
00715 numPackages++;
00716 }
00717 }
00718 }
00719 mi = rpmdbFreeIterator(mi);
00720 }
00721
00722 if (!(interfaceFlags & UNINSTALL_NODEPS)) {
00723 if (rpmdepCheck(ts, &conflicts, &numConflicts)) {
00724 numFailed = numPackages;
00725 stopUninstall = 1;
00726 }
00727
00728
00729 if (!stopUninstall && conflicts) {
00730 rpmMessage(RPMMESS_ERROR, _("removing these packages would break "
00731 "dependencies:\n"));
00732 printDepProblems(stderr, conflicts, numConflicts);
00733 conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
00734 numFailed += numPackages;
00735 stopUninstall = 1;
00736 }
00737
00738 }
00739
00740 if (!stopUninstall) {
00741 transFlags |= RPMTRANS_FLAG_REVERSE;
00742 numFailed += rpmRunTransactions(ts, NULL, NULL, NULL, &probs,
00743 transFlags, 0);
00744 }
00745
00746 ts = rpmtransFree(ts);
00747 (void) rpmdbClose(db);
00748
00749 return numFailed;
00750 }
00751
00752 int rpmInstallSource(const char * rootdir, const char * arg,
00753 const char ** specFile, char ** cookie)
00754 {
00755 FD_t fd;
00756 int rc;
00757
00758 fd = Fopen(arg, "r.ufdio");
00759 if (fd == NULL || Ferror(fd)) {
00760 rpmMessage(RPMMESS_ERROR, _("cannot open %s: %s\n"), arg, Fstrerror(fd));
00761 if (fd) (void) Fclose(fd);
00762 return 1;
00763 }
00764
00765 if (rpmIsVerbose())
00766 fprintf(stdout, _("Installing %s\n"), arg);
00767
00768 {
00769
00770 rpmRC rpmrc = rpmInstallSourcePackage(rootdir, fd, specFile, NULL, NULL,
00771 cookie);
00772
00773 rc = (rpmrc == RPMRC_OK ? 0 : 1);
00774 }
00775 if (rc != 0) {
00776 rpmMessage(RPMMESS_ERROR, _("%s cannot be installed\n"), arg);
00777
00778 if (specFile && *specFile)
00779 *specFile = _free(*specFile);
00780 if (cookie && *cookie)
00781 *cookie = _free(*cookie);
00782
00783 }
00784
00785 (void) Fclose(fd);
00786
00787 return rc;
00788 }
00789
00790
00791 static int reverse = -1;
00792
00795 static int IDTintcmp(const void * a, const void * b)
00796
00797 {
00798
00799 IDT ap = (IDT)a;
00800 IDT bp = (IDT)b;
00801
00802 int rc = ((int)ap->val.u32 - (int)bp->val.u32);
00803
00804 if (rc)
00805 return ( reverse * rc );
00806 return ( strcmp(ap->n, bp->n) );
00807 }
00808
00809 IDTX IDTXfree(IDTX idtx)
00810 {
00811 if (idtx) {
00812 int i;
00813 if (idtx->idt)
00814 for (i = 0; i < idtx->nidt; i++) {
00815 IDT idt = idtx->idt + i;
00816 idt->h = headerFree(idt->h);
00817 idt->key = _free(idt->key);
00818 }
00819 idtx->idt = _free(idtx->idt);
00820 idtx = _free(idtx);
00821 }
00822 return NULL;
00823 }
00824
00825 IDTX IDTXnew(void)
00826 {
00827 IDTX idtx = xcalloc(1, sizeof(*idtx));
00828 idtx->delta = 10;
00829 idtx->size = sizeof(*((IDT)0));
00830 return idtx;
00831 }
00832
00833 IDTX IDTXgrow(IDTX idtx, int need)
00834 {
00835 if (need < 0) return NULL;
00836 if (idtx == NULL)
00837 idtx = IDTXnew();
00838 if (need == 0) return idtx;
00839
00840 if ((idtx->nidt + need) > idtx->alloced) {
00841 while (need > 0) {
00842 idtx->alloced += idtx->delta;
00843 need -= idtx->delta;
00844 }
00845 idtx->idt = xrealloc(idtx->idt, (idtx->alloced * idtx->size) );
00846 }
00847 return idtx;
00848 }
00849
00850 IDTX IDTXsort(IDTX idtx)
00851 {
00852 if (idtx != NULL && idtx->idt != NULL && idtx->nidt > 0)
00853 qsort(idtx->idt, idtx->nidt, idtx->size, IDTintcmp);
00854 return idtx;
00855 }
00856
00857 IDTX IDTXload(rpmdb db, rpmTag tag)
00858 {
00859 IDTX idtx = NULL;
00860 rpmdbMatchIterator mi;
00861 HGE_t hge = (HGE_t) headerGetEntry;
00862 Header h;
00863
00864 mi = rpmdbInitIterator(db, tag, NULL, 0);
00865
00866 while ((h = rpmdbNextIterator(mi)) != NULL) {
00867 rpmTagType type = RPM_NULL_TYPE;
00868 int_32 count = 0;
00869 int_32 * tidp;
00870
00871 tidp = NULL;
00872 if (!hge(h, tag, &type, (void **)&tidp, &count) || tidp == NULL)
00873 continue;
00874
00875 if (type == RPM_INT32_TYPE && (*tidp == 0 || *tidp == -1))
00876 continue;
00877
00878 idtx = IDTXgrow(idtx, 1);
00879 if (idtx == NULL)
00880 continue;
00881 if (idtx->idt == NULL)
00882 continue;
00883
00884 { IDT idt;
00885
00886 idt = idtx->idt + idtx->nidt;
00887
00888 idt->h = headerLink(h);
00889 (void) headerNVR(idt->h, &idt->n, &idt->v, &idt->r);
00890 idt->key = NULL;
00891 idt->instance = rpmdbGetIteratorOffset(mi);
00892 idt->val.u32 = *tidp;
00893 }
00894 idtx->nidt++;
00895 }
00896
00897 mi = rpmdbFreeIterator(mi);
00898
00899 return IDTXsort(idtx);
00900 }
00901
00902 IDTX IDTXglob(const char * globstr, rpmTag tag)
00903 {
00904 IDTX idtx = NULL;
00905 HGE_t hge = (HGE_t) headerGetEntry;
00906 Header h;
00907 int_32 * tidp;
00908 FD_t fd;
00909 const char ** av = NULL;
00910 int ac = 0;
00911 int rc;
00912 int i;
00913
00914 av = NULL; ac = 0;
00915 rc = rpmGlob(globstr, &ac, &av);
00916
00917 if (rc == 0)
00918 for (i = 0; i < ac; i++) {
00919 rpmTagType type;
00920 int_32 count;
00921 int isSource;
00922 rpmRC rpmrc;
00923
00924 fd = Fopen(av[i], "r.ufdio");
00925 if (fd == NULL || Ferror(fd)) {
00926 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), av[i],
00927 Fstrerror(fd));
00928 if (fd) (void) Fclose(fd);
00929 continue;
00930 }
00931
00932
00933 rpmrc = rpmReadPackageHeader(fd, &h, &isSource, NULL, NULL);
00934
00935 if (rpmrc != RPMRC_OK || isSource) {
00936 (void) Fclose(fd);
00937 continue;
00938 }
00939
00940 tidp = NULL;
00941
00942 if (hge(h, tag, &type, (void **) &tidp, &count) && tidp) {
00943
00944 idtx = IDTXgrow(idtx, 1);
00945 if (idtx == NULL || idtx->idt == NULL) {
00946 h = headerFree(h);
00947 (void) Fclose(fd);
00948 continue;
00949 }
00950 { IDT idt;
00951 idt = idtx->idt + idtx->nidt;
00952 idt->h = headerLink(h);
00953 (void) headerNVR(idt->h, &idt->n, &idt->v, &idt->r);
00954 idt->key = xstrdup(av[i]);
00955 idt->instance = 0;
00956 idt->val.u32 = *tidp;
00957 }
00958 idtx->nidt++;
00959 }
00960
00961
00962 h = headerFree(h);
00963 (void) Fclose(fd);
00964 }
00965
00966 for (i = 0; i < ac; i++)
00967 av[i] = _free(av[i]);
00968 av = _free(av); ac = 0;
00969
00970 return IDTXsort(idtx);
00971 }
00972
00973 int rpmRollback(struct rpmInstallArguments_s * ia, const char ** argv)
00974 {
00975 rpmdb db = NULL;
00976 rpmTransactionSet ts = NULL;
00977 rpmDependencyConflict conflicts = NULL;
00978 int numConflicts = 0;
00979 rpmProblemSet probs = NULL;
00980 IDTX itids = NULL;
00981 IDTX rtids = NULL;
00982 unsigned thistid = 0xffffffff;
00983 unsigned prevtid;
00984 time_t tid;
00985 IDT rp;
00986 int nrids = 0;
00987 IDT ip;
00988 int niids = 0;
00989 int packagesIn;
00990 int packagesOut;
00991 int rc;
00992 int i;
00993 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
00994
00995 if (argv != NULL && *argv != NULL) {
00996 rc = -1;
00997 goto exit;
00998 }
00999
01000 rc = rpmdbOpen(ia->rootdir, &db, O_RDWR, 0644);
01001 if (rc != 0)
01002 goto exit;
01003
01004 itids = IDTXload(db, RPMTAG_INSTALLTID);
01005 if (itids != NULL) {
01006 ip = itids->idt;
01007 niids = itids->nidt;
01008 } else {
01009 ip = NULL;
01010 niids = 0;
01011 }
01012
01013 { const char * globstr = rpmExpand("%{_repackage_dir}/*.rpm", NULL);
01014 if (globstr == NULL || *globstr == '%') {
01015 globstr = _free(globstr);
01016 rc = -1;
01017 goto exit;
01018 }
01019 rtids = IDTXglob(globstr, RPMTAG_REMOVETID);
01020 if (rtids != NULL) {
01021 rp = rtids->idt;
01022 nrids = rtids->nidt;
01023 } else {
01024 rp = NULL;
01025 nrids = 0;
01026 }
01027 globstr = _free(globstr);
01028 }
01029
01030
01031 do {
01032 prevtid = thistid;
01033 rc = 0;
01034 packagesTotal = 0;
01035 packagesIn = 0;
01036 packagesOut = 0;
01037 ia->installInterfaceFlags &= ~ifmask;
01038
01039
01040 thistid = 0;
01041 if (ip != NULL && ip->val.u32 > thistid)
01042 thistid = ip->val.u32;
01043 if (rp != NULL && rp->val.u32 > thistid)
01044 thistid = rp->val.u32;
01045
01046
01047 if (thistid == 0 || thistid < ia->rbtid)
01048 break;
01049
01050 ts = rpmtransCreateSet(db, ia->rootdir);
01051
01052
01053 while (rp != NULL && rp->val.u32 == thistid) {
01054
01055 rpmMessage(RPMMESS_DEBUG, "\t+++ %s-%s-%s\t(from %s)\n", rp->n, rp->v, rp->r, basename(rp->key));
01056
01057 if (!(ia->installInterfaceFlags & ifmask))
01058 ia->installInterfaceFlags |= INSTALL_INSTALL;
01059
01060 rc = rpmtransAddPackage(ts, rp->h, NULL, rp->key,
01061 (ia->installInterfaceFlags & INSTALL_UPGRADE) != 0,
01062 ia->relocations);
01063 if (rc != 0)
01064 goto exit;
01065
01066 packagesTotal++;
01067 packagesIn++;
01068
01069 #ifdef NOTYET
01070 rp->h = headerFree(rp->h);
01071 #endif
01072 nrids--;
01073 if (nrids > 0)
01074 rp++;
01075 else
01076 rp = NULL;
01077 }
01078
01079
01080
01081
01082
01083 if (packagesIn == 0)
01084 break;
01085
01086
01087 while (ip != NULL && ip->val.u32 == thistid) {
01088
01089 rpmMessage(RPMMESS_DEBUG,
01090 "\t--- %s-%s-%s\t(from rpmdb instance #%u)\n", ip->n, ip->v, ip->r, ip->instance);
01091
01092 if (!(ia->installInterfaceFlags & ifmask))
01093 ia->installInterfaceFlags |= INSTALL_ERASE;
01094
01095 rc = rpmtransRemovePackage(ts, ip->instance);
01096 if (rc != 0)
01097 goto exit;
01098
01099 packagesTotal++;
01100 packagesOut++;
01101
01102 #ifdef NOTYET
01103 ip->instance = 0;
01104 #endif
01105 niids--;
01106 if (niids > 0)
01107 ip++;
01108 else
01109 ip = NULL;
01110 }
01111
01112
01113 if (packagesTotal <= 0)
01114 break;
01115
01116 tid = (time_t)thistid;
01117 rpmMessage(RPMMESS_DEBUG, _("rollback (+%d,-%d) packages to %s"),
01118 packagesIn, packagesOut, ctime(&tid));
01119
01120 conflicts = NULL;
01121 numConflicts = 0;
01122 rc = rpmdepCheck(ts, &conflicts, &numConflicts);
01123 if (rc != 0) {
01124 rpmMessage(RPMMESS_ERROR, _("failed dependencies:\n"));
01125 printDepProblems(stderr, conflicts, numConflicts);
01126 conflicts = rpmdepFreeConflicts(conflicts, numConflicts);
01127 goto exit;
01128 }
01129
01130 rc = rpmdepOrder(ts);
01131 if (rc != 0)
01132 goto exit;
01133
01134 probs = NULL;
01135 rc = rpmRunTransactions(ts, rpmShowProgress,
01136 (void *) ((long)ia->installInterfaceFlags),
01137 NULL, &probs, ia->transFlags,
01138 (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE));
01139 if (rc > 0) {
01140 rpmProblemSetPrint(stderr, probs);
01141 if (probs != NULL) rpmProblemSetFree(probs);
01142 probs = NULL;
01143 }
01144 if (rc)
01145 goto exit;
01146
01147 ts = rpmtransFree(ts);
01148
01149
01150 if (!rpmIsDebug())
01151 for (i = 0; i < rtids->nidt; i++) {
01152 IDT rrp = rtids->idt + i;
01153 if (rrp->val.u32 != thistid)
01154 continue;
01155 (void) unlink(rrp->key);
01156 }
01157
01158 } while (1);
01159
01160 exit:
01161 ts = rpmtransFree(ts);
01162
01163 if (db != NULL) (void) rpmdbClose(db);
01164
01165 rtids = IDTXfree(rtids);
01166 itids = IDTXfree(itids);
01167
01168 return rc;
01169 }