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.
This commit is contained in:
Gustavo Sverzut Barbieri 2011-12-04 14:02:30 -02:00 committed by Lucas De Marchi
parent f12ae3c438
commit 69f9dd4369
6 changed files with 125 additions and 268 deletions

View File

@ -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;
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);
}
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));
if (fp == NULL) {
int err = -errno;
ERR(ctx, "could not open /proc/modules: %s\n", strerror(errno));
return err;
}
loaded_modules_free_module(m);
entry = kmod_list_remove(entry);
while (fgets(line, sizeof(line), fp)) {
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);
*list = l;
return 0;
}

View File

@ -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

View File

@ -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" */

View File

@ -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:
*;
};

View File

@ -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;
kmod_loaded_unref(mod);
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_module_unref_list(list);
kmod_unref(ctx);

View File

@ -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;
}