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