]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
implement softdeps.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Fri, 16 Dec 2011 23:18:10 +0000 (21:18 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Sat, 17 Dec 2011 21:43:11 +0000 (19:43 -0200)
TODO
libkmod/libkmod-config.c
libkmod/libkmod-module.c
libkmod/libkmod-private.h
libkmod/libkmod.c
libkmod/libkmod.h
libkmod/libkmod.sym
test/test-lookup.c

diff --git a/TODO b/TODO
index 8ace9992d604bb77164f72955de440d84fb150e9..47a6aa8d55bac43a7867226df09f59a90b745201 100644 (file)
--- a/TODO
+++ b/TODO
@@ -17,8 +17,6 @@ Features:
 
 * Add functions list all modules known by modules.dep
 
-* Implement soft dependencies
-
 * provide 1:1 compatibility with module-init-tools's modprobe
    - show modversions (needs elf manipulation)
    - dump configuration
index b9ef0cdf3f337c897e2348c8ade481797a53b6b7..057c0930c37867681f5da5670d6a2b491c178882 100644 (file)
@@ -48,6 +48,14 @@ struct kmod_command {
        char modname[];
 };
 
+struct kmod_softdep {
+       char *name;
+       const char **pre;
+       const char **post;
+       unsigned int n_pre;
+       unsigned int n_post;
+};
+
 const char *kmod_alias_get_name(const struct kmod_list *l) {
        const struct kmod_alias *alias = l->data;
        return alias->name;
@@ -78,6 +86,23 @@ const char *kmod_command_get_modname(const struct kmod_list *l) {
        return alias->modname;
 }
 
+const char *kmod_softdep_get_name(const struct kmod_list *l) {
+       const struct kmod_softdep *dep = l->data;
+       return dep->name;
+}
+
+const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count) {
+       const struct kmod_softdep *dep = l->data;
+       *count = dep->n_pre;
+       return dep->pre;
+}
+
+const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count) {
+       const struct kmod_softdep *dep = l->data;
+       *count = dep->n_post;
+       return dep->post;
+}
+
 static int kmod_config_add_command(struct kmod_config *config,
                                                const char *modname,
                                                const char *command,
@@ -242,6 +267,149 @@ static void kmod_config_free_blacklist(struct kmod_config *config,
        config->blacklists = kmod_list_remove(l);
 }
 
+static int kmod_config_add_softdep(struct kmod_config *config,
+                                                       const char *modname,
+                                                       const char *line)
+{
+       struct kmod_list *list;
+       struct kmod_softdep *dep;
+       const char *s, *p;
+       char *itr;
+       unsigned int n_pre = 0, n_post = 0;
+       size_t modnamelen = strlen(modname) + 1;
+       size_t buflen = 0;
+       bool was_space = false;
+       enum { S_NONE, S_PRE, S_POST } mode = S_NONE;
+
+       DBG(config->ctx, "modname=%s\n", modname);
+
+       /* analyze and count */
+       for (p = s = line; ; s++) {
+               size_t plen;
+
+               if (*s != '\0') {
+                       if (!isspace(*s)) {
+                               was_space = false;
+                               continue;
+                       }
+
+                       if (was_space) {
+                               p = s + 1;
+                               continue;
+                       }
+                       was_space = true;
+
+                       if (p >= s)
+                               continue;
+               }
+               plen = s - p;
+
+               if (plen == sizeof("pre:") - 1 &&
+                               memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
+                       mode = S_PRE;
+               else if (plen == sizeof("post:") - 1 &&
+                               memcmp(p, "post:", sizeof("post:") - 1) == 0)
+                       mode = S_POST;
+               else if (*s != '\0' || (*s == '\0' && !was_space)) {
+                       if (mode == S_PRE) {
+                               buflen += plen + 1;
+                               n_pre++;
+                       } else if (mode == S_POST) {
+                               buflen += plen + 1;
+                               n_post++;
+                       }
+               }
+               p = s + 1;
+               if (*s == '\0')
+                       break;
+       }
+
+       DBG(config->ctx, "%u pre, %u post\n", n_pre, n_post);
+
+       dep = malloc(sizeof(struct kmod_softdep) + modnamelen +
+                    n_pre * sizeof(const char *) +
+                    n_post * sizeof(const char *) +
+                    buflen);
+       if (dep == NULL) {
+               ERR(config->ctx, "out-of-memory modname=%s\n", modname);
+               return -ENOMEM;
+       }
+       dep->n_pre = n_pre;
+       dep->n_post = n_post;
+       dep->pre = (const char **)((char *)dep + sizeof(struct kmod_softdep));
+       dep->post = dep->pre + n_pre;
+       dep->name = (char *)(dep->post + n_post);
+
+       memcpy(dep->name, modname, modnamelen);
+
+       /* copy strings */
+       itr = dep->name + modnamelen;
+       n_pre = 0;
+       n_post = 0;
+       mode = S_NONE;
+       for (p = s = line; ; s++) {
+               size_t plen;
+
+               if (*s != '\0') {
+                       if (!isspace(*s)) {
+                               was_space = false;
+                               continue;
+                       }
+
+                       if (was_space) {
+                               p = s + 1;
+                               continue;
+                       }
+                       was_space = true;
+
+                       if (p >= s)
+                               continue;
+               }
+               plen = s - p;
+
+               if (plen == sizeof("pre:") - 1 &&
+                               memcmp(p, "pre:", sizeof("pre:") - 1) == 0)
+                       mode = S_PRE;
+               else if (plen == sizeof("post:") - 1 &&
+                               memcmp(p, "post:", sizeof("post:") - 1) == 0)
+                       mode = S_POST;
+               else if (*s != '\0' || (*s == '\0' && !was_space)) {
+                       if (mode == S_PRE) {
+                               dep->pre[n_pre] = itr;
+                               memcpy(itr, p, plen);
+                               itr[plen] = '\0';
+                               itr += plen + 1;
+                               n_pre++;
+                       } else if (mode == S_POST) {
+                               dep->post[n_post] = itr;
+                               memcpy(itr, p, plen);
+                               itr[plen] = '\0';
+                               itr += plen + 1;
+                               n_post++;
+                       }
+               }
+               p = s + 1;
+               if (*s == '\0')
+                       break;
+       }
+
+       list = kmod_list_append(config->softdeps, dep);
+       if (list == NULL) {
+               free(dep);
+               return -ENOMEM;
+       }
+       config->softdeps = list;
+
+       return 0;
+}
+
+static void kmod_config_free_softdep(struct kmod_config *config,
+                                                       struct kmod_list *l)
+{
+       free(l->data);
+       config->softdeps = kmod_list_remove(l);
+}
+
 static void kcmdline_parse_result(struct kmod_config *config, char *modname,
                                                char *param, char *value)
 {
@@ -381,8 +549,16 @@ static int kmod_config_parse(struct kmod_config *config, int fd,
                                        underscores(ctx, modname),
                                        strtok_r(NULL, "\0", &saveptr),
                                        cmd, &config->remove_commands);
+               } else if streq(cmd, "softdep") {
+                       char *modname = strtok_r(NULL, "\t ", &saveptr);
+
+                       if (modname == NULL)
+                               goto syntax_error;
+
+                       kmod_config_add_softdep(config,
+                                       underscores(ctx, modname),
+                                       strtok_r(NULL, "\0", &saveptr));
                } else if (streq(cmd, "include")
-                               || streq(cmd, "softdep")
                                || streq(cmd, "config")) {
                        INFO(ctx, "%s: command %s not implemented yet\n",
                                                                filename, cmd);
@@ -422,6 +598,9 @@ void kmod_config_free(struct kmod_config *config)
                                                &config->remove_commands);
        }
 
+       while (config->softdeps)
+               kmod_config_free_softdep(config, config->softdeps);
+
        free(config);
 }
 
