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