*
* 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;
- struct kmod_list *modules;
- int refcount;
- bool parsed;
-};
-
-struct kmod_loaded_module {
- char *name;
- long size;
- char *deps;
- uintptr_t addr;
- int use_count;
-};
-
-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 = kmod_ref(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;
-
- if (--mod->refcount > 0)
- return mod;
-
- DBG(mod->ctx, "kmod_loaded %p released\n", mod);
-
- kmod_unref(mod->ctx);
- loaded_modules_free(mod);
- free(mod);
- return NULL;
-}
-
-static int loaded_modules_parse(struct kmod_loaded *mod,
+KMOD_EXPORT int kmod_loaded_get_list(struct kmod_ctx *ctx,
struct kmod_list **list)
{
struct kmod_list *l = NULL;
FILE *fp;
char line[4096];
+ if (ctx == NULL || list == NULL)
+ return -ENOENT;
+
fp = fopen("/proc/modules", "r");
- if (fp == NULL)
- return -errno;
+ if (fp == NULL) {
+ int err = -errno;
+ ERR(ctx, "could not open /proc/modules: %s\n", strerror(errno));
+ return err;
+ }
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;
-
- m->addr = strtoull(tok, NULL, 16);
-
-done:
- l = kmod_list_append(l, m);
+ struct kmod_module *m;
+ struct kmod_list *node;
+ int err;
+ char *saveptr, *name = strtok_r(line, " \t", &saveptr);
+
+ err = kmod_module_new_from_name(ctx, name, &m);
+ if (err < 0) {
+ ERR(ctx, "could not get module from name '%s': %s\n",
+ name, strerror(-err));
+ continue;
+ }
+
+ node = kmod_list_append(l, m);
+ if (node)
+ l = node;
+ else {
+ ERR(ctx, "out of memory\n");
+ kmod_module_unref(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(const struct kmod_list *entry,
- const char **name,
- long *size, int *use_count,
- const char **deps,
- uintptr_t *addr)
-{
- const 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;
-}
-
-extern long delete_module(const char *name, unsigned int flags);
-
-KMOD_EXPORT int kmod_loaded_remove_module(struct kmod_loaded *mod,
- struct kmod_list *entry,
- unsigned int flags)
-{
- struct kmod_loaded_module *m;
- int err;
-
- if (mod == NULL)
- return -ENOSYS;
-
- if (entry == NULL)
- return -ENOENT;
-
- m = entry->data;
-
- /* Filter out other flags */
- flags &= (KMOD_REMOVE_FORCE | KMOD_REMOVE_NOWAIT);
-
- err = delete_module(m->name, flags);
- if (err != 0) {
- ERR(mod->ctx, "Removing '%s': %s\n", m->name,
- strerror(-err));
- return err;
- }
-
- loaded_modules_free_module(m);
- entry = kmod_list_remove(entry);
-
return 0;
}
return kmod_module_ref(entry->data);
}
+KMOD_EXPORT long kmod_module_get_size(const struct kmod_module *mod)
+{
+ // FIXME TODO: this should be available from /sys/module/foo
+ FILE *fp;
+ char line[4096];
+ int lineno = 0;
+ long size = -ENOENT;
+
+ if (mod == NULL)
+ return -ENOENT;
+
+ fp = fopen("/proc/modules", "r");
+ if (fp == NULL) {
+ int err = -errno;
+ ERR(mod->ctx,
+ "could not open /proc/modules: %s\n", strerror(errno));
+ return err;
+ }
+
+ while (fgets(line, sizeof(line), fp)) {
+ char *saveptr, *endptr, *tok = strtok_r(line, " \t", &saveptr);
+ long value;
+
+ lineno++;
+ if (tok == NULL || strcmp(tok, mod->name) != 0)
+ continue;
+
+ tok = strtok_r(NULL, " \t", &saveptr);
+ if (tok == NULL) {
+ ERR(mod->ctx,
+ "invalid line format at /proc/modules:%d\n", lineno);
+ break;
+ }
+
+ value = strtol(tok, &endptr, 10);
+ if (endptr == tok || *endptr != '\0') {
+ ERR(mod->ctx,
+ "invalid line format at /proc/modules:%d\n", lineno);
+ break;
+ }
+
+ size = value;
+ break;
+ }
+ fclose(fp);
+ return size;
+}
+
KMOD_EXPORT const char *kmod_module_get_name(const struct kmod_module *mod)
{
// FIXME calculate name if name == NULL
list_entry != NULL; \
list_entry = kmod_list_next(first_entry, list_entry))
-/*
- * 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);
-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(const struct kmod_list *entry,
- const char **name, long *size, int *use_count,
- const char **deps, uintptr_t *addr);
+int kmod_loaded_get_list(struct kmod_ctx *ctx, struct kmod_list **list);
enum kmod_remove {
KMOD_REMOVE_FORCE = O_TRUNC,
KMOD_REMOVE_NOWAIT = O_NONBLOCK,
};
-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,
unsigned long kmod_module_section_get_address(const struct kmod_list *entry);
void kmod_module_section_free_list(struct kmod_list *list);
+long kmod_module_get_size(const struct kmod_module *mod);
#ifdef __cplusplus
} /* extern "C" */
kmod_unref;
kmod_list_next;
kmod_list_prev;
- kmod_loaded_new;
- kmod_loaded_ref;
- kmod_loaded_unref;
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_section_get_address;
kmod_module_get_holders;
+
+ kmod_module_get_size;
local:
*;
};
int main(int argc, char *argv[])
{
struct kmod_ctx *ctx;
- struct kmod_loaded *mod;
struct kmod_list *list, *itr;
int err;
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);
+ err = kmod_loaded_get_list(ctx, &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 : "");
+ struct kmod_module *mod = kmod_module_get_module(itr);
+ const char *name = kmod_module_get_name(mod);
+ int use_count = kmod_module_get_refcnt(mod);
+ long size = kmod_module_get_size(mod);
+ struct kmod_list *holders, *hitr;
+ int first = 1;
+
+ printf("%-19s %8ld %d ", name, size, use_count);
+ holders = kmod_module_get_holders(mod);
+ kmod_list_foreach(hitr, holders) {
+ struct kmod_module *hm = kmod_module_get_module(hitr);
+
+ if (!first)
+ putchar(',');
+ else
+ first = 0;
+
+ fputs(kmod_module_get_name(hm), stdout);
+ kmod_module_unref(hm);
+ }
+ putchar('\n');
+ kmod_module_unref_list(holders);
+ kmod_module_unref(mod);
}
-
- kmod_loaded_unref(mod);
+ kmod_module_unref_list(list);
kmod_unref(ctx);
{
const char *modname = NULL;
struct kmod_ctx *ctx;
- struct kmod_loaded *mod;
struct kmod_list *list, *itr;
- int err;
+ int err, count = 0;
if (argc == 2)
modname = argv[1];
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);
+ err = kmod_loaded_get_list(ctx, &list);
if (err < 0) {
fprintf(stderr, "%s\n", strerror(-err));
exit(EXIT_FAILURE);
}
+ err = 0;
kmod_list_foreach(itr, list) {
- const char *name;
- int use_count;
-
- kmod_loaded_get_module_info(itr, &name, NULL, &use_count,
- NULL, NULL);
+ struct kmod_module *mod = kmod_module_get_module(itr);
+ const char *name = kmod_module_get_name(mod);
if ((modname && !strcmp(modname, name)) ||
- (modname == NULL && use_count == 0)) {
+ (modname == NULL && kmod_module_get_refcnt(mod) < 1)) {
printf("Trying to remove '%s'\n", name);
- kmod_loaded_remove_module(mod, itr, 0);
- break;
+ err = kmod_module_remove_module(mod, 0);
+ if (err == 0)
+ count++;
+ else {
+ fprintf(stderr, "Error removing %s: %s\n",
+ name, strerror(-err));
+ }
}
- }
- kmod_loaded_unref(mod);
+ kmod_module_unref(mod);
+ }
+ kmod_module_unref_list(list);
kmod_unref(ctx);
- return EXIT_SUCCESS;
+ return count > 0;
}