]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/modules-load/modules-load.c
fileio: in envfiles, do not skip lines following empty lines
[thirdparty/systemd.git] / src / modules-load / modules-load.c
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
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
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
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
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>
29 #include <getopt.h>
30 #include <libkmod.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "strv.h"
35 #include "conf-files.h"
36 #include "virt.h"
37 #include "fileio.h"
38
39 static char **arg_proc_cmdline_modules = NULL;
40
41 static 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
51 #pragma GCC diagnostic push
52 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
53 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
54 const char *fn, const char *format, va_list args)
55 {
56 log_metav(priority, file, line, fn, format, args);
57 }
58 #pragma GCC diagnostic pop
59
60 static int add_modules(const char *p) {
61 char **t;
62 _cleanup_strv_free_ char **k = NULL;
63
64 k = strv_split(p, ",");
65 if (!k)
66 return log_oom();
67
68 t = strv_merge(arg_proc_cmdline_modules, k);
69 if (!t)
70 return log_oom();
71
72 strv_free(arg_proc_cmdline_modules);
73 arg_proc_cmdline_modules = t;
74
75 return 0;
76 }
77
78 static int parse_proc_cmdline(void) {
79 char _cleanup_free_ *line = NULL;
80 char *w, *state;
81 int r;
82 size_t l;
83
84 if (detect_container(NULL) > 0)
85 return 0;
86
87 r = read_one_line_file("/proc/cmdline", &line);
88 if (r < 0) {
89 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
90 return 0;
91 }
92
93 FOREACH_WORD_QUOTED(w, l, line, state) {
94 char _cleanup_free_ *word;
95
96 word = strndup(w, l);
97 if (!word)
98 return log_oom();
99
100 if (startswith(word, "modules-load=")) {
101
102 r = add_modules(word + 13);
103 if (r < 0)
104 return r;
105
106 } else if (startswith(word, "rd.modules-load=")) {
107
108 if (in_initrd()) {
109 r = add_modules(word + 16);
110 if (r < 0)
111 return r;
112 }
113
114 }
115 }
116
117 return 0;
118 }
119
120 static int load_module(struct kmod_ctx *ctx, const char *m) {
121 const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
122 struct kmod_list *itr, *modlist = NULL;
123 int r = 0;
124
125 log_debug("load: %s\n", m);
126
127 r = kmod_module_new_from_lookup(ctx, m, &modlist);
128 if (r < 0) {
129 log_error("Failed to lookup alias '%s': %s", m, strerror(-r));
130 return r;
131 }
132
133 if (!modlist) {
134 log_error("Failed to find module '%s'", m);
135 return -ENOENT;
136 }
137
138 kmod_list_foreach(itr, modlist) {
139 struct kmod_module *mod;
140 int state, err;
141
142 mod = kmod_module_get_module(itr);
143 state = kmod_module_get_initstate(mod);
144
145 switch (state) {
146 case KMOD_MODULE_BUILTIN:
147 log_info("Module '%s' is builtin", kmod_module_get_name(mod));
148 break;
149
150 case KMOD_MODULE_LIVE:
151 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
152 break;
153
154 default:
155 err = kmod_module_probe_insert_module(mod, probe_flags,
156 NULL, NULL, NULL, NULL);
157
158 if (err == 0)
159 log_info("Inserted module '%s'", kmod_module_get_name(mod));
160 else if (err == KMOD_PROBE_APPLY_BLACKLIST)
161 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
162 else {
163 log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
164 strerror(-err));
165 r = err;
166 }
167 }
168
169 kmod_module_unref(mod);
170 }
171
172 kmod_module_unref_list(modlist);
173
174 return r;
175 }
176
177 static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
178 _cleanup_fclose_ FILE *f = NULL;
179 int r;
180
181 assert(ctx);
182 assert(path);
183
184 r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
185 if (r < 0) {
186 if (ignore_enoent && r == -ENOENT)
187 return 0;
188
189 log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
190 return r;
191 }
192
193 log_debug("apply: %s\n", path);
194 for (;;) {
195 char line[LINE_MAX], *l;
196 int k;
197
198 if (!fgets(line, sizeof(line), f)) {
199 if (feof(f))
200 break;
201
202 log_error("Failed to read file '%s', ignoring: %m", path);
203 return -errno;
204 }
205
206 l = strstrip(line);
207 if (!*l)
208 continue;
209 if (strchr(COMMENTS "\n", *l))
210 continue;
211
212 k = load_module(ctx, l);
213 if (k < 0 && r == 0)
214 r = k;
215 }
216
217 return r;
218 }
219
220 static int help(void) {
221
222 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
223 "Loads statically configured kernel modules.\n\n"
224 " -h --help Show this help\n",
225 program_invocation_short_name);
226
227 return 0;
228 }
229
230 static int parse_argv(int argc, char *argv[]) {
231
232 static const struct option options[] = {
233 { "help", no_argument, NULL, 'h' },
234 { NULL, 0, NULL, 0 }
235 };
236
237 int c;
238
239 assert(argc >= 0);
240 assert(argv);
241
242 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
243
244 switch (c) {
245
246 case 'h':
247 help();
248 return 0;
249
250 case '?':
251 return -EINVAL;
252
253 default:
254 log_error("Unknown option code %c", c);
255 return -EINVAL;
256 }
257 }
258
259 return 1;
260 }
261
262 int main(int argc, char *argv[]) {
263 int r, k;
264 struct kmod_ctx *ctx;
265
266 r = parse_argv(argc, argv);
267 if (r <= 0)
268 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
269
270 log_set_target(LOG_TARGET_AUTO);
271 log_parse_environment();
272 log_open();
273
274 umask(0022);
275
276 if (parse_proc_cmdline() < 0)
277 return EXIT_FAILURE;
278
279 ctx = kmod_new(NULL, NULL);
280 if (!ctx) {
281 log_error("Failed to allocate memory for kmod.");
282 goto finish;
283 }
284
285 kmod_load_resources(ctx);
286 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
287
288 r = 0;
289
290 if (argc > optind) {
291 int i;
292
293 for (i = optind; i < argc; i++) {
294 k = apply_file(ctx, argv[i], false);
295 if (k < 0 && r == 0)
296 r = k;
297 }
298
299 } else {
300 _cleanup_free_ char **files = NULL;
301 char **fn, **i;
302
303 STRV_FOREACH(i, arg_proc_cmdline_modules) {
304 k = load_module(ctx, *i);
305 if (k < 0)
306 r = EXIT_FAILURE;
307 }
308
309 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
310 if (r < 0) {
311 log_error("Failed to enumerate modules-load.d files: %s", strerror(-r));
312 goto finish;
313 }
314
315 STRV_FOREACH(fn, files) {
316 k = apply_file(ctx, *fn, true);
317 if (k < 0 && r == 0)
318 r = k;
319 }
320 }
321
322 finish:
323 kmod_unref(ctx);
324 strv_free(arg_proc_cmdline_modules);
325
326 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
327 }