lib/transaction.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 #include <rpmlib.h>
00007 
00008 #include <rpmmacro.h>   /* XXX for rpmExpand */
00009 
00010 #include "fsm.h"
00011 #include "psm.h"
00012 
00013 #include "rpmdb.h"
00014 
00015 #include "rpmds.h"
00016 
00017 #include "rpmlock.h"
00018 
00019 #define _RPMFI_INTERNAL
00020 #include "rpmfi.h"
00021 
00022 #define _RPMTE_INTERNAL
00023 #include "rpmte.h"
00024 
00025 #define _RPMTS_INTERNAL
00026 #include "rpmts.h"
00027 
00028 #include "cpio.h"
00029 #include "fprint.h"
00030 #include "legacy.h"     /* XXX domd5 */
00031 #include "misc.h" /* XXX stripTrailingChar, splitString, currentDirectory */
00032 
00033 #include "debug.h"
00034 
00035 /*
00036  * This is needed for the IDTX definitions.  I think probably those need
00037  * to be moved into a different source file (idtx.{c,h}), but that is up
00038  * to Jeff Johnson.
00039  */
00040 #include "rpmcli.h"
00041 
00042 /*@access Header @*/            /* XXX ts->notify arg1 is void ptr */
00043 /*@access rpmps @*/     /* XXX need rpmProblemSetOK() */
00044 /*@access dbiIndexSet @*/
00045 
00046 /*@access rpmpsm @*/
00047 
00048 /*@access alKey @*/
00049 /*@access fnpyKey @*/
00050 
00051 /*@access rpmfi @*/
00052 
00053 /*@access rpmte @*/
00054 /*@access rpmtsi @*/
00055 /*@access rpmts @*/
00056 
00057 /*@access IDT @*/
00058 /*@access IDTX @*/
00059 /*@access FD_t @*/
00060 
00061 /* XXX: This is a hack.  I needed a to setup a notify callback
00062  * for the rollback transaction, but I did not want to create
00063  * a header for rpminstall.c.
00064  */
00065 extern void * rpmShowProgress(/*@null@*/ const void * arg,
00066                         const rpmCallbackType what,
00067                         const unsigned long amount,
00068                         const unsigned long total,
00069                         /*@null@*/ fnpyKey key,
00070                         /*@null@*/ void * data)
00071         /*@*/;
00072 
00075 static int archOkay(/*@null@*/ const char * pkgArch)
00076         /*@*/
00077 {
00078     if (pkgArch == NULL) return 0;
00079     return (rpmMachineScore(RPM_MACHTABLE_INSTARCH, pkgArch) ? 1 : 0);
00080 }
00081 
00084 static int osOkay(/*@null@*/ const char * pkgOs)
00085         /*@*/
00086 {
00087     if (pkgOs == NULL) return 0;
00088     return (rpmMachineScore(RPM_MACHTABLE_INSTOS, pkgOs) ? 1 : 0);
00089 }
00090 
00093 static int sharedCmp(const void * one, const void * two)
00094         /*@*/
00095 {
00096     sharedFileInfo a = (sharedFileInfo) one;
00097     sharedFileInfo b = (sharedFileInfo) two;
00098 
00099     if (a->otherPkg < b->otherPkg)
00100         return -1;
00101     else if (a->otherPkg > b->otherPkg)
00102         return 1;
00103 
00104     return 0;
00105 }
00106 
00115 /* XXX only ts->{probs,rpmdb} modified */
00116 /*@-bounds@*/
00117 static int handleInstInstalledFiles(const rpmts ts,
00118                 rpmte p, rpmfi fi,
00119                 sharedFileInfo shared,
00120                 int sharedCount, int reportConflicts)
00121         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00122         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
00123 {
00124     uint_32 tscolor = rpmtsColor(ts);
00125     uint_32 otecolor, tecolor;
00126     uint_32 oFColor, FColor;
00127     const char * altNEVR = NULL;
00128     rpmfi otherFi = NULL;
00129     int numReplaced = 0;
00130     rpmps ps;
00131     int i;
00132 
00133     {   rpmdbMatchIterator mi;
00134         Header h;
00135         int scareMem = 0;
00136 
00137         mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
00138                         &shared->otherPkg, sizeof(shared->otherPkg));
00139         while ((h = rpmdbNextIterator(mi)) != NULL) {
00140             altNEVR = hGetNEVR(h, NULL);
00141             otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
00142             break;
00143         }
00144         mi = rpmdbFreeIterator(mi);
00145     }
00146 
00147     /* Compute package color. */
00148     tecolor = rpmteColor(p);
00149     tecolor &= tscolor;
00150 
00151     /* Compute other pkg color. */
00152     otecolor = 0;
00153     otherFi = rpmfiInit(otherFi, 0);
00154     if (otherFi != NULL)
00155     while (rpmfiNext(otherFi) >= 0)
00156         otecolor |= rpmfiFColor(otherFi);
00157     otecolor &= tscolor;
00158 
00159     if (otherFi == NULL)
00160         return 1;
00161 
00162     fi->replaced = xcalloc(sharedCount, sizeof(*fi->replaced));
00163 
00164     ps = rpmtsProblems(ts);
00165     for (i = 0; i < sharedCount; i++, shared++) {
00166         int otherFileNum, fileNum;
00167         int isCfgFile;
00168 
00169         otherFileNum = shared->otherFileNum;
00170         (void) rpmfiSetFX(otherFi, otherFileNum);
00171         oFColor = rpmfiFColor(otherFi);
00172         oFColor &= tscolor;
00173 
00174         fileNum = shared->pkgFileNum;
00175         (void) rpmfiSetFX(fi, fileNum);
00176         FColor = rpmfiFColor(fi);
00177         FColor &= tscolor;
00178 
00179         isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
00180 
00181 #ifdef  DYING
00182         /* XXX another tedious segfault, assume file state normal. */
00183         if (otherStates && otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
00184             continue;
00185 #endif
00186 
00187         if (XFA_SKIPPING(fi->actions[fileNum]))
00188             continue;
00189 
00190         if (rpmfiCompare(otherFi, fi)) {
00191             int rConflicts;
00192 
00193             rConflicts = reportConflicts;
00194             /* Resolve file conflicts to prefer Elf64 (if not forced). */
00195             if (tscolor != 0 && FColor != 0 && FColor != oFColor)
00196             {
00197                 if (oFColor & 0x2) {
00198                     fi->actions[fileNum] = FA_SKIPCOLOR;
00199                     rConflicts = 0;
00200                 } else
00201                 if (FColor & 0x2) {
00202                     fi->actions[fileNum] = FA_CREATE;
00203                     rConflicts = 0;
00204                 }
00205             }
00206 
00207             if (rConflicts) {
00208                 rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
00209                         rpmteNEVR(p), rpmteKey(p),
00210                         rpmfiDN(fi), rpmfiBN(fi),
00211                         altNEVR,
00212                         0);
00213             }
00214             /* Save file identifier to mark as state REPLACED. */
00215             if ( !(isCfgFile || XFA_SKIPPING(fi->actions[fileNum])) ) {
00216                 /*@-assignexpose@*/ /* FIX: p->replaced, not fi */
00217                 if (!shared->isRemoved)
00218                     fi->replaced[numReplaced++] = *shared;
00219                 /*@=assignexpose@*/
00220             }
00221         }
00222 
00223         /* Determine config file dispostion, skipping missing files (if any). */
00224         if (isCfgFile) {
00225             int skipMissing =
00226                 ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
00227             fileAction action = rpmfiDecideFate(otherFi, fi, skipMissing);
00228             fi->actions[fileNum] = action;
00229         }
00230         fi->replacedSizes[fileNum] = rpmfiFSize(otherFi);
00231     }
00232     ps = rpmpsFree(ps);
00233 
00234     altNEVR = _free(altNEVR);
00235     otherFi = rpmfiFree(otherFi);
00236 
00237     fi->replaced = xrealloc(fi->replaced,       /* XXX memory leak */
00238                            sizeof(*fi->replaced) * (numReplaced + 1));
00239     fi->replaced[numReplaced].otherPkg = 0;
00240 
00241     return 0;
00242 }
00243 /*@=bounds@*/
00244 
00247 /* XXX only ts->rpmdb modified */
00248 static int handleRmvdInstalledFiles(const rpmts ts, rpmfi fi,
00249                 sharedFileInfo shared, int sharedCount)
00250         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00251         /*@modifies ts, fi, rpmGlobalMacroContext, fileSystem, internalState @*/
00252 {
00253     HGE_t hge = fi->hge;
00254     Header h;
00255     const char * otherStates;
00256     int i, xx;
00257 
00258     rpmdbMatchIterator mi;
00259 
00260     mi = rpmtsInitIterator(ts, RPMDBI_PACKAGES,
00261                         &shared->otherPkg, sizeof(shared->otherPkg));
00262     h = rpmdbNextIterator(mi);
00263     if (h == NULL) {
00264         mi = rpmdbFreeIterator(mi);
00265         return 1;
00266     }
00267 
00268     xx = hge(h, RPMTAG_FILESTATES, NULL, (void **) &otherStates, NULL);
00269 
00270 /*@-boundswrite@*/
00271     for (i = 0; i < sharedCount; i++, shared++) {
00272         int otherFileNum, fileNum;
00273         otherFileNum = shared->otherFileNum;
00274         fileNum = shared->pkgFileNum;
00275 
00276         if (otherStates[otherFileNum] != RPMFILE_STATE_NORMAL)
00277             continue;
00278 
00279         fi->actions[fileNum] = FA_SKIP;
00280     }
00281 /*@=boundswrite@*/
00282 
00283     mi = rpmdbFreeIterator(mi);
00284 
00285     return 0;
00286 }
00287 
00288 #define ISROOT(_d)      (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
00289 
00290 /*@unchecked@*/
00291 int _fps_debug = 0;
00292 
00293 static int fpsCompare (const void * one, const void * two)
00294         /*@*/
00295 {
00296     const struct fingerPrint_s * a = (const struct fingerPrint_s *)one;
00297     const struct fingerPrint_s * b = (const struct fingerPrint_s *)two;
00298     int adnlen = strlen(a->entry->dirName);
00299     int asnlen = (a->subDir ? strlen(a->subDir) : 0);
00300     int abnlen = strlen(a->baseName);
00301     int bdnlen = strlen(b->entry->dirName);
00302     int bsnlen = (b->subDir ? strlen(b->subDir) : 0);
00303     int bbnlen = strlen(b->baseName);
00304     char * afn, * bfn, * t;
00305     int rc = 0;
00306 
00307     if (adnlen == 1 && asnlen != 0) adnlen = 0;
00308     if (bdnlen == 1 && bsnlen != 0) bdnlen = 0;
00309 
00310 /*@-boundswrite@*/
00311     afn = t = alloca(adnlen+asnlen+abnlen+2);
00312     if (adnlen) t = stpcpy(t, a->entry->dirName);
00313     *t++ = '/';
00314     if (a->subDir && asnlen) t = stpcpy(t, a->subDir);
00315     if (abnlen) t = stpcpy(t, a->baseName);
00316     if (afn[0] == '/' && afn[1] == '/') afn++;
00317 
00318     bfn = t = alloca(bdnlen+bsnlen+bbnlen+2);
00319     if (bdnlen) t = stpcpy(t, b->entry->dirName);
00320     *t++ = '/';
00321     if (b->subDir && bsnlen) t = stpcpy(t, b->subDir);
00322     if (bbnlen) t = stpcpy(t, b->baseName);
00323     if (bfn[0] == '/' && bfn[1] == '/') bfn++;
00324 /*@=boundswrite@*/
00325 
00326     rc = strcmp(afn, bfn);
00327 /*@-modfilesys@*/
00328 if (_fps_debug)
00329 fprintf(stderr, "\trc(%d) = strcmp(\"%s\", \"%s\")\n", rc, afn, bfn);
00330 /*@=modfilesys@*/
00331 
00332 /*@-modfilesys@*/
00333 if (_fps_debug)
00334 fprintf(stderr, "\t%s/%s%s\trc %d\n",
00335 ISROOT(b->entry->dirName),
00336 (b->subDir ? b->subDir : ""),
00337 b->baseName,
00338 rc
00339 );
00340 /*@=modfilesys@*/
00341 
00342     return rc;
00343 }
00344 
00345 /*@unchecked@*/
00346 static int _linear_fps_search = 0;
00347 
00348 static int findFps(const struct fingerPrint_s * fiFps,
00349                 const struct fingerPrint_s * otherFps,
00350                 int otherFc)
00351         /*@*/
00352 {
00353     int otherFileNum;
00354 
00355 /*@-modfilesys@*/
00356 if (_fps_debug)
00357 fprintf(stderr, "==> %s/%s%s\n",
00358 ISROOT(fiFps->entry->dirName),
00359 (fiFps->subDir ? fiFps->subDir : ""),
00360 fiFps->baseName);
00361 /*@=modfilesys@*/
00362 
00363   if (_linear_fps_search) {
00364 
00365 linear:
00366     for (otherFileNum = 0; otherFileNum < otherFc; otherFileNum++, otherFps++) {
00367 
00368 /*@-modfilesys@*/
00369 if (_fps_debug)
00370 fprintf(stderr, "\t%4d %s/%s%s\n", otherFileNum,
00371 ISROOT(otherFps->entry->dirName),
00372 (otherFps->subDir ? otherFps->subDir : ""),
00373 otherFps->baseName);
00374 /*@=modfilesys@*/
00375 
00376         /* If the addresses are the same, so are the values. */
00377         if (fiFps == otherFps)
00378             break;
00379 
00380         /* Otherwise, compare fingerprints by value. */
00381         /*@-nullpass@*/ /* LCL: looks good to me */
00382         if (FP_EQUAL((*fiFps), (*otherFps)))
00383             break;
00384         /*@=nullpass@*/
00385     }
00386 
00387 if (otherFileNum == otherFc) {
00388 /*@-modfilesys@*/
00389 if (_fps_debug)
00390 fprintf(stderr, "*** FP_EQUAL NULL %s/%s%s\n",
00391 ISROOT(fiFps->entry->dirName),
00392 (fiFps->subDir ? fiFps->subDir : ""),
00393 fiFps->baseName);
00394 /*@=modfilesys@*/
00395 }
00396 
00397     return otherFileNum;
00398 
00399   } else {
00400 
00401     const struct fingerPrint_s * bingoFps;
00402 
00403 /*@-boundswrite@*/
00404     bingoFps = bsearch(fiFps, otherFps, otherFc, sizeof(*otherFps), fpsCompare);
00405 /*@=boundswrite@*/
00406     if (bingoFps == NULL) {
00407 /*@-modfilesys@*/
00408 if (_fps_debug)
00409 fprintf(stderr, "*** bingoFps NULL %s/%s%s\n",
00410 ISROOT(fiFps->entry->dirName),
00411 (fiFps->subDir ? fiFps->subDir : ""),
00412 fiFps->baseName);
00413 /*@=modfilesys@*/
00414         goto linear;
00415     }
00416 
00417     /* If the addresses are the same, so are the values. */
00418     /*@-nullpass@*/     /* LCL: looks good to me */
00419     if (!(fiFps == bingoFps || FP_EQUAL((*fiFps), (*bingoFps)))) {
00420 /*@-modfilesys@*/
00421 if (_fps_debug)
00422 fprintf(stderr, "***  BAD %s/%s%s\n",
00423 ISROOT(bingoFps->entry->dirName),
00424 (bingoFps->subDir ? bingoFps->subDir : ""),
00425 bingoFps->baseName);
00426 /*@=modfilesys@*/
00427         goto linear;
00428     }
00429 
00430     otherFileNum = (bingoFps != NULL ? (bingoFps - otherFps) : 0);
00431 
00432   }
00433 
00434     return otherFileNum;
00435 }
00436 
00440 /* XXX only ts->{probs,di} modified */
00441 static void handleOverlappedFiles(const rpmts ts,
00442                 const rpmte p, rpmfi fi)
00443         /*@globals h_errno, fileSystem, internalState @*/
00444         /*@modifies ts, fi, fileSystem, internalState @*/
00445 {
00446     uint_32 fixupSize = 0;
00447     rpmps ps;
00448     const char * fn;
00449     int i, j;
00450 
00451     ps = rpmtsProblems(ts);
00452     fi = rpmfiInit(fi, 0);
00453     if (fi != NULL)
00454     while ((i = rpmfiNext(fi)) >= 0) {
00455         uint_32 tscolor = rpmtsColor(ts);
00456         uint_32 oFColor, FColor;
00457         struct fingerPrint_s * fiFps;
00458         int otherPkgNum, otherFileNum;
00459         rpmfi otherFi;
00460         int_32 FFlags;
00461         int_16 FMode;
00462         const rpmfi * recs;
00463         int numRecs;
00464 
00465         if (XFA_SKIPPING(fi->actions[i]))
00466             continue;
00467 
00468         fn = rpmfiFN(fi);
00469         fiFps = fi->fps + i;
00470         FFlags = rpmfiFFlags(fi);
00471         FMode = rpmfiFMode(fi);
00472         FColor = rpmfiFColor(fi);
00473         FColor &= tscolor;
00474 
00475         fixupSize = 0;
00476 
00477         /*
00478          * Retrieve all records that apply to this file. Note that the
00479          * file info records were built in the same order as the packages
00480          * will be installed and removed so the records for an overlapped
00481          * files will be sorted in exactly the same order.
00482          */
00483         (void) htGetEntry(ts->ht, fiFps,
00484                         (const void ***) &recs, &numRecs, NULL);
00485 
00486         /*
00487          * If this package is being added, look only at other packages
00488          * being added -- removed packages dance to a different tune.
00489          *
00490          * If both this and the other package are being added, overlapped
00491          * files must be identical (or marked as a conflict). The
00492          * disposition of already installed config files leads to
00493          * a small amount of extra complexity.
00494          *
00495          * If this package is being removed, then there are two cases that
00496          * need to be worried about:
00497          * If the other package is being added, then skip any overlapped files
00498          * so that this package removal doesn't nuke the overlapped files
00499          * that were just installed.
00500          * If both this and the other package are being removed, then each
00501          * file removal from preceding packages needs to be skipped so that
00502          * the file removal occurs only on the last occurence of an overlapped
00503          * file in the transaction set.
00504          *
00505          */
00506 
00507         /* Locate this overlapped file in the set of added/removed packages. */
00508         for (j = 0; j < numRecs && recs[j] != fi; j++)
00509             {};
00510 
00511         /* Find what the previous disposition of this file was. */
00512         otherFileNum = -1;                      /* keep gcc quiet */
00513         otherFi = NULL;
00514         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
00515             struct fingerPrint_s * otherFps;
00516             int otherFc;
00517 
00518             otherFi = recs[otherPkgNum];
00519 
00520             /* Added packages need only look at other added packages. */
00521             if (rpmteType(p) == TR_ADDED && rpmteType(otherFi->te) != TR_ADDED)
00522                 /*@innercontinue@*/ continue;
00523 
00524             otherFps = otherFi->fps;
00525             otherFc = rpmfiFC(otherFi);
00526 
00527             otherFileNum = findFps(fiFps, otherFps, otherFc);
00528             (void) rpmfiSetFX(otherFi, otherFileNum);
00529 
00530             /* XXX Happens iff fingerprint for incomplete package install. */
00531             if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
00532                 /*@innerbreak@*/ break;
00533         }
00534 
00535         oFColor = rpmfiFColor(otherFi);
00536         oFColor &= tscolor;
00537 
00538 /*@-boundswrite@*/
00539         switch (rpmteType(p)) {
00540         case TR_ADDED:
00541           { struct stat sb;
00542             int reportConflicts =
00543                 !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
00544             int done = 0;
00545 
00546             if (otherPkgNum < 0) {
00547                 /* XXX is this test still necessary? */
00548                 if (fi->actions[i] != FA_UNKNOWN)
00549                     /*@switchbreak@*/ break;
00550                 if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
00551                     /* Here is a non-overlapped pre-existing config file. */
00552                     fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
00553                         ? FA_ALTNAME : FA_BACKUP;
00554                 } else {
00555                     fi->actions[i] = FA_CREATE;
00556                 }
00557                 /*@switchbreak@*/ break;
00558             }
00559 
00560 assert(otherFi != NULL);
00561             /* Mark added overlapped non-identical files as a conflict. */
00562             if (rpmfiCompare(otherFi, fi)) {
00563                 int rConflicts;
00564 
00565                 rConflicts = reportConflicts;
00566                 /* Resolve file conflicts to prefer Elf64 (if not forced) ... */
00567                 if (tscolor != 0) {
00568                     if (FColor & 0x2) {
00569                         /* ... last Elf64 file is installed ... */
00570                         if (!XFA_SKIPPING(fi->actions[i])) {
00571                             /* XXX static helpers are order dependent. Ick. */
00572                             if (strcmp(fn, "/usr/sbin/libgcc_post_upgrade")
00573                              && strcmp(fn, "/usr/sbin/glibc_post_upgrade"))
00574                                 otherFi->actions[otherFileNum] = FA_SKIP;
00575                         }
00576                         fi->actions[i] = FA_CREATE;
00577                         rConflicts = 0;
00578                     } else
00579                     if (oFColor & 0x2) {
00580                         /* ... first Elf64 file is installed ... */
00581                         if (XFA_SKIPPING(fi->actions[i]))
00582                             otherFi->actions[otherFileNum] = FA_CREATE;
00583                         fi->actions[i] = FA_SKIPCOLOR;
00584                         rConflicts = 0;
00585                     } else
00586                     if (FColor == 0 && oFColor == 0) {
00587                         /* ... otherwise, do both, last in wins. */
00588                         otherFi->actions[otherFileNum] = FA_CREATE;
00589                         fi->actions[i] = FA_CREATE;
00590                         rConflicts = 0;
00591                     }
00592                     done = 1;
00593                 }
00594 
00595                 if (rConflicts) {
00596                     rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
00597                         rpmteNEVR(p), rpmteKey(p),
00598                         fn, NULL,
00599                         rpmteNEVR(otherFi->te),
00600                         0);
00601                 }
00602             }
00603 
00604             /* Try to get the disk accounting correct even if a conflict. */
00605             fixupSize = rpmfiFSize(otherFi);
00606 
00607             if ((FFlags & RPMFILE_CONFIG) && !lstat(fn, &sb)) {
00608                 /* Here is an overlapped  pre-existing config file. */
00609                 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
00610                         ? FA_ALTNAME : FA_SKIP;
00611             } else {
00612                 if (!done)
00613                     fi->actions[i] = FA_CREATE;
00614             }
00615           } /*@switchbreak@*/ break;
00616 
00617         case TR_REMOVED:
00618             if (otherPkgNum >= 0) {
00619 assert(otherFi != NULL);
00620                 /* Here is an overlapped added file we don't want to nuke. */
00621                 if (otherFi->actions[otherFileNum] != FA_ERASE) {
00622                     /* On updates, don't remove files. */
00623                     fi->actions[i] = FA_SKIP;
00624                     /*@switchbreak@*/ break;
00625                 }
00626                 /* Here is an overlapped removed file: skip in previous. */
00627                 otherFi->actions[otherFileNum] = FA_SKIP;
00628             }
00629             if (XFA_SKIPPING(fi->actions[i]))
00630                 /*@switchbreak@*/ break;
00631             if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
00632                 /*@switchbreak@*/ break;
00633             if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG))) {
00634                 fi->actions[i] = FA_ERASE;
00635                 /*@switchbreak@*/ break;
00636             }
00637                 
00638             /* Here is a pre-existing modified config file that needs saving. */
00639             /* XXX avoid md5 on sparse /var/log/lastlog file. */
00640             if (strcmp(fn, "/var/log/lastlog"))
00641             {   char md5sum[50];
00642                 const unsigned char * MD5 = rpmfiMD5(fi);
00643                 if (!domd5(fn, md5sum, 0, NULL) && memcmp(MD5, md5sum, 16)) {
00644                     fi->actions[i] = FA_BACKUP;
00645                     /*@switchbreak@*/ break;
00646                 }
00647             }
00648             fi->actions[i] = FA_ERASE;
00649             /*@switchbreak@*/ break;
00650         }
00651 /*@=boundswrite@*/
00652 
00653         /* Update disk space info for a file. */
00654         rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
00655                 fi->replacedSizes[i], fixupSize, fi->actions[i]);
00656 
00657     }
00658     ps = rpmpsFree(ps);
00659 }
00660 
00668 static int ensureOlder(rpmts ts,
00669                 const rpmte p, const Header h)
00670         /*@modifies ts @*/
00671 {
00672     int_32 reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
00673     const char * reqEVR;
00674     rpmds req;
00675     char * t;
00676     int nb;
00677     int rc;
00678 
00679     if (p == NULL || h == NULL)
00680         return 1;
00681 
00682 /*@-boundswrite@*/
00683     nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
00684     t = alloca(nb);
00685     *t = '\0';
00686     reqEVR = t;
00687     if (rpmteE(p) != NULL)      t = stpcpy( stpcpy(t, rpmteE(p)), ":");
00688     if (rpmteV(p) != NULL)      t = stpcpy(t, rpmteV(p));
00689     *t++ = '-';
00690     if (rpmteR(p) != NULL)      t = stpcpy(t, rpmteR(p));
00691 /*@=boundswrite@*/
00692 
00693     req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
00694     rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
00695     req = rpmdsFree(req);
00696 
00697     if (rc == 0) {
00698         rpmps ps = rpmtsProblems(ts);
00699         const char * altNEVR = hGetNEVR(h, NULL);
00700         rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
00701                 rpmteNEVR(p), rpmteKey(p),
00702                 NULL, NULL,
00703                 altNEVR,
00704                 0);
00705         altNEVR = _free(altNEVR);
00706         ps = rpmpsFree(ps);
00707         rc = 1;
00708     } else
00709         rc = 0;
00710 
00711     return rc;
00712 }
00713 
00719 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
00720 /*@-bounds@*/
00721 static void skipFiles(const rpmts ts, rpmfi fi)
00722         /*@globals rpmGlobalMacroContext, h_errno @*/
00723         /*@modifies fi, rpmGlobalMacroContext @*/
00724 {
00725     uint_32 tscolor = rpmtsColor(ts);
00726     uint_32 FColor;
00727     int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
00728     int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
00729     char ** netsharedPaths = NULL;
00730     const char ** languages;
00731     const char * dn, * bn;
00732     int dnlen, bnlen, ix;
00733     const char * s;
00734     int * drc;
00735     char * dff;
00736     int dc;
00737     int i, j;
00738 
00739     if (!noDocs)
00740         noDocs = rpmExpandNumeric("%{_excludedocs}");
00741 
00742     {   const char *tmpPath = rpmExpand("%{_netsharedpath}", NULL);
00743         /*@-branchstate@*/
00744         if (tmpPath && *tmpPath != '%')
00745             netsharedPaths = splitString(tmpPath, strlen(tmpPath), ':');
00746         /*@=branchstate@*/
00747         tmpPath = _free(tmpPath);
00748     }
00749 
00750     s = rpmExpand("%{_install_langs}", NULL);
00751     /*@-branchstate@*/
00752     if (!(s && *s != '%'))
00753         s = _free(s);
00754     if (s) {
00755         languages = (const char **) splitString(s, strlen(s), ':');
00756         s = _free(s);
00757     } else
00758         languages = NULL;
00759     /*@=branchstate@*/
00760 
00761     /* Compute directory refcount, skip directory if now empty. */
00762     dc = rpmfiDC(fi);
00763     drc = alloca(dc * sizeof(*drc));
00764     memset(drc, 0, dc * sizeof(*drc));
00765     dff = alloca(dc * sizeof(*dff));
00766     memset(dff, 0, dc * sizeof(*dff));
00767 
00768     fi = rpmfiInit(fi, 0);
00769     if (fi != NULL)     /* XXX lclint */
00770     while ((i = rpmfiNext(fi)) >= 0)
00771     {
00772         char ** nsp;
00773 
00774         bn = rpmfiBN(fi);
00775         bnlen = strlen(bn);
00776         ix = rpmfiDX(fi);
00777         dn = rpmfiDN(fi);
00778         dnlen = strlen(dn);
00779         if (dn == NULL)
00780             continue;   /* XXX can't happen */
00781 
00782         drc[ix]++;
00783 
00784         /* Don't bother with skipped files */
00785         if (XFA_SKIPPING(fi->actions[i])) {
00786             drc[ix]--; dff[ix] = 1;
00787             continue;
00788         }
00789 
00790         /* Ignore colored files not in our rainbow. */
00791         FColor = rpmfiFColor(fi);
00792         if (tscolor && FColor && !(tscolor & FColor)) {
00793             drc[ix]--;  dff[ix] = 1;
00794             fi->actions[i] = FA_SKIPCOLOR;
00795             continue;
00796         }
00797 
00798         /*
00799          * Skip net shared paths.
00800          * Net shared paths are not relative to the current root (though
00801          * they do need to take package relocations into account).
00802          */
00803         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
00804             int len;
00805 
00806             len = strlen(*nsp);
00807             if (dnlen >= len) {
00808                 if (strncmp(dn, *nsp, len))
00809                     /*@innercontinue@*/ continue;
00810                 /* Only directories or complete file paths can be net shared */
00811                 if (!(dn[len] == '/' || dn[len] == '\0'))
00812                     /*@innercontinue@*/ continue;
00813             } else {
00814                 if (len < (dnlen + bnlen))
00815                     /*@innercontinue@*/ continue;
00816                 if (strncmp(dn, *nsp, dnlen))
00817                     /*@innercontinue@*/ continue;
00818                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
00819                     /*@innercontinue@*/ continue;
00820                 len = dnlen + bnlen;
00821                 /* Only directories or complete file paths can be net shared */
00822                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
00823                     /*@innercontinue@*/ continue;
00824             }
00825 
00826             /*@innerbreak@*/ break;
00827         }
00828 
00829         if (nsp && *nsp) {
00830             drc[ix]--;  dff[ix] = 1;
00831             fi->actions[i] = FA_SKIPNETSHARED;
00832             continue;
00833         }
00834 
00835         /*
00836          * Skip i18n language specific files.
00837          */
00838         if (languages != NULL && fi->flangs != NULL && *fi->flangs[i]) {
00839             const char **lang, *l, *le;
00840             for (lang = languages; *lang != NULL; lang++) {
00841                 if (!strcmp(*lang, "all"))
00842                     /*@innerbreak@*/ break;
00843                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
00844                     for (le = l; *le != '\0' && *le != '|'; le++)
00845                         {};
00846                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
00847                         /*@innerbreak@*/ break;
00848                     if (*le == '|') le++;       /* skip over | */
00849                 }
00850                 if (*l != '\0')
00851                     /*@innerbreak@*/ break;
00852             }
00853             if (*lang == NULL) {
00854                 drc[ix]--;      dff[ix] = 1;
00855                 fi->actions[i] = FA_SKIPNSTATE;
00856                 continue;
00857             }
00858         }
00859 
00860         /*
00861          * Skip config files if requested.
00862          */
00863         if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
00864             drc[ix]--;  dff[ix] = 1;
00865             fi->actions[i] = FA_SKIPNSTATE;
00866             continue;
00867         }
00868 
00869         /*
00870          * Skip documentation if requested.
00871          */
00872         if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
00873             drc[ix]--;  dff[ix] = 1;
00874             fi->actions[i] = FA_SKIPNSTATE;
00875             continue;
00876         }
00877     }
00878 
00879     /* Skip (now empty) directories that had skipped files. */
00880 #ifndef NOTYET
00881     if (fi != NULL)     /* XXX can't happen */
00882     for (j = 0; j < dc; j++)
00883 #else
00884     if ((fi = rpmfiInitD(fi)) != NULL)
00885     while (j = rpmfiNextD(fi) >= 0)
00886 #endif
00887     {
00888 
00889         if (drc[j]) continue;   /* dir still has files. */
00890         if (!dff[j]) continue;  /* dir was not emptied here. */
00891         
00892         /* Find parent directory and basename. */
00893         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
00894         bn = dn + dnlen;        bnlen = 0;
00895         while (bn > dn && bn[-1] != '/') {
00896                 bnlen++;
00897                 dnlen--;
00898                 bn--;
00899         }
00900 
00901         /* If explicitly included in the package, skip the directory. */
00902         fi = rpmfiInit(fi, 0);
00903         if (fi != NULL)         /* XXX lclint */
00904         while ((i = rpmfiNext(fi)) >= 0) {
00905             const char * fdn, * fbn;
00906             int_16 fFMode;
00907 
00908             if (XFA_SKIPPING(fi->actions[i]))
00909                 /*@innercontinue@*/ continue;
00910 
00911             fFMode = rpmfiFMode(fi);
00912 
00913             if (whatis(fFMode) != XDIR)
00914                 /*@innercontinue@*/ continue;
00915             fdn = rpmfiDN(fi);
00916             if (strlen(fdn) != dnlen)
00917                 /*@innercontinue@*/ continue;
00918             if (strncmp(fdn, dn, dnlen))
00919                 /*@innercontinue@*/ continue;
00920             fbn = rpmfiBN(fi);
00921             if (strlen(fbn) != bnlen)
00922                 /*@innercontinue@*/ continue;
00923             if (strncmp(fbn, bn, bnlen))
00924                 /*@innercontinue@*/ continue;
00925             rpmMessage(RPMMESS_DEBUG, _("excluding directory %s\n"), dn);
00926             fi->actions[i] = FA_SKIPNSTATE;
00927             /*@innerbreak@*/ break;
00928         }
00929     }
00930 
00931 /*@-dependenttrans@*/
00932     if (netsharedPaths) freeSplitString(netsharedPaths);
00933 #ifdef  DYING   /* XXX freeFi will deal with this later. */
00934     fi->flangs = _free(fi->flangs);
00935 #endif
00936     if (languages) freeSplitString((char **)languages);
00937 /*@=dependenttrans@*/
00938 }
00939 /*@=bounds@*/
00940 /*@=mustmod@*/
00941 
00948 static /*@null@*/
00949 rpmfi rpmtsiFi(const rpmtsi tsi)
00950         /*@*/
00951 {
00952     rpmfi fi = NULL;
00953 
00954     if (tsi != NULL && tsi->ocsave != -1) {
00955         /*@-type -abstract@*/ /* FIX: rpmte not opaque */
00956         rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
00957         /*@-assignexpose@*/
00958         if (te != NULL && (fi = te->fi) != NULL)
00959             fi->te = te;
00960         /*@=assignexpose@*/
00961         /*@=type =abstract@*/
00962     }
00963     /*@-compdef -refcounttrans -usereleased @*/
00964     return fi;
00965     /*@=compdef =refcounttrans =usereleased @*/
00966 }
00967 
00975 static rpmRC _rpmtsRollback(rpmts rollbackTransaction)
00976         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00977         /*@modifies rollbackTransaction,
00978                 rpmGlobalMacroContext, fileSystem, internalState @*/
00979 {
00980     int    rc         = 0;
00981     int    numAdded   = 0;
00982     int    numRemoved = 0;
00983     int_32 tid;
00984     rpmtsi tsi;
00985     rpmte  te;
00986     rpmps  ps;
00987 
00988     /*
00989      * Gather information about this rollback transaction for reporting.
00990      *    1) Get tid
00991      */
00992     tid = rpmtsGetTid(rollbackTransaction);
00993 
00994     /*
00995      *    2) Get number of install elments and erase elements
00996      */
00997     tsi = rpmtsiInit(rollbackTransaction);
00998     while((te = rpmtsiNext(tsi, 0)) != NULL) {
00999         switch (rpmteType(te)) {
01000         case TR_ADDED:
01001            numAdded++;
01002            /*@switchbreak@*/ break;
01003         case TR_REMOVED:
01004            numRemoved++;
01005            /*@switchbreak@*/ break;
01006         default:
01007            /*@switchbreak@*/ break;
01008         }       
01009     }
01010     tsi = rpmtsiFree(tsi);
01011 
01012     rpmMessage(RPMMESS_NORMAL, _("Transaction failed...rolling back\n"));
01013     rpmMessage(RPMMESS_NORMAL,
01014         _("Rollback packages (+%d/-%d) to %-24.24s (0x%08x):\n"),
01015                         numAdded, numRemoved, ctime(&tid), tid);
01016 
01017     /* Check the transaction to see if it is doable */
01018     rc = rpmtsCheck(rollbackTransaction);
01019     ps = rpmtsProblems(rollbackTransaction);
01020     if (rc != 0 && rpmpsNumProblems(ps) > 0) {
01021         rpmMessage(RPMMESS_ERROR, _("Failed dependencies:\n"));
01022         rpmpsPrint(NULL, ps);
01023         ps = rpmpsFree(ps);
01024         return -1;
01025     }
01026     ps = rpmpsFree(ps);
01027 
01028     /* Order the transaction */
01029     rc = rpmtsOrder(rollbackTransaction);
01030     if (rc != 0) {
01031         rpmMessage(RPMMESS_ERROR,
01032             _("Could not order auto-rollback transaction!\n"));
01033        return -1;
01034     }
01035 
01036 
01037 
01038     /* Run the transaction and print any problems
01039      * We want to stay with the original transactions flags except
01040      * that we want to add what is essentially a force.
01041      * This handles two things in particular:
01042      *  
01043      *  1.  We we want to upgrade over a newer package.
01044      *  2.  If a header for the old package is there we
01045      *      we want to replace it.  No questions asked.
01046      */
01047     rc = rpmtsRun(rollbackTransaction, NULL,
01048           RPMPROB_FILTER_REPLACEPKG
01049         | RPMPROB_FILTER_REPLACEOLDFILES
01050         | RPMPROB_FILTER_REPLACENEWFILES
01051         | RPMPROB_FILTER_OLDPACKAGE
01052     );
01053     ps = rpmtsProblems(rollbackTransaction);
01054     if (rc > 0 && rpmpsNumProblems(ps) > 0)
01055         rpmpsPrint(stderr, ps);
01056     ps = rpmpsFree(ps);
01057 
01058     /*
01059      * After we have ran through the transaction we need to
01060      * remove any repackaged packages we just installed/upgraded
01061      * from the rp repository.
01062      */
01063     tsi = rpmtsiInit(rollbackTransaction);
01064     while((te = rpmtsiNext(tsi, 0)) != NULL) {
01065         rpmMessage(RPMMESS_NORMAL, _("Cleaning up repackaged packages:\n"));
01066         switch (rpmteType(te)) {
01067         /* The install elements are repackaged packages */
01068         case TR_ADDED:
01069             /* Make sure the filename is still there.  XXX: Can't happen */
01070             if(te->key) {
01071                 rpmMessage(RPMMESS_NORMAL, _("\tRemoving %s:\n"), te->key);
01072                 (void) unlink(te->key); /* XXX: Should check for an error? */
01073             }
01074             /*@switchbreak@*/ break;
01075                                                                                 
01076         /* Ignore erase elements...nothing to do */
01077         default:
01078             /*@switchbreak@*/ break;
01079         }
01080     }
01081     tsi = rpmtsiFree(tsi);
01082 
01083     /* Free the rollback transaction */
01084     rollbackTransaction = rpmtsFree(rollbackTransaction);
01085 
01086     return rc;
01087 }
01088 
01100 static rpmRC getRepackageHeaderFromTE(rpmts ts, rpmte te,
01101                 /*@out@*/ /*@null@*/ Header *hdrp,
01102                 /*@out@*/ /*@null@*/ const char **fnp)
01103         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01104         /*@modifies ts, *hdrp, *fnp,
01105                 rpmGlobalMacroContext, fileSystem, internalState @*/
01106 {
01107     int_32 tid;
01108     const char * name;
01109     const char * rpname = NULL;
01110     const char * _repackage_dir = NULL;
01111     const char * globStr = "-*.rpm";
01112     char * rp = NULL;           /* Rollback package name */
01113     IDTX rtids = NULL;
01114     IDT rpIDT;
01115     int nrids = 0;
01116     int nb;                     /* Number of bytes */
01117     Header h = NULL;
01118     int rc   = RPMRC_NOTFOUND;  /* Assume we do not find it*/
01119     int xx;
01120 
01121     rpmMessage(RPMMESS_DEBUG,
01122         _("Getting repackaged header from transaction element\n"));
01123 
01124     /* Set header pointer to null if its not already */
01125     if (hdrp)
01126         *hdrp = NULL;
01127     if (fnp)
01128         *fnp = NULL;
01129 
01130     /* Get the TID of the current transaction */
01131     tid = rpmtsGetTid(ts);
01132     /* Need the repackage dir if the user want to
01133      * rollback on a failure.
01134      */
01135     _repackage_dir = rpmExpand("%{?_repackage_dir}", NULL);
01136     if (_repackage_dir == NULL) goto exit;
01137 
01138     /* Build the glob string to find the possible repackaged
01139      * packages for this package.
01140      */
01141     name = rpmteN(te);  
01142     nb = strlen(_repackage_dir) + strlen(name) + strlen(globStr) + 2;
01143     rp = memset((char *) malloc(nb), 0, nb);
01144     xx = snprintf(rp, nb, "%s/%s%s.rpm", _repackage_dir, name, globStr);
01145 
01146     /* Get the index of possible repackaged packages */
01147     rpmMessage(RPMMESS_DEBUG, _("\tLooking for %s...\n"), rp);
01148     rtids = IDTXglob(ts, rp, RPMTAG_REMOVETID);
01149     rp = _free(rp);
01150     if (rtids != NULL) {
01151         rpmMessage(RPMMESS_DEBUG, _("\tMatches found.\n"));
01152         rpIDT = rtids->idt;
01153         nrids = rtids->nidt;
01154     } else {
01155         rpmMessage(RPMMESS_DEBUG, _("\tNo matches found.\n"));
01156         goto exit;
01157     }
01158 
01159     /* Now walk through index until we find the package (or we have
01160      * exhausted the index.
01161      */
01162 /*@-branchstate@*/
01163     do {
01164         /* If index is null we have exhausted the list and need to
01165          * get out of here...the repackaged package was not found.
01166          */
01167         if (rpIDT == NULL) {
01168             rpmMessage(RPMMESS_DEBUG, _("\tRepackaged package not found!.\n"));
01169             break;
01170         }
01171 
01172         /* Is this the same tid.  If not decrement the list and continue */
01173         if (rpIDT->val.u32 != tid) {
01174             nrids--;
01175             if (nrids > 0)
01176                 rpIDT++;
01177             else
01178                 rpIDT = NULL;
01179             continue;
01180         }
01181 
01182         /* OK, the tid matches.  Now lets see if the name is the same.
01183          * If I could not get the name from the package, I will go onto
01184          * the next one.  Perhaps I should return an error at this
01185          * point, but if this was not the correct one, at least the correct one
01186          * would be found.
01187          * XXX:  Should Match NAC!
01188          */
01189         rpmMessage(RPMMESS_DEBUG, _("\tREMOVETID matched INSTALLTID.\n"));
01190         if (headerGetEntry(rpIDT->h, RPMTAG_NAME, NULL, (void **) &rpname, NULL)) {
01191             rpmMessage(RPMMESS_DEBUG, _("\t\tName:  %s.\n"), rpname);
01192             if (!strcmp(name,rpname)) {
01193                 /* It matched we have a canidate */
01194                 h  = headerLink(rpIDT->h);
01195                 nb = strlen(rpIDT->key) + 1;
01196                 rp = memset((char *) malloc(nb), 0, nb);
01197                 rp = strncat(rp, rpIDT->key, nb);
01198                 rc = RPMRC_OK;
01199                 break;
01200             }
01201         }
01202 
01203         /* Decrement list */    
01204         nrids--;
01205         if (nrids > 0)
01206             rpIDT++;
01207         else
01208             rpIDT = NULL;
01209     } while (1);
01210 /*@=branchstate@*/
01211 
01212 exit:
01213     if (rc != RPMRC_NOTFOUND && h != NULL && hdrp != NULL) {
01214         rpmMessage(RPMMESS_DEBUG, _("\tRepackaged Package was %s...\n"), rp);
01215         if (hdrp != NULL)
01216             *hdrp = headerLink(h);
01217 /*@-branchstate@*/
01218         if (fnp != NULL)
01219             *fnp = rp;
01220         else
01221             rp = _free(rp);
01222 /*@=branchstate@*/
01223     }
01224     if (h != NULL)
01225         h = headerFree(h);
01226     rtids = IDTXfree(rtids);
01227     return rc;  
01228 }
01229 
01239 static rpmRC _rpmtsAddRollbackElement(rpmts rollbackTransaction,
01240                 rpmts runningTransaction, rpmte te)
01241         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01242         /*@modifies rollbackTransaction, runningTransaction,
01243                 rpmGlobalMacroContext, fileSystem, internalState @*/
01244 {
01245     Header h   = NULL;
01246     Header rph = NULL;
01247     char * rpn; 
01248     unsigned int db_instance = 0;
01249     rpmtsi pi;          
01250     rpmte p;
01251     int rc  = RPMRC_FAIL;       /* Assume Failure */
01252 
01253     switch(rpmteType(te)) {
01254     case TR_ADDED:
01255     {   rpmdbMatchIterator mi;
01256 
01257         rpmMessage(RPMMESS_DEBUG,
01258             _("Adding install element to auto-rollback transaction.\n"));
01259 
01260         /* Get the header for this package from the database
01261          * First get the database instance (the key).
01262          */
01263         db_instance = rpmteDBInstance(te);
01264         if (db_instance == 0) {
01265             /* Could not get the db instance: WTD! */
01266             rpmMessage(RPMMESS_FATALERROR,
01267                 _("Could not get install element database instance!\n"));
01268             break;
01269         }
01270 
01271         /* Now suck the header out of the database */
01272         mi = rpmtsInitIterator(rollbackTransaction,
01273             RPMDBI_PACKAGES, &db_instance, sizeof(db_instance));
01274         h = rpmdbNextIterator(mi);
01275         if (h != NULL) h = headerLink(h);
01276         mi = rpmdbFreeIterator(mi);
01277         if (h == NULL) {
01278             /* Header was not there??? */
01279             rpmMessage(RPMMESS_FATALERROR,
01280                 _("Could not get header for auto-rollback transaction!\n"));
01281             break;
01282         }
01283 
01284         /* Now see if there is a repackaged package for this */
01285         rc = getRepackageHeaderFromTE(runningTransaction, te, &rph, &rpn);
01286         switch(rc) {
01287         case RPMRC_OK:
01288             /* Add the install element, as we had a repackaged package */
01289             rpmMessage(RPMMESS_DEBUG,
01290                 _("\tAdded repackaged package header: %s.\n"), rpn);
01291             rpmMessage(RPMMESS_DEBUG,
01292                 _("\tAdded from install element %s.\n"), rpmteNEVRA(te));
01293             rc = rpmtsAddInstallElement(rollbackTransaction, headerLink(rph),
01294                 (fnpyKey) rpn, 1, te->relocs);
01295             /*@innerbreak@*/ break;
01296 
01297         case RPMRC_NOTFOUND:
01298             /* Add the header as an erase element, we did not
01299              * have a repackaged package
01300              */
01301             rpmMessage(RPMMESS_DEBUG, _("\tAdded erase element.\n"));
01302             rpmMessage(RPMMESS_DEBUG,
01303                 _("\tAdded from install element %s.\n"), rpmteNEVRA(te));
01304             rc = rpmtsAddEraseElement(rollbackTransaction, h, db_instance);
01305             /*@innerbreak@*/ break;
01306                         
01307         default:
01308             /* Not sure what to do on failure...just give up */
01309             rpmMessage(RPMMESS_FATALERROR,
01310                 _("Could not get repackaged header for auto-rollback transaction!\n"));
01311             /*@innerbreak@*/ break;
01312         }
01313     }   break;
01314 
01315    case TR_REMOVED:
01316         rpmMessage(RPMMESS_DEBUG,
01317             _("Add erase element to auto-rollback transaction.\n"));
01318         /* See if this element has already been added.
01319          * If so we want to do nothing.  Compare N's for match.
01320          * XXX:  Really should compare NAC's.
01321          */
01322         pi = rpmtsiInit(rollbackTransaction);
01323         while ((p = rpmtsiNext(pi, 0)) != NULL) {
01324             if (!strcmp(rpmteN(p), rpmteN(te))) {
01325                 rpmMessage(RPMMESS_DEBUG, _("\tFound existing upgrade element.\n"));
01326                 rpmMessage(RPMMESS_DEBUG, _("\tNot adding erase element for %s.\n"),
01327                         rpmteN(te));
01328                 rc = RPMRC_OK;  
01329                 pi = rpmtsiFree(pi);
01330                 goto cleanup;
01331             }
01332         }
01333         pi = rpmtsiFree(pi);
01334 
01335         /* Get the repackage header from the current transaction
01336         * element.
01337         */
01338         rc = getRepackageHeaderFromTE(runningTransaction, te, &rph, &rpn);
01339         switch(rc) {
01340         case RPMRC_OK:
01341             /* Add the install element */
01342             rpmMessage(RPMMESS_DEBUG,
01343                 _("\tAdded repackaged package %s.\n"), rpn);
01344             rpmMessage(RPMMESS_DEBUG,
01345                 _("\tAdded from erase element %s.\n"), rpmteNEVRA(te));
01346             rc = rpmtsAddInstallElement(rollbackTransaction, rph,
01347                 (fnpyKey) rpn, 1, te->relocs);
01348             if (rc != RPMRC_OK)
01349                 rpmMessage(RPMMESS_FATALERROR,
01350                     _("Could not add erase element to auto-rollback transaction.\n"));
01351             /*@innerbreak@*/ break;
01352 
01353         case RPMRC_NOTFOUND:
01354             /* Just did not have a repackaged package */
01355             rpmMessage(RPMMESS_DEBUG,
01356                 _("\tNo repackaged package...nothing to do.\n"));
01357             rc = RPMRC_OK;
01358             /*@innerbreak@*/ break;
01359 
01360         default:
01361             rpmMessage(RPMMESS_FATALERROR,
01362                 _("Failure reading repackaged package!\n"));
01363             /*@innerbreak@*/ break;
01364         }
01365         break;
01366 
01367     default:
01368         break;
01369     }
01370 
01371 /* XXX:  I want to free this, but if I do then the consumers of
01372  *       are hosed.  Just leaving you a little note Jeff, so you
01373  *       know that this does introduce a memory leak.  I wanted
01374  *       keep the patch as simple as possible so I am not fixxing
01375  *       the leak.
01376  *   if (rpn != NULL)
01377  *      free(rpn);
01378  */
01379 
01380 cleanup:
01381     /* Clean up */
01382     if (h != NULL)
01383         h = headerFree(h);
01384     if (rph != NULL)
01385         rph = headerFree(rph);
01386     return rc;
01387 }
01388 
01389 #define NOTIFY(_ts, _al) /*@i@*/ if ((_ts)->notify) (void) (_ts)->notify _al
01390 
01391 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
01392 {
01393     uint_32 tscolor = rpmtsColor(ts);
01394     int i, j;
01395     int ourrc = 0;
01396     int totalFileCount = 0;
01397     rpmfi fi;
01398     sharedFileInfo shared, sharedList;
01399     int numShared;
01400     int nexti;
01401     alKey lastFailKey;
01402     fingerPrintCache fpc;
01403     rpmps ps;
01404     rpmpsm psm;
01405     rpmtsi pi;  rpmte p;
01406     rpmtsi qi;  rpmte q;
01407     int numAdded;
01408     int numRemoved;
01409     rpmts rollbackTransaction = NULL;
01410     int rollbackOnFailure = 0;
01411     void * lock = NULL;
01412     int xx;
01413 
01414     /* XXX programmer error segfault avoidance. */
01415     if (rpmtsNElements(ts) <= 0)
01416         return -1;
01417 
01418     /* See if we need to rollback on failure */
01419     rollbackOnFailure = rpmExpandNumeric(
01420         "%{?_rollback_transaction_on_failure}");
01421     if (rpmtsGetType(ts) & (RPMTRANS_TYPE_ROLLBACK
01422         | RPMTRANS_TYPE_AUTOROLLBACK)) {
01423         rollbackOnFailure = 0;
01424     }
01425     /* If we are in test mode, there is no need to rollback on
01426      * failure, nor acquire the transaction lock.
01427      */
01428 /*@-branchstate@*/
01429     /* If we are in test mode, then there's no need for transaction lock. */
01430     if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST) {
01431         rollbackOnFailure = 0;
01432     } else {
01433         lock = rpmtsAcquireLock(ts);
01434         if (lock == NULL)
01435             return -1;  /* XXX W2DO? */
01436     }
01437 /*@=branchstate@*/
01438 
01439     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
01440         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01441     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
01442         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
01443 
01444     if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
01445         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01446 
01447     ts->probs = rpmpsFree(ts->probs);
01448     ts->probs = rpmpsCreate();
01449 
01450     /* XXX Make sure the database is open RDWR for package install/erase. */
01451     {   int dbmode = (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
01452                 ? O_RDONLY : (O_RDWR|O_CREAT);
01453 
01454         /* Open database RDWR for installing packages. */
01455         if (rpmtsOpenDB(ts, dbmode)) {
01456             rpmtsFreeLock(lock);
01457             return -1;  /* XXX W2DO? */
01458         }
01459     }
01460 
01461     ts->ignoreSet = ignoreSet;
01462     {   const char * currDir = currentDirectory();
01463         rpmtsSetCurrDir(ts, currDir);
01464         currDir = _free(currDir);
01465     }
01466 
01467     (void) rpmtsSetChrootDone(ts, 0);
01468 
01469     {   int_32 tid = (int_32) time(NULL);
01470         (void) rpmtsSetTid(ts, tid);
01471     }
01472 
01473     /* Get available space on mounted file systems. */
01474     xx = rpmtsInitDSI(ts);
01475 
01476     /* ===============================================
01477      * For packages being installed:
01478      * - verify package arch/os.
01479      * - verify package epoch:version-release is newer.
01480      * - count files.
01481      * For packages being removed:
01482      * - count files.
01483      */
01484 
01485 rpmMessage(RPMMESS_DEBUG, _("sanity checking %d elements\n"), rpmtsNElements(ts));
01486     ps = rpmtsProblems(ts);
01487     /* The ordering doesn't matter here */
01488     pi = rpmtsiInit(ts);
01489     /* XXX Only added packages need be checked. */
01490     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01491         rpmdbMatchIterator mi;
01492         int fc;
01493 
01494         if ((fi = rpmtsiFi(pi)) == NULL)
01495             continue;   /* XXX can't happen */
01496         fc = rpmfiFC(fi);
01497 
01498         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH) && !tscolor)
01499             if (!archOkay(rpmteA(p)))
01500                 rpmpsAppend(ps, RPMPROB_BADARCH,
01501                         rpmteNEVR(p), rpmteKey(p),
01502                         rpmteA(p), NULL,
01503                         NULL, 0);
01504 
01505         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
01506             if (!osOkay(rpmteO(p)))
01507                 rpmpsAppend(ps, RPMPROB_BADOS,
01508                         rpmteNEVR(p), rpmteKey(p),
01509                         rpmteO(p), NULL,
01510                         NULL, 0);
01511 
01512         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
01513             Header h;
01514             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
01515             while ((h = rpmdbNextIterator(mi)) != NULL)
01516                 xx = ensureOlder(ts, p, h);
01517             mi = rpmdbFreeIterator(mi);
01518         }
01519 
01520         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
01521             mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
01522             xx = rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP,
01523                                 rpmteE(p));
01524             xx = rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP,
01525                                 rpmteV(p));
01526             xx = rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP,
01527                                 rpmteR(p));
01528             if (tscolor) {
01529                 xx = rpmdbSetIteratorRE(mi, RPMTAG_ARCH, RPMMIRE_STRCMP,
01530                                 rpmteA(p));
01531                 xx = rpmdbSetIteratorRE(mi, RPMTAG_OS, RPMMIRE_STRCMP,
01532                                 rpmteO(p));
01533             }
01534 
01535             while (rpmdbNextIterator(mi) != NULL) {
01536                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
01537                         rpmteNEVR(p), rpmteKey(p),
01538                         NULL, NULL,
01539                         NULL, 0);
01540                 /*@innerbreak@*/ break;
01541             }
01542             mi = rpmdbFreeIterator(mi);
01543         }
01544 
01545         /* Count no. of files (if any). */
01546         totalFileCount += fc;
01547 
01548     }
01549     pi = rpmtsiFree(pi);
01550     ps = rpmpsFree(ps);
01551 
01552     /* The ordering doesn't matter here */
01553     pi = rpmtsiInit(ts);
01554     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01555         int fc;
01556 
01557         if ((fi = rpmtsiFi(pi)) == NULL)
01558             continue;   /* XXX can't happen */
01559         fc = rpmfiFC(fi);
01560 
01561         totalFileCount += fc;
01562     }
01563     pi = rpmtsiFree(pi);
01564 
01565 
01566     /* Run pre-transaction scripts, but only if there are no known
01567      * problems up to this point. */
01568     if (!((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
01569           || (ts->probs->numProblems &&
01570                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))) {
01571         rpmMessage(RPMMESS_DEBUG, _("running pre-transaction scripts\n"));
01572         pi = rpmtsiInit(ts);
01573         while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01574             if ((fi = rpmtsiFi(pi)) == NULL)
01575                 continue;       /* XXX can't happen */
01576 
01577             /* If no pre-transaction script, then don't bother. */
01578             if (fi->pretrans == NULL)
01579                 continue;
01580 
01581             p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
01582                             rpmteKey(p), ts->notifyData);
01583             p->h = NULL;
01584             if (rpmteFd(p) != NULL) {
01585                 rpmVSFlags ovsflags = rpmtsVSFlags(ts);
01586                 rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
01587                 rpmRC rpmrc;
01588                 ovsflags = rpmtsSetVSFlags(ts, vsflags);
01589                 rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
01590                             rpmteNEVR(p), &p->h);
01591                 vsflags = rpmtsSetVSFlags(ts, ovsflags);
01592                 switch (rpmrc) {
01593                 default:
01594                     /*@-noeffectuncon@*/ /* FIX: notify annotations */
01595                     p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
01596                                     0, 0,
01597                                     rpmteKey(p), ts->notifyData);
01598                     /*@=noeffectuncon@*/
01599                     p->fd = NULL;
01600                     /*@switchbreak@*/ break;
01601                 case RPMRC_NOTTRUSTED:
01602                 case RPMRC_NOKEY:
01603                 case RPMRC_OK:
01604                     /*@switchbreak@*/ break;
01605                 }
01606             }
01607 
01608 /*@-branchstate@*/
01609             if (rpmteFd(p) != NULL) {
01610                 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
01611                 if (fi != NULL) {       /* XXX can't happen */
01612                     fi->te = p;
01613                     p->fi = fi;
01614                 }
01615 /*@-compdef -usereleased@*/     /* p->fi->te undefined */
01616                 psm = rpmpsmNew(ts, p, p->fi);
01617 /*@=compdef =usereleased@*/
01618 assert(psm != NULL);
01619                 psm->stepName = "pretrans";
01620                 psm->scriptTag = RPMTAG_PRETRANS;
01621                 psm->progTag = RPMTAG_PRETRANSPROG;
01622                 xx = rpmpsmStage(psm, PSM_SCRIPT);
01623                 psm = rpmpsmFree(psm);
01624 
01625 /*@-noeffectuncon -compdef -usereleased @*/
01626                 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
01627                                   rpmteKey(p), ts->notifyData);
01628 /*@=noeffectuncon =compdef =usereleased @*/
01629                 p->fd = NULL;
01630                 p->h = headerFree(p->h);
01631             }
01632 /*@=branchstate@*/
01633         }
01634         pi = rpmtsiFree(pi);
01635     }
01636 
01637     /* ===============================================
01638      * Initialize transaction element file info for package:
01639      */
01640 
01641     /*
01642      * FIXME?: we'd be better off assembling one very large file list and
01643      * calling fpLookupList only once. I'm not sure that the speedup is
01644      * worth the trouble though.
01645      */
01646 rpmMessage(RPMMESS_DEBUG, _("computing %d file fingerprints\n"), totalFileCount);
01647 
01648     numAdded = numRemoved = 0;
01649     pi = rpmtsiInit(ts);
01650     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01651         int fc;
01652 
01653         if ((fi = rpmtsiFi(pi)) == NULL)
01654             continue;   /* XXX can't happen */
01655         fc = rpmfiFC(fi);
01656 
01657         /*@-branchstate@*/
01658         switch (rpmteType(p)) {
01659         case TR_ADDED:
01660             numAdded++;
01661             fi->record = 0;
01662             /* Skip netshared paths, not our i18n files, and excluded docs */
01663             if (fc > 0)
01664                 skipFiles(ts, fi);
01665             /*@switchbreak@*/ break;
01666         case TR_REMOVED:
01667             numRemoved++;
01668             fi->record = rpmteDBOffset(p);
01669             /*@switchbreak@*/ break;
01670         }
01671         /*@=branchstate@*/
01672 
01673         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
01674     }
01675     pi = rpmtsiFree(pi);
01676 
01677     if (!rpmtsChrootDone(ts)) {
01678         const char * rootDir = rpmtsRootDir(ts);
01679         xx = chdir("/");
01680         /*@-superuser -noeffect @*/
01681         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
01682             xx = chroot(rootDir);
01683         /*@=superuser =noeffect @*/
01684         (void) rpmtsSetChrootDone(ts, 1);
01685     }
01686 
01687     ts->ht = htCreate(totalFileCount * 2, 0, 0, fpHashFunction, fpEqual);
01688     fpc = fpCacheCreate(totalFileCount);
01689 
01690     /* ===============================================
01691      * Add fingerprint for each file not skipped.
01692      */
01693     pi = rpmtsiInit(ts);
01694     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01695         int fc;
01696 
01697         (void) rpmdbCheckSignals();
01698 
01699         if ((fi = rpmtsiFi(pi)) == NULL)
01700             continue;   /* XXX can't happen */
01701         fc = rpmfiFC(fi);
01702 
01703         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01704         fpLookupList(fpc, fi->dnl, fi->bnl, fi->dil, fc, fi->fps);
01705         /*@-branchstate@*/
01706         fi = rpmfiInit(fi, 0);
01707         if (fi != NULL)         /* XXX lclint */
01708         while ((i = rpmfiNext(fi)) >= 0) {
01709             if (XFA_SKIPPING(fi->actions[i]))
01710                 /*@innercontinue@*/ continue;
01711             /*@-dependenttrans@*/
01712             htAddEntry(ts->ht, fi->fps + i, (void *) fi);
01713             /*@=dependenttrans@*/
01714         }
01715         /*@=branchstate@*/
01716         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
01717 
01718     }
01719     pi = rpmtsiFree(pi);
01720 
01721     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount,
01722         NULL, ts->notifyData));
01723 
01724     /* ===============================================
01725      * Compute file disposition for each package in transaction set.
01726      */
01727 rpmMessage(RPMMESS_DEBUG, _("computing file dispositions\n"));
01728     ps = rpmtsProblems(ts);
01729     pi = rpmtsiInit(ts);
01730     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01731         dbiIndexSet * matches;
01732         int knownBad;
01733         int fc;
01734 
01735         (void) rpmdbCheckSignals();
01736 
01737         if ((fi = rpmtsiFi(pi)) == NULL)
01738             continue;   /* XXX can't happen */
01739         fc = rpmfiFC(fi);
01740 
01741         NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
01742                         ts->orderCount, NULL, ts->notifyData));
01743 
01744         if (fc == 0) continue;
01745 
01746         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01747         /* Extract file info for all files in this package from the database. */
01748         matches = xcalloc(fc, sizeof(*matches));
01749         if (rpmdbFindFpList(rpmtsGetRdb(ts), fi->fps, matches, fc)) {
01750             ps = rpmpsFree(ps);
01751             rpmtsFreeLock(lock);
01752             return 1;   /* XXX WTFO? */
01753         }
01754 
01755         numShared = 0;
01756         fi = rpmfiInit(fi, 0);
01757         while ((i = rpmfiNext(fi)) >= 0)
01758             numShared += dbiIndexSetCount(matches[i]);
01759 
01760         /* Build sorted file info list for this package. */
01761         shared = sharedList = xcalloc((numShared + 1), sizeof(*sharedList));
01762 
01763         fi = rpmfiInit(fi, 0);
01764         while ((i = rpmfiNext(fi)) >= 0) {
01765             /*
01766              * Take care not to mark files as replaced in packages that will
01767              * have been removed before we will get here.
01768              */
01769             for (j = 0; j < dbiIndexSetCount(matches[i]); j++) {
01770                 int ro;
01771                 ro = dbiIndexRecordOffset(matches[i], j);
01772                 knownBad = 0;
01773                 qi = rpmtsiInit(ts);
01774                 while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
01775                     if (ro == knownBad)
01776                         /*@innerbreak@*/ break;
01777                     if (rpmteDBOffset(q) == ro)
01778                         knownBad = ro;
01779                 }
01780                 qi = rpmtsiFree(qi);
01781 
01782                 shared->pkgFileNum = i;
01783                 shared->otherPkg = dbiIndexRecordOffset(matches[i], j);
01784                 shared->otherFileNum = dbiIndexRecordFileNumber(matches[i], j);
01785                 shared->isRemoved = (knownBad == ro);
01786                 shared++;
01787             }
01788             matches[i] = dbiFreeIndexSet(matches[i]);
01789         }
01790         numShared = shared - sharedList;
01791         shared->otherPkg = -1;
01792         matches = _free(matches);
01793 
01794         /* Sort file info by other package index (otherPkg) */
01795         qsort(sharedList, numShared, sizeof(*shared), sharedCmp);
01796 
01797         /* For all files from this package that are in the database ... */
01798         /*@-branchstate@*/
01799         for (i = 0; i < numShared; i = nexti) {
01800             int beingRemoved;
01801 
01802             shared = sharedList + i;
01803 
01804             /* Find the end of the files in the other package. */
01805             for (nexti = i + 1; nexti < numShared; nexti++) {
01806                 if (sharedList[nexti].otherPkg != shared->otherPkg)
01807                     /*@innerbreak@*/ break;
01808             }
01809 
01810             /* Is this file from a package being removed? */
01811             beingRemoved = 0;
01812             if (ts->removedPackages != NULL)
01813             for (j = 0; j < ts->numRemovedPackages; j++) {
01814                 if (ts->removedPackages[j] != shared->otherPkg)
01815                     /*@innercontinue@*/ continue;
01816                 beingRemoved = 1;
01817                 /*@innerbreak@*/ break;
01818             }
01819 
01820             /* Determine the fate of each file. */
01821             switch (rpmteType(p)) {
01822             case TR_ADDED:
01823                 xx = handleInstInstalledFiles(ts, p, fi, shared, nexti - i,
01824         !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES)));
01825                 /*@switchbreak@*/ break;
01826             case TR_REMOVED:
01827                 if (!beingRemoved)
01828                     xx = handleRmvdInstalledFiles(ts, fi, shared, nexti - i);
01829                 /*@switchbreak@*/ break;
01830             }
01831         }
01832         /*@=branchstate@*/
01833 
01834         free(sharedList);
01835 
01836         /* Update disk space needs on each partition for this package. */
01837         handleOverlappedFiles(ts, p, fi);
01838 
01839         /* Check added package has sufficient space on each partition used. */
01840         switch (rpmteType(p)) {
01841         case TR_ADDED:
01842             rpmtsCheckDSIProblems(ts, p);
01843             /*@switchbreak@*/ break;
01844         case TR_REMOVED:
01845             /*@switchbreak@*/ break;
01846         }
01847         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), fc);
01848     }
01849     pi = rpmtsiFree(pi);
01850     ps = rpmpsFree(ps);
01851 
01852     if (rpmtsChrootDone(ts)) {
01853         const char * rootDir = rpmtsRootDir(ts);
01854         const char * currDir = rpmtsCurrDir(ts);
01855         /*@-superuser -noeffect @*/
01856         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
01857             xx = chroot(".");
01858         /*@=superuser =noeffect @*/
01859         (void) rpmtsSetChrootDone(ts, 0);
01860         if (currDir != NULL)
01861             xx = chdir(currDir);
01862     }
01863 
01864     NOTIFY(ts, (NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount,
01865         NULL, ts->notifyData));
01866 
01867     /* ===============================================
01868      * Free unused memory as soon as possible.
01869      */
01870     pi = rpmtsiInit(ts);
01871     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01872         if ((fi = rpmtsiFi(pi)) == NULL)
01873             continue;   /* XXX can't happen */
01874         if (rpmfiFC(fi) == 0)
01875             continue;
01876         fi->fps = _free(fi->fps);
01877     }
01878     pi = rpmtsiFree(pi);
01879 
01880     fpc = fpCacheFree(fpc);
01881     ts->ht = htFree(ts->ht);
01882 
01883     /* ===============================================
01884      * If unfiltered problems exist, free memory and return.
01885      */
01886     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
01887      || (ts->probs->numProblems &&
01888                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
01889        )
01890     {
01891         rpmtsFreeLock(lock);
01892         return ts->orderCount;
01893     }
01894 
01895     /* ===============================================
01896      * If we were requested to rollback this transaction
01897      * if an error occurs, then we need to create a
01898      * a rollback transaction.
01899      */
01900      if (rollbackOnFailure) {
01901         rpmtransFlags tsFlags;
01902         rpmVSFlags ovsflags;
01903         rpmVSFlags vsflags;
01904 
01905         rpmMessage(RPMMESS_DEBUG,
01906             _("Creating auto-rollback transaction\n"));
01907 
01908         rollbackTransaction = rpmtsCreate();
01909 
01910         /* Set the verify signature flags:
01911          *      - can't verify digests on repackaged packages.  Other than
01912          *        they are wrong, this will cause segfaults down stream.
01913          *      - signatures are out too.
01914          *      - header check are out.
01915          */     
01916         vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
01917         vsflags |= _RPMVSF_NODIGESTS;
01918         vsflags |= _RPMVSF_NOSIGNATURES;
01919         vsflags |= RPMVSF_NOHDRCHK;
01920         vsflags |= RPMVSF_NEEDPAYLOAD;      /* XXX no legacy signatures */
01921         ovsflags = rpmtsSetVSFlags(ts, vsflags);
01922 
01923         /*
01924          *  If we run this thing its imperitive that it be known that it
01925          *  is an autorollback transaction.  This will affect the instance
01926          *  counts passed to the scriptlets in the psm.
01927          */
01928         rpmtsSetType(rollbackTransaction, RPMTRANS_TYPE_AUTOROLLBACK);
01929 
01930         /* Set transaction flags to be the same as the running transaction */
01931         tsFlags = rpmtsSetFlags(rollbackTransaction, rpmtsFlags(ts));
01932 
01933         /* Set root dir to be the same as the running transaction */
01934         rpmtsSetRootDir(rollbackTransaction, rpmtsRootDir(ts));
01935 
01936         /* Setup the notify of the call back to be the same as the running
01937          * transaction
01938          */
01939         xx = rpmtsSetNotifyCallback(rollbackTransaction, ts->notify, ts->notifyData);
01940 
01941         /* Create rpmtsScore for running transaction and rollback transaction */
01942         xx = rpmtsScoreInit(ts, rollbackTransaction);
01943      }
01944 
01945     /* ===============================================
01946      * Save removed files before erasing.
01947      */
01948     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
01949         int progress;
01950 
01951         progress = 0;
01952         pi = rpmtsiInit(ts);
01953         while ((p = rpmtsiNext(pi, 0)) != NULL) {
01954 
01955             (void) rpmdbCheckSignals();
01956 
01957             if ((fi = rpmtsiFi(pi)) == NULL)
01958                 continue;       /* XXX can't happen */
01959             switch (rpmteType(p)) {
01960             case TR_ADDED:
01961                 /*@switchbreak@*/ break;
01962             case TR_REMOVED:
01963                 if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
01964                     /*@switchbreak@*/ break;
01965                 if (!progress)
01966                     NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_START,
01967                                 7, numRemoved, NULL, ts->notifyData));
01968 
01969                 NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_PROGRESS, progress,
01970                         numRemoved, NULL, ts->notifyData));
01971                 progress++;
01972 
01973                 (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01974 
01975         /* XXX TR_REMOVED needs CPIO_MAP_{ABSOLUTE,ADDDOT} CPIO_ALL_HARDLINKS */
01976                 fi->mapflags |= CPIO_MAP_ABSOLUTE;
01977                 fi->mapflags |= CPIO_MAP_ADDDOT;
01978                 fi->mapflags |= CPIO_ALL_HARDLINKS;
01979                 psm = rpmpsmNew(ts, p, fi);
01980 assert(psm != NULL);
01981                 xx = rpmpsmStage(psm, PSM_PKGSAVE);
01982                 psm = rpmpsmFree(psm);
01983                 fi->mapflags &= ~CPIO_MAP_ABSOLUTE;
01984                 fi->mapflags &= ~CPIO_MAP_ADDDOT;
01985                 fi->mapflags &= ~CPIO_ALL_HARDLINKS;
01986 
01987                 (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01988 
01989                 /*@switchbreak@*/ break;
01990             }
01991         }
01992         pi = rpmtsiFree(pi);
01993         if (progress) {
01994             NOTIFY(ts, (NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved,
01995                         NULL, ts->notifyData));
01996         }
01997     }
01998 
01999     /* ===============================================
02000      * Install and remove packages.
02001      */
02002     lastFailKey = (alKey)-2;    /* erased packages have -1 */
02003     pi = rpmtsiInit(ts);
02004     /*@-branchstate@*/ /* FIX: fi reload needs work */
02005     while ((p = rpmtsiNext(pi, 0)) != NULL) {
02006         alKey pkgKey;
02007         int gotfd;
02008 
02009         (void) rpmdbCheckSignals();
02010 
02011         gotfd = 0;
02012         if ((fi = rpmtsiFi(pi)) == NULL)
02013             continue;   /* XXX can't happen */
02014         
02015         psm = rpmpsmNew(ts, p, fi);
02016 assert(psm != NULL);
02017         psm->unorderedSuccessor =
02018                 (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1) ? 1 : 0);
02019 
02020         switch (rpmteType(p)) {
02021         case TR_ADDED:
02022             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
02023 
02024             pkgKey = rpmteAddedKey(p);
02025 
02026             rpmMessage(RPMMESS_DEBUG, "========== +++ %s %s-%s 0x%x\n",
02027                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02028 
02029             p->h = NULL;
02030             /*@-type@*/ /* FIX: rpmte not opaque */
02031             {
02032                 /*@-noeffectuncon@*/ /* FIX: notify annotations */
02033                 p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
02034                                 rpmteKey(p), ts->notifyData);
02035                 /*@=noeffectuncon@*/
02036                 if (rpmteFd(p) != NULL) {
02037                     rpmVSFlags ovsflags = rpmtsVSFlags(ts);
02038                     rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
02039                     rpmRC rpmrc;
02040 
02041                     ovsflags = rpmtsSetVSFlags(ts, vsflags);
02042                     rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
02043                                 rpmteNEVR(p), &p->h);
02044                     vsflags = rpmtsSetVSFlags(ts, ovsflags);
02045 
02046                     switch (rpmrc) {
02047                     default:
02048                         /*@-noeffectuncon@*/ /* FIX: notify annotations */
02049                         p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
02050                                         0, 0,
02051                                         rpmteKey(p), ts->notifyData);
02052                         /*@=noeffectuncon@*/
02053                         p->fd = NULL;
02054                         ourrc++;
02055 
02056                         /* If we should rollback this transaction
02057                            on failure, lets do it.                 */
02058                         if (rollbackOnFailure) {
02059                             rpmMessage(RPMMESS_ERROR,
02060                                 _("Add failed.  Could not read package header.\n"));
02061                             /* Clean up the current transaction */
02062                             p->h = headerFree(p->h);
02063                             xx = rpmdbSync(rpmtsGetRdb(ts));
02064                             psm = rpmpsmFree(psm);
02065                             p->fi = rpmfiFree(p->fi);
02066                             pi = rpmtsiFree(pi);
02067 
02068                             /* Run the rollback transaction */
02069                             xx = _rpmtsRollback(rollbackTransaction);
02070                             return -1;
02071                         }
02072                         /*@innerbreak@*/ break;
02073                     case RPMRC_NOTTRUSTED:
02074                     case RPMRC_NOKEY:
02075                     case RPMRC_OK:
02076                         /*@innerbreak@*/ break;
02077                     }
02078                     if (rpmteFd(p) != NULL) gotfd = 1;
02079                 }
02080             }
02081             /*@=type@*/
02082 
02083             if (rpmteFd(p) != NULL) {
02084                 /*
02085                  * XXX Sludge necessary to tranfer existing fstates/actions
02086                  * XXX around a recreated file info set.
02087                  */
02088                 psm->fi = rpmfiFree(psm->fi);
02089                 {
02090                     char * fstates = fi->fstates;
02091                     fileAction * actions = fi->actions;
02092                     rpmte savep;
02093 
02094                     fi->fstates = NULL;
02095                     fi->actions = NULL;
02096 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
02097                     fi = rpmfiFree(fi);
02098 /*@=nullstate@*/
02099 
02100                     savep = rpmtsSetRelocateElement(ts, p);
02101                     fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
02102                     (void) rpmtsSetRelocateElement(ts, savep);
02103 
02104                     if (fi != NULL) {   /* XXX can't happen */
02105                         fi->te = p;
02106                         fi->fstates = _free(fi->fstates);
02107                         fi->fstates = fstates;
02108                         fi->actions = _free(fi->actions);
02109                         fi->actions = actions;
02110                         p->fi = fi;
02111                     }
02112                 }
02113                 psm->fi = rpmfiLink(p->fi, NULL);
02114 
02115 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
02116                 if (rpmpsmStage(psm, PSM_PKGINSTALL)) {
02117                     ourrc++;
02118                     lastFailKey = pkgKey;
02119 
02120                     /* If we should rollback this transaction
02121                        on failure, lets do it.                 */
02122                     if (rollbackOnFailure) {
02123                         rpmMessage(RPMMESS_ERROR,
02124                             _("Add failed in rpmpsmStage().\n"));
02125                         /* Clean up the current transaction */
02126                         p->h = headerFree(p->h);
02127                         xx = rpmdbSync(rpmtsGetRdb(ts));
02128                         psm = rpmpsmFree(psm);
02129                         p->fi = rpmfiFree(p->fi);
02130                         pi = rpmtsiFree(pi);
02131 
02132                         /* Run the rollback transaction */
02133                         xx = _rpmtsRollback(rollbackTransaction);
02134                         return -1;
02135                     }
02136                 }
02137                 
02138                 /* If we should rollback on failure lets add
02139                  * this element to the rollback transaction
02140                  * as an erase element as it has installed succesfully.
02141                  */
02142                 if (rollbackOnFailure) {
02143                     int rc;
02144 
02145                     rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
02146                     if (rc != RPMRC_OK) {
02147                         /* Clean up the current transaction */
02148                         p->h = headerFree(p->h);
02149                         xx = rpmdbSync(rpmtsGetRdb(ts));
02150                         psm = rpmpsmFree(psm);
02151                         p->fi = rpmfiFree(p->fi);
02152                         pi = rpmtsiFree(pi);
02153                         
02154                         /* Clean up rollback transaction */
02155                         rollbackTransaction = rpmtsFree(rollbackTransaction);
02156                         return -1;
02157                     }
02158                 }
02159 /*@=nullstate@*/
02160             } else {
02161                 ourrc++;
02162                 lastFailKey = pkgKey;
02163                 
02164                 /* If we should rollback this transaction
02165                  * on failure, lets do it.
02166                  */
02167                 if (rollbackOnFailure) {
02168                     rpmMessage(RPMMESS_ERROR, _("Add failed.  Could not get file list.\n"));
02169                     /* Clean up the current transaction */
02170                     p->h = headerFree(p->h);
02171                     xx = rpmdbSync(rpmtsGetRdb(ts));
02172                     psm = rpmpsmFree(psm);
02173                     p->fi = rpmfiFree(p->fi);
02174                     pi = rpmtsiFree(pi);
02175 
02176                     /* Run the rollback transaction */
02177                     xx = _rpmtsRollback(rollbackTransaction);
02178                     return -1;
02179                 }
02180             }
02181 
02182             if (gotfd) {
02183                 /*@-noeffectuncon @*/ /* FIX: check rc */
02184                 (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
02185                         rpmteKey(p), ts->notifyData);
02186                 /*@=noeffectuncon @*/
02187                 /*@-type@*/
02188                 p->fd = NULL;
02189                 /*@=type@*/
02190             }
02191 
02192             p->h = headerFree(p->h);
02193 
02194             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_INSTALL), 0);
02195 
02196             /*@switchbreak@*/ break;
02197 
02198         case TR_REMOVED:
02199             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
02200 
02201             rpmMessage(RPMMESS_DEBUG, "========== --- %s %s-%s 0x%x\n",
02202                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
02203 
02204             /*
02205              * XXX This has always been a hack, now mostly broken.
02206              * If install failed, then we shouldn't erase.
02207              */
02208             if (rpmteDependsOnKey(p) != lastFailKey) {
02209                 if (rpmpsmStage(psm, PSM_PKGERASE)) {
02210                     ourrc++;
02211 
02212                     /* If we should rollback this transaction
02213                      * on failure, lets do it.
02214                      */
02215                     if (rollbackOnFailure) {
02216                         rpmMessage(RPMMESS_ERROR,
02217                             _("Erase failed failed in rpmpsmStage().\n"));
02218                         /* Clean up the current transaction */
02219                         xx = rpmdbSync(rpmtsGetRdb(ts));
02220                         psm = rpmpsmFree(psm);
02221                         p->fi = rpmfiFree(p->fi);
02222                         pi = rpmtsiFree(pi);
02223 
02224                         /* Run the rollback transaction */
02225                         xx = _rpmtsRollback(rollbackTransaction);
02226                         return -1;
02227                     }
02228                 }
02229 
02230                 /* If we should rollback on failure lets add
02231                  * this element to the rollback transaction
02232                  * as an install element as it has erased succesfully.
02233                  */
02234                 if (rollbackOnFailure) {
02235                     int rc;
02236 
02237                     rc = _rpmtsAddRollbackElement(rollbackTransaction, ts, p);
02238 
02239                     if (rc != RPMRC_OK) {
02240                         /* Clean up the current transaction */
02241                         xx = rpmdbSync(rpmtsGetRdb(ts));
02242                         psm = rpmpsmFree(psm);
02243                         p->fi = rpmfiFree(p->fi);
02244                         pi = rpmtsiFree(pi);
02245                 
02246                         /* Clean up rollback transaction */
02247                         rollbackTransaction = rpmtsFree(rollbackTransaction);
02248                         return -1;
02249                     }
02250                 }
02251             }
02252 
02253             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_ERASE), 0);
02254 
02255             /*@switchbreak@*/ break;
02256         }
02257         xx = rpmdbSync(rpmtsGetRdb(ts));
02258 
02259 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
02260         psm = rpmpsmFree(psm);
02261 /*@=nullstate@*/
02262 
02263 #ifdef  DYING
02264 /*@-type@*/ /* FIX: p is almost opaque */
02265         p->fi = rpmfiFree(p->fi);
02266 /*@=type@*/
02267 #endif
02268 
02269     }
02270     /*@=branchstate@*/
02271     pi = rpmtsiFree(pi);
02272 
02273     /* If we created a rollback transaction lets get rid of it */
02274     if (rollbackOnFailure && rollbackTransaction != NULL)
02275         rollbackTransaction = rpmtsFree(rollbackTransaction);
02276 
02277     rpmMessage(RPMMESS_DEBUG, _("running post-transaction scripts\n"));
02278     pi = rpmtsiInit(ts);
02279     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
02280         int haspostscript;
02281 
02282         if ((fi = rpmtsiFi(pi)) == NULL)
02283             continue;   /* XXX can't happen */
02284 
02285         haspostscript = (fi->posttrans != NULL ? 1 : 0);
02286         p->fi = rpmfiFree(p->fi);
02287 
02288         /* If no post-transaction script, then don't bother. */
02289         if (!haspostscript)
02290             continue;
02291 
02292         p->fd = ts->notify(p->h, RPMCALLBACK_INST_OPEN_FILE, 0, 0,
02293                         rpmteKey(p), ts->notifyData);
02294         p->h = NULL;
02295         if (rpmteFd(p) != NULL) {
02296             rpmVSFlags ovsflags = rpmtsVSFlags(ts);
02297             rpmVSFlags vsflags = ovsflags | RPMVSF_NEEDPAYLOAD;
02298             rpmRC rpmrc;
02299             ovsflags = rpmtsSetVSFlags(ts, vsflags);
02300             rpmrc = rpmReadPackageFile(ts, rpmteFd(p),
02301                         rpmteNEVR(p), &p->h);
02302             vsflags = rpmtsSetVSFlags(ts, ovsflags);
02303             switch (rpmrc) {
02304             default:
02305                 p->fd = ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE,
02306                                 0, 0, rpmteKey(p), ts->notifyData);
02307                 p->fd = NULL;
02308                 /*@switchbreak@*/ break;
02309             case RPMRC_NOTTRUSTED:
02310             case RPMRC_NOKEY:
02311             case RPMRC_OK:
02312                 /*@switchbreak@*/ break;
02313             }
02314         }
02315 
02316         if (rpmteFd(p) != NULL) {
02317             p->fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, 1);
02318             if (p->fi != NULL)  /* XXX can't happen */
02319                 p->fi->te = p;
02320 /*@-compdef -usereleased@*/     /* p->fi->te undefined */
02321             psm = rpmpsmNew(ts, p, p->fi);
02322 /*@=compdef =usereleased@*/
02323 assert(psm != NULL);
02324             psm->stepName = "posttrans";
02325             psm->scriptTag = RPMTAG_POSTTRANS;
02326             psm->progTag = RPMTAG_POSTTRANSPROG;
02327             xx = rpmpsmStage(psm, PSM_SCRIPT);
02328             psm = rpmpsmFree(psm);
02329 
02330 /*@-noeffectuncon -compdef -usereleased @*/
02331             (void) ts->notify(p->h, RPMCALLBACK_INST_CLOSE_FILE, 0, 0,
02332                               rpmteKey(p), ts->notifyData);
02333 /*@=noeffectuncon =compdef =usereleased @*/
02334             p->fd = NULL;
02335             p->fi = rpmfiFree(p->fi);
02336             p->h = headerFree(p->h);
02337         }
02338     }
02339     pi = rpmtsiFree(pi);
02340 
02341     rpmtsFreeLock(lock);
02342 
02343     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
02344     if (ourrc)
02345         return -1;
02346     else
02347         return 0;
02348     /*@=nullstate@*/
02349 }

Generated on Mon Mar 5 14:30:58 2007 for rpm by  doxygen 1.5.1