rpm 5.3.7

lib/transaction.c

Go to the documentation of this file.
00001 
00005 #include "system.h"
00006 
00007 #include <rpmio.h>
00008 #include <rpmiotypes.h>
00009 #include <rpmlog.h>
00010 #include <rpmmacro.h>   /* XXX for rpmExpand */
00011 #include <rpmsx.h>
00012 
00013 #include <rpmtypes.h>
00014 #include <rpmtag.h>
00015 #include <pkgio.h>
00016 
00017 #define _FPRINT_INTERNAL
00018 #include "fprint.h"
00019 
00020 #define _RPMDB_INTERNAL /* XXX for dbiIndexFoo() */
00021 #include <rpmdb.h>
00022 #include "legacy.h"     /* XXX dodigest */
00023 
00024 #define _RPMFI_INTERNAL
00025 #include <rpmfi.h>
00026 #include "fsm.h"
00027 
00028 #define _RPMTE_INTERNAL
00029 #include "rpmte.h"
00030 #define _RPMTS_INTERNAL
00031 #include "rpmts.h"
00032 
00033 #define _RPMSQ_INTERNAL
00034 #define _RPMPSM_INTERNAL
00035 #include "psm.h"
00036 
00037 #include "rpmds.h"
00038 
00039 #include "rpmlock.h"
00040 
00041 #include "misc.h" /* XXX currentDirectory */
00042 
00043 #if defined(RPM_VENDOR_MANDRIVA)
00044 #include "filetriggers.h" /* XXX mayAddToFilesAwaitingFiletriggers, rpmRunFileTriggers */
00045 #endif
00046 
00047 #include <rpmcli.h>     /* XXX QVA_t INSTALL_FOO flags */
00048 #include <rpmrollback.h>        /* IDTX prototypes */
00049 
00050 #include "debug.h"
00051 
00052 /*@access dbiIndexSet @*/
00053 
00054 /*@access fnpyKey @*/
00055 
00056 /*@access alKey @*/
00057 /*@access rpmdb @*/     /* XXX cast */
00058 
00059 /*@access rpmfi @*/
00060 /*@access rpmps @*/     /* XXX need rpmProblemSetOK() */
00061 /*@access rpmpsm @*/
00062 
00063 /*@access rpmte @*/
00064 /*@access rpmtsi @*/
00065 /*@access rpmts @*/
00066 
00067 /*@access IDT @*/
00068 /*@access IDTX @*/
00069 /*@access FD_t @*/
00070 
00071 static int handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi,
00072                                    Header otherHeader, rpmfi otherFi,
00073                                    int beingRemoved)
00074         /*@modifies ts, p, fi @*/
00075 {
00076     unsigned int fx = rpmfiFX(fi);
00077     int isCfgFile = ((rpmfiFFlags(otherFi) | rpmfiFFlags(fi)) & RPMFILE_CONFIG);
00078 #ifdef  REFERENCE
00079     rpmfs fs = rpmteGetFileStates(p);
00080     if (XFA_SKIPPING(rpmfsGetAction(fs, fx)))
00081 #else
00082     if (iosmFileActionSkipped(fi->actions[fx]))
00083 #endif
00084         return 0;
00085 
00086     if (rpmfiCompare(otherFi, fi)) {
00087 #ifdef  REFERENCE
00088         rpm_color_t tscolor = rpmtsColor(ts);
00089         rpm_color_t prefcolor = rpmtsPrefColor(ts);
00090         rpm_color_t FColor = rpmfiFColor(fi) & tscolor;
00091         rpm_color_t oFColor = rpmfiFColor(otherFi) & tscolor;
00092 #else
00093         rpmuint32_t tscolor = rpmtsColor(ts);
00094         rpmuint32_t prefcolor = rpmtsPrefColor(ts);
00095         rpmuint32_t FColor = rpmfiFColor(fi) & tscolor;
00096         rpmuint32_t oFColor = rpmfiFColor(otherFi) & tscolor;
00097 #endif
00098         int rConflicts;
00099 
00100         rConflicts = !(beingRemoved || (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES));
00101         /* Resolve file conflicts to prefer Elf64 (if not forced). */
00102         if (tscolor != 0 && FColor != 0 && FColor != oFColor) {
00103             if (oFColor & prefcolor) {
00104 #ifdef  REFERENCE
00105                 rpmfsSetAction(fs, fx, FA_SKIPCOLOR);
00106 #else
00107                 fi->actions[fx] = FA_SKIPCOLOR;
00108 #endif
00109                 rConflicts = 0;
00110             } else if (FColor & prefcolor) {
00111 #ifdef  REFERENCE
00112                 rpmfsSetAction(fs, fx, FA_CREATE);
00113 #else
00114                 fi->actions[fx] = FA_CREATE;
00115 #endif
00116                 rConflicts = 0;
00117             }
00118         }
00119 
00120         if (rConflicts) {
00121             HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00122             rpmps ps = rpmtsProblems(ts);
00123             int xx;
00124             he->tag = RPMTAG_NVRA;
00125             xx = headerGet(otherHeader, he, 0);
00126             rpmpsAppend(ps, RPMPROB_FILE_CONFLICT,
00127                         rpmteNEVRA(p), rpmteKey(p),
00128                         rpmfiDN(fi), rpmfiBN(fi),
00129                         he->p.str,
00130                         0);
00131             he->p.ptr = _free(he->p.ptr);
00132             ps = rpmpsFree(ps);
00133         }
00134 
00135         /* Save file identifier to mark as state REPLACED. */
00136 #ifdef  REFERENCE
00137         if ( !(isCfgFile || XFA_SKIPPING(rpmfsGetAction(fs, fx))) ) {
00138             if (!beingRemoved)
00139                 rpmfsAddReplaced(rpmteGetFileStates(p), rpmfiFX(fi),
00140                                  headerGetInstance(otherHeader),
00141                                  rpmfiFX(otherFi));
00142         }
00143 #else
00144         if ( !(isCfgFile || iosmFileActionSkipped(fi->actions[fx])) ) {
00145             if (!beingRemoved) {
00146                 struct sharedFileInfo_s _shared;
00147 
00148                 p->replaced = xrealloc(p->replaced,
00149                         sizeof(*p->replaced) * (p->nreplaced + 1));
00150                 memset(p->replaced + p->nreplaced, 0, sizeof(*p->replaced));
00151 
00152                 _shared.pkgFileNum = fx;
00153                 _shared.otherFileNum = rpmfiFX(otherFi);
00154                 _shared.otherPkg = headerGetInstance(otherHeader);
00155                 _shared.isRemoved = 0;
00156                 p->replaced[p->nreplaced++] = _shared;
00157             }
00158         }
00159 #endif
00160     }
00161 
00162     /* Determine config file dispostion, skipping missing files (if any). */
00163     if (isCfgFile) {
00164         int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1);
00165 #ifdef  REFERENCE
00166         rpmFileAction action = rpmfiDecideFate(otherFi, fi, skipMissing);
00167         rpmfsSetAction(fs, fx, action);
00168 #else
00169         fi->actions[fx] = rpmfiDecideFate(otherFi, fi, skipMissing);
00170 #endif
00171     }
00172 #ifdef  REFERENCE
00173     rpmfiSetFReplacedSize(fi, rpmfiFSize(otherFi));
00174 #else
00175     fi->replacedSizes[fx] = rpmfiFSize(otherFi);
00176 #endif
00177 
00178     return 0;
00179 }
00180 
00181 #define ISROOT(_d)      (((_d)[0] == '/' && (_d)[1] == '\0') ? "" : (_d))
00182 
00183 /*@unchecked@*/
00184 int _fps_debug = 0;
00185 #define FPSDEBUG(_debug, _list) if ((_debug) || _fps_debug) fprintf _list
00186 
00190 /* XXX only ts->{probs,di} modified */
00191 static void handleOverlappedFiles(const rpmts ts, const rpmte p, rpmfi fi)
00192         /*@globals h_errno, fileSystem, internalState @*/
00193         /*@modifies ts, fi, fileSystem, internalState @*/
00194 {
00195     uint32_t fixupSize = 0;
00196     rpmps ps;
00197     const char * fn;
00198     int i, j;
00199 
00200     uint32_t tscolor = rpmtsColor(ts);
00201     uint32_t prefcolor = rpmtsPrefColor(ts);
00202 #ifdef  REFERENCE
00203     rpmfs fs = rpmteGetFileStates(p);
00204     rpmfs otherFs;
00205 #endif  /* REFERENCE */
00206 
00207 FPSDEBUG(0, (stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, ts, p, fi));
00208     ps = rpmtsProblems(ts);
00209     fi = rpmfiInit(fi, 0);
00210     if (fi != NULL)
00211     while ((i = rpmfiNext(fi)) >= 0) {
00212         uint32_t oFColor;
00213         uint32_t FColor;
00214         struct fingerPrint_s * fiFps;
00215         int otherPkgNum, otherFileNum;
00216         rpmfi otherFi;
00217 
00218         rpmte otherTe;
00219 #ifdef  REFERENCE
00220         rpmfileAttrs FFlags;
00221         rpm_mode_t FMode;
00222 #else   /* REFERENCE */
00223         rpmuint32_t FFlags;
00224         rpmuint16_t FMode;
00225 #endif  /* REFERENCE */
00226         struct rpmffi_s ** recs;
00227         int numRecs;
00228 
00229         if (iosmFileActionSkipped(fi->actions[i]))
00230             continue;
00231 
00232         fn = rpmfiFN(fi);
00233 #ifdef  REFERENCE
00234         fiFps = rpmfiFpsIndex(fi, i);
00235 #else   /* REFERENCE */
00236         fiFps = fi->fps + i;
00237 #endif  /* REFERENCE */
00238         FFlags = rpmfiFFlags(fi);
00239         FMode = rpmfiFMode(fi);
00240         FColor = rpmfiFColor(fi);
00241         FColor &= tscolor;
00242 
00243         fixupSize = 0;
00244 
00245         /*
00246          * Retrieve all records that apply to this file. Note that the
00247          * file info records were built in the same order as the packages
00248          * will be installed and removed so the records for an overlapped
00249          * files will be sorted in exactly the same order.
00250          */
00251         recs = NULL;
00252         numRecs = 0;
00253 #ifdef  REFERENCE
00254         (void) rpmFpHashGetEntry(ht, fiFps, &recs, &numRecs, NULL);
00255 #else   /* REFERENCE */
00256         (void) htGetEntry(ts->ht, fiFps, &recs, &numRecs, NULL);
00257 #endif  /* REFERENCE */
00258 
00259         /*
00260          * If this package is being added, look only at other packages
00261          * being added -- removed packages dance to a different tune.
00262          *
00263          * If both this and the other package are being added, overlapped
00264          * files must be identical (or marked as a conflict). The
00265          * disposition of already installed config files leads to
00266          * a small amount of extra complexity.
00267          *
00268          * If this package is being removed, then there are two cases that
00269          * need to be worried about:
00270          * If the other package is being added, then skip any overlapped files
00271          * so that this package removal doesn't nuke the overlapped files
00272          * that were just installed.
00273          * If both this and the other package are being removed, then each
00274          * file removal from preceding packages needs to be skipped so that
00275          * the file removal occurs only on the last occurence of an overlapped
00276          * file in the transaction set.
00277          */
00278 
00279         /* Locate this overlapped file in the set of added/removed packages. */
00280         for (j = 0; j < numRecs && recs[j]->p != p; j++) {
00281 FPSDEBUG(0, (stderr, "\trecs %p[%u:%u] te %p != %p\n", recs, (unsigned)j, (unsigned)numRecs, recs[j]->p, p));
00282         }
00283 FPSDEBUG(0, (stderr, "*** got recs %p[%u:%u]\n", recs, (unsigned)j, (unsigned)numRecs));
00284 
00285         /* Find what the previous disposition of this file was. */
00286         otherFileNum = -1;                      /* keep gcc quiet */
00287         otherFi = NULL;
00288         otherTe = NULL;
00289 #ifdef  REFERENCE
00290         otherFs = NULL;
00291 #endif  /* REFERENCE */
00292 
00293         for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) {
00294 FPSDEBUG(0, (stderr, "\trecs %p[%u:%u] %p -> {%p,%d}\n", recs, (unsigned)otherPkgNum, (unsigned)numRecs, recs[otherPkgNum], recs[otherPkgNum]->p, recs[otherPkgNum]->fileno));
00295             otherTe = recs[otherPkgNum]->p;
00296             otherFi = rpmteFI(otherTe, RPMTAG_BASENAMES);
00297             otherFileNum = recs[otherPkgNum]->fileno;
00298 #ifdef  REFERENCE
00299             otherFs = rpmteGetFileStates(otherTe);
00300 #endif  /* REFERENCE */
00301 
00302             /* Added packages need only look at other added packages. */
00303             if (rpmteType(p) == TR_ADDED && rpmteType(otherTe) != TR_ADDED)
00304                 /*@innercontinue@*/ continue;
00305 
00306             (void) rpmfiSetFX(otherFi, otherFileNum);
00307 
00308             /* XXX Happens iff fingerprint for incomplete package install. */
00309             if (otherFi->actions[otherFileNum] != FA_UNKNOWN)
00310                 /*@innerbreak@*/ break;
00311         }
00312 
00313         oFColor = rpmfiFColor(otherFi);
00314         oFColor &= tscolor;
00315 
00316         switch (rpmteType(p)) {
00317         case TR_ADDED:
00318           { int reportConflicts =
00319                 !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES);
00320             int done = 0;
00321 
00322             if (otherPkgNum < 0) {
00323                 iosmFileAction action;
00324                 /* XXX is this test still necessary? */
00325                 if (fi->actions[i] != FA_UNKNOWN)
00326                     /*@switchbreak@*/ break;
00327 #ifdef  REFERENCE
00328                 if (rpmfiConfigConflict(fi))
00329 #else
00330                 if ((FFlags & RPMFILE_CONFIG) && (FFlags & RPMFILE_EXISTS))
00331 #endif
00332                 {
00333                     /* Here is a non-overlapped pre-existing config file. */
00334                     action = (FFlags & RPMFILE_NOREPLACE)
00335                         ? FA_ALTNAME : FA_BACKUP;
00336                 } else {
00337                     action = FA_CREATE;
00338                 }
00339 #ifdef  REFERENCE
00340                 rpmfsSetAction(fs, i, action);
00341 #else
00342                 fi->actions[i] = action;
00343 #endif
00344                 /*@switchbreak@*/ break;
00345             }
00346 
00347 assert(otherFi != NULL);
00348             /* Mark added overlapped non-identical files as a conflict. */
00349             if (rpmfiCompare(otherFi, fi)) {
00350                 int rConflicts;
00351 
00352                 rConflicts = reportConflicts;
00353                 /* Resolve file conflicts to prefer Elf64 (if not forced) ... */
00354                 if (tscolor != 0) {
00355                     if (FColor & prefcolor) {
00356                         /* ... last file of preferred colour is installed ... */
00357                         if (!iosmFileActionSkipped(fi->actions[i])) {
00358 #ifdef  DEAD
00359                             /* XXX static helpers are order dependent. Ick. */
00360                             if (strcmp(fn, "/usr/sbin/libgcc_post_upgrade")
00361                              && strcmp(fn, "/usr/sbin/glibc_post_upgrade"))
00362 #endif
00363                                 otherFi->actions[otherFileNum] = FA_SKIPCOLOR;
00364                         }
00365                         fi->actions[i] = FA_CREATE;
00366                         rConflicts = 0;
00367                     } else
00368                     if (oFColor & prefcolor) {
00369                         /* ... first file of preferred colour is installed ... */
00370                         if (iosmFileActionSkipped(fi->actions[i]))
00371                             otherFi->actions[otherFileNum] = FA_CREATE;
00372                         fi->actions[i] = FA_SKIPCOLOR;
00373                         rConflicts = 0;
00374                     } else
00375                     if (FColor == 0 && oFColor == 0) {
00376                         /* ... otherwise, do both, last in wins. */
00377                         otherFi->actions[otherFileNum] = FA_CREATE;
00378                         fi->actions[i] = FA_CREATE;
00379                         rConflicts = 0;
00380                     }
00381                     done = 1;
00382                 }
00383 
00384                 if (rConflicts) {
00385                     rpmpsAppend(ps, RPMPROB_NEW_FILE_CONFLICT,
00386                         rpmteNEVR(p), rpmteKey(p),
00387                         fn, NULL,
00388                         rpmteNEVR(otherFi->te),
00389                         0);
00390                 }
00391             }
00392 
00393             /* Try to get the disk accounting correct even if a conflict. */
00394             fixupSize = rpmfiFSize(otherFi);
00395 
00396 #ifdef  REFERENCE
00397             if (rpmfiConfigConflict(fi))
00398 #else   /* REFERENCE */
00399             if ((FFlags & RPMFILE_CONFIG) && (FFlags & RPMFILE_EXISTS))
00400 #endif  /* REFERENCE */
00401             {
00402                 /* Here is an overlapped  pre-existing config file. */
00403                 fi->actions[i] = (FFlags & RPMFILE_NOREPLACE)
00404                         ? FA_ALTNAME : FA_SKIP;
00405             } else {
00406                 if (!done)
00407                     fi->actions[i] = FA_CREATE;
00408             }
00409           } /*@switchbreak@*/ break;
00410 
00411         case TR_REMOVED:
00412             if (otherPkgNum >= 0) {
00413 assert(otherFi != NULL);
00414                 /* Here is an overlapped added file we don't want to nuke. */
00415                 if (otherFi->actions[otherFileNum] != FA_ERASE) {
00416                     /* On updates, don't remove files. */
00417                     fi->actions[i] = FA_SKIP;
00418                     /*@switchbreak@*/ break;
00419                 }
00420                 /* Here is an overlapped removed file: skip in previous. */
00421                 otherFi->actions[otherFileNum] = FA_SKIP;
00422             }
00423             if (iosmFileActionSkipped(fi->actions[i]))
00424                 /*@switchbreak@*/ break;
00425             if (rpmfiFState(fi) != RPMFILE_STATE_NORMAL)
00426                 /*@switchbreak@*/ break;
00427 
00428             /* Disposition is assumed to be FA_ERASE. */
00429             fi->actions[i] = FA_ERASE;
00430             if (!(S_ISREG(FMode) && (FFlags & RPMFILE_CONFIG)))
00431                 /*@switchbreak@*/ break;
00432 
00433             /* Check for pre-existing modified config file that needs saving. */
00434             if (!(FFlags & RPMFILE_SPARSE))
00435             {   int dalgo = 0;
00436                 size_t dlen = 0;
00437                 const unsigned char * digest = rpmfiDigest(fi, &dalgo, &dlen);
00438                 unsigned char * fdigest;
00439 assert(digest != NULL);
00440                 
00441                 fdigest = xcalloc(1, dlen);
00442                 /* Save (by renaming) locally modified config files. */
00443                 if (!dodigest(dalgo, fn, fdigest, 0, NULL)
00444                  && memcmp(digest, fdigest, dlen))
00445                     fi->actions[i] = FA_BACKUP;
00446                 fdigest = _free(fdigest);
00447             }
00448             /*@switchbreak@*/ break;
00449         }
00450 
00451         /* Update disk space info for a file. */
00452 #ifdef  REFERENCE
00453         rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
00454                        rpmfiFReplacedSize(fi), fixupSize, rpmfsGetAction(fs, i));
00455 #else
00456         rpmtsUpdateDSI(ts, fiFps->entry->dev, rpmfiFSize(fi),
00457                 fi->replacedSizes[i], fixupSize, fi->actions[i]);
00458 #endif
00459 
00460     }
00461     ps = rpmpsFree(ps);
00462 }
00463 
00471 /*@-nullpass@*/
00472 static int ensureOlder(rpmts ts,
00473                 const rpmte p, const Header h)
00474         /*@globals internalState @*/
00475         /*@modifies ts, internalState @*/
00476 {
00477     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00478     rpmuint32_t reqFlags = (RPMSENSE_LESS | RPMSENSE_EQUAL);
00479     const char * reqEVR;
00480     rpmds req;
00481     char * t;
00482     size_t nb;
00483     int rc;
00484 
00485 FPSDEBUG(0, (stderr, "--> %s(%p,%p,%p)\n", __FUNCTION__, ts, p, h));
00486     if (p == NULL || h == NULL)
00487         return 1;
00488 
00489     nb = strlen(rpmteNEVR(p)) + (rpmteE(p) != NULL ? strlen(rpmteE(p)) : 0) + 1;
00490 #ifdef  RPM_VENDOR_MANDRIVA
00491     nb += (rpmteD(p) != NULL ? strlen(rpmteD(p)) + 1 : 0);
00492 #endif
00493     t = alloca(nb);
00494     *t = '\0';
00495     reqEVR = t;
00496     if (rpmteE(p) != NULL)      t = stpcpy( stpcpy(t, rpmteE(p)), ":");
00497     if (rpmteV(p) != NULL)      t = stpcpy(t, rpmteV(p));
00498     *t++ = '-';
00499     if (rpmteR(p) != NULL)      t = stpcpy(t, rpmteR(p));
00500 #ifdef RPM_VENDOR_MANDRIVA
00501     if (rpmteD(p) != NULL)      *t++ = ':', t = stpcpy(t, rpmteD(p));
00502 #endif
00503 
00504     req = rpmdsSingle(RPMTAG_REQUIRENAME, rpmteN(p), reqEVR, reqFlags);
00505     rc = rpmdsNVRMatchesDep(h, req, _rpmds_nopromote);
00506     (void)rpmdsFree(req);
00507     req = NULL;
00508 
00509     if (rc == 0) {
00510         rpmps ps = rpmtsProblems(ts);
00511         he->tag = RPMTAG_NVRA;
00512         rc = headerGet(h, he, 0);
00513 assert(he->p.str != NULL);
00514         rpmpsAppend(ps, RPMPROB_OLDPACKAGE,
00515                 rpmteNEVR(p), rpmteKey(p),
00516                 NULL, NULL,
00517                 he->p.str,
00518                 0);
00519         he->p.ptr = _free(he->p.ptr);
00520         ps = rpmpsFree(ps);
00521         rc = 1;
00522     } else
00523         rc = 0;
00524 
00525     return rc;
00526 }
00527 /*@=nullpass@*/
00528 
00534 /*@-mustmod@*/ /* FIX: fi->actions is modified. */
00535 /*@-nullpass@*/
00536 static void rpmtsSkipFiles(const rpmts ts, rpmfi fi)
00537         /*@globals rpmGlobalMacroContext, h_errno, internalState @*/
00538         /*@modifies fi, rpmGlobalMacroContext, internalState @*/
00539 {
00540     rpmuint32_t tscolor = rpmtsColor(ts);
00541     rpmuint32_t FColor;
00542     int noConfigs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONFIGS);
00543     int noDocs = (rpmtsFlags(ts) & RPMTRANS_FLAG_NODOCS);
00544     ARGV_t netsharedPaths = NULL;
00545     ARGV_t languages = NULL;
00546     const char * dn, * bn;
00547     size_t dnlen, bnlen;
00548     int ix;
00549     const char * s;
00550     int * drc;
00551     char * dff;
00552     int dc;
00553     int i, j;
00554     int xx;
00555 
00556 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, fi));
00557 #if defined(RPM_VENDOR_OPENPKG) /* allow-excludedocs-default */
00558     /* The "%_excludedocs" macro is intended to set the _default_ if
00559        both --excludedocs and --includedocs are not specified and it
00560        is evaluated already before. So, do not override it here again,
00561        because it would not allow us to make "%_excludedocs 1" the
00562        default. */
00563 #else
00564     if (!noDocs)
00565         noDocs = rpmExpandNumeric("%{_excludedocs}");
00566 #endif
00567 
00568     {   const char *tmpPath = rpmExpand("%{?_netsharedpath}", NULL);
00569         if (tmpPath && *tmpPath)
00570             xx = argvSplit(&netsharedPaths, tmpPath, ":");
00571         tmpPath = _free(tmpPath);
00572     }
00573 
00574     s = rpmExpand("%{?_install_langs}", NULL);
00575     if (!(s && *s))
00576         s = _free(s);
00577     if (s) {
00578         xx = argvSplit(&languages, s, ":");
00579         s = _free(s);
00580     }
00581 
00582     /* Compute directory refcount, skip directory if now empty. */
00583     dc = rpmfiDC(fi);
00584     drc = alloca(dc * sizeof(*drc));
00585     memset(drc, 0, dc * sizeof(*drc));
00586     dff = alloca(dc * sizeof(*dff));
00587     memset(dff, 0, dc * sizeof(*dff));
00588 
00589     fi = rpmfiInit(fi, 0);
00590     if (fi != NULL)     /* XXX lclint */
00591     while ((i = rpmfiNext(fi)) >= 0)
00592     {
00593         ARGV_t nsp;
00594 
00595         bn = rpmfiBN(fi);
00596         bnlen = strlen(bn);
00597         ix = rpmfiDX(fi);
00598         dn = rpmfiDN(fi);
00599         if (dn == NULL)
00600             continue;   /* XXX can't happen */
00601         dnlen = strlen(dn);
00602 
00603         drc[ix]++;
00604 
00605         /* Don't bother with skipped files */
00606         if (iosmFileActionSkipped(fi->actions[i])) {
00607             drc[ix]--; dff[ix] = 1;
00608             continue;
00609         }
00610 
00611         /* Ignore colored files not in our rainbow. */
00612         FColor = rpmfiFColor(fi);
00613         if (tscolor && FColor && !(tscolor & FColor)) {
00614             drc[ix]--;  dff[ix] = 1;
00615             fi->actions[i] = FA_SKIPCOLOR;
00616             continue;
00617         }
00618 
00619         /*
00620          * Skip net shared paths.
00621          * Net shared paths are not relative to the current root (though
00622          * they do need to take package relocations into account).
00623          */
00624         for (nsp = netsharedPaths; nsp && *nsp; nsp++) {
00625             size_t len;
00626 
00627             len = strlen(*nsp);
00628             if (dnlen >= len) {
00629                 if (strncmp(dn, *nsp, len))
00630                     /*@innercontinue@*/ continue;
00631                 /* Only directories or complete file paths can be net shared */
00632                 if (!(dn[len] == '/' || dn[len] == '\0'))
00633                     /*@innercontinue@*/ continue;
00634             } else {
00635                 if (len < (dnlen + bnlen))
00636                     /*@innercontinue@*/ continue;
00637                 if (strncmp(dn, *nsp, dnlen))
00638                     /*@innercontinue@*/ continue;
00639                 /* Insure that only the netsharedpath basename is compared. */
00640                 if ((s = strchr((*nsp) + dnlen, '/')) != NULL && s[1] != '\0')
00641                     /*@innercontinue@*/ continue;
00642                 if (strncmp(bn, (*nsp) + dnlen, bnlen))
00643                     /*@innercontinue@*/ continue;
00644                 len = dnlen + bnlen;
00645                 /* Only directories or complete file paths can be net shared */
00646                 if (!((*nsp)[len] == '/' || (*nsp)[len] == '\0'))
00647                     /*@innercontinue@*/ continue;
00648             }
00649 
00650             /*@innerbreak@*/ break;
00651         }
00652 
00653         if (nsp && *nsp) {
00654             drc[ix]--;  dff[ix] = 1;
00655             fi->actions[i] = FA_SKIPNETSHARED;
00656             continue;
00657         }
00658 
00659         /*
00660          * Skip i18n language specific files.
00661          */
00662         if (languages != NULL && fi->flangs != NULL && *fi->flangs[i]) {
00663             ARGV_t lang;
00664             const char *l, *le;
00665             for (lang = languages; *lang != NULL; lang++) {
00666                 if (!strcmp(*lang, "all"))
00667                     /*@innerbreak@*/ break;
00668                 for (l = fi->flangs[i]; *l != '\0'; l = le) {
00669                     for (le = l; *le != '\0' && *le != '|'; le++)
00670                         {};
00671                     if ((le-l) > 0 && !strncmp(*lang, l, (le-l)))
00672                         /*@innerbreak@*/ break;
00673                     if (*le == '|') le++;       /* skip over | */
00674                 }
00675                 if (*l != '\0')
00676                     /*@innerbreak@*/ break;
00677             }
00678             if (*lang == NULL) {
00679                 drc[ix]--;      dff[ix] = 1;
00680                 fi->actions[i] = FA_SKIPNSTATE;
00681                 continue;
00682             }
00683         }
00684 
00685         /*
00686          * Skip config files if requested.
00687          */
00688         if (noConfigs && (rpmfiFFlags(fi) & RPMFILE_CONFIG)) {
00689             drc[ix]--;  dff[ix] = 1;
00690             fi->actions[i] = FA_SKIPNSTATE;
00691             continue;
00692         }
00693 
00694         /*
00695          * Skip documentation if requested.
00696          */
00697         if (noDocs && (rpmfiFFlags(fi) & RPMFILE_DOC)) {
00698             drc[ix]--;  dff[ix] = 1;
00699             fi->actions[i] = FA_SKIPNSTATE;
00700             continue;
00701         }
00702     }
00703 
00704     /* Skip (now empty) directories that had skipped files. */
00705 #ifndef NOTYET
00706     if (fi != NULL)     /* XXX can't happen */
00707     for (j = 0; j < dc; j++)
00708 #else
00709     if ((fi = rpmfiInitD(fi)) != NULL)
00710     while (j = rpmfiNextD(fi) >= 0)
00711 #endif
00712     {
00713 
00714         if (drc[j]) continue;   /* dir still has files. */
00715         if (!dff[j]) continue;  /* dir was not emptied here. */
00716         
00717         /* Find parent directory and basename. */
00718         dn = fi->dnl[j];        dnlen = strlen(dn) - 1;
00719         bn = dn + dnlen;        bnlen = 0;
00720         while (bn > dn && bn[-1] != '/') {
00721                 bnlen++;
00722                 dnlen--;
00723                 bn--;
00724         }
00725 
00726         /* If explicitly included in the package, skip the directory. */
00727         fi = rpmfiInit(fi, 0);
00728         if (fi != NULL)         /* XXX lclint */
00729         while ((i = rpmfiNext(fi)) >= 0) {
00730             const char * fdn, * fbn;
00731             rpmuint16_t fFMode;
00732 
00733             if (iosmFileActionSkipped(fi->actions[i]))
00734                 /*@innercontinue@*/ continue;
00735 
00736             fFMode = rpmfiFMode(fi);
00737 
00738             if (!S_ISDIR(fFMode))
00739                 /*@innercontinue@*/ continue;
00740             fdn = rpmfiDN(fi);
00741             if (strlen(fdn) != dnlen)
00742                 /*@innercontinue@*/ continue;
00743             if (strncmp(fdn, dn, dnlen))
00744                 /*@innercontinue@*/ continue;
00745             fbn = rpmfiBN(fi);
00746             if (strlen(fbn) != bnlen)
00747                 /*@innercontinue@*/ continue;
00748             if (strncmp(fbn, bn, bnlen))
00749                 /*@innercontinue@*/ continue;
00750             rpmlog(RPMLOG_DEBUG, D_("excluding directory %s\n"), dn);
00751             fi->actions[i] = FA_SKIPNSTATE;
00752             /*@innerbreak@*/ break;
00753         }
00754     }
00755 
00756 /*@-dependenttrans@*/
00757     netsharedPaths = argvFree(netsharedPaths);
00758     languages = argvFree(languages);
00759 /*@=dependenttrans@*/
00760 }
00761 /*@=nullpass@*/
00762 /*@=mustmod@*/
00763 
00770 static /*@null@*/
00771 rpmfi rpmtsiFi(const rpmtsi tsi)
00772         /*@*/
00773 {
00774     rpmfi fi = NULL;
00775 
00776     if (tsi != NULL && tsi->ocsave != -1) {
00777         /*@-type -abstract@*/ /* FIX: rpmte not opaque */
00778         rpmte te = rpmtsElement(tsi->ts, tsi->ocsave);
00779         /*@-assignexpose@*/
00780         if (te != NULL && (fi = te->fi) != NULL)
00781             fi->te = te;
00782         /*@=assignexpose@*/
00783         /*@=type =abstract@*/
00784     }
00785     /*@-compdef -refcounttrans -usereleased @*/
00786     return fi;
00787     /*@=compdef =refcounttrans =usereleased @*/
00788 }
00789 
00796 static int cmpArgvStr(/*@null@*/ const char ** AV, /*@null@*/ const char * B)
00797         /*@*/
00798 {
00799     const char ** a;
00800 
00801     if (AV != NULL && B != NULL)
00802     for (a = AV; *a != NULL; a++) {
00803         if (**a && *B && !strcmp(*a, B))
00804             return 1;
00805     }
00806     return 0;
00807 }
00808 
00815 static int rpmtsMarkLinkedFailed(rpmts ts, rpmte p)
00816         /*@globals fileSystem @*/
00817         /*@modifies ts, p, fileSystem @*/
00818 {
00819     rpmtsi qi; rpmte q;
00820     int bingo;
00821 
00822     p->linkFailed = 1;
00823 
00824     qi = rpmtsiInit(ts);
00825     while ((q = rpmtsiNext(qi, TR_REMOVED)) != NULL) {
00826 
00827         if (q->done)
00828             continue;
00829 
00830         /*
00831          * Either element may have missing data and can have multiple entries.
00832          * Try for hdrid, then pkgid, finally NEVRA, argv vs. argv compares.
00833          */
00834         bingo = cmpArgvStr(q->flink.Hdrid, p->hdrid);
00835         if (!bingo)
00836                 bingo = cmpArgvStr(q->flink.Pkgid, p->pkgid);
00837         if (!bingo)
00838                 bingo = cmpArgvStr(q->flink.NEVRA, p->NEVRA);
00839 
00840         if (!bingo)
00841             continue;
00842 
00843         q->linkFailed = p->linkFailed;
00844     }
00845     qi = rpmtsiFree(qi);
00846 
00847     return 0;
00848 }
00849 
00850 /* ================================================================= */
00851 
00852 /* Get a rpmdbMatchIterator containing all files in
00853  * the rpmdb that share the basename with one from
00854  * the transaction.
00855  * @param ts            transaction set
00856  * @return              rpmmi sorted by (package, fileNum)
00857  */
00858 static
00859 rpmmi rpmtsFindBaseNamesInDB(rpmts ts, uint32_t fileCount)
00860         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00861         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00862 {
00863     rpmtsi pi;  rpmte p;
00864     rpmfi fi;
00865     rpmmi mi;
00866     int i, xx;
00867     const char * s;
00868     size_t ns;
00869     void * ptr;
00870     static rpmTag _tag = RPMTAG_BASENAMES;
00871     static double e = 1.0e-4;
00872     size_t m = 0;
00873     size_t k = 0;
00874     rpmbf bf;
00875 
00876 FPSDEBUG(0, (stderr, "--> %s(%p,%u)\n", __FUNCTION__, ts, (unsigned)fileCount));
00877     rpmbfParams(fileCount, e, &m, &k);
00878     bf = rpmbfNew(m, k, 0);
00879 
00880     mi = rpmmiInit(rpmtsGetRdb(ts), _tag, NULL, 0);
00881 
00882     pi = rpmtsiInit(ts);
00883     while ((p = rpmtsiNext(pi, 0)) != NULL) {
00884 
00885         (void) rpmdbCheckSignals();
00886 
00887         if ((fi = rpmteFI(p, _tag)) == NULL)
00888             continue;   /* XXX can't happen */
00889 
00890         ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
00891                     ts->orderCount);
00892 
00893         /* Gather all installed headers with matching basename's. */
00894         fi = rpmfiInit(fi, 0);
00895         while ((i = rpmfiNext(fi)) >= 0) {
00896             s = rpmfiBN(fi);
00897             ns = strlen(s);
00898 
00899             if (ns == 0)        /* XXX "/" fixup */
00900                 /*@innercontinue@*/ continue;
00901             if (rpmbfChk(bf, s, ns))
00902                 /*@innercontinue@*/ continue;
00903 
00904             xx = rpmmiGrowBasename(mi, s);
00905 
00906             xx = rpmbfAdd(bf, s, ns);
00907          }
00908     }
00909     pi = rpmtsiFree(pi);
00910     bf = rpmbfFree(bf);
00911 
00912     (void) rpmmiSort(mi);
00913 
00914     return mi;
00915 }
00916 
00917 /* Check files in the transactions against the rpmdb
00918  * Lookup all files with the same basename in the rpmdb
00919  * and then check for matching finger prints
00920  * @param ts            transaction set
00921  * @param fpc           global finger print cache
00922  */
00923 static
00924 int rpmtsCheckInstalledFiles(rpmts ts, uint32_t fileCount,
00925                 hashTable ht, fingerPrintCache fpc)
00926         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00927         /*@modifies ts, fpc, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00928 {
00929     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00930     rpmTagData BN = { .ptr = NULL };
00931     rpmTagData DN = { .ptr = NULL };
00932     rpmTagData DI = { .ptr = NULL };
00933     rpmTagData FSTATES = { .ptr = NULL };
00934     rpmuint32_t fc;
00935 
00936     rpmte p;
00937     rpmmi mi;
00938     Header h;
00939     rpmfi fi;
00940 
00941     const char * oldDir;
00942     int beingRemoved;
00943     rpmfi otherFi = NULL;
00944     unsigned int fileNum;
00945     int xx;
00946     int rc = 0;
00947 
00948 FPSDEBUG(0, (stderr, "--> %s(%p,%u,%p,%p)\n", __FUNCTION__, ts, (unsigned)fileCount, ht, fpc));
00949 
00950 rpmlog(RPMLOG_DEBUG, D_("computing file dispositions\n"));
00951 
00952     /* XXX fileCount == 0 installing src.rpm's */
00953     if (fileCount == 0)
00954         return rc;
00955 
00956     mi = rpmtsFindBaseNamesInDB(ts, fileCount);
00957 
00958     /* Loop over all packages from the rpmdb */
00959     while ((h = rpmmiNext(mi)) != NULL) {
00960         fingerPrint fp;
00961         uint32_t hdrNum = rpmmiInstance(mi);
00962         uint32_t tagNum = rpmmiBNTag(mi);
00963         int i;
00964         int j;
00965 
00966         /* Is this package being removed? */
00967         beingRemoved = 0;
00968         if (ts->removedPackages != NULL)
00969         for (j = 0; j < ts->numRemovedPackages; j++) {
00970             if (ts->removedPackages[j] != hdrNum)
00971                 /*@innercontinue@*/ continue;
00972             beingRemoved = 1;
00973             /*@innerbreak@*/ break;
00974         }
00975 
00976         he->tag = RPMTAG_BASENAMES;
00977         xx = headerGet(h, he, 0);
00978         BN.argv = (xx ? he->p.argv : NULL);
00979         fc = (xx ? he->c : 0);
00980 
00981         he->tag = RPMTAG_DIRNAMES;
00982         xx = headerGet(h, he, 0);
00983         DN.argv = (xx ? he->p.argv : NULL);
00984         he->tag = RPMTAG_DIRINDEXES;
00985         xx = headerGet(h, he, 0);
00986         DI.ui32p = (xx ? he->p.ui32p : NULL);
00987         he->tag = RPMTAG_FILESTATES;
00988         xx = headerGet(h, he, 0);
00989         FSTATES.ui8p = (xx ? he->p.ui8p : NULL);
00990 
00991         /* loop over all interesting files in that package */
00992         oldDir = NULL;
00993         for (i = 0; i < (int)fc; i++) {
00994             const char * baseName = BN.argv[i];
00995             rpmuint32_t baseKey = hashFunctionString(0, baseName, 0);
00996             int gotRecs;
00997             struct rpmffi_s ** recs;
00998             int numRecs;
00999             const char * dirName;
01000 
01001             /* Skip uninteresting basenames. */
01002             if (baseKey != tagNum)
01003                 /*@innercontinue@*/ continue;
01004             fileNum = i;
01005             dirName = DN.argv[DI.ui32p[fileNum]];
01006 
01007             /* lookup finger print for this file */
01008             if (dirName == oldDir) {
01009                 /* directory is the same as last round */
01010                 fp.baseName = baseName;
01011             } else {
01012                 fp = fpLookup(fpc, dirName, baseName, 1);
01013                 oldDir = dirName;
01014             }
01015 
01016             /* search for files in the transaction with same finger print */
01017             recs = NULL;
01018             numRecs = 0;
01019 #ifdef  REFERENCE
01020             gotRecs = rpmFpHashGetEntry(ht, &fp, &recs, &numRecs, NULL);
01021 #else   /* REFERENCE */
01022             gotRecs = (htGetEntry(ts->ht, &fp, &recs, &numRecs, NULL) == 0);
01023 #endif  /* REFERENCE */
01024 
01025             for (j = 0; j < numRecs && gotRecs; j++) {
01026                 p = recs[j]->p;
01027                 fi = rpmteFI(p, RPMTAG_BASENAMES);
01028 
01029                 /* Determine the fate of each file. */
01030                 switch (rpmteType(p)) {
01031                 case TR_ADDED:
01032                     if (otherFi == NULL) {
01033                         static int scareMem = 0;
01034                         otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01035                     }
01036                     (void) rpmfiSetFX(fi, recs[j]->fileno);
01037                     (void) rpmfiSetFX(otherFi, fileNum);
01038                     xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved);
01039                     /*@switchbreak@*/ break;
01040                 case TR_REMOVED:
01041                     if (!beingRemoved) {
01042                         (void) rpmfiSetFX(fi, recs[j]->fileno);
01043 #ifdef  REFERENCE
01044                         if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) {
01045                             rpmfs fs = rpmteGetFileStates(p);
01046                             rpmfsSetAction(fs, recs[j].fileno, FA_SKIP);
01047                         }
01048 #else
01049                         if (FSTATES.ui8p[fileNum] == RPMFILE_STATE_NORMAL)
01050                             fi->actions[recs[j]->fileno] = FA_SKIP;
01051 #endif
01052                     }
01053                     /*@switchbreak@*/ break;
01054                 }
01055             }
01056 
01057         }
01058 
01059         otherFi = rpmfiFree(otherFi);
01060         FSTATES.ptr = _free(FSTATES.ptr);
01061         DI.ptr = _free(DI.ptr);
01062         DN.ptr = _free(DN.ptr);
01063         BN.ptr = _free(BN.ptr);
01064     }
01065 
01066     mi = rpmmiFree(mi);
01067 
01068     return rc;
01069 }
01070 
01071 /*
01072  * For packages being installed:
01073  * - verify package arch/os.
01074  * - verify package epoch:version-release is newer.
01075  */
01076 static rpmps rpmtsSanityCheck(rpmts ts, uint32_t * tfcp)
01077         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01078         /*@modifies ts, *tfcp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01079 {
01080     rpmps ps;
01081     rpmtsi pi;
01082     rpmte p;
01083     rpmfi fi;
01084     uint32_t totalFileCount = 0;
01085     int fc;
01086 
01087 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, tfcp));
01088 rpmlog(RPMLOG_DEBUG, D_("sanity checking %d elements\n"), rpmtsNElements(ts));
01089     ps = rpmtsProblems(ts);
01090     /* The ordering doesn't matter here */
01091     pi = rpmtsiInit(ts);
01092     /* XXX Only added packages need be checked. */
01093     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01094         int xx;
01095 
01096         if (p->isSource) continue;
01097         if ((fi = rpmtsiFi(pi)) == NULL)
01098             continue;   /* XXX can't happen */
01099         fc = rpmfiFC(fi);
01100 
01101 #ifdef  REFERENCE
01102         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
01103             if (!archOkay(rpmteA(p)))
01104                 rpmpsAppend(ps, RPMPROB_BADARCH,
01105                         rpmteNEVRA(p), rpmteKey(p),
01106                         rpmteA(p), NULL,
01107                         NULL, 0);
01108 
01109         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
01110             if (!osOkay(rpmteO(p)))
01111                 rpmpsAppend(ps, RPMPROB_BADOS,
01112                         rpmteNEVRA(p), rpmteKey(p),
01113                         rpmteO(p), NULL,
01114                         NULL, 0);
01115 #endif  /* REFERENCE */
01116 
01117         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
01118             rpmmi mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
01119             Header h;
01120             while ((h = rpmmiNext(mi)) != NULL)
01121                 xx = ensureOlder(ts, p, h);
01122             mi = rpmmiFree(mi);
01123         }
01124 
01125         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
01126             ARGV_t keys = NULL;
01127             int nkeys;
01128             xx = rpmdbMireApply(rpmtsGetRdb(ts), RPMTAG_NVRA,
01129                 RPMMIRE_STRCMP, rpmteNEVRA(p), &keys);
01130             nkeys = argvCount(keys);
01131             if (nkeys > 0)
01132                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
01133                         rpmteNEVR(p), rpmteKey(p),
01134                         NULL, NULL,
01135                         NULL, 0);
01136             keys = argvFree(keys);
01137         }
01138 
01139 #ifdef  REFERENCE
01140         /* XXX rpmte problems can only be relocation problems atm */
01141         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE)) {
01142             rpmpsi psi = rpmpsInitIterator(rpmteProblems(p));
01143             while (rpmpsNextIterator(psi) >= 0) {
01144                 rpmpsAppendProblem(ps, rpmpsGetProblem(psi));
01145             }
01146             rpmpsFreeIterator(psi);
01147         }
01148 #endif  /* REFERENCE */
01149 
01150         /* Count no. of files (if any). */
01151         totalFileCount += fc;
01152 
01153     }
01154     pi = rpmtsiFree(pi);
01155 
01156     /* The ordering doesn't matter here */
01157     pi = rpmtsiInit(ts);
01158     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01159 
01160         if (p->isSource) continue;
01161         if ((fi = rpmtsiFi(pi)) == NULL)
01162             continue;   /* XXX can't happen */
01163         fc = rpmfiFC(fi);
01164 
01165         totalFileCount += fc;
01166     }
01167     pi = rpmtsiFree(pi);
01168 
01169     if (tfcp)
01170         *tfcp = totalFileCount;
01171 
01172     return ps;
01173 }
01174 
01175 /*
01176  * Run pre/post transaction script.
01177  * param ts     transaction set
01178  * param stag   RPMTAG_PRETRANS or RPMTAG_POSTTRANS
01179  * return       0 on success
01180  */
01181 static int rpmtsRunScript(rpmts ts, rpmTag stag) 
01182         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01183         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01184 {
01185     rpmtsi pi; 
01186     rpmte p;
01187     rpmfi fi;
01188     rpmpsm psm;
01189     int xx;
01190     rpmTag ptag;
01191 
01192 FPSDEBUG(0, (stderr, "--> %s(%p,%s(%u))\n", __FUNCTION__, ts, tagName(stag), (unsigned)stag));
01193     switch (stag) {
01194     default:
01195 assert(0);
01196         /*@notreached@*/ break;
01197     case RPMTAG_PRETRANS:       ptag = RPMTAG_PRETRANSPROG;     break;
01198     case RPMTAG_POSTTRANS:      ptag = RPMTAG_POSTTRANSPROG;    break;
01199     }
01200 
01201     pi = rpmtsiInit(ts);
01202     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01203         if (p->isSource) continue;
01204         if ((fi = rpmtsiFi(pi)) == NULL)
01205             continue;   /* XXX can't happen */
01206 
01207         /* If no prre/post transaction script, then don't bother. */
01208         if (!rpmteHaveTransScript(p, stag))
01209             continue;
01210 
01211         if (rpmteOpen(p, ts, 0)) {
01212             if (p->fi != NULL)  /* XXX can't happen */
01213                 p->fi->te = p;
01214 #ifdef  REFERENCE
01215             psm = rpmpsmNew(ts, p);
01216 #else   /* REFERENCE */
01217             psm = rpmpsmNew(ts, p, p->fi);
01218 #endif  /* REFERENCE */
01219             xx = rpmpsmScriptStage(psm, stag, ptag);
01220             psm = rpmpsmFree(psm, __FUNCTION__);
01221             xx = rpmteClose(p, ts, 0);
01222         }
01223     }
01224     pi = rpmtsiFree(pi);
01225 
01226     return 0;
01227 }
01228 
01229 /* Add fingerprint for each file not skipped. */
01230 static void rpmtsAddFingerprints(rpmts ts, uint32_t fileCount, hashTable ht,
01231                 fingerPrintCache fpc)
01232         /*@modifies ts, fpc @*/
01233 {
01234     rpmtsi pi;
01235     rpmte p;
01236     rpmfi fi;
01237     int i;
01238 
01239     hashTable symlinks = htCreate(fileCount/16+16, 0, 0, fpHashFunction, fpEqual);
01240 
01241 FPSDEBUG(0, (stderr, "--> %s(%p,%u,%p,%p)\n", __FUNCTION__, ts, (unsigned)fileCount, ht, fpc));
01242     pi = rpmtsiInit(ts);
01243     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01244         (void) rpmdbCheckSignals();
01245 
01246         if (p->isSource) continue;
01247         if ((fi = rpmtsiFi(pi)) == NULL)
01248             continue;   /* XXX can't happen */
01249 
01250         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01251 
01252         rpmfiFpLookup(fi, fpc);
01253 
01254         /* Collect symlinks. */
01255         fi = rpmfiInit(fi, 0);
01256         if (fi != NULL)         /* XXX lclint */
01257         while ((i = rpmfiNext(fi)) >= 0) {
01258             char const *linktarget;
01259             linktarget = rpmfiFLink(fi);
01260             if (!(linktarget && *linktarget != '\0'))
01261                 /*@innercontinue@*/ continue;
01262             if (iosmFileActionSkipped(fi->actions[i]))
01263                 /*@innercontinue@*/ continue;
01264 #ifdef  REFERENCE
01265             {   struct rpmffi_s ffi;
01266                 ffi.p = p;
01267                 ffi.fileno = i;
01268                 htAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi);
01269             }
01270 #else
01271             {   struct rpmffi_s *ffip = alloca(sizeof(*ffip));
01272 /*@-dependenttrans@*/
01273                 ffip->p = p;
01274 /*@=dependenttrans@*/
01275                 ffip->fileno = i;
01276                 htAddEntry(symlinks, fi->fps + i, (void *) ffip);
01277             }
01278 #endif
01279         }
01280 
01281         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
01282 
01283     }
01284     pi = rpmtsiFree(pi);
01285 
01286     /* ===============================================
01287      * Check fingerprints if they contain symlinks
01288      * and add them to the hash table
01289      */
01290 
01291     pi = rpmtsiInit(ts);
01292     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01293         (void) rpmdbCheckSignals();
01294 
01295         if (p->isSource) continue;
01296         if ((fi = rpmteFI(p, RPMTAG_BASENAMES)) == NULL)
01297             continue;   /* XXX can't happen */
01298         fi = rpmfiInit(fi, 0);
01299         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01300         while ((i = rpmfiNext(fi)) >= 0) {
01301 #ifdef  REFERENCE
01302             if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
01303                 continue;
01304 #else
01305             if (iosmFileActionSkipped(fi->actions[i]))
01306                 /*@innercontinue@*/ continue;
01307 #endif
01308             fpLookupSubdir(symlinks, ht, fpc, p, i);
01309         }
01310         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01311     }
01312     pi = rpmtsiFree(pi);
01313 
01314     symlinks = htFree(symlinks);
01315 
01316 }
01317 
01318 static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet, rpmsx * sxp)
01319         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01320         /*@modifies ts, *sxp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01321 {
01322     int xx;
01323 
01324 /*@+voidabstract@*/
01325 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%p)\n", __FUNCTION__, ts, ignoreSet, (void *)sxp));
01326 /*@=voidabstract@*/
01327     /* --noscripts implies no scripts or triggers, duh. */
01328     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
01329         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01330     /* --notriggers implies no triggers, duh. */
01331     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
01332         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
01333 
01334     /* --justdb implies no scripts or triggers, duh. */
01335     if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
01336         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01337 
01338     /* if SELinux isn't enabled or init fails, don't bother... */
01339     if (!rpmtsSELinuxEnabled(ts))
01340         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY)));
01341 
01342     if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY))) {
01343         *sxp = rpmsxNew("%{?_install_file_context_path}", 0);
01344         if (*sxp == NULL)
01345             (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY)));
01346     } else
01347         *sxp = NULL;
01348 
01349     /* XXX Make sure the database is open RDWR for package install/erase. */
01350     {   int dbmode = O_RDONLY;
01351 
01352         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
01353             rpmtsi pi;
01354             rpmte p;
01355             pi = rpmtsiInit(ts);
01356             while ((p = rpmtsiNext(pi, 0)) != NULL) {
01357                 if (p->isSource) continue;
01358                 dbmode = (O_RDWR|O_CREAT);
01359                 break;
01360             }
01361             pi = rpmtsiFree(pi);
01362         }
01363 
01364         /* Open database RDWR for installing packages. */
01365         if (rpmtsOpenDB(ts, dbmode))
01366             return -1;  /* XXX W2DO? */
01367 
01368     }
01369 
01370     ts->ignoreSet = ignoreSet;
01371     ts->probs = rpmpsFree(ts->probs);
01372 
01373     {   const char * currDir = currentDirectory();
01374         rpmtsSetCurrDir(ts, currDir);
01375         currDir = _free(currDir);
01376     }
01377 
01378     (void) rpmtsSetChrootDone(ts, 0);
01379 
01380     /* XXX rpmtsCreate() sets the transaction id, but apps may not honor. */
01381     {   rpmuint32_t tid = (rpmuint32_t) time(NULL);
01382         (void) rpmtsSetTid(ts, tid);
01383     }
01384 
01385     /* Get available space on mounted file systems. */
01386     xx = rpmtsInitDSI(ts);
01387 
01388     return 0;
01389 }
01390 
01391 static int rpmtsFinish(rpmts ts, /*@only@*/ rpmsx sx)
01392         /*@modifies sx @*/
01393 {
01394 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, sx));
01395 #ifdef  REFERENCE
01396     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
01397         matchpathcon_fini();
01398     }
01399 #else   /* REFERENCE */
01400     if (sx != NULL) sx = rpmsxFree(sx);
01401 #endif  /* REFERENCE */
01402     return 0;
01403 }
01404 
01405 static int rpmtsPrepare(rpmts ts, rpmsx sx, uint32_t fileCount,
01406                 uint32_t * nrmvdp)
01407         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01408         /*@modifies ts, *nrmvdp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01409 {
01410     rpmtsi pi;
01411     rpmte p;
01412     fingerPrintCache fpc;
01413     rpmfi fi;
01414     int xx;
01415     int rc = 0;
01416 
01417 #ifdef  REFERENCE
01418     uint64_t fileCount = countFiles(ts);
01419     const char * rootDir = rpmtsRootDir(ts);
01420     int dochroot = (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/');
01421 
01422     rpmFpHash ht = rpmFpHashCreate(fileCount/2+1, fpHashFunction, fpEqual,
01423                              NULL, NULL);
01424 
01425     fpc = fpCacheCreate(fileCount/2 + 10001);
01426 
01427     rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount);
01428 
01429     /* Skip netshared paths, not our i18n files, and excluded docs */
01430     pi = rpmtsiInit(ts);
01431     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01432         if ((fi = rpmteFI(p)) == NULL)
01433             continue;   /* XXX can't happen */
01434 
01435         if (rpmfiFC(fi) > 0) 
01436             rpmtsSkipFiles(ts, p);
01437     }
01438     pi = rpmtsiFree(pi);
01439 
01440     /* Enter chroot for fingerprinting if necessary */
01441     if (!rpmtsChrootDone(ts)) {
01442         xx = chdir("/");
01443         if (dochroot) {
01444             /* opening db before chroot not optimal, see rhbz#103852 c#3 */
01445             xx = rpmdbOpenAll(ts->rdb);
01446             if (chroot(rootDir) == -1) {
01447                 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
01448                 rc = -1;
01449                 goto exit;
01450             }
01451         }
01452         (void) rpmtsSetChrootDone(ts, 1);
01453     }
01454     
01455 #else   /* REFERENCE */
01456 
01457     void * ptr;
01458     uint32_t numAdded = 0;
01459     uint32_t numRemoved = 0;
01460 
01461 FPSDEBUG(0, (stderr, "--> %s(%p,%p,%u,%p)\n", __FUNCTION__, ts, sx, (unsigned)fileCount, nrmvdp));
01462 rpmlog(RPMLOG_DEBUG, D_("computing %u file fingerprints\n"), (unsigned)fileCount);
01463 
01464     pi = rpmtsiInit(ts);
01465     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01466         int fc;
01467 
01468         if (p->isSource) continue;
01469         if ((fi = rpmtsiFi(pi)) == NULL)
01470             continue;   /* XXX can't happen */
01471         fc = rpmfiFC(fi);
01472 
01473         switch (rpmteType(p)) {
01474         case TR_ADDED:
01475             numAdded++;
01476             fi->record = 0;
01477             /* Skip netshared paths, not our i18n files, and excluded docs */
01478             if (fc > 0)
01479                 rpmtsSkipFiles(ts, fi);
01480             /*@switchbreak@*/ break;
01481         case TR_REMOVED:
01482             numRemoved++;
01483             fi->record = rpmteDBOffset(p);
01484             /*@switchbreak@*/ break;
01485         }
01486 
01487         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
01488     }
01489     pi = rpmtsiFree(pi);
01490 
01491     if (nrmvdp)
01492         *nrmvdp = numRemoved;
01493 
01494     if (!rpmtsChrootDone(ts)) {
01495         const char * rootDir = rpmtsRootDir(ts);
01496         static int openall_before_chroot = -1;
01497 
01498         if (openall_before_chroot < 0)
01499             openall_before_chroot = rpmExpandNumeric("%{?_openall_before_chroot}");
01500 
01501         xx = Chdir("/");
01502         /*@-modobserver@*/
01503         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
01504             if (openall_before_chroot)
01505                 xx = rpmdbOpenAll(rpmtsGetRdb(ts));
01506             xx = Chroot(rootDir);
01507         }
01508         /*@=modobserver@*/
01509         (void) rpmtsSetChrootDone(ts, 1);
01510     }
01511 
01512     ts->ht = htCreate(fileCount/2 + 1, 0, 1, fpHashFunction, fpEqual);
01513     fpc = fpCacheCreate(fileCount/2 + 10001);
01514 
01515 #endif  /* REFERENCE */
01516 
01517     ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount);
01518 
01519     /* ===============================================
01520      * Add fingerprint for each file not skipped.
01521      */
01522 #ifdef  REFERENCE
01523     rpmtsAddFingerprints(ts, fileCount, ht, fpc);
01524 #else   /* REFERENCE */
01525     rpmtsAddFingerprints(ts, fileCount, ts->ht, fpc);
01526 #endif  /* REFERENCE */
01527 
01528     /* ===============================================
01529      * Compute file disposition for each package in transaction set.
01530      */
01531 #ifdef  REFERENCE
01532     rpmtsCheckInstalledFiles(ts, fileCount, ht, fpc);
01533 #else   /* REFERENCE */
01534     rc = rpmtsCheckInstalledFiles(ts, fileCount, ts->ht, fpc);
01535     if (rc)
01536         goto exit;
01537 #endif  /* REFERENCE */
01538 
01539     pi = rpmtsiInit(ts);
01540     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01541         if ((fi = rpmteFI(p, RPMTAG_BASENAMES)) == NULL)
01542             continue;   /* XXX can't happen */
01543         /* XXX Set all SRPM files to FA_CREATE. */
01544         if (p->isSource) {
01545             int i;
01546             fi = rpmfiInit(fi, 0);
01547             if (fi != NULL)
01548             while ((i = rpmfiNext(fi)) >= 0)
01549                 fi->actions[i] = FA_CREATE;
01550             continue;
01551         }
01552 
01553         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01554 
01555         /* Update disk space needs on each partition for this package. */
01556 /*@-nullpass@*/
01557 #ifdef  REFERENCE
01558         handleOverlappedFiles(ts, ht, p, fi);
01559 #else   /* REFERENCE */
01560         handleOverlappedFiles(ts, p, fi);
01561 #endif  /* REFERENCE */
01562 /*@=nullpass@*/
01563 
01564         /* Check added package has sufficient space on each partition used. */
01565         switch (rpmteType(p)) {
01566         case TR_ADDED:
01567             rpmtsCheckDSIProblems(ts, p);
01568             /*@switchbreak@*/ break;
01569         case TR_REMOVED:
01570             /*@switchbreak@*/ break;
01571         }
01572         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
01573     }
01574     pi = rpmtsiFree(pi);
01575 
01576     if (rpmtsChrootDone(ts)) {
01577         const char * rootDir = rpmtsRootDir(ts);
01578         const char * currDir = rpmtsCurrDir(ts);
01579         /*@-modobserver@*/
01580         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
01581             xx = Chroot(".");
01582         /*@=modobserver@*/
01583         (void) rpmtsSetChrootDone(ts, 0);
01584         if (currDir != NULL)
01585             xx = Chdir(currDir);
01586     }
01587 
01588     ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount);
01589 
01590     /* ===============================================
01591      * Free unused memory as soon as possible.
01592      */
01593 #ifdef  REFERENCE
01594     pi = rpmtsiInit(ts);
01595     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01596         rpmteSetFI(p, NULL);
01597     }
01598     pi = rpmtsiFree(pi);
01599 #else   /* REFERENCE */
01600     pi = rpmtsiInit(ts);
01601     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01602         if (p->isSource) continue;
01603         if ((fi = rpmtsiFi(pi)) == NULL)
01604             continue;   /* XXX can't happen */
01605         if (rpmfiFC(fi) == 0)
01606             continue;
01607         fi->fps = _free(fi->fps);
01608     }
01609     pi = rpmtsiFree(pi);
01610 #endif  /* REFERENCE */
01611 
01612 exit:
01613 #ifdef  REFERENCE
01614     ht = rpmFpHashFree(ht);
01615 #else   /* REFERENCE */
01616     ts->ht = htFree(ts->ht);
01617 #endif  /* REFERENCE */
01618     fpc = fpCacheFree(fpc);
01619 
01620     return rc;
01621 }
01622 
01623 /*
01624  * Transaction main loop: install and remove packages
01625  */
01626 static int rpmtsProcess(rpmts ts, rpmprobFilterFlags ignoreSet,
01627                 int rollbackFailures)
01628         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01629         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01630 {
01631     rpmtsi pi;
01632     rpmte p;
01633     int rc = 0;
01634 
01635 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%d)\n", __FUNCTION__, ts, ignoreSet, rollbackFailures));
01636     pi = rpmtsiInit(ts);
01637     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01638         rpmfi fi;
01639         rpmop sw;
01640         rpmpsm psm = NULL;
01641         pkgStage stage = PSM_UNKNOWN;
01642         int failed;
01643         int gotfd;
01644         int xx;
01645 
01646 #ifdef  REFERENCE
01647         rpmElementType tetype = rpmteType(p);
01648         rpmtsOpX op = (tetype == TR_ADDED) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
01649 #endif  /* REFERENCE */
01650 
01651         (void) rpmdbCheckSignals();
01652 
01653         failed = 1;
01654         gotfd = 0;
01655         if ((fi = rpmtsiFi(pi)) == NULL)
01656             continue;   /* XXX can't happen */
01657         
01658         if (rpmteFailed(p)) {
01659             /* XXX this should be a warning, need a better message though */
01660             rpmlog(RPMLOG_DEBUG, D_("element %s marked as failed, skipping\n"),
01661                                         rpmteNEVRA(p));
01662             rc++;
01663             continue;
01664         }
01665 
01666         psm = rpmpsmNew(ts, p, fi);
01667         {   int async = (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1)) ? 
01668                         1 : 0;
01669             rpmpsmSetAsync(psm, async);
01670         }
01671 
01672         switch (rpmteType(p)) {
01673         case TR_ADDED:
01674             rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
01675                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01676             stage = PSM_PKGINSTALL;
01677             sw = rpmtsOp(ts, RPMTS_OP_INSTALL);
01678 #ifdef  REFERENCE
01679             if (rpmteOpen(p, ts, 1)) {
01680                 (void) rpmswEnter(rpmtsOp(ts, op), 0);
01681                 failed = rpmpsmStage(psm, stage);
01682                 (void) rpmswExit(rpmtsOp(ts, op), 0);
01683                 rpmteClose(p, ts, 1);
01684             }
01685 #else   /* REFERENCE */
01686             if ((p->h = rpmteFDHeader(ts, p)) != NULL)
01687                 gotfd = 1;
01688 
01689             if (gotfd && rpmteFd(p) != NULL) {
01690                 /*
01691                  * XXX Sludge necessary to transfer existing fstates/actions
01692                  * XXX around a recreated file info set.
01693                  */
01694                 rpmuint8_t * fstates = fi->fstates;
01695                 iosmFileAction * actions = (iosmFileAction *) fi->actions;
01696                 int mapflags = fi->mapflags;
01697                 rpmte savep;
01698                 int scareMem = 0;
01699 
01700                 psm->fi = rpmfiFree(psm->fi);
01701 
01702                 fi->fstates = NULL;
01703                 fi->actions = NULL;
01704 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
01705                 fi = rpmfiFree(fi);
01706 /*@=nullstate@*/
01707 
01708                 savep = rpmtsSetRelocateElement(ts, p);
01709                 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, scareMem);
01710                 (void) rpmtsSetRelocateElement(ts, savep);
01711 
01712                 if (fi != NULL) {       /* XXX can't happen */
01713                     fi->te = p;
01714                     fi->fstates = _free(fi->fstates);
01715                     fi->fstates = fstates;
01716                     fi->actions = _free(fi->actions);
01717                     fi->actions = (int *) actions;
01718                     if (mapflags & IOSM_SBIT_CHECK)
01719                         fi->mapflags |= IOSM_SBIT_CHECK;
01720                     p->fi = fi;
01721                 }
01722 
01723                 psm->fi = rpmfiLink(p->fi, __FUNCTION__);
01724 
01725                 (void) rpmswEnter(sw, 0);
01726                 failed = (rpmpsmStage(psm, stage) != RPMRC_OK);
01727                 (void) rpmswExit(sw, 0);
01728 
01729                 xx = rpmteClose(p, ts, 0);
01730                 gotfd = 0;
01731             }
01732 
01733 #endif  /* REFERENCE */
01734             /*@switchbreak@*/ break;
01735 
01736         case TR_REMOVED:
01737             rpmlog(RPMLOG_DEBUG, "========== --- %s %s-%s 0x%x\n",
01738                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01739             stage = PSM_PKGERASE;
01740             sw = rpmtsOp(ts, RPMTS_OP_ERASE);
01741 #ifdef  REFERENCE
01742             if (rpmteOpen(p, ts, 1)) {
01743                 (void) rpmswEnter(rpmtsOp(ts, op), 0);
01744                 failed = rpmpsmStage(psm, stage);
01745                 (void) rpmswExit(rpmtsOp(ts, op), 0);
01746                 rpmteClose(p, ts, 1);
01747             }
01748 #else   /* REFERENCE */
01749             (void) rpmswEnter(sw, 0);
01750             failed = (rpmpsmStage(psm, stage) != RPMRC_OK);
01751             (void) rpmswExit(sw, 0);
01752 #endif  /* REFERENCE */
01753             /*@switchbreak@*/ break;
01754         }
01755 
01756 #if defined(RPM_VENDOR_MANDRIVA)
01757         if (!failed) {
01758             if(!rpmteIsSource(p))
01759                 xx = mayAddToFilesAwaitingFiletriggers(rpmtsRootDir(ts),
01760                                 fi, (rpmteType(p) == TR_ADDED ? 1 : 0));
01761             p->done = 1;
01762         }
01763 #endif
01764 
01765 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
01766         psm = rpmpsmFree(psm, __FUNCTION__);
01767 /*@=nullstate@*/
01768 
01769         if (failed) {
01770             rc++;
01771 #ifdef  REFERENCE
01772             rpmteMarkFailed(p, ts);
01773 #else   /* REFERENCE */
01774             xx = rpmtsMarkLinkedFailed(ts, p);
01775         /* If we received an error, lets break out and rollback, provided
01776          * autorollback is enabled.
01777          */
01778             if (rollbackFailures) {
01779                 xx = rpmtsRollback(ts, ignoreSet, 1, p);
01780                 break;
01781             }
01782 #endif  /* REFERENCE */
01783         }
01784 
01785         if (p->h != NULL) {
01786             (void) headerFree(p->h);
01787             p->h = NULL;
01788         }
01789 
01790 #ifdef  REFERENCE
01791         (void) rpmdbSync(rpmtsGetRdb(ts));
01792 #endif  /* REFERENCE */
01793 
01794     }
01795     pi = rpmtsiFree(pi);
01796     return rc;
01797 }
01798 
01799 /* ================================================================= */
01800 static int rpmtsRepackage(rpmts ts, uint32_t numRemoved)
01801         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01802         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01803 {
01804     rpmpsm psm;
01805     rpmfi fi;
01806     rpmtsi pi;
01807     rpmte p;
01808     void * ptr;
01809     int progress = 0;
01810     int rc = 0;
01811     int xx;
01812 
01813 FPSDEBUG(0, (stderr, "--> %s(%p,%u)\n", __FUNCTION__, ts, (unsigned)numRemoved));
01814     pi = rpmtsiInit(ts);
01815     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01816 
01817         (void) rpmdbCheckSignals();
01818 
01819         if (p->isSource) continue;
01820         if ((fi = rpmtsiFi(pi)) == NULL)
01821             continue;   /* XXX can't happen */
01822         switch (rpmteType(p)) {
01823         case TR_ADDED:
01824             /*@switchbreak@*/ break;
01825         case TR_REMOVED:
01826             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
01827                 /*@switchbreak@*/ break;
01828             if (!progress)
01829                 ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_START,
01830                                 7, numRemoved);
01831 
01832             ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_PROGRESS,
01833                                 progress, numRemoved);
01834             progress++;
01835 
01836             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01837 
01838         /* XXX TR_REMOVED needs IOSM_MAP_{ABSOLUTE,ADDDOT} IOSM_ALL_HARDLINKS */
01839             fi->mapflags |= IOSM_MAP_ABSOLUTE;
01840             fi->mapflags |= IOSM_MAP_ADDDOT;
01841             fi->mapflags |= IOSM_ALL_HARDLINKS;
01842             psm = rpmpsmNew(ts, p, fi);
01843 assert(psm != NULL);
01844             xx = rpmpsmStage(psm, PSM_PKGSAVE);
01845             psm = rpmpsmFree(psm, __FUNCTION__);
01846             fi->mapflags &= ~IOSM_MAP_ABSOLUTE;
01847             fi->mapflags &= ~IOSM_MAP_ADDDOT;
01848             fi->mapflags &= ~IOSM_ALL_HARDLINKS;
01849 
01850             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01851 
01852             /*@switchbreak@*/ break;
01853         }
01854     }
01855     pi = rpmtsiFree(pi);
01856     if (progress)
01857         ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved);
01858 
01859     return rc;
01860 }
01861 
01868 /*@-nullpass@*/
01869 static rpmRC _processFailedPackage(rpmts ts, rpmte p)
01870         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01871         /*@modifies ts, p, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01872 {
01873     int rc  = RPMRC_OK; /* assume success */
01874 
01875 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, p));
01876     /* Handle failed packages. */
01877     /* XXX TODO: Add header to rpmdb in PSM_INIT, not PSM_POST. */
01878     if (p != NULL && rpmteType(p) == TR_ADDED && !p->installed) {
01879 /*@-compdef -usereleased@*/     /* p->fi->te undefined */
01880         rpmpsm psm = rpmpsmNew(ts, p, p->fi);
01881 /*@=compdef =usereleased@*/
01882         /*
01883          * If it died before the header was put in the rpmdb, we need
01884          * do to something wacky which is add the header to the DB anyway.
01885          * This will allow us to add the failed package as an erase
01886          * to the rollback transaction.  This must be done because we
01887          * want the the erase scriptlets to run, and the only way that
01888          * is going is if the header is in the rpmdb.
01889          */
01890 assert(psm != NULL);
01891         psm->stepName = "failed";       /* XXX W2DO? */
01892         rc = rpmpsmStage(psm, PSM_RPMDB_ADD);
01893         psm = rpmpsmFree(psm, __FUNCTION__);
01894     }
01895     return rc;
01896 }
01897 /*@=nullpass@*/
01898 
01899 /*@-nullpass@*/
01900 rpmRC rpmtsRollback(rpmts rbts, rpmprobFilterFlags ignoreSet, int running, rpmte rbte)
01901         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01902         /*@modifies rbts, rpmGlobalMacroContext, fileSystem, internalState @*/
01903 {
01904     const char * semfn = NULL;
01905     rpmRC rc = 0;
01906     rpmuint32_t arbgoal = rpmtsARBGoal(rbts);
01907     QVA_t ia = memset(alloca(sizeof(*ia)), 0, sizeof(*ia));
01908     time_t ttid;
01909     int xx;
01910 
01911 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%d,%p)\n", __FUNCTION__, rbts, ignoreSet, running, rbte));
01912     /* Don't attempt rollback's of rollback transactions */
01913     if ((rpmtsType(rbts) & RPMTRANS_TYPE_ROLLBACK) ||
01914         (rpmtsType(rbts) & RPMTRANS_TYPE_AUTOROLLBACK))
01915         return RPMRC_OK;
01916 
01917     if (arbgoal == 0xffffffff) 
01918         arbgoal = rpmtsGetTid(rbts);
01919 
01920     /* Don't attempt rollbacks if no goal is set. */
01921     if (!running && arbgoal == 0xffffffff)
01922         return RPMRC_OK;
01923 
01924     /* We need to remove an headers that were going to be removed so 
01925      * as to not foul up the regular rollback mechanism which will not 
01926      * handle properly a file being in the repackaged package directory
01927      * and also its header still in the DB.
01928      */
01929     {   rpmtsi tsi;
01930         rpmte te;
01931 
01932         /* XXX Insure an O_RDWR rpmdb. */
01933         xx = rpmtsOpenDB(rbts, O_RDWR);
01934 
01935         tsi = rpmtsiInit(rbts);
01936         while((te = rpmtsiNext(tsi, TR_REMOVED)) != NULL) {
01937             if (te->isSource) continue;
01938             if(!te->u.removed.dboffset)
01939                 continue;
01940             rc = rpmdbRemove(rpmtsGetRdb(rbts),
01941                         rpmtsGetTid(rbts),
01942                         te->u.removed.dboffset, NULL);
01943             if (rc != RPMRC_OK) {
01944                 rpmlog(RPMLOG_ERR, _("rpmdb erase failed. NEVRA: %s\n"),
01945                         rpmteNEVRA(te));
01946                 break;
01947             }
01948         }
01949         tsi = rpmtsiFree(tsi);
01950         if (rc != RPMRC_OK) 
01951             goto cleanup;
01952     }
01953 
01954     /* Process the failed package */
01955     rc = _processFailedPackage(rbts, rbte);
01956     if (rc != RPMRC_OK)
01957         goto cleanup;
01958 
01959     rpmtsEmpty(rbts);
01960 
01961     ttid = (time_t)arbgoal;
01962     rpmlog(RPMLOG_NOTICE, _("Rollback to %-24.24s (0x%08x)\n"),
01963         ctime(&ttid), arbgoal);
01964 
01965     /* Set the verify signature flags:
01966      *  - can't verify signatures/digests on repackaged packages.
01967      *  - header check are out.
01968      */
01969     {
01970         rpmVSFlags vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
01971         vsflags |= _RPMVSF_NODIGESTS;
01972         vsflags |= _RPMVSF_NOSIGNATURES;
01973         vsflags |= RPMVSF_NOHDRCHK;
01974         vsflags |= RPMVSF_NEEDPAYLOAD;      
01975         xx = rpmtsSetVSFlags(rbts, vsflags); 
01976     }
01977 
01978     /* Set transaction flags to be the same as the running transaction */
01979     {
01980         rpmtransFlags tsFlags = rpmtsFlags(rbts);
01981         tsFlags &= ~RPMTRANS_FLAG_DIRSTASH;     /* No repackage of rollbacks */
01982         tsFlags &= ~RPMTRANS_FLAG_REPACKAGE;    /* No repackage of rollbacks */
01983         tsFlags |= RPMTRANS_FLAG_NOFDIGESTS;    /* Don't check file digests */
01984         tsFlags = rpmtsSetFlags(rbts, tsFlags);
01985     }
01986 
01987     /* Create install arguments structure */    
01988     ia->rbtid = arbgoal;
01989     /* transFlags/depFlags from rbts, (re-)set in rpmRollback(). */
01990     ia->transFlags = rpmtsFlags(rbts);
01991     ia->depFlags = rpmtsDFlags(rbts);
01992     /* XXX probFilter is normally set in main(). */
01993     ia->probFilter = ignoreSet; /* XXX RPMPROB_FILTER_NONE? */
01994     /* XXX installInterfaceFlags is normally set in main(). */
01995     ia->installInterfaceFlags = INSTALL_UPGRADE | INSTALL_HASH ;
01996 
01997     /* rpmtsCheck and rpmtsOrder failures do not have links. */
01998     ia->no_rollback_links = 1;
01999 
02000     /* Create a file semaphore. */
02001     semfn = rpmExpand("%{?semaphore_backout}", NULL);
02002     if (semfn && *semfn) {
02003         FD_t fd = Fopen(semfn, "w.fdio");
02004         if (fd)
02005             xx = Fclose(fd);
02006     }
02007 
02008 /*@-compmempass@*/
02009     rc = rpmRollback(rbts, ia, NULL);
02010 /*@=compmempass@*/
02011 
02012 cleanup: 
02013     /* Remove the file semaphore. */
02014     if (semfn && *semfn)
02015         xx = Unlink(semfn);
02016     semfn = _free(semfn);
02017 
02018     return rc;
02019 }
02020 /*@=nullpass@*/
02021 
02022 int _rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
02023 {
02024     int ourrc = -1;     /* assume failure */
02025     uint32_t totalFileCount = 0;
02026     rpmps ps;
02027     rpmsx sx = NULL;
02028     uint32_t numRemoved;
02029     int rollbackFailures = 0;
02030     void * lock = NULL;
02031     int xx;
02032 
02033 FPSDEBUG(0, (stderr, "--> %s(%p,%p,0x%x)\n", __FUNCTION__, ts, okProbs, ignoreSet));
02034 if (_rpmts_debug)
02035 fprintf(stderr, "--> %s(%p,%p,0x%x) tsFlags 0x%x\n", __FUNCTION__, ts, okProbs, (unsigned) ignoreSet, rpmtsFlags(ts));
02036 
02037     /* XXX programmer error segfault avoidance. */
02038     if (rpmtsNElements(ts) <= 0) {
02039         rpmlog(RPMLOG_ERR,
02040             _("Invalid number of transaction elements.\n"));
02041         return -1;
02042     }
02043 
02044     /* Don't acquire the transaction lock if testing. */
02045     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST))
02046         lock = rpmtsAcquireLock(ts);
02047 
02048     rollbackFailures = rpmExpandNumeric("%{?_rollback_transaction_on_failure}");
02049     /* Don't rollback unless repackaging. */
02050     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
02051         rollbackFailures = 0;
02052     /* Don't rollback if testing. */
02053     if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
02054         rollbackFailures = 0;
02055 
02056     if (rpmtsType(ts) & (RPMTRANS_TYPE_ROLLBACK | RPMTRANS_TYPE_AUTOROLLBACK))
02057         rollbackFailures = 0;
02058 
02059     /* ===============================================
02060      * Setup flags and such, open the rpmdb in O_RDWR mode.
02061      */
02062     sx = NULL;
02063     if (rpmtsSetup(ts, ignoreSet, &sx))
02064         goto exit;
02065 
02066     /* ===============================================
02067      * For packages being installed:
02068      * - verify package epoch:version-release is newer.
02069      * - count files.
02070      * For packages being removed:
02071      * - count files.
02072      */
02073 
02074     totalFileCount = 0;
02075     ps = rpmtsSanityCheck(ts, &totalFileCount);
02076     ps = rpmpsFree(ps);
02077 
02078     /* ===============================================
02079      * Run pre-transaction scripts, but only if no known problems exist.
02080      */
02081     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRETRANS) &&
02082        (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST))
02083           || (rpmpsNumProblems(ts->probs) &&
02084                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))))
02085     {
02086         rpmlog(RPMLOG_DEBUG, D_("running pre-transaction scripts\n"));
02087         xx = rpmtsRunScript(ts, RPMTAG_PRETRANS);
02088     }
02089 
02090     /* ===============================================
02091      * Compute file disposition for each package in transaction set.
02092      */
02093     numRemoved = 0;
02094     if (rpmtsPrepare(ts, sx, totalFileCount, &numRemoved))
02095         goto exit;
02096 
02097     /* ===============================================
02098      * If unfiltered problems exist, free memory and return.
02099      */
02100     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
02101      || (rpmpsNumProblems(ts->probs) &&
02102                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
02103        )
02104     {
02105         lock = rpmtsFreeLock(lock);
02106         if (sx != NULL) sx = rpmsxFree(sx);
02107         return ts->orderCount;
02108     }
02109 
02110     /* ===============================================
02111      * Save removed files before erasing.
02112      */
02113     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
02114         xx = rpmtsRepackage(ts, numRemoved);
02115     }
02116 
02117 #ifdef  NOTYET
02118     xx = rpmtxnBegin(rpmtsGetRdb(ts), NULL, &ts->txn);
02119 #endif
02120 
02121     /* ===============================================
02122      * Install and remove packages.
02123      */
02124     ourrc = rpmtsProcess(ts, ignoreSet, rollbackFailures);
02125 
02126     /* ===============================================
02127      * Run post-transaction scripts unless disabled.
02128      */
02129     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTTRANS) &&
02130         !(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST))
02131     {
02132 
02133 #if defined(RPM_VENDOR_MANDRIVA)
02134         if ((rpmtsFlags(ts) & _noTransTriggers) != _noTransTriggers)
02135             rpmRunFileTriggers(rpmtsRootDir(ts));
02136 #endif
02137 
02138         rpmlog(RPMLOG_DEBUG, D_("running post-transaction scripts\n"));
02139         xx = rpmtsRunScript(ts, RPMTAG_POSTTRANS);
02140     }
02141 
02142 exit:
02143     xx = rpmtsFinish(ts, sx);
02144 
02145     lock = rpmtsFreeLock(lock);
02146 
02147     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
02148     if (ourrc) {
02149         if (ts->txn != NULL)
02150             xx = rpmtxnAbort(ts->txn);
02151         ts->txn = NULL;
02152         return -1;
02153     } else {
02154         if (ts->txn != NULL)
02155             xx = rpmtxnCommit(ts->txn);
02156         ts->txn = NULL;
02157         xx = rpmtxnCheckpoint(rpmtsGetRdb(ts));
02158         return 0;
02159     }
02160     /*@=nullstate@*/
02161 }
02162 
02163 int (*rpmtsRun) (rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
02164         = _rpmtsRun;