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