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