]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/binfmt/binfmt.c
f4af4bef26747842199836ee098734f84717f4e6
[thirdparty/systemd.git] / src / binfmt / binfmt.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <getopt.h>
10 #include <limits.h>
11 #include <stdbool.h>
12 #include <stdio.h>
13 #include <stdlib.h>
14 #include <string.h>
15
16 #include "alloc-util.h"
17 #include "conf-files.h"
18 #include "def.h"
19 #include "fd-util.h"
20 #include "fileio.h"
21 #include "log.h"
22 #include "pager.h"
23 #include "string-util.h"
24 #include "strv.h"
25 #include "terminal-util.h"
26 #include "util.h"
27
28 static bool arg_cat_config = false;
29 static bool arg_no_pager = false;
30
31 static int delete_rule(const char *rule) {
32 _cleanup_free_ char *x = NULL, *fn = NULL;
33 char *e;
34
35 assert(rule[0]);
36
37 x = strdup(rule);
38 if (!x)
39 return log_oom();
40
41 e = strchrnul(x+1, x[0]);
42 *e = 0;
43
44 fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
45 if (!fn)
46 return log_oom();
47
48 return write_string_file(fn, "-1", 0);
49 }
50
51 static int apply_rule(const char *rule) {
52 int r;
53
54 delete_rule(rule);
55
56 r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, 0);
57 if (r < 0)
58 return log_error_errno(r, "Failed to add binary format: %m");
59
60 return 0;
61 }
62
63 static int apply_file(const char *path, bool ignore_enoent) {
64 _cleanup_fclose_ FILE *f = NULL;
65 int r;
66
67 assert(path);
68
69 r = search_and_fopen(path, "re", NULL, (const char**) CONF_PATHS_STRV("binfmt.d"), &f);
70 if (r < 0) {
71 if (ignore_enoent && r == -ENOENT)
72 return 0;
73
74 return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
75 }
76
77 log_debug("apply: %s", path);
78 for (;;) {
79 char l[LINE_MAX], *p;
80 int k;
81
82 if (!fgets(l, sizeof(l), f)) {
83 if (feof(f))
84 break;
85
86 return log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
87 }
88
89 p = strstrip(l);
90 if (!*p)
91 continue;
92 if (strchr(COMMENTS "\n", *p))
93 continue;
94
95 k = apply_rule(p);
96 if (k < 0 && r == 0)
97 r = k;
98 }
99
100 return r;
101 }
102
103 static void help(void) {
104 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
105 "Registers binary formats.\n\n"
106 " -h --help Show this help\n"
107 " --version Show package version\n"
108 " --cat-config Show configuration files\n"
109 " --no-pager Do not pipe output into a pager\n"
110 , program_invocation_short_name);
111 }
112
113 static int parse_argv(int argc, char *argv[]) {
114
115 enum {
116 ARG_VERSION = 0x100,
117 ARG_CAT_CONFIG,
118 ARG_NO_PAGER,
119 };
120
121 static const struct option options[] = {
122 { "help", no_argument, NULL, 'h' },
123 { "version", no_argument, NULL, ARG_VERSION },
124 { "cat-config", no_argument, NULL, ARG_CAT_CONFIG },
125 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
126 {}
127 };
128
129 int c;
130
131 assert(argc >= 0);
132 assert(argv);
133
134 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
135
136 switch (c) {
137
138 case 'h':
139 help();
140 return 0;
141
142 case ARG_VERSION:
143 return version();
144
145 case ARG_CAT_CONFIG:
146 arg_cat_config = true;
147 break;
148
149 case ARG_NO_PAGER:
150 arg_no_pager = true;
151 break;
152
153 case '?':
154 return -EINVAL;
155
156 default:
157 assert_not_reached("Unhandled option");
158 }
159
160 if (arg_cat_config && argc > optind) {
161 log_error("Positional arguments are not allowed with --cat-config");
162 return -EINVAL;
163 }
164
165 return 1;
166 }
167
168 int main(int argc, char *argv[]) {
169 int r, k;
170
171 r = parse_argv(argc, argv);
172 if (r <= 0)
173 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
174
175 log_set_target(LOG_TARGET_AUTO);
176 log_parse_environment();
177 log_open();
178
179 umask(0022);
180
181 r = 0;
182
183 if (argc > optind) {
184 int i;
185
186 for (i = optind; i < argc; i++) {
187 k = apply_file(argv[i], false);
188 if (k < 0 && r == 0)
189 r = k;
190 }
191 } else {
192 _cleanup_strv_free_ char **files = NULL;
193 char **f;
194
195 r = conf_files_list_strv(&files, ".conf", NULL, 0, (const char**) CONF_PATHS_STRV("binfmt.d"));
196 if (r < 0) {
197 log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
198 goto finish;
199 }
200
201 if (arg_cat_config) {
202 (void) pager_open(arg_no_pager, false);
203
204 r = cat_files(NULL, files, 0);
205 goto finish;
206 }
207
208 /* Flush out all rules */
209 write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0);
210
211 STRV_FOREACH(f, files) {
212 k = apply_file(*f, true);
213 if (k < 0 && r == 0)
214 r = k;
215 }
216 }
217
218 finish:
219 pager_close();
220
221 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
222 }