5523e9
diff --git a/configure.ac b/configure.ac
5523e9
index 167491e..3bacc1d 100644
5523e9
--- a/configure.ac
5523e9
+++ b/configure.ac
5523e9
@@ -745,6 +745,16 @@ AS_IF([test "$enable_plugins" = yes],[
5523e9
 ])
5523e9
 AM_CONDITIONAL(ENABLE_PLUGINS,[test "$enable_plugins" = yes])
5523e9
 
5523e9
+with_dbus=no
5523e9
+AS_IF([test "$enable_plugins" != no],[
5523e9
+  PKG_CHECK_MODULES([DBUS],
5523e9
+    [dbus-1 >= 1.0],
5523e9
+    [AC_DEFINE(DBUS, 1, [Build with dbus support?]) with_dbus=yes],
5523e9
+    [with_dbus=no])
5523e9
+  AC_SUBST(DBUS_CFLAGS)
5523e9
+  AC_SUBST(DBUS_LIBS)
5523e9
+])
5523e9
+AM_CONDITIONAL(DBUS, [test "$with_dbus" = yes])
5523e9
 
5523e9
 with_dmalloc=no
5523e9
 AC_ARG_WITH(dmalloc, [AS_HELP_STRING([--with-dmalloc],[build with dmalloc debugging support])])
5523e9
diff --git a/lib/psm.c b/lib/psm.c
5523e9
index 8f5376d..e80a90e 100644
5523e9
--- a/lib/psm.c
5523e9
+++ b/lib/psm.c
5523e9
@@ -23,8 +23,11 @@
5523e9
 #include "lib/rpmfi_internal.h" /* XXX replaced/states... */
5523e9
 #include "lib/rpmte_internal.h"	/* XXX internal apis */
5523e9
 #include "lib/rpmdb_internal.h" /* rpmdbAdd/Remove */
5523e9
+#include "lib/rpmts_internal.h" /* ts->plugins */
5523e9
 #include "lib/rpmscript.h"
5523e9
 
5523e9
+#include "lib/rpmplugins.h"
5523e9
+
5523e9
 #include "debug.h"
5523e9
 
5523e9
 typedef enum pkgStage_e {
5523e9
@@ -421,7 +424,7 @@ static rpmRC runScript(rpmpsm psm, ARGV_const_t prefixes,
5523e9
 
5523e9
     rpmswEnter(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
5523e9
     rc = rpmScriptRun(script, arg1, arg2, sfd,
5523e9
-		      prefixes, warn_only, selinux);
5523e9
+		      prefixes, warn_only, selinux, psm->ts->plugins);
5523e9
     rpmswExit(rpmtsOp(psm->ts, RPMTS_OP_SCRIPTLETS), 0);
5523e9
 
5523e9
     /* Map warn-only errors to "notfound" for script stop callback */
5523e9
@@ -1033,16 +1036,23 @@ rpmRC rpmpsmRun(rpmts ts, rpmte te, pkgGoal goal)
5523e9
 	switch (goal) {
5523e9
 	case PKG_INSTALL:
5523e9
 	case PKG_ERASE:
5523e9
-	    op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
5523e9
-	    rpmswEnter(rpmtsOp(psm->ts, op), 0);
5523e9
+	    /* Run pre transaction element hook for all plugins */
5523e9
+	    if (rpmpluginsCallPsmPre(ts->plugins, te) != RPMRC_FAIL) {
5523e9
+
5523e9
+		op = (goal == PKG_INSTALL) ? RPMTS_OP_INSTALL : RPMTS_OP_ERASE;
5523e9
+		rpmswEnter(rpmtsOp(psm->ts, op), 0);
5523e9
 
5523e9
-	    rc = rpmpsmNext(psm, PSM_INIT);
5523e9
-	    if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
5523e9
-	    if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
5523e9
-	    if (!rc) rc = rpmpsmNext(psm, PSM_POST);
5523e9
-	    (void) rpmpsmNext(psm, PSM_FINI);
5523e9
+		rc = rpmpsmNext(psm, PSM_INIT);
5523e9
+		if (!rc) rc = rpmpsmNext(psm, PSM_PRE);
5523e9
+		if (!rc) rc = rpmpsmNext(psm, PSM_PROCESS);
5523e9
+		if (!rc) rc = rpmpsmNext(psm, PSM_POST);
5523e9
+		(void) rpmpsmNext(psm, PSM_FINI);
5523e9
+
5523e9
+		rpmswExit(rpmtsOp(psm->ts, op), 0);
5523e9
+	    }
5523e9
 
5523e9
-	    rpmswExit(rpmtsOp(psm->ts, op), 0);
5523e9
+	    /* Run post transaction element hook for all plugins */
5523e9
+	    rpmpluginsCallPsmPost(ts->plugins, te, rc);
5523e9
 	    break;
5523e9
 	case PKG_PRETRANS:
5523e9
 	case PKG_POSTTRANS:
5523e9
diff --git a/lib/rpmplugins.c b/lib/rpmplugins.c
5523e9
index 9098aa5..7285f54 100644
5523e9
--- a/lib/rpmplugins.c
5523e9
+++ b/lib/rpmplugins.c
5523e9
@@ -76,16 +76,16 @@ rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path,
5523e9
     return rpmpluginsCallInit(plugins, name, opts);
5523e9
 }
5523e9
 
5523e9
-rpmRC rpmpluginsAddCollectionPlugin(rpmPlugins plugins, const char *name)
5523e9
+rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name)
5523e9
 {
5523e9
     char *path;
5523e9
     char *options;
5523e9
     rpmRC rc = RPMRC_FAIL;
5523e9
 
5523e9
-    path = rpmExpand("%{?__collection_", name, "}", NULL);
5523e9
+    path = rpmExpand("%{?__", type, "_", name, "}", NULL);
5523e9
     if (!path || rstreq(path, "")) {
5523e9
-	rpmlog(RPMLOG_ERR, _("Failed to expand %%__collection_%s macro\n"),
5523e9
-	       name);
5523e9
+	rpmlog(RPMLOG_ERR, _("Failed to expand %%__%s_%s macro\n"),
5523e9
+	       type, name);
5523e9
 	goto exit;
5523e9
     }
5523e9
 
5523e9
@@ -195,3 +195,88 @@ rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name)
5523e9
     RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_COLL_PRE_REMOVE);
