00001
00005 #include "system.h"
00006
00007 #include <rpmcli.h>
00008
00009 #include "rpmdb.h"
00010 #include "rpmds.h"
00011
00012 #define _RPMTE_INTERNAL
00013 #include "rpmte.h"
00014 #define _RPMTS_INTERNAL
00015 #include "rpmts.h"
00016
00017 #include "manifest.h"
00018 #include "misc.h"
00019 #include "rpmgi.h"
00020 #include "debug.h"
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, uint_32 rbtid)
00089 {
00090 IDTX idtx = NULL;
00091 rpmdbMatchIterator mi;
00092 HGE_t hge = (HGE_t) headerGetEntry;
00093 Header h;
00094
00095
00096 mi = rpmtsInitIterator(ts, tag, NULL, 0);
00097 #ifdef NOTYET
00098 (void) rpmdbSetIteratorRE(mi, RPMTAG_NAME, RPMMIRE_DEFAULT, '!gpg-pubkey');
00099 #endif
00100 while ((h = rpmdbNextIterator(mi)) != NULL) {
00101 rpmTagType type = RPM_NULL_TYPE;
00102 int_32 count = 0;
00103 int_32 * tidp;
00104
00105 tidp = NULL;
00106 if (!hge(h, tag, &type, (void **)&tidp, &count) || tidp == NULL)
00107 continue;
00108
00109 if (type == RPM_INT32_TYPE && (*tidp == 0 || *tidp == -1))
00110 continue;
00111
00112
00113 if (*tidp < 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 = *tidp;
00129 }
00130 idtx->nidt++;
00131 }
00132 mi = rpmdbFreeIterator(mi);
00133
00134
00135 return IDTXsort(idtx);
00136 }
00137
00138 IDTX IDTXglob(rpmts ts, const char * globstr, rpmTag tag, uint_32 rbtid)
00139 {
00140 HGE_t hge = (HGE_t) headerGetEntry;
00141 IDTX idtx = NULL;
00142 Header h;
00143 int_32 * tidp;
00144 FD_t fd;
00145 const char ** av = NULL;
00146 const char * fn;
00147 int ac = 0;
00148 rpmRC rpmrc;
00149 int xx;
00150 int i;
00151
00152 av = NULL; ac = 0;
00153 fn = rpmgiEscapeSpaces(globstr);
00154 xx = rpmGlob(fn, &ac, &av);
00155 fn = _free(fn);
00156
00157
00158 if (xx == 0)
00159 for (i = 0; i < ac; i++) {
00160 rpmTagType type;
00161 int_32 count;
00162 int isSource;
00163
00164 fd = Fopen(av[i], "r");
00165 if (fd == NULL || Ferror(fd)) {
00166 rpmError(RPMERR_OPEN, _("open of %s failed: %s\n"), av[i],
00167 Fstrerror(fd));
00168 if (fd != NULL) (void) Fclose(fd);
00169 continue;
00170 }
00171
00172 rpmrc = rpmReadPackageFile(ts, fd, av[i], &h);
00173 (void) Fclose(fd);
00174 switch (rpmrc) {
00175 default:
00176 goto bottom;
00177 break;
00178 case RPMRC_NOTTRUSTED:
00179 case RPMRC_NOKEY:
00180 case RPMRC_OK:
00181 isSource = (headerIsEntry(h, RPMTAG_SOURCERPM) == 0);
00182 if (isSource)
00183 goto bottom;
00184 break;
00185 }
00186
00187 { const char * origin = headerGetOrigin(h);
00188 assert(origin != NULL);
00189 assert(!strcmp(av[i], origin));
00190 }
00191 tidp = NULL;
00192 if (!hge(h, tag, &type, (void **) &tidp, &count) || tidp == NULL)
00193 goto bottom;
00194
00195
00196 if (*tidp < rbtid)
00197 goto bottom;
00198
00199 idtx = IDTXgrow(idtx, 1);
00200 if (idtx == NULL || idtx->idt == NULL)
00201 goto bottom;
00202
00203 { IDT idt;
00204 idt = idtx->idt + idtx->nidt;
00205 idt->done = 0;
00206 idt->h = headerLink(h);
00207 idt->key = av[i];
00208 av[i] = NULL;
00209 idt->instance = 0;
00210 idt->val.u32 = *tidp;
00211 }
00212 idtx->nidt++;
00213 bottom:
00214 h = headerFree(h);
00215 }
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 int rc = 0;
00285 int xx;
00286
00287
00288
00289
00290 while (ip != NULL && ip->val.u32 == thistid) {
00291
00292 if (ip->done)
00293 goto bottom;
00294
00295 {
00296 HGE_t hge = (HGE_t)headerGetEntryMinMemory;
00297 const char ** flinkPkgid = NULL;
00298 const char ** flinkHdrid = NULL;
00299 const char ** flinkNEVRA = NULL;
00300 rpmTagType pt, ht, nt;
00301 int_32 pn, hn, nn;
00302 int bingo;
00303
00304 xx = hge(ip->h, RPMTAG_BLINKPKGID, &pt, (void **)&flinkPkgid, &pn);
00305
00306
00307 if (pn == 1 && flinkPkgid[0] != NULL && !strcmp(flinkPkgid[0], RPMTE_CHAIN_END)) {
00308 flinkPkgid = headerFreeData(flinkPkgid, pt);
00309 goto erase;
00310 }
00311
00312 xx = hge(ip->h, RPMTAG_BLINKHDRID, &ht, (void **)&flinkHdrid, &hn);
00313 xx = hge(ip->h, RPMTAG_BLINKNEVRA, &nt, (void **)&flinkNEVRA, &nn);
00314
00315
00316
00317
00318
00319
00320
00321
00322 bingo = 0;
00323 if (!bingo)
00324 bingo = cmpArgvStr(ts, "NEVRA", flinkNEVRA, nn, (p ? p->NEVRA : NULL));
00325 if (!bingo)
00326 bingo = cmpArgvStr(ts, "Hdrid", flinkHdrid, hn, (p ? p->hdrid : NULL));
00327 if (!bingo)
00328 bingo = cmpArgvStr(ts, "Pkgid", flinkPkgid, pn, (p ? p->pkgid : NULL));
00329 flinkPkgid = headerFreeData(flinkPkgid, pt);
00330 flinkHdrid = headerFreeData(flinkHdrid, ht);
00331 flinkNEVRA = headerFreeData(flinkNEVRA, nt);
00332
00333 if (bingo < 0) {
00334 rc = -1;
00335 goto exit;
00336 }
00337
00338 if (!bingo)
00339 goto bottom;
00340 }
00341
00342 erase:
00343 rpmMessage(RPMMESS_DEBUG, "\t--- erase h#%u\n", ip->instance);
00344
00345 rc = rpmtsAddEraseElement(ts, ip->h, ip->instance);
00346 if (rc != 0)
00347 goto exit;
00348
00349
00350 if (p != NULL) {
00351 rpmte q = ts->teErase;
00352 xx = rpmteChain(p, q, ip->h, "Rollback");
00353 }
00354
00355 #ifdef NOTYET
00356 ip->instance = 0;
00357 #endif
00358 ip->done = 1;
00359
00360 bottom:
00361
00362
00363 niids--;
00364 if (niids > 0)
00365 ip++;
00366 else
00367 ip = NULL;
00368 }
00369
00370 exit:
00371 return rc;
00372 }
00373
00374 static int rpmrbProblems(rpmts ts, const char * msg, int rc)
00375 {
00376 rpmps ps = rpmtsProblems(ts);
00377
00378 if (rc != 0 && rpmpsNumProblems(ps) > 0) {
00379 if (msg)
00380 rpmMessage(RPMMESS_ERROR, "%s:\n", msg);
00381 rpmpsPrint(NULL, ps);
00382 }
00383 ps = rpmpsFree(ps);
00384 return rc;
00385 }
00386
00387 int rpmrbCheck(rpmts ts)
00388 {
00389 return rpmrbProblems(ts, N_("Failed dependencies"), rpmtsCheck(ts));
00390 }
00391
00392 int rpmrbOrder(rpmts ts)
00393 {
00394 return rpmrbProblems(ts, N_("Ordering problems"), rpmtsOrder(ts));
00395 }
00396
00397 int rpmrbRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
00398 {
00399 return rpmrbProblems(ts, N_("Rollback problems"),
00400 rpmtsRun(ts, okProbs, ignoreSet));
00401 }
00402
00404 int rpmRollback(rpmts ts, QVA_t ia, const char ** argv)
00405 {
00406 int ifmask= (INSTALL_UPGRADE|INSTALL_FRESHEN|INSTALL_INSTALL|INSTALL_ERASE);
00407 unsigned thistid = 0xffffffff;
00408 unsigned prevtid;
00409 time_t tid;
00410 IDTX itids = NULL;
00411 IDTX rtids = NULL;
00412 IDT rp;
00413 int nrids = 0;
00414 IDT ip;
00415 int niids = 0;
00416 int rc = 0;
00417 int vsflags, ovsflags;
00418 int numAdded;
00419 int numRemoved;
00420 int _unsafe_rollbacks = 0;
00421 rpmtransFlags transFlags = ia->transFlags;
00422 rpmdepFlags depFlags = ia->depFlags;
00423 int xx;
00424
00425 if (argv != NULL && *argv != NULL) {
00426 rc = -1;
00427 goto exit;
00428 }
00429
00430 _unsafe_rollbacks = rpmExpandNumeric("%{?_unsafe_rollbacks}");
00431
00432 vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
00433 if (ia->qva_flags & VERIFY_DIGEST)
00434 vsflags |= _RPMVSF_NODIGESTS;
00435 if (ia->qva_flags & VERIFY_SIGNATURE)
00436 vsflags |= _RPMVSF_NOSIGNATURES;
00437 if (ia->qva_flags & VERIFY_HDRCHK)
00438 vsflags |= RPMVSF_NOHDRCHK;
00439 vsflags |= RPMVSF_NEEDPAYLOAD;
00440 ovsflags = rpmtsSetVSFlags(ts, vsflags);
00441
00442 (void) rpmtsSetFlags(ts, transFlags);
00443 (void) rpmtsSetDFlags(ts, depFlags);
00444
00445
00446
00447
00448 rpmtsSetType(ts, RPMTRANS_TYPE_ROLLBACK);
00449
00450 itids = IDTXload(ts, RPMTAG_INSTALLTID, ia->rbtid);
00451 if (itids != NULL) {
00452 ip = itids->idt;
00453 niids = itids->nidt;
00454 } else {
00455 ip = NULL;
00456 niids = 0;
00457 }
00458
00459 { const char * globstr = rpmExpand("%{_repackage_dir}/*/*.rpm", NULL);
00460 if (globstr == NULL || *globstr == '%') {
00461 globstr = _free(globstr);
00462 rc = -1;
00463 goto exit;
00464 }
00465 rtids = IDTXglob(ts, globstr, RPMTAG_REMOVETID, ia->rbtid);
00466
00467 if (rtids != NULL) {
00468 rp = rtids->idt;
00469 nrids = rtids->nidt;
00470 } else {
00471 rp = NULL;
00472 nrids = 0;
00473 }
00474 globstr = _free(globstr);
00475 }
00476
00477 { int notifyFlags, xx;
00478 notifyFlags = ia->installInterfaceFlags | (rpmIsVerbose() ? INSTALL_LABEL : 0 );
00479 xx = rpmtsSetNotifyCallback(ts,
00480 rpmShowProgress, (void *) ((long)notifyFlags));
00481 }
00482
00483
00484 do {
00485 prevtid = thistid;
00486 rc = 0;
00487 rpmcliPackagesTotal = 0;
00488 numAdded = 0;
00489 numRemoved = 0;
00490 ia->installInterfaceFlags &= ~ifmask;
00491
00492
00493 thistid = 0;
00494 if (ip != NULL && ip->val.u32 > thistid)
00495 thistid = ip->val.u32;
00496 if (rp != NULL && rp->val.u32 > thistid)
00497 thistid = rp->val.u32;
00498
00499
00500 if (thistid == 0 || thistid < ia->rbtid)
00501 break;
00502
00503
00504 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
00505 break;
00506
00507
00508 if (ia->rbtidExcludes != NULL && ia->numrbtidExcludes > 0)
00509 {
00510 uint_32 *excludedTID;
00511 int excluded = 0;
00512 for(excludedTID = ia->rbtidExcludes;
00513 excludedTID < ia->rbtidExcludes + ia->numrbtidExcludes;
00514 excludedTID++) {
00515 if (thistid == *excludedTID) {
00516 time_t ttid = (time_t)thistid;
00517 rpmMessage(RPMMESS_NORMAL,
00518 _("Excluding TID from rollback: %-24.24s (0x%08x)\n"),
00519 ctime(&ttid), thistid);
00520 excluded = 1;
00521 break;
00522 }
00523 }
00524 if (excluded) {
00525
00526 while (rp != NULL && rp->val.u32 == thistid) {
00527
00528 nrids--;
00529 if (nrids > 0)
00530 rp++;
00531 else
00532 rp = NULL;
00533 }
00534
00535 while (ip != NULL && ip->val.u32 == thistid) {
00536
00537 niids--;
00538 if (niids > 0)
00539 ip++;
00540 else
00541 ip = NULL;
00542 }
00543 continue;
00544 }
00545 }
00546
00547 rpmtsEmpty(ts);
00548 (void) rpmtsSetFlags(ts, transFlags);
00549 (void) rpmtsSetDFlags(ts, depFlags);
00550 ts->probs = rpmpsFree(ts->probs);
00551 ts->probs = rpmpsCreate();
00552
00553
00554
00555 while (rp != NULL && rp->val.u32 == thistid) {
00556 if (!rp->done) {
00557 rpmMessage(RPMMESS_DEBUG, "\t+++ install %s\n",
00558 (rp->key ? rp->key : "???"));
00559
00560
00561 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
00562 0, ia->relocations);
00563
00564 if (rc != 0)
00565 goto exit;
00566
00567 numAdded++;
00568 rpmcliPackagesTotal++;
00569 if (!(ia->installInterfaceFlags & ifmask))
00570 ia->installInterfaceFlags |= INSTALL_UPGRADE;
00571
00572
00573 rc = findErases(ts, ts->teInstall, thistid, ip, niids);
00574 if (rc < 0)
00575 goto exit;
00576 #ifdef NOTYET
00577 rp->h = headerFree(rp->h);
00578 #endif
00579 rp->done = 1;
00580 }
00581
00582
00583 nrids--;
00584 if (nrids > 0)
00585 rp++;
00586 else
00587 rp = NULL;
00588 }
00589
00590
00591 rc = findErases(ts, NULL, thistid, ip, niids);
00592 if (rc < 0)
00593 goto exit;
00594
00595
00596 while (ip != NULL && ip->val.u32 == thistid) {
00597 #ifdef NOTNOW
00598
00599 assert(ip->done || ia->no_rollback_links);
00600 #endif
00601 if (!(ip->done || ia->no_rollback_links)) {
00602 numRemoved++;
00603
00604 if (_unsafe_rollbacks)
00605 rpmcliPackagesTotal++;
00606
00607 if (!(ia->installInterfaceFlags & ifmask))
00608 ia->installInterfaceFlags |= INSTALL_ERASE;
00609 }
00610
00611
00612 niids--;
00613 if (niids > 0)
00614 ip++;
00615 else
00616 ip = NULL;
00617 }
00618
00619
00620 (void) rpmrbProblems(ts, N_("Missing re-packaged package(s)"), 1);
00621
00622
00623 if (rpmcliPackagesTotal <= 0)
00624 break;
00625
00626 tid = (time_t)thistid;
00627 rpmMessage(RPMMESS_NORMAL,
00628 _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
00629 numAdded, numRemoved, ctime(&tid), thistid);
00630
00631 rc = (ia->rbCheck ? (*ia->rbCheck) (ts) : 0);
00632 if (rc != 0)
00633 goto exit;
00634
00635 rc = (ia->rbOrder ? (*ia->rbOrder) (ts) : 0);
00636 if (rc != 0)
00637 goto exit;
00638
00639
00640 rpmtsClean(ts);
00641
00642
00643 xx = rpmtsPrint(ts, stdout);
00644
00645 rc = (ia->rbRun
00646 ? (*ia->rbRun)(ts, NULL, (ia->probFilter|RPMPROB_FILTER_OLDPACKAGE))
00647 : 0);
00648 if (rc != 0)
00649 goto exit;
00650
00651
00652 if (rtids && !rpmIsDebug()) {
00653 int i;
00654 rpmMessage(RPMMESS_NORMAL, _("Cleaning up repackaged packages:\n"));
00655 if (rtids->idt)
00656 for (i = 0; i < rtids->nidt; i++) {
00657 IDT rrp = rtids->idt + i;
00658 if (rrp->val.u32 != thistid)
00659 continue;
00660 if (rrp->key) {
00661 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), rrp->key);
00662 (void) unlink(rrp->key);
00663 }
00664 }
00665 }
00666
00667
00668 itids = IDTXfree(itids);
00669 itids = IDTXload(ts, RPMTAG_INSTALLTID, ia->rbtid);
00670 if (itids != NULL) {
00671 ip = itids->idt;
00672 niids = itids->nidt;
00673 } else {
00674 ip = NULL;
00675 niids = 0;
00676 }
00677
00678
00679 while (ip != NULL && ip->val.u32 == thistid) {
00680
00681 niids--;
00682 if (niids > 0)
00683 ip++;
00684 else
00685 ip = NULL;
00686 }
00687
00688 } while (1);
00689
00690 exit:
00691 rtids = IDTXfree(rtids);
00692 itids = IDTXfree(itids);
00693
00694 rpmtsEmpty(ts);
00695 (void) rpmtsSetFlags(ts, transFlags);
00696 (void) rpmtsSetDFlags(ts, depFlags);
00697
00698 return rc;
00699 }