From: Gustavo Sverzut Barbieri Date: Sat, 10 Dec 2011 22:47:01 +0000 (-0200) Subject: export module's options and commands. X-Git-Tag: v1~55^2~8 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=bd3f5535268836aa697f84fa6946e4b0fc22df0b;p=thirdparty%2Fkmod.git export module's options and commands. This will be required to implement modprobe later. The implementation follows "man modprobe.conf" and allows options to be specified for alias as well, thus the need for kmod_resolve_alias_options(). Example mod-a.conf: options mod-a a=1 b=2 options mod-a c=3 alias mymod-a mod-a options mymod-a d=4 Results in: options mod-a a=1 b=2 c=3 options mymod-a a=1 b=2 c=3 d=4 Install commands are being concatenated with ";", but manpage is not clean about this behavior. --- diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index 429f58af..dd3a036b 100644 --- a/libkmod/libkmod-config.c +++ b/libkmod/libkmod-config.c @@ -63,6 +63,26 @@ const char *kmod_alias_get_modname(const struct kmod_list *l) { return alias->modname; } +const char *kmod_option_get_options(const struct kmod_list *l) { + const struct kmod_options *alias = l->data; + return alias->options; +} + +const char *kmod_option_get_modname(const struct kmod_list *l) { + const struct kmod_options *alias = l->data; + return alias->modname; +} + +const char *kmod_command_get_command(const struct kmod_list *l) { + const struct kmod_command *alias = l->data; + return alias->command; +} + +const char *kmod_command_get_modname(const struct kmod_list *l) { + const struct kmod_command *alias = l->data; + return alias->modname; +} + static int kmod_config_add_command(struct kmod_config *config, const char *modname, const char *command, diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index b10d4120..738c3f3f 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -46,10 +46,16 @@ struct kmod_module { struct kmod_ctx *ctx; char *path; struct kmod_list *dep; - int refcount; + char *options; + char *install_commands; + char *remove_commands; int n_dep; + int refcount; struct { bool dep : 1; + bool options : 1; + bool install_commands : 1; + bool remove_commands : 1; } init; char name[]; }; @@ -285,6 +291,9 @@ KMOD_EXPORT struct kmod_module *kmod_module_unref(struct kmod_module *mod) kmod_module_unref_list(mod->dep); kmod_unref(mod->ctx); + free(mod->options); + free(mod->install_commands); + free(mod->remove_commands); free(mod->path); free(mod); return NULL; @@ -819,3 +828,156 @@ KMOD_EXPORT void kmod_module_section_free_list(struct kmod_list *list) list = kmod_list_remove(list); } } + +KMOD_EXPORT const char *kmod_module_get_options(const struct kmod_module *mod) +{ + if (mod == NULL) + return NULL; + + if (!mod->init.options) { + /* lazy init */ + struct kmod_module *m = (struct kmod_module *)mod; + const struct kmod_list *l, *ctx_options; + char *opts = NULL; + size_t optslen = 0; + ctx_options = kmod_get_options(mod->ctx); + kmod_list_foreach(l, ctx_options) { + const char *modname = kmod_option_get_modname(l); + const char *str; + size_t len; + void *tmp; + + if (strcmp(modname, mod->name) != 0) + continue; + + str = kmod_option_get_options(l); + len = strlen(str); + if (len < 1) + continue; + + tmp = realloc(opts, optslen + len + 2); + if (tmp == NULL) { + free(opts); + goto failed; + } + opts = tmp; + if (optslen > 0) { + opts[optslen] = ' '; + optslen++; + } + memcpy(opts + optslen, str, len); + optslen += len; + opts[optslen] = '\0'; + } + m->init.options = true; + m->options = opts; + } + + return mod->options; + +failed: + ERR(mod->ctx, "out of memory\n"); + return NULL; +} + +KMOD_EXPORT const char *kmod_module_get_install_commands(const struct kmod_module *mod) +{ + if (mod == NULL) + return NULL; + + if (!mod->init.install_commands) { + /* lazy init */ + struct kmod_module *m = (struct kmod_module *)mod; + const struct kmod_list *l, *ctx_install_commands; + char *cmds = NULL; + size_t cmdslen = 0; + ctx_install_commands = kmod_get_install_commands(mod->ctx); + kmod_list_foreach(l, ctx_install_commands) { + const char *modname = kmod_command_get_modname(l); + const char *str; + size_t len; + void *tmp; + + if (strcmp(modname, mod->name) != 0) + continue; + + str = kmod_command_get_command(l); + len = strlen(str); + if (len < 1) + continue; + + tmp = realloc(cmds, cmdslen + len + 2); + if (tmp == NULL) { + free(cmds); + goto failed; + } + cmds = tmp; + if (cmdslen > 0) { + cmds[cmdslen] = ';'; + cmdslen++; + } + memcpy(cmds + cmdslen, str, len); + cmdslen += len; + cmds[cmdslen] = '\0'; + } + m->init.install_commands = true; + m->install_commands = cmds; + } + + return mod->install_commands; + +failed: + ERR(mod->ctx, "out of memory\n"); + return NULL; +} + +KMOD_EXPORT const char *kmod_module_get_remove_commands(const struct kmod_module *mod) +{ + if (mod == NULL) + return NULL; + + if (!mod->init.remove_commands) { + /* lazy init */ + struct kmod_module *m = (struct kmod_module *)mod; + const struct kmod_list *l, *ctx_remove_commands; + char *cmds = NULL; + size_t cmdslen = 0; + ctx_remove_commands = kmod_get_remove_commands(mod->ctx); + kmod_list_foreach(l, ctx_remove_commands) { + const char *modname = kmod_command_get_modname(l); + const char *str; + size_t len; + void *tmp; + + if (strcmp(modname, mod->name) != 0) + continue; + + str = kmod_command_get_command(l); + len = strlen(str); + if (len < 1) + continue; + + tmp = realloc(cmds, cmdslen + len + 2); + if (tmp == NULL) { + free(cmds); + goto failed; + } + cmds = tmp; + if (cmdslen > 0) { + cmds[cmdslen] = ';'; + cmdslen++; + } + memcpy(cmds + cmdslen, str, len); + cmdslen += len; + cmds[cmdslen] = '\0'; + } + m->init.remove_commands = true; + m->remove_commands = cmds; + } + + return mod->remove_commands; + +failed: + ERR(mod->ctx, "out of memory\n"); + return NULL; +} diff --git a/libkmod/libkmod-private.h b/libkmod/libkmod-private.h index ce81ae02..eb98ddc2 100644 --- a/libkmod/libkmod-private.h +++ b/libkmod/libkmod-private.h @@ -78,6 +78,10 @@ struct kmod_module *kmod_pool_get_module(struct kmod_ctx *ctx, const char *name) void kmod_pool_add_module(struct kmod_ctx *ctx, struct kmod_module *mod) __attribute__((nonnull(1,2))); void kmod_pool_del_module(struct kmod_ctx *ctx, struct kmod_module *mod) __attribute__((nonnull(1,2))); +const struct kmod_list *kmod_get_options(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1))); +const struct kmod_list *kmod_get_install_commands(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1))); +const struct kmod_list *kmod_get_remove_commands(const struct kmod_ctx *ctx) __must_check __attribute__((nonnull(1))); + /* libkmod-config.c */ struct kmod_config { @@ -92,6 +96,11 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **config) __attribu void kmod_config_free(struct kmod_config *config) __attribute__((nonnull(1))); const char *kmod_alias_get_name(const struct kmod_list *l) __attribute__((nonnull(1))); const char *kmod_alias_get_modname(const struct kmod_list *l) __attribute__((nonnull(1))); +const char *kmod_option_get_options(const struct kmod_list *l) __attribute__((nonnull(1))); +const char *kmod_option_get_modname(const struct kmod_list *l) __attribute__((nonnull(1))); +const char *kmod_command_get_command(const struct kmod_list *l) __attribute__((nonnull(1))); +const char *kmod_command_get_modname(const struct kmod_list *l) __attribute__((nonnull(1))); + /* libkmod-module.c */ int kmod_module_parse_depline(struct kmod_module *mod, char *line) __attribute__((nonnull(1, 2))); diff --git a/libkmod/libkmod.c b/libkmod/libkmod.c index b1f4b714..59ed81b7 100644 --- a/libkmod/libkmod.c +++ b/libkmod/libkmod.c @@ -622,3 +622,102 @@ KMOD_EXPORT void kmod_unload_resources(struct kmod_ctx *ctx) } } } + +KMOD_EXPORT int kmod_resolve_alias_options(struct kmod_ctx *ctx, const char *alias, char **options) +{ + struct kmod_list *modules = NULL, *l; + char *opts = NULL; + size_t optslen = 0; + int err; + + if (ctx == NULL || options == NULL) + return -ENOENT; + + err = kmod_module_new_from_lookup(ctx, alias, &modules); + if (err >= 0) { + kmod_list_foreach(l, modules) { + const char *str = kmod_module_get_options(l->data); + size_t len; + void *tmp; + + if (str == NULL) + continue; + len = strlen(str); + + tmp = realloc(opts, optslen + len + 2); + if (tmp == NULL) + goto failed; + opts = tmp; + if (optslen > 0) { + opts[optslen] = ' '; + optslen++; + } + memcpy(opts + optslen, str, len); + optslen += len; + opts[optslen] = '\0'; + } + } + + kmod_list_foreach(l, ctx->config->options) { + const struct kmod_list *ml; + const char *modname = kmod_option_get_modname(l); + const char *str; + bool already_done = false; + size_t len; + void *tmp; + + if (fnmatch(modname, alias, 0) != 0) + continue; + + kmod_list_foreach(ml, modules) { + const char *mln = kmod_module_get_name(ml->data); + if (fnmatch(modname, mln, 0) == 0) { + already_done = true; + break; + } + } + if (already_done) + continue; + + str = kmod_option_get_options(l); + len = strlen(str); + tmp = realloc(opts, optslen + len + 2); + if (tmp == NULL) + goto failed; + opts = tmp; + if (optslen > 0) { + opts[optslen] = ' '; + optslen++; + } + memcpy(opts + optslen, str, len); + optslen += len; + opts[optslen] = '\0'; + } + + DBG(ctx, "alias=%s options='%s'\n", alias, opts); + kmod_module_unref_list(modules); + *options = opts; + return 0; + +failed: + kmod_module_unref_list(modules); + free(opts); + ERR(ctx, "out of memory\n"); + *options = NULL; + return -ENOMEM; +} + +const struct kmod_list *kmod_get_options(const struct kmod_ctx *ctx) +{ + return ctx->config->options; +} + +const struct kmod_list *kmod_get_install_commands(const struct kmod_ctx *ctx) +{ + return ctx->config->install_commands; +} + +const struct kmod_list *kmod_get_remove_commands(const struct kmod_ctx *ctx) +{ + return ctx->config->remove_commands; +} diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index 4bff2a31..a7fc7764 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -127,6 +127,12 @@ void kmod_module_section_free_list(struct kmod_list *list); long kmod_module_get_size(const struct kmod_module *mod); +const char *kmod_module_get_options(const struct kmod_module *mod); +const char *kmod_module_get_install_commands(const struct kmod_module *mod); +const char *kmod_module_get_remove_commands(const struct kmod_module *mod); + +int kmod_resolve_alias_options(struct kmod_ctx *ctx, const char *alias, char **options); + #ifdef __cplusplus } /* extern "C" */ #endif diff --git a/libkmod/libkmod.sym b/libkmod/libkmod.sym index 0487ff8e..f383331a 100644 --- a/libkmod/libkmod.sym +++ b/libkmod/libkmod.sym @@ -41,6 +41,11 @@ global: kmod_module_section_get_address; kmod_module_get_holders; kmod_module_get_size; + + kmod_module_get_options; + kmod_module_get_install_commands; + kmod_module_get_remove_commands; + kmod_resolve_alias_options; local: *; }; diff --git a/test/test-lookup.c b/test/test-lookup.c index 4d6a00d1..9f3bebcc 100644 --- a/test/test-lookup.c +++ b/test/test-lookup.c @@ -33,8 +33,9 @@ int main(int argc, char *argv[]) const char *alias = NULL; struct kmod_ctx *ctx; struct kmod_list *list = NULL, *l; + char *options; int load_resources = 0; - int i, err; + int err; printf("libkmod version %s\n", VERSION); @@ -93,10 +94,27 @@ int main(int argc, char *argv[]) kmod_list_foreach(l, list) { struct kmod_module *mod = kmod_module_get_module(l); + const char *str; + printf("\t%s\n", kmod_module_get_name(mod)); + str = kmod_module_get_options(mod); + if (str) + printf("\t\toptions: '%s'\n", str); + str = kmod_module_get_install_commands(mod); + if (str) + printf("\t\tinstall commands: '%s'\n", str); + str = kmod_module_get_remove_commands(mod); + if (str) + printf("\t\tremove commands: '%s'\n", str); kmod_module_unref(mod); } + err = kmod_resolve_alias_options(ctx, alias, &options); + if (err == 0) { + printf("Alias options: '%s'\n", options); + free(options); + } + kmod_module_unref_list(list); kmod_unref(ctx);