[Rpm-maint] [PATCH 4/5] Add plugin calling support

Steve Lawrence slawrence at tresys.com
Thu Jun 17 19:55:26 UTC 2010


This patch adds a simple plugin system that makes simple problems easy to
solve, and difficult problems, such as SELinux, possible.

When the transaction gets to the point where a collection action should occur,
it expands a macro of the form %__collection_<collection name> to get the path
to a plugin and any additional options. The plugin is dlopen'ed, and the
appropriate function is called in the plugin, with the additional arguments
passed in.

This also adds a --nocollections option to disable performing Collection
actions.
---
 lib/Makefile.am   |    3 +-
 lib/collections.h |   27 ++++++++++++
 lib/poptI.c       |    4 ++
 lib/rpmts.h       |    1 +
 lib/transaction.c |  114 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 system.h          |    2 +
 6 files changed, 150 insertions(+), 1 deletions(-)
 create mode 100644 lib/collections.h

diff --git a/lib/Makefile.am b/lib/Makefile.am
index c308bc6..1357c7c 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -33,7 +33,8 @@ librpm_la_SOURCES = \
 	rpmvercmp.c signature.c signature.h transaction.c \
 	verify.c rpmlock.c rpmlock.h misc.h \
 	rpmscript.h rpmscript.c legacy.c merge.c \
-	rpmliblua.c rpmliblua.h rpmchroot.c rpmchroot.h
+	rpmliblua.c rpmliblua.h rpmchroot.c rpmchroot.h \
+	collections.h
 
 librpm_la_LDFLAGS = -version-info 1:0:0
 
diff --git a/lib/collections.h b/lib/collections.h
new file mode 100644
index 0000000..06ac79b
--- /dev/null
+++ b/lib/collections.h
@@ -0,0 +1,27 @@
+#ifndef _COLLECTIONS_H
+#define _COLLECTIONS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef rpmRC(*collHookFunc)(rpmts, const char *, const char *);
+
+#define COLLHOOK_POST_ADD_FUNC		post_add
+#define COLLHOOK_POST_ANY_FUNC		post_any
+#define COLLHOOK_PRE_REMOVE_FUNC	pre_remove
+
+#define COLLECTION_HOOKS	collection_hooks
+typedef enum rpmCollHook_e {
+	COLLHOOK_NONE		= 0,
+	COLLHOOK_POST_ADD	= 1 << 0,
+	COLLHOOK_POST_ANY	= 1 << 1,
+	COLLHOOK_PRE_REMOVE	= 1 << 2
+} rpmCollHook;
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _COLLECTIONS_H */
diff --git a/lib/poptI.c b/lib/poptI.c
index 5021f17..c30c3b5 100644
--- a/lib/poptI.c
+++ b/lib/poptI.c
@@ -254,6 +254,10 @@ struct poptOption rpmInstallPoptTable[] = {
 	&rpmIArgs.transFlags, RPMTRANS_FLAG_NOTRIGGERPOSTUN,
 	N_("do not execute any %%triggerpostun scriptlet(s)"), NULL},
 
