]>
Commit | Line | Data |
---|---|---|
1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ | |
2 | ||
3 | #include <getopt.h> | |
4 | #include <sys/stat.h> | |
5 | ||
6 | #include "alloc-util.h" | |
7 | #include "build.h" | |
8 | #include "conf-files.h" | |
9 | #include "constants.h" | |
10 | #include "errno-util.h" | |
11 | #include "fd-util.h" | |
12 | #include "fileio.h" | |
13 | #include "log.h" | |
14 | #include "main-func.h" | |
15 | #include "module-util.h" | |
16 | #include "pretty-print.h" | |
17 | #include "proc-cmdline.h" | |
18 | #include "string-util.h" | |
19 | #include "strv.h" | |
20 | ||
21 | static char **arg_proc_cmdline_modules = NULL; | |
22 | static const char conf_file_dirs[] = CONF_PATHS_NULSTR("modules-load.d"); | |
23 | ||
24 | STATIC_DESTRUCTOR_REGISTER(arg_proc_cmdline_modules, strv_freep); | |
25 | ||
26 | static int parse_proc_cmdline_item(const char *key, const char *value, void *data) { | |
27 | int r; | |
28 | ||
29 | if (proc_cmdline_key_streq(key, "modules_load")) { | |
30 | ||
31 | if (proc_cmdline_value_missing(key, value)) | |
32 | return 0; | |
33 | ||
34 | r = strv_split_and_extend(&arg_proc_cmdline_modules, value, ",", /* filter_duplicates = */ true); | |
35 | if (r < 0) | |
36 | return log_error_errno(r, "Failed to parse modules_load= kernel command line option: %m"); | |
37 | } | |
38 | ||
39 | return 0; | |
40 | } | |
41 | ||
42 | static int apply_file(struct kmod_ctx *ctx, const char *path, bool ignore_enoent) { | |
43 | _cleanup_fclose_ FILE *f = NULL; | |
44 | _cleanup_free_ char *pp = NULL; | |
45 | int r; | |
46 | ||
47 | assert(ctx); | |
48 | assert(path); | |
49 | ||
50 | r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f, &pp); | |
51 | if (r < 0) { | |
52 | if (ignore_enoent && r == -ENOENT) | |
53 | return 0; | |
54 | ||
55 | return log_error_errno(r, "Failed to open %s: %m", path); | |
56 | } | |
57 | ||
58 | log_debug("apply: %s", pp); | |
59 | for (;;) { | |
60 | _cleanup_free_ char *line = NULL; | |
61 | int k; | |
62 | ||
63 | k = read_stripped_line(f, LONG_LINE_MAX, &line); | |
64 | if (k < 0) | |
65 | return log_error_errno(k, "Failed to read file '%s': %m", pp); | |
66 | if (k == 0) | |
67 | break; | |
68 | ||
69 | if (isempty(line)) | |
70 | continue; | |
71 | if (strchr(COMMENTS, *line)) | |
72 | continue; | |
73 | ||
74 | k = module_load_and_warn(ctx, line, true); | |
75 | if (k == -ENOENT) | |
76 | continue; | |
77 | RET_GATHER(r, k); | |
78 | } | |
79 | ||
80 | return r; | |
81 | } | |
82 | ||
83 | static int help(void) { | |
84 | _cleanup_free_ char *link = NULL; | |
85 | int r; | |
86 | ||
87 | r = terminal_urlify_man("systemd-modules-load.service", "8", &link); | |
88 | if (r < 0) | |
89 | return log_oom(); | |
90 | ||
91 | printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" | |
92 | "Loads statically configured kernel modules.\n\n" | |
93 | " -h --help Show this help\n" | |
94 | " --version Show package version\n" | |
95 | "\nSee the %s for details.\n", | |
96 | program_invocation_short_name, | |
97 | link); | |
98 | ||
99 | return 0; | |
100 | } | |
101 | ||
102 | static int parse_argv(int argc, char *argv[]) { | |
103 | enum { | |
104 | ARG_VERSION = 0x100, | |
105 | }; | |
106 | ||
107 | static const struct option options[] = { | |
108 | { "help", no_argument, NULL, 'h' }, | |
109 | { "version", no_argument, NULL, ARG_VERSION }, | |
110 | {} | |
111 | }; | |
112 | ||
113 | int c; | |
114 | ||
115 | assert(argc >= 0); | |
116 | assert(argv); | |
117 | ||
118 | while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) | |
119 | switch (c) { | |
120 | ||
121 | case 'h': | |
122 | return help(); | |
123 | ||
124 | case ARG_VERSION: | |
125 | return version(); | |
126 | ||
127 | case '?': | |
128 | return -EINVAL; | |
129 | ||
130 | default: | |
131 | assert_not_reached(); | |
132 | } | |
133 | ||
134 | return 1; | |
135 | } | |
136 | ||
137 | static int run(int argc, char *argv[]) { | |
138 | _cleanup_(sym_kmod_unrefp) struct kmod_ctx *ctx = NULL; | |
139 | int r, k; | |
140 | ||
141 | r = parse_argv(argc, argv); | |
142 | if (r <= 0) | |
143 | return r; | |
144 | ||
145 | log_setup(); | |
146 | ||
147 | umask(0022); | |
148 | ||
149 | r = proc_cmdline_parse(parse_proc_cmdline_item, NULL, PROC_CMDLINE_STRIP_RD_PREFIX); | |
150 | if (r < 0) | |
151 | log_warning_errno(r, "Failed to parse kernel command line, ignoring: %m"); | |
152 | ||
153 | r = module_setup_context(&ctx); | |
154 | if (r < 0) | |
155 | return log_error_errno(r, "Failed to initialize libkmod context: %m"); | |
156 | ||
157 | r = 0; | |
158 | ||
159 | if (argc > optind) { | |
160 | for (int i = optind; i < argc; i++) | |
161 | RET_GATHER(r, apply_file(ctx, argv[i], false)); | |
162 | ||
163 | } else { | |
164 | _cleanup_strv_free_ char **files = NULL; | |
165 | ||
166 | STRV_FOREACH(i, arg_proc_cmdline_modules) { | |
167 | k = module_load_and_warn(ctx, *i, true); | |
168 | if (k == -ENOENT) | |
169 | continue; | |
170 | RET_GATHER(r, k); | |
171 | } | |
172 | ||
173 | k = conf_files_list_nulstr(&files, ".conf", NULL, 0, conf_file_dirs); | |
174 | if (k < 0) | |
175 | return log_error_errno(k, "Failed to enumerate modules-load.d files: %m"); | |
176 | ||
177 | STRV_FOREACH(fn, files) | |
178 | RET_GATHER(r, apply_file(ctx, *fn, true)); | |
179 | } | |
180 | ||
181 | return r; | |
182 | } | |
183 | ||
184 | DEFINE_MAIN_FUNCTION(run); |