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