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