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