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