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 |   26 +++++++++++
 lib/poptI.c       |    4 ++
 lib/rpmte.c       |  130 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 lib/rpmts.h       |    1 +
 system.h          |    2 +
 6 files changed, 165 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..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 5304e7b..2c33605 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"
@@ -813,6 +815,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 */
@@ -827,11 +952,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 <dlfcn.h>
+
 #endif /* H_SYSTEM */
-- 
1.6.2.5

_______________________________________________
Rpm-maint mailing list
Rpm-maint@lists.rpm.org
http://lists.rpm.org/mailman/listinfo/rpm-maint

Reply via email to