]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/modules-load/modules-load.c
Merge pull request #1793 from filbranden/extract1
[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 <errno.h>
23 #include <getopt.h>
24 #include <libkmod.h>
25 #include <limits.h>
26 #include <string.h>
27 #include <sys/stat.h>
28
29 #include "conf-files.h"
30 #include "def.h"
31 #include "fd-util.h"
32 #include "fileio.h"
33 #include "log.h"
34 #include "proc-cmdline.h"
35 #include "string-util.h"
36 #include "strv.h"
37 #include "util.h"
38
39 static char **arg_proc_cmdline_modules = NULL;
40
41 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("modules-load");
42
43 static void systemd_kmod_log(void *data, int priority, const char *file, int line,
44 const char *fn, const char *format, va_list args) {
45
46 DISABLE_WARNING_FORMAT_NONLITERAL;
47 log_internalv(priority, 0, file, line, fn, format, args);
48 REENABLE_WARNING;
49 }
50
51 static int add_modules(const char *p) {
52 _cleanup_strv_free_ char **k = NULL;
53
54 k = strv_split(p, ",");
55 if (!k)
56 return log_oom();
57
58 if (strv_extend_strv(&arg_proc_cmdline_modules, k, true) < 0)
59 return log_oom();
60
61 return 0;
62 }
63
64 static int parse_proc_cmdline_item(const char *key, const char *value) {
65 int r;
66
67 if (STR_IN_SET(key, "modules-load", "rd.modules-load") && value) {
68 r = add_modules(value);
69 if (r < 0)
70 return r;
71 }
72
73 return 0;
74 }
75
76 static int load_module(struct kmod_ctx *ctx, const char *m) {
77 const int probe_flags = KMOD_PROBE_APPLY_BLACKLIST;
78 struct kmod_list *itr, *modlist = NULL;
79 int r = 0;
80
81 log_debug("load: %s", m);
82
83 r = kmod_module_new_from_lookup(ctx, m, &modlist);
84 if (r < 0)
85 return log_error_errno(r, "Failed to lookup alias '%s': %m", m);
86
87 if (!modlist) {
88 log_error("Failed to find module '%s'", m);
89 return -ENOENT;
90 }
91
92 kmod_list_foreach(itr, modlist) {
93 struct kmod_module *mod;
94 int state, err;
95
96 mod = kmod_module_get_module(itr);
97 state = kmod_module_get_initstate(mod);
98
99 switch (state) {
100 case KMOD_MODULE_BUILTIN:
101 log_info("Module '%s' is builtin", kmod_module_get_name(mod));
102 break;
103
104 case KMOD_MODULE_LIVE:
105 log_debug("Module '%s' is already loaded", kmod_module_get_name(mod));
106 break;
107
108 default:
109 err = kmod_module_probe_insert_module(mod, probe_flags,
110 NULL, NULL, NULL, NULL);
111
112 if (err == 0)
113 log_info("Inserted module '%s'", kmod_module_get_name(mod));
114 else if (err == KMOD_PROBE_APPLY_BLACKLIST)
115 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
116 else {
117 log_error_errno(err, "Failed to insert '%s': %m", kmod_module_get_name(mod));
118 r = err;
119 }
120 }
121
122 kmod_module_unref(mod);
123 }
124
125 kmod_module_unref_list(modlist);
126
127 return r;
128 }
129
130 static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) {
131 _cleanup_fclose_ FILE *f = NULL;
132 int r;
133
134 assert(ctx);
135 assert(path);
136
137 r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
138 if (r < 0) {
139 if (ignore_enoent && r == -ENOENT)
140 return 0;
141
142 return log_error_errno(r, "Failed to open %s, ignoring: %m", path);
143 }
144
145 log_debug("apply: %s", path);
146 for (;;) {
147 char line[LINE_MAX], *l;
148 int k;
149
150 if (!fgets(line, sizeof(line), f)) {
151 if (feof(f))
152 break;
153
154 return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
155 }
156
157 l = strstrip(line);
158 if (!*l)
159 continue;
160 if (strchr(COMMENTS "\n", *l))
161 continue;
162
163 k = load_module(ctx, l);
164 if (k < 0 && r == 0)
165 r = k;
166 }
167
168 return r;
169 }
170
171 static void help(void) {
172 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
173 "Loads statically configured kernel modules.\n\n"
174 " -h --help Show this help\n"
175 " --version Show package version\n",
176 program_invocation_short_name);
177 }
178
179 static int parse_argv(int argc, char *argv[]) {
180
181 enum {
182 ARG_VERSION = 0x100,
183 };
184
185 static const struct option options[] = {
186 { "help", no_argument, NULL, 'h' },
187 { "version", no_argument, NULL, ARG_VERSION },
188 {}
189 };
190
191 int c;
192
193 assert(argc >= 0);
194 assert(argv);
195
196 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
197
198 switch (c) {
199
200 case 'h':
201 help();
202 return 0;
203
204 case ARG_VERSION:
205 return version();
206
207 case '?':
208 return -EINVAL;
209
210 default:
211 assert_not_reached("Unhandled option");
212 }
213
214 return 1;
215 }
216
217 int main(int argc, char *argv[]) {
218 int r, k;
219 struct kmod_ctx *ctx;
220
221 r = parse_argv(argc, argv);
222 if (r <= 0)
223 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
224
225 log_set_target(LOG_TARGET_AUTO);
226 log_parse_environment();
227 log_open();
228
229 umask(0022);
230
231 r = parse_proc_cmdline(parse_proc_cmdline_item);
232 if (r < 0)
233 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
234
235 ctx = kmod_new(NULL, NULL);
236 if (!ctx) {
237 log_error("Failed to allocate memory for kmod.");
238 goto finish;
239 }
240
241 kmod_load_resources(ctx);
242 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
243
244 r = 0;
245
246 if (argc > optind) {
247 int i;
248
249 for (i = optind; i < argc; i++) {
250 k = apply_file(ctx, argv[i], false);
251 if (k < 0 && r == 0)
252 r = k;
253 }
254
255 } else {
256 _cleanup_strv_free_ char **files = NULL;
257 char **fn, **i;
258
259 STRV_FOREACH(i, arg_proc_cmdline_modules) {
260 k = load_module(ctx, *i);
261 if (k < 0 && r == 0)
262 r = k;
263 }
264
265 k = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
266 if (k < 0) {
267 log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
268 if (r == 0)
269 r = k;
270 goto finish;
271 }
272
273 STRV_FOREACH(fn, files) {
274 k = apply_file(ctx, *fn, true);
275 if (k < 0 && r == 0)
276 r = k;
277 }
278 }
279
280 finish:
281 kmod_unref(ctx);
282 strv_free(arg_proc_cmdline_modules);
283
284 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
285 }