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