rpm 5.3.12
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  * @return              rpmmi sorted by (package, fileNum)
00897  */
00898 static
00899 rpmmi rpmtsFindBaseNamesInDB(rpmts ts, uint32_t fileCount)
00900         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00901         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00902 {
00903     rpmtsi pi;  rpmte p;
00904     rpmfi fi;
00905     rpmmi mi;
00906     int i, xx;
00907     const char * s;
00908     size_t ns;
00909     void * ptr;
00910     static rpmTag _tag = RPMTAG_BASENAMES;
00911     static double e = 1.0e-4;
00912     size_t m = 0;
00913     size_t k = 0;
00914     rpmbf bf;
00915 
00916 FPSDEBUG(0, (stderr, "--> %s(%p,%u)\n", __FUNCTION__, ts, (unsigned)fileCount));
00917     rpmbfParams(fileCount, e, &m, &k);
00918     bf = rpmbfNew(m, k, 0);
00919 
00920     mi = rpmmiInit(rpmtsGetRdb(ts), _tag, NULL, 0);
00921 
00922     pi = rpmtsiInit(ts);
00923     while ((p = rpmtsiNext(pi, 0)) != NULL) {
00924 
00925         (void) rpmdbCheckSignals();
00926 
00927         if ((fi = rpmteFI(p, _tag)) == NULL)
00928             continue;   /* XXX can't happen */
00929 
00930         ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, rpmtsiOc(pi),
00931                     ts->orderCount);
00932 
00933         /* Gather all installed headers with matching basename's. */
00934         fi = rpmfiInit(fi, 0);
00935         while ((i = rpmfiNext(fi)) >= 0) {
00936             s = rpmfiBN(fi);
00937             ns = strlen(s);
00938 
00939             if (ns == 0)        /* XXX "/" fixup */
00940                 /*@innercontinue@*/ continue;
00941             if (rpmbfChk(bf, s, ns))
00942                 /*@innercontinue@*/ continue;
00943 
00944             xx = rpmmiGrowBasename(mi, s);
00945 
00946             xx = rpmbfAdd(bf, s, ns);
00947          }
00948     }
00949     pi = rpmtsiFree(pi);
00950     bf = rpmbfFree(bf);
00951 
00952     (void) rpmmiSort(mi);
00953 
00954     return mi;
00955 }
00956 
00957 /* Check files in the transactions against the rpmdb
00958  * Lookup all files with the same basename in the rpmdb
00959  * and then check for matching finger prints
00960  * @param ts            transaction set
00961  * @param fpc           global finger print cache
00962  */
00963 static
00964 int rpmtsCheckInstalledFiles(rpmts ts, uint32_t fileCount,
00965                 hashTable ht, fingerPrintCache fpc)
00966         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00967         /*@modifies ts, fpc, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
00968 {
00969     HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
00970     rpmTagData BN = { .ptr = NULL };
00971     rpmTagData DN = { .ptr = NULL };
00972     rpmTagData DI = { .ptr = NULL };
00973     rpmTagData FSTATES = { .ptr = NULL };
00974     rpmuint32_t fc;
00975 
00976     rpmte p;
00977     rpmmi mi;
00978     Header h;
00979     rpmfi fi;
00980 
00981     const char * oldDir;
00982     int beingRemoved;
00983     rpmfi otherFi = NULL;
00984     unsigned int fileNum;
00985     int xx;
00986     int rc = 0;
00987 
00988 FPSDEBUG(0, (stderr, "--> %s(%p,%u,%p,%p)\n", __FUNCTION__, ts, (unsigned)fileCount, ht, fpc));
00989 
00990 rpmlog(RPMLOG_DEBUG, D_("computing file dispositions\n"));
00991 
00992     /* XXX fileCount == 0 installing src.rpm's */
00993     if (fileCount == 0)
00994         return rc;
00995 
00996     mi = rpmtsFindBaseNamesInDB(ts, fileCount);
00997 
00998     /* Loop over all packages from the rpmdb */
00999     while ((h = rpmmiNext(mi)) != NULL) {
01000         fingerPrint fp;
01001         uint32_t hdrNum = rpmmiInstance(mi);
01002         uint32_t tagNum = rpmmiBNTag(mi);
01003         int i;
01004         int j;
01005 
01006         /* Is this package being removed? */
01007         beingRemoved = 0;
01008         if (ts->removedPackages != NULL)
01009         for (j = 0; j < ts->numRemovedPackages; j++) {
01010             if (ts->removedPackages[j] != hdrNum)
01011                 /*@innercontinue@*/ continue;
01012             beingRemoved = 1;
01013             /*@innerbreak@*/ break;
01014         }
01015 
01016         he->tag = RPMTAG_BASENAMES;
01017         xx = headerGet(h, he, 0);
01018         BN.argv = (xx ? he->p.argv : NULL);
01019         fc = (xx ? he->c : 0);
01020 
01021         he->tag = RPMTAG_DIRNAMES;
01022         xx = headerGet(h, he, 0);
01023         DN.argv = (xx ? he->p.argv : NULL);
01024         he->tag = RPMTAG_DIRINDEXES;
01025         xx = headerGet(h, he, 0);
01026         DI.ui32p = (xx ? he->p.ui32p : NULL);
01027         he->tag = RPMTAG_FILESTATES;
01028         xx = headerGet(h, he, 0);
01029         FSTATES.ui8p = (xx ? he->p.ui8p : NULL);
01030 
01031         /* loop over all interesting files in that package */
01032         oldDir = NULL;
01033         for (i = 0; i < (int)fc; i++) {
01034             const char * baseName = BN.argv[i];
01035             rpmuint32_t baseKey = hashFunctionString(0, baseName, 0);
01036             int gotRecs;
01037             struct rpmffi_s ** recs;
01038             int numRecs;
01039             const char * dirName;
01040 
01041             /* Skip uninteresting basenames. */
01042             if (baseKey != tagNum)
01043                 /*@innercontinue@*/ continue;
01044             fileNum = i;
01045             dirName = DN.argv[DI.ui32p[fileNum]];
01046 
01047             /* lookup finger print for this file */
01048             if (dirName == oldDir) {
01049                 /* directory is the same as last round */
01050                 fp.baseName = baseName;
01051             } else {
01052                 fp = fpLookup(fpc, dirName, baseName, 1);
01053                 oldDir = dirName;
01054             }
01055 
01056             /* search for files in the transaction with same finger print */
01057             recs = NULL;
01058             numRecs = 0;
01059 #ifdef  REFERENCE
01060             gotRecs = rpmFpHashGetEntry(ht, &fp, &recs, &numRecs, NULL);
01061 #else   /* REFERENCE */
01062             gotRecs = (htGetEntry(ts->ht, &fp, &recs, &numRecs, NULL) == 0);
01063 #endif  /* REFERENCE */
01064 
01065             for (j = 0; j < numRecs && gotRecs; j++) {
01066                 p = recs[j]->p;
01067                 fi = rpmteFI(p, RPMTAG_BASENAMES);
01068 
01069                 /* Determine the fate of each file. */
01070                 switch (rpmteType(p)) {
01071                 case TR_ADDED:
01072                     if (otherFi == NULL) {
01073                         static int scareMem = 0;
01074                         otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, scareMem);
01075                     }
01076                     (void) rpmfiSetFX(fi, recs[j]->fileno);
01077                     (void) rpmfiSetFX(otherFi, fileNum);
01078                     xx = handleInstInstalledFile(ts, p, fi, h, otherFi, beingRemoved);
01079                     /*@switchbreak@*/ break;
01080                 case TR_REMOVED:
01081                     if (!beingRemoved) {
01082                         (void) rpmfiSetFX(fi, recs[j]->fileno);
01083 #ifdef  REFERENCE
01084                         if (*rpmtdGetChar(&ostates) == RPMFILE_STATE_NORMAL) {
01085                             rpmfs fs = rpmteGetFileStates(p);
01086                             rpmfsSetAction(fs, recs[j].fileno, FA_SKIP);
01087                         }
01088 #else
01089                         if (FSTATES.ui8p[fileNum] == RPMFILE_STATE_NORMAL)
01090                             fi->actions[recs[j]->fileno] = FA_SKIP;
01091 #endif
01092                     }
01093                     /*@switchbreak@*/ break;
01094                 }
01095             }
01096 
01097         }
01098 
01099         otherFi = rpmfiFree(otherFi);
01100         FSTATES.ptr = _free(FSTATES.ptr);
01101         DI.ptr = _free(DI.ptr);
01102         DN.ptr = _free(DN.ptr);
01103         BN.ptr = _free(BN.ptr);
01104     }
01105 
01106     mi = rpmmiFree(mi);
01107 
01108     return rc;
01109 }
01110 
01111 /*
01112  * For packages being installed:
01113  * - verify package arch/os.
01114  * - verify package epoch:version-release is newer.
01115  */
01116 static rpmps rpmtsSanityCheck(rpmts ts, uint32_t * tfcp)
01117         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01118         /*@modifies ts, *tfcp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01119 {
01120     rpmps ps;
01121     rpmtsi pi;
01122     rpmte p;
01123     rpmfi fi;
01124     uint32_t totalFileCount = 0;
01125     int fc;
01126 
01127 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, tfcp));
01128 rpmlog(RPMLOG_DEBUG, D_("sanity checking %d elements\n"), rpmtsNElements(ts));
01129     ps = rpmtsProblems(ts);
01130     /* The ordering doesn't matter here */
01131     pi = rpmtsiInit(ts);
01132     /* XXX Only added packages need be checked. */
01133     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01134         int xx;
01135 
01136         if (p->isSource) continue;
01137         if ((fi = rpmtsiFi(pi)) == NULL)
01138             continue;   /* XXX can't happen */
01139         fc = rpmfiFC(fi);
01140 
01141 #ifdef  REFERENCE
01142         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREARCH))
01143             if (!archOkay(rpmteA(p)))
01144                 rpmpsAppend(ps, RPMPROB_BADARCH,
01145                         rpmteNEVRA(p), rpmteKey(p),
01146                         rpmteA(p), NULL,
01147                         NULL, 0);
01148 
01149         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_IGNOREOS))
01150             if (!osOkay(rpmteO(p)))
01151                 rpmpsAppend(ps, RPMPROB_BADOS,
01152                         rpmteNEVRA(p), rpmteKey(p),
01153                         rpmteO(p), NULL,
01154                         NULL, 0);
01155 #endif  /* REFERENCE */
01156 
01157         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_OLDPACKAGE)) {
01158             rpmmi mi = rpmtsInitIterator(ts, RPMTAG_NAME, rpmteN(p), 0);
01159             Header h;
01160             while ((h = rpmmiNext(mi)) != NULL)
01161                 xx = ensureOlder(ts, p, h);
01162             mi = rpmmiFree(mi);
01163         }
01164 
01165         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEPKG)) {
01166             ARGV_t keys = NULL;
01167             int nkeys;
01168             xx = rpmdbMireApply(rpmtsGetRdb(ts), RPMTAG_NVRA,
01169                 RPMMIRE_STRCMP, rpmteNEVRA(p), &keys);
01170             nkeys = argvCount(keys);
01171 
01172 #if defined(RPM_VENDOR_MANDRIVA)
01173             /* mdvbz: #63711
01174              * workaround for distepoch never being added to RPMTAG_NVRA yet,
01175              * leading to packages of same EVRA but with different distepoch
01176              * being treated as the same package */
01177             if (nkeys > 0) {
01178                 int i;
01179                 for (i = 0; i < nkeys; i++) {
01180                     rpmmi mi = rpmtsInitIterator(ts, RPMTAG_NVRA, keys[i], 0);
01181                     Header h;
01182                     while ((h = rpmmiNext(mi)) != NULL) {
01183                         HE_t he = memset(alloca(sizeof(*he)), 0, sizeof(*he));
01184                         he->tag = RPMTAG_DISTEPOCH;
01185                         xx = headerGet(h, he, 0);
01186                         if (strcmp(he->p.str ? he->p.str : "", rpmteD(p) ? rpmteD(p) : ""))
01187                             nkeys--;
01188                         he->p.ptr = _free(he->p.ptr);
01189                     }
01190                     mi = rpmmiFree(mi);
01191                 }
01192             }
01193 #endif
01194             if (nkeys > 0)
01195                 rpmpsAppend(ps, RPMPROB_PKG_INSTALLED,
01196                         rpmteNEVR(p), rpmteKey(p),
01197                         NULL, NULL,
01198                         NULL, 0);
01199             keys = argvFree(keys);
01200         }
01201 
01202 #ifdef  REFERENCE
01203         /* XXX rpmte problems can only be relocation problems atm */
01204         if (!(rpmtsFilterFlags(ts) & RPMPROB_FILTER_FORCERELOCATE)) {
01205             rpmpsi psi = rpmpsInitIterator(rpmteProblems(p));
01206             while (rpmpsNextIterator(psi) >= 0) {
01207                 rpmpsAppendProblem(ps, rpmpsGetProblem(psi));
01208             }
01209             rpmpsFreeIterator(psi);
01210         }
01211 #endif  /* REFERENCE */
01212 
01213         /* Count no. of files (if any). */
01214         totalFileCount += fc;
01215 
01216     }
01217     pi = rpmtsiFree(pi);
01218 
01219     /* The ordering doesn't matter here */
01220     pi = rpmtsiInit(ts);
01221     while ((p = rpmtsiNext(pi, TR_REMOVED)) != NULL) {
01222 
01223         if (p->isSource) continue;
01224         if ((fi = rpmtsiFi(pi)) == NULL)
01225             continue;   /* XXX can't happen */
01226         fc = rpmfiFC(fi);
01227 
01228         totalFileCount += fc;
01229     }
01230     pi = rpmtsiFree(pi);
01231 
01232     if (tfcp)
01233         *tfcp = totalFileCount;
01234 
01235     return ps;
01236 }
01237 
01238 /*
01239  * Run pre/post transaction script.
01240  * param ts     transaction set
01241  * param stag   RPMTAG_PRETRANS or RPMTAG_POSTTRANS
01242  * return       0 on success
01243  */
01244 static int rpmtsRunScript(rpmts ts, rpmTag stag) 
01245         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01246         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01247 {
01248     rpmtsi pi; 
01249     rpmte p;
01250     rpmfi fi;
01251     rpmpsm psm;
01252     int xx;
01253     rpmTag ptag;
01254 
01255 FPSDEBUG(0, (stderr, "--> %s(%p,%s(%u))\n", __FUNCTION__, ts, tagName(stag), (unsigned)stag));
01256     switch (stag) {
01257     default:
01258 assert(0);
01259         /*@notreached@*/ break;
01260     case RPMTAG_PRETRANS:       ptag = RPMTAG_PRETRANSPROG;     break;
01261     case RPMTAG_POSTTRANS:      ptag = RPMTAG_POSTTRANSPROG;    break;
01262     }
01263 
01264     pi = rpmtsiInit(ts);
01265     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01266         if (p->isSource) continue;
01267         if ((fi = rpmtsiFi(pi)) == NULL)
01268             continue;   /* XXX can't happen */
01269 
01270         /* If no prre/post transaction script, then don't bother. */
01271         if (!rpmteHaveTransScript(p, stag))
01272             continue;
01273 
01274         if (rpmteOpen(p, ts, 0)) {
01275             if (p->fi != NULL)  /* XXX can't happen */
01276                 p->fi->te = p;
01277 #ifdef  REFERENCE
01278             psm = rpmpsmNew(ts, p);
01279 #else   /* REFERENCE */
01280             psm = rpmpsmNew(ts, p, p->fi);
01281 #endif  /* REFERENCE */
01282             xx = rpmpsmScriptStage(psm, stag, ptag);
01283             psm = rpmpsmFree(psm, __FUNCTION__);
01284             xx = rpmteClose(p, ts, 0);
01285         }
01286     }
01287     pi = rpmtsiFree(pi);
01288 
01289     return 0;
01290 }
01291 
01292 /* Add fingerprint for each file not skipped. */
01293 static void rpmtsAddFingerprints(rpmts ts, uint32_t fileCount, hashTable ht,
01294                 fingerPrintCache fpc)
01295         /*@modifies ts, fpc @*/
01296 {
01297     rpmtsi pi;
01298     rpmte p;
01299     rpmfi fi;
01300     int i;
01301 
01302     hashTable symlinks = htCreate(fileCount/16+16, 0, 0, fpHashFunction, fpEqual);
01303 
01304 FPSDEBUG(0, (stderr, "--> %s(%p,%u,%p,%p)\n", __FUNCTION__, ts, (unsigned)fileCount, ht, fpc));
01305     pi = rpmtsiInit(ts);
01306     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01307         (void) rpmdbCheckSignals();
01308 
01309         if (p->isSource) continue;
01310         if ((fi = rpmtsiFi(pi)) == NULL)
01311             continue;   /* XXX can't happen */
01312 
01313         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01314 
01315         rpmfiFpLookup(fi, fpc);
01316 
01317         /* Collect symlinks. */
01318         fi = rpmfiInit(fi, 0);
01319         if (fi != NULL)         /* XXX lclint */
01320         while ((i = rpmfiNext(fi)) >= 0) {
01321             char const *linktarget;
01322             linktarget = rpmfiFLink(fi);
01323             if (!(linktarget && *linktarget != '\0'))
01324                 /*@innercontinue@*/ continue;
01325             if (iosmFileActionSkipped(fi->actions[i]))
01326                 /*@innercontinue@*/ continue;
01327 #ifdef  REFERENCE
01328             {   struct rpmffi_s ffi;
01329                 ffi.p = p;
01330                 ffi.fileno = i;
01331                 htAddEntry(symlinks, rpmfiFpsIndex(fi, i), ffi);
01332             }
01333 #else
01334             {   struct rpmffi_s *ffip = alloca(sizeof(*ffip));
01335 /*@-dependenttrans@*/
01336                 ffip->p = p;
01337 /*@=dependenttrans@*/
01338                 ffip->fileno = i;
01339                 htAddEntry(symlinks, fi->fps + i, (void *) ffip);
01340             }
01341 #endif
01342         }
01343 
01344         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
01345 
01346     }
01347     pi = rpmtsiFree(pi);
01348 
01349     /* ===============================================
01350      * Check fingerprints if they contain symlinks
01351      * and add them to the hash table
01352      */
01353 
01354     pi = rpmtsiInit(ts);
01355     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01356         (void) rpmdbCheckSignals();
01357 
01358         if (p->isSource) continue;
01359         if ((fi = rpmteFI(p, RPMTAG_BASENAMES)) == NULL)
01360             continue;   /* XXX can't happen */
01361         fi = rpmfiInit(fi, 0);
01362         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01363         while ((i = rpmfiNext(fi)) >= 0) {
01364 #ifdef  REFERENCE
01365             if (XFA_SKIPPING(rpmfsGetAction(rpmteGetFileStates(p), i)))
01366                 continue;
01367 #else
01368             if (iosmFileActionSkipped(fi->actions[i]))
01369                 /*@innercontinue@*/ continue;
01370 #endif
01371             fpLookupSubdir(symlinks, ht, fpc, p, i);
01372         }
01373         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01374     }
01375     pi = rpmtsiFree(pi);
01376 
01377     symlinks = htFree(symlinks);
01378 
01379 }
01380 
01381 static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet, rpmsx * sxp)
01382         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01383         /*@modifies ts, *sxp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01384 {
01385     int xx;
01386 
01387 /*@+voidabstract@*/
01388 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%p)\n", __FUNCTION__, ts, ignoreSet, (void *)sxp));
01389 /*@=voidabstract@*/
01390     /* --noscripts implies no scripts or triggers, duh. */
01391     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOSCRIPTS)
01392         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01393     /* --notriggers implies no triggers, duh. */
01394     if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERS)
01395         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers));
01396 
01397     /* --justdb implies no scripts or triggers, duh. */
01398     if (rpmtsFlags(ts) & RPMTRANS_FLAG_JUSTDB)
01399         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers));
01400 
01401     /* if SELinux isn't enabled or init fails, don't bother... */
01402     if (!rpmtsSELinuxEnabled(ts))
01403         (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY)));
01404 
01405     if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY))) {
01406         *sxp = rpmsxNew("%{?_install_file_context_path}", 0);
01407         if (*sxp == NULL)
01408             (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | (RPMTRANS_FLAG_NOCONTEXTS|RPMTRANS_FLAG_NOPOLICY)));
01409     } else
01410         *sxp = NULL;
01411 
01412     /* XXX Make sure the database is open RDWR for package install/erase. */
01413     {   int dbmode = O_RDONLY;
01414 
01415         if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
01416             rpmtsi pi;
01417             rpmte p;
01418             pi = rpmtsiInit(ts);
01419             while ((p = rpmtsiNext(pi, 0)) != NULL) {
01420                 if (p->isSource) continue;
01421                 dbmode = (O_RDWR|O_CREAT);
01422                 break;
01423             }
01424             pi = rpmtsiFree(pi);
01425         }
01426 
01427         /* Open database RDWR for installing packages. */
01428         if (rpmtsOpenDB(ts, dbmode))
01429             return -1;  /* XXX W2DO? */
01430 
01431     }
01432 
01433     ts->ignoreSet = ignoreSet;
01434     ts->probs = rpmpsFree(ts->probs);
01435 
01436     {   const char * currDir = currentDirectory();
01437         rpmtsSetCurrDir(ts, currDir);
01438         currDir = _free(currDir);
01439     }
01440 
01441     (void) rpmtsSetChrootDone(ts, 0);
01442 
01443     /* XXX rpmtsCreate() sets the transaction id, but apps may not honor. */
01444     {   rpmuint32_t tid = (rpmuint32_t) time(NULL);
01445         (void) rpmtsSetTid(ts, tid);
01446     }
01447 
01448     /* Get available space on mounted file systems. */
01449     xx = rpmtsInitDSI(ts);
01450 
01451     return 0;
01452 }
01453 
01454 static int rpmtsFinish(rpmts ts, /*@only@*/ rpmsx sx)
01455         /*@modifies sx @*/
01456 {
01457 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, sx));
01458 #ifdef  REFERENCE
01459     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) {
01460         matchpathcon_fini();
01461     }
01462 #else   /* REFERENCE */
01463     if (sx != NULL) sx = rpmsxFree(sx);
01464 #endif  /* REFERENCE */
01465     return 0;
01466 }
01467 
01468 static int rpmtsPrepare(rpmts ts, rpmsx sx, uint32_t fileCount,
01469                 uint32_t * nrmvdp)
01470         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01471         /*@modifies ts, *nrmvdp, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01472 {
01473     rpmtsi pi;
01474     rpmte p;
01475     fingerPrintCache fpc;
01476     rpmfi fi;
01477     int xx;
01478     int rc = 0;
01479 
01480 #ifdef  REFERENCE
01481     uint64_t fileCount = countFiles(ts);
01482     const char * rootDir = rpmtsRootDir(ts);
01483     int dochroot = (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/');
01484 
01485     rpmFpHash ht = rpmFpHashCreate(fileCount/2+1, fpHashFunction, fpEqual,
01486                              NULL, NULL);
01487 
01488     fpc = fpCacheCreate(fileCount/2 + 10001);
01489 
01490     rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount);
01491 
01492     /* Skip netshared paths, not our i18n files, and excluded docs */
01493     pi = rpmtsiInit(ts);
01494     while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
01495         if ((fi = rpmteFI(p)) == NULL)
01496             continue;   /* XXX can't happen */
01497 
01498         if (rpmfiFC(fi) > 0) 
01499             rpmtsSkipFiles(ts, p);
01500     }
01501     pi = rpmtsiFree(pi);
01502 
01503     /* Enter chroot for fingerprinting if necessary */
01504     if (!rpmtsChrootDone(ts)) {
01505         xx = chdir("/");
01506         if (dochroot) {
01507             /* opening db before chroot not optimal, see rhbz#103852 c#3 */
01508             xx = rpmdbOpenAll(ts->rdb);
01509             if (chroot(rootDir) == -1) {
01510                 rpmlog(RPMLOG_ERR, _("Unable to change root directory: %m\n"));
01511                 rc = -1;
01512                 goto exit;
01513             }
01514         }
01515         (void) rpmtsSetChrootDone(ts, 1);
01516     }
01517     
01518 #else   /* REFERENCE */
01519 
01520     void * ptr;
01521     uint32_t numAdded = 0;
01522     uint32_t numRemoved = 0;
01523 
01524 FPSDEBUG(0, (stderr, "--> %s(%p,%p,%u,%p)\n", __FUNCTION__, ts, sx, (unsigned)fileCount, nrmvdp));
01525 rpmlog(RPMLOG_DEBUG, D_("computing %u file fingerprints\n"), (unsigned)fileCount);
01526 
01527     pi = rpmtsiInit(ts);
01528     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01529         int fc;
01530 
01531         if (p->isSource) continue;
01532         if ((fi = rpmtsiFi(pi)) == NULL)
01533             continue;   /* XXX can't happen */
01534         fc = rpmfiFC(fi);
01535 
01536         switch (rpmteType(p)) {
01537         case TR_ADDED:
01538             numAdded++;
01539             fi->record = 0;
01540             /* Skip netshared paths, not our i18n files, and excluded docs */
01541             if (fc > 0)
01542                 rpmtsSkipFiles(ts, fi);
01543             /*@switchbreak@*/ break;
01544         case TR_REMOVED:
01545             numRemoved++;
01546             fi->record = rpmteDBOffset(p);
01547             /*@switchbreak@*/ break;
01548         }
01549 
01550         fi->fps = (fc > 0 ? xmalloc(fc * sizeof(*fi->fps)) : NULL);
01551     }
01552     pi = rpmtsiFree(pi);
01553 
01554     if (nrmvdp)
01555         *nrmvdp = numRemoved;
01556 
01557     if (!rpmtsChrootDone(ts)) {
01558         const char * rootDir = rpmtsRootDir(ts);
01559         static int openall_before_chroot = -1;
01560 
01561         if (openall_before_chroot < 0)
01562             openall_before_chroot = rpmExpandNumeric("%{?_openall_before_chroot}");
01563 
01564         xx = Chdir("/");
01565         /*@-modobserver@*/
01566         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/') {
01567             if (openall_before_chroot)
01568                 xx = rpmdbOpenAll(rpmtsGetRdb(ts));
01569             xx = Chroot(rootDir);
01570         }
01571         /*@=modobserver@*/
01572         (void) rpmtsSetChrootDone(ts, 1);
01573     }
01574 
01575     ts->ht = htCreate(fileCount/2 + 1, 0, 1, fpHashFunction, fpEqual);
01576     fpc = fpCacheCreate(fileCount/2 + 10001);
01577 
01578 #endif  /* REFERENCE */
01579 
01580     ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_START, 6, ts->orderCount);
01581 
01582     /* ===============================================
01583      * Add fingerprint for each file not skipped.
01584      */
01585 #ifdef  REFERENCE
01586     rpmtsAddFingerprints(ts, fileCount, ht, fpc);
01587 #else   /* REFERENCE */
01588     rpmtsAddFingerprints(ts, fileCount, ts->ht, fpc);
01589 #endif  /* REFERENCE */
01590 
01591     /* ===============================================
01592      * Compute file disposition for each package in transaction set.
01593      */
01594 #ifdef  REFERENCE
01595     rpmtsCheckInstalledFiles(ts, fileCount, ht, fpc);
01596 #else   /* REFERENCE */
01597     rc = rpmtsCheckInstalledFiles(ts, fileCount, ts->ht, fpc);
01598     if (rc)
01599         goto exit;
01600 #endif  /* REFERENCE */
01601 
01602     pi = rpmtsiInit(ts);
01603     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01604         if ((fi = rpmteFI(p, RPMTAG_BASENAMES)) == NULL)
01605             continue;   /* XXX can't happen */
01606         /* XXX Set all SRPM files to FA_CREATE. */
01607         if (p->isSource) {
01608             int i;
01609             fi = rpmfiInit(fi, 0);
01610             if (fi != NULL)
01611             while ((i = rpmfiNext(fi)) >= 0)
01612                 fi->actions[i] = FA_CREATE;
01613             continue;
01614         }
01615 
01616         (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0);
01617 
01618         /* Update disk space needs on each partition for this package. */
01619 /*@-nullpass@*/
01620 #ifdef  REFERENCE
01621         handleOverlappedFiles(ts, ht, p, fi);
01622 #else   /* REFERENCE */
01623         handleOverlappedFiles(ts, p, fi);
01624 #endif  /* REFERENCE */
01625 /*@=nullpass@*/
01626 
01627         /* Check added package has sufficient space on each partition used. */
01628         switch (rpmteType(p)) {
01629         case TR_ADDED:
01630             rpmtsCheckDSIProblems(ts, p);
01631             /*@switchbreak@*/ break;
01632         case TR_REMOVED:
01633             /*@switchbreak@*/ break;
01634         }
01635         (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), rpmfiFC(fi));
01636     }
01637     pi = rpmtsiFree(pi);
01638 
01639     if (rpmtsChrootDone(ts)) {
01640         const char * rootDir = rpmtsRootDir(ts);
01641         const char * currDir = rpmtsCurrDir(ts);
01642         /*@-modobserver@*/
01643         if (rootDir != NULL && strcmp(rootDir, "/") && *rootDir == '/')
01644             xx = Chroot(".");
01645         /*@=modobserver@*/
01646         (void) rpmtsSetChrootDone(ts, 0);
01647         if (currDir != NULL)
01648             xx = Chdir(currDir);
01649     }
01650 
01651     ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, ts->orderCount);
01652 
01653     /* ===============================================
01654      * Free unused memory as soon as possible.
01655      */
01656 #ifdef  REFERENCE
01657     pi = rpmtsiInit(ts);
01658     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01659         rpmteSetFI(p, NULL);
01660     }
01661     pi = rpmtsiFree(pi);
01662 #else   /* REFERENCE */
01663     pi = rpmtsiInit(ts);
01664     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01665         if (p->isSource) continue;
01666         if ((fi = rpmtsiFi(pi)) == NULL)
01667             continue;   /* XXX can't happen */
01668         if (rpmfiFC(fi) == 0)
01669             continue;
01670         fi->fps = _free(fi->fps);
01671     }
01672     pi = rpmtsiFree(pi);
01673 #endif  /* REFERENCE */
01674 
01675 exit:
01676 #ifdef  REFERENCE
01677     ht = rpmFpHashFree(ht);
01678 #else   /* REFERENCE */
01679     ts->ht = htFree(ts->ht);
01680 #endif  /* REFERENCE */
01681     fpc = fpCacheFree(fpc);
01682 
01683     return rc;
01684 }
01685 
01686 /*
01687  * Transaction main loop: install and remove packages
01688  */
01689 static int rpmtsProcess(rpmts ts, rpmprobFilterFlags ignoreSet,
01690                 int rollbackFailures)
01691         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01692         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01693 {
01694     rpmtsi pi;
01695     rpmte p;
01696     int rc = 0;
01697 
01698 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%d)\n", __FUNCTION__, ts, ignoreSet, rollbackFailures));
01699     pi = rpmtsiInit(ts);
01700     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01701         rpmfi fi;
01702         rpmop sw;
01703         rpmpsm psm = NULL;
01704         pkgStage stage = PSM_UNKNOWN;
01705         int failed;
01706         int gotfd;
01707         int xx;
01708 
01709 #ifdef  REFERENCE
01710         rpmElementType tetype = rpmteType(p);
01711         rpmtsOpX op = (tetype == TR_ADDED) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
01712 #endif  /* REFERENCE */
01713 
01714         (void) rpmdbCheckSignals();
01715 
01716         failed = 1;
01717         gotfd = 0;
01718         if ((fi = rpmtsiFi(pi)) == NULL)
01719             continue;   /* XXX can't happen */
01720         
01721         if (rpmteFailed(p)) {
01722             /* XXX this should be a warning, need a better message though */
01723             rpmlog(RPMLOG_DEBUG, D_("element %s marked as failed, skipping\n"),
01724                                         rpmteNEVRA(p));
01725             rc++;
01726             continue;
01727         }
01728 
01729         psm = rpmpsmNew(ts, p, fi);
01730         {   int async = (rpmtsiOc(pi) >= rpmtsUnorderedSuccessors(ts, -1)) ? 
01731                         1 : 0;
01732             rpmpsmSetAsync(psm, async);
01733         }
01734 
01735         switch (rpmteType(p)) {
01736         case TR_ADDED:
01737             rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
01738                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01739             stage = PSM_PKGINSTALL;
01740             sw = rpmtsOp(ts, RPMTS_OP_INSTALL);
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             if ((p->h = rpmteFDHeader(ts, p)) != NULL)
01750                 gotfd = 1;
01751 
01752             if (gotfd && rpmteFd(p) != NULL) {
01753                 /*
01754                  * XXX Sludge necessary to transfer existing fstates/actions
01755                  * XXX around a recreated file info set.
01756                  */
01757                 rpmuint8_t * fstates = fi->fstates;
01758                 iosmFileAction * actions = (iosmFileAction *) fi->actions;
01759                 int mapflags = fi->mapflags;
01760                 rpmte savep;
01761                 int scareMem = 0;
01762 
01763                 psm->fi = rpmfiFree(psm->fi);
01764 
01765                 fi->fstates = NULL;
01766                 fi->actions = NULL;
01767 /*@-nullstate@*/ /* FIX: fi->actions is NULL */
01768                 fi = rpmfiFree(fi);
01769 /*@=nullstate@*/
01770 
01771                 savep = rpmtsSetRelocateElement(ts, p);
01772                 fi = rpmfiNew(ts, p->h, RPMTAG_BASENAMES, scareMem);
01773                 (void) rpmtsSetRelocateElement(ts, savep);
01774 
01775                 if (fi != NULL) {       /* XXX can't happen */
01776                     fi->te = p;
01777                     fi->fstates = _free(fi->fstates);
01778                     fi->fstates = fstates;
01779                     fi->actions = _free(fi->actions);
01780                     fi->actions = (int *) actions;
01781                     if (mapflags & IOSM_SBIT_CHECK)
01782                         fi->mapflags |= IOSM_SBIT_CHECK;
01783                     p->fi = fi;
01784                 }
01785 
01786                 psm->fi = rpmfiLink(p->fi, __FUNCTION__);
01787 
01788                 (void) rpmswEnter(sw, 0);
01789                 failed = (rpmpsmStage(psm, stage) != RPMRC_OK);
01790                 (void) rpmswExit(sw, 0);
01791 
01792                 xx = rpmteClose(p, ts, 0);
01793                 gotfd = 0;
01794             }
01795 
01796 #endif  /* REFERENCE */
01797             /*@switchbreak@*/ break;
01798 
01799         case TR_REMOVED:
01800             rpmlog(RPMLOG_DEBUG, "========== --- %s %s-%s 0x%x\n",
01801                 rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
01802             stage = PSM_PKGERASE;
01803             sw = rpmtsOp(ts, RPMTS_OP_ERASE);
01804 #ifdef  REFERENCE
01805             if (rpmteOpen(p, ts, 1)) {
01806                 (void) rpmswEnter(rpmtsOp(ts, op), 0);
01807                 failed = rpmpsmStage(psm, stage);
01808                 (void) rpmswExit(rpmtsOp(ts, op), 0);
01809                 rpmteClose(p, ts, 1);
01810             }
01811 #else   /* REFERENCE */
01812             (void) rpmswEnter(sw, 0);
01813             failed = (rpmpsmStage(psm, stage) != RPMRC_OK);
01814             (void) rpmswExit(sw, 0);
01815 #endif  /* REFERENCE */
01816             /*@switchbreak@*/ break;
01817         }
01818 
01819 #if defined(RPM_VENDOR_MANDRIVA)
01820         if (!failed && !(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) {
01821             if(!rpmteIsSource(p))
01822                 xx = mayAddToFilesAwaitingFiletriggers(rpmtsRootDir(ts),
01823                                 fi, (rpmteType(p) == TR_ADDED ? 1 : 0));
01824             p->done = 1;
01825         }
01826 #endif
01827 
01828 /*@-nullstate@*/ /* FIX: psm->fi may be NULL */
01829         psm = rpmpsmFree(psm, __FUNCTION__);
01830 /*@=nullstate@*/
01831 
01832         if (failed) {
01833             rc++;
01834 #ifdef  REFERENCE
01835             rpmteMarkFailed(p, ts);
01836 #else   /* REFERENCE */
01837             xx = rpmtsMarkLinkedFailed(ts, p);
01838         /* If we received an error, lets break out and rollback, provided
01839          * autorollback is enabled.
01840          */
01841             if (rollbackFailures) {
01842                 xx = rpmtsRollback(ts, ignoreSet, 1, p);
01843                 break;
01844             }
01845 #endif  /* REFERENCE */
01846         }
01847 
01848         if (p->h != NULL) {
01849             (void) headerFree(p->h);
01850             p->h = NULL;
01851         }
01852 
01853 #ifdef  REFERENCE
01854         (void) rpmdbSync(rpmtsGetRdb(ts));
01855 #endif  /* REFERENCE */
01856 
01857     }
01858     pi = rpmtsiFree(pi);
01859     return rc;
01860 }
01861 
01862 /* ================================================================= */
01863 static int rpmtsRepackage(rpmts ts, uint32_t numRemoved)
01864         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01865         /*@modifies ts, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01866 {
01867     rpmpsm psm;
01868     rpmfi fi;
01869     rpmtsi pi;
01870     rpmte p;
01871     void * ptr;
01872     int progress = 0;
01873     int rc = 0;
01874     int xx;
01875 
01876 FPSDEBUG(0, (stderr, "--> %s(%p,%u)\n", __FUNCTION__, ts, (unsigned)numRemoved));
01877     pi = rpmtsiInit(ts);
01878     while ((p = rpmtsiNext(pi, 0)) != NULL) {
01879 
01880         (void) rpmdbCheckSignals();
01881 
01882         if (p->isSource) continue;
01883         if ((fi = rpmtsiFi(pi)) == NULL)
01884             continue;   /* XXX can't happen */
01885         switch (rpmteType(p)) {
01886         case TR_ADDED:
01887             /*@switchbreak@*/ break;
01888         case TR_REMOVED:
01889             if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
01890                 /*@switchbreak@*/ break;
01891             if (!progress)
01892                 ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_START,
01893                                 7, numRemoved);
01894 
01895             ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_PROGRESS,
01896                                 progress, numRemoved);
01897             progress++;
01898 
01899             (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01900 
01901         /* XXX TR_REMOVED needs IOSM_MAP_{ABSOLUTE,ADDDOT} IOSM_ALL_HARDLINKS */
01902             fi->mapflags |= IOSM_MAP_ABSOLUTE;
01903             fi->mapflags |= IOSM_MAP_ADDDOT;
01904             fi->mapflags |= IOSM_ALL_HARDLINKS;
01905             psm = rpmpsmNew(ts, p, fi);
01906 assert(psm != NULL);
01907             xx = rpmpsmStage(psm, PSM_PKGSAVE);
01908             psm = rpmpsmFree(psm, __FUNCTION__);
01909             fi->mapflags &= ~IOSM_MAP_ABSOLUTE;
01910             fi->mapflags &= ~IOSM_MAP_ADDDOT;
01911             fi->mapflags &= ~IOSM_ALL_HARDLINKS;
01912 
01913             (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_REPACKAGE), 0);
01914 
01915             /*@switchbreak@*/ break;
01916         }
01917     }
01918     pi = rpmtsiFree(pi);
01919     if (progress)
01920         ptr = rpmtsNotify(ts, NULL, RPMCALLBACK_REPACKAGE_STOP, 7, numRemoved);
01921 
01922     return rc;
01923 }
01924 
01931 /*@-nullpass@*/
01932 static rpmRC _processFailedPackage(rpmts ts, rpmte p)
01933         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01934         /*@modifies ts, p, rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01935 {
01936     int rc  = RPMRC_OK; /* assume success */
01937 
01938 FPSDEBUG(0, (stderr, "--> %s(%p,%p)\n", __FUNCTION__, ts, p));
01939     /* Handle failed packages. */
01940     /* XXX TODO: Add header to rpmdb in PSM_INIT, not PSM_POST. */
01941     if (p != NULL && rpmteType(p) == TR_ADDED && !p->installed) {
01942 /*@-compdef -usereleased@*/     /* p->fi->te undefined */
01943         rpmpsm psm = rpmpsmNew(ts, p, p->fi);
01944 /*@=compdef =usereleased@*/
01945         /*
01946          * If it died before the header was put in the rpmdb, we need
01947          * do to something wacky which is add the header to the DB anyway.
01948          * This will allow us to add the failed package as an erase
01949          * to the rollback transaction.  This must be done because we
01950          * want the the erase scriptlets to run, and the only way that
01951          * is going is if the header is in the rpmdb.
01952          */
01953 assert(psm != NULL);
01954         psm->stepName = "failed";       /* XXX W2DO? */
01955         rc = rpmpsmStage(psm, PSM_RPMDB_ADD);
01956         psm = rpmpsmFree(psm, __FUNCTION__);
01957     }
01958     return rc;
01959 }
01960 /*@=nullpass@*/
01961 
01962 /*@-nullpass@*/
01963 rpmRC rpmtsRollback(rpmts rbts, rpmprobFilterFlags ignoreSet, int running, rpmte rbte)
01964         /*@globals rpmGlobalMacroContext, h_errno, fileSystem, internalState @*/
01965         /*@modifies rbts, rpmGlobalMacroContext, fileSystem, internalState @*/
01966 {
01967     const char * semfn = NULL;
01968     rpmRC rc = 0;
01969     rpmuint32_t arbgoal = rpmtsARBGoal(rbts);
01970     QVA_t ia = memset(alloca(sizeof(*ia)), 0, sizeof(*ia));
01971     time_t ttid;
01972     int xx;
01973 
01974 FPSDEBUG(0, (stderr, "--> %s(%p,0x%x,%d,%p)\n", __FUNCTION__, rbts, ignoreSet, running, rbte));
01975     /* Don't attempt rollback's of rollback transactions */
01976     if ((rpmtsType(rbts) & RPMTRANS_TYPE_ROLLBACK) ||
01977         (rpmtsType(rbts) & RPMTRANS_TYPE_AUTOROLLBACK))
01978         return RPMRC_OK;
01979 
01980     if (arbgoal == 0xffffffff) 
01981         arbgoal = rpmtsGetTid(rbts);
01982 
01983     /* Don't attempt rollbacks if no goal is set. */
01984     if (!running && arbgoal == 0xffffffff)
01985         return RPMRC_OK;
01986 
01987     /* We need to remove an headers that were going to be removed so 
01988      * as to not foul up the regular rollback mechanism which will not 
01989      * handle properly a file being in the repackaged package directory
01990      * and also its header still in the DB.
01991      */
01992     {   rpmtsi tsi;
01993         rpmte te;
01994 
01995         /* XXX Insure an O_RDWR rpmdb. */
01996         xx = rpmtsOpenDB(rbts, O_RDWR);
01997 
01998         tsi = rpmtsiInit(rbts);
01999         while((te = rpmtsiNext(tsi, TR_REMOVED)) != NULL) {
02000             if (te->isSource) continue;
02001             if(!te->u.removed.dboffset)
02002                 continue;
02003             rc = rpmdbRemove(rpmtsGetRdb(rbts),
02004                         rpmtsGetTid(rbts),
02005                         te->u.removed.dboffset, NULL);
02006             if (rc != RPMRC_OK) {
02007                 rpmlog(RPMLOG_ERR, _("rpmdb erase failed. NEVRA: %s\n"),
02008                         rpmteNEVRA(te));
02009                 break;
02010             }
02011         }
02012         tsi = rpmtsiFree(tsi);
02013         if (rc != RPMRC_OK) 
02014             goto cleanup;
02015     }
02016 
02017     /* Process the failed package */
02018     rc = _processFailedPackage(rbts, rbte);
02019     if (rc != RPMRC_OK)
02020         goto cleanup;
02021 
02022     rpmtsEmpty(rbts);
02023 
02024     ttid = (time_t)arbgoal;
02025     rpmlog(RPMLOG_NOTICE, _("Rollback to %-24.24s (0x%08x)\n"),
02026         ctime(&ttid), arbgoal);
02027 
02028     /* Set the verify signature flags:
02029      *  - can't verify signatures/digests on repackaged packages.
02030      *  - header check are out.
02031      */
02032     {
02033         rpmVSFlags vsflags = rpmExpandNumeric("%{?_vsflags_erase}");
02034         vsflags |= _RPMVSF_NODIGESTS;
02035         vsflags |= _RPMVSF_NOSIGNATURES;
02036         vsflags |= RPMVSF_NOHDRCHK;
02037         vsflags |= RPMVSF_NEEDPAYLOAD;      
02038         xx = rpmtsSetVSFlags(rbts, vsflags); 
02039     }
02040 
02041     /* Set transaction flags to be the same as the running transaction */
02042     {
02043         rpmtransFlags tsFlags = rpmtsFlags(rbts);
02044         tsFlags &= ~RPMTRANS_FLAG_DIRSTASH;     /* No repackage of rollbacks */
02045         tsFlags &= ~RPMTRANS_FLAG_REPACKAGE;    /* No repackage of rollbacks */
02046         tsFlags |= RPMTRANS_FLAG_NOFDIGESTS;    /* Don't check file digests */
02047         tsFlags = rpmtsSetFlags(rbts, tsFlags);
02048     }
02049 
02050     /* Create install arguments structure */    
02051     ia->rbtid = arbgoal;
02052     /* transFlags/depFlags from rbts, (re-)set in rpmRollback(). */
02053     ia->transFlags = rpmtsFlags(rbts);
02054     ia->depFlags = rpmtsDFlags(rbts);
02055     /* XXX probFilter is normally set in main(). */
02056     ia->probFilter = ignoreSet; /* XXX RPMPROB_FILTER_NONE? */
02057     /* XXX installInterfaceFlags is normally set in main(). */
02058     ia->installInterfaceFlags = INSTALL_UPGRADE | INSTALL_HASH ;
02059 
02060     /* rpmtsCheck and rpmtsOrder failures do not have links. */
02061     ia->no_rollback_links = 1;
02062 
02063     /* Create a file semaphore. */
02064     semfn = rpmExpand("%{?semaphore_backout}", NULL);
02065     if (semfn && *semfn) {
02066         FD_t fd = Fopen(semfn, "w.fdio");
02067         if (fd)
02068             xx = Fclose(fd);
02069     }
02070 
02071 /*@-compmempass@*/
02072     rc = rpmRollback(rbts, ia, NULL);
02073 /*@=compmempass@*/
02074 
02075 cleanup: 
02076     /* Remove the file semaphore. */
02077     if (semfn && *semfn)
02078         xx = Unlink(semfn);
02079     semfn = _free(semfn);
02080 
02081     return rc;
02082 }
02083 /*@=nullpass@*/
02084 
02085 int _rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
02086 {
02087     int ourrc = -1;     /* assume failure */
02088     uint32_t totalFileCount = 0;
02089     rpmps ps;
02090     rpmsx sx = NULL;
02091     uint32_t numRemoved;
02092     int rollbackFailures = 0;
02093     void * lock = NULL;
02094     int xx;
02095 
02096 FPSDEBUG(0, (stderr, "--> %s(%p,%p,0x%x)\n", __FUNCTION__, ts, okProbs, ignoreSet));
02097 if (_rpmts_debug)
02098 fprintf(stderr, "--> %s(%p,%p,0x%x) tsFlags 0x%x\n", __FUNCTION__, ts, okProbs, (unsigned) ignoreSet, rpmtsFlags(ts));
02099 
02100     /* XXX programmer error segfault avoidance. */
02101     if (rpmtsNElements(ts) <= 0) {
02102         rpmlog(RPMLOG_ERR,
02103             _("Invalid number of transaction elements.\n"));
02104         return -1;
02105     }
02106 
02107     /* Don't acquire the transaction lock if testing. */
02108     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST))
02109         lock = rpmtsAcquireLock(ts);
02110 
02111     rollbackFailures = rpmExpandNumeric("%{?_rollback_transaction_on_failure}");
02112     /* Don't rollback unless repackaging. */
02113     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_REPACKAGE))
02114         rollbackFailures = 0;
02115     /* Don't rollback if testing. */
02116     if (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)
02117         rollbackFailures = 0;
02118 
02119     if (rpmtsType(ts) & (RPMTRANS_TYPE_ROLLBACK | RPMTRANS_TYPE_AUTOROLLBACK))
02120         rollbackFailures = 0;
02121 
02122     /* ===============================================
02123      * Setup flags and such, open the rpmdb in O_RDWR mode.
02124      */
02125     sx = NULL;
02126     if (rpmtsSetup(ts, ignoreSet, &sx))
02127         goto exit;
02128 
02129     /* ===============================================
02130      * For packages being installed:
02131      * - verify package epoch:version-release is newer.
02132      * - count files.
02133      * For packages being removed:
02134      * - count files.
02135      */
02136 
02137     totalFileCount = 0;
02138     ps = rpmtsSanityCheck(ts, &totalFileCount);
02139     ps = rpmpsFree(ps);
02140 
02141     /* ===============================================
02142      * Run pre-transaction scripts, but only if no known problems exist.
02143      */
02144     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPRETRANS) &&
02145        (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_TEST))
02146           || (rpmpsNumProblems(ts->probs) &&
02147                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs))))))
02148     {
02149         rpmlog(RPMLOG_DEBUG, D_("running pre-transaction scripts\n"));
02150         xx = rpmtsRunScript(ts, RPMTAG_PRETRANS);
02151     }
02152 
02153     /* ===============================================
02154      * Compute file disposition for each package in transaction set.
02155      */
02156     numRemoved = 0;
02157     if (rpmtsPrepare(ts, sx, totalFileCount, &numRemoved))
02158         goto exit;
02159 
02160     /* ===============================================
02161      * If unfiltered problems exist, free memory and return.
02162      */
02163     if ((rpmtsFlags(ts) & RPMTRANS_FLAG_BUILD_PROBS)
02164      || (rpmpsNumProblems(ts->probs) &&
02165                 (okProbs == NULL || rpmpsTrim(ts->probs, okProbs)))
02166        )
02167     {
02168         lock = rpmtsFreeLock(lock);
02169         if (sx != NULL) sx = rpmsxFree(sx);
02170         return ts->orderCount;
02171     }
02172 
02173     /* ===============================================
02174      * Save removed files before erasing.
02175      */
02176     if (rpmtsFlags(ts) & (RPMTRANS_FLAG_DIRSTASH | RPMTRANS_FLAG_REPACKAGE)) {
02177         xx = rpmtsRepackage(ts, numRemoved);
02178     }
02179 
02180 #ifdef  NOTYET
02181     xx = rpmtxnBegin(rpmtsGetRdb(ts), NULL, &ts->txn);
02182 #endif
02183 
02184     /* ===============================================
02185      * Install and remove packages.
02186      */
02187     ourrc = rpmtsProcess(ts, ignoreSet, rollbackFailures);
02188 
02189     /* ===============================================
02190      * Run post-transaction scripts unless disabled.
02191      */
02192     if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOPOSTTRANS) &&
02193         !(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST))
02194     {
02195 
02196 #if defined(RPM_VENDOR_MANDRIVA)
02197         if ((rpmtsFlags(ts) & _noTransTriggers) != _noTransTriggers)
02198             rpmRunFileTriggers(rpmtsRootDir(ts));
02199 #endif
02200 
02201         rpmlog(RPMLOG_DEBUG, D_("running post-transaction scripts\n"));
02202         xx = rpmtsRunScript(ts, RPMTAG_POSTTRANS);
02203     }
02204 
02205 exit:
02206     xx = rpmtsFinish(ts, sx);
02207 
02208     lock = rpmtsFreeLock(lock);
02209 
02210     /*@-nullstate@*/ /* FIX: ts->flList may be NULL */
02211     if (ourrc) {
02212         if (ts->txn != NULL)
02213             xx = rpmtxnAbort(ts->txn);
02214         ts->txn = NULL;
02215         return -1;
02216     } else {
02217         if (ts->txn != NULL)
02218             xx = rpmtxnCommit(ts->txn);
02219         ts->txn = NULL;
02220         xx = rpmtxnCheckpoint(rpmtsGetRdb(ts));
02221         return 0;
02222     }
02223     /*@=nullstate@*/
02224 }
02225 
02226 int (*rpmtsRun) (rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
02227         = _rpmtsRun;