]> git.ipfire.org Git - thirdparty/kmod.git/commitdiff
kmod_module: extended information gathering.
authorGustavo Sverzut Barbieri <barbieri@profusion.mobi>
Sun, 4 Dec 2011 14:40:00 +0000 (12:40 -0200)
committerLucas De Marchi <lucas.demarchi@profusion.mobi>
Sun, 4 Dec 2011 19:24:08 +0000 (17:24 -0200)
provide means to get:
 * refcount
 * initstate
 * holders
 * sections

this can be used to individually query properties from modules,
similar to /proc/modules (kmod_loaded / kmod_loaded_module).

libkmod/libkmod-module.c
libkmod/libkmod-private.h
libkmod/libkmod-util.c
libkmod/libkmod.h
libkmod/libkmod.sym

index 8bc644f71110b9aefbc3b48db5f2451184e55504..10c8b16501588b8be4d88936f78d9bc39cfb5ce4 100644 (file)
@@ -27,6 +27,8 @@
 #include <string.h>
 #include <ctype.h>
 #include <inttypes.h>
+#include <limits.h>
+#include <dirent.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/mman.h>
@@ -359,3 +361,239 @@ KMOD_EXPORT int kmod_module_insert_module(struct kmod_module *mod,
 
        return err;
 }
+
+KMOD_EXPORT const char *kmod_module_initstate_str(enum kmod_module_initstate state)
+{
+    switch (state) {
+    case KMOD_MODULE_BUILTIN:
+       return "builtin";
+    case KMOD_MODULE_LIVE:
+       return "live";
+    case KMOD_MODULE_COMING:
+       return "coming";
+    case KMOD_MODULE_GOING:
+       return "going";
+    default:
+       return NULL;
+    }
+}
+
+KMOD_EXPORT int kmod_module_get_initstate(const struct kmod_module *mod)
+{
+       char path[PATH_MAX], buf[32];
+       int fd, err, pathlen;
+
+       pathlen = snprintf(path, sizeof(path),
+                               "/sys/module/%s/initstate", mod->name);
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               err = -errno;
+
+               if (pathlen > (int)sizeof("/initstate") - 1) {
+                       struct stat st;
+                       path[pathlen - (sizeof("/initstate") - 1)] = '\0';
+                       if (stat(path, &st) == 0 && S_ISDIR(st.st_mode))
+                               return KMOD_MODULE_BUILTIN;
+               }
+
+               ERR(mod->ctx, "could not open '%s': %s\n",
+                       path, strerror(-err));
+               return err;
+       }
+
+       err = read_str_safe(fd, buf, sizeof(buf));
+       close(fd);
+       if (err < 0) {
+               ERR(mod->ctx, "could not read from '%s': %s\n",
+                       path, strerror(-err));
+               return err;
+       }
+
+       if (strcmp(buf, "live\n") == 0)
+               return KMOD_MODULE_LIVE;
+       else if (strcmp(buf, "coming\n") == 0)
+               return KMOD_MODULE_COMING;
+       else if (strcmp(buf, "going\n") == 0)
+               return KMOD_MODULE_GOING;
+
+       ERR(mod->ctx, "unknown %s: '%s'\n", path, buf);
+       return -EINVAL;
+}
+
+KMOD_EXPORT int kmod_module_get_refcnt(const struct kmod_module *mod)
+{
+       char path[PATH_MAX];
+       long refcnt;
+       int fd, err;
+
+       snprintf(path, sizeof(path), "/sys/module/%s/refcnt", mod->name);
+       fd = open(path, O_RDONLY);
+       if (fd < 0) {
+               err = -errno;
+               ERR(mod->ctx, "could not open '%s': %s\n",
+                       path, strerror(errno));
+               return err;
+       }
+
+       err = read_str_long(fd, &refcnt, 10);
+       close(fd);
+       if (err < 0) {
+               ERR(mod->ctx, "could not read integer from '%s': '%s'\n",
+                       path, strerror(-err));
+               return err;
+       }
+
+       return (int)refcnt;
+}
+
+KMOD_EXPORT struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod)
+{
+       char dname[PATH_MAX];
+       struct kmod_list *list = NULL;
+       DIR *d;
+       struct dirent *de;
+
+       if (mod == NULL)
+               return NULL;
+       snprintf(dname, sizeof(dname), "/sys/module/%s/holders", mod->name);
+
+       d = opendir(dname);
+       if (d == NULL) {
+               ERR(mod->ctx, "could not open '%s': %s\n",
+                       dname, strerror(errno));
+               return NULL;
+       }
+
+       while ((de = readdir(d)) != NULL) {
+               struct kmod_list *node;
+               struct kmod_module *holder;
+               int err;
+
+               if (de->d_name[0] == '.') {
+                       if (de->d_name[1] == '\0' ||
+                           (de->d_name[1] == '.' && de->d_name[2] == '\0'))
+                               continue;
+               }
+
+               err = kmod_module_new_from_name(mod->ctx, de->d_name, &holder);
+               if (err < 0) {
+                       ERR(mod->ctx, "could not create module for '%s': %s\n",
+                               de->d_name, strerror(-err));
+                       continue;
+               }
+
+               node = kmod_list_append(list, holder);
+               if (node)
+                       list = node;
+               else {
+                       ERR(mod->ctx, "out of memory\n");
+                       kmod_module_unref(holder);
+               }
+       }
+
+       closedir(d);
+       return list;
+}
+
+struct kmod_module_section {
+       unsigned long address;
+       char name[];
+};
+
+static void kmod_module_section_free(struct kmod_module_section *section)
+{
+       free(section);
+}
+
+KMOD_EXPORT struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod)
+{
+       char dname[PATH_MAX];
+       struct kmod_list *list = NULL;
+       DIR *d;
+       int dfd;
+       struct dirent *de;
+
+       if (mod == NULL)
+               return NULL;
+       snprintf(dname, sizeof(dname), "/sys/module/%s/sections", mod->name);
+
+       d = opendir(dname);
+       if (d == NULL) {
+               ERR(mod->ctx, "could not open '%s': %s\n",
+                       dname, strerror(errno));
+               return NULL;
+       }
+
+       dfd = dirfd(d);
+       while ((de = readdir(d)) != NULL) {
+               struct kmod_module_section *section;
+               struct kmod_list *node;
+               unsigned long address;
+               size_t namesz;
+               int fd, err;
+
+               if (de->d_name[0] == '.') {
+                       if (de->d_name[1] == '\0' ||
+                           (de->d_name[1] == '.' && de->d_name[2] == '\0'))
+                               continue;
+               }
+
+               fd = openat(dfd, de->d_name, O_RDONLY);
+               if (fd < 0) {
+                       ERR(mod->ctx, "could not open '%s/%s': %s\n",
+                               dname, de->d_name, strerror(errno));
+                       continue;
+               }
+
+               err = read_str_ulong(fd, &address, 16);
+               if (err < 0) {
+                       ERR(mod->ctx, "could not read long from '%s/%s': %s\n",
+                               dname, de->d_name, strerror(-err));
+                       close(fd);
+                       continue;
+               }
+
+               namesz = strlen(de->d_name) + 1;
+               section = malloc(sizeof(struct kmod_module_section) + namesz);
+               section->address = address;
+               memcpy(section->name, de->d_name, namesz);
+
+               node = kmod_list_append(list, section);
+               if (node)
+                       list = node;
+               else {
+                       ERR(mod->ctx, "out of memory\n");
+                       free(section);
+               }
+               close(fd);
+       }
+
+       closedir(d);
+       return list;
+}
+
+KMOD_EXPORT const char *kmod_module_section_get_name(const struct kmod_list *entry)
+{
+       struct kmod_module_section *section;
+       if (entry == NULL)
+               return NULL;
+       section = entry->data;
+       return section->name;
+}
+
+KMOD_EXPORT unsigned long kmod_module_section_get_address(const struct kmod_list *entry)
+{
+       struct kmod_module_section *section;
+       if (entry == NULL)
+               return (unsigned long)-1;
+       section = entry->data;
+       return section->address;
+}
+
+KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list)
+{
+       while (list) {
+               kmod_module_section_free(list->data);
+               list = kmod_list_remove(list);
+       }
+}
index f00f3f9ede653f3e9d53e97c8f18eede339c1cf9..660a85c6490947754a3f859935e6442911a7176d 100644 (file)
@@ -82,4 +82,9 @@ char *underscores(struct kmod_ctx *ctx, char *s) __attribute__((nonnull(1, 2)));
 bool startswith(const char *s, const char *prefix) __attribute__((nonnull(1, 2)));
 void *memdup(const void *p, size_t n) __attribute__((nonnull(1)));
 
