]> git.ipfire.org Git - thirdparty/kmod.git/blobdiff - libkmod/libkmod.c
improve "const" keyword usage.
[thirdparty/kmod.git] / libkmod / libkmod.c
index 3c3d59e98271b39572563fb87fd1deafe2281616..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
 struct kmod_ctx {
        int refcount;
        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;
+                       int priority, const char *file, int line,
+                       const char *fn, const char *format, va_list args);
+       const void *userdata;
+       char *dirname;
        int log_priority;
+       struct kmod_config config;
 };
 
 void kmod_log(struct kmod_ctx *ctx,
-          int priority, const char *file, int line, const char *fn,
-          const char *format, ...)
+               int priority, const char *file, int line, const char *fn,
+               const char *format, ...)
 {
        va_list args;
 
@@ -64,13 +68,18 @@ void kmod_log(struct kmod_ctx *ctx,
 }
 
 static void log_stderr(struct kmod_ctx *ctx,
-                      int priority, const char *file, int line, const char *fn,
-                      const char *format, va_list args)
+                       int priority, const char *file, int line,
+                       const char *fn, const char *format, va_list args)
 {
        fprintf(stderr, "libkmod: %s: ", fn);
        vfprintf(stderr, format, args);
 }
 
+const char *kmod_get_dirname(const struct kmod_ctx *ctx)
+{
+       return ctx->dirname;
+}
+
 /**
  * kmod_get_userdata:
  * @ctx: kmod library context
@@ -80,11 +89,11 @@ static void log_stderr(struct kmod_ctx *ctx,
  *
  * Returns: stored userdata
  **/
-KMOD_EXPORT void *kmod_get_userdata(struct kmod_ctx *ctx)
+KMOD_EXPORT void *kmod_get_userdata(const struct kmod_ctx *ctx)
 {
        if (ctx == NULL)
                return NULL;
-       return ctx->userdata;
+       return (void *)ctx->userdata;
 }
 
 /**
@@ -94,7 +103,7 @@ KMOD_EXPORT void *kmod_get_userdata(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;
@@ -118,6 +127,25 @@ static int log_priority(const char *priority)
        return 0;
 }
 
+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;
+
+       if (asprintf(&p, "%s/%s", dirname_default_prefix, u.release) < 0)
+               return NULL;
+
+       return p;
+}
+
 /**
  * kmod_new:
  *
@@ -129,28 +157,32 @@ static int log_priority(const char *priority)
  *
  * Returns: a new kmod library context
  **/
-KMOD_EXPORT int kmod_new(struct kmod_ctx **ctx)
+KMOD_EXPORT struct kmod_ctx *kmod_new(const char *dirname)
 {
        const char *env;
-       struct kmod_ctx *c;
+       struct kmod_ctx *ctx;
 
-       c = calloc(1, sizeof(struct kmod_ctx));
-       if (!c)
-               return -ENOMEM;
+       ctx = calloc(1, sizeof(struct kmod_ctx));
+       if (!ctx)
+               return NULL;
+
+       ctx->refcount = 1;
+       ctx->log_fn = log_stderr;
+       ctx->log_priority = LOG_ERR;
 
-       c->refcount = 1;
-       c->log_fn = log_stderr;
-       c->log_priority = LOG_ERR;
+       ctx->dirname = get_kernel_release(dirname);
 
        /* environment overwrites config */
        env = getenv("KMOD_LOG");
        if (env != NULL)
-               kmod_set_log_priority(c, log_priority(env));
+               kmod_set_log_priority(ctx, log_priority(env));
 
-       info(c, "ctx %p created\n", c);
-       dbg(c, "log_priority=%d\n", c->log_priority);
-       *ctx = c;
-       return 0;
+       kmod_parse_config(ctx, &ctx->config);
+
+       INFO(ctx, "ctx %p created\n", ctx);
+       DBG(ctx, "log_priority=%d\n", ctx->log_priority);
+
+       return ctx;
 }
 
 /**
@@ -181,10 +213,12 @@ KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
 {
        if (ctx == NULL)
                return NULL;
-       ctx->refcount--;
-       if (ctx->refcount > 0)
+
+       if (--ctx->refcount > 0)
                return ctx;
-       info(ctx, "context %p released\n", ctx);
+       INFO(ctx, "context %p released\n", ctx);
+       free(ctx->dirname);
+       kmod_free_config(ctx, &ctx->config);
        free(ctx);
        return NULL;
 }
@@ -200,13 +234,13 @@ KMOD_EXPORT struct kmod_ctx *kmod_unref(struct kmod_ctx *ctx)
  *
  **/
 KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *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 (*log_fn)(struct kmod_ctx *ctx,
+                                               int priority, const char *file,
+                                               int line, const char *fn,
+                                               const char *format, va_list args))
 {
        ctx->log_fn = log_fn;
-       info(ctx, "custom logging function %p registered\n", log_fn);
+       INFO(ctx, "custom logging function %p registered\n", log_fn);
 }
 
 /**
@@ -215,7 +249,7 @@ KMOD_EXPORT void kmod_set_log_fn(struct kmod_ctx *ctx,
  *
  * Returns: the current logging priority
  **/
