]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/binfmt/binfmt.c
Merge pull request #25168 from valentindavid/valentindavid/umount-move-recursive...
[thirdparty/systemd.git] / src / binfmt / binfmt.c
CommitLineData
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 27static bool arg_cat_config = false;
0221d68a 28static PagerFlags arg_pager_flags = 0;
846acb67 29static bool arg_unregister = false;
fabe5c0e 30
99a041d1
ZJS
31static 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
36static 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 42 _cleanup_free_ char *rulename = NULL;
99a041d1
ZJS
43 int r;
44
e8bec624 45 rulename = strdupcspn(rule + 1, CHAR_TO_STR(rule[0]));
99a041d1 46 if (!rulename)
14212119 47 return log_oom();
151b190e 48
99a041d1
ZJS
49 if (!filename_is_valid(rulename) ||
50 STR_IN_SET(rulename, "register", "status"))
baaa35ad 51 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
99a041d1
ZJS
52 "%s:%u: Rule name '%s' is not valid, refusing.",
53 filename, line, rulename);
54 r = delete_rule(rulename);
55 if (r < 0 && r != -ENOENT)
56 log_warning_errno(r, "%s:%u: Failed to delete rule '%s', ignoring: %m",
57 filename, line, rulename);
58 if (r >= 0)
59 log_debug("%s:%u: Rule '%s' deleted.", filename, line, rulename);
151b190e 60
57512c89 61 r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, WRITE_STRING_FILE_DISABLE_BUFFER);
23bbb0de 62 if (r < 0)
99a041d1
ZJS
63 return log_error_errno(r, "%s:%u: Failed to add binary format '%s': %m",
64 filename, line, rulename);
151b190e 65
99a041d1 66 log_debug("%s:%u: Binary format '%s' registered.", filename, line, rulename);
151b190e
LP
67 return 0;
68}
69
99a041d1 70static int apply_file(const char *filename, bool ignore_enoent) {
fabe5c0e 71 _cleanup_fclose_ FILE *f = NULL;
2708160c 72 _cleanup_free_ char *pp = NULL;
fabe5c0e 73 int r;
151b190e 74
99a041d1 75 assert(filename);
151b190e 76
99a041d1 77 r = search_and_fopen(filename, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f, &pp);
fabe5c0e
LP
78 if (r < 0) {
79 if (ignore_enoent && r == -ENOENT)
151b190e
LP
80 return 0;
81
99a041d1 82 return log_error_errno(r, "Failed to open file '%s': %m", filename);
151b190e
LP
83 }
84
28e5e1e9 85 log_debug("Applying %s%s", pp, special_glyph(SPECIAL_GLYPH_ELLIPSIS));
99a041d1
ZJS
86 for (unsigned line = 1;; line++) {
87 _cleanup_free_ char *text = NULL;
741d2cb5 88 char *p;
151b190e
LP
89 int k;
90
99a041d1 91 k = read_line(f, LONG_LINE_MAX, &text);
741d2cb5 92 if (k < 0)
2708160c 93 return log_error_errno(k, "Failed to read file '%s': %m", pp);
741d2cb5
LP
94 if (k == 0)
95 break;
151b190e 96
99a041d1 97 p = strstrip(text);
741d2cb5 98 if (isempty(p))
151b190e 99 continue;
741d2cb5 100 if (strchr(COMMENTS, p[0]))
151b190e
LP
101 continue;
102
99a041d1
ZJS
103 k = apply_rule(filename, line, p);
104 if (k < 0 && r >= 0)
151b190e
LP
105 r = k;
106 }
107
151b190e
LP
108 return r;
109}
110
37ec0fdd
LP
111static int help(void) {
112 _cleanup_free_ char *link = NULL;
113 int r;
114
115 r = terminal_urlify_man("systemd-binfmt.service", "8", &link);
116 if (r < 0)
117 return log_oom();
118
fabe5c0e 119 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
37ec0fdd 120 "Registers binary formats with the kernel.\n\n"
eb9da376 121 " -h --help Show this help\n"
601185b4 122 " --version Show package version\n"
6aaab70f 123 " --cat-config Show configuration files\n"
dcd5c891 124 " --no-pager Do not pipe output into a pager\n"
846acb67 125 " --unregister Unregister all existing entries\n"
bc556335
DDM
126 "\nSee the %s for details.\n",
127 program_invocation_short_name,
128 link);
37ec0fdd
LP
129
130 return 0;
fabe5c0e
LP
131}
132
133static int parse_argv(int argc, char *argv[]) {
eb9da376
LP
134 enum {
135 ARG_VERSION = 0x100,
6aaab70f 136 ARG_CAT_CONFIG,
dcd5c891 137 ARG_NO_PAGER,
846acb67 138 ARG_UNREGISTER,
eb9da376
LP
139 };
140
fabe5c0e 141 static const struct option options[] = {
dcd5c891
LP
142 { "help", no_argument, NULL, 'h' },
143 { "version", no_argument, NULL, ARG_VERSION },
144 { "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
145 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
846acb67 146 { "unregister", no_argument, NULL, ARG_UNREGISTER },
eb9da376 147 {}
fabe5c0e
LP
148 };
149
150 int c;
151
152 assert(argc >= 0);
153 assert(argv);
154
601185b4 155 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
fabe5c0e
LP
156
157 switch (c) {
158
159 case 'h':
37ec0fdd 160 return help();
eb9da376
LP
161
162 case ARG_VERSION:
3f6fd1ba 163 return version();
fabe5c0e 164
6aaab70f
ZJS
165 case ARG_CAT_CONFIG:
166 arg_cat_config = true;
167 break;
168
dcd5c891 169 case ARG_NO_PAGER:
0221d68a 170 arg_pager_flags |= PAGER_DISABLE;
dcd5c891
LP
171 break;
172
846acb67
LP
173 case ARG_UNREGISTER:
174 arg_unregister = true;
175 break;
176
fabe5c0e
LP
177 case '?':
178 return -EINVAL;
179
180 default:
04499a70 181 assert_not_reached();
fabe5c0e 182 }
fabe5c0e 183
846acb67 184 if ((arg_unregister || arg_cat_config) && argc > optind)
baaa35ad 185 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
846acb67 186 "Positional arguments are not allowed with --cat-config or --unregister");
6aaab70f 187
fabe5c0e
LP
188 return 1;
189}
190
94ba5b15
YW
191static int binfmt_mounted_warn(void) {
192 int r;
193
194 r = binfmt_mounted();
195 if (r < 0)
196 return log_error_errno(r, "Failed to check if /proc/sys/fs/binfmt_misc is mounted: %m");
197 if (r == 0)
198 log_debug("/proc/sys/fs/binfmt_misc is not mounted in read-write mode, skipping.");
199
200 return r;
201}
202
3be1cabe 203static int run(int argc, char *argv[]) {
fabe5c0e
LP
204 int r, k;
205
206 r = parse_argv(argc, argv);
207 if (r <= 0)
52707598 208 return r;
151b190e 209
d2acb93d 210 log_setup();
151b190e 211
4c12626c
LP
212 umask(0022);
213
fabe5c0e 214 r = 0;
13317670 215
846acb67
LP
216 if (arg_unregister)
217 return disable_binfmt();
218
94ba5b15
YW
219 if (argc > optind) {
220 r = binfmt_mounted_warn();
221 if (r <= 0)
222 return r;
223
33068a0f 224 for (int i = optind; i < argc; i++) {
170dcb7b 225 k = apply_file(argv[i], false);
99a041d1 226 if (k < 0 && r >= 0)
13317670
LP
227 r = k;
228 }
94ba5b15 229 } else {
fabe5c0e 230 _cleanup_strv_free_ char **files = NULL;
db1413d7 231
a826d4f7 232 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d"));
3be1cabe
ZJS
233 if (r < 0)
234 return log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
151b190e 235
6aaab70f 236 if (arg_cat_config) {
384c2c32 237 pager_open(arg_pager_flags);
dcd5c891 238
3be1cabe 239 return cat_files(NULL, files, 0);
6aaab70f
ZJS
240 }
241
94ba5b15
YW
242 r = binfmt_mounted_warn();
243 if (r <= 0)
244 return r;
245
13317670 246 /* Flush out all rules */
99a041d1
ZJS
247 r = write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", WRITE_STRING_FILE_DISABLE_BUFFER);
248 if (r < 0)
249 log_warning_errno(r, "Failed to flush binfmt_misc rules, ignoring: %m");
250 else
251 log_debug("Flushed all binfmt_misc rules.");
13317670 252
db1413d7 253 STRV_FOREACH(f, files) {
db1413d7 254 k = apply_file(*f, true);
99a041d1 255 if (k < 0 && r >= 0)
db1413d7
KS
256 r = k;
257 }
db1413d7 258 }
fabe5c0e 259
3be1cabe 260 return r;
151b190e 261}
3be1cabe
ZJS
262
263DEFINE_MAIN_FUNCTION(run);