]> git.ipfire.org Git - thirdparty/kmod.git/blobdiff - libkmod/libkmod-module.c
libkmod: Fix use of sizeof instead of ARRAY_SIZE
[thirdparty/kmod.git] / libkmod / libkmod-module.c
index 889f26479a987ccb6c32e7a90a80080ae475beb7..efdd679851ce1134e4f7df50cc8073afa33168e2 100644 (file)
@@ -431,17 +431,18 @@ KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx,
                        return -EEXIST;
                }
 
-               *mod = kmod_module_ref(m);
-               return 0;
-       }
+               kmod_module_ref(m);
+       } else {
+               err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
+               if (err < 0) {
+                       free(abspath);
+                       return err;
+               }
 
-       err = kmod_module_new(ctx, name, name, namelen, NULL, 0, &m);
-       if (err < 0) {
-               free(abspath);
-               return err;
+               m->path = abspath;
        }
 
-       m->path = abspath;
+       m->builtin = KMOD_MODULE_BUILTIN_NO;
        *mod = m;
 
        return 0;
@@ -498,13 +499,26 @@ KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
        return mod;
 }
 
-#define CHECK_ERR_AND_FINISH(_err, _label_err, _list, label_finish)    \
-       do {                                                            \
-               if ((_err) < 0)                                         \
-                       goto _label_err;                                \
-               if (*(_list) != NULL)                                   \
-                       goto finish;                                    \
-       } while (0)
+typedef int (*lookup_func)(struct kmod_ctx *ctx, const char *name, struct kmod_list **list) __attribute__((nonnull(1, 2, 3)));
+
+static int __kmod_module_new_from_lookup(struct kmod_ctx *ctx, const lookup_func lookup[],
+                                        size_t lookup_count, const char *s,
+                                        struct kmod_list **list)
+{
+       unsigned int i;
+
+       for (i = 0; i < lookup_count; i++) {
+               int err;
+
+               err = lookup[i](ctx, s, list);
+               if (err < 0 && err != -ENOSYS)
+                       return err;
+               else if (*list != NULL)
+                       return 0;
+       }
+
+       return 0;
+}
 
 /**
  * kmod_module_new_from_lookup:
@@ -520,7 +534,7 @@ KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod)
  *
  * The search order is: 1. aliases in configuration file; 2. module names in
  * modules.dep index; 3. symbol aliases in modules.symbols index; 4. aliases
- * in modules.alias index.
+ * from install commands; 5. builtin indexes from kernel.
  *
  * The initial refcount is 1, and needs to be decremented to release the
  * resources of the kmod_module. The returned @list must be released by
@@ -537,8 +551,17 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
                                                const char *given_alias,
                                                struct kmod_list **list)
 {
-       int err;
+       const lookup_func lookup[] = {
+               kmod_lookup_alias_from_config,
+               kmod_lookup_alias_from_moddep_file,
+               kmod_lookup_alias_from_symbols_file,
+               kmod_lookup_alias_from_commands,
+               kmod_lookup_alias_from_aliases_file,
+               kmod_lookup_alias_from_builtin_file,
+               kmod_lookup_alias_from_kernel_builtin_file,
+       };
        char alias[PATH_MAX];
+       int err;
 
        if (ctx == NULL || given_alias == NULL)
                return -ENOENT;
@@ -555,40 +578,75 @@ KMOD_EXPORT int kmod_module_new_from_lookup(struct kmod_ctx *ctx,
 
        DBG(ctx, "input alias=%s, normalized=%s\n", given_alias, alias);
 
-       /* Aliases from config file override all the others */
-       err = kmod_lookup_alias_from_config(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+       err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup),
+                                           alias, list);
 
