* 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;
}
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
*
* 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;
}
/**
*
* 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;
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:
*
*
* 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;
}
/**
{
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;
}
*
**/
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);
}
/**
*
* 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;
}
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;
}