lib/transaction.c

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

Generated on Wed Jan 28 12:45:24 2009 for rpm by  doxygen 1.4.7