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