Add functions to operate on modules
diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c
new file mode 100644
index 0000000..5e8ae73
--- /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 <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
+ * 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 <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <string.h>
+
+#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;
+}