rpm
4.5
|
00001 00005 #include "system.h" 00006 00007 #include <rpmcli.h> 00008 00009 #include "rpmdb.h" 00010 #include "rpmds.h" 00011 00012 #define _RPMTE_INTERNAL /* XXX findErases needs rpmte internals. */ 00013 #include "rpmte.h" /* XXX: rpmteChain */ 00014 #define _RPMTS_INTERNAL /* ts->goal, ts->dbmode, ts->suggests */ 00015 #include "rpmts.h" 00016 00017 #include "manifest.h" 00018 #include "misc.h" /* XXX rpmGlob() */ 00019 #include "rpmgi.h" /* XXX rpmgiEscapeSpaces */ 00020 #include "debug.h" 00021 00022 /*@access rpmts @*/ /* XXX ts->goal, ts->dbmode */ 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, uint_32 rbtid) 00089 { 00090 IDTX idtx = NULL; 00091 rpmdbMatchIterator mi; 00092 HGE_t hge = (HGE_t) headerGetEntry; 00093 Header h; 00094 00095 /*@-branchstate@*/ 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, &tidp, &count) || tidp == NULL) 00107 continue; 00108 00109 if (type == RPM_INT32_TYPE && (*tidp == 0 || *tidp == -1)) 00110 continue; 00111 00112 /* Don't bother with headers installed prior to the rollback goal. */ 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 /*@-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 = *tidp; 00129 } 00130 idtx->nidt++; 00131 } 00132 mi = rpmdbFreeIterator(mi); 00133 /*@=branchstate@*/ 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; /* XXX MinMem? <shrug> */ 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 /*@-branchstate@*/ 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 /*@notreached@*/ /*@switchbreak@*/ 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 /*@switchbreak@*/ 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, &tidp, &count) || tidp == NULL) 00193 goto bottom; 00194 00195 /* Don't bother with headers installed prior to the rollback goal. */ 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 /*@=branchstate@*/ 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 /*@*/ 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 int rc = 0; 00285 int xx; 00286 00287 /* Erase the previously installed packages for this transaction. 00288 * Provided this transaction is not excluded from the rollback. 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, &flinkPkgid, &pn); 00305 00306 /* XXX Always erase packages at beginning of upgrade chain. */ 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, &flinkHdrid, &hn); 00313 xx = hge(ip->h, RPMTAG_BLINKNEVRA, &nt, &flinkNEVRA, &nn); 00314 00315 /* 00316 * Link data may be missing and can have multiple entries. 00317 */ 00318 /* XXX Until link tags are reliably populated, check in the order 00319 * NEVRA -> hdrid -> pkgid 00320 * because NEVRA is easier to debug (hdrid/pkgid are more precise.) 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 /* Cross link the transaction elements to mimic --upgrade. */ 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 /* Go to the next header in the rpmdb */ 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, /*@null@*/ 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; /* XXX no legacy signatures */ 00440 ovsflags = rpmtsSetVSFlags(ts, vsflags); 00441 00442 (void) rpmtsSetFlags(ts, transFlags); 00443 (void) rpmtsSetDFlags(ts, depFlags); 00444 00445 /* Make the transaction a rollback transaction. In a rollback 00446 * a best effort is what we want 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 /* Run transactions until rollback goal is achieved. */ 00484 do { 00485 prevtid = thistid; 00486 rc = 0; 00487 rpmcliPackagesTotal = 0; 00488 numAdded = 0; 00489 numRemoved = 0; 00490 ia->installInterfaceFlags &= ~ifmask; 00491 00492 /* Find larger of the remaining install/erase transaction id's. */ 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 /* If we've achieved the rollback goal, then we're done. */ 00500 if (thistid == 0 || thistid < ia->rbtid) 00501 break; 00502 00503 /* If we've reached the (configured) rollback goal, then we're done. */ 00504 if (_unsafe_rollbacks && thistid <= _unsafe_rollbacks) 00505 break; 00506 00507 /* Is this transaction excluded from the rollback? */ 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 /*@innerbreak@*/ break; 00522 } 00523 } 00524 if (excluded) { 00525 /* Iterate over repackaged packages */ 00526 while (rp != NULL && rp->val.u32 == thistid) { 00527 /* Go to the next repackaged package */ 00528 nrids--; 00529 if (nrids > 0) 00530 rp++; 00531 else 00532 rp = NULL; 00533 } 00534 /* Iterate over installed packages */ 00535 while (ip != NULL && ip->val.u32 == thistid) { 00536 /* Go to the next header in the rpmdb */ 00537 niids--; 00538 if (niids > 0) 00539 ip++; 00540 else 00541 ip = NULL; 00542 } 00543 continue; /* with next transaction */ 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 /* Install the previously erased packages for this transaction. 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 /*@-abstract@*/ 00561 rc = rpmtsAddInstallElement(ts, rp->h, (fnpyKey)rp->key, 00562 0, ia->relocations); 00563 /*@=abstract@*/ 00564 if (rc != 0) 00565 goto exit; 00566 00567 numAdded++; 00568 rpmcliPackagesTotal++; 00569 if (!(ia->installInterfaceFlags & ifmask)) 00570 ia->installInterfaceFlags |= INSTALL_UPGRADE; 00571 00572 /* Re-add linked (i.e. from upgrade/obsoletes) erasures. */ 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 /* Go to the next repackaged package */ 00583 nrids--; 00584 if (nrids > 0) 00585 rp++; 00586 else 00587 rp = NULL; 00588 } 00589 00590 /* Re-add pure (i.e. not from upgrade/obsoletes) erasures. */ 00591 rc = findErases(ts, NULL, thistid, ip, niids); 00592 if (rc < 0) 00593 goto exit; 00594 00595 /* Check that all erasures have been re-added. */ 00596 while (ip != NULL && ip->val.u32 == thistid) { 00597 #ifdef NOTNOW 00598 /* XXX Prevent incomplete rollback transactions. */ 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 /* Go to the next header in the rpmdb */ 00612 niids--; 00613 if (niids > 0) 00614 ip++; 00615 else 00616 ip = NULL; 00617 } 00618 00619 /* Print any rollback transaction problems */ 00620 (void) rpmrbProblems(ts, N_("Missing re-packaged package(s)"), 1); 00621 00622 /* Anything to do? */ 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 /* Drop added/available package indices and dependency sets. */ 00640 rpmtsClean(ts); 00641 00642 /* Print the transaction set. */ 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 /* Remove repackaged packages after successful reinstall. */ 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 /*@innercontinue@*/ continue; 00660 if (rrp->key) { /* XXX can't happen */ 00661 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), rrp->key); 00662 (void) unlink(rrp->key); /* XXX: Should check rc??? */ 00663 } 00664 } 00665 } 00666 00667 /* The rpmdb has changed, so reload installed package chains. */ 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 /* Re-position the iterator at the current install tid. */ 00679 while (ip != NULL && ip->val.u32 == thistid) { 00680 /* Go to the next header in the rpmdb */ 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 }