-KMOD_EXPORT int kmod_get_log_priority(struct kmod_ctx *ctx)
+KMOD_EXPORT int kmod_get_log_priority(const struct kmod_ctx *ctx)
 {
        return ctx->log_priority;
 }
@@ -233,56 +267,151 @@ KMOD_EXPORT void kmod_set_log_priority(struct kmod_ctx *ctx, int priority)
        ctx->log_priority = priority;
 }
 
-struct kmod_list_entry;
-struct kmod_list_entry *kmod_list_entry_get_next(struct kmod_list_entry *list_entry);
-const char *kmod_list_entry_get_name(struct kmod_list_entry *list_entry);
-const char *kmod_list_entry_get_value(struct kmod_list_entry *list_entry);
 
-struct kmod_thing {
-       struct kmod_ctx *ctx;
-       int refcount;
-};
-
-KMOD_EXPORT struct kmod_thing *kmod_thing_ref(struct kmod_thing *thing)
+static int kmod_lookup_alias_from_alias_bin(struct kmod_ctx *ctx,
+                                               const char *file,
+                                               const char *name,
+                                               struct kmod_list **list)
 {
-       if (!thing)
-               return NULL;
-       thing->refcount++;
-       return thing;
+       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;
+
 }
 
-KMOD_EXPORT struct kmod_thing *kmod_thing_unref(struct kmod_thing *thing)
+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 (thing == NULL)
-               return NULL;
-       thing->refcount--;
-       if (thing->refcount > 0)
-               return thing;
-       dbg(thing->ctx, "context %p released\n", thing);
-       free(thing);
-       return NULL;
+       if (!startswith(name, "symbol:"))
+               return 0;
+
+       return kmod_lookup_alias_from_alias_bin(ctx, symbols_file, name, list);
 }
 
-KMOD_EXPORT struct kmod_ctx *kmod_thing_get_ctx(struct kmod_thing *thing)
+
+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 thing->ctx;
+       return kmod_lookup_alias_from_alias_bin(ctx, aliases_file, name, list);
 }
 
-KMOD_EXPORT int kmod_thing_new_from_string(struct kmod_ctx *ctx, const char *string, struct kmod_thing **thing)
+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)
 {
-       struct kmod_thing *t;
+       char *fn, *line;
+       struct index_file *idx;
+       int n = 0;
 
-       t = calloc(1, sizeof(struct kmod_thing));
-       if (!t)
+       /*
+        * 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;
 
-       t->refcount = 1;
-       t->ctx = ctx;
-       *thing = t;
-       return 0;
+       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;
 }
 
-KMOD_EXPORT struct kmod_list_entry *kmod_thing_get_some_list_entry(struct kmod_thing *thing)
+int kmod_lookup_alias_from_config(struct kmod_ctx *ctx, const char *name,
+                                               struct kmod_list **list)
 {
-       return NULL;
+       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;
 }