1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2010 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "conf-files.h"
33 #include "module-util.h"
34 #include "proc-cmdline.h"
35 #include "string-util.h"
39 static char **arg_proc_cmdline_modules
= NULL
;
41 static const char conf_file_dirs
[] = CONF_PATHS_NULSTR("modules-load.d");
43 static void systemd_kmod_log(void *data
, int priority
, const char *file
, int line
,
44 const char *fn
, const char *format
, va_list args
) {
46 DISABLE_WARNING_FORMAT_NONLITERAL
;
47 log_internalv(priority
, 0, file
, line
, fn
, format
, args
);
51 static int add_modules(const char *p
) {
52 _cleanup_strv_free_
char **k
= NULL
;
54 k
= strv_split(p
, ",");
58 if (strv_extend_strv(&arg_proc_cmdline_modules
, k
, true) < 0)
64 static int parse_proc_cmdline_item(const char *key
, const char *value
, void *data
) {
67 if (proc_cmdline_key_streq(key
, "modules_load")) {
69 if (proc_cmdline_value_missing(key
, value
))
72 r
= add_modules(value
);
80 static int load_module(struct kmod_ctx
*ctx
, const char *m
) {
81 const int probe_flags
= KMOD_PROBE_APPLY_BLACKLIST
;
82 struct kmod_list
*itr
;
83 _cleanup_(kmod_module_unref_listp
) struct kmod_list
*modlist
= NULL
;
86 log_debug("load: %s", m
);
88 r
= kmod_module_new_from_lookup(ctx
, m
, &modlist
);
90 return log_error_errno(r
, "Failed to lookup alias '%s': %m", m
);
93 log_error("Failed to find module '%s'", m
);
97 kmod_list_foreach(itr
, modlist
) {
98 _cleanup_(kmod_module_unrefp
) struct kmod_module
*mod
= NULL
;
101 mod
= kmod_module_get_module(itr
);
102 state
= kmod_module_get_initstate(mod
);
105 case KMOD_MODULE_BUILTIN
:
106 log_info("Module '%s' is builtin", kmod_module_get_name(mod
));
109 case KMOD_MODULE_LIVE
:
110 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod
));
114 err
= kmod_module_probe_insert_module(mod
, probe_flags
,
115 NULL
, NULL
, NULL
, NULL
);
118 log_info("Inserted module '%s'", kmod_module_get_name(mod
));
119 else if (err
== KMOD_PROBE_APPLY_BLACKLIST
)
120 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod
));
124 log_full_errno(err
== ENODEV
? LOG_NOTICE
:
125 err
== ENOENT
? LOG_WARNING
:
128 "Failed to insert '%s': %m",
129 kmod_module_get_name(mod
));
130 if (!IN_SET(err
, ENODEV
, ENOENT
))
139 static int apply_file(struct kmod_ctx
*ctx
, const char *path
, bool ignore_enoent
) {
140 _cleanup_fclose_
FILE *f
= NULL
;
146 r
= search_and_fopen_nulstr(path
, "re", NULL
, conf_file_dirs
, &f
);
148 if (ignore_enoent
&& r
== -ENOENT
)
151 return log_error_errno(r
, "Failed to open %s, ignoring: %m", path
);
154 log_debug("apply: %s", path
);
156 char line
[LINE_MAX
], *l
;
159 if (!fgets(line
, sizeof(line
), f
)) {
163 return log_error_errno(errno
, "Failed to read file '%s', ignoring: %m", path
);
169 if (strchr(COMMENTS
"\n", *l
))
172 k
= load_module(ctx
, l
);
180 static void help(void) {
181 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
182 "Loads statically configured kernel modules.\n\n"
183 " -h --help Show this help\n"
184 " --version Show package version\n",
185 program_invocation_short_name
);
188 static int parse_argv(int argc
, char *argv
[]) {
194 static const struct option options
[] = {
195 { "help", no_argument
, NULL
, 'h' },
196 { "version", no_argument
, NULL
, ARG_VERSION
},
205 while ((c
= getopt_long(argc
, argv
, "h", options
, NULL
)) >= 0)
220 assert_not_reached("Unhandled option");
226 int main(int argc
, char *argv
[]) {
228 _cleanup_(kmod_unrefp
) struct kmod_ctx
*ctx
= NULL
;
230 r
= parse_argv(argc
, argv
);
232 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;
234 log_set_target(LOG_TARGET_AUTO
);
235 log_parse_environment();
240 r
= proc_cmdline_parse(parse_proc_cmdline_item
, NULL
, PROC_CMDLINE_STRIP_RD_PREFIX
);
242 log_warning_errno(r
, "Failed to parse kernel command line, ignoring: %m");
244 ctx
= kmod_new(NULL
, NULL
);
246 log_error("Failed to allocate memory for kmod.");
250 kmod_load_resources(ctx
);
251 kmod_set_log_fn(ctx
, systemd_kmod_log
, NULL
);
258 for (i
= optind
; i
< argc
; i
++) {
259 k
= apply_file(ctx
, argv
[i
], false);
265 _cleanup_strv_free_
char **files
= NULL
;
268 STRV_FOREACH(i
, arg_proc_cmdline_modules
) {
269 k
= load_module(ctx
, *i
);
274 k
= conf_files_list_nulstr(&files
, ".conf", NULL
, 0, conf_file_dirs
);
276 log_error_errno(k
, "Failed to enumerate modules-load.d files: %m");
282 STRV_FOREACH(fn
, files
) {
283 k
= apply_file(ctx
, *fn
, true);
290 strv_free(arg_proc_cmdline_modules
);
292 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;