rpm 5.2.1
|
00001 00005 #include "system.h" 00006 00007 #include <rpmio.h> 00008 #include <rpmiotypes.h> 00009 #include <rpmcb.h> 00010 #include <argv.h> 00011 00012 #include <rpmtypes.h> 00013 #include <rpmtag.h> 00014 #include <pkgio.h> 00015 #include <rpmdb.h> 00016 00017 #include <rpmds.h> 00018 #include "manifest.h" 00019 #include "misc.h" /* XXX rpmGlob() */ 00020 00021 #define _RPMTE_INTERNAL /* XXX findErases needs rpmte internals. */ 00022 #define _RPMTS_INTERNAL /* XXX ts->teErase, ts->probs */ 00023 #define _RPMTS_PRINT 00024 #include <rpmgi.h> /* XXX rpmgiEscapeSpaces */ 00025 00026 #include <rpmcli.h> 00027 #define _RPMROLLBACK_INTERNAL 00028 #include <rpmrollback.h> 00029 00030 #include "debug.h" 00031 00032 /*@access FD_t @*/ /* XXX void * arg */ 00033 /*@access rpmts @*/ 00034 /*@access rpmte @*/ /* XXX p->hdrid, p->pkgid, p->NEVRA */ 00035 /*@access IDTX @*/ 00036 /*@access IDT @*/ 00037 00038 /*@unchecked@*/ 00039 static int reverse = -1; 00040 00043 static int IDTintcmp(const void * a, const void * b) 00044 /*@*/ 00045 { 00046 /*@-castexpose@*/ 00047 return ( reverse * (((IDT)a)->val.u32 - ((IDT)b)->val.u32) ); 00048 /*@=castexpose@*/ 00049 } 00050 00051 IDTX IDTXfree(IDTX idtx) 00052 { 00053 if (idtx) { 00054 int i; 00055 if (idtx->idt) 00056 for (i = 0; i < idtx->nidt; i++) { 00057 IDT idt = idtx->idt + i; 00058 (void)headerFree(idt->h); 00059 idt->h = NULL; 00060 idt->key = _free(idt->key); 00061 } 00062 idtx->idt = _free(idtx->idt); 00063 idtx = _free(idtx); 00064 } 00065 return NULL; 00066 } 00067 00068 IDTX IDTXnew(void) 00069 { 00070 IDTX idtx = xcalloc(1, sizeof(*idtx)); 00071 idtx->delta = 10; 00072 idtx->size = (int)sizeof(*((IDT)0)); 00073 return idtx; 00074 } 00075 00076 IDTX IDTXgrow(IDTX idtx, int need) 00077 { 00078 if (need < 0) return NULL; 00079 if (idtx == NULL) 00080 idtx = IDTXnew(); 00081 if (need == 0) return idtx; 00082 00083 if ((idtx->nidt + need) > idtx->alloced) { 00084 while (need > 0) { 00085 idtx->alloced += idtx->delta; 00086 need -= idtx->delta; 00087 } 00088 idtx->idt = xrealloc(idtx->idt, (idtx->alloced * idtx->size) ); 00089 } 00090 return idtx; 00091 } 00092 00093 IDTX IDTXsort(IDTX idtx) 00094 { 00095 if (idtx != NULL && idtx->idt != NULL && idtx->nidt > 0) 00096 qsort(idtx->idt, idtx->nidt, idtx->size, IDTintcmp); 00097 return idtx; 00098 } 00099 00100 IDTX IDTXload(rpmts ts, rpmTag tag, rpmuint32_t rbtid) 00101 { 00102 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00103 IDTX idtx = NULL; 00104 rpmmi mi; 00105 Header h; 00106 rpmuint32_t tid; 00107 int xx; 00108 00109 mi = rpmtsInitIterator(ts, tag, NULL, 0); 00110 #ifdef NOTYET 00111 (void) rpmmiAddPattern(mi, RPMTAG_NAME, RPMMIRE_DEFAULT, '!gpg-pubkey'); 00112 #endif 00113 while ((h = rpmmiNext(mi)) != NULL) { 00114 he->tag = tag; 00115 xx = headerGet(h, he, 0); 00116 if (!xx || he->p.ui32p == NULL) 00117 continue; 00118 tid = (he->p.ui32p ? he->p.ui32p[0] : 0); 00119 he->p.ptr = _free(he->p.ptr); 00120 00121 if (tid == 0 || tid == 0xffffffff) 00122 continue; 00123 00124 /* Don't bother with headers installed prior to the rollback goal. */ 00125 if (tid < rbtid) 00126 continue; 00127 00128 idtx = IDTXgrow(idtx, 1); 00129 if (idtx == NULL || idtx->idt == NULL) 00130 continue; 00131 00132 { IDT idt; 00133 /*@-nullderef@*/ 00134 idt = idtx->idt + idtx->nidt; 00135 /*@=nullderef@*/ 00136 idt->done = 0; 00137 idt->h = headerLink(h); 00138 idt->key = NULL; 00139 idt->instance = rpmmiInstance(mi); 00140 idt->val.u32 = tid; 00141 } 00142 idtx->nidt++; 00143 } 00144 mi = rpmmiFree(mi); 00145 00146 return IDTXsort(idtx); 00147 } 00148 00149 IDTX IDTXglob(rpmts ts, const char * globstr, rpmTag tag, rpmuint32_t rbtid) 00150 { 00151 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00152 IDTX idtx = NULL; 00153 Header h; 00154 rpmuint32_t tid; 00155 FD_t fd; 00156 const char ** av = NULL; 00157 const char * fn; 00158 int ac = 0; 00159 rpmRC rpmrc; 00160 int xx; 00161 int i; 00162 00163 av = NULL; ac = 0; 00164 fn = rpmgiEscapeSpaces(globstr); 00165 xx = rpmGlob(fn, &ac, &av); 00166 fn = _free(fn); 00167 00168 if (xx == 0) 00169 for (i = 0; i < ac; i++) { 00170 int isSource; 00171 00172 fd = Fopen(av[i], "r.fdio"); 00173 if (fd == NULL || Ferror(fd)) { 00174 rpmlog(RPMLOG_ERR, _("open of %s failed: %s\n"), av[i], 00175 Fstrerror(fd)); 00176 if (fd != NULL) (void) Fclose(fd); 00177 continue; 00178 } 00179 00180 rpmrc = rpmReadPackageFile(ts, fd, av[i], &h); 00181 (void) Fclose(fd); 00182 switch (rpmrc) { 00183 default: 00184 goto bottom; 00185 /*@notreached@*/ /*@switchbreak@*/ break; 00186 case RPMRC_NOTTRUSTED: 00187 case RPMRC_NOKEY: 00188 case RPMRC_OK: 00189 isSource = 00190 (headerIsEntry(h, RPMTAG_SOURCERPM) == 0 && 00191 headerIsEntry(h, RPMTAG_ARCH) != 0); 00192 if (isSource) 00193 goto bottom; 00194 /*@switchbreak@*/ break; 00195 } 00196 00197 { const char * origin = headerGetOrigin(h); 00198 assert(origin != NULL); 00199 assert(!strcmp(av[i], origin)); 00200 } 00201 he->tag = tag; 00202 xx = headerGet(h, he, 0); 00203 if (!xx || he->p.ui32p == NULL) 00204 goto bottom; 00205 tid = (he->p.ui32p ? he->p.ui32p[0] : 0); 00206 he->p.ptr = _free(he->p.ptr); 00207 00208 /* Don't bother with headers installed prior to the rollback goal. */ 00209 if (tid < rbtid) 00210 goto bottom; 00211 00212 idtx = IDTXgrow(idtx, 1); 00213 if (idtx == NULL || idtx->idt == NULL) 00214 goto bottom; 00215 00216 { IDT idt; 00217 idt = idtx->idt + idtx->nidt; 00218 idt->done = 0; 00219 idt->h = headerLink(h); 00220 idt->key = av[i]; 00221 av[i] = NULL; 00222 idt->instance = 0; 00223 idt->val.u32 = tid; 00224 } 00225 idtx->nidt++; 00226 bottom: 00227 (void)headerFree(h); 00228 h = NULL; 00229 } 00230 00231 for (i = 0; i < ac; i++) 00232 av[i] = _free(av[i]); 00233 av = _free(av); ac = 0; 00234 00235 return IDTXsort(idtx); 00236 } 00237 00247 static int cmpArgvStr(rpmts ts, const char *lname, const char ** AV, int AC, 00248 /*@null@*/ const char * B) 00249 /*@modifies ts @*/ 00250 { 00251 const char * A; 00252 int i; 00253 00254 if (AV != NULL && AC > 0 && B == NULL) { 00255 if (!strcmp(lname, "NEVRA")) { 00256 rpmps ps = rpmtsProblems(ts); 00257 for (i = 0; i < AC && (A = AV[i]) != NULL; i++) { 00258 rpmpsAppend(ps, RPMPROB_NOREPACKAGE, 00259 NULL, NULL, /* NEVRA, key */ 00260 lname, NULL, /* dn, bn */ 00261 A, /* altNEVRA */ 00262 0); 00263 } 00264 ps = rpmpsFree(ps); 00265 } 00266 return 0; 00267 } 00268 00269 if (AV != NULL && B != NULL) 00270 for (i = 0; i < AC && (A = AV[i]) != NULL; i++) { 00271 if (*A && *B && !strcmp(A, B)) 00272 return 1; 00273 } 00274 return 0; 00275 } 00276 00292 static int findErases(rpmts ts, /*@null@*/ rpmte p, unsigned thistid, 00293 /*@null@*/ IDT ip, int niids) 00294 /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/ 00295 /*@modifies ts, p, ip, rpmGlobalMacroContext, fileSystem, internalState @*/ 00296 { 00297 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he)); 00298 int rc = 0; 00299 int xx; 00300 00301 /* Erase the previously installed packages for this transaction. 00302 * Provided this transaction is not excluded from the rollback. 00303 */ 00304 while (ip != NULL && ip->val.u32 == thistid) { 00305 00306 if (ip->done) 00307 goto bottom; 00308 00309 { 00310 const char ** flinkPkgid = NULL; 00311 const char ** flinkHdrid = NULL; 00312 const char ** flinkNEVRA = NULL; 00313 rpmuint32_t pn, hn, nn; 00314 int bingo; 00315 00316 he->tag = RPMTAG_BLINKPKGID; 00317 xx = headerGet(ip->h, he, 0); 00318 flinkPkgid = he->p.argv; 00319 pn = he->c; 00320 00321 /* XXX Always erase packages at beginning of upgrade chain. */ 00322 if (pn == 1 && flinkPkgid[0] != NULL && !strcmp(flinkPkgid[0], RPMTE_CHAIN_END)) { 00323 flinkPkgid = _free(flinkPkgid); 00324 goto erase; 00325 } 00326 00327 he->tag = RPMTAG_BLINKHDRID; 00328 xx = headerGet(ip->h, he, 0); 00329 flinkHdrid = he->p.argv; 00330 hn = he->c; 00331 he->tag = RPMTAG_BLINKNEVRA; 00332 xx = headerGet(ip->h, he, 0); 00333 flinkNEVRA = he->p.argv; 00334 nn = he->c; 00335 00336 /* 00337 * Link data may be missing and can have multiple entries. 00338 */ 00339 /* XXX Until link tags are reliably populated, check in the order 00340 * NEVRA -> hdrid -> pkgid 00341 * because NEVRA is easier to debug (hdrid/pkgid are more precise.) 00342 */ 00343 bingo = 0; 00344 if (!bingo) 00345 bingo = cmpArgvStr(ts, "NEVRA", flinkNEVRA, nn, (p ? p->NEVRA : NULL)); 00346 if (!bingo) 00347 bingo = cmpArgvStr(ts, "Hdrid", flinkHdrid, hn, (p ? p->hdrid : NULL)); 00348 /*@-nullstate@*/ 00349 if (!bingo) 00350 bingo = cmpArgvStr(ts, "Pkgid", flinkPkgid, pn, (p ? p->pkgid : NULL)); 00351 /*@=nullstate@*/ 00352 flinkPkgid = _free(flinkPkgid); 00353 flinkHdrid = _free(flinkHdrid); 00354 flinkNEVRA = _free(flinkNEVRA); 00355 00356 if (bingo < 0) { 00357 rc = -1; 00358 goto exit; 00359 } 00360 00361 if (!bingo) 00362 goto bottom; 00363 } 00364 00365 erase: 00366 rpmlog(RPMLOG_DEBUG, D_("\t--- erase h#%u\n"), ip->instance); 00367 00368 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance); 00369 if (rc != 0) 00370 goto exit; 00371 00372 /* Cross link the transaction elements to mimic --upgrade. */ 00373 if (p != NULL) { 00374 rpmte q = ts->teErase; 00375 xx = rpmteChain(p, q, ip->h, "Rollback"); 00376 } 00377 00378 #ifdef NOTYET 00379 ip->instance = 0; 00380 #endif 00381 ip->done = 1; 00382 00383 bottom: 00384 00385 /* Go to the next header in the rpmdb */ 00386 niids--; 00387 if (niids > 0) 00388 ip++; 00389 else 00390 ip = NULL; 00391 } 00392 00393 exit: 00394 return rc; 00395 } 00396 00398 int rpmRollback(rpmts ts, QVA_t ia, const char ** argv) 00399 { 00400 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE); 00401 unsigned thistid = 0xffffffff; 00402 unsigned prevtid; 00403 time_t tid; 00404 IDTX itids = NULL; 00405 IDTX rtids = NULL; 00406 IDT rp; 00407 int nrids = 0; 00408 IDT ip; 00409 int niids = 0; 00410 int rc = 0; 00411 int vsflags, ovsflags; 00412 int numAdded; 00413 int numRemoved; 00414 unsigned int _unsafe_rollbacks = 0; 00415 rpmtransFlags transFlags = ia->transFlags; 00416 rpmdepFlags depFlags = ia->depFlags; 00417 int xx; 00418 00419 if (argv != NULL && *argv != NULL) { 00420 rc = -1; 00421 goto exit; 00422 } 00423 00424 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}"); 00425 00426 vsflags = rpmExpandNumeric("%{?_vsflags_erase}"); 00427 if (ia->qva_flags & VERIFY_DIGEST) 00428 vsflags |= _RPMVSF_NODIGESTS; 00429 if (ia->qva_flags & VERIFY_SIGNATURE) 00430 vsflags |= _RPMVSF_NOSIGNATURES; 00431 if (ia->qva_flags & VERIFY_HDRCHK) 00432 vsflags |= RPMVSF_NOHDRCHK; 00433 vsflags |= RPMVSF_NEEDPAYLOAD; /* XXX no legacy signatures */ 00434 ovsflags = rpmtsSetVSFlags(ts, vsflags); 00435 00436 (void) rpmtsSetFlags(ts, transFlags); 00437 (void) rpmtsSetDFlags(ts, depFlags); 00438 00439 /* Make the transaction a rollback transaction. In a rollback 00440 * a best effort is what we want 00441 */ 00442 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK); 00443 00444 itids = IDTXload(ts, RPMTAG_INSTALLTID, ia->rbtid); 00445 if (itids != NULL) { 00446 ip = itids->idt; 00447 niids = itids->nidt; 00448 } else { 00449 ip = NULL; 00450 niids = 0; 00451 } 00452 00453 { const char * globstr = rpmExpand("%{_repackage_dir}/*/*.rpm", NULL); 00454 if (globstr == NULL || *globstr == '%') { 00455 globstr = _free(globstr); 00456 rc = -1; 00457 goto exit; 00458 } 00459 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID, ia->rbtid); 00460 00461 if (rtids != NULL) { 00462 rp = rtids->idt; 00463 nrids = rtids->nidt; 00464 } else { 00465 rp = NULL; 00466 nrids = 0; 00467 } 00468 globstr = _free(globstr); 00469 } 00470 00471 { int notifyFlags; 00472 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 ); 00473 xx = rpmtsSetNotifyCallback(ts, 00474 rpmShowProgress, (void *) ((long)notifyFlags)); 00475 } 00476 00477 /* Run transactions until rollback goal is achieved. */ 00478 do { 00479 prevtid = thistid; 00480 rc = 0; 00481 rpmcliPackagesTotal = 0; 00482 numAdded = 0; 00483 numRemoved = 0; 00484 ia->installInterfaceFlags &= ~ifmask; 00485 00486 /* Find larger of the remaining install/erase transaction id's. */ 00487 thistid = 0; 00488 if (ip != NULL && ip->val.u32 > thistid) 00489 thistid = ip->val.u32; 00490 if (rp != NULL && rp->val.u32 > thistid) 00491 thistid = rp->val.u32; 00492 00493 /* If we've achieved the rollback goal, then we're done. */ 00494 if (thistid == 0 || thistid < ia->rbtid) 00495 break; 00496 00497 /* If we've reached the (configured) rollback goal, then we're done. */ 00498 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks) 00499 break; 00500 00501 /* Is this transaction excluded from the rollback? */ 00502 if (ia->rbtidExcludes != NULL && ia->numrbtidExcludes > 0) 00503 { 00504 rpmuint32_t *excludedTID; 00505 int excluded = 0; 00506 for(excludedTID = ia->rbtidExcludes; 00507 excludedTID < ia->rbtidExcludes + ia->numrbtidExcludes; 00508 excludedTID++) { 00509 if (thistid == *excludedTID) { 00510 time_t ttid = (time_t)thistid; 00511 rpmlog(RPMLOG_NOTICE, 00512 _("Excluding TID from rollback: %-24.24s (0x%08x)\n"), 00513 ctime(&ttid), thistid); 00514 excluded = 1; 00515 /*@innerbreak@*/ break; 00516 } 00517 } 00518 if (excluded) { 00519 /* Iterate over repackaged packages */ 00520 while (rp != NULL && rp->val.u32 == thistid) { 00521 /* Go to the next repackaged package */ 00522 nrids--; 00523 if (nrids > 0) 00524 rp++; 00525 else 00526 rp = NULL; 00527 } 00528 /* Iterate over installed packages */ 00529 while (ip != NULL && ip->val.u32 == thistid) { 00530 /* Go to the next header in the rpmdb */ 00531 niids--; 00532 if (niids > 0) 00533 ip++; 00534 else 00535 ip = NULL; 00536 } 00537 continue; /* with next transaction */ 00538 } 00539 } 00540 00541 rpmtsEmpty(ts); 00542 (void) rpmtsSetFlags(ts, transFlags); 00543 (void) rpmtsSetDFlags(ts, depFlags); 00544 ts->probs = rpmpsFree(ts->probs); 00545 00546 /* Install the previously erased packages for this transaction. 00547 */ 00548 while (rp != NULL && rp->val.u32 == thistid) { 00549 if (!rp->done) { 00550 rpmlog(RPMLOG_DEBUG, D_("\t+++ install %s\n"), 00551 (rp->key ? rp->key : "???")); 00552 00553 /*@-abstract@*/ 00554 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key, 00555 0, ia->relocations); 00556 /*@=abstract@*/ 00557 if (rc != 0) 00558 goto exit; 00559 00560 numAdded++; 00561 rpmcliPackagesTotal++; 00562 if (!(ia->installInterfaceFlags & ifmask)) 00563 ia->installInterfaceFlags |= INSTALL_UPGRADE; 00564 00565 /* Re-add linked (i.e. from upgrade/obsoletes) erasures. */ 00566 rc = findErases(ts, ts->teInstall, thistid, ip, niids); 00567 if (rc < 0) 00568 goto exit; 00569 #ifdef NOTYET 00570 (void)headerFree(rp->h); 00571 rpm->h = NULL; 00572 #endif 00573 rp->done = 1; 00574 } 00575 00576 /* Go to the next repackaged package */ 00577 nrids--; 00578 if (nrids > 0) 00579 rp++; 00580 else 00581 rp = NULL; 00582 } 00583 00584 /* Re-add pure (i.e. not from upgrade/obsoletes) erasures. */ 00585 rc = findErases(ts, NULL, thistid, ip, niids); 00586 if (rc < 0) 00587 goto exit; 00588 00589 /* Check that all erasures have been re-added. */ 00590 while (ip != NULL && ip->val.u32 == thistid) { 00591 #ifdef NOTNOW 00592 /* XXX Prevent incomplete rollback transactions. */ 00593 assert(ip->done || ia->no_rollback_links); 00594 #endif 00595 if (!(ip->done || ia->no_rollback_links)) { 00596 numRemoved++; 00597 00598 if (_unsafe_rollbacks != 0) 00599 rpmcliPackagesTotal++; 00600 00601 if (!(ia->installInterfaceFlags & ifmask)) 00602 ia->installInterfaceFlags |= INSTALL_ERASE; 00603 } 00604 00605 /* Go to the next header in the rpmdb */ 00606 niids--; 00607 if (niids > 0) 00608 ip++; 00609 else 00610 ip = NULL; 00611 } 00612 00613 /* Print any rollback transaction problems */ 00614 xx = rpmcliInstallProblems(ts, _("Missing re-packaged package(s)"), 1); 00615 00616 /* Anything to do? */ 00617 if (rpmcliPackagesTotal <= 0) 00618 break; 00619 00620 tid = (time_t)thistid; 00621 rpmlog(RPMLOG_NOTICE, 00622 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"), 00623 numAdded, numRemoved, ctime(&tid), thistid); 00624 00625 rc = (ia->rbCheck ? (*ia->rbCheck) (ts) : 0); 00626 if (rc != 0) 00627 goto exit; 00628 00629 rc = (ia->rbOrder ? (*ia->rbOrder) (ts) : 0); 00630 if (rc != 0) 00631 goto exit; 00632 00633 /* Drop added/available package indices and dependency sets. */ 00634 rpmtsClean(ts); 00635 00636 /* Print the transaction set. */ 00637 xx = rpmtsPrint(ts, stdout); 00638 00639 rc = (ia->rbRun 00640 ? (*ia->rbRun)(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE)) 00641 : 0); 00642 if (rc != 0) 00643 goto exit; 00644 00645 /* Remove repackaged packages after successful reinstall. */ 00646 if (rtids && !rpmIsDebug()) { 00647 int i; 00648 rpmlog(RPMLOG_NOTICE, _("Cleaning up repackaged packages:\n")); 00649 if (rtids->idt) 00650 for (i = 0; i < rtids->nidt; i++) { 00651 IDT rrp = rtids->idt + i; 00652 if (rrp->val.u32 != thistid) 00653 /*@innercontinue@*/ continue; 00654 if (rrp->key) { /* XXX can't happen */ 00655 rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key); 00656 (void) unlink(rrp->key); /* XXX: Should check rc??? */ 00657 } 00658 } 00659 } 00660 00661 /* The rpmdb has changed, so reload installed package chains. */ 00662 itids = IDTXfree(itids); 00663 itids = IDTXload(ts, RPMTAG_INSTALLTID, ia->rbtid); 00664 if (itids != NULL) { 00665 ip = itids->idt; 00666 niids = itids->nidt; 00667 } else { 00668 ip = NULL; 00669 niids = 0; 00670 } 00671 00672 /* Re-position the iterator at the current install tid. */ 00673 while (ip != NULL && ip->val.u32 == thistid) { 00674 /* Go to the next header in the rpmdb */ 00675 niids--; 00676 if (niids > 0) 00677 ip++; 00678 else 00679 ip = NULL; 00680 } 00681 00682 } while (1); 00683 00684 exit: 00685 rtids = IDTXfree(rtids); 00686 itids = IDTXfree(itids); 00687 00688 rpmtsEmpty(ts); 00689 (void) rpmtsSetFlags(ts, transFlags); 00690 (void) rpmtsSetDFlags(ts, depFlags); 00691 00692 return rc; 00693 }