]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/modules-load/modules-load.c
tree-wide: drop license boilerplate
[thirdparty/systemd.git] / src / modules-load / modules-load.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <getopt.h>
10 #include <libkmod.h>
11 #include <limits.h>
12 #include <string.h>
13 #include <sys/stat.h>
14
15 #include "conf-files.h"
16 #include "def.h"
17 #include "fd-util.h"
18 #include "fileio.h"
19 #include "log.h"
20 #include "module-util.h"
21 #include "proc-cmdline.h"
22 #include "string-util.h"
23 #include "strv.h"
24 #include "util.h"
25
26 static char **arg_proc_cmdline_modules = NULL;
27
28 static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d");
29
30 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
31 const char *fn, const char *format, va_list args) {
32
33 DISABLE_WARNING_FORMAT_NONLITERAL;
34 log_internalv(priority, 0, file, line, fn, format, args);
35 REENABLE_WARNING;
36 }
37
38 static int add_modules(const char *p) {
39 _cleanup_strv_free_ char **k = NULL;
40
41 k = strv_split(p, ",");
42 if (!k)
43 return log_oom();
44
45 if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0)
46 return log_oom();
47
48 return 0;
49 }
50
51 static int parse_proc_cmdline_item(const char *key, const char *value, void *data) {
52 int r;
53
54 if (proc_cmdline_key_streq(key, "modules_load")) {
55
56 if (proc_cmdline_value_missing(key, value))
57 return 0;
58
59 r = add_modules(value);
60 if (r < 0)
61 return r;
62 }
63
64 return 0;
65 }
66
67 static int load_module(struct kmod_ctx *ctx, const char *m) {
68 const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
69 struct kmod_list *itr;
70 _cleanup_(kmod_module_unref_listp) struct kmod_list *modlist = NULL;
71 int r = 0;
72
73 log_debug("load: %s", m);
74
75 r = kmod_module_new_from_lookup(ctx, m, &modlist);
76 if (r < 0)
77 return log_error_errno(r, "Failed to lookup alias '%s': %m", m);
78
79 if (!modlist) {
80 log_error("Failed to find module '%s'", m);
81 return -ENOENT;
82 }
83
84 kmod_list_foreach(itr, modlist) {
85 _cleanup_(kmod_module_unrefp) struct kmod_module *mod = NULL;
86 int state, err;
87
88 mod = kmod_module_get_module(itr);
89 state = kmod_module_get_initstate(mod);
90
91 switch (state) {
92 case KMOD_MODULE_BUILTIN:
93 log_info("Module '%s' is builtin", kmod_module_get_name(mod));
94 break;
95
96 case KMOD_MODULE_LIVE:
97 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
98 break;
99
100 default:
101 err = kmod_module_probe_insert_module(mod, probe_flags,
102 NULL, NULL, NULL, NULL);
103
104 if (err == 0)
105 log_info("Inserted module '%s'", kmod_module_get_name(mod));
106 else if (err == KMOD_PROBE_APPLY_BLACKLIST)
107 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
108 else {
109 assert(err < 0);
110
111 log_full_errno(err == ENODEV ? LOG_NOTICE :
112 err == ENOENT ? LOG_WARNING :
113 LOG_ERR,
114 err,
115 "Failed to insert '%s': %m",
116 kmod_module_get_name(mod));
117 if (!IN_SET(err, ENODEV, ENOENT))
118 r = err;
119 }
120 }
121 }
122
123 return r;
124 }
125
126 static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
127 _cleanup_fclose_ FILE *f = NULL;
128 int r;
129
130 assert(ctx);
131 assert(path);
132
133 r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
134 if (r < 0) {
135 if (ignore_enoent && r == -ENOENT)
136 return 0;
137
138 return log_error_errno(r, "Failed to open %s, ignoring: %m", path);
139 }
140
141 log_debug("apply: %s", path);
142 for (;;) {
143 char line[LINE_MAX], *l;
144 int k;
145
146 if (!fgets(line, sizeof(line), f)) {
147 if (feof(f))
148 break;
149
150 return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
151 }
152
153 l = strstrip(line);
154 if (!*l)
155 continue;
156 if (strchr(COMMENTS "\n", *l))
157 continue;
158
159 k = load_module(ctx, l);
160 if (k < 0 && r == 0)
161 r = k;
162 }
163
164 return r;
165 }
166
167 static void help(void) {
168 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
169 "Loads statically configured kernel modules.\n\n"
170 " -h --help Show this help\n"
171 " --version Show package version\n",
172 program_invocation_short_name);
173 }
174
175 static int parse_argv(int argc, char *argv[]) {
176
177 enum {
178 ARG_VERSION = 0x100,
179 };
180
181 static const struct option options[] = {
182 { "help", no_argument, NULL, 'h' },
183 { "version", no_argument, NULL, ARG_VERSION },
184 {}
185 };
186
187 int c;
188
189 assert(argc >= 0);
190 assert(argv);
191
192 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
193
194 switch (c) {
195
196 case 'h':
197 help();
198 return 0;
199
200 case ARG_VERSION:
201 return version();
202
203 case '?':
204 return -EINVAL;
205
206 default:
207 assert_not_reached("Unhandled option");
208 }
209
210 return 1;
211 }
212
213 int main(int argc, char *argv[]) {
214 int r, k;
215 _cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
216
217 r = parse_argv(argc, argv);
218 if (r <= 0)
219 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
220
221 log_set_target(LOG_TARGET_AUTO);
222 log_parse_environment();
223 log_open();
224
225 umask(0022);
226
227 r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX);
228 if (r < 0)
229 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
230
231 ctx = kmod_new(NULL, NULL);
232 if (!ctx) {
233 log_error("Failed to allocate memory for kmod.");
234 goto finish;
235 }
236
237 kmod_load_resources(ctx);
238 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
239
240 r = 0;
241
242 if (argc > optind) {
243 int i;
244
245 for (i = optind; i < argc; i++) {
246 k = apply_file(ctx, argv[i], false);
247 if (k < 0 && r == 0)
248 r = k;
249 }
250
251 } else {
252 _cleanup_strv_free_ char **files = NULL;
253 char **fn, **i;
254
255 STRV_FOREACH(i, arg_proc_cmdline_modules) {
256 k = load_module(ctx, *i);
257 if (k < 0 && r == 0)
258 r = k;
259 }
260
261 k = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs);
262 if (k < 0) {
263 log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
264 if (r == 0)
265 r = k;
266 goto finish;
267 }
268
269 STRV_FOREACH(fn, files) {
270 k = apply_file(ctx, *fn, true);
271 if (k < 0 && r == 0)
272 r = k;
273 }
274 }
275
276 finish:
277 strv_free(arg_proc_cmdline_modules);
278
279 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
280 }