diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index 429f58a..dd3a036 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 b10d412..738c3f3 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 ce81ae0..eb98ddc 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 b1f4b71..59ed81b 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 4bff2a3..a7fc776 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 0487ff8..f383331 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 4d6a00d..9f3bebc 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);