index e6388f2bfba5093e899dec901a6e2ad64907c1a0..cb0ec3dc6a7778c4f443ac3446b3b11db37a3809 100644 (file)
@@ -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 @@ struct kmod_module {
        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 @@ struct kmod_module {
                bool options : 1;
                bool install_commands : 1;
                bool remove_commands : 1;
+               bool softdeps : 1;
        } init;
 };
 
@@ -393,6 +399,8 @@ KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod)
        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 @@ void kmod_module_set_install_commands(struct kmod_module *mod, const char *cmd)
        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
index b9a93d274e7c1aa7cb00873ac5305ce7add4f5af..85cfc125a0cba46d4adf3cf98ffeaeef701d4056 100644 (file)
@@ -85,6 +85,7 @@ void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod, const c
 const struct kmod_list *kmod_get_options(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1)));
 const struct kmod_list *kmod_get_install_commands(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1)));
 const struct kmod_list *kmod_get_remove_commands(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1)));
+const struct kmod_list *kmod_get_softdeps(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1)));
 
 
 /* libkmod-config.c */
@@ -95,6 +96,7 @@ struct kmod_config {
        struct kmod_list *options;
        struct kmod_list *remove_commands;
        struct kmod_list *install_commands;
+       struct kmod_list *softdeps;
 };
 int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **config, const char * const *config_paths) __attribute__((nonnull(1, 2,3)));
 void kmod_config_free(struct kmod_config *config) __attribute__((nonnull(1)));
