]>
Commit | Line | Data |
---|---|---|
db9ecf05 | 1 | /* SPDX-License-Identifier: LGPL-2.1-or-later */ |
151b190e | 2 | |
151b190e | 3 | #include <errno.h> |
fabe5c0e | 4 | #include <getopt.h> |
3f6fd1ba LP |
5 | #include <limits.h> |
6 | #include <stdbool.h> | |
7 | #include <stdio.h> | |
8 | #include <stdlib.h> | |
ca78ad1d ZJS |
9 | #include <sys/stat.h> |
10 | #include <sys/types.h> | |
151b190e | 11 | |
b5efdb8a | 12 | #include "alloc-util.h" |
846acb67 | 13 | #include "binfmt-util.h" |
d6b4d1c7 | 14 | #include "build.h" |
3f6fd1ba | 15 | #include "conf-files.h" |
28db6fbf | 16 | #include "constants.h" |
3ffd4af2 | 17 | #include "fd-util.h" |
3f6fd1ba | 18 | #include "fileio.h" |
151b190e | 19 | #include "log.h" |
3be1cabe | 20 | #include "main-func.h" |
dcd5c891 | 21 | #include "pager.h" |
7452c3ff | 22 | #include "path-util.h" |
294bf0c3 | 23 | #include "pretty-print.h" |
07630cea | 24 | #include "string-util.h" |
db1413d7 | 25 | #include "strv.h" |
151b190e | 26 | |
6aaab70f | 27 | static bool arg_cat_config = false; |
0221d68a | 28 | static PagerFlags arg_pager_flags = 0; |
846acb67 | 29 | static bool arg_unregister = false; |
fabe5c0e | 30 | |
99a041d1 ZJS |
31 | static int delete_rule(const char *rulename) { |
32 | const char *fn = strjoina("/proc/sys/fs/binfmt_misc/", rulename); | |
33 | return write_string_file(fn, "-1", WRITE_STRING_FILE_DISABLE_BUFFER); | |
34 | } | |
151b190e | 35 | |
99a041d1 ZJS |
36 | static int apply_rule(const char *filename, unsigned line, const char *rule) { |
37 | assert(filename); | |
38 | assert(line > 0); | |
7452c3ff | 39 | assert(rule); |
151b190e LP |
40 | assert(rule[0]); |
41 | ||
99a041d1 ZJS |
42 | _cleanup_free_ char *rulename = NULL; |
43 | const char *e; | |
44 | int r; | |
45 | ||
f3670df1 | 46 | e = strchrnul(rule + 1, rule[0]); |
99a041d1 ZJS |
47 | rulename = strndup(rule + 1, e - rule - 1); |
48 | if (!rulename) | |
14212119 | 49 | return log_oom(); |
151b190e | 50 | |
99a041d1 ZJS |
51 | if (!filename_is_valid(rulename) || |
52 | STR_IN_SET(rulename, "register", "status")) | |
baaa35ad | 53 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
99a041d1 ZJS |
54 | "%s:%u: Rule name '%s' is not valid, refusing.", |
55 | filename, line, rulename); | |
56 | r = delete_rule(rulename); | |
57 | if (r < 0 && r != -ENOENT) | |
58 | log_warning_errno(r, "%s:%u: Failed to delete rule '%s', ignoring: %m", | |
59 | filename, line, rulename); | |
60 | if (r >= 0) | |
61 | log_debug("%s:%u: Rule '%s' deleted.", filename, line, rulename); | |
151b190e | 62 | |
57512c89 | 63 | r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, WRITE_STRING_FILE_DISABLE_BUFFER); |
23bbb0de | 64 | if (r < 0) |
99a041d1 ZJS |
65 | return log_error_errno(r, "%s:%u: Failed to add binary format '%s': %m", |
66 | filename, line, rulename); | |
151b190e | 67 | |
99a041d1 | 68 | log_debug("%s:%u: Binary format '%s' registered.", filename, line, rulename); |
151b190e LP |
69 | return 0; |
70 | } | |
71 | ||
99a041d1 | 72 | static int apply_file(const char *filename, bool ignore_enoent) { |
fabe5c0e | 73 | _cleanup_fclose_ FILE *f = NULL; |
2708160c | 74 | _cleanup_free_ char *pp = NULL; |
fabe5c0e | 75 | int r; |
151b190e | 76 | |
99a041d1 | 77 | assert(filename); |
151b190e | 78 | |
99a041d1 | 79 | r = search_and_fopen(filename, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f, &pp); |
fabe5c0e LP |
80 | if (r < 0) { |
81 | if (ignore_enoent && r == -ENOENT) | |
151b190e LP |
82 | return 0; |
83 | ||
99a041d1 | 84 | return log_error_errno(r, "Failed to open file '%s': %m", filename); |
151b190e LP |
85 | } |
86 | ||
28e5e1e9 | 87 | log_debug("Applying %s%s", pp, special_glyph(SPECIAL_GLYPH_ELLIPSIS)); |
99a041d1 ZJS |
88 | for (unsigned line = 1;; line++) { |
89 | _cleanup_free_ char *text = NULL; | |
741d2cb5 | 90 | char *p; |
151b190e LP |
91 | int k; |
92 | ||
99a041d1 | 93 | k = read_line(f, LONG_LINE_MAX, &text); |
741d2cb5 | 94 | if (k < 0) |
2708160c | 95 | return log_error_errno(k, "Failed to read file '%s': %m", pp); |
741d2cb5 LP |
96 | if (k == 0) |
97 | break; | |
151b190e | 98 | |
99a041d1 | 99 | p = strstrip(text); |
741d2cb5 | 100 | if (isempty(p)) |
151b190e | 101 | continue; |
741d2cb5 | 102 | if (strchr(COMMENTS, p[0])) |
151b190e LP |
103 | continue; |
104 | ||
99a041d1 ZJS |
105 | k = apply_rule(filename, line, p); |
106 | if (k < 0 && r >= 0) | |
151b190e LP |
107 | r = k; |
108 | } | |
109 | ||
151b190e LP |
110 | return r; |
111 | } | |
112 | ||
37ec0fdd LP |
113 | static int help(void) { |
114 | _cleanup_free_ char *link = NULL; | |
115 | int r; | |
116 | ||
117 | r = terminal_urlify_man("systemd-binfmt.service", "8", &link); | |
118 | if (r < 0) | |
119 | return log_oom(); | |
120 | ||
fabe5c0e | 121 | printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n" |
37ec0fdd | 122 | "Registers binary formats with the kernel.\n\n" |
eb9da376 | 123 | " -h --help Show this help\n" |
601185b4 | 124 | " --version Show package version\n" |
6aaab70f | 125 | " --cat-config Show configuration files\n" |
dcd5c891 | 126 | " --no-pager Do not pipe output into a pager\n" |
846acb67 | 127 | " --unregister Unregister all existing entries\n" |
bc556335 DDM |
128 | "\nSee the %s for details.\n", |
129 | program_invocation_short_name, | |
130 | link); | |
37ec0fdd LP |
131 | |
132 | return 0; | |
fabe5c0e LP |
133 | } |
134 | ||
135 | static int parse_argv(int argc, char *argv[]) { | |
eb9da376 LP |
136 | enum { |
137 | ARG_VERSION = 0x100, | |
6aaab70f | 138 | ARG_CAT_CONFIG, |
dcd5c891 | 139 | ARG_NO_PAGER, |
846acb67 | 140 | ARG_UNREGISTER, |
eb9da376 LP |
141 | }; |
142 | ||
fabe5c0e | 143 | static const struct option options[] = { |
dcd5c891 LP |
144 | { "help", no_argument, NULL, 'h' }, |
145 | { "version", no_argument, NULL, ARG_VERSION }, | |
146 | { "cat-config", no_argument, NULL, ARG_CAT_CONFIG }, | |
147 | { "no-pager", no_argument, NULL, ARG_NO_PAGER }, | |
846acb67 | 148 | { "unregister", no_argument, NULL, ARG_UNREGISTER }, |
eb9da376 | 149 | {} |
fabe5c0e LP |
150 | }; |
151 | ||
152 | int c; | |
153 | ||
154 | assert(argc >= 0); | |
155 | assert(argv); | |
156 | ||
601185b4 | 157 | while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) |
fabe5c0e LP |
158 | |
159 | switch (c) { | |
160 | ||
161 | case 'h': | |
37ec0fdd | 162 | return help(); |
eb9da376 LP |
163 | |
164 | case ARG_VERSION: | |
3f6fd1ba | 165 | return version(); |
fabe5c0e | 166 | |
6aaab70f ZJS |
167 | case ARG_CAT_CONFIG: |
168 | arg_cat_config = true; | |
169 | break; | |
170 | ||
dcd5c891 | 171 | case ARG_NO_PAGER: |
0221d68a | 172 | arg_pager_flags |= PAGER_DISABLE; |
dcd5c891 LP |
173 | break; |
174 | ||
846acb67 LP |
175 | case ARG_UNREGISTER: |
176 | arg_unregister = true; | |
177 | break; | |
178 | ||
fabe5c0e LP |
179 | case '?': |
180 | return -EINVAL; | |
181 | ||
182 | default: | |
04499a70 | 183 | assert_not_reached(); |
fabe5c0e | 184 | } |
fabe5c0e | 185 | |
846acb67 | 186 | if ((arg_unregister || arg_cat_config) && argc > optind) |
baaa35ad | 187 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), |
846acb67 | 188 | "Positional arguments are not allowed with --cat-config or --unregister"); |
6aaab70f | 189 | |
fabe5c0e LP |
190 | return 1; |
191 | } | |
192 | ||
3be1cabe | 193 | static int run(int argc, char *argv[]) { |
fabe5c0e LP |
194 | int r, k; |
195 | ||
196 | r = parse_argv(argc, argv); | |
197 | if (r <= 0) | |
52707598 | 198 | return r; |
151b190e | 199 | |
d2acb93d | 200 | log_setup(); |
151b190e | 201 | |
4c12626c LP |
202 | umask(0022); |
203 | ||
fabe5c0e | 204 | r = 0; |
13317670 | 205 | |
846acb67 LP |
206 | if (arg_unregister) |
207 | return disable_binfmt(); | |
208 | ||
33068a0f ZJS |
209 | if (argc > optind) |
210 | for (int i = optind; i < argc; i++) { | |
170dcb7b | 211 | k = apply_file(argv[i], false); |
99a041d1 | 212 | if (k < 0 && r >= 0) |
13317670 LP |
213 | r = k; |
214 | } | |
33068a0f | 215 | else { |
fabe5c0e | 216 | _cleanup_strv_free_ char **files = NULL; |
db1413d7 | 217 | |
a826d4f7 | 218 | r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d")); |
3be1cabe ZJS |
219 | if (r < 0) |
220 | return log_error_errno(r, "Failed to enumerate binfmt.d files: %m"); | |
151b190e | 221 | |
6aaab70f | 222 | if (arg_cat_config) { |
384c2c32 | 223 | pager_open(arg_pager_flags); |
dcd5c891 | 224 | |
3be1cabe | 225 | return cat_files(NULL, files, 0); |
6aaab70f ZJS |
226 | } |
227 | ||
13317670 | 228 | /* Flush out all rules */ |
99a041d1 ZJS |
229 | r = write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", WRITE_STRING_FILE_DISABLE_BUFFER); |
230 | if (r < 0) | |
231 | log_warning_errno(r, "Failed to flush binfmt_misc rules, ignoring: %m"); | |
232 | else | |
233 | log_debug("Flushed all binfmt_misc rules."); | |
13317670 | 234 | |
db1413d7 | 235 | STRV_FOREACH(f, files) { |
db1413d7 | 236 | k = apply_file(*f, true); |
99a041d1 | 237 | if (k < 0 && r >= 0) |
db1413d7 KS |
238 | r = k; |
239 | } | |
db1413d7 | 240 | } |
fabe5c0e | 241 | |
3be1cabe | 242 | return r; |
151b190e | 243 | } |
3be1cabe ZJS |
244 | |
245 | DEFINE_MAIN_FUNCTION(run); |