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"
00020
00021 #define _RPMTE_INTERNAL
00022 #define _RPMTS_INTERNAL
00023 #define _RPMTS_PRINT
00024 #include <rpmgi.h>
00025
00026 #include <rpmcli.h>
00027 #define _RPMROLLBACK_INTERNAL
00028 #include <rpmrollback.h>
00029
00030 #include "debug.h"
00031
00032
00033
00034
00035
00036
00037
00038
00039 static int reverse = -1;
00040
00043 static int IDTintcmp(const void * a, const void * b)
00044
00045 {
00046
00047 return ( reverse * (((IDT)a)->val.u32 - ((IDT)b)->val.u32) );
00048
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
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
00134 idt = idtx->idt + idtx->nidt;
00135
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 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 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
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 const char * B)
00249
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,
00260 lname, NULL,
00261 A,
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, rpmte p, unsigned thistid,
00293 IDT ip, int niids)
00294
00295
00296 {
00297 HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00298 int rc = 0;
00299 int xx;
00300
00301
00302
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
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
00338
00339
00340
00341
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
00349 if (!bingo)
00350 bingo = cmpArgvStr(ts, "Pkgid", flinkPkgid, pn, (p ? p->pkgid : NULL));
00351
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
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
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;
00434 ovsflags = rpmtsSetVSFlags(ts, vsflags);
00435
00436 (void) rpmtsSetFlags(ts, transFlags);
00437 (void) rpmtsSetDFlags(ts, depFlags);
00438
00439
00440
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
00478 do {
00479 prevtid = thistid;
00480 rc = 0;
00481 rpmcliPackagesTotal = 0;
00482 numAdded = 0;
00483 numRemoved = 0;
00484 ia->installInterfaceFlags &= ~ifmask;
00485
00486
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
00494 if (thistid == 0 || thistid < ia->rbtid)
00495 break;
00496
00497
00498 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
00499 break;
00500
00501
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 break;
00516 }
00517 }
00518 if (excluded) {
00519
00520 while (rp != NULL && rp->val.u32 == thistid) {
00521
00522 nrids--;
00523 if (nrids > 0)
00524 rp++;
00525 else
00526 rp = NULL;
00527 }
00528
00529 while (ip != NULL && ip->val.u32 == thistid) {
00530
00531 niids--;
00532 if (niids > 0)
00533 ip++;
00534 else
00535 ip = NULL;
00536 }
00537 continue;
00538 }
00539 }
00540
00541 rpmtsEmpty(ts);
00542 (void) rpmtsSetFlags(ts, transFlags);
00543 (void) rpmtsSetDFlags(ts, depFlags);
00544 ts->probs = rpmpsFree(ts->probs);
00545
00546
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
00554 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
00555 0, ia->relocations);
00556
00557 if (rc != 0)
00558 goto exit;
00559
00560 numAdded++;
00561 rpmcliPackagesTotal++;
00562 if (!(ia->installInterfaceFlags & ifmask))
00563 ia->installInterfaceFlags |= INSTALL_UPGRADE;
00564
00565
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
00577 nrids--;
00578 if (nrids > 0)
00579 rp++;
00580 else
00581 rp = NULL;
00582 }
00583
00584
00585 rc = findErases(ts, NULL, thistid, ip, niids);
00586 if (rc < 0)
00587 goto exit;
00588
00589
00590 while (ip != NULL && ip->val.u32 == thistid) {
00591 #ifdef NOTNOW
00592
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
00606 niids--;
00607 if (niids > 0)
00608 ip++;
00609 else
00610 ip = NULL;
00611 }
00612
00613
00614 xx = rpmcliInstallProblems(ts, _("Missing re-packaged package(s)"), 1);
00615
00616
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
00634 rpmtsClean(ts);
00635
00636
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
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 continue;
00654 if (rrp->key) {
00655 rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
00656 (void) unlink(rrp->key);
00657 }
00658 }
00659 }
00660
00661
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
00673 while (ip != NULL && ip->val.u32 == thistid) {
00674
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 }