]> git.ipfire.org Git - thirdparty/kmod.git/blobdiff - libkmod/libkmod.c
improve "const" keyword usage.
[thirdparty/kmod.git] / libkmod / libkmod.c
index 13948fb3575f7c40cab86f289d964521d6e4afe0..c9966e0ce435462ea04a1f0dc9d598745ebfdb08 100644 (file)
@@ -2,7 +2,6 @@
  * libkmod - interface to kernel module operations
  *
  * Copyright (C) 2011  ProFUSION embedded systems
- * Copyright (C) 2011  Lucas De Marchi <lucas.de.marchi@gmail.com>
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
 #include <stdarg.h>
 #include <unistd.h>
 #include <errno.h>
+#include <fnmatch.h>
 #include <string.h>
 #include <ctype.h>
 #include <sys/utsname.h>
 
 #include "libkmod.h"
 #include "libkmod-private.h"
+#include "libkmod-index.h"
 
 /**
  * SECTION:libkmod
@@ -49,9 +50,10 @@ struct kmod_ctx {
        void (*log_fn)(struct kmod_ctx *ctx,
                        int priority, const char *file, int line,
                        const char *fn, const char *format, va_list args);
-       void *userdata;
-       const char *dirname;
+       const void *userdata;
+       char *dirname;
        int log_priority;
+       struct kmod_config config;
 };
 
 void kmod_log(struct kmod_ctx *ctx,
@@ -71,10 +73,9 @@ static void log_stderr(struct kmod_ctx *ctx,
 {
        fprintf(stderr, "libkmod: %s: ", fn);
        vfprintf(stderr, format, args);
-       fprintf(stderr, "\n");
 }
 
-const char *kmod_get_dirname(struct kmod_ctx *ctx)
+const char *kmod_get_dirname(const struct kmod_ctx *ctx)
 {
        return ctx->dirname;
 }
@@ -92,7 +93,7 @@ KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
 {
        if (ctx == NULL)
                return NULL;
-       return ctx->userdata;
+       return (void *)ctx->userdata;
 }
 
 /**
@@ -102,7 +103,7 @@ KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
  *
  * Store custom @userdata in the library context.
  **/
-KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, void *userdata)
+KMOD_EXPORT void kmod_set_userdata(struct kmod_ctx *ctx, const void *userdata)
 {
        if (ctx == NULL)
                return;
@@ -126,14 +127,23 @@ static int log_priority(const char *priority)
        return 0;
 }
 
-static const char *get_kernel_release(void)
+static const char *dirname_default_prefix = "/lib/modules";
+
+static char *get_kernel_release(const char *dirname)
 {
        struct utsname u;
+       char *p;
+
+       if (dirname != NULL)
+               return strdup(dirname);
 
        if (uname(&u) < 0)
                return NULL;
 
-       return strdup(u.release);
+       if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
+               return NULL;
+
+       return p;
 }
 
 /**
@@ -160,16 +170,15 @@ KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname)
        ctx->log_fn = log_stderr;
        ctx->log_priority = LOG_ERR;
 
-       if (dirname != NULL)
-               ctx->dirname = strdup(dirname);
-       else
-               ctx->dirname = get_kernel_release();
+       ctx->dirname = get_kernel_release(dirname);
 
        /* environment overwrites config */
        env = getenv("KMOD_LOG");
        if (env != NULL)
                kmod_set_log_priority(ctx, log_priority(env));
 
+       kmod_parse_config(ctx, &ctx->config);
+
        INFO(ctx, "ctx %p created\n", ctx);
        DBG(ctx, "log_priority=%d\n", ctx->log_priority);
 
@@ -208,7 +217,8 @@ KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
        if (--ctx->refcount > 0)
                return ctx;
        INFO(ctx, "context %p released\n", ctx);
-       free((char *)ctx->dirname);
+       free(ctx->dirname);
+       kmod_free_config(ctx, &ctx->config);
        free(ctx);
        return NULL;
 }
@@ -256,3 +266,152 @@ KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
 {
        ctx->log_priority = priority;
 }