-       DBG(ctx, "lookup modules.dep %s\n", alias);
-       err = kmod_lookup_alias_from_moddep_file(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+       DBG(ctx, "lookup=%s found=%d\n", alias, err >= 0 && *list);
 
-       DBG(ctx, "lookup modules.symbols %s\n", alias);
-       err = kmod_lookup_alias_from_symbols_file(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+       if (err < 0) {
+               kmod_module_unref_list(*list);
+               *list = NULL;
+       }
 
-       DBG(ctx, "lookup install and remove commands %s\n", alias);
-       err = kmod_lookup_alias_from_commands(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+       return err;
+}
 
-       DBG(ctx, "lookup modules.aliases %s\n", alias);
-       err = kmod_lookup_alias_from_aliases_file(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+/**
+ * kmod_module_new_from_name_lookup:
+ * @ctx: kmod library context
+ * @modname: module name to look for
+ * @mod: returned module on success
+ *
+ * Lookup by module name, without considering possible aliases. This is similar
+ * to kmod_module_new_from_lookup(), but don't consider as source indexes and
+ * configurations that work with aliases. When succesful, this always resolves
+ * to one and only one module.
+ *
+ * The search order is: 1. module names in modules.dep index;
+ * 2. builtin indexes from kernel.
+ *
+ * The initial refcount is 1, and needs to be decremented to release the
+ * resources of the kmod_module. Since libkmod keeps track of all
+ * kmod_modules created, they are all released upon @ctx destruction too. Do
+ * not unref @ctx before all the desired operations with the returned list are
+ * completed.
+ *
+ * Returns: 0 on success or < 0 otherwise. It fails if any of the lookup
+ * methods failed, which is basically due to memory allocation failure. If
+ * module is not found, it still returns 0, but @mod is left untouched.
+ */
+KMOD_EXPORT int kmod_module_new_from_name_lookup(struct kmod_ctx *ctx,
+                                                const char *modname,
+                                                struct kmod_module **mod)
+{
+       const lookup_func lookup[] = {
+               kmod_lookup_alias_from_moddep_file,
+               kmod_lookup_alias_from_builtin_file,
+               kmod_lookup_alias_from_kernel_builtin_file,
+       };
+       char name_norm[PATH_MAX];
+       struct kmod_list *list = NULL;
+       int err;
 
-       DBG(ctx, "lookup modules.builtin %s\n", alias);
-       err = kmod_lookup_alias_from_builtin_file(ctx, alias, list);
-       CHECK_ERR_AND_FINISH(err, fail, list, finish);
+       if (ctx == NULL || modname == NULL || mod == NULL)
+               return -ENOENT;
+
+       modname_normalize(modname, name_norm, NULL);
+
+       DBG(ctx, "input modname=%s, normalized=%s\n", modname, name_norm);
+
+       err = __kmod_module_new_from_lookup(ctx, lookup, ARRAY_SIZE(lookup),
+                                           name_norm, &list);
+
+       DBG(ctx, "lookup=%s found=%d\n", name_norm, err >= 0 && list);
+
+       if (err >= 0 && list != NULL)
+               *mod = kmod_module_get_module(list);
+
+       kmod_module_unref_list(list);
 
-finish:
-       DBG(ctx, "lookup %s=%d, list=%p\n", alias, err, *list);
-       return err;
-fail:
-       DBG(ctx, "Failed to lookup %s\n", alias);
-       kmod_module_unref_list(*list);
-       *list = NULL;
        return err;
 }
-#undef CHECK_ERR_AND_FINISH
 
 /**
  * kmod_module_unref_list:
@@ -974,14 +1032,19 @@ static int command_do(struct kmod_module *mod, const char *type,
        err = system(cmd);
        unsetenv("MODPROBE_MODULE");
 
-       if (err == -1 || WEXITSTATUS(err)) {
-               ERR(mod->ctx, "Error running %s command for %s\n",
-                                                               type, modname);
-               if (err != -1)
-                       err = -WEXITSTATUS(err);
+       if (err == -1) {
+               ERR(mod->ctx, "Could not run %s command '%s' for module %s: %m\n",
+                   type, cmd, modname);
+               return -EINVAL;
        }
 
-       return err;
+       if (WEXITSTATUS(err)) {
+               ERR(mod->ctx, "Error running %s command '%s' for module %s: retcode %d\n",
+                   type, cmd, modname, WEXITSTATUS(err));
+               return -EINVAL;
+       }
+
+       return 0;
 }
 
 struct probe_insert_cb {
@@ -2266,7 +2329,7 @@ list_error:
  *
  * After use, free the @list by calling kmod_module_info_free_list().
  *
- * Returns: 0 on success or < 0 otherwise.
+ * Returns: number of entries in @list on success or < 0 otherwise.
  */
 KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_list **list)
 {
@@ -2280,13 +2343,22 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
 
        assert(*list == NULL);
 
-       elf = kmod_module_get_elf(mod);
-       if (elf == NULL)
-               return -errno;
+       /* remove const: this can only change internal state */
+       if (kmod_module_is_builtin((struct kmod_module *)mod)) {
+               count = kmod_builtin_get_modinfo(mod->ctx,
+                                               kmod_module_get_name(mod),
+                                               &strings);
+               if (count < 0)
+                       return count;
+       } else {
+               elf = kmod_module_get_elf(mod);
+               if (elf == NULL)
+                       return -errno;
 
-       count = kmod_elf_get_strings(elf, ".modinfo", &strings);
-       if (count < 0)
-               return count;
+               count = kmod_elf_get_strings(elf, ".modinfo", &strings);
+               if (count < 0)
+                       return count;
+       }
 
        for (i = 0; i < count; i++) {
                struct kmod_list *n;
@@ -2310,7 +2382,7 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
                        goto list_error;
        }
 
-       if (kmod_module_signature_info(mod->file, &sig_info)) {
+       if (mod->file && kmod_module_signature_info(mod->file, &sig_info)) {
                struct kmod_list *n;
 
                n = kmod_module_info_append(list, "sig_id", strlen("sig_id"),
@@ -2357,6 +2429,9 @@ KMOD_EXPORT int kmod_module_get_info(const struct kmod_module *mod, struct kmod_
        ret = count;
 
 list_error:
+       /* aux structures freed in normal case also */
+       kmod_module_signature_info_free(&sig_info);
+
        if (ret < 0) {
                kmod_module_info_free_list(*list);
                *list = NULL;
@@ -2863,3 +2938,46 @@ KMOD_EXPORT void kmod_module_dependency_symbols_free_list(struct kmod_list *list
                list = kmod_list_remove(list);
        }
 }
+
+/**
+ * kmod_module_get_builtin:
+ * @ctx: kmod library context
+ * @list: where to save the builtin module list
+ *
+ * Returns: 0 on success or < 0 otherwise.
+ */
+int kmod_module_get_builtin(struct kmod_ctx *ctx, struct kmod_list **list)
+{
+       struct kmod_builtin_iter *iter;
+       int err = 0;
+
+       iter = kmod_builtin_iter_new(ctx);
+       if (!iter)
+               return -errno;
+
+       while (kmod_builtin_iter_next(iter)) {
+               struct kmod_module *mod = NULL;
+               char modname[PATH_MAX];
+
+               if (!kmod_builtin_iter_get_modname(iter, modname)) {
+                       err = -errno;
+                       goto fail;
+               }
+
+               err = kmod_module_new_from_name(ctx, modname, &mod);
+               if (err < 0)
+                       goto fail;
+
+               kmod_module_set_builtin(mod, true);
+
+               *list = kmod_list_append(*list, mod);
+       }
+
+       kmod_builtin_iter_free(iter);
+       return err;
+fail:
+       kmod_builtin_iter_free(iter);
+       kmod_module_unref_list(*list);
+       *list = NULL;
+       return err;
+}