implement softdeps.
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
index e6388f2..cb0ec3d 100644
--- a/libkmod/libkmod-module.c
+++ b/libkmod/libkmod-module.c
@@ -34,6 +34,7 @@
#include <sys/types.h>
#include <sys/mman.h>
#include <string.h>
+#include <fnmatch.h>
#include "libkmod.h"
#include "libkmod-private.h"
@@ -52,6 +53,10 @@
char *options;
const char *install_commands; /* owned by kmod_config */
const char *remove_commands; /* owned by kmod_config */
+ struct {
+ struct kmod_list *pre;
+ struct kmod_list *post;
+ } softdeps;
char *alias; /* only set if this module was created from an alias */
int n_dep;
int refcount;
@@ -60,6 +65,7 @@
bool options : 1;
bool install_commands : 1;
bool remove_commands : 1;
+ bool softdeps : 1;
} init;
};
@@ -393,6 +399,8 @@
DBG(mod->ctx, "kmod_module %p released\n", mod);
kmod_pool_del_module(mod->ctx, mod, mod->hashkey);
+ kmod_module_unref_list(mod->softdeps.pre);
+ kmod_module_unref_list(mod->softdeps.post);
kmod_module_unref_list(mod->dep);
kmod_unref(mod->ctx);
free(mod->options);
@@ -851,6 +859,111 @@
mod->install_commands = cmd;
}
+static struct kmod_list *lookup_softdep(struct kmod_ctx *ctx, const char * const * array, unsigned int count)
+{
+ struct kmod_list *ret = NULL;
+ unsigned i;
+
+ for (i = 0; i < count; i++) {
+ const char *depname = array[i];
+ struct kmod_list *lst = NULL;
+ int err;
+
+ err = kmod_module_new_from_lookup(ctx, depname, &lst);
+ if (err < 0) {
+ ERR(ctx, "failed to lookup soft dependency '%s', continuing anyway.\n", depname);
+ continue;
+ } else if (lst != NULL)
+ ret = kmod_list_append_list(ret, lst);
+ }
+ return ret;
+}
+
+/**
+ * kmod_module_get_softdeps:
+ * @mod: kmod module
+ * @pre: where to save the list of preceding soft dependencies.
+ * @post: where to save the list of post soft dependencies.
+ *
+ * Get soft dependencies for this kmod module. Soft dependencies come
+ * from configuration file and are cached in @mod. The first call
+ * to this function will search for this module in configuration and
+ * subsequent calls return the known results.
+ *
+ * Both @pre and @post are newly created list of kmod_module and
+ * should be unreferenced with kmod_module_unref_list().
+ *
+ * Returns: 0 on success or < 0 otherwise.
+ */
+KMOD_EXPORT int kmod_module_get_softdeps(const struct kmod_module *mod, struct kmod_list **pre, struct kmod_list **post)
+{
+ const struct kmod_list *l;
+ struct kmod_list *l_new;
+
+ if (mod == NULL || pre == NULL || post == NULL)
+ return -ENOENT;
+
+ assert(*pre == NULL);
+ assert(*post == NULL);
+
+ if (!mod->init.softdeps) {
+ /* lazy init */
+ struct kmod_module *m = (struct kmod_module *)mod;
+ const struct kmod_list *ctx_softdeps;
+
+ ctx_softdeps = kmod_get_softdeps(mod->ctx);
+
+ kmod_list_foreach(l, ctx_softdeps) {
+ const char *modname = kmod_softdep_get_name(l);
+ const char * const *array;
+ unsigned count;
+
+ if (fnmatch(modname, mod->name, 0) != 0)
+ continue;
+
+ array = kmod_softdep_get_pre(l, &count);
+ m->softdeps.pre = lookup_softdep(mod->ctx, array, count);
+ array = kmod_softdep_get_post(l, &count);
+ m->softdeps.post = lookup_softdep(mod->ctx, array, count);
+ /*
+ * find only the first command, as modprobe from
+ * module-init-tools does
+ */
+ break;
+ }
+
+ m->init.softdeps = true;
+ }
+
+ kmod_list_foreach(l, mod->softdeps.pre) {
+ l_new = kmod_list_append(*pre, kmod_module_ref(l->data));
+ if (l_new == NULL) {
+ kmod_module_unref(l->data);
+ goto fail;
+ }
+ *pre = l_new;
+ }
+
+ kmod_list_foreach(l, mod->softdeps.post) {
+ l_new = kmod_list_append(*post, kmod_module_ref(l->data));
+ if (l_new == NULL) {
+ kmod_module_unref(l->data);
+ goto fail;
+ }
+ *post = l_new;
+ }
+
+ return 0;
+
+fail:
+ kmod_module_unref_list(*pre);
+ *pre = NULL;
+ kmod_module_unref_list(*post);
+ *post = NULL;
+ return -ENOMEM;
+}
+
+
/**
* kmod_module_get_remove_commands:
* @mod: kmod module