chiark / gitweb /
Merge nss-myhostname
[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                 return log_oom();
54
55         t = strv_merge(arg_proc_cmdline_modules, k);
56         strv_free(k);
57         if (!t)
58                 return log_oom();
59
60         strv_free(arg_proc_cmdline_modules);
61         arg_proc_cmdline_modules = t;
62
63         return 0;
64 }
65
66 static int parse_proc_cmdline(void) {
67         char _cleanup_free_ *line = NULL;
68         char *w, *state;
69         int r;
70         size_t l;
71
72         if (detect_container(NULL) > 0)
73                 return 0;
74
75         r = read_one_line_file("/proc/cmdline", &line);
76         if (r < 0) {
77                 log_warning("Failed to read /proc/cmdline, ignoring: %s", strerror(-r));
78                 return 0;
79         }
80
81         FOREACH_WORD_QUOTED(w, l, line, state) {
82                 char _cleanup_free_ *word;
83
84                 word = strndup(w, l);
85                 if (!word)
86                         return log_oom();
87
88                 if (startswith(word, "modules-load=")) {
89
90                         r = add_modules(word + 13);
91                         if (r < 0)
92                                 return r;
93
94                 } else if (startswith(word, "rd.modules-load=")) {
95
96                         if (in_initrd()) {
97                                 r = add_modules(word + 16);
98                                 if (r < 0)
99                                         return r;
100                         }
101
102                 }
103         }
104
105         return 0;
106 }
107
108 static int load_module(struct kmod_ctx *ctx, const char *m) {
109         const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
110         struct kmod_list *itr, *modlist = NULL;
111         int r = 0;
112
113         log_debug("load: %s\n", m);
114
115         r = kmod_module_new_from_lookup(ctx, m, &modlist);
116         if (r < 0) {
117                 log_error("Failed to lookup alias '%s': %s", m, strerror(-r));
118                 return r;
119         }
120
121         if (!modlist) {
122                 log_error("Failed to find module '%s'", m);
123                 return -ENOENT;
124         }
125
126         kmod_list_foreach(itr, modlist) {
127                 struct kmod_module *mod;
128                 int state, err;
129
130                 mod = kmod_module_get_module(itr);
131                 state = kmod_module_get_initstate(mod);
132
133                 switch (state) {
134                 case KMOD_MODULE_BUILTIN:
135                         log_info("Module '%s' is builtin", kmod_module_get_name(mod));
136                         break;
137
138                 case KMOD_MODULE_LIVE:
139                         log_info("Module '%s' is already loaded", kmod_module_get_name(mod));
140                         break;
141
142                 default:
143                         err = kmod_module_probe_insert_module(mod, probe_flags,
144                                                               NULL, NULL, NULL, NULL);
145
146                         if (err == 0)
147                                 log_info("Inserted module '%s'", kmod_module_get_name(mod));
148                         else if (err == KMOD_PROBE_APPLY_BLACKLIST)
149                                 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
150                         else {
151                                 log_error("Failed to insert '%s': %s", kmod_module_get_name(mod),
152                                           strerror(-err));
153                                 r = err;
154                         }
155                 }
156
157                 kmod_module_unref(mod);
158         }
159
160         kmod_module_unref_list(modlist);
161
162         return r;
163 }
164
165 int main(int argc, char *argv[]) {
166         int r = EXIT_FAILURE, k;
167         char **files = NULL, **fn, **i;
168         struct kmod_ctx *ctx;
169
170         if (argc > 1) {
171                 log_error("This program takes no argument.");
172                 return EXIT_FAILURE;
173         }
174
175         log_set_target(LOG_TARGET_AUTO);
176         log_parse_environment();
177         log_open();
178
179         umask(0022);
180
181         if (parse_proc_cmdline() < 0)
182                 return EXIT_FAILURE;
183
184         ctx = kmod_new(NULL, NULL);
185         if (!ctx) {
186                 log_error("Failed to allocate memory for kmod.");
187                 goto finish;
188         }
189
190         kmod_load_resources(ctx);
191         kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
192
193         r = EXIT_SUCCESS;
194
195         STRV_FOREACH(i, arg_proc_cmdline_modules) {
196                 k = load_module(ctx, *i);
197                 if (k < 0)
198                         r = EXIT_FAILURE;
199         }
200
201         k = conf_files_list(&files, ".conf",
202                             "/etc/modules-load.d",
203                             "/run/modules-load.d",
204                             "/usr/local/lib/modules-load.d",
205                             "/usr/lib/modules-load.d",
206 #ifdef HAVE_SPLIT_USR
207                             "/lib/modules-load.d",
208 #endif
209                             NULL);
210         if (k < 0) {
211                 log_error("Failed to enumerate modules-load.d files: %s", strerror(-k));
212                 r = EXIT_FAILURE;
213                 goto finish;
214         }
215
216         STRV_FOREACH(fn, files) {
217                 FILE *f;
218
219                 f = fopen(*fn, "re");
220                 if (!f) {
221                         if (errno == ENOENT)
222                                 continue;
223
224                         log_error("Failed to open %s: %m", *fn);
225                         r = EXIT_FAILURE;
226                         continue;
227                 }
228
229                 log_debug("apply: %s\n", *fn);
230                 for (;;) {
231                         char line[LINE_MAX], *l;
232
233                         if (!fgets(line, sizeof(line), f))
234                                 break;
235
236                         l = strstrip(line);
237                         if (*l == '#' || *l == 0)
238                                 continue;
239
240                         k = load_module(ctx, l);
241                         if (k < 0)
242                                 r = EXIT_FAILURE;
243                 }
244
245                 if (ferror(f)) {
246                         log_error("Failed to read from file: %m");
247                         r = EXIT_FAILURE;
248                 }
249
250                 fclose(f);
251         }
252
253 finish:
254         strv_free(files);
255         kmod_unref(ctx);
256         strv_free(arg_proc_cmdline_modules);
257
258         return r;
259 }