]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/binfmt/binfmt.c
Rename def.h to constants.h
[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
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 72static 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
113static 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
135static 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 193static 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
245DEFINE_MAIN_FUNCTION(run);