rpm  5.2.1
lib/rpmrollback.c
Go to the documentation of this file.
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 }