chiark / gitweb /
22ea7333ed762e503846c9559d882341311fffe0
[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_meta(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|KMOD_PROBE_IGNORE_LOADED;
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         kmod_list_foreach(itr, modlist) {
133                 struct kmod_module *mod;
134                 int err;
135
136                 mod = kmod_module_get_module(itr);
137                 err = kmod_module_probe_insert_module(mod, probe_flags,
138                                                       NULL, NULL, NULL, NULL);
139
140                 if (err == 0)
141                         log_info("Inserted module '%s'", kmod_module_get_name(mod));
142                 else if (err == KMOD_PROBE_APPLY_BLACKLIST)
143                         log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
144                 else {
145                         log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
146                                   strerror(-err));
147                         r = err;
148                 }
149
150                 kmod_module_unref(mod);
151         }
152
153         kmod_module_unref_list(modlist);
154
155         return r;
156 }
157
158 int main(int argc, char *argv[]) {
159         int r = EXIT_FAILURE, k;
160         char **files, **fn, **i;
161         struct kmod_ctx *ctx;
162
163         if (argc > 1) {
164                 log_error("This program takes no argument.");
165                 return EXIT_FAILURE;
166         }
167
168         log_set_target(LOG_TARGET_AUTO);
169         log_parse_environment();
170         log_open();
171
172         umask(0022);
173
174         if (parse_proc_cmdline() < 0)
175                 return EXIT_FAILURE;
176
177         ctx = kmod_new(NULL, NULL);
178         if (!ctx) {
179                 log_error("Failed to allocate memory for kmod.");
180                 goto finish;
181         }
182
183         kmod_load_resources(ctx);
184         kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
185
186         r = EXIT_SUCCESS;
187
188         STRV_FOREACH(i, arg_proc_cmdline_modules) {
189                 k = load_module(ctx, *i);
190                 if (k < 0)
191                         r = EXIT_FAILURE;
192         }
193
194         k = conf_files_list(&files, ".conf",
195                             "/etc/modules-load.d",
196                             "/run/modules-load.d",
197                             "/usr/local/lib/modules-load.d",
198                             "/usr/lib/modules-load.d",
199 #ifdef HAVE_SPLIT_USR
200                             "/lib/modules-load.d",
201 #endif
202                             NULL);
203         if (k < 0) {
204                 log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
205                 r = EXIT_FAILURE;
206                 goto finish;
207         }
208
209         STRV_FOREACH(fn, files) {
210                 FILE *f;
211
212                 f = fopen(*fn, "re");
213                 if (!f) {
214                         if (errno == ENOENT)
215                                 continue;
216
217                         log_error("Failed to open %s: %m", *fn);
218                         r = EXIT_FAILURE;
219                         continue;
220                 }
221
222                 log_debug("apply: %s\n", *fn);
223                 for (;;) {
224                         char line[LINE_MAX], *l;
225
226                         if (!fgets(line, sizeof(line), f))
227                                 break;
228
229                         l = strstrip(line);
230                         if (*l == '#' || *l == 0)
231                                 continue;
232
233                         k = load_module(ctx, l);
234                         if (k < 0)
235                                 r = EXIT_FAILURE;
236                 }
237
238                 if (ferror(f)) {
239                         log_error("Failed to read from file: %m");
240                         r = EXIT_FAILURE;
241                 }
242
243                 fclose(f);
244         }
245
246 finish:
247         strv_free(files);
248         kmod_unref(ctx);
249         strv_free(arg_proc_cmdline_modules);
250
251         return r;
252 }