diff options
Diffstat (limited to 'lib/transaction.c')
-rw-r--r-- | lib/transaction.c | 579 |
1 files changed, 318 insertions, 261 deletions
diff --git a/lib/transaction.c b/lib/transaction.c index fa17d34b7..6af1d1662 100644 --- a/lib/transaction.c +++ b/lib/transaction.c @@ -4,6 +4,9 @@ #include "system.h" +#include <inttypes.h> +#include <libgen.h> + #include <rpm/rpmlib.h> /* rpmMachineScore, rpmReadPackageFile */ #include <rpm/rpmmacro.h> /* XXX for rpmExpand */ #include <rpm/rpmlog.h> @@ -11,6 +14,7 @@ #include <rpm/rpmds.h> #include <rpm/rpmfileutil.h> #include <rpm/rpmstring.h> +#include <rpm/rpmsq.h> #include "lib/fprint.h" #include "lib/misc.h" @@ -21,6 +25,7 @@ #include "lib/rpmte_internal.h" /* only internal apis */ #include "lib/rpmts_internal.h" #include "rpmio/rpmhook.h" +#include "lib/rpmtriggers.h" #include "lib/rpmplugins.h" @@ -63,6 +68,45 @@ struct diskspaceInfo_s { #define adj_fs_blocks(_nb) (((_nb) * 21) / 20) #define BLOCK_ROUND(size, block) (((size) + (block) - 1) / (block)) +static char *getMntPoint(const char *dirName, dev_t dev) +{ + char mntPoint[PATH_MAX]; + char *resolved_path = realpath(dirName, mntPoint); + char *end = NULL; + struct stat sb; + char *res = NULL; + + if (!resolved_path) { + strncpy(mntPoint, dirName, PATH_MAX); + mntPoint[PATH_MAX-1] = '\0'; + } + + while (end != mntPoint) { + end = strrchr(mntPoint, '/'); + if (end == mntPoint) { /* reached "/" */ + stat("/", &sb); + if (dev != sb.st_dev) { + res = xstrdup(mntPoint); + } else { + res = xstrdup("/"); + } + break; + } else if (end) { + *end = '\0'; + } else { /* dirName doesn't start with / - should not happen */ + res = xstrdup(dirName); + break; + } + stat(mntPoint, &sb); + if (dev != sb.st_dev) { + *end = '/'; + res = xstrdup(mntPoint); + break; + } + } + return res; +} + static int rpmtsInitDSI(const rpmts ts) { if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_DISKSPACE) @@ -77,8 +121,6 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev, { rpmDiskSpaceInfo dsi; struct stat sb; - char * resolved_path; - char mntPoint[PATH_MAX]; int rc; #if STATFS_IN_SYS_STATVFS @@ -119,11 +161,7 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev, dsi->bneeded = 0; dsi->ineeded = 0; #ifdef STATFS_HAS_F_BAVAIL -# ifdef ST_RDONLY dsi->bavail = (sfb.f_flag & ST_RDONLY) ? 0 : sfb.f_bavail; -# else - dsi->bavail = sfb.f_bavail; -# endif #else /* FIXME: the statfs struct doesn't have a member to tell how many blocks are * available for non-superusers. f_blocks - f_bfree is probably too big, but @@ -137,34 +175,16 @@ static rpmDiskSpaceInfo rpmtsCreateDSI(const rpmts ts, dev_t dev, ? sfb.f_ffree : -1; /* Find mount point belonging to this device number */ - resolved_path = realpath(dirName, mntPoint); - if (!resolved_path) { - strncpy(mntPoint, dirName, PATH_MAX); - mntPoint[PATH_MAX-1] = '\0'; - } - char * end = NULL; - while (end != mntPoint) { - end = strrchr(mntPoint, '/'); - if (end == mntPoint) { /* reached "/" */ - stat("/", &sb); - if (dsi->dev != sb.st_dev) { - dsi->mntPoint = xstrdup(mntPoint); - } else { - dsi->mntPoint = xstrdup("/"); - } - break; - } else if (end) { - *end = '\0'; - } else { /* dirName doesn't start with / - should not happen */ - dsi->mntPoint = xstrdup(dirName); - break; - } - stat(mntPoint, &sb); - if (dsi->dev != sb.st_dev) { - *end = '/'; - dsi->mntPoint = xstrdup(mntPoint); - break; - } + dsi->mntPoint = getMntPoint(dirName, dsi->dev); + + /* normalize block size to 4096 bytes if it is too big. */ + if (dsi->bsize > 4096) { + uint64_t old_size = dsi->bavail * dsi->bsize; + rpmlog(RPMLOG_DEBUG, + "dubious blocksize % " PRId64 " on %s, normalizing to 4096\n", + dsi->bsize, dsi->mntPoint); + dsi->bsize = 4096; /* Assume 4k block size */ + dsi->bavail = old_size / dsi->bsize; } rpmlog(RPMLOG_DEBUG, @@ -291,17 +311,21 @@ static uint64_t countFiles(rpmts ts) uint64_t fc = 0; rpmtsi pi = rpmtsiInit(ts); rpmte p; - while ((p = rpmtsiNext(pi, 0)) != NULL) - fc += rpmfiFC(rpmteFI(p)); + rpmfiles files; + while ((p = rpmtsiNext(pi, 0)) != NULL) { + files = rpmteFiles(p); + fc += rpmfilesFC(files); + rpmfilesFree(files); + } rpmtsiFree(pi); return fc; } -static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx) +static int handleRemovalConflict(rpmfiles fi, int fx, rpmfiles ofi, int ofx) { int rConflicts = 0; /* Removed files don't conflict, normally */ - rpmFileTypes ft = rpmfiWhatis(rpmfiFModeIndex(fi, fx)); - rpmFileTypes oft = rpmfiWhatis(rpmfiFModeIndex(ofi, ofx)); + rpmFileTypes ft = rpmfiWhatis(rpmfilesFMode(fi, fx)); + rpmFileTypes oft = rpmfiWhatis(rpmfilesFMode(ofi, ofx)); struct stat sb; char *fn = NULL; @@ -312,7 +336,7 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx) } else if (oft == LINK) { /* We can't correctly handle directory symlink changing to directory */ if (ft == XDIR) { - fn = rpmfiFNIndex(fi, fx); + fn = rpmfilesFN(fi, fx); if (stat(fn, &sb) == 0 && S_ISDIR(sb.st_mode)) rConflicts = 1; } @@ -324,7 +348,7 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx) */ if (rConflicts) { if (fn == NULL) - fn = rpmfiFNIndex(fi, fx); + fn = rpmfilesFN(fi, fx); if (lstat(fn, &sb) || rpmfiWhatis(sb.st_mode) == ft) rConflicts = 0; } @@ -342,15 +366,15 @@ static int handleRemovalConflict(rpmfi fi, int fx, rpmfi ofi, int ofx) * unnecessary with careful packaging. */ static int handleColorConflict(rpmts ts, - rpmfs fs, rpmfi fi, int fx, - rpmfs ofs, rpmfi ofi, int ofx) + rpmfs fs, rpmfiles fi, int fx, + rpmfs ofs, rpmfiles ofi, int ofx) { int rConflicts = 1; rpm_color_t tscolor = rpmtsColor(ts); if (tscolor != 0) { - rpm_color_t fcolor = rpmfiFColorIndex(fi, fx) & tscolor; - rpm_color_t ofcolor = rpmfiFColorIndex(ofi, ofx) & tscolor; + rpm_color_t fcolor = rpmfilesFColor(fi, fx) & tscolor; + rpm_color_t ofcolor = rpmfilesFColor(ofi, ofx) & tscolor; if (fcolor != 0 && ofcolor != 0 && fcolor != ofcolor) { rpm_color_t prefcolor = rpmtsPrefColor(ts); @@ -377,22 +401,24 @@ static int handleColorConflict(rpmts ts, * @param ts transaction set * @param p current transaction element * @param fi file info set - * @param shared shared file info - * @param sharedCount no. of shared elements - * @param reportConflicts + * @param fx file index + * @param otherHeader header containing the matching file + * @param otherFi matching file info set + * @param ofx matching file index + * @param beingRemoved file being removed (installed otherwise) */ /* XXX only ts->{probs,rpmdb} modified */ -static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx, - Header otherHeader, rpmfi otherFi, int ofx, +static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfiles fi, int fx, + Header otherHeader, rpmfiles otherFi, int ofx, int beingRemoved) { rpmfs fs = rpmteGetFileStates(p); - int isCfgFile = ((rpmfiFFlagsIndex(otherFi, ofx) | rpmfiFFlagsIndex(fi, fx)) & RPMFILE_CONFIG); + int isCfgFile = ((rpmfilesFFlags(otherFi, ofx) | rpmfilesFFlags(fi, fx)) & RPMFILE_CONFIG); if (XFA_SKIPPING(rpmfsGetAction(fs, fx))) return; - if (rpmfiCompareIndex(otherFi, ofx, fi, fx)) { + if (rpmfilesCompare(otherFi, ofx, fi, fx)) { int rConflicts = 1; char rState = RPMFILE_STATE_REPLACED; @@ -421,20 +447,22 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx, rState = RPMFILE_STATE_WRONGCOLOR; } + if (rConflicts) { - char *path = rpmfiFNIndex(fi, fx); + char *path = rpmfilesFN(fi, fx); /* Call file conflict hook for all plugins */ rpmpluginsCallFileConflict(ts->plugins, ts, path, otherHeader, otherFi, rConflicts); } - + /* Somebody used The Force, lets shut up... */ if (rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACEOLDFILES) { rConflicts = 0; } + if (rConflicts) { char *altNEVR = headerGetAsString(otherHeader, RPMTAG_NEVRA); - char *fn = rpmfiFNIndex(fi, fx); + char *fn = rpmfilesFN(fi, fx); rpmteAddProblem(p, RPMPROB_FILE_CONFLICT, altNEVR, fn, headerGetInstance(otherHeader)); free(fn); @@ -449,34 +477,42 @@ static void handleInstInstalledFile(const rpmts ts, rpmte p, rpmfi fi, int fx, } } - /* Determine config file dispostion, skipping missing files (if any). */ + /* Determine config file disposition, skipping missing files (if any). */ if (isCfgFile) { int skipMissing = ((rpmtsFlags(ts) & RPMTRANS_FLAG_ALLFILES) ? 0 : 1); rpmFileAction action; - action = rpmfiDecideFateIndex(otherFi, ofx, fi, fx, skipMissing); + action = rpmfilesDecideFate(otherFi, ofx, fi, fx, skipMissing); rpmfsSetAction(fs, fx, action); } - rpmfiSetFReplacedSizeIndex(fi, fx, rpmfiFSizeIndex(otherFi, ofx)); + + /* Skip already existing files - if 'minimize_writes' is set. */ + if ((!isCfgFile) && (rpmfsGetAction(fs, fx) == FA_UNKNOWN) && ts->min_writes) { + if (rpmfileContentsEqual(otherFi, ofx, fi, fx)) { + rpmfsSetAction(fs, fx, FA_TOUCH); + } + } + + rpmfilesSetFReplacedSize(fi, fx, rpmfilesFSize(otherFi, ofx)); } /** * Update disk space needs on each partition for this package's files. */ /* XXX only ts->{probs,di} modified */ -static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi fi) +static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfiles fi) { rpm_loff_t fixupSize = 0; int i, j; rpmfs fs = rpmteGetFileStates(p); rpmfs otherFs; - rpm_count_t fc = rpmfiFC(fi); + rpm_count_t fc = rpmfilesFC(fi); int reportConflicts = !(rpmtsFilterFlags(ts) & RPMPROB_FILTER_REPLACENEWFILES); - fingerPrint * fpList = rpmfiFps(fi); + fingerPrint * fpList = rpmfilesFps(fi); for (i = 0; i < fc; i++) { struct fingerPrint_s * fiFps; int otherPkgNum, otherFileNum; - rpmfi otherFi; + rpmfiles otherFi; rpmte otherTe; rpmfileAttrs FFlags; struct rpmffi_s * recs; @@ -485,7 +521,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi if (XFA_SKIPPING(rpmfsGetAction(fs, i))) continue; - FFlags = rpmfiFFlagsIndex(fi, i); + FFlags = rpmfilesFFlags(fi, i); fixupSize = 0; @@ -513,7 +549,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi * that were just installed. * If both this and the other package are being removed, then each * file removal from preceding packages needs to be skipped so that - * the file removal occurs only on the last occurence of an overlapped + * the file removal occurs only on the last occurrence of an overlapped * file in the transaction set. * */ @@ -535,7 +571,6 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi for (otherPkgNum = j - 1; otherPkgNum >= 0; otherPkgNum--) { otherTe = recs[otherPkgNum].p; - otherFi = rpmteFI(otherTe); otherFileNum = recs[otherPkgNum].fileno; otherFs = rpmteGetFileStates(otherTe); @@ -544,8 +579,10 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi continue; /* XXX Happens iff fingerprint for incomplete package install. */ - if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN) + if (rpmfsGetAction(otherFs, otherFileNum) != FA_UNKNOWN) { + otherFi = rpmteFiles(otherTe); break; + } } switch (rpmteType(p)) { @@ -555,7 +592,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi rpmFileAction action; if (rpmfsGetAction(fs, i) != FA_UNKNOWN) break; - if (rpmfiConfigConflictIndex(fi, i)) { + if (rpmfilesConfigConflict(fi, i)) { /* Here is a non-overlapped pre-existing config file. */ action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_BACKUP; @@ -568,7 +605,7 @@ static void handleOverlappedFiles(rpmts ts, fingerPrintCache fpc, rpmte p, rpmfi assert(otherFi != NULL); /* Mark added overlapped non-identical files as a conflict. */ - if (rpmfiCompareIndex(otherFi, otherFileNum, fi, i)) { + if (rpmfilesCompare(otherFi, otherFileNum, fi, i)) { int rConflicts; /* If enabled, resolve colored conflicts to preferred type */ @@ -576,7 +613,7 @@ assert(otherFi != NULL); otherFs, otherFi, otherFileNum); if (rConflicts && reportConflicts) { - char *fn = rpmfiFNIndex(fi, i); + char *fn = rpmfilesFN(fi, i); rpmteAddProblem(p, RPMPROB_NEW_FILE_CONFLICT, rpmteNEVRA(otherTe), fn, 0); free(fn); @@ -587,10 +624,13 @@ assert(otherFi != NULL); if (oaction != FA_UNKNOWN && !XFA_SKIPPING(oaction)) { rpmfileAttrs oflags; /* ...but ghosts aren't really created so... */ - oflags = rpmfiFFlagsIndex(otherFi, otherFileNum); + oflags = rpmfilesFFlags(otherFi, otherFileNum); if (!(oflags & RPMFILE_GHOST)) { rpmfsSetAction(fs, i, FA_SKIP); } + /* if the other file is color skipped then skip this file too */ + } else if (oaction == FA_SKIPCOLOR) { + rpmfsSetAction(fs, i, FA_SKIPCOLOR); } } @@ -599,9 +639,9 @@ assert(otherFi != NULL); break; /* Try to get the disk accounting correct even if a conflict. */ - fixupSize = rpmfiFSizeIndex(otherFi, otherFileNum); + fixupSize = rpmfilesFSize(otherFi, otherFileNum); - if (rpmfiConfigConflictIndex(fi, i)) { + if (rpmfilesConfigConflict(fi, i)) { /* Here is an overlapped pre-existing config file. */ rpmFileAction action; action = (FFlags & RPMFILE_NOREPLACE) ? FA_ALTNAME : FA_SKIP; @@ -627,12 +667,14 @@ assert(otherFi != NULL); } if (XFA_SKIPPING(rpmfsGetAction(fs, i))) break; - if (rpmfiFStateIndex(fi, i) != RPMFILE_STATE_NORMAL) + if (rpmfilesFState(fi, i) != RPMFILE_STATE_NORMAL) { + rpmfsSetAction(fs, i, FA_SKIP); break; + } /* Pre-existing modified config files need to be saved. */ - if (rpmfiConfigConflictIndex(fi, i)) { - rpmfsSetAction(fs, i, FA_BACKUP); + if (rpmfilesConfigConflict(fi, i)) { + rpmfsSetAction(fs, i, FA_SAVE); break; } @@ -640,10 +682,11 @@ assert(otherFi != NULL); rpmfsSetAction(fs, i, FA_ERASE); break; } + rpmfilesFree(otherFi); /* Update disk space info for a file. */ rpmtsUpdateDSI(ts, fpEntryDev(fpc, fiFps), fpEntryDir(fpc, fiFps), - rpmfiFSizeIndex(fi, i), rpmfiFReplacedSizeIndex(fi, i), + rpmfilesFSize(fi, i), rpmfilesFReplacedSize(fi, i), fixupSize, rpmfsGetAction(fs, i)); } @@ -654,7 +697,6 @@ assert(otherFi != NULL); * @param tspool transaction string pool * @param p current transaction element * @param h installed header - * @param ps problem set */ static void ensureOlder(rpmstrPool tspool, const rpmte p, const Header h) { @@ -677,9 +719,9 @@ static void ensureOlder(rpmstrPool tspool, const rpmte p, const Header h) * netshardpath and though should be excluded. * @param ts transaction set * @param fi file info set - * @returns pointer to matching path or NULL + * @returns 1 if path is net shared path, otherwise 0 */ -static char ** matchNetsharedpath(const rpmts ts, rpmfi fi) +static int matchNetsharedpath(const rpmts ts, rpmfi fi) { char ** nsp; const char * dn, * bn; @@ -717,29 +759,25 @@ static char ** matchNetsharedpath(const rpmts ts, rpmfi fi) break; } - return nsp; + return (nsp != NULL && *nsp != NULL); } -static void skipEraseFiles(const rpmts ts, rpmte p) +static void skipEraseFiles(const rpmts ts, rpmfiles files, rpmfs fs) { - rpmfi fi = rpmteFI(p); - rpmfs fs = rpmteGetFileStates(p); int i; - char ** nsp; /* * Skip net shared paths. * Net shared paths are not relative to the current root (though * they do need to take package relocations into account). */ if (ts->netsharedPaths) { - fi = rpmfiInit(fi, 0); + rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD); while ((i = rpmfiNext(fi)) >= 0) { - nsp = matchNetsharedpath(ts, fi); - if (nsp && *nsp) { + if (matchNetsharedpath(ts, fi)) rpmfsSetAction(fs, i, FA_SKIPNETSHARED); - } } + rpmfiFree(fi); } } @@ -747,9 +785,10 @@ static void skipEraseFiles(const rpmts ts, rpmte p) /** * Skip any files that do not match install policies. * @param ts transaction set - * @param fi file info set + * @param files file info set + * @param fs file states */ -static void skipInstallFiles(const rpmts ts, rpmte p) +static void skipInstallFiles(const rpmts ts, rpmfiles files, rpmfs fs) { rpm_color_t tscolor = rpmtsColor(ts); rpm_color_t FColor; @@ -759,8 +798,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p) char * dff; int dc; int i, j, ix; - rpmfi fi = rpmteFI(p); - rpmfs fs = rpmteGetFileStates(p); + rpmfi fi = rpmfilesIter(files, RPMFI_ITER_FWD); if (!noDocs) noDocs = rpmExpandNumeric("%{_excludedocs}"); @@ -772,13 +810,13 @@ static void skipInstallFiles(const rpmts ts, rpmte p) fi = rpmfiInit(fi, 0); while ((i = rpmfiNext(fi)) >= 0) { - char ** nsp; const char *flangs; ix = rpmfiDX(fi); drc[ix]++; /* Don't bother with skipped files */ + /* XXX FIXME: --excludepath on %license should not be permitted */ if (XFA_SKIPPING(rpmfsGetAction(fs, i))) { drc[ix]--; dff[ix] = 1; continue; @@ -798,8 +836,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p) * they do need to take package relocations into account). */ if (ts->netsharedPaths) { - nsp = matchNetsharedpath(ts, fi); - if (nsp && *nsp) { + if (matchNetsharedpath(ts, fi)) { drc[ix]--; dff[ix] = 1; rpmfsSetAction(fs, i, FA_SKIPNETSHARED); continue; @@ -807,6 +844,14 @@ static void skipInstallFiles(const rpmts ts, rpmte p) } /* + * In general, excluding license files is not permitted. In case + * of SKIPNETSHARED and SKIPCOLOR the file is expected to be + * there via other means however so that is ok. + */ + if (rpmfiFFlags(fi) & RPMFILE_LICENSE) + continue; + + /* * Skip i18n language specific files. */ flangs = (ts->installLangs != NULL) ? rpmfiFLangs(fi) : NULL; @@ -851,7 +896,8 @@ static void skipInstallFiles(const rpmts ts, rpmte p) } /* Skip (now empty) directories that had skipped files. */ - for (j = 0; j < dc; j++) { + /* Iterate over dirs in reversed order to solve subdirs at first */ + for (j = dc - 1; j >= 0; j--) { const char * dn, * bn; size_t dnlen, bnlen; @@ -859,7 +905,7 @@ static void skipInstallFiles(const rpmts ts, rpmte p) if (!dff[j]) continue; /* dir was not emptied here. */ /* Find parent directory and basename. */ - dn = rpmfiDNIndex(fi, j); dnlen = strlen(dn) - 1; + dn = rpmfilesDN(files, j); dnlen = strlen(dn) - 1; bn = dn + dnlen; bnlen = 0; while (bn > dn && bn[-1] != '/') { bnlen++; @@ -892,12 +938,18 @@ static void skipInstallFiles(const rpmts ts, rpmte p) continue; rpmlog(RPMLOG_DEBUG, "excluding directory %s\n", dn); rpmfsSetAction(fs, i, FA_SKIPNSTATE); + ix = rpmfiDX(fi); + /* Decrease count of files for parent directory */ + drc[ix]--; + /* Mark directory because something was removed from them */ + dff[ix] = 1; break; } } free(drc); free(dff); + rpmfiFree(fi); } #undef HASHTYPE @@ -932,6 +984,7 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount) tsMembers tsmem = rpmtsMembers(ts); rpmstrPool tspool = rpmtsPool(ts); rpmtsi pi; rpmte p; + rpmfiles files; rpmfi fi; rpmdbMatchIterator mi; int oc = 0; @@ -945,12 +998,13 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount) pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { - (void) rpmdbCheckSignals(); + (void) rpmsqPoll(); rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_PROGRESS, oc++, tsmem->orderCount); /* Gather all installed headers with matching basename's. */ - fi = rpmfiInit(rpmteFI(p), 0); + files = rpmteFiles(p); + fi = rpmfilesIter(files, RPMFI_ITER_FWD); while (rpmfiNext(fi) >= 0) { size_t keylen; @@ -965,7 +1019,9 @@ rpmdbMatchIterator rpmFindBaseNamesInDB(rpmts ts, uint64_t fileCount) keylen++; /* XXX "/" fixup. */ rpmdbExtendIterator(mi, baseName, keylen); rpmStringSetAddEntry(baseNames, baseNameId); - } + } + rpmfiFree(fi); + rpmfilesFree(files); } rpmtsiFree(pi); rpmStringSetFree(baseNames); @@ -986,7 +1042,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) { tsMembers tsmem = rpmtsMembers(ts); rpmte p; - rpmfi fi; + rpmfiles fi; rpmfs fs; int j; unsigned int fileNum; @@ -1015,15 +1071,15 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) fingerPrint *fpp = NULL; unsigned int installedPkg; int beingRemoved = 0; - rpmfi otherFi = NULL; + rpmfiles otherFi = NULL; rpmte *removedPkg = NULL; /* Is this package being removed? */ installedPkg = rpmdbGetIteratorOffset(mi); - if (removedHashGetEntry(tsmem->removedPackages, installedPkg, + if (packageHashGetEntry(tsmem->removedPackages, installedPkg, &removedPkg, NULL, NULL)) { beingRemoved = 1; - otherFi = rpmfiLink(rpmteFI(removedPkg[0])); + otherFi = rpmteFiles(removedPkg[0]); } h = headerLink(h); @@ -1057,7 +1113,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) fpLookup(fpc, dirName, baseName, &fpp); fpIx = 0; } else { - fpp = rpmfiFps(otherFi); + fpp = rpmfilesFps(otherFi); fpIx = fileNum; } @@ -1066,7 +1122,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) for (j = 0; j < numRecs; j++) { p = recs[j].p; - fi = rpmteFI(p); + fi = rpmteFiles(p); fs = rpmteGetFileStates(p); /* Determine the fate of each file. */ @@ -1074,7 +1130,7 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) case TR_ADDED: if (!otherFi) { /* XXX What to do if this fails? */ - otherFi = rpmfiNew(ts, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); + otherFi = rpmfilesNew(NULL, h, RPMTAG_BASENAMES, RPMFI_KEEPHEADER); } handleInstInstalledFile(ts, p, fi, recs[j].fileno, h, otherFi, fileNum, beingRemoved); @@ -1086,13 +1142,14 @@ void checkInstalledFiles(rpmts ts, uint64_t fileCount, fingerPrintCache fpc) } break; } + rpmfilesFree(fi); } newheader = rpmdbNextIterator(mi); } while (newheader==h); - otherFi = rpmfiFree(otherFi); + otherFi = rpmfilesFree(otherFi); if (!beingRemoved) { rpmtdFreeData(&ostates); rpmtdFreeData(&bnames); @@ -1146,7 +1203,7 @@ static rpmps checkProblems(rpmts ts) if (!(probFilter & RPMPROB_FILTER_REPLACEPKG)) { Header h; rpmdbMatchIterator mi; - mi = rpmtsInitIterator(ts, RPMDBI_NAME, rpmteN(p), 0); + mi = rpmtsPrunedIterator(ts, RPMDBI_NAME, rpmteN(p), 1); rpmdbSetIteratorRE(mi, RPMTAG_EPOCH, RPMMIRE_STRCMP, rpmteE(p)); rpmdbSetIteratorRE(mi, RPMTAG_VERSION, RPMMIRE_STRCMP, rpmteV(p)); rpmdbSetIteratorRE(mi, RPMTAG_RELEASE, RPMMIRE_STRCMP, rpmteR(p)); @@ -1180,92 +1237,16 @@ static int runTransScripts(rpmts ts, pkgGoal goal) int rc = 0; rpmte p; rpmtsi pi = rpmtsiInit(ts); - while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) { - rc += rpmteProcess(p, goal); - } - rpmtsiFree(pi); - return rc; -} - -static int rpmtsSetupCollections(rpmts ts) -{ - /* seenCollectionsPost and TEs are basically a key-value pair. each item in - * seenCollectionsPost is a collection that has been seen from any package, - * and the associated index in the TEs is the last transaction element - * where that collection was seen. */ - ARGV_t seenCollectionsPost = NULL; - rpmte *TEs = NULL; - int numSeenPost = 0; - - /* seenCollectionsPre is a list of collections that have been seen from - * only removed packages */ - ARGV_t seenCollectionsPre = NULL; - int numSeenPre = 0; - - ARGV_const_t collname; - int installing = 1; - int i; - - rpmte p; - rpmtsi pi = rpmtsiInit(ts); - while ((p = rpmtsiNext(pi, 0)) != NULL) { - /* detect when we switch from installing to removing packages, and - * update the lastInCollectionAdd lists */ - if (installing && rpmteType(p) == TR_REMOVED) { - installing = 0; - for (i = 0; i < numSeenPost; i++) { - rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]); - } - } - - rpmteSetupCollectionPlugins(p); - - for (collname = rpmteCollections(p); collname && *collname; collname++) { - /* figure out if we've seen this collection in post before */ - for (i = 0; i < numSeenPost && strcmp(*collname, seenCollectionsPost[i]); i++) { - } - if (i < numSeenPost) { - /* we've seen the collection, update the index */ - TEs[i] = p; - } else { - /* haven't seen the collection yet, add it */ - argvAdd(&seenCollectionsPost, *collname); - TEs = xrealloc(TEs, sizeof(*TEs) * (numSeenPost + 1)); - TEs[numSeenPost] = p; - numSeenPost++; - } + rpmElementTypes types = TR_ADDED; + int i = 0; + if (goal == PKG_TRANSFILETRIGGERUN) + types = TR_REMOVED; - /* figure out if we've seen this collection in pre remove before */ - if (installing == 0) { - for (i = 0; i < numSeenPre && strcmp(*collname, seenCollectionsPre[i]); i++) { - } - if (i >= numSeenPre) { - /* haven't seen this collection, add it */ - rpmteAddToFirstInCollectionRemove(p, *collname); - argvAdd(&seenCollectionsPre, *collname); - numSeenPre++; - } - } - } + while ((p = rpmtsiNext(pi, types)) != NULL) { + rc += rpmteProcess(p, goal, i++); } rpmtsiFree(pi); - - /* we've looked at all the rpmte's, update the lastInCollectionAny lists */ - for (i = 0; i < numSeenPost; i++) { - rpmteAddToLastInCollectionAny(TEs[i], seenCollectionsPost[i]); - if (installing == 1) { - /* lastInCollectionAdd is only updated above if packages were - * removed. if nothing is removed in the transaction, we need to - * update that list here */ - rpmteAddToLastInCollectionAdd(TEs[i], seenCollectionsPost[i]); - } - } - - argvFree(seenCollectionsPost); - argvFree(seenCollectionsPre); - _free(TEs); - - return 0; + return rc; } static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet) @@ -1279,21 +1260,7 @@ static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet) (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransTriggers)); if (rpmtsFlags(ts) & (RPMTRANS_FLAG_JUSTDB | RPMTRANS_FLAG_TEST)) - (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers | RPMTRANS_FLAG_NOCOLLECTIONS)); - - /* if SELinux isn't enabled or it is a test run, don't bother... */ - if (!is_selinux_enabled() || (rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { - rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); - } - - if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS) { - rpmlog(RPMLOG_DEBUG, "Selinux disabled.\n"); - } else { - if (rpmtsSELabelInit(ts, 1)) { - rpmlog(RPMLOG_WARNING, "Failed to open SELinux handle.\n"); - rpmtsSetFlags(ts, (rpmtsFlags(ts) | RPMTRANS_FLAG_NOCONTEXTS)); - } - } + (void) rpmtsSetFlags(ts, (rpmtsFlags(ts) | _noTransScripts | _noTransTriggers)); /* * Make sure the database is open RDWR for package install/erase. @@ -1315,9 +1282,6 @@ static int rpmtsSetup(rpmts ts, rpmprobFilterFlags ignoreSet) static int rpmtsFinish(rpmts ts) { - if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { - rpmtsSELabelFini(ts, 1); - } return rpmChrootSet(NULL); } @@ -1326,7 +1290,6 @@ static int rpmtsPrepare(rpmts ts) tsMembers tsmem = rpmtsMembers(ts); rpmtsi pi; rpmte p; - rpmfi fi; int rc = 0; uint64_t fileCount = countFiles(ts); const char *dbhome = NULL; @@ -1336,16 +1299,21 @@ static int rpmtsPrepare(rpmts ts) rpmlog(RPMLOG_DEBUG, "computing %" PRIu64 " file fingerprints\n", fileCount); - /* Skip netshared paths, not our i18n files, and excluded docs */ + /* Reset actions, set skip for netshared paths and excluded files */ pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { - if (rpmfiFC(rpmteFI(p)) == 0) - continue; - if (rpmteType(p) == TR_ADDED) { - skipInstallFiles(ts, p); - } else { - skipEraseFiles(ts, p); + rpmfiles files = rpmteFiles(p); + if (rpmfilesFC(files) > 0) { + rpmfs fs = rpmteGetFileStates(p); + /* Ensure clean state, this could get called more than once. */ + rpmfsResetActions(fs); + if (rpmteType(p) == TR_ADDED) { + skipInstallFiles(ts, files, fs); + } else { + skipEraseFiles(ts, files, fs); + } } + rpmfilesFree(files); } rpmtsiFree(pi); @@ -1368,13 +1336,14 @@ static int rpmtsPrepare(rpmts ts) pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { - if ((fi = rpmteFI(p)) == NULL) + rpmfiles files = rpmteFiles(p);; + if (files == NULL) continue; /* XXX can't happen */ (void) rpmswEnter(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); /* check files in ts against each other and update disk space needs on each partition for this package. */ - handleOverlappedFiles(ts, fpc, p, fi); + handleOverlappedFiles(ts, fpc, p, files); /* Check added package has sufficient space on each partition used. */ if (rpmteType(p) == TR_ADDED) { @@ -1391,6 +1360,7 @@ static int rpmtsPrepare(rpmts ts) rpmtsCheckDSIProblems(ts, p); } (void) rpmswExit(rpmtsOp(ts, RPMTS_OP_FINGERPRINT), 0); + rpmfilesFree(files); } rpmtsiFree(pi); rpmtsNotify(ts, NULL, RPMCALLBACK_TRANS_STOP, 6, tsmem->orderCount); @@ -1403,7 +1373,7 @@ static int rpmtsPrepare(rpmts ts) if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) { pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { - rpmteSetFI(p, NULL); + rpmteCleanFiles(p); } rpmtsiFree(pi); } @@ -1421,6 +1391,7 @@ static int rpmtsProcess(rpmts ts) { rpmtsi pi; rpmte p; int rc = 0; + int i = 0; pi = rpmtsiInit(ts); while ((p = rpmtsiNext(pi, 0)) != NULL) { @@ -1429,49 +1400,114 @@ static int rpmtsProcess(rpmts ts) rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n", rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p)); - if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOCONTEXTS)) { - rpmtsSELabelInit(ts, 0); - } - - failed = rpmteProcess(p, rpmteType(p)); + failed = rpmteProcess(p, rpmteType(p), i++); if (failed) { rpmlog(RPMLOG_ERR, "%s: %s %s\n", rpmteNEVRA(p), rpmteTypeString(p), failed > 1 ? _("skipped") : _("failed")); rc++; } - (void) rpmdbSync(rpmtsGetRdb(ts)); } rpmtsiFree(pi); return rc; } -static rpmRC rpmtsSetupTransactionPlugins(rpmts ts) +rpmRC rpmtsSetupTransactionPlugins(rpmts ts) { rpmRC rc = RPMRC_OK; - char *plugins = NULL, *plugin = NULL; - const char *delims = ","; - - plugins = rpmExpand("%{?__transaction_plugins}", NULL); - if (!plugins || rstreq(plugins, "")) { - goto exit; - } + ARGV_t files = NULL; + int nfiles = 0; + char *dsoPath = NULL; - plugin = strtok(plugins, delims); - while(plugin != NULL) { - rpmlog(RPMLOG_DEBUG, "plugin is %s\n", plugin); - if (!rpmpluginsPluginAdded(ts->plugins, (const char*)plugin)) { - if (rpmpluginsAddPlugin(ts->plugins, "transaction", - (const char*)plugin) == RPMRC_FAIL) { - /* any configured plugin failing to load is a failure */ + /* + * Assume allocated equals initialized. There are some oddball cases + * (verification of non-installed package) where this is not true + * currently but that's not a new issue. + */ + if ((rpmtsFlags(ts) & RPMTRANS_FLAG_NOPLUGINS) || rpmPluginsGetCount(rpmtsPlugins(ts)) != 0) + return RPMRC_OK; + + dsoPath = rpmExpand("%{__plugindir}/*.so", NULL); + if (rpmGlob(dsoPath, &nfiles, &files) == 0) { + rpmPlugins tsplugins = rpmtsPlugins(ts); + for (int i = 0; i < nfiles; i++) { + char *bn = basename(files[i]); + bn[strlen(bn)-strlen(".so")] = '\0'; + if (rpmpluginsAddPlugin(tsplugins, "transaction", bn) == RPMRC_FAIL) + { + /* any configured plugin failing to load is a failure */ // temporally make the loading policy relaxed: no failures + //refer to commit id: 3959da1846227711d97c17495aa4779e653a1b3a //rc = RPMRC_FAIL; } } - plugin = strtok(NULL, delims); + files = argvFree(files); } + free(dsoPath); + + return rc; +} +/** + * Run a scriptlet with args. + * + * Run a script with an interpreter. If the interpreter is not specified, + * /bin/sh will be used. If the interpreter is /bin/sh, then the args from + * the header will be ignored, passing instead arg1 and arg2. + * + * @param ts transaction set + * @param te transaction element + * @param prefixes install prefixes + * @param script scriptlet from header + * @param arg1 no. instances of package installed after scriptlet exec + * (-1 is no arg) + * @param arg2 ditto, but for the target package + * @return 0 on success + */ +rpmRC runScript(rpmts ts, rpmte te, Header h, ARGV_const_t prefixes, + rpmScript script, int arg1, int arg2) +{ + rpmte xte = te; + rpmRC stoprc, rc = RPMRC_OK; + rpmTagVal stag = rpmScriptTag(script); + FD_t sfd = NULL; + int warn_only = (stag != RPMTAG_PREIN && + stag != RPMTAG_PREUN && + stag != RPMTAG_PRETRANS && + stag != RPMTAG_VERIFYSCRIPT); + + /* Fake up a transaction element for triggers from rpmdb */ + if (te == NULL) { + te = rpmteNew(ts, h, TR_REMOVED, NULL, NULL); + rpmteSetHeader(te, h); + } + + sfd = rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_START, stag, 0); + if (sfd == NULL) + sfd = rpmtsScriptFd(ts); + + rpmswEnter(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0); + rc = rpmScriptRun(script, arg1, arg2, sfd, + prefixes, warn_only, rpmtsPlugins(ts)); + rpmswExit(rpmtsOp(ts, RPMTS_OP_SCRIPTLETS), 0); + + /* Map warn-only errors to "notfound" for script stop callback */ + stoprc = (rc != RPMRC_OK && warn_only) ? RPMRC_NOTFOUND : rc; + rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_STOP, stag, stoprc); + + /* + * Notify callback for all errors. "total" abused for warning/error, + * rc only reflects whether the condition prevented install/erase + * (which is only happens with %prein and %preun scriptlets) or not. + */ + if (rc != RPMRC_OK) { + if (warn_only) { + rc = RPMRC_OK; + } + rpmtsNotify(ts, te, RPMCALLBACK_SCRIPT_ERROR, stag, rc); + } + + if (te != xte) + rpmteFree(te); -exit: - free(plugins); return rc; } @@ -1479,9 +1515,11 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) { int rc = -1; /* assume failure */ tsMembers tsmem = rpmtsMembers(ts); - rpmlock lock = NULL; + rpmtxn txn = NULL; rpmps tsprobs = NULL; int TsmPreDone = 0; /* TsmPre hook hasn't been called */ + /* Ignore SIGPIPE for the duration of transaction */ + rpmsqAction_t oact = rpmsqSetAction(SIGPIPE, RPMSQ_IGN); /* Force default 022 umask during transaction for consistent results */ mode_t oldmask = umask(022); @@ -1494,7 +1532,7 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) /* If we are in test mode, then there's no need for transaction lock. */ if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_TEST)) { - if (!(lock = rpmtsAcquireLock(ts))) { + if (!(txn = rpmtxnBegin(ts, RPMTXN_WRITE))) { goto exit; } } @@ -1504,24 +1542,20 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) goto exit; } - if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL) { - goto exit; - } - - rpmtsSetupCollections(ts); - /* Check package set for problems */ tsprobs = checkProblems(ts); /* Run pre transaction hook for all plugins */ TsmPreDone = 1; - if (rpmpluginsCallTsmPre(ts->plugins, ts) == RPMRC_FAIL) { + if (rpmpluginsCallTsmPre(rpmtsPlugins(ts), ts) == RPMRC_FAIL) { goto exit; } - /* Run pre-transaction scripts, but only if there are no known - * problems up to this point and not disabled otherwise. */ - if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRE)) + /* Run %pretrans scripts, but only if there are no known problems up to + * this point and not disabled otherwise. This is evil as it runs before + * fingerprinting and problem checking and is best avoided. + */ + if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRETRANS)) || (rpmpsNumProblems(tsprobs)))) { rpmlog(RPMLOG_DEBUG, "running pre-transaction scripts\n"); runTransScripts(ts, PKG_PRETRANS); @@ -1553,24 +1587,47 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet) if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))) tsmem->pool = rpmstrPoolFree(tsmem->pool); + /* Run %transfiletriggerun scripts unless disabled */ + if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRETRANS| + RPMTRANS_FLAG_NOTRIGGERUN))) { + + runFileTriggers(ts, NULL, RPMSENSE_TRIGGERUN, + RPMSCRIPT_TRANSFILETRIGGER, 0); + runTransScripts(ts, PKG_TRANSFILETRIGGERUN); + } + /* Actually install and remove packages, get final exit code */ rc = rpmtsProcess(ts) ? -1 : 0; - /* Run post-transaction scripts unless disabled */ - if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOST))) { + /* Run %posttrans scripts unless disabled */ + if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS))) { rpmlog(RPMLOG_DEBUG, "running post-transaction scripts\n"); runTransScripts(ts, PKG_POSTTRANS); } + /* Run %transfiletriggerpostun scripts unless disabled */ + if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { + runFileTriggers(ts, NULL, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER, 0); + } + if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERPOSTUN))) { + runPostUnTransFileTrigs(ts); + } + + /* Run %transfiletriggerin scripts unless disabled */ + if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_NOPOSTTRANS|RPMTRANS_FLAG_NOTRIGGERIN))) { + runTransScripts(ts, PKG_TRANSFILETRIGGERIN); + } exit: /* Run post transaction hook for all plugins */ if (TsmPreDone) /* If TsmPre hook has been called, call the TsmPost hook */ - rpmpluginsCallTsmPost(ts->plugins, ts, rc); + rpmpluginsCallTsmPost(rpmtsPlugins(ts), ts, rc); /* Finish up... */ (void) umask(oldmask); (void) rpmtsFinish(ts); rpmpsFree(tsprobs); - rpmlockFree(lock); + rpmtxnEnd(txn); + /* Restore SIGPIPE *after* unblocking signals in rpmtxnEnd() */ + rpmsqSetAction(SIGPIPE, oact); return rc; } |