From 04bdec775ac56c7673f87257306b23536a954474 Mon Sep 17 00:00:00 2001 From: Steve Lawrence Date: Mon, 21 Jun 2010 17:04:39 -0400 Subject: [PATCH] Add plugin calling support 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_ 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 | 26 +++++++++++ lib/poptI.c | 4 ++ lib/rpmte.c | 130 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ lib/rpmts.h | 1 + system.h | 2 + 6 files changed, 165 insertions(+), 1 deletion(-) 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..78fbaec --- /dev/null +++ b/lib/collections.h @@ -0,0 +1,26 @@ +#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/rpmte.c b/lib/rpmte.c index 7765f70..e622558 100644 --- a/lib/rpmte.c +++ b/lib/rpmte.c @@ -6,11 +6,13 @@ #include #include /* RPM_MACHTABLE_* */ +#include #include #include #include #include +#include "lib/collections.h" #include "lib/rpmte_internal.h" #include "debug.h" @@ -748,6 +750,129 @@ rpmfs rpmteGetFileStates(rpmte te) { return te->fs; } +static int rpmteRunCollection(rpmte te, 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(te->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(te->ts) & (RPMTRANS_FLAG_TEST | RPMTRANS_FLAG_JUSTDB)) { + /* don't perform the action if --test or --justdb are set */ + rc = RPMRC_OK; + } else { + rc = (*hookFunc) (te->ts, collname, options); + } + + exit: + if (handle) + dlclose(handle); + _free(plugin); + + return rc; +} + +static rpmRC rpmteRunAllCollections(rpmte te, rpmCollHook hook) +{ + ARGV_const_t colls; + rpmRC rc = RPMRC_OK; + + switch (hook) { + case COLLHOOK_POST_ADD: + colls = te->lastInCollectionsAdd; + break; + case COLLHOOK_POST_ANY: + colls = te->lastInCollectionsAny; + break; + case COLLHOOK_PRE_REMOVE: + colls = te->firstInCollectionsRemove; + break; + default: + colls = NULL; + } + + for (; colls && *colls; colls++) { + rpmteRunCollection(te, *colls, hook); + } + + return rc; +} + int rpmteProcess(rpmte te, pkgGoal goal) { /* Only install/erase resets pkg file info */ @@ -762,11 +887,16 @@ int rpmteProcess(rpmte te, pkgGoal goal) } } + rpmteRunAllCollections(te, COLLHOOK_PRE_REMOVE); + if (rpmteOpen(te, reset_fi)) { failed = rpmpsmRun(te->ts, te, goal); rpmteClose(te, reset_fi); } + rpmteRunAllCollections(te, COLLHOOK_POST_ADD); + rpmteRunAllCollections(te, COLLHOOK_POST_ANY); + /* XXX should %pretrans failure fail the package install? */ if (failed && !scriptstage) { failed = rpmteMarkFailed(te); 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/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 + #endif /* H_SYSTEM */ -- 2.7.4