diff options
author | Steve Lawrence <slawrence@tresys.com> | 2010-06-21 17:04:39 -0400 |
---|---|---|
committer | Panu Matilainen <pmatilai@redhat.com> | 2010-06-22 11:12:43 +0300 |
commit | 04bdec775ac56c7673f87257306b23536a954474 (patch) | |
tree | 9b3209bfd02f9bee5311a7d9952e8122ed4be1e0 /lib | |
parent | 2fd0913a6abd91389a3f1498ef9c4b2c6c72bff1 (diff) | |
download | rpm-04bdec775ac56c7673f87257306b23536a954474.tar.gz rpm-04bdec775ac56c7673f87257306b23536a954474.tar.bz2 rpm-04bdec775ac56c7673f87257306b23536a954474.zip |
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_<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.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.am | 3 | ||||
-rw-r--r-- | lib/collections.h | 26 | ||||
-rw-r--r-- | lib/poptI.c | 4 | ||||
-rw-r--r-- | lib/rpmte.c | 130 | ||||
-rw-r--r-- | lib/rpmts.h | 1 |
5 files changed, 163 insertions, 1 deletions
diff --git a/lib/Makefile.am b/lib/Makefile.am index c308bc658..1357c7c5b 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 000000000..78fbaecc4 --- /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 5021f17f9..c30c3b5af 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 7765f70cb..e622558ed 100644 --- a/lib/rpmte.c +++ b/lib/rpmte.c @@ -6,11 +6,13 @@ #include <rpm/rpmtypes.h> #include <rpm/rpmlib.h> /* RPM_MACHTABLE_* */ +#include <rpm/rpmmacro.h> #include <rpm/rpmds.h> #include <rpm/rpmfi.h> #include <rpm/rpmts.h> #include <rpm/rpmdb.h> +#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 a30ca30f2..9b7c30641 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) */ |