+ { "nocollections", '\0', POPT_BIT_SET,
+	&rpmIArgs.transFlags, RPMTRANS_FLAG_NOCOLLECTIONS,
+	N_("do not perform any collection actions"), NULL},
+
  { "oldpackage", '\0', POPT_BIT_SET,
 	&rpmIArgs.probFilter, RPMPROB_FILTER_OLDPACKAGE,
 	N_("upgrade to an old version of the package (--force on upgrades does this automatically)"),
diff --git a/lib/rpmts.h b/lib/rpmts.h
index a30ca30..9b7c306 100644
--- a/lib/rpmts.h
+++ b/lib/rpmts.h
@@ -55,6 +55,7 @@ typedef enum rpmtransFlags_e {
     RPMTRANS_FLAG_NOTRIGGERPOSTUN = (1 << 23),	/*!< from --notriggerpostun */
     RPMTRANS_FLAG_NOPAYLOAD	= (1 << 24),
     RPMTRANS_FLAG_APPLYONLY	= (1 << 25),
+    RPMTRANS_FLAG_NOCOLLECTIONS	= (1 << 26),	/*!< from --nocollections */
 
     RPMTRANS_FLAG_NOMD5		= (1 << 27),	/*!< from --nomd5 */
     RPMTRANS_FLAG_NOFILEDIGEST	= (1 << 27),	/*!< from --nofiledigest (alias to --nomd5) */
diff --git a/lib/transaction.c b/lib/transaction.c
index 4c5cdb3..0b30125 100644
--- a/lib/transaction.c
+++ b/lib/transaction.c
@@ -12,6 +12,7 @@
 #include <rpm/rpmfileutil.h>
 #include <rpm/rpmstring.h>
 
+#include "lib/collections.h"
 #include "lib/fprint.h"
 #include "lib/misc.h"
 #include "lib/rpmchroot.h"
@@ -1374,6 +1375,98 @@ exit:
     return rc;
 }
 
+static int rpmtsRunCollection(rpmts ts, const char * collname, rpmCollHook hook)
+{
+#define STR1(x) #x
+#define STR(x) STR1(x)
+
+	void * handle = NULL;
+	collHookFunc hookFunc;
+	const char * hookFuncSym;
+	rpmCollHook * pluginHooks;
+	char * plugin;
+	char * options;
+	char * error;
+	int rc = RPMRC_FAIL;
+
+	if (rpmtsFlags(ts) & RPMTRANS_FLAG_NOCOLLECTIONS) {
+		return RPMRC_OK;
+	}
+
+	plugin = rpmExpand("%{?__collection_", collname, "}", NULL);
+	if (!plugin || rstreq(plugin, "")) {
+		fprintf(stderr, "Failed to expand %%__collection_%s macro\n", collname);
+		goto exit;
+	}
+
+	/* split the options from the plugin string */
+#define SKIPSPACE(s)    { while (*(s) &&  risspace(*(s))) (s)++; }
+#define SKIPNONSPACE(s) { while (*(s) && !risspace(*(s))) (s)++; }
+	options = plugin;
+	SKIPNONSPACE(options);
+	if (risspace(*options)) {
+		*options = '\0';
+		options++;
+		SKIPSPACE(options);
+	}
+	if (*options == '\0') {
+		options = NULL;
+	}
+
+	handle = dlopen(plugin, RTLD_LAZY);
+	if (!handle) {
+		fprintf(stderr, "Failed to open %s: %s\n", plugin, dlerror());
+		goto exit;
+	}
+
+	dlerror();
+
+	pluginHooks = (rpmCollHook *)dlsym(handle, STR(COLLECTION_HOOKS));
+	if ((error = dlerror()) != NULL) {
+		fprintf(stderr, "Failed to resolve symbol: %s\n", STR(COLLECTION_HOOKS));
+		goto exit;
+	}
+
+	if (!(*pluginHooks & hook)) {
+		/* plugin doesn't support this hook, exit */
+		rc = RPMRC_OK;
+		goto exit;
+	}
+
+	switch(hook) {
+	case COLLHOOK_POST_ADD:
+		hookFuncSym = STR(COLLHOOK_POST_ADD_FUNC);
+		break;
+	case COLLHOOK_POST_ANY:
+		hookFuncSym = STR(COLLHOOK_POST_ANY_FUNC);
+		break;
+	case COLLHOOK_PRE_REMOVE:
+		hookFuncSym = STR(COLLHOOK_PRE_REMOVE_FUNC);
+		break;
+	default:
+		goto exit;
+	}
+
+	*(void **) (&hookFunc) = dlsym(handle, hookFuncSym);
+	if ((error = dlerror()) != NULL) {
+		fprintf(stderr, "Failed to resolve symbol %s: %s\n", hookFuncSym, error);
+		goto exit;
+	}
+
+	if (rpmtsFlags(ts) & (RPMTRANS_FLAG_TEST | RPMTRANS_FLAG_JUSTDB)) {
+		/* don't perform the action if --test or --justdb are set */
+		rc = RPMRC_OK;
+	} else {
+		rc = (*hookFunc)(ts, collname, options);
+	}
+
+exit:
+	if (handle) dlclose(handle);
+	_free(plugin);
+
+	return rc;
+}
+
 /*
  * Transaction main loop: install and remove packages
  */
@@ -1385,10 +1478,18 @@ static int rpmtsProcess(rpmts ts)
     pi = rpmtsiInit(ts);
     while ((p = rpmtsiNext(pi, 0)) != NULL) {
 	int failed;
+	ARGV_const_t colls;
 
 	rpmlog(RPMLOG_DEBUG, "========== +++ %s %s-%s 0x%x\n",
 		rpmteNEVR(p), rpmteA(p), rpmteO(p), rpmteColor(p));
 
+	/* execute any pre collection actions */
+	for (colls = rpmteFirstInCollectionRemove(p); colls && *colls; colls++) {
+	    if (rpmtsRunCollection(ts, *colls, COLLHOOK_PRE_REMOVE) != RPMRC_OK) {
+	        rc++;
+	    }
+	}
+
 	failed = rpmteProcess(p, rpmteType(p));
 	if (failed) {
 	    rpmlog(RPMLOG_ERR, "%s: %s %s\n", rpmteNEVRA(p),
@@ -1396,6 +1497,19 @@ static int rpmtsProcess(rpmts ts)
 	    rc++;
 	}
 	(void) rpmdbSync(rpmtsGetRdb(ts));
+
+	/* execute any post collection actions */
+	for (colls = rpmteLastInCollectionAdd(p); colls && *colls; colls++) {
+	    if (rpmtsRunCollection(ts, *colls, COLLHOOK_POST_ADD) != RPMRC_OK) {
+	        rc++;
+	    }
+	}
+
+	for (colls = rpmteLastInCollectionAny(p); colls && *colls; colls++) {
+	    if (rpmtsRunCollection(ts, *colls, COLLHOOK_POST_ANY) != RPMRC_OK) {
+	        rc++;
+	    }
+	}
     }
     pi = rpmtsiFree(pi);
     return rc;
diff --git a/system.h b/system.h
index ac18e16..e34f6d6 100644
--- a/system.h
+++ b/system.h
@@ -144,4 +144,6 @@ extern const char *__progname;
 #include "misc/fnmatch.h"
 #endif
 
+#include <dlfcn.h>
+
 #endif	/* H_SYSTEM */
-- 
1.6.2.5



More information about the Rpm-maint mailing list