- Main Page
- Related Pages
- Modules
- Data Structures
- Files

- File List
- Globals

# lib/rpmrollback.c

Go to the documentation of this file.

    00001
    00005 #include "system.h"
    00006
    00007 #include <rpmio.h>
    00008 #define _RPMTE_INTERNAL         /* XXX findErases needs rpmte internals. */
    00009 #define _RPMTS_INTERNAL         /* XXX ts->teErase, ts->probs */
    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"               /* XXX rpmGlob() */
    00018 #include "rpmgi.h"              /* XXX rpmgiEscapeSpaces */
    00019 #include "debug.h"
    00020
    00021 /*@access FD_t @*/      /* XXX void * arg */
    00022 /*@access rpmts @*/
    00023 /*@access rpmte @*/     /* XXX p->hdrid, p->pkgid, p->NEVRA */
    00024 /*@access IDTX @*/
    00025 /*@access IDT @*/
    00026
    00027 /*@unchecked@*/
    00028 static int reverse = -1;
    00029
    00032 static int IDTintcmp(const void * a, const void * b)
    00033         /*@*/
    00034 {
    00035     /*@-castexpose@*/
    00036     return ( reverse * (((IDT)a)->val.u32 - ((IDT)b)->val.u32) );
    00037     /*@=castexpose@*/
    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         /* Don't bother with headers installed prior to the rollback goal. */
    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             /*@-nullderef@*/
    00122             idt = idtx->idt + idtx->nidt;
    00123             /*@=nullderef@*/
    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             /*@notreached@*/ /*@switchbreak@*/ 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             /*@switchbreak@*/ 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         /* Don't bother with headers installed prior to the rollback goal. */
    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                 /*@null@*/ const char * B)
    00236         /*@modifies ts @*/
    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,     /* NEVRA, key */
    00247                         lname, NULL,    /* dn, bn */
    00248                         A,              /* altNEVRA */
    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, /*@null@*/ rpmte p, unsigned thistid,
    00280                 /*@null@*/ IDT ip, int niids)
    00281         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
    00282         /*@modifies ts, p, ip, rpmGlobalMacroContext, fileSystem, internalState @*/
    00283 {
    00284     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
    00285     int rc = 0;
    00286     int xx;
    00287
    00288     /* Erase the previously installed packages for this transaction.
    00289      * Provided this transaction is not excluded from the rollback.
    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             /* XXX Always erase packages at beginning of upgrade chain. */
    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              * Link data may be missing and can have multiple entries.
    00325              */
    00326             /* XXX Until link tags are reliably populated, check in the order
    00327              *  NEVRA -> hdrid -> pkgid
    00328              * because NEVRA is easier to debug (hdrid/pkgid are more precise.)
    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 /*@-nullstate@*/
    00336             if (!bingo)
    00337                 bingo = cmpArgvStr(ts, "Pkgid", flinkPkgid, pn, (p ? p->pkgid : NULL));
    00338 /*@=nullstate@*/
    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         /* Cross link the transaction elements to mimic --upgrade. */
    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         /* Go to the next header in the rpmdb */
    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;      /* XXX no legacy signatures */
    00421     ovsflags = rpmtsSetVSFlags(ts, vsflags);
    00422
    00423     (void) rpmtsSetFlags(ts, transFlags);
    00424     (void) rpmtsSetDFlags(ts, depFlags);
    00425
    00426     /*  Make the transaction a rollback transaction.  In a rollback
    00427      *  a best effort is what we want
    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     /* Run transactions until rollback goal is achieved. */
    00465     do {
    00466         prevtid = thistid;
    00467         rc = 0;
    00468         rpmcliPackagesTotal = 0;
    00469         numAdded = 0;
    00470         numRemoved = 0;
    00471         ia->installInterfaceFlags &= ~ifmask;
    00472
    00473         /* Find larger of the remaining install/erase transaction id's. */
    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         /* If we've achieved the rollback goal, then we're done. */
    00481         if (thistid == 0 || thistid < ia->rbtid)
    00482             break;
    00483
    00484         /* If we've reached the (configured) rollback goal, then we're done. */
    00485         if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks)
    00486             break;
    00487
    00488         /* Is this transaction excluded from the rollback? */
    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                     /*@innerbreak@*/ break;
    00503                 }
    00504             }
    00505             if (excluded) {
    00506                 /* Iterate over repackaged packages */
    00507                 while (rp != NULL && rp->val.u32 == thistid) {
    00508                     /* Go to the next repackaged package */
    00509                     nrids--;
    00510                     if (nrids > 0)
    00511                         rp++;
    00512                     else
    00513                         rp = NULL;
    00514                 }
    00515                 /* Iterate over installed packages */
    00516                 while (ip != NULL && ip->val.u32 == thistid) {
    00517                     /* Go to the next header in the rpmdb */
    00518                     niids--;
    00519                     if (niids > 0)
    00520                         ip++;
    00521                     else
    00522                         ip = NULL;
    00523                 }
    00524                 continue;               /* with next transaction */
    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         /* Install the previously erased packages for this transaction.
    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 /*@-abstract@*/
    00542                 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key,
    00543                                0, ia->relocations);
    00544 /*@=abstract@*/
    00545                 if (rc != 0)
    00546                     goto exit;
    00547
    00548                 numAdded++;
    00549                 rpmcliPackagesTotal++;
    00550                 if (!(ia->installInterfaceFlags & ifmask))
    00551                     ia->installInterfaceFlags |= INSTALL_UPGRADE;
    00552
    00553                 /* Re-add linked (i.e. from upgrade/obsoletes) erasures. */
    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             /* Go to the next repackaged package */
    00564             nrids--;
    00565             if (nrids > 0)
    00566                 rp++;
    00567             else
    00568                 rp = NULL;
    00569         }
    00570
    00571         /* Re-add pure (i.e. not from upgrade/obsoletes) erasures. */
    00572         rc = findErases(ts, NULL, thistid, ip, niids);
    00573         if (rc < 0)
    00574             goto exit;
    00575
    00576         /* Check that all erasures have been re-added. */
    00577         while (ip != NULL && ip->val.u32 == thistid) {
    00578 #ifdef  NOTNOW
    00579 /* XXX Prevent incomplete rollback transactions. */
    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             /* Go to the next header in the rpmdb */
    00593             niids--;
    00594             if (niids > 0)
    00595                 ip++;
    00596             else
    00597                 ip = NULL;
    00598         }
    00599
    00600         /* Print any rollback transaction problems */
    00601         xx = rpmcliInstallProblems(ts, _("Missing re-packaged package(s)"), 1);
    00602
    00603         /* Anything to do? */
    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         /* Drop added/available package indices and dependency sets. */
    00621         rpmtsClean(ts);
    00622
    00623         /* Print the transaction set. */
    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         /* Remove repackaged packages after successful reinstall. */
    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                     /*@innercontinue@*/ continue;
    00641                 if (rrp->key) { /* XXX can't happen */
    00642                     rpmlog(RPMLOG_NOTICE, _("\tRemoving %s:\n"), rrp->key);
    00643                     (void) unlink(rrp->key);    /* XXX: Should check rc??? */
    00644                 }
    00645             }
    00646         }
    00647
    00648         /* The rpmdb has changed, so reload installed package chains. */
    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         /* Re-position the iterator at the current install tid. */
    00660         while (ip != NULL && ip->val.u32 == thistid) {
    00661             /* Go to the next header in the rpmdb */
    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 }