chiark / gitweb /
1b887aea3f63336444ba0be5c1fd242e850843dc
[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 <libkmod.h>
30
31 #include "log.h"
32 #include "util.h"
33 #include "strv.h"
34 #include "conf-files.h"
35 #include "virt.h"
36
37 static char **arg_proc_cmdline_modules = NULL;
38
39 #pragma GCC diagnostic push
40 #pragma GCC diagnostic ignored "-Wformat-nonliteral"
41 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
42                              const char *fn, const char *format, va_list args)
43 {
44         log_metav(priority, file, line, fn, format, args);
45 }
46 #pragma GCC diagnostic pop
47
48 static int add_modules(const char *p) {
49         char **t, **k;
50
51         k = strv_split(p, ",");
52         if (!k) {
53                 log_error("Out of memory");
54                 return -ENOMEM;
55         }
56
57         t = strv_merge(arg_proc_cmdline_modules, k);
58         strv_free(k);
59         if (!t) {
60                 log_error("Out of memory");
61                 return -ENOMEM;
62         }
63
64         strv_free(arg_proc_cmdline_modules);
65         arg_proc_cmdline_modules = t;
66
67         return 0;
68 }
69
70 static int parse_proc_cmdline(void) {
71         char *line, *w, *state;
72         int r;
73         size_t l;
74
75         if (detect_container(NULL) > 0)
76                 return 0;
77
78         r = read_one_line_file("/proc/cmdline", &line);
79         if (r < 0) {
80                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
81                 return 0;
82         }
83
84         FOREACH_WORD_QUOTED(w, l, line, state) {
85                 char *word;
86
87                 word = strndup(w, l);
88                 if (!word) {
89                         r = -ENOMEM;
90                         goto finish;
91                 }
92
93                 if (startswith(word, "driver=")) {
94
95                         r = add_modules(word + 7);
96                         if (r < 0)
97                                 goto finish;
98
99                 } else if (startswith(word, "rd.driver=")) {
100
101                         if (in_initrd()) {
102                                 r = add_modules(word + 10);
103                                 if (r < 0)
104                                         goto finish;
105                         }
106
107                 }
108
109                 free(word);
110         }
111
112         r = 0;
113
114 finish:
115         free(line);
116         return r;
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 int main(int argc, char *argv[]) {
177         int r = EXIT_FAILURE, k;
178         char **files, **fn, **i;
179         struct kmod_ctx *ctx;
180
181         if (argc > 1) {
182                 log_error("This program takes no argument.");
183                 return EXIT_FAILURE;
184         }
185
186         log_set_target(LOG_TARGET_AUTO);
187         log_parse_environment();
188         log_open();
189
190         umask(0022);
191
192         if (parse_proc_cmdline() < 0)
193                 return EXIT_FAILURE;
194
195         ctx = kmod_new(NULL, NULL);
196         if (!ctx) {
197                 log_error("Failed to allocate memory for kmod.");
198                 goto finish;
199         }
200
201         kmod_load_resources(ctx);
202         kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
203
204         r = EXIT_SUCCESS;
205
206         STRV_FOREACH(i, arg_proc_cmdline_modules) {
207                 k = load_module(ctx, *i);
208                 if (k < 0)
209                         r = EXIT_FAILURE;
210         }
211
212         k = conf_files_list(&files, ".conf",
213                             "/etc/modules-load.d",
214                             "/run/modules-load.d",
215                             "/usr/local/lib/modules-load.d",
216                             "/usr/lib/modules-load.d",
217 #ifdef HAVE_SPLIT_USR
218                             "/lib/modules-load.d",
219 #endif
220                             NULL);
221         if (k < 0) {
222                 log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
223                 r = EXIT_FAILURE;
224                 goto finish;
225         }
226
227         STRV_FOREACH(fn, files) {
228                 FILE *f;
229
230                 f = fopen(*fn, "re");
231                 if (!f) {
232                         if (errno == ENOENT)
233                                 continue;
234
235                         log_error("Failed to open %s: %m", *fn);
236                         r = EXIT_FAILURE;
237                         continue;
238                 }
239
240                 log_debug("apply: %s\n", *fn);
241                 for (;;) {
242                         char line[LINE_MAX], *l;
243
244                         if (!fgets(line, sizeof(line), f))
245                                 break;
246
247                         l = strstrip(line);
248                         if (*l == '#' || *l == 0)
249                                 continue;
250
251                         k = load_module(ctx, l);
252                         if (k < 0)
253                                 r = EXIT_FAILURE;
254                 }
255
256                 if (ferror(f)) {
257                         log_error("Failed to read from file: %m");
258                         r = EXIT_FAILURE;
259                 }
260
261                 fclose(f);
262         }
263
264 finish:
265         strv_free(files);
266         kmod_unref(ctx);
267         strv_free(arg_proc_cmdline_modules);
268
269         return r;
270 }