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