From 69f9dd4369ec9945b3ca3f4aea800fdb027f47da Mon Sep 17 00:00:00 2001 From: Gustavo Sverzut Barbieri Date: Sun, 4 Dec 2011 14:02:30 -0200 Subject: [PATCH] no more kmod_loaded and kmod_loaded_module. kmod_loaded_get_list() now returns a regular list of kmod_modules, use kmod_module_get_module(), kmod_module_unref() and kmod_module_unref_list() to operate on it. --- libkmod/libkmod-loaded.c | 239 +++++---------------------------------- libkmod/libkmod-module.c | 48 ++++++++ libkmod/libkmod.h | 18 +-- libkmod/libkmod.sym | 7 +- test/test-loaded.c | 40 ++++--- test/test-rmmod.c | 35 +++--- 6 files changed, 122 insertions(+), 265 deletions(-) diff --git a/libkmod/libkmod-loaded.c b/libkmod/libkmod-loaded.c index 06f7f314..6914e57a 100644 --- a/libkmod/libkmod-loaded.c +++ b/libkmod/libkmod-loaded.c @@ -36,230 +36,47 @@ * * 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; } diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index 10c8b165..f18dbb07 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -279,6 +279,54 @@ KMOD_EXPORT struct kmod_module *kmod_module_get_module(const struct kmod_list *e 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 diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index c552f290..c6d27a35 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -63,28 +63,13 @@ struct kmod_list *kmod_list_prev(const struct kmod_list *first_entry, 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, @@ -133,6 +118,7 @@ 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); +long kmod_module_get_size(const struct kmod_module *mod); #ifdef __cplusplus } /* extern "C" */ diff --git a/libkmod/libkmod.sym b/libkmod/libkmod.sym index 07690ddd..7b95749f 100644 --- a/libkmod/libkmod.sym +++ b/libkmod/libkmod.sym @@ -11,12 +11,7 @@ global: 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; @@ -42,6 +37,8 @@ global: kmod_module_section_get_address; kmod_module_get_holders; + + kmod_module_get_size; local: *; }; diff --git a/test/test-loaded.c b/test/test-loaded.c index e5cfe13d..c862cd97 100644 --- a/test/test-loaded.c +++ b/test/test-loaded.c @@ -11,7 +11,6 @@ int main(int argc, char *argv[]) { struct kmod_ctx *ctx; - struct kmod_loaded *mod; struct kmod_list *list, *itr; int err; @@ -21,11 +20,7 @@ int main(int argc, char *argv[]) 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); @@ -34,16 +29,31 @@ int main(int argc, char *argv[]) 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); diff --git a/test/test-rmmod.c b/test/test-rmmod.c index d7690b34..7a7bc5b4 100644 --- a/test/test-rmmod.c +++ b/test/test-rmmod.c @@ -12,9 +12,8 @@ int main(int argc, char *argv[]) { 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]; @@ -25,33 +24,33 @@ int main(int argc, char *argv[]) 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; } -- 2.47.2