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