+ssize_t read_str_safe(int fd, char *buf, size_t buflen) __must_check __attribute__((nonnull(2)));
+int read_str_long(int fd, long *value, int base) __must_check __attribute__((nonnull(2)));
+int read_str_ulong(int fd, unsigned long *value, int base) __must_check __attribute__((nonnull(2)));
+
+
 #endif
index b6e3cfc53aa0a59a986e29a5eda9a59672a4e6a1..e506b52cdb6df6f755de78949444f5ef387259a8 100644 (file)
@@ -143,3 +143,64 @@ inline void *memdup(const void *p, size_t n)
 
        return memcpy(r, p, n);
 }
+
+ssize_t read_str_safe(int fd, char *buf, size_t buflen) {
+       size_t todo = buflen;
+       size_t done;
+       do {
+               ssize_t r = read(fd, buf, todo);
+               if (r == 0)
+                       break;
+               else if (r > 0)
+                       todo -= r;
+               else {
+                       if (errno == EAGAIN || errno == EWOULDBLOCK ||
+                               errno == EINTR)
+                               continue;
+                       else
+                               return -errno;
+               }
+       } while (todo > 0);
+       done = buflen - todo;
+       if (done == 0)
+               buf[0] = '\0';
+       else {
+               if (done < buflen)
+                       buf[done] = '\0';
+               else if (buf[done - 1] != '\0')
+                       return -ENOSPC;
+       }
+       return done;
+}
+
+int read_str_long(int fd, long *value, int base) {
+       char buf[32], *end;
+       long v;
+       int err;
+       *value = 0;
+       err = read_str_safe(fd, buf, sizeof(buf));
+       if (err < 0)
+               return err;
+       errno = 0;
+       v = strtol(buf, &end, base);
+       if (end == buf || !isspace(*end))
+               return -EINVAL;
+       *value = v;
+       return 0;
+}
+
+int read_str_ulong(int fd, unsigned long *value, int base) {
+       char buf[32], *end;
+       long v;
+       int err;
+       *value = 0;
+       err = read_str_safe(fd, buf, sizeof(buf));
+       if (err < 0)
+               return err;
+       errno = 0;
+       v = strtoul(buf, &end, base);
+       if (end == buf || !isspace(*end))
+               return -EINVAL;
+       *value = v;
+       return 0;
+}
index fca4107303bd7d567e531a75983310bed0247483..c552f2903868543662f8a50cae052c60e16a3d85 100644 (file)
@@ -117,6 +117,23 @@ int kmod_module_insert_module(struct kmod_module *mod, unsigned int flags);
 const char *kmod_module_get_name(const struct kmod_module *mod);
 const char *kmod_module_get_path(const struct kmod_module *mod);
 
