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

Generated on Fri Oct 12 08:44:54 2007 for rpm by  doxygen 1.5.2