]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/core/kmod-setup.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / core / kmod-setup.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19 ***/
20
21 #include <ftw.h>
22 #include <string.h>
23 #include <unistd.h>
24
25 #if HAVE_KMOD
26 #include <libkmod.h>
27 #endif
28
29 #include "alloc-util.h"
30 #include "bus-util.h"
31 #include "capability-util.h"
32 #include "fileio.h"
33 #include "kmod-setup.h"
34 #include "macro.h"
35 #include "module-util.h"
36 #include "string-util.h"
37
38 #if HAVE_KMOD
39 static void systemd_kmod_log(
40 void *data,
41 int priority,
42 const char *file, int line,
43 const char *fn,
44 const char *format,
45 va_list args) {
46
47 /* library logging is enabled at debug only */
48 DISABLE_WARNING_FORMAT_NONLITERAL;
49 log_internalv(LOG_DEBUG, 0, file, line, fn, format, args);
50 REENABLE_WARNING;
51 }
52
53 static int has_virtio_rng_nftw_cb(
54 const char *fpath,
55 const struct stat *sb,
56 int tflag,
57 struct FTW *ftwbuf) {
58
59 _cleanup_free_ char *alias = NULL;
60 int r;
61
62 if ((FTW_D == tflag) && (ftwbuf->level > 2))
63 return FTW_SKIP_SUBTREE;
64
65 if (FTW_F != tflag)
66 return FTW_CONTINUE;
67
68 if (!endswith(fpath, "/modalias"))
69 return FTW_CONTINUE;
70
71 r = read_one_line_file(fpath, &alias);
72 if (r < 0)
73 return FTW_SKIP_SIBLINGS;
74
75 if (startswith(alias, "pci:v00001AF4d00001005"))
76 return FTW_STOP;
77
78 if (startswith(alias, "pci:v00001AF4d00001044"))
79 return FTW_STOP;
80
81 return FTW_SKIP_SIBLINGS;
82 }
83
84 static bool has_virtio_rng(void) {
85 return (nftw("/sys/devices/pci0000:00", has_virtio_rng_nftw_cb, 64, FTW_MOUNT|FTW_PHYS|FTW_ACTIONRETVAL) == FTW_STOP);
86 }
87 #endif
88
89 int kmod_setup(void) {
90 #if HAVE_KMOD
91
92 static const struct {
93 const char *module;
94 const char *path;
95 bool warn_if_unavailable:1;
96 bool warn_if_module:1;
97 bool (*condition_fn)(void);
98 } kmod_table[] = {
99 /* auto-loading on use doesn't work before udev is up */
100 { "autofs4", "/sys/class/misc/autofs", true, false, NULL },
101
102 /* early configure of ::1 on the loopback device */
103 { "ipv6", "/sys/module/ipv6", false, true, NULL },
104
105 /* this should never be a module */
106 { "unix", "/proc/net/unix", true, true, NULL },
107
108 #if HAVE_LIBIPTC
109 /* netfilter is needed by networkd, nspawn among others, and cannot be autoloaded */
110 { "ip_tables", "/proc/net/ip_tables_names", false, false, NULL },
111 #endif
112 /* virtio_rng would be loaded by udev later, but real entropy might be needed very early */
113 { "virtio_rng", NULL, false, false, has_virtio_rng },
114 };
115 _cleanup_(kmod_unrefp) struct kmod_ctx *ctx = NULL;
116 unsigned int i;
117 int r;
118
119 if (have_effective_cap(CAP_SYS_MODULE) == 0)
120 return 0;
121
122 for (i = 0; i < ELEMENTSOF(kmod_table); i++) {
123 _cleanup_(kmod_module_unrefp) struct kmod_module *mod = NULL;
124
125 if (kmod_table[i].path && access(kmod_table[i].path, F_OK) >= 0)
126 continue;
127
128 if (kmod_table[i].condition_fn && !kmod_table[i].condition_fn())
129 continue;
130
131 if (kmod_table[i].warn_if_module)
132 log_debug("Your kernel apparently lacks built-in %s support. Might be "
133 "a good idea to compile it in. We'll now try to work around "
134 "this by loading the module...", kmod_table[i].module);
135
136 if (!ctx) {
137 ctx = kmod_new(NULL, NULL);
138 if (!ctx)
139 return log_oom();
140
141 kmod_set_log_fn(ctx, systemd_kmod_log, NULL);
142 kmod_load_resources(ctx);
143 }
144
145 r = kmod_module_new_from_name(ctx, kmod_table[i].module, &mod);
146 if (r < 0) {
147 log_error("Failed to lookup module '%s'", kmod_table[i].module);
148 continue;
149 }
150
151 r = kmod_module_probe_insert_module(mod, KMOD_PROBE_APPLY_BLACKLIST, NULL, NULL, NULL, NULL);
152 if (r == 0)
153 log_debug("Inserted module '%s'", kmod_module_get_name(mod));
154 else if (r == KMOD_PROBE_APPLY_BLACKLIST)
155 log_info("Module '%s' is blacklisted", kmod_module_get_name(mod));
156 else {
157 bool print_warning = kmod_table[i].warn_if_unavailable || (r < 0 && r != -ENOENT);
158
159 log_full_errno(print_warning ? LOG_WARNING : LOG_DEBUG, r,
160 "Failed to insert module '%s': %m", kmod_module_get_name(mod));
161 }
162 }
163
164 #endif
165 return 0;
166 }