+
+
+static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
+                                               const char *file,
+                                               const char *name,
+                                               struct kmod_list **list)
+{
+       char *fn;
+       int err, nmatch = 0;
+       struct index_file *idx;
+       struct index_value *realnames, *realname;
+
+       if (asprintf(&fn, "%s/%s.bin", ctx->dirname, file) < 0)
+               return -ENOMEM;
+
+       DBG(ctx, "file=%s name=%s\n", fn, name);
+
+       idx = index_file_open(fn);
+       if (idx == NULL) {
+               free(fn);
+               return -ENOSYS;
+       }
+
+       realnames = index_searchwild(idx, name);
+       for (realname = realnames; realname; realname = realnames->next) {
+               struct kmod_module *mod;
+
+               err = kmod_module_new_from_name(ctx, realname->value, &mod);
+               if (err < 0) {
+                       ERR(ctx, "%s\n", strerror(-err));
+                       goto fail;
+               }
+
+               *list = kmod_list_append(*list, mod);
+               nmatch++;
+       }
+
+       index_values_free(realnames);
+       index_file_close(idx);
+       free(fn);
+
+       return nmatch;
+
+fail:
+       *list = kmod_list_remove_n_latest(*list, nmatch);
+       return err;
+
+}
+
+static const char *symbols_file = "modules.symbols";
+
+int kmod_lookup_alias_from_symbols_file(struct kmod_ctx *ctx, const char *name,
+                                               struct kmod_list **list)
+{
+       if (!startswith(name, "symbol:"))
+               return 0;
+
+       return kmod_lookup_alias_from_alias_bin(ctx, symbols_file, name, list);
+}
+
+
+static const char *aliases_file = "modules.alias";
+
+int kmod_lookup_alias_from_aliases_file(struct kmod_ctx *ctx, const char *name,
+                                               struct kmod_list **list)
+{
+       return kmod_lookup_alias_from_alias_bin(ctx, aliases_file, name, list);
+}
+
+static const char *moddep_file = "modules.dep";
+
+int kmod_lookup_alias_from_moddep_file(struct kmod_ctx *ctx, const char *name,
+                                               struct kmod_list **list)
+{
+       char *fn, *line;
+       struct index_file *idx;
+       int n = 0;
+
+       /*
+        * Module names do not contain ':'. Return early if we know it will
+        * not be found.
+        */
+       if (strchr(name, ':'))
+               return 0;
+
+       if (asprintf(&fn, "%s/%s.bin", ctx->dirname, moddep_file) < 0)
+               return -ENOMEM;
+
+       DBG(ctx, "file=%s modname=%s\n", fn, name);
+
+       idx = index_file_open(fn);
+       if (idx == NULL) {
+               free(fn);
+               return -ENOSYS;
+       }
+
+       line = index_search(idx, name);
+       if (line != NULL) {
+               struct kmod_module *mod;
+
+               n = kmod_module_new_from_name(ctx, name, &mod);
+               if (n < 0) {
+                       ERR(ctx, "%s\n", strerror(-n));
+                       goto finish;
+               }
+
+               *list = kmod_list_append(*list, mod);
+               kmod_module_parse_dep(mod, line);
+       }
+
+finish:
+       free(line);
+       index_file_close(idx);
+       free(fn);
+
+       return n;
+}
+
+int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
+                                               struct kmod_list **list)
+{
+       struct kmod_config *config = &ctx->config;
+       struct kmod_list *l;
+       int err, nmatch = 0;
+
+       kmod_list_foreach(l, config->aliases) {
+               const char *aliasname = kmod_alias_get_name(l);
+               const char *modname = kmod_alias_get_modname(l);
+
+               if (fnmatch(aliasname, name, 0) == 0) {
+                       struct kmod_module *mod;
+
+                       err = kmod_module_new_from_name(ctx, modname, &mod);
+                       if (err < 0) {
+                               ERR(ctx, "%s", strerror(-err));
+                               goto fail;
+                       }
+
+                       *list = kmod_list_append(*list, mod);
+                       nmatch++;
+               }
+       }
+
+       return nmatch;
+
+fail:
+       *list = kmod_list_remove_n_latest(*list, nmatch);
+       return err;
+}