]> git.proxmox.com Git - systemd.git/blame - src/binfmt/binfmt.c
bump version to 252.11-pve1
[systemd.git] / src / binfmt / binfmt.c
CommitLineData
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 26static bool arg_cat_config = false;
6e866b33 27static PagerFlags arg_pager_flags = 0;
20a6e51f 28static bool arg_unregister = false;
663996b3 29
ea0999c9
MB
30static 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
35static 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 71static 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
112static 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
134static 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 192static 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
244DEFINE_MAIN_FUNCTION(run);