mirror of
https://github.com/AuxXxilium/kmod.git
synced 2025-03-09 06:57:59 +07:00
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:
parent
f12ae3c438
commit
69f9dd4369
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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" */
|
||||
|
@ -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:
|
||||
*;
|
||||
};
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user