summaryrefslogtreecommitdiff
path: root/lib
diff options
context:
space:
mode:
authorSteve Lawrence <slawrence@tresys.com>2010-06-21 17:04:39 -0400
committerPanu Matilainen <pmatilai@redhat.com>2010-06-22 11:12:43 +0300
commit04bdec775ac56c7673f87257306b23536a954474 (patch)
tree9b3209bfd02f9bee5311a7d9952e8122ed4be1e0 /lib
parent2fd0913a6abd91389a3f1498ef9c4b2c6c72bff1 (diff)
downloadrpm-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.am3
-rw-r--r--lib/collections.h26
-rw-r--r--lib/poptI.c4
-rw-r--r--lib/rpmte.c130
-rw-r--r--lib/rpmts.h1
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) */