@@ -105,6 +107,10 @@ const char *kmod_option_get_modname(const struct kmod_list *l) __attribute__((no
 const char *kmod_command_get_command(const struct kmod_list *l) __attribute__((nonnull(1)));
 const char *kmod_command_get_modname(const struct kmod_list *l) __attribute__((nonnull(1)));
 
+const char *kmod_softdep_get_name(const struct kmod_list *l) __attribute__((nonnull(1)));
+const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count) __attribute__((nonnull(1, 2)));
+const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count);
+
 
 /* libkmod-module.c */
 int kmod_module_new_from_alias(struct kmod_ctx *ctx, const char *alias, const char *name, struct kmod_module **mod);
index c87e95c0c6cc85b1e14042dd782791f9fa047c61..87c9a3d04b2c0d0797a41e1630c02a1d7311c33e 100644 (file)
@@ -754,3 +754,8 @@ const struct kmod_list *kmod_get_remove_commands(const struct kmod_ctx *ctx)
 {
        return ctx->config->remove_commands;
 }
+
+const struct kmod_list *kmod_get_softdeps(const struct kmod_ctx *ctx)
+{
+       return ctx->config->softdeps;
+}
index d9169d9c2a9c063fb9f5bb37164bd0cf88ca38fa..194946d186f340bda6c629fcfbb4dd5c1b246223 100644 (file)
@@ -131,6 +131,8 @@ const char *kmod_module_get_options(const struct kmod_module *mod);
 const char *kmod_module_get_install_commands(const struct kmod_module *mod);
 const char *kmod_module_get_remove_commands(const struct kmod_module *mod);
 
+int kmod_module_get_softdeps(const struct kmod_module *mod, struct kmod_list **pre, struct kmod_list **post);
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index 552c3f3a2636098dc251b6af50f0dfe9d2b9e896..71b7ccc856d877d5a41cf4022217de5f57141128 100644 (file)
@@ -45,6 +45,7 @@ global:
         kmod_module_get_options;
         kmod_module_get_install_commands;
         kmod_module_get_remove_commands;
+        kmod_module_get_softdeps;
 local:
         *;
 };
index f4501b5f0f54367fdc9422a771053769dee5cfd7..e68832c795dbd2e315ad2ced0400c33f0ed5ef48 100644 (file)
@@ -92,6 +92,7 @@ int main(int argc, char *argv[])
                printf("Alias: '%s'\nModules matching:\n", alias);
 
        kmod_list_foreach(l, list) {
+               struct kmod_list *d, *pre = NULL, *post = NULL;
                struct kmod_module *mod = kmod_module_get_module(l);
                const char *str;
 
@@ -105,6 +106,31 @@ int main(int argc, char *argv[])
                str = kmod_module_get_remove_commands(mod);
                if (str)
                        printf("\t\tremove commands: '%s'\n", str);
+
+               err = kmod_module_get_softdeps(mod, &pre, &post);
+               if (err == 0) {
+                       if (pre != NULL || post != NULL)
+                               puts("\t\tsoft dependencies:");
+                       if (pre != NULL) {
+                               fputs("\t\t\tpre:", stdout);
+                               kmod_list_foreach(d, pre) {
+                                       struct kmod_module *dm = kmod_module_get_module(d);
+                                       printf(" %s", kmod_module_get_name(dm));
+                               }
+                               putchar('\n');
+                               kmod_module_unref_list(pre);
+                       }
+                       if (post != NULL) {
+                               fputs("\t\t\tpost:", stdout);
+                               kmod_list_foreach(d, post) {
+                                       struct kmod_module *dm = kmod_module_get_module(d);
+                                       printf(" %s", kmod_module_get_name(dm));
+                               }
+                               putchar('\n');
+                               kmod_module_unref_list(post);
+                       }
+               }
+
                kmod_module_unref(mod);
        }