+enum kmod_module_initstate {
+       KMOD_MODULE_BUILTIN = 0,
+       KMOD_MODULE_LIVE,
+       KMOD_MODULE_COMING,
+       KMOD_MODULE_GOING
+};
+const char *kmod_module_initstate_str(enum kmod_module_initstate initstate);
+int kmod_module_get_initstate(const struct kmod_module *mod);
+int kmod_module_get_refcnt(const struct kmod_module *mod);
+struct kmod_list *kmod_module_get_holders(const struct kmod_module *mod);
+
+struct kmod_list *kmod_module_get_sections(const struct kmod_module *mod);
+const char *kmod_module_section_get_name(const struct kmod_list *entry);
+unsigned long kmod_module_section_get_address(const struct kmod_list *entry);
+void kmod_module_section_free_list(struct kmod_list *list);
+
+
 #ifdef __cplusplus
 } /* extern "C" */
 #endif
index fcbe8a909fdc4fd501b5a9d5c05111559f3cc0de..07690ddd896fcd49a5dc4f1ddeb4d6f95b0ce74e 100644 (file)
@@ -32,6 +32,16 @@ global:
 
        kmod_module_get_name;
        kmod_module_get_path;
+
+       kmod_module_initstate_str;
+       kmod_module_get_initstate;
+       kmod_module_get_refcnt;
+       kmod_module_get_sections;
+       kmod_module_section_free_list;
+       kmod_module_section_get_name;
+       kmod_module_section_get_address;
+
+       kmod_module_get_holders;
 local:
         *;
 };