]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/modules-load/modules-load.c
treewide: yet more log_*_errno + return simplifications
[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 <getopt.h>
30 #include <libkmod.h>
31
32 #include "log.h"
33 #include "util.h"
34 #include "strv.h"
35 #include "conf-files.h"
36 #include "fileio.h"
37 #include "build.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) < 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 log_error_errno(r, "Failed to open %s, ignoring: %m", path);
143 return r;
144 }
145
146 log_debug("apply: %s", path);
147 for (;;) {
148 char line[LINE_MAX], *l;
149 int k;
150
151 if (!fgets(line, sizeof(line), f)) {
152 if (feof(f))
153 break;
154
155 log_error("Failed to read file '%s', ignoring: %m", path);
156 return -errno;
157 }
158
159 l = strstrip(line);
160 if (!*l)
161 continue;
162 if (strchr(COMMENTS "\n", *l))
163 continue;
164
165 k = load_module(ctx, l);
166 if (k < 0 && r == 0)
167 r = k;
168 }
169
170 return r;
171 }
172
173 static void help(void) {
174 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
175 "Loads statically configured kernel modules.\n\n"
176 " -h --help Show this help\n"
177 " --version Show package version\n",
178 program_invocation_short_name);
179 }
180
181 static int parse_argv(int argc, char *argv[]) {
182
183 enum {
184 ARG_VERSION = 0x100,
185 };
186
187 static const struct option options[] = {
188 { "help", no_argument, NULL, 'h' },
189 { "version", no_argument, NULL, ARG_VERSION },
190 {}
191 };
192
193 int c;
194
195 assert(argc >= 0);
196 assert(argv);
197
198 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
199
200 switch (c) {
201
202 case 'h':
203 help();
204 return 0;
205
206 case ARG_VERSION:
207 puts(PACKAGE_STRING);
208 puts(SYSTEMD_FEATURES);
209 return 0;
210
211 case '?':
212 return -EINVAL;
213
214 default:
215 assert_not_reached("Unhandled option");
216 }
217
218 return 1;
219 }
220
221 int main(int argc, char *argv[]) {
222 int r, k;
223 struct kmod_ctx *ctx;
224
225 r = parse_argv(argc, argv);
226 if (r <= 0)
227 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
228
229 log_set_target(LOG_TARGET_AUTO);
230 log_parse_environment();
231 log_open();
232
233 umask(0022);
234
235 r = parse_proc_cmdline(parse_proc_cmdline_item);
236 if (r < 0)
237 log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m");
238
239 ctx = kmod_new(NULL, NULL);
240 if (!ctx) {
241 log_error("Failed to allocate memory for kmod.");
242 goto finish;
243 }
244
245 kmod_load_resources(ctx);
246 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
247
248 r = 0;
249
250 if (argc > optind) {
251 int i;
252
253 for (i = optind; i < argc; i++) {
254 k = apply_file(ctx, argv[i], false);
255 if (k < 0 && r == 0)
256 r = k;
257 }
258
259 } else {
260 _cleanup_free_ char **files = NULL;
261 char **fn, **i;
262
263 STRV_FOREACH(i, arg_proc_cmdline_modules) {
264 k = load_module(ctx, *i);
265 if (k < 0 && r == 0)
266 r = k;
267 }
268
269 k = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
270 if (k < 0) {
271 log_error_errno(k, "Failed to enumerate modules-load.d files: %m");
272 if (r == 0)
273 r = k;
274 goto finish;
275 }
276
277 STRV_FOREACH(fn, files) {
278 k = apply_file(ctx, *fn, true);
279 if (k < 0 && r == 0)
280 r = k;
281 }
282 }
283
284 finish:
285 kmod_unref(ctx);
286 strv_free(arg_proc_cmdline_modules);
287
288 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
289 }