summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorLubos Kardos <lkardos@lkardos.brq.redhat.com>2014-09-17 10:47:32 +0200
committerLubos Kardos <lkardos@redhat.com>2015-02-05 08:08:12 +0100
commitec78eea7fe6a60bc10038ca3a7a4c5d85e2a9a16 (patch)
tree1278f3a860858998db3e92bfb9ebe979e6dcd66d /lib
parentb04c4f559b25bf8b6774a445a0e537c8ce1d2c59 (diff)
downloadrpm-ec78eea7fe6a60bc10038ca3a7a4c5d85e2a9a16.tar.gz
Add support for executing file triggers.
Supported file triggers: %filetriggerin %filetriggerun %filetriggerpostun %transfiletriggerin %transfiletriggerun
Diffstat (limited to 'lib')
-rw-r--r--lib/psm.c92
-rw-r--r--lib/rpmfiles.h8
-rw-r--r--lib/rpmte_internal.h2
-rw-r--r--lib/rpmts_internal.h13
-rw-r--r--lib/transaction.c452
5 files changed, 511 insertions, 56 deletions
diff --git a/lib/psm.c b/lib/psm.c
index c4a4818a5..1cd8769ec 100644
--- a/lib/psm.c
+++ b/lib/psm.c
@@ -238,61 +238,6 @@ exit:
return rpmrc;
}
-/**
- * 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
- */
-static rpmRC runScript(rpmts ts, rpmte te, ARGV_const_t prefixes,
- rpmScript script, int arg1, int arg2)
-{
- 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);
-
- 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);
- }
-
- return rc;
-}
-
static rpmRC runInstScript(rpmpsm psm, rpmTagVal scriptTag)
{
rpmRC rc = RPMRC_OK;
@@ -704,6 +649,7 @@ static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
if (rpmtsFilterFlags(psm->ts) & RPMPROB_FILTER_REPLACEPKG)
markReplacedInstance(ts, psm->te);
+
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERPREIN)) {
/* Run triggers in other package(s) this package sets off. */
rc = runTriggers(psm, RPMSENSE_TRIGGERPREIN);
@@ -748,8 +694,19 @@ static rpmRC rpmPackageInstall(rpmts ts, rpmpsm psm)
if (rc) break;
}
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER);
+ if (rc) break;
+
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_FILETRIGGER);
+ if (rc) break;
+
rc = markReplacedFiles(psm);
}
+
rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_INSTALL), 0);
return rc;
@@ -762,6 +719,17 @@ static rpmRC rpmPackageErase(rpmts ts, rpmpsm psm)
rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_ERASE), 0);
while (once--) {
+
+ /* Run file triggers in this package other package(s) set off. */
+ rc = runImmedFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER);
+ if (rc) break;
+
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_FILETRIGGER);
+ if (rc) break;
+
if (!(rpmtsFlags(ts) & RPMTRANS_FLAG_NOTRIGGERUN)) {
/* Run triggers in this package other package(s) set off. */
rc = runImmedTriggers(psm, RPMSENSE_TRIGGERUN);
@@ -789,8 +757,14 @@ static rpmRC rpmPackageErase(rpmts ts, rpmpsm psm)
if (rc) break;
}
+ /* Run file triggers in other package(s) this package sets off. */
+ rc = runFileTriggers(psm->ts, psm->te, RPMSENSE_TRIGGERPOSTUN,
+ RPMSCRIPT_FILETRIGGER);
+ if (rc) break;
+
rc = dbRemove(ts, psm->te);
}
+
rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_ERASE), 0);
return rc;
@@ -835,6 +809,14 @@ rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
case PKG_VERIFY:
rc = runInstScript(psm, goal);
break;
+ case PKG_TRANSFILETRIGGERIN:
+ rc = runImmedFileTriggers(ts, te, RPMSENSE_TRIGGERIN,
+ RPMSCRIPT_TRANSFILETRIGGER);
+ break;
+ case PKG_TRANSFILETRIGGERUN:
+ rc = runImmedFileTriggers(ts, te, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_TRANSFILETRIGGER);
+ break;
default:
break;
}
diff --git a/lib/rpmfiles.h b/lib/rpmfiles.h
index 4f464c0ea..0c785d208 100644
--- a/lib/rpmfiles.h
+++ b/lib/rpmfiles.h
@@ -136,6 +136,14 @@ typedef rpmFlags rpmfiFlags;
(RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
RPMFI_NOFILECOLORS | RPMFI_NOFILEVERIFYFLAGS)
+#define RPMFI_FLAGS_ONLY_FILENAMES \
+ (RPMFI_NOFILECLASS | RPMFI_NOFILEDEPS | RPMFI_NOFILELANGS | \
+ RPMFI_NOFILEUSER | RPMFI_NOFILEGROUP | RPMFI_NOFILEMODES | \
+ RPMFI_NOFILESIZES | RPMFI_NOFILECAPS | RPMFI_NOFILELINKTOS | \
+ RPMFI_NOFILEDIGESTS | RPMFI_NOFILEMTIMES | RPMFI_NOFILERDEVS | \
+ RPMFI_NOFILEINODES | RPMFI_NOFILESTATES | RPMFI_NOFILECOLORS | \
+ RPMFI_NOFILEVERIFYFLAGS | RPMFI_NOFILEFLAGS)
+
typedef enum rpmFileIter_e {
RPMFI_ITER_FWD = 0,
RPMFI_ITER_BACK = 1,
diff --git a/lib/rpmte_internal.h b/lib/rpmte_internal.h
index af25c6269..464f47628 100644
--- a/lib/rpmte_internal.h
+++ b/lib/rpmte_internal.h
@@ -14,6 +14,8 @@ typedef enum pkgGoal_e {
PKG_VERIFY = RPMTAG_VERIFYSCRIPT,
PKG_PRETRANS = RPMTAG_PRETRANS,
PKG_POSTTRANS = RPMTAG_POSTTRANS,
+ PKG_TRANSFILETRIGGERIN = RPMTAG_TRANSFILETRIGGERIN,
+ PKG_TRANSFILETRIGGERUN = RPMTAG_TRANSFILETRIGGERUN,
} pkgGoal;
/** \ingroup rpmte
diff --git a/lib/rpmts_internal.h b/lib/rpmts_internal.h
index b125ce6af..9f74e677a 100644
--- a/lib/rpmts_internal.h
+++ b/lib/rpmts_internal.h
@@ -8,6 +8,7 @@
#include "lib/fprint.h"
#include "lib/rpmlock.h"
#include "lib/rpmdb_internal.h"
+#include "lib/rpmscript.h"
typedef struct diskspaceInfo_s * rpmDiskSpaceInfo;
@@ -100,6 +101,18 @@ int rpmtsSolve(rpmts ts, rpmds key);
RPM_GNUC_INTERNAL
rpmRC rpmtsSetupTransactionPlugins(rpmts ts);
+
+RPM_GNUC_INTERNAL
+rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm);
+
+RPM_GNUC_INTERNAL
+rpmRC runImmedFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm);
+RPM_GNUC_INTERNAL
+rpmRC runScript(rpmts ts, rpmte te, ARGV_const_t prefixes,
+ rpmScript script, int arg1, int arg2);
+
#ifdef __cplusplus
}
#endif
diff --git a/lib/transaction.c b/lib/transaction.c
index b08b9d950..2bb690b96 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -1184,7 +1184,11 @@ static int runTransScripts(rpmts ts, pkgGoal goal)
int rc = 0;
rpmte p;
rpmtsi pi = rpmtsiInit(ts);
- while ((p = rpmtsiNext(pi, TR_ADDED)) != NULL) {
+ rpmElementTypes types = TR_ADDED;
+ if (goal == PKG_TRANSFILETRIGGERUN)
+ types = TR_REMOVED;
+
+ while ((p = rpmtsiNext(pi, types)) != NULL) {
rc += rpmteProcess(p, goal);
}
rpmtsiFree(pi);
@@ -1382,6 +1386,438 @@ rpmRC rpmtsSetupTransactionPlugins(rpmts ts)
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, ARGV_const_t prefixes,
+ rpmScript script, int arg1, int arg2)
+{
+ 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);
+
+ 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);
+ }
+
+ return rc;
+}
+
+/*
+ * Get files from next package from match iterator. If files are
+ * available in memory then don't read them from rpmdb.
+ */
+static rpmfiles rpmtsNextFiles(rpmts ts, rpmdbMatchIterator mi)
+{
+ Header h;
+ rpmte *te;
+ rpmfiles files = NULL;
+ rpmstrPool pool = ts->members->pool;
+ int ix;
+ unsigned int offset;
+
+ ix = rpmdbGetIteratorIndex(mi);
+ if (ix < rpmdbGetIteratorCount(mi)) {
+ offset = rpmdbGetIteratorOffsetFor(mi, ix);
+ if (packageHashGetEntry(ts->members->removedPackages, offset,
+ &te, NULL, NULL)) {
+ /* Files are available in memory */
+ files = rpmteFiles(te[0]);
+ }
+
+ if (packageHashGetEntry(ts->members->installedPackages, offset,
+ &te, NULL, NULL)) {
+ /* Files are available in memory */
+ files = rpmteFiles(te[0]);
+ }
+ }
+
+ if (files) {
+ rpmdbSetIteratorIndex(mi, ix + 1);
+ } else {
+ /* Files are not available in memory. Read them from rpmdb */
+ h = rpmdbNextIterator(mi);
+ if (h) {
+ files = rpmfilesNew(pool, h, RPMTAG_BASENAMES,
+ RPMFI_FLAGS_ONLY_FILENAMES);
+ }
+ }
+
+ return files;
+}
+
+
+typedef struct matchFilesIter_s {
+ rpmts ts;
+ rpmds rpmdsTrigger;
+ rpmfiles files;
+ rpmfi fi;
+ const char *pfx;
+ rpmdbMatchIterator pi;
+ packageHash tranPkgs;
+} *matchFilesIter;
+
+static matchFilesIter matchFilesIterator(rpmds trigger, rpmfiles files)
+{
+ matchFilesIter mfi = xcalloc(1, sizeof(*mfi));
+ rpmdsInit(trigger);
+ mfi->rpmdsTrigger = trigger;
+ mfi->files = rpmfilesLink(files);
+ return mfi;
+}
+
+static matchFilesIter matchDBFilesIterator(rpmds trigger, rpmts ts,
+ int inTransaction)
+{
+ matchFilesIter mfi = xcalloc(1, sizeof(*mfi));
+ rpmsenseFlags sense;
+
+ rpmdsSetIx(trigger, 0);
+ sense = rpmdsFlags(trigger);
+ rpmdsInit(trigger);
+
+ mfi->rpmdsTrigger = trigger;
+ mfi->ts = ts;
+
+ /* If inTransaction is set then filter out packages that aren't in transaction */
+ if (inTransaction) {
+ if (sense & RPMSENSE_TRIGGERIN)
+ mfi->tranPkgs = ts->members->installedPackages;
+ else
+ mfi->tranPkgs = ts->members->removedPackages;
+ }
+ return mfi;
+}
+
+static const char *matchFilesNext(matchFilesIter mfi)
+{
+ const char *matchFile = NULL;
+ int fx;
+
+ /* Decide if we iterate over given files (mfi->files) */
+ if (!mfi->ts)
+ do {
+ /* Get next file from mfi->fi */
+ rpmfiNext(mfi->fi);
+ matchFile = rpmfiFN(mfi->fi);
+ if (strlen(matchFile))
+ break;
+ matchFile = NULL;
+
+ /* If we are done with current mfi->fi, create mfi->fi for next prefix */
+ fx = rpmdsNext(mfi->rpmdsTrigger);
+ mfi->pfx = rpmdsN(mfi->rpmdsTrigger);
+ rpmfiFree(mfi->fi);
+ mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx);
+
+ } while (fx >= 0);
+ /* or we iterate over files in rpmdb */
+ else
+ do {
+ rpmfiNext(mfi->fi);
+ matchFile = rpmfiFN(mfi->fi);
+ if (strlen(matchFile))
+ break;
+ matchFile = NULL;
+
+ /* If we are done with current mfi->fi, create mfi->fi for next package */
+ rpmfilesFree(mfi->files);
+ rpmfiFree(mfi->fi);
+ mfi->files = rpmtsNextFiles(mfi->ts, mfi->pi);
+ mfi->fi = rpmfilesFindPrefix(mfi->files, mfi->pfx);
+ if (mfi->files)
+ continue;
+
+ /* If we are done with all packages, go through packages with new prefix */
+ fx = rpmdsNext(mfi->rpmdsTrigger);
+ mfi->pfx = rpmdsN(mfi->rpmdsTrigger);
+ rpmdbFreeIterator(mfi->pi);
+ mfi->pi = rpmdbInitPrefixIterator(rpmtsGetRdb(mfi->ts),
+ RPMDBI_DIRNAMES, mfi->pfx, 0);
+
+ rpmdbFilterIterator(mfi->pi, mfi->tranPkgs, 0);
+ rpmdbUniqIterator(mfi->pi);
+
+ } while (fx >= 0);
+
+
+ return matchFile;
+}
+
+static int matchFilesEmpty(matchFilesIter mfi)
+{
+ const char *matchFile;
+
+ /* Try to get the first file */
+ matchFile = matchFilesNext(mfi);
+
+ /* Rewind back this file */
+ rpmfiInit(mfi->fi, 0);
+
+ if (matchFile)
+ /* We have at least one file so iterator is not empty */
+ return 0;
+ else
+ /* No file in iterator */
+ return 1;
+}
+
+static matchFilesIter matchFilesIteratorFree(matchFilesIter mfi)
+{
+ rpmfiFree(mfi->fi);
+ rpmfilesFree(mfi->files);
+ rpmdbFreeIterator(mfi->pi);
+ free(mfi);
+ return NULL;
+}
+
+/*
+ * Run all file triggers in header h
+ * @param searchMode 0 match trigger prefixes against files in te
+ * 1 match trigger prefixes against files in whole ts
+ * 2 match trigger prefixes against files in whole
+ * rpmdb
+ */
+static int runHandleTriggersInPkg(rpmts ts, rpmte te, Header h,
+ rpmsenseFlags sense, rpmscriptTriggerModes tm,
+ int searchMode)
+{
+ int nerrors = 0;
+ rpmds rpmdsTriggers, rpmdsTrigger;
+ int ti = 0;
+ rpmfiles files = NULL;
+ matchFilesIter mfi;
+ rpmScript script;
+ struct rpmtd_s installPrefixes;
+ char *(*inputFunc)(void *);
+
+ rpmdsTriggers = rpmdsNew(h, triggerDsTag(tm), 0);
+
+ /* Loop over triggers in pakage (in header h) */
+ while ((rpmdsTrigger = rpmdsFilterTi(rpmdsTriggers, ti))) {
+ /*
+ * Now rpmdsTrigger contains all dependencies belonging to one trigger
+ * with trigger index tix. Have a look at the first one to check flags.
+ */
+ if ((rpmdsNext(rpmdsTrigger) >= 0) &&
+ (rpmdsFlags(rpmdsTrigger) & sense)) {
+
+ switch (searchMode) {
+ case 0:
+ /* Create iterator over files in te that this trigger matches */
+ files = rpmteFiles(te);
+ mfi = matchFilesIterator(rpmdsTrigger, files);
+ break;
+ case 1:
+ /* Create iterator over files in ts that this trigger matches */
+ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 1);
+ break;
+ case 2:
+ /* Create iterator over files in whole rpmd that this trigger matches */
+ mfi = matchDBFilesIterator(rpmdsTrigger, ts, 0);
+ break;
+ }
+
+ /* If this trigger matches any file then run trigger script */
+ if (!matchFilesEmpty(mfi)) {
+ script = rpmScriptFromTriggerTag(h, triggertag(sense), tm, ti);
+
+ headerGet(h, RPMTAG_INSTPREFIXES, &installPrefixes,
+ HEADERGET_ALLOC|HEADERGET_ARGV);
+
+
+ /*
+ * As input function set function to get next file from
+ * matching file iterator. As parameter for this function
+ * set matching file iterator. Input function will be called
+ * during execution of trigger script in order to get data
+ * that will be passed as stdin to trigger script. To get
+ * these data from lua script function rpm.input() can be used.
+ */
+ inputFunc = (char *(*)(void *)) matchFilesNext;
+ rpmScriptSetNextFileFunc(script, inputFunc, mfi);
+
+ nerrors += runScript(ts, te, installPrefixes.data,
+ script, 0, 0);
+ rpmtdFreeData(&installPrefixes);
+ rpmScriptFree(script);
+ }
+ rpmfilesFree(files);
+ matchFilesIteratorFree(mfi);
+ }
+ rpmdsFree(rpmdsTrigger);
+ ti++;
+ }
+ rpmdsFree(rpmdsTriggers);
+
+ return nerrors;
+}
+
+/* Return true if any file in package (te) starts with pfx */
+static int matchFilesInPkg(rpmts ts, rpmte te, const char *pfx,
+ rpmsenseFlags sense)
+{
+ int rc;
+ rpmfiles files = rpmteFiles(te);
+ rpmfi fi = rpmfilesFindPrefix(files, pfx);
+
+ rc = (fi != NULL);
+ rpmfilesFree(files);
+ rpmfiFree(fi);
+ return rc;
+}
+
+/* Return true if any added/removed file in ts starts with pfx */
+static int matchFilesInTran(rpmts ts, rpmte te, const char *pfx,
+ rpmsenseFlags sense)
+{
+ int rc = 1;
+ rpmdbMatchIterator pi;
+
+ /* Get all files from rpmdb starting with pfx */
+ pi = rpmdbInitPrefixIterator(rpmtsGetRdb(ts), RPMDBI_DIRNAMES, pfx, 0);
+
+ if (sense & RPMSENSE_TRIGGERIN)
+ /* Leave in pi only files installed in ts */
+ rpmdbFilterIterator(pi, ts->members->installedPackages, 0);
+ else
+ /* Leave in pi only files removed in ts */
+ rpmdbFilterIterator(pi, ts->members->removedPackages, 0);
+
+ rc = rpmdbGetIteratorCount(pi);
+ rpmdbFreeIterator(pi);
+
+ return rc;
+}
+
+/*
+ * It runs file triggers in other package(s) this package/transaction sets off.
+ * If tm is RPMSCRIPT_FILETRIGGERSCRIPT then it runs file triggers that are
+ * fired by files in transaction entry. If tm is RPMSCRIPT_TRANSFILETRIGGERSCRIPT
+ * then it runs file triggers that are fired by all files in transaction set.
+ * In that case te can be NULL.
+ *
+ * @param ts transaction set
+ * @param te transaction entry
+ * @param sense defines which triggers should be set off (triggerin,
+ * triggerun, triggerpostun)
+ * @param tm trigger mode, (filetrigger/transfiletrigger)
+ */
+rpmRC runFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm)
+{
+ int nerrors = 0;
+ rpmdbIndexIterator ii;
+ rpmdbMatchIterator mi;
+ const void *key;
+ char *pfx;
+ size_t keylen;
+ Header trigH;
+ int (*matchFunc)(rpmts, rpmte, const char*, rpmsenseFlags sense);
+
+ /* Decide if we match triggers against files in te or in whole ts */
+ if (tm == RPMSCRIPT_FILETRIGGER)
+ matchFunc = matchFilesInPkg;
+ else
+ matchFunc = matchFilesInTran;
+
+ ii = rpmdbIndexIteratorInit(rpmtsGetRdb(ts), triggerDsTag(tm));
+ mi = rpmdbNewIterator(rpmtsGetRdb(ts), RPMDBI_PACKAGES);
+
+ /* Loop over all file triggers in rpmdb */
+ while ((rpmdbIndexIteratorNext(ii, &key, &keylen)) == 0) {
+ pfx = xmalloc(keylen + 1);
+ memcpy(pfx, key, keylen);
+ pfx[keylen] = '\0';
+
+ /* Check if file trigger is fired by any file in ts/te */
+ if (matchFunc(ts, te, pfx, sense))
+ /* If yes then store it */
+ rpmdbAppendIterator(mi, rpmdbIndexIteratorPkgOffsets(ii),
+ rpmdbIndexIteratorNumPkgs(ii));
+ free(pfx);
+ }
+ rpmdbIndexIteratorFree(ii);
+
+ rpmdbUniqIterator(mi);
+ /*
+ * Don't handle transaction triggers installed in current transaction
+ * to avoid executing the same script two times. These triggers are
+ * handled in runImmedFileTriggers().
+ */
+ if (tm == RPMSCRIPT_TRANSFILETRIGGER) {
+ rpmdbFilterIterator(mi, ts->members->removedPackages, 1);
+ rpmdbFilterIterator(mi, ts->members->installedPackages, 1);
+ }
+
+ /* Handle stored triggers */
+ if (rpmdbGetIteratorCount(mi)) {
+ while((trigH = rpmdbNextIterator(mi)) != NULL) {
+
+ if (tm == RPMSCRIPT_FILETRIGGER)
+ nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 0);
+ else
+ nerrors += runHandleTriggersInPkg(ts, te, trigH, sense, tm, 1);
+ }
+ }
+ rpmdbFreeIterator(mi);
+
+ return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
+
+/* Run file triggers in this te other package(s) set off.
+ * @param ts transaction set
+ * @param te transaction entry
+ * @param sense defines which triggers should be set off (triggerin,
+ * triggerun, triggerpostun)
+ * @param tm trigger mode, (filetrigger/transfiletrigger)
+ */
+rpmRC runImmedFileTriggers(rpmts ts, rpmte te, rpmsenseFlags sense,
+ rpmscriptTriggerModes tm)
+{
+ int nerrors = 0;
+
+ nerrors += runHandleTriggersInPkg(ts, te, rpmteHeader(te), sense, tm, 2);
+ return (nerrors == 0) ? RPMRC_OK : RPMRC_FAIL;
+}
int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
{
@@ -1421,6 +1857,14 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
goto exit;
}
+ if (!rpmpsNumProblems(tsprobs)) {
+ /* Run file triggers in this package other package(s) set off. */
+ runFileTriggers(ts, NULL, RPMSENSE_TRIGGERUN,
+ RPMSCRIPT_TRANSFILETRIGGER);
+ /* Run file triggers in other package(s) this package sets off. */
+ runTransScripts(ts, PKG_TRANSFILETRIGGERUN);
+ }
+
/* 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_NOPRETRANS))
@@ -1455,6 +1899,7 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
if (!(rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS)))
tsmem->pool = rpmstrPoolFree(tsmem->pool);
+
/* Actually install and remove packages, get final exit code */
rc = rpmtsProcess(ts) ? -1 : 0;
@@ -1464,6 +1909,11 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
runTransScripts(ts, PKG_POSTTRANS);
}
+ /* Run file triggers in other package(s) this package sets off. */
+ runFileTriggers(ts, NULL, RPMSENSE_TRIGGERIN, RPMSCRIPT_TRANSFILETRIGGER);
+
+ /* Run file triggers in this package other package(s) set off. */
+ runTransScripts(ts, PKG_TRANSFILETRIGGERIN);
exit:
/* Run post transaction hook for all plugins */
if (TsmPreDone) /* If TsmPre hook has been called, call the TsmPost hook */