5523e9
     return hookFunc();
5523e9
 }
5523e9
+
5523e9
+rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts)
5523e9
+{
5523e9
+    rpmRC (*hookFunc)(rpmts);
5523e9
+    int i;
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    const char *name = NULL;
5523e9
+
5523e9
+    for (i = 0; i < plugins->count; i++) {
5523e9
+	name = plugins->names[i];
5523e9
+	RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_PRE);
5523e9
+	if (hookFunc(ts) == RPMRC_FAIL)
5523e9
+	    rc = RPMRC_FAIL;
5523e9
+    }
5523e9
+
5523e9
+    return rc;
5523e9
+}
5523e9
+
5523e9
+rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res)
5523e9
+{
5523e9
+    rpmRC (*hookFunc)(rpmts, int);
5523e9
+    int i;
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    const char *name = NULL;
5523e9
+
5523e9
+    for (i = 0; i < plugins->count; i++) {
5523e9
+	name = plugins->names[i];
5523e9
+	RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_TSM_POST);
5523e9
+	if (hookFunc(ts, res) == RPMRC_FAIL)
5523e9
+	    rc = RPMRC_FAIL;
5523e9
+    }
5523e9
+
5523e9
+    return rc;
5523e9
+}
5523e9
+
5523e9
+rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te)
5523e9
+{
5523e9
+    rpmRC (*hookFunc)(rpmte);
5523e9
+    int i;
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    const char *name = NULL;
5523e9
+
5523e9
+    for (i = 0; i < plugins->count; i++) {
5523e9
+	name = plugins->names[i];
5523e9
+	RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_PRE);
5523e9
+	if (hookFunc(te) == RPMRC_FAIL)
5523e9
+	    rc = RPMRC_FAIL;
5523e9
+    }
5523e9
+
5523e9
+    return rc;
5523e9
+}
5523e9
+
5523e9
+rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res)
5523e9
+{
5523e9
+    rpmRC (*hookFunc)(rpmte, int);
5523e9
+    int i;
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    const char *name = NULL;
5523e9
+
5523e9
+    for (i = 0; i < plugins->count; i++) {
5523e9
+	name = plugins->names[i];
5523e9
+	RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_PSM_POST);
5523e9
+	if (hookFunc(te, res) == RPMRC_FAIL)
5523e9
+	    rc = RPMRC_FAIL;
5523e9
+    }
5523e9
+
5523e9
+    return rc;
5523e9
+}
5523e9
+
5523e9
+rpmRC rpmpluginsCallScriptSetup(rpmPlugins plugins, char* path)
5523e9
+{
5523e9
+    rpmRC (*hookFunc)(char*);
5523e9
+    int i;
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    const char *name = NULL;
5523e9
+
5523e9
+    for (i = 0; i < plugins->count; i++) {
5523e9
+	name = plugins->names[i];
5523e9
+	RPMPLUGINS_SET_HOOK_FUNC(PLUGINHOOK_SCRIPT_SETUP);
5523e9
+	if (hookFunc(path) == RPMRC_FAIL)
5523e9
+	    rc = RPMRC_FAIL;
5523e9
+    }
5523e9
+
5523e9
+    return rc;
5523e9
+}
5523e9
diff --git a/lib/rpmplugins.h b/lib/rpmplugins.h
5523e9
index 7985559..c462eae 100644
5523e9
--- a/lib/rpmplugins.h
5523e9
+++ b/lib/rpmplugins.h
5523e9
@@ -11,11 +11,20 @@ extern "C" {
5523e9
 
5523e9
 #define PLUGINHOOK_INIT_FUNC			pluginhook_init
5523e9
 #define PLUGINHOOK_CLEANUP_FUNC			pluginhook_cleanup
5523e9
+
5523e9
 #define PLUGINHOOK_OPENTE_FUNC			pluginhook_opente
5523e9
 #define PLUGINHOOK_COLL_POST_ADD_FUNC		pluginhook_coll_post_add
5523e9
 #define PLUGINHOOK_COLL_POST_ANY_FUNC		pluginhook_coll_post_any
5523e9
 #define PLUGINHOOK_COLL_PRE_REMOVE_FUNC		pluginhook_coll_pre_remove
5523e9
 
5523e9
+#define PLUGINHOOK_TSM_PRE_FUNC        pluginhook_tsm_pre
5523e9
+#define PLUGINHOOK_TSM_POST_FUNC        pluginhook_tsm_post
5523e9
+
5523e9
+#define PLUGINHOOK_PSM_PRE_FUNC        pluginhook_psm_pre
5523e9
+#define PLUGINHOOK_PSM_POST_FUNC        pluginhook_psm_post
5523e9
+ 
5523e9
+#define PLUGINHOOK_SCRIPT_SETUP_FUNC    pluginhook_script_setup
5523e9
+
5523e9
 enum rpmPluginHook_e {
5523e9
     PLUGINHOOK_NONE		= 0,
5523e9
     PLUGINHOOK_INIT		= 1 << 0,
5523e9
@@ -23,7 +32,12 @@ enum rpmPluginHook_e {
5523e9
     PLUGINHOOK_OPENTE		= 1 << 2,
5523e9
     PLUGINHOOK_COLL_POST_ADD	= 1 << 3,
5523e9
     PLUGINHOOK_COLL_POST_ANY	= 1 << 4,
5523e9
-    PLUGINHOOK_COLL_PRE_REMOVE	= 1 << 5
5523e9
+    PLUGINHOOK_COLL_PRE_REMOVE	= 1 << 5,
5523e9
+    PLUGINHOOK_TSM_PRE         = 1 << 6,
5523e9
+    PLUGINHOOK_TSM_POST        = 1 << 7,
5523e9
+    PLUGINHOOK_PSM_PRE         = 1 << 8,
5523e9
+    PLUGINHOOK_PSM_POST        = 1 << 9,
5523e9
+    PLUGINHOOK_SCRIPT_SETUP    = 1 << 10
5523e9
 };
5523e9
 
5523e9
 typedef rpmFlags rpmPluginHook;
5523e9
@@ -53,12 +67,13 @@ rpmPlugins rpmpluginsFree(rpmPlugins plugins);
5523e9
 rpmRC rpmpluginsAdd(rpmPlugins plugins, const char *name, const char *path, const char *opts);
5523e9
 
5523e9
 /** \ingroup rpmplugins
5523e9
- * Add and open a collection plugin
5523e9
+ * Add and open a rpm plugin
5523e9
  * @param plugins	plugins structure to add a collection plugin to
5523e9
- * @param name		name of collection to open
5523e9
+ * @param type     type of plugin
5523e9
+ * @param name		name of plugin
5523e9
  * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
  */
5523e9
-rpmRC rpmpluginsAddCollectionPlugin(rpmPlugins plugins, const char *name);
5523e9
+rpmRC rpmpluginsAddPlugin(rpmPlugins plugins, const char *type, const char *name);
5523e9
 
5523e9
 /** \ingroup rpmplugins
5523e9
  * Determine if a plugin has been added already
5523e9
@@ -119,6 +134,48 @@ rpmRC rpmpluginsCallCollectionPostAny(rpmPlugins plugins, const char *name);
5523e9
  */
5523e9
 rpmRC rpmpluginsCallCollectionPreRemove(rpmPlugins plugins, const char *name);
5523e9
 
5523e9
+/** \ingroup rpmplugins
5523e9
+ * Call the pre transaction plugin hook
5523e9
+ * @param plugins	plugins structure
5523e9
+ * @param ts		processed transaction
5523e9
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
+ */
5523e9
+rpmRC rpmpluginsCallTsmPre(rpmPlugins plugins, rpmts ts);
5523e9
+
5523e9
+/** \ingroup rpmplugins
5523e9
+ * Call the post transaction plugin hook
5523e9
+ * @param plugins	plugins structure
5523e9
+ * @param ts		processed transaction
5523e9
+ * @param res		transaction result code
5523e9
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
+ */
5523e9
+rpmRC rpmpluginsCallTsmPost(rpmPlugins plugins, rpmts ts, int res);
5523e9
+
5523e9
+/** \ingroup rpmplugins
5523e9
+ * Call the pre transaction element plugin hook
5523e9
+ * @param plugins	plugins structure
5523e9
+ * @param te		processed transaction element
5523e9
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
+ */
5523e9
+rpmRC rpmpluginsCallPsmPre(rpmPlugins plugins, rpmte te);
5523e9
+
5523e9
+/** \ingroup rpmplugins
5523e9
+ * Call the post transaction element plugin hook
5523e9
+ * @param plugins	plugins structure
5523e9
+ * @param te		processed transaction element
5523e9
+ * @param res		transaction element result code
5523e9
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
+ */
5523e9
+rpmRC rpmpluginsCallPsmPost(rpmPlugins plugins, rpmte te, int res);
5523e9
+
5523e9
+/** \ingroup rpmplugins
5523e9
+ * Call the script setup plugin hook
5523e9
+ * @param plugins	plugins structure
5523e9
+ * @param path		script path
5523e9
+ * @return		RPMRC_OK on success, RPMRC_FAIL otherwise
5523e9
+ */
5523e9
+rpmRC rpmpluginsCallScriptSetup(rpmPlugins plugins, char* path);
5523e9
+
5523e9
 #ifdef __cplusplus
5523e9
 }
5523e9
 #endif
5523e9
diff --git a/lib/rpmscript.c b/lib/rpmscript.c
5523e9
index 57c24c6..f8c5fc7 100644
5523e9
--- a/lib/rpmscript.c
5523e9
+++ b/lib/rpmscript.c
5523e9
@@ -14,6 +14,8 @@
5523e9
 #include "rpmio/rpmlua.h"
5523e9
 #include "lib/rpmscript.h"
5523e9
 
5523e9
+#include "lib/rpmplugins.h"     /* rpm plugins hooks */
5523e9
+
5523e9
 #include "debug.h"
5523e9
 
5523e9
 struct rpmScript_s {
5523e9
@@ -91,7 +93,7 @@ static rpmRC runLuaScript(int selinux, ARGV_const_t prefixes,
5523e9
 
5523e9
 static const char * const SCRIPT_PATH = "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin";
5523e9
 
5523e9
-static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
5523e9
+static void doScriptExec(rpmPlugins plugins, int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
5523e9
 			FD_t scriptFd, FD_t out)
5523e9
 {
5523e9
     int pipes[2];
5523e9
@@ -169,7 +171,10 @@ static void doScriptExec(int selinux, ARGV_const_t argv, ARGV_const_t prefixes,
5523e9
 	}
5523e9
 
5523e9
 	if (xx == 0) {
5523e9
-	    xx = execv(argv[0], argv);
5523e9
+	    /* Run script setup hook for all plugins */
5523e9
+	    if (rpmpluginsCallScriptSetup(plugins, argv[0]) != RPMRC_FAIL) {
5523e9
+		xx = execv(argv[0], argv);
5523e9
+	    }
5523e9
 	}
5523e9
     }
5523e9
     _exit(127); /* exit 127 for compatibility with bash(1) */
5523e9
@@ -202,7 +207,7 @@ exit:
5523e9
 /**
5523e9
  * Run an external script.
5523e9
  */
5523e9
-static rpmRC runExtScript(int selinux, ARGV_const_t prefixes,
5523e9
+static rpmRC runExtScript(rpmPlugins plugins, int selinux, ARGV_const_t prefixes,
5523e9
 		   const char *sname, rpmlogLvl lvl, FD_t scriptFd,
5523e9
 		   ARGV_t * argvp, const char *script, int arg1, int arg2)
5523e9
 {
5523e9
@@ -258,7 +263,7 @@ static rpmRC runExtScript(int selinux, ARGV_const_t prefixes,
5523e9
     } else if (pid == 0) {/* Child */
5523e9
 	rpmlog(RPMLOG_DEBUG, "%s: execv(%s) pid %d\n",
5523e9
 	       sname, *argvp[0], (unsigned)getpid());
5523e9
-	doScriptExec(selinux, *argvp, prefixes, scriptFd, out);
5523e9
+	doScriptExec(plugins, selinux, *argvp, prefixes, scriptFd, out);
5523e9
     }
5523e9
 
5523e9
     do {
5523e9
@@ -297,7 +302,7 @@ exit:
5523e9
 }
5523e9
 
5523e9
 rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
5523e9
-		   ARGV_const_t prefixes, int warn_only, int selinux)
5523e9
+		   ARGV_const_t prefixes, int warn_only, int selinux, rpmPlugins plugins)
5523e9
 {
5523e9
     ARGV_t args = NULL;
5523e9
     rpmlogLvl lvl = warn_only ? RPMLOG_WARNING : RPMLOG_ERR;
5523e9
@@ -315,7 +320,7 @@ rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
5523e9
     if (rstreq(args[0], "<lua>")) {
5523e9
 	rc = runLuaScript(selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
5523e9
     } else {
5523e9
-	rc = runExtScript(selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
5523e9
+	rc = runExtScript(plugins, selinux, prefixes, script->descr, lvl, scriptFd, &args, script->body, arg1, arg2);
5523e9
     }
5523e9
     argvFree(args);
5523e9
 
5523e9
diff --git a/lib/rpmscript.h b/lib/rpmscript.h
5523e9
index 7d584bc..852735b 100644
5523e9
--- a/lib/rpmscript.h
5523e9
+++ b/lib/rpmscript.h
5523e9
@@ -29,7 +29,7 @@ rpmScript rpmScriptFree(rpmScript script);
5523e9
 
5523e9
 RPM_GNUC_INTERNAL
5523e9
 rpmRC rpmScriptRun(rpmScript script, int arg1, int arg2, FD_t scriptFd,
5523e9
-                   ARGV_const_t prefixes, int warn_only, int selinux);
5523e9
+                   ARGV_const_t prefixes, int warn_only, int selinux, rpmPlugins plugins);
5523e9
 
5523e9
 RPM_GNUC_INTERNAL
5523e9
 rpmTagVal rpmScriptTag(rpmScript script);
5523e9
diff --git a/lib/rpmte.c b/lib/rpmte.c
5523e9
index 87fb391..9fc5522 100644
5523e9
--- a/lib/rpmte.c
5523e9
+++ b/lib/rpmte.c
5523e9
@@ -889,7 +889,7 @@ rpmRC rpmteSetupCollectionPlugins(rpmte te)
5523e9
     rpmteOpen(te, 0);
5523e9
     for (; colls && *colls; colls++) {
5523e9
 	if (!rpmpluginsPluginAdded(plugins, *colls)) {
5523e9
-	    rc = rpmpluginsAddCollectionPlugin(plugins, *colls);
5523e9
+	    rc = rpmpluginsAddPlugin(plugins, "collection", *colls);
5523e9
 	    if (rc != RPMRC_OK) {
5523e9
 		break;
5523e9
 	    }
5523e9
diff --git a/lib/transaction.c b/lib/transaction.c
5523e9
index 45c30b5..08a5643 100644
5523e9
--- a/lib/transaction.c
5523e9
+++ b/lib/transaction.c
5523e9
@@ -22,6 +22,8 @@
5523e9
 #include "lib/rpmts_internal.h"
5523e9
 #include "rpmio/rpmhook.h"
5523e9
 
5523e9
+#include "lib/rpmplugins.h"
5523e9
+
5523e9
 /* XXX FIXME: merge with existing (broken?) tests in system.h */
5523e9
 /* portability fiddles */
5523e9
 #if STATFS_IN_SYS_STATVFS
5523e9
@@ -1435,12 +1437,43 @@ static int rpmtsProcess(rpmts ts)
5523e9
     return rc;
5523e9
 }
5523e9
 
5523e9
+static rpmRC rpmtsSetupTransactionPlugins(rpmts ts)
5523e9
+{
5523e9
+    rpmRC rc = RPMRC_OK;
5523e9
+    char *plugins = NULL, *plugin = NULL;
5523e9
+    const char *delims = ",";
5523e9
+
5523e9
+    plugins = rpmExpand("%{?__transaction_plugins}", NULL);
5523e9
+    if (!plugins || rstreq(plugins, "")) {
5523e9
+	goto exit;
5523e9
+    }
5523e9
+
5523e9
+    plugin = strtok(plugins, delims);
5523e9
+    while(plugin != NULL) {
5523e9
+	rpmlog(RPMLOG_DEBUG, "plugin is %s\n", plugin);
5523e9
+	if (!rpmpluginsPluginAdded(ts->plugins, (const char*)plugin)) {
5523e9
+	    if (rpmpluginsAddPlugin(ts->plugins, "transaction",
5523e9
+				    (const char*)plugin) == RPMRC_FAIL) {
5523e9
+		/* any configured plugin failing to load is a failure */
5523e9
+		rc = RPMRC_FAIL;
5523e9
+	    }
5523e9
+	}
5523e9
+	plugin = strtok(NULL, delims);
5523e9
+    }
5523e9
+
5523e9
+exit:
5523e9
+    free(plugins);
5523e9
+    return rc;
5523e9
+}
5523e9
+
5523e9
 int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
5523e9
 {
5523e9
     int rc = -1; /* assume failure */
5523e9
     tsMembers tsmem = rpmtsMembers(ts);
5523e9
     rpmlock lock = NULL;
5523e9
     rpmps tsprobs = NULL;
5523e9
+    int TsmPreDone = 0; /* TsmPre hook hasn't been called */
5523e9
+    
5523e9
     /* Force default 022 umask during transaction for consistent results */
5523e9
     mode_t oldmask = umask(022);
5523e9
 
5523e9
@@ -1462,11 +1495,21 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
5523e9
 	goto exit;
5523e9
     }
5523e9
 
5523e9
+    if (rpmtsSetupTransactionPlugins(ts) == RPMRC_FAIL) {
5523e9
+	goto exit;
5523e9
+    }
5523e9
+
5523e9
     rpmtsSetupCollections(ts);
5523e9
 
5523e9
     /* Check package set for problems */
5523e9
     tsprobs = checkProblems(ts);
5523e9
 
5523e9
+    /* Run pre transaction hook for all plugins */
5523e9
+    TsmPreDone = 1;
5523e9
+    if (rpmpluginsCallTsmPre(ts->plugins, ts) == RPMRC_FAIL) {
5523e9
+	goto exit;
5523e9
+    }
5523e9
+
5523e9
     /* Run pre-transaction scripts, but only if there are no known
5523e9
      * problems up to this point and not disabled otherwise. */
5523e9
     if (!((rpmtsFlags(ts) & (RPMTRANS_FLAG_BUILD_PROBS|RPMTRANS_FLAG_NOPRE))
5523e9
@@ -1511,6 +1554,10 @@ int rpmtsRun(rpmts ts, rpmps okProbs, rpmprobFilterFlags ignoreSet)
5523e9
     }
5523e9
 
5523e9
 exit:
5523e9
+    /* Run post transaction hook for all plugins */
5523e9
+    if (TsmPreDone) /* If TsmPre hook has been called, call the TsmPost hook */
5523e9
+	rpmpluginsCallTsmPost(ts->plugins, ts, rc);
5523e9
+
5523e9
     /* Finish up... */
5523e9
     (void) umask(oldmask);
5523e9
     (void) rpmtsFinish(ts);
5523e9
diff --git a/macros.in b/macros.in
5523e9
index 3aaebcd..fb030b5 100644
5523e9
--- a/macros.in
5523e9
+++ b/macros.in
5523e9
@@ -1032,6 +1032,9 @@ done \
5523e9
 %__collection_sepolicy		%{__plugindir}/sepolicy.so
5523e9
 %__collection_sepolicy_flags	1
5523e9
 
5523e9
+# Transaction plugin macros
5523e9
+%__transaction_systemd_inhibit	%{__plugindir}/systemd_inhibit.so
5523e9
+
5523e9
 #------------------------------------------------------------------------------
5523e9
 # Macros for further automated spec %setup and patch application
5523e9
 
5523e9
diff --git a/plugins/Makefile.am b/plugins/Makefile.am
5523e9
index a9c962c..0c0a410 100644
5523e9
--- a/plugins/Makefile.am
5523e9
+++ b/plugins/Makefile.am
5523e9
@@ -24,3 +24,10 @@ sepolicy_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmi
5523e9
 
5523e9
 plugins_LTLIBRARIES += sepolicy.la
5523e9
 endif
5523e9
+
5523e9
+if DBUS
5523e9
+systemd_inhibit_la_SOURCES = systemd_inhibit.c
5523e9
+systemd_inhibit_la_CPPFLAGS = $(AM_CPPFLAGS) @DBUS_CFLAGS@
5523e9
+systemd_inhibit_la_LIBADD = $(top_builddir)/lib/librpm.la $(top_builddir)/rpmio/librpmio.la @DBUS_LIBS@
5523e9
+plugins_LTLIBRARIES += systemd_inhibit.la
5523e9
+endif
5523e9
diff --git a/plugins/plugin.h b/plugins/plugin.h
5523e9
index 5156f93..ad4171a 100644
5523e9
--- a/plugins/plugin.h
5523e9
+++ b/plugins/plugin.h
5523e9
@@ -7,9 +7,23 @@
5523e9
 #include "lib/rpmplugins.h"
5523e9
 #include "lib/rpmchroot.h"
5523e9
 
5523e9
+/* general plugin hooks */
5523e9
 rpmRC PLUGINHOOK_INIT_FUNC(rpmts ts, const char * name, const char * opts);
5523e9
 rpmRC PLUGINHOOK_CLEANUP_FUNC(void);
5523e9
+
5523e9
+/* collection plugin hooks */
5523e9
 rpmRC PLUGINHOOK_OPENTE_FUNC(rpmte te);
5523e9
 rpmRC PLUGINHOOK_COLL_POST_ANY_FUNC(void);
5523e9
 rpmRC PLUGINHOOK_COLL_POST_ADD_FUNC(void);
5523e9
 rpmRC PLUGINHOOK_COLL_PRE_REMOVE_FUNC(void);
5523e9
+
5523e9
+/* per transaction plugin hooks */
5523e9
+rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts);
5523e9
+rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int res);
5523e9
+
5523e9
+/* per transaction element plugin hooks */
5523e9
+rpmRC PLUGINHOOK_PSM_PRE_FUNC(rpmte te);
5523e9
+rpmRC PLUGINHOOK_PSM_POST_FUNC(rpmte te, int res);
5523e9
+
5523e9
+/*per script plugin hooks */
5523e9
+rpmRC PLUGINHOOK_SCRIPT_SETUP_FUNC(char* path);
5523e9
diff --git a/plugins/systemd_inhibit.c b/plugins/systemd_inhibit.c
5523e9
new file mode 100644
5523e9
index 0000000..e990bec
5523e9
--- /dev/null
5523e9
+++ b/plugins/systemd_inhibit.c
5523e9
@@ -0,0 +1,111 @@
5523e9
+#include <dbus/dbus.h>
5523e9
+#include <sys/types.h>
5523e9
+#include <sys/stat.h>
5523e9
+#include <unistd.h>
5523e9
+#include <rpm/rpmlog.h>
5523e9
+#include <rpm/rpmts.h>
5523e9
+#include "plugin.h"
5523e9
+
5523e9
+rpmPluginHook PLUGIN_HOOKS = (
5523e9
+    PLUGINHOOK_INIT |
5523e9
+    PLUGINHOOK_CLEANUP |
5523e9
+    PLUGINHOOK_TSM_PRE |
5523e9
+    PLUGINHOOK_TSM_POST
5523e9
+);
5523e9
+
5523e9
+static int lock_fd = -1;
5523e9
+
5523e9
+rpmRC PLUGINHOOK_INIT_FUNC(rpmts ts, const char *name, const char *opts)
5523e9
+{
5523e9
+    struct stat st;
5523e9
+
5523e9
+    if (lstat("/run/systemd/system/", &st) == 0) {
5523e9
+        if (S_ISDIR(st.st_mode)) {
5523e9
+            return RPMRC_OK;
5523e9
+        }
5523e9
+    }
5523e9
+
5523e9
+    return RPMRC_NOTFOUND;
5523e9
+}
5523e9
+
5523e9
+rpmRC PLUGINHOOK_CLEANUP_FUNC(void)
5523e9
+{
5523e9
+    return RPMRC_OK;
5523e9
+}
5523e9
+
5523e9
+static int inhibit(void)
5523e9
+{
5523e9
+    DBusError err;
5523e9
+    DBusConnection *bus = NULL;
5523e9
+    DBusMessage *msg = NULL;
5523e9
+    DBusMessage *reply = NULL;
5523e9
+    int fd = -1;
5523e9
+
5523e9
+    dbus_error_init(&err;;
5523e9
+    bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &err;;
5523e9
+
5523e9
+    if (bus) {
5523e9
+	msg = dbus_message_new_method_call("org.freedesktop.login1",
5523e9
+					   "/org/freedesktop/login1",
5523e9
+					   "org.freedesktop.login1.Manager",
5523e9
+					   "Inhibit");
5523e9
+    }
5523e9
+
5523e9
+    if (msg) {
5523e9
+	const char *what = "shutdown";
5523e9
+	const char *mode = "block";
5523e9
+	const char *who = "RPM";
5523e9
+	const char *reason = "Transaction running";
5523e9
+
5523e9
+	dbus_message_append_args(msg,
5523e9
+				 DBUS_TYPE_STRING, &what,
5523e9
+				 DBUS_TYPE_STRING, &who,
5523e9
+				 DBUS_TYPE_STRING, &reason,
5523e9
+				 DBUS_TYPE_STRING, &mode,
5523e9
+				 DBUS_TYPE_INVALID);
5523e9
+
5523e9
+	reply = dbus_connection_send_with_reply_and_block(bus, msg, -1, &err;;
5523e9
+	dbus_message_unref(msg);
5523e9
+    }
5523e9
+
5523e9
+    if (reply) {
5523e9
+	dbus_message_get_args(reply, &err,
5523e9
+			      DBUS_TYPE_UNIX_FD, &fd,
5523e9
+			      DBUS_TYPE_INVALID);
5523e9
+	dbus_message_unref(reply);
5523e9
+    }
5523e9
+    
5523e9
+    if (dbus_error_is_set(&err))
5523e9
+	dbus_error_free(&err;;
5523e9
+    if (bus)
5523e9
+	dbus_connection_close(bus);
5523e9
+
5523e9
+    return fd;
5523e9
+}
5523e9
+
5523e9
+rpmRC PLUGINHOOK_TSM_PRE_FUNC(rpmts ts)
5523e9
+{
5523e9
+    if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST|RPMTRANS_FLAG_BUILD_PROBS))
5523e9
+	return RPMRC_OK;
5523e9
+
5523e9
+    lock_fd = inhibit();
5523e9
+
5523e9
+    if (lock_fd < 0) {
5523e9
+	rpmlog(RPMLOG_WARNING,
5523e9
+	       "Unable to get systemd shutdown inhibition lock\n");
5523e9
+    } else {
5523e9
+	rpmlog(RPMLOG_DEBUG, "System shutdown blocked (fd %d)\n", lock_fd);
5523e9
+    }
5523e9
+
5523e9
+    return RPMRC_OK;
5523e9
+}
5523e9
+
5523e9
+rpmRC PLUGINHOOK_TSM_POST_FUNC(rpmts ts, int res)
5523e9
+{
5523e9
+    if (lock_fd >= 0) {
5523e9
+	close(lock_fd);
5523e9
+	lock_fd = -1;
5523e9
+	rpmlog(RPMLOG_DEBUG, "System shutdown unblocked\n");
5523e9
+    }
5523e9
+    return RPMRC_OK;
5523e9
+}