From: Lucas De Marchi Date: Fri, 25 Nov 2011 03:22:56 +0000 (-0200) Subject: Add functions to operate on modules X-Git-Tag: v1~186 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=8f788d58c3c58f0559b32fe896a00c35dc58c01e;p=thirdparty%2Fkmod.git Add functions to operate on modules --- diff --git a/Makefile.am b/Makefile.am index e4a73057..db30172f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -32,7 +32,8 @@ libkmod_libkmod_la_SOURCES =\ libkmod/macro.h \ libkmod/libkmod.c \ libkmod/libkmod-list.c \ - libkmod/libkmod-loaded.c + libkmod/libkmod-loaded.c \ + libkmod/libkmod-module.c EXTRA_DIST += libkmod/libkmod.sym diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c new file mode 100644 index 00000000..5e8ae73e --- /dev/null +++ b/libkmod/libkmod-module.c @@ -0,0 +1,224 @@ +/* + * libkmod - interface to kernel module operations + * + * Copyright (C) 2011 ProFUSION embedded systems + * Copyright (C) 2011 Lucas De Marchi + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation version 2.1. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "libkmod.h" +#include "libkmod-private.h" + +/** + * kmod_module: + * + * Opaque object representing a module. + */ +struct kmod_module { + struct kmod_ctx *ctx; + int refcount; + const char *path; + const char *name; +}; + +static char *path_to_modname(const char *path) +{ + char *modname; + char *c; + + modname = basename(path); + if (modname == NULL || modname[0] == '\0') + return NULL; + + modname = strdup(modname); + for (c = modname; *c != '\0' && *c != '.'; c++) { + if (*c == '-') + *c = '_'; + } + + *c = '\0'; + return modname; +} + +static const char *get_modname(struct kmod_module *mod) +{ + if (mod->name == NULL) + mod->name = path_to_modname(mod->path); + + return mod->name; +} + +KMOD_EXPORT int kmod_module_new_from_name(struct kmod_ctx *ctx, + const char *name, + struct kmod_module **mod) +{ + struct kmod_module *m; + + if (ctx == NULL || name == NULL) + return -ENOENT; + + m = calloc(1, sizeof(*m)); + if (m == NULL) { + free(m); + return -ENOMEM; + } + + m->ctx = kmod_ref(ctx); + m->name = strdup(name); + + *mod = m; + + return 0; +} + +KMOD_EXPORT int kmod_module_new_from_path(struct kmod_ctx *ctx, + const char *path, + struct kmod_module **mod) +{ + struct kmod_module *m; + int err; + struct stat st; + + if (ctx == NULL || path == NULL) + return -ENOENT; + + err = stat(path, &st); + if (err < 0) + return -errno; + + m = calloc(1, sizeof(*m)); + if (m == NULL) { + free(m); + return -ENOMEM; + } + + m->ctx = kmod_ref(ctx); + m->path = strdup(path); + + *mod = m; + + return 0; +} + +KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod) +{ + if (mod == NULL) + return NULL; + + if (--mod->refcount > 0) + return mod; + + DBG(mod->ctx, "kmod_module %p released\n", mod); + + kmod_unref(mod->ctx); + free((char *) mod->path); + free((char *) mod->name); + free(mod); + return NULL; +} + +KMOD_EXPORT struct kmod_module *kmod_module_ref(struct kmod_module *mod) +{ + if (mod == NULL) + return NULL; + + mod->refcount++; + + return mod; +} + +extern long delete_module(const char *name, unsigned int flags); + +KMOD_EXPORT int kmod_module_remove_module(struct kmod_module *mod, + unsigned int flags) +{ + int err; + const char *modname; + + if (mod == NULL) + return -ENOENT; + + /* Filter out other flags */ + flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT); + + modname = get_modname(mod); + err = delete_module(modname, flags); + if (err != 0) { + ERR(mod->ctx, "Removing '%s': %s\n", modname, + strerror(-err)); + return err; + } + + return 0; +} + +extern long init_module(void *mem, unsigned long len, const char *args); + +KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod, + unsigned int flags) +{ + int err; + void *mmaped_file; + struct stat st; + int fd; + const char *args = ""; + + if (mod == NULL) + return -ENOENT; + + if (mod->path == NULL) { + ERR(mod->ctx, "Not supported to load a module by name yet"); + return -ENOSYS; + } + + if (flags != 0) + INFO(mod->ctx, "Flags are not implemented yet"); + + if ((fd = open(mod->path, O_RDONLY)) < 0) { + err = -errno; + return err; + } + + stat(mod->path, &st); + + if ((mmaped_file = mmap(0, st.st_size, PROT_READ, + MAP_PRIVATE, fd, 0)) == MAP_FAILED) { + close(fd); + return -errno; + } + + err = init_module(mmaped_file, st.st_size, args); + if (err < 0) + ERR(mod->ctx, "Failed to insert module '%s'", mod->path); + + munmap(mmaped_file, st.st_size); + close(fd); + + return err; +} diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index d68d2ef3..23ba079b 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -66,6 +66,11 @@ struct kmod_list *kmod_list_next(struct kmod_list *first_entry, } /* extern "C" */ #endif +/* + * kmod_loaded + * + * retrieve info from /proc/modules regarding loaded modules + */ struct kmod_loaded; int kmod_loaded_new(struct kmod_ctx *ctx, struct kmod_loaded **mod); struct kmod_loaded *kmod_loaded_ref(struct kmod_loaded *mod); @@ -82,4 +87,29 @@ enum kmod_remove { int kmod_loaded_remove_module(struct kmod_loaded *kmod, struct kmod_list *entry, unsigned int flags); + +enum kmod_insert { + KMOD_INSERT_FORCE_VERMAGIC = 0x1, + KMOD_INSERT_FORCE_MODVERSION = 0x2, + KMOD_INSERT_HANDLE_DEPENDENCIES = 0x4, + KMOD_INSERT_IGNORE_CONFIG = 0x8, +}; + +/* + * kmod_module + * + * Operate on kernel modules + */ +struct kmod_module; +int kmod_module_new_from_name(struct kmod_ctx *ctx, const char *name, + struct kmod_module **mod); +int kmod_module_new_from_path(struct kmod_ctx *ctx, const char *path, + struct kmod_module **mod); + +struct kmod_module *kmod_module_ref(struct kmod_module *mod); +struct kmod_module *kmod_module_unref(struct kmod_module *mod); + +int kmod_module_remove_module(struct kmod_module *mod, unsigned int flags); +int kmod_module_insert_module(struct kmod_module *mod, unsigned int flags); + #endif diff --git a/libkmod/libkmod.sym b/libkmod/libkmod.sym index b22312d8..8972dd94 100644 --- a/libkmod/libkmod.sym +++ b/libkmod/libkmod.sym @@ -16,6 +16,14 @@ global: kmod_loaded_get_list; kmod_loaded_get_module_info; kmod_loaded_remove_module; + + kmod_module_new_from_name; + kmod_module_new_from_path; + kmod_module_ref; + kmod_module_unref; + kmod_module_remove_module; + kmod_module_insert_module; + local: *; }; diff --git a/libkmod/macro.h b/libkmod/macro.h index 4c8f5432..76fdedb6 100644 --- a/libkmod/macro.h +++ b/libkmod/macro.h @@ -49,6 +49,8 @@ ((char *)(member_ptr) - offsetof(containing_type, member)) \ - check_types_match(*(member_ptr), ((containing_type *)0)->member)) +/* Attributes */ + #define __must_check __attribute__((warn_unused_result)) #define __printf_format(a,b) __attribute__((format (printf, a, b))) #if !defined(__always_inline)