]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
Add libkmod-loaded to handle live modules information
authorLucas De Marchi <lucas.demarchi@profusion.mobi>
Tue, 22 Nov 2011 07:42:09 +0000 (05:42 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Wed, 23 Nov 2011 13:44:17 +0000 (11:44 -0200)
All the functions needed by a lsmod binary are in place.
test/test-loaded.c implements it with the same output of lsmod.

Makefile.am
libkmod/libkmod-loaded.c [new file with mode: 0644]
libkmod/libkmod.h
libkmod/libkmod.sym
test/.gitignore
test/test-loaded.c [new file with mode: 0644]

index 57a1da3c23c87e9246863364dc485e7d73f80945..a6b81db8bd5f339ee4484b088fd73ecd4de41b13 100644 (file)
@@ -31,7 +31,8 @@ libkmod_libkmod_la_SOURCES =\
        libkmod/libkmod-private.h \
        libkmod/libkmod-util.h \
        libkmod/libkmod.c \
-       libkmod/libkmod-list.c
+       libkmod/libkmod-list.c \
+       libkmod/libkmod-loaded.c
 
 EXTRA_DIST += libkmod/libkmod.sym
 
@@ -42,8 +43,11 @@ libkmod_libkmod_la_LDFLAGS = $(AM_LDFLAGS) \
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libkmod/libkmod.pc
 
-TESTS = test/test-init
+TESTS = test/test-init test/test-loaded
 
-check_PROGRAMS = test/test-init
+check_PROGRAMS = test/test-init test/test-loaded
 test_test_init_SOURCES = test/test-init.c
 test_test_init_LDADD = libkmod/libkmod.la
+
+test_test_loaded_SOURCES = test/test-loaded.c
+test_test_loaded_LDADD = libkmod/libkmod.la
diff --git a/libkmod/libkmod-loaded.c b/libkmod/libkmod-loaded.c
new file mode 100644 (file)
index 0000000..b0bed74
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ * 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 "libkmod.h"
+#include "libkmod-private.h"
+
+/**
+ * SECTION:libkmod-loaded
+ * @short_description: currently loaded modules
+ *
+ * Information about currently loaded modules, as reported by Linux kernel
+ */
+
+/**
+ * kmod_loaded:
+ *
+ * Opaque object representing a loaded module.
+ */
+struct kmod_loaded {
+       struct kmod_ctx *ctx;
+       int refcount;
+       struct kmod_list *modules;
+       bool parsed;
+};
+
+struct kmod_loaded_module {
+       char *name;
+       long size;
+       int use_count;
+       char *deps;
+       uintptr_t addr;
+};
+
+KMOD_EXPORT int kmod_loaded_new(struct kmod_ctx *ctx, struct kmod_loaded **mod)
+{
+       struct kmod_loaded *m;
+
+       m = calloc(1, sizeof(*m));
+       if (m == NULL)
+               return -ENOMEM;
+
+       m->refcount = 1;
+       m->ctx = ctx;
+       *mod = m;
+       return 0;
+}
+
+KMOD_EXPORT struct kmod_loaded *kmod_loaded_ref(struct kmod_loaded *mod)
+{
+       if (mod == NULL)
+               return NULL;
+       mod->refcount++;
+       return mod;
+}
+
+static void loaded_modules_free_module(struct kmod_loaded_module *m)
+{
+       free(m->name);
+       free(m->deps);
+       free(m);
+}
+
+static void loaded_modules_free(struct kmod_loaded *mod)
+{
+       while (mod->modules != NULL) {
+               loaded_modules_free_module(mod->modules->data);
+               mod->modules = kmod_list_remove(mod->modules);
+       }
+}
+
+KMOD_EXPORT struct kmod_loaded *kmod_loaded_unref(struct kmod_loaded *mod)
+{
+       if (mod == NULL)
+               return NULL;
+       mod->refcount--;
+       dbg(mod->ctx, "kmod_loaded %p released\n", mod);
+       loaded_modules_free(mod);
+       free(mod);
+       return NULL;
+}
+
+static int loaded_modules_parse(struct kmod_loaded *mod,
+                                               struct kmod_list **list)
+{
+       struct kmod_list *l = NULL;
+       FILE *fp;
+       char line[4096];
+
+       fp = fopen("/proc/modules", "r");
+       if (fp == NULL)
+               return -errno;
+
+       while (fgets(line, sizeof(line), fp)) {
+               char *tok;
+               struct kmod_loaded_module *m;
+
+               m = calloc(1, sizeof(*m));
+               if (m == NULL)
+                       goto err;
+
+               tok = strtok(line, " \t");
+               m->name = strdup(tok);
+
+               tok = strtok(NULL, " \t\n");
+               m->size = atoi(tok);
+
+               /* Null if no module unloading is supported */
+               tok = strtok(NULL, " \t\n");
+               if (tok == NULL)
+                       goto done;
+
+               m->use_count = atoi(tok);
+               tok = strtok(NULL, "\n");
+               if (tok == NULL)
+                       goto done;
+
+               /* Strip trailing comma */
+               if (strchr(tok, ',')) {
+                       char *end;
+                       tok = strtok(tok, " \t");
+                       end = &tok[strlen(tok) - 1];
+                       if (*end == ',')
+                               *end = '\0';
+                       m->deps = strdup(tok);
+                       tok = &end[2];
+               } else if (tok[0] == '-' && tok[1] == '\0')
+                       goto done;
+               else if (tok[0] == '-' && isspace(tok[1]))
+                       tok = &tok[3];
+
+               tok = strtok(tok, " \t\n");
+               if (tok == NULL)
+                       goto done;
+
+               tok = strtok(NULL, " \t\n");
+               if (tok == NULL)
+                       goto done;
+
+               sscanf(tok, "%" SCNxPTR, &m->addr);
+
+done:
+               l = kmod_list_append(l, m);
+       }
+
+       fclose(fp);
+       mod->parsed = 1;
+       *list = l;
+
+       return 0;
+
+err:
+       fclose(fp);
+       mod->modules = l;
+       loaded_modules_free(mod);
+       mod->modules = NULL;
+       return -ENOMEM;
+}
+
+KMOD_EXPORT int kmod_loaded_get_list(struct kmod_loaded *mod,
+                                               struct kmod_list **list)
+{
+       if (mod == NULL)
+               return -ENOENT;
+
+       if (!mod->parsed) {
+               int err = loaded_modules_parse(mod, &mod->modules);
+               if (err < 0)
+                       return err;
+       }
+
+       *list = mod->modules;
+
+       return 0;
+}
+
+KMOD_EXPORT int kmod_loaded_get_module_info(struct kmod_list *entry,
+                                               const char **name,
+                                               long *size, int *use_count,
+                                               const char **deps,
+                                               uintptr_t *addr)
+{
+       struct kmod_loaded_module *m;
+
+       if (entry == NULL)
+               return -ENOENT;
+
+       m = entry->data;
+
+       if (name)
+               *name = m->name;
+       if (size)
+               *size = m->size;
+       if (use_count)
+               *use_count = m->use_count;
+       if (addr)
+               *addr = m->addr;
+       if (deps)
+               *deps = m->deps;
+
+       return 0;
+}
index 2f3006dd89769a88939c675dc9cb6950030adbae..93c5da1935d816c45f095a0e0ea8653ab9cf0327 100644 (file)
@@ -22,6 +22,7 @@
 #define _LIBABC_H_
 
 #include <stdarg.h>
+#include <inttypes.h>
 
 #ifdef __cplusplus
 extern "C" {
@@ -64,4 +65,13 @@ struct kmod_list *kmod_list_next(struct kmod_list *first_entry,
 } /* extern "C" */
 #endif
 
+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);
+struct kmod_loaded *kmod_loaded_unref(struct kmod_loaded *mod);
+int kmod_loaded_get_list(struct kmod_loaded *mod, struct kmod_list **list);
+int kmod_loaded_get_module_info(struct kmod_list *entry, const char **name,
+                               long *size, int *use_count, const char **deps,
+                               uintptr_t *addr);
+
 #endif
index 3a06d74e64d08923222a70c293d59cce0e300e9f..0482adafebfe4e6ecb138da9054de5450d5cc945 100644 (file)
@@ -10,6 +10,11 @@ global:
        kmod_set_userdata;
        kmod_unref;
        kmod_list_next;
+       kmod_loaded_new;
+       kmod_loaded_ref;
+       kmod_loaded_unref;
+       kmod_loaded_get_list;
+       kmod_loaded_get_module_info;
 local:
         *;
 };
index 9f66dbd7ea7792fba9e8af06cb639ed7ef539d4c..20b56b765faf7a0ba4683032317e18bb071c7a7a 100644 (file)
@@ -1,2 +1,3 @@
 .dirstamp
 test-init
+test-loaded
diff --git a/test/test-loaded.c b/test/test-loaded.c
new file mode 100644 (file)
index 0000000..c81c288
--- /dev/null
@@ -0,0 +1,51 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <errno.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <string.h>
+#include <libkmod.h>
+
+
+int main(int argc, char *argv[])
+{
+       struct kmod_ctx *ctx;
+       struct kmod_loaded *mod;
+       struct kmod_list *list, *itr;
+       int err;
+
+       ctx = kmod_new();
+       if (ctx == NULL)
+               exit(EXIT_FAILURE);
+
+       printf("libkmod version %s\n", VERSION);
+
+       err = kmod_loaded_new(ctx, &mod);
+       if (err < 0)
+               exit(EXIT_FAILURE);
+
+       err = kmod_loaded_get_list(mod, &list);
+       if (err < 0) {
+               fprintf(stderr, "%s\n", strerror(-err));
+               exit(EXIT_FAILURE);
+       }
+
+       printf("Module                  Size  Used by\n");
+
+       kmod_list_foreach(itr, list) {
+               const char *name, *deps;
+               long size;
+               int use_count;
+               kmod_loaded_get_module_info(itr, &name, &size, &use_count,
+                                                               &deps, NULL);
+               printf("%-19s %8ld  %d %s\n", name, size,
+                                       use_count, deps ? deps : "");
+       }
+
+       kmod_loaded_unref(mod);
+
+       kmod_unref(ctx);
+
+       return EXIT_SUCCESS;
+}