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