1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
6 #include "module-util.h"
7 #include "proc-cmdline.h"
12 static void *libkmod_dl
= NULL
;
14 DLSYM_PROTOTYPE(kmod_list_next
) = NULL
;
15 DLSYM_PROTOTYPE(kmod_load_resources
) = NULL
;
16 DLSYM_PROTOTYPE(kmod_module_get_initstate
) = NULL
;
17 DLSYM_PROTOTYPE(kmod_module_get_module
) = NULL
;
18 DLSYM_PROTOTYPE(kmod_module_get_name
) = NULL
;
19 DLSYM_PROTOTYPE(kmod_module_new_from_lookup
) = NULL
;
20 DLSYM_PROTOTYPE(kmod_module_probe_insert_module
) = NULL
;
21 DLSYM_PROTOTYPE(kmod_module_unref
) = NULL
;
22 DLSYM_PROTOTYPE(kmod_module_unref_list
) = NULL
;
23 DLSYM_PROTOTYPE(kmod_new
) = NULL
;
24 DLSYM_PROTOTYPE(kmod_set_log_fn
) = NULL
;
25 DLSYM_PROTOTYPE(kmod_unref
) = NULL
;
26 DLSYM_PROTOTYPE(kmod_validate_resources
) = NULL
;
28 int dlopen_libkmod(void) {
29 ELF_NOTE_DLOPEN("kmod",
30 "Support for loading kernel modules",
31 ELF_NOTE_DLOPEN_PRIORITY_RECOMMENDED
,
34 return dlopen_many_sym_or_warn(
38 DLSYM_ARG(kmod_list_next
),
39 DLSYM_ARG(kmod_load_resources
),
40 DLSYM_ARG(kmod_module_get_initstate
),
41 DLSYM_ARG(kmod_module_get_module
),
42 DLSYM_ARG(kmod_module_get_name
),
43 DLSYM_ARG(kmod_module_new_from_lookup
),
44 DLSYM_ARG(kmod_module_probe_insert_module
),
45 DLSYM_ARG(kmod_module_unref
),
46 DLSYM_ARG(kmod_module_unref_list
),
48 DLSYM_ARG(kmod_set_log_fn
),
49 DLSYM_ARG(kmod_unref
),
50 DLSYM_ARG(kmod_validate_resources
));
53 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
54 char ***denylist
= ASSERT_PTR(data
);
57 if (proc_cmdline_key_streq(key
, "module_blacklist")) {
59 if (proc_cmdline_value_missing(key
, value
))
62 r
= strv_split_and_extend(denylist
, value
, ",", /* filter_duplicates = */ true);
70 int module_load_and_warn(struct kmod_ctx
*ctx
, const char *module
, bool verbose
) {
71 _cleanup_(sym_kmod_module_unref_listp
) struct kmod_list
*modlist
= NULL
;
72 _cleanup_strv_free_
char **denylist
= NULL
;
73 bool denylist_parsed
= false;
74 struct kmod_list
*itr
;
80 /* verbose==true means we should log at non-debug level if we
81 * fail to find or load the module. */
83 log_debug("Loading module: %s", module
);
85 r
= sym_kmod_module_new_from_lookup(ctx
, module
, &modlist
);
87 return log_full_errno(verbose
? LOG_ERR
: LOG_DEBUG
, r
,
88 "Failed to look up module alias '%s': %m", module
);
91 return log_full_errno(verbose
? LOG_ERR
: LOG_DEBUG
,
92 SYNTHETIC_ERRNO(ENOENT
),
93 "Failed to find module '%s'", module
);
95 sym_kmod_list_foreach(itr
, modlist
) {
96 _cleanup_(sym_kmod_module_unrefp
) struct kmod_module
*mod
= NULL
;
99 mod
= sym_kmod_module_get_module(itr
);
100 state
= sym_kmod_module_get_initstate(mod
);
103 case KMOD_MODULE_BUILTIN
:
104 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
105 "Module '%s' is built in", sym_kmod_module_get_name(mod
));
108 case KMOD_MODULE_LIVE
:
109 log_debug("Module '%s' is already loaded", sym_kmod_module_get_name(mod
));
113 err
= sym_kmod_module_probe_insert_module(
115 KMOD_PROBE_APPLY_BLACKLIST
,
116 /* extra_options= */ NULL
,
117 /* run_install= */ NULL
,
119 /* print_action= */ NULL
);
121 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
122 "Inserted module '%s'", sym_kmod_module_get_name(mod
));
123 else if (err
== KMOD_PROBE_APPLY_BLACKLIST
)
124 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
125 "Module '%s' is deny-listed (by kmod)", sym_kmod_module_get_name(mod
));
130 if (!denylist_parsed
) {
131 r
= proc_cmdline_parse(parse_proc_cmdline_item
, &denylist
, 0);
133 log_full_errno(!verbose
? LOG_DEBUG
: LOG_WARNING
,
135 "Failed to parse kernel command line, ignoring: %m");
137 denylist_parsed
= true;
139 if (strv_contains(denylist
, sym_kmod_module_get_name(mod
))) {
140 log_full(verbose
? LOG_INFO
: LOG_DEBUG
,
141 "Module '%s' is deny-listed (by kernel)", sym_kmod_module_get_name(mod
));
146 log_full_errno(!verbose
? LOG_DEBUG
:
147 err
== -ENODEV
? LOG_NOTICE
:
148 err
== -ENOENT
? LOG_WARNING
:
151 "Failed to insert module '%s': %m",
152 sym_kmod_module_get_name(mod
));
153 if (!IN_SET(err
, -ENODEV
, -ENOENT
))
162 _printf_(6,0) static void systemd_kmod_log(
171 log_internalv(priority
, 0, file
, line
, fn
, format
, args
);
174 int module_setup_context(struct kmod_ctx
**ret
) {
175 _cleanup_(sym_kmod_unrefp
) struct kmod_ctx
*ctx
= NULL
;
180 r
= dlopen_libkmod();
184 ctx
= sym_kmod_new(NULL
, NULL
);
188 (void) sym_kmod_load_resources(ctx
);
189 sym_kmod_set_log_fn(ctx
, systemd_kmod_log
, NULL
);
191 *ret
= TAKE_PTR(ctx
);