chiark / gitweb /
Remove unused variables
[elogind.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         log_metav(priority, file, line, fn, format, args);
56 }
57 #pragma GCC diagnostic pop
58
59 static int add_modules(const char *p) {
60         _cleanup_strv_free_ char **k = NULL;
61
62         k = strv_split(p, ",");
63         if (!k)
64                 return log_oom();
65
66         if (strv_extend_strv(&arg_proc_cmdline_modules, k) < 0)
67                 return log_oom();
68
69         return 0;
70 }
71
72 static int parse_proc_cmdline(void) {
73         _cleanup_free_ char *line = NULL;
74         char *w, *state;
75         size_t l;
76         int r;
77
78         r = proc_cmdline(&line);
79         if (r < 0)
80                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
81         if (r <= 0)
82                 return 0;
83
84         FOREACH_WORD_QUOTED(w, l, line, state) {
85                 _cleanup_free_ char *word;
86
87                 word = strndup(w, l);
88                 if (!word)
89                         return log_oom();
90
91                 if (startswith(word, "modules-load=")) {
92
93                         r = add_modules(word + 13);
94                         if (r < 0)
95                                 return r;
96
97                 } else if (startswith(word, "rd.modules-load=")) {
98
99                         if (in_initrd()) {
100                                 r = add_modules(word + 16);
101                                 if (r < 0)
102                                         return r;
103                         }
104
105                 }
106         }
107
108         return 0;
109 }
110
111 static int load_module(struct kmod_ctx *ctx, const char *m) {
112         const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
113         struct kmod_list *itr, *modlist = NULL;
114         int r = 0;
115
116         log_debug("load: %s", m);
117
118         r = kmod_module_new_from_lookup(ctx, m, &modlist);
119         if (r < 0) {
120                 log_error("Failed to lookup alias '%s': %s", m, strerror(-r));
121                 return r;
122         }
123
124         if (!modlist) {
125                 log_error("Failed to find module '%s'", m);
126                 return -ENOENT;
127         }
128
129         kmod_list_foreach(itr, modlist) {
130                 struct kmod_module *mod;
131                 int state, err;
132
133                 mod = kmod_module_get_module(itr);
134                 state = kmod_module_get_initstate(mod);
135
136                 switch (state) {
137                 case KMOD_MODULE_BUILTIN:
138                         log_info("Module '%s' is builtin", kmod_module_get_name(mod));
139                         break;
140
141                 case KMOD_MODULE_LIVE:
142                         log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
143                         break;
144
145                 default:
146                         err = kmod_module_probe_insert_module(mod, probe_flags,
147                                                               NULL, NULL, NULL, NULL);
148
149                         if (err == 0)
150                                 log_info("Inserted module '%s'", kmod_module_get_name(mod));
151                         else if (err == KMOD_PROBE_APPLY_BLACKLIST)
152                                 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
153                         else {
154                                 log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
155                                           strerror(-err));
156                                 r = err;
157                         }
158                 }
159
160                 kmod_module_unref(mod);
161         }
162
163         kmod_module_unref_list(modlist);
164
165         return r;
166 }
167
168 static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
169         _cleanup_fclose_ FILE *f = NULL;
170         int r;
171
172         assert(ctx);
173         assert(path);
174
175         r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
176         if (r < 0) {
177                 if (ignore_enoent && r == -ENOENT)
178                         return 0;
179
180                 log_error("Failed to open %s, ignoring: %s", path, strerror(-r));
181                 return r;
182         }
183
184         log_debug("apply: %s", path);
185         for (;;) {
186                 char line[LINE_MAX], *l;
187                 int k;
188
189                 if (!fgets(line, sizeof(line), f)) {
190                         if (feof(f))
191                                 break;
192
193                         log_error("Failed to read file '%s', ignoring: %m", path);
194                         return -errno;
195                 }
196
197                 l = strstrip(line);
198                 if (!*l)
199                         continue;
200                 if (strchr(COMMENTS "\n", *l))
201                         continue;
202
203                 k = load_module(ctx, l);
204                 if (k < 0 && r == 0)
205                         r = k;
206         }
207
208         return r;
209 }
210
211 static int help(void) {
212
213         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
214                "Loads statically configured kernel modules.\n\n"
215                "  -h --help             Show this help\n"
216                "     --version          Show package version\n",
217                program_invocation_short_name);
218
219         return 0;
220 }
221
222 static int parse_argv(int argc, char *argv[]) {
223
224         enum {
225                 ARG_VERSION = 0x100,
226         };
227
228         static const struct option options[] = {
229                 { "help",      no_argument,       NULL, 'h'           },
230                 { "version",   no_argument,       NULL, ARG_VERSION   },
231                 {}
232         };
233
234         int c;
235
236         assert(argc >= 0);
237         assert(argv);
238
239         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
240
241                 switch (c) {
242
243                 case 'h':
244                         return help();
245
246                 case ARG_VERSION:
247                         puts(PACKAGE_STRING);
248                         puts(SYSTEMD_FEATURES);
249                         return 0;
250
251                 case '?':
252                         return -EINVAL;
253
254                 default:
255                         assert_not_reached("Unhandled option");
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 && r == 0)
306                                 r = k;
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 }