]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/binfmt/binfmt.c
clients: unify how we invoke getopt_long()
[thirdparty/systemd.git] / src / binfmt / binfmt.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2010 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <stdlib.h>
23 #include <stdbool.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <limits.h>
28 #include <stdarg.h>
29 #include <getopt.h>
30
31 #include "log.h"
32 #include "hashmap.h"
33 #include "strv.h"
34 #include "util.h"
35 #include "conf-files.h"
36 #include "fileio.h"
37 #include "build.h"
38
39 static const char conf_file_dirs[] =
40 "/etc/binfmt.d\0"
41 "/run/binfmt.d\0"
42 "/usr/local/lib/binfmt.d\0"
43 "/usr/lib/binfmt.d\0"
44 #ifdef HAVE_SPLIT_USR
45 "/lib/binfmt.d\0"
46 #endif
47 ;
48
49 static int delete_rule(const char *rule) {
50 _cleanup_free_ char *x = NULL, *fn = NULL;
51 char *e;
52
53 assert(rule[0]);
54
55 x = strdup(rule);
56 if (!x)
57 return log_oom();
58
59 e = strchrnul(x+1, x[0]);
60 *e = 0;
61
62 fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
63 if (!fn)
64 return log_oom();
65
66 return write_string_file(fn, "-1");
67 }
68
69 static int apply_rule(const char *rule) {
70 int r;
71
72 delete_rule(rule);
73
74 r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule);
75 if (r < 0) {
76 log_error("Failed to add binary format: %s", strerror(-r));
77 return r;
78 }
79
80 return 0;
81 }
82
83 static int apply_file(const char *path, bool ignore_enoent) {
84 _cleanup_fclose_ FILE *f = NULL;
85 int r;
86
87 assert(path);
88
89 r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
90 if (r < 0) {
91 if (ignore_enoent && r == -ENOENT)
92 return 0;
93
94 log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
95 return r;
96 }
97
98 log_debug("apply: %s\n", path);
99 for (;;) {
100 char l[LINE_MAX], *p;
101 int k;
102
103 if (!fgets(l, sizeof(l), f)) {
104 if (feof(f))
105 break;
106
107 log_error("Failed to read file '%s', ignoring: %m", path);
108 return -errno;
109 }
110
111 p = strstrip(l);
112 if (!*p)
113 continue;
114 if (strchr(COMMENTS "\n", *p))
115 continue;
116
117 k = apply_rule(p);
118 if (k < 0 && r == 0)
119 r = k;
120 }
121
122 return r;
123 }
124
125 static int help(void) {
126
127 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
128 "Registers binary formats.\n\n"
129 " -h --help Show this help\n"
130 " --version Show package version\n",
131 program_invocation_short_name);
132
133 return 0;
134 }
135
136 static int parse_argv(int argc, char *argv[]) {
137
138 enum {
139 ARG_VERSION = 0x100,
140 };
141
142 static const struct option options[] = {
143 { "help", no_argument, NULL, 'h' },
144 { "version", no_argument, NULL, ARG_VERSION },
145 {}
146 };
147
148 int c;
149
150 assert(argc >= 0);
151 assert(argv);
152
153 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
154
155 switch (c) {
156
157 case 'h':
158 return help();
159
160 case ARG_VERSION:
161 puts(PACKAGE_STRING);
162 puts(SYSTEMD_FEATURES);
163 return 0;
164
165 case '?':
166 return -EINVAL;
167
168 default:
169 assert_not_reached("Unhandled option");
170 }
171 }
172
173 return 1;
174 }
175
176 int main(int argc, char *argv[]) {
177 int r, k;
178
179 r = parse_argv(argc, argv);
180 if (r <= 0)
181 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
182
183 log_set_target(LOG_TARGET_AUTO);
184 log_parse_environment();
185 log_open();
186
187 umask(0022);
188
189 r = 0;
190
191 if (argc > optind) {
192 int i;
193
194 for (i = optind; i < argc; i++) {
195 k = apply_file(argv[i], false);
196 if (k < 0 && r == 0)
197 r = k;
198 }
199 } else {
200 _cleanup_strv_free_ char **files = NULL;
201 char **f;
202
203 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
204 if (r < 0) {
205 log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
206 goto finish;
207 }
208
209 /* Flush out all rules */
210 write_string_file("/proc/sys/fs/binfmt_misc/status", "-1");
211
212 STRV_FOREACH(f, files) {
213 k = apply_file(*f, true);
214 if (k < 0 && r == 0)
215 r = k;
216 }
217 }
218
219 finish:
220 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
221 }