]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/modules-load/modules-load.c
clients: unify how we invoke getopt_long()
[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 "fileio.h"
37 #include "build.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 _cleanup_free_ char *line = NULL;
80 char *w, *state;
81 size_t l;
82 int r;
83
84 r = proc_cmdline(&line);
85 if (r < 0)
86 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
87 if (r <= 0)
88 return 0;
89
90 FOREACH_WORD_QUOTED(w, l, line, state) {
91 _cleanup_free_ char *word;
92
93 word = strndup(w, l);
94 if (!word)
95 return log_oom();
96
97 if (startswith(word, "modules-load=")) {
98
99 r = add_modules(word + 13);
100 if (r < 0)
101 return r;
102
103 } else if (startswith(word, "rd.modules-load=")) {
104
105 if (in_initrd()) {
106 r = add_modules(word + 16);
107 if (r < 0)
108 return r;
109 }
110
111 }
112 }
113
114 return 0;
115 }
116
117 static int load_module(struct kmod_ctx *ctx, const char *m) {
118 const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
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
130 if (!modlist) {
131 log_error("Failed to find module '%s'", m);
132 return -ENOENT;
133 }
134
135 kmod_list_foreach(itr, modlist) {
136 struct kmod_module *mod;
137 int state, err;
138
139 mod = kmod_module_get_module(itr);
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:
148 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
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 }
164 }
165
166 kmod_module_unref(mod);
167 }
168
169 kmod_module_unref_list(modlist);
170
171 return r;
172 }
173
174 static 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;
206 if (strchr(COMMENTS "\n", *l))
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
217 static int help(void) {
218
219 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
220 "Loads statically configured kernel modules.\n\n"
221 " -h --help Show this help\n"
222 " --version Show package version\n",
223 program_invocation_short_name);
224
225 return 0;
226 }
227
228 static int parse_argv(int argc, char *argv[]) {
229
230 enum {
231 ARG_VERSION = 0x100,
232 };
233
234 static const struct option options[] = {
235 { "help", no_argument, NULL, 'h' },
236 { "version", no_argument, NULL, ARG_VERSION },
237 {}
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':
250 return help();
251
252 case ARG_VERSION:
253 puts(PACKAGE_STRING);
254 puts(SYSTEMD_FEATURES);
255 return 0;
256
257 case '?':
258 return -EINVAL;
259
260 default:
261 assert_not_reached("Unhandled option");
262 }
263 }
264
265 return 1;
266 }
267
268 int main(int argc, char *argv[]) {
269 int r, k;
270 struct kmod_ctx *ctx;
271
272 r = parse_argv(argc, argv);
273 if (r <= 0)
274 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
275
276 log_set_target(LOG_TARGET_AUTO);
277 log_parse_environment();
278 log_open();
279
280 umask(0022);
281
282 if (parse_proc_cmdline() < 0)
283 return EXIT_FAILURE;
284
285 ctx = kmod_new(NULL, NULL);
286 if (!ctx) {
287 log_error("Failed to allocate memory for kmod.");
288 goto finish;
289 }
290
291 kmod_load_resources(ctx);
292 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
293
294 r = 0;
295
296 if (argc > optind) {
297 int i;
298
299 for (i = optind; i < argc; i++) {
300 k = apply_file(ctx, argv[i], false);
301 if (k < 0 && r == 0)
302 r = k;
303 }
304
305 } else {
306 _cleanup_free_ char **files = NULL;
307 char **fn, **i;
308
309 STRV_FOREACH(i, arg_proc_cmdline_modules) {
310 k = load_module(ctx, *i);
311 if (k < 0 && r == 0)
312 r = k;
313 }
314
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;
319 }
320
321 STRV_FOREACH(fn, files) {
322 k = apply_file(ctx, *fn, true);
323 if (k < 0 && r == 0)
324 r = k;
325 }
326 }
327
328 finish:
329 kmod_unref(ctx);
330 strv_free(arg_proc_cmdline_modules);
331
332 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
333 }