]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/modules-load/modules-load.c
sd-memfd: use assert_return
[thirdparty/systemd.git] / src / modules-load / modules-load.c
CommitLineData
b2423f1f
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
b2423f1f
LP
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 16 Lesser General Public License for more details.
b2423f1f 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
b2423f1f
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
22#include <unistd.h>
23#include <fcntl.h>
24#include <errno.h>
25#include <string.h>
26#include <sys/stat.h>
27#include <limits.h>
28#include <dirent.h>
fabe5c0e 29#include <getopt.h>
83684a35 30#include <libkmod.h>
b2423f1f
LP
31
32#include "log.h"
33#include "util.h"
34#include "strv.h"
2c21044f 35#include "conf-files.h"
a5c32cff 36#include "fileio.h"
eb9da376 37#include "build.h"
03658d4f
LP
38
39static char **arg_proc_cmdline_modules = NULL;
b2423f1f 40
fabe5c0e
LP
41static const char conf_file_dirs[] =
42 "/etc/modules-load.d\0"
43 "/run/modules-load.d\0"
44 "/usr/local/lib/modules-load.d\0"
45 "/usr/lib/modules-load.d\0"
46#ifdef HAVE_SPLIT_USR
47 "/lib/modules-load.d\0"
48#endif
49 ;
50
cdb454f2
LP
51#pragma GCC diagnostic push
52#pragma GCC diagnostic ignored "-Wformat-nonliteral"
83684a35
TG
53static void systemd_kmod_log(void *data, int priority, const char *file, int line,
54 const char *fn, const char *format, va_list args)
55{
e62abb62 56 log_metav(priority, file, line, fn, format, args);
83684a35 57}
cdb454f2 58#pragma GCC diagnostic pop
83684a35 59
03658d4f 60static int add_modules(const char *p) {
fabe5c0e
LP
61 char **t;
62 _cleanup_strv_free_ char **k = NULL;
03658d4f
LP
63
64 k = strv_split(p, ",");
0d0f0c50
SL
65 if (!k)
66 return log_oom();
03658d4f
LP
67
68 t = strv_merge(arg_proc_cmdline_modules, k);
0d0f0c50
SL
69 if (!t)
70 return log_oom();
03658d4f
LP
71
72 strv_free(arg_proc_cmdline_modules);
73 arg_proc_cmdline_modules = t;
74
75 return 0;
76}
77
78static int parse_proc_cmdline(void) {
7fd1b19b 79 _cleanup_free_ char *line = NULL;
c007bb1b 80 char *w, *state;
03658d4f 81 size_t l;
74df0fca 82 int r;
03658d4f 83
74df0fca
LP
84 r = proc_cmdline(&line);
85 if (r < 0)
03658d4f 86 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
74df0fca 87 if (r <= 0)
03658d4f 88 return 0;
03658d4f
LP
89
90 FOREACH_WORD_QUOTED(w, l, line, state) {
7fd1b19b 91 _cleanup_free_ char *word;
03658d4f
LP
92
93 word = strndup(w, l);
c007bb1b
ZJS
94 if (!word)
95 return log_oom();
03658d4f 96
91ac7425 97 if (startswith(word, "modules-load=")) {
03658d4f 98
b2fc39a6 99 r = add_modules(word + 13);
03658d4f 100 if (r < 0)
c007bb1b 101 return r;
03658d4f 102
91ac7425 103 } else if (startswith(word, "rd.modules-load=")) {
03658d4f
LP
104
105 if (in_initrd()) {
b2fc39a6 106 r = add_modules(word + 16);
03658d4f 107 if (r < 0)
c007bb1b 108 return r;
03658d4f
LP
109 }
110
111 }
03658d4f
LP
112 }
113
c007bb1b 114 return 0;
03658d4f
LP
115}
116
117static int load_module(struct kmod_ctx *ctx, const char *m) {
27fda47f 118 const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
03658d4f
LP
119 struct kmod_list *itr, *modlist = NULL;
120 int r = 0;
121
122 log_debug("load: %s\n", m);
123
124 r = kmod_module_new_from_lookup(ctx, m, &modlist);
125 if (r < 0) {
126 log_error("Failed to lookup alias '%s': %s", m, strerror(-r));
127 return r;
128 }
129
27fda47f
MS
130 if (!modlist) {
131 log_error("Failed to find module '%s'", m);
8f9c0b4c 132 return -ENOENT;
27fda47f
MS
133 }
134
03658d4f
LP
135 kmod_list_foreach(itr, modlist) {
136 struct kmod_module *mod;
27fda47f 137 int state, err;
03658d4f
LP
138
139 mod = kmod_module_get_module(itr);
27fda47f
MS
140 state = kmod_module_get_initstate(mod);
141
142 switch (state) {
143 case KMOD_MODULE_BUILTIN:
144 log_info("Module '%s' is builtin", kmod_module_get_name(mod));
145 break;
146
147 case KMOD_MODULE_LIVE:
b56c267f 148 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
27fda47f
MS
149 break;
150
151 default:
152 err = kmod_module_probe_insert_module(mod, probe_flags,
153 NULL, NULL, NULL, NULL);
154
155 if (err == 0)
156 log_info("Inserted module '%s'", kmod_module_get_name(mod));
157 else if (err == KMOD_PROBE_APPLY_BLACKLIST)
158 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
159 else {
160 log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
161 strerror(-err));
162 r = err;
163 }
03658d4f
LP
164 }
165
166 kmod_module_unref(mod);
167 }
168
169 kmod_module_unref_list(modlist);
170
171 return r;
172}
173
fabe5c0e
LP
174static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
175 _cleanup_fclose_ FILE *f = NULL;
176 int r;
177
178 assert(ctx);
179 assert(path);
180
181 r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
182 if (r < 0) {
183 if (ignore_enoent && r == -ENOENT)
184 return 0;
185
186 log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
187 return r;
188 }
189
190 log_debug("apply: %s\n", path);
191 for (;;) {
192 char line[LINE_MAX], *l;
193 int k;
194
195 if (!fgets(line, sizeof(line), f)) {
196 if (feof(f))
197 break;
198
199 log_error("Failed to read file '%s', ignoring: %m", path);
200 return -errno;
201 }
202
203 l = strstrip(line);
204 if (!*l)
205 continue;
d3b6d0c2 206 if (strchr(COMMENTS "\n", *l))
fabe5c0e
LP
207 continue;
208
209 k = load_module(ctx, l);
210 if (k < 0 && r == 0)
211 r = k;
212 }
213
214 return r;
215}
216
217static int help(void) {
218
219 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
220 "Loads statically configured kernel modules.\n\n"
eb9da376
LP
221 " -h --help Show this help\n"
222 " --version Show package version\n",
fabe5c0e
LP
223 program_invocation_short_name);
224
225 return 0;
226}
227
228static int parse_argv(int argc, char *argv[]) {
229
eb9da376
LP
230 enum {
231 ARG_VERSION = 0x100,
232 };
233
fabe5c0e
LP
234 static const struct option options[] = {
235 { "help", no_argument, NULL, 'h' },
eb9da376
LP
236 { "version", no_argument, NULL, ARG_VERSION },
237 {}
fabe5c0e
LP
238 };
239
240 int c;
241
242 assert(argc >= 0);
243 assert(argv);
244
245 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
246
247 switch (c) {
248
249 case 'h':
eb9da376
LP
250 return help();
251
252 case ARG_VERSION:
253 puts(PACKAGE_STRING);
254 puts(SYSTEMD_FEATURES);
fabe5c0e
LP
255 return 0;
256
257 case '?':
258 return -EINVAL;
259
260 default:
eb9da376 261 assert_not_reached("Unhandled option");
fabe5c0e
LP
262 }
263 }
264
265 return 1;
266}
267
b2423f1f 268int main(int argc, char *argv[]) {
fabe5c0e 269 int r, k;
83684a35 270 struct kmod_ctx *ctx;
b2423f1f 271
fabe5c0e
LP
272 r = parse_argv(argc, argv);
273 if (r <= 0)
274 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
b2423f1f 275
4cfa2c99 276 log_set_target(LOG_TARGET_AUTO);
b2423f1f
LP
277 log_parse_environment();
278 log_open();
279
4c12626c
LP
280 umask(0022);
281
03658d4f
LP
282 if (parse_proc_cmdline() < 0)
283 return EXIT_FAILURE;
284
4e2075ce
LP
285 ctx = kmod_new(NULL, NULL);
286 if (!ctx) {
83684a35 287 log_error("Failed to allocate memory for kmod.");
b2423f1f
LP
288 goto finish;
289 }
290
83684a35 291 kmod_load_resources(ctx);
83684a35 292 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
b2423f1f 293
fabe5c0e 294 r = 0;
03658d4f 295
fabe5c0e
LP
296 if (argc > optind) {
297 int i;
b2423f1f 298
fabe5c0e
LP
299 for (i = optind; i < argc; i++) {
300 k = apply_file(ctx, argv[i], false);
301 if (k < 0 && r == 0)
302 r = k;
b2423f1f
LP
303 }
304
fabe5c0e
LP
305 } else {
306 _cleanup_free_ char **files = NULL;
307 char **fn, **i;
b2423f1f 308
fabe5c0e
LP
309 STRV_FOREACH(i, arg_proc_cmdline_modules) {
310 k = load_module(ctx, *i);
b857193b
LP
311 if (k < 0 && r == 0)
312 r = k;
b2423f1f
LP
313 }
314
fabe5c0e
LP
315 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
316 if (r < 0) {
317 log_error("Failed to enumerate modules-load.d files: %s", strerror(-r));
318 goto finish;
b2423f1f
LP
319 }
320
fabe5c0e
LP
321 STRV_FOREACH(fn, files) {
322 k = apply_file(ctx, *fn, true);
323 if (k < 0 && r == 0)
324 r = k;
325 }
b2423f1f
LP
326 }
327
b2423f1f 328finish:
83684a35 329 kmod_unref(ctx);
03658d4f 330 strv_free(arg_proc_cmdline_modules);
b2423f1f 331
fabe5c0e 332 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
b2423f1f 333}