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