diff --git a/libkmod/docs/libkmod-docs.xml b/libkmod/docs/libkmod-docs.xml index 674fe3a5..c4f9810e 100644 --- a/libkmod/docs/libkmod-docs.xml +++ b/libkmod/docs/libkmod-docs.xml @@ -60,4 +60,8 @@ Index of new symbols in 33 + + Index of new symbols in 35 + + diff --git a/libkmod/docs/libkmod-sections.txt b/libkmod/docs/libkmod-sections.txt index dd502647..aa899037 100644 --- a/libkmod/docs/libkmod-sections.txt +++ b/libkmod/docs/libkmod-sections.txt @@ -35,6 +35,7 @@ kmod_list_prev kmod_config_iter kmod_config_get_blacklists kmod_config_get_install_commands +kmod_config_get_masks kmod_config_get_remove_commands kmod_config_get_aliases kmod_config_get_options diff --git a/libkmod/libkmod-config.c b/libkmod/libkmod-config.c index 9ca9d2f2..073ce63f 100644 --- a/libkmod/libkmod-config.c +++ b/libkmod/libkmod-config.c @@ -50,6 +50,11 @@ struct kmod_weakdep { unsigned int n_weak; }; +const char *kmod_mask_get_modname(const struct kmod_list *l) +{ + return l->data; +} + const char *kmod_blacklist_get_modname(const struct kmod_list *l) { return l->data; @@ -231,6 +236,27 @@ static int kmod_config_add_blacklist(struct kmod_config *config, const char *mod return 0; } +static int kmod_config_add_mask(struct kmod_config *config, const char *modname) +{ + _cleanup_free_ char *p; + struct kmod_list *list; + + DBG(config->ctx, "modname=%s\n", modname); + + _clang_suppress_alloc_ p = strdup(modname); + if (!p) + return -ENOMEM; + + list = kmod_list_append(config->masks, p); + if (!list) + return -ENOMEM; + + TAKE_PTR(p); + config->masks = list; + + return 0; +} + static int kmod_config_add_softdep(struct kmod_config *config, const char *modname, const char *line) { @@ -606,18 +632,24 @@ static char *weakdep_to_char(struct kmod_weakdep *dep) static void kcmdline_parse_result(struct kmod_config *config, char *modname, char *param, char *value) { + bool is_blacklist, is_mask; if (modname == NULL || param == NULL) return; DBG(config->ctx, "%s %s\n", modname, param); - if (streq(modname, "modprobe") && strstartswith(param, "blacklist=")) { + is_blacklist = strstartswith(param, "blacklist="); + is_mask = strstartswith(param, "mask="); + if (streq(modname, "modprobe") && (is_blacklist || is_mask)) { for (;;) { char *t = strsep(&value, ","); if (t == NULL) break; - kmod_config_add_blacklist(config, t); + if (is_blacklist) + kmod_config_add_blacklist(config, t); + else + kmod_config_add_mask(config, t); } } else { if (underscores(modname) < 0) { @@ -823,6 +855,13 @@ static int kmod_config_parse(struct kmod_config *config, int fd, const char *fil kmod_config_add_command(config, modname, installcmd, cmd, &config->install_commands); + } else if (streq(cmd, "mask")) { + char *modname = strtok_r(NULL, "\t ", &saveptr); + + if (underscores(modname) < 0) + goto syntax_error; + + kmod_config_add_mask(config, modname); } else if (streq(cmd, "remove")) { char *modname = strtok_r(NULL, "\t ", &saveptr); char *removecmd = strtok_r(NULL, "\0", &saveptr); @@ -872,6 +911,7 @@ void kmod_config_free(struct kmod_config *config) kmod_list_release(config->blacklists, free); kmod_list_release(config->options, free); kmod_list_release(config->install_commands, free); + kmod_list_release(config->masks, free); kmod_list_release(config->remove_commands, free); kmod_list_release(config->softdeps, free); kmod_list_release(config->weakdeps, free); @@ -1094,6 +1134,7 @@ int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config, enum config_type { CONFIG_TYPE_BLACKLIST = 0, CONFIG_TYPE_INSTALL, + CONFIG_TYPE_MASK, CONFIG_TYPE_REMOVE, CONFIG_TYPE_ALIAS, CONFIG_TYPE_OPTION, @@ -1144,6 +1185,10 @@ static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx *ctx, iter->get_key = kmod_command_get_modname; iter->get_value = kmod_command_get_command; break; + case CONFIG_TYPE_MASK: + iter->list = config->masks; + iter->get_key = kmod_mask_get_modname; + break; case CONFIG_TYPE_REMOVE: iter->list = config->remove_commands; iter->get_key = kmod_command_get_modname; @@ -1194,6 +1239,14 @@ KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const stru return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL); } +KMOD_EXPORT struct kmod_config_iter *kmod_config_get_masks(const struct kmod_ctx *ctx) +{ + if (ctx == NULL) + return NULL; + + return kmod_config_iter_new(ctx, CONFIG_TYPE_MASK); +} + // clang-format off KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx) // clang-format on diff --git a/libkmod/libkmod-internal.h b/libkmod/libkmod-internal.h index 547b8369..1e24df30 100644 --- a/libkmod/libkmod-internal.h +++ b/libkmod/libkmod-internal.h @@ -99,6 +99,7 @@ struct kmod_config { struct kmod_list *aliases; struct kmod_list *blacklists; struct kmod_list *options; + struct kmod_list *masks; struct kmod_list *remove_commands; struct kmod_list *install_commands; struct kmod_list *softdeps; @@ -112,6 +113,7 @@ _nonnull_all_ void kmod_config_free(struct kmod_config *config); _nonnull_all_ const char *kmod_blacklist_get_modname(const struct kmod_list *l); _nonnull_all_ const char *kmod_alias_get_name(const struct kmod_list *l); _nonnull_all_ const char *kmod_alias_get_modname(const struct kmod_list *l); +_nonnull_all_ const char *kmod_mask_get_modname(const struct kmod_list *l); _nonnull_all_ const char *kmod_option_get_options(const struct kmod_list *l); _nonnull_all_ const char *kmod_option_get_modname(const struct kmod_list *l); _nonnull_all_ const char *kmod_command_get_command(const struct kmod_list *l); diff --git a/libkmod/libkmod-module.c b/libkmod/libkmod-module.c index 7bf37bba..f166da3c 100644 --- a/libkmod/libkmod-module.c +++ b/libkmod/libkmod-module.c @@ -734,12 +734,30 @@ static bool module_is_blacklisted(const struct kmod_module *mod) return false; } +static bool module_is_masked(const struct kmod_module *mod) +{ + const struct kmod_ctx *ctx = mod->ctx; + const struct kmod_config *config = kmod_get_config(ctx); + const struct kmod_list *bl = config->masks; + const struct kmod_list *l; + + kmod_list_foreach(l, bl) { + const char *modname = kmod_mask_get_modname(l); + + if (streq(modname, mod->name)) + return true; + } + + return false; +} + KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx, enum kmod_filter filter_type, const struct kmod_list *input, struct kmod_list **output) { const struct kmod_list *li; + int err = 0; if (ctx == NULL || output == NULL) return -ENOENT; @@ -758,9 +776,20 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx, if ((filter_type & KMOD_FILTER_BUILTIN) && kmod_module_is_builtin(mod)) continue; + if ((filter_type & KMOD_FILTER_MASK) && module_is_masked(mod)) { + if (!mod->required) + continue; + ERR(mod->ctx, "module is masked: %s\n", + kmod_module_get_name(mod)); + err = -EINVAL; + goto fail; + } + node = kmod_list_append(*output, mod); - if (node == NULL) + if (node == NULL) { + err = -ENOMEM; goto fail; + } *output = node; kmod_module_ref(mod); @@ -771,7 +800,7 @@ KMOD_EXPORT int kmod_module_apply_filter(const struct kmod_ctx *ctx, fail: kmod_module_unref_list(*output); *output = NULL; - return -ENOMEM; + return err; } static int command_do(struct kmod_module *mod, const char *type, const char *cmd) @@ -1005,7 +1034,7 @@ KMOD_EXPORT int kmod_module_probe_insert_module( const void *data, void (*print_action)(struct kmod_module *m, bool install, const char *options)) { - struct kmod_list *list = NULL, *l; + struct kmod_list *list = NULL, *l, *filtered = NULL; struct probe_insert_cb cb; int err; @@ -1019,6 +1048,11 @@ KMOD_EXPORT int kmod_module_probe_insert_module( return 0; } + if (module_is_masked(mod)) { + ERR(mod->ctx, "module is masked: %s\n", kmod_module_get_name(mod)); + return -EINVAL; + } + if (module_is_blacklisted(mod)) { if (mod->alias != NULL && (flags & KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY)) return KMOD_PROBE_APPLY_BLACKLIST_ALIAS_ONLY; @@ -1035,15 +1069,23 @@ KMOD_EXPORT int kmod_module_probe_insert_module( if (err < 0) return err; - if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) { - struct kmod_list *filtered = NULL; + err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_MASK, list, &filtered); + kmod_module_unref_list(list); + if (err < 0) + return err; + + if (filtered == NULL) + return -EINVAL; + list = filtered; + + if (flags & KMOD_PROBE_APPLY_BLACKLIST_ALL) { err = kmod_module_apply_filter(mod->ctx, KMOD_FILTER_BLACKLIST, list, &filtered); + kmod_module_unref_list(list); if (err < 0) return err; - kmod_module_unref_list(list); if (filtered == NULL) return KMOD_PROBE_APPLY_BLACKLIST_ALL; diff --git a/libkmod/libkmod.h b/libkmod/libkmod.h index 1c0d1185..f460d520 100644 --- a/libkmod/libkmod.h +++ b/libkmod/libkmod.h @@ -365,6 +365,22 @@ struct kmod_list *kmod_list_prev(const struct kmod_list *list, */ struct kmod_config_iter; +/** + * kmod_config_get_masks: + * @ctx: kmod library context + * + * Retrieve an iterator to deal with the mask list maintained inside the + * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and + * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must + * be made to initialize the iterator and check if it's valid. + * + * Returns: a new iterator over the masks or NULL on failure. Free it + * with kmod_config_iter_free_iter(). + * + * Since: 35 + */ +struct kmod_config_iter *kmod_config_get_masks(const struct kmod_ctx *ctx); + /** * kmod_config_get_blacklists: * @ctx: kmod library context @@ -905,12 +921,14 @@ int kmod_module_get_weakdeps(const struct kmod_module *mod, struct kmod_list **w * kmod_filter: * @KMOD_FILTER_BLACKLIST: filter modules in blacklist out * @KMOD_FILTER_BUILTIN: filter builtin modules out + * @KMOD_FILTER_MASK: filter masked modules out * * Bitmask defining what gets filtered out, used by kmod_module_apply_filter(). */ enum kmod_filter { KMOD_FILTER_BLACKLIST = 0x00001, KMOD_FILTER_BUILTIN = 0x00002, + KMOD_FILTER_MASK = 0x00004, }; /** diff --git a/libkmod/libkmod.sym b/libkmod/libkmod.sym index ea1cb448..01ee7ee4 100644 --- a/libkmod/libkmod.sym +++ b/libkmod/libkmod.sym @@ -105,3 +105,8 @@ global: kmod_config_get_weakdeps; kmod_module_get_weakdeps; } LIBKMOD_30; + +LIBKMOD_35 { +global: + kmod_config_get_masks; +} LIBKMOD_33; diff --git a/man/modprobe.8.scd b/man/modprobe.8.scd index aaf04c34..c6482109 100644 --- a/man/modprobe.8.scd +++ b/man/modprobe.8.scd @@ -23,7 +23,8 @@ that for convenience, there is no difference between \_ and - in module names directory @DISTCONFDIR@/`uname -r` for all the modules and other files, except for the optional configuration files (see *modprobe.d*(5)). *modprobe* will also use module options specified on the kernel command line in the form of -.