]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/binfmt/binfmt.c
util-lib: split our string related calls from util.[ch] into its own file string...
[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 <errno.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stdbool.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29
30 #include "conf-files.h"
31 #include "fileio.h"
32 #include "log.h"
33 #include "string-util.h"
34 #include "strv.h"
35 #include "util.h"
36
37 static const char conf_file_dirs[] = CONF_DIRS_NULSTR("binfmt");
38
39 static int delete_rule(const char *rule) {
40 _cleanup_free_ char *x = NULL, *fn = NULL;
41 char *e;
42
43 assert(rule[0]);
44
45 x = strdup(rule);
46 if (!x)
47 return log_oom();
48
49 e = strchrnul(x+1, x[0]);
50 *e = 0;
51
52 fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
53 if (!fn)
54 return log_oom();
55
56 return write_string_file(fn, "-1", 0);
57 }
58
59 static int apply_rule(const char *rule) {
60 int r;
61
62 delete_rule(rule);
63
64 r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule, 0);
65 if (r < 0)
66 return log_error_errno(r, "Failed to add binary format: %m");
67
68 return 0;
69 }
70
71 static int apply_file(const char *path, bool ignore_enoent) {
72 _cleanup_fclose_ FILE *f = NULL;
73 int r;
74
75 assert(path);
76
77 r = search_and_fopen_nulstr(path, "re", NULL, conf_file_dirs, &f);
78 if (r < 0) {
79 if (ignore_enoent && r == -ENOENT)
80 return 0;
81
82 return log_error_errno(r, "Failed to open file '%s', ignoring: %m", path);
83 }
84
85 log_debug("apply: %s", path);
86 for (;;) {
87 char l[LINE_MAX], *p;
88 int k;
89
90 if (!fgets(l, sizeof(l), f)) {
91 if (feof(f))
92 break;
93
94 log_error_errno(errno, "Failed to read file '%s', ignoring: %m", path);
95 return -errno;
96 }
97
98 p = strstrip(l);
99 if (!*p)
100 continue;
101 if (strchr(COMMENTS "\n", *p))
102 continue;
103
104 k = apply_rule(p);
105 if (k < 0 && r == 0)
106 r = k;
107 }
108
109 return r;
110 }
111
112 static void help(void) {
113 printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
114 "Registers binary formats.\n\n"
115 " -h --help Show this help\n"
116 " --version Show package version\n"
117 , program_invocation_short_name);
118 }
119
120 static int parse_argv(int argc, char *argv[]) {
121
122 enum {
123 ARG_VERSION = 0x100,
124 };
125
126 static const struct option options[] = {
127 { "help", no_argument, NULL, 'h' },
128 { "version", no_argument, NULL, ARG_VERSION },
129 {}
130 };
131
132 int c;
133
134 assert(argc >= 0);
135 assert(argv);
136
137 while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
138
139 switch (c) {
140
141 case 'h':
142 help();
143 return 0;
144
145 case ARG_VERSION:
146 return version();
147
148 case '?':
149 return -EINVAL;
150
151 default:
152 assert_not_reached("Unhandled option");
153 }
154
155 return 1;
156 }
157
158 int main(int argc, char *argv[]) {
159 int r, k;
160
161 r = parse_argv(argc, argv);
162 if (r <= 0)
163 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
164
165 log_set_target(LOG_TARGET_AUTO);
166 log_parse_environment();
167 log_open();
168
169 umask(0022);
170
171 r = 0;
172
173 if (argc > optind) {
174 int i;
175
176 for (i = optind; i < argc; i++) {
177 k = apply_file(argv[i], false);
178 if (k < 0 && r == 0)
179 r = k;
180 }
181 } else {
182 _cleanup_strv_free_ char **files = NULL;
183 char **f;
184
185 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
186 if (r < 0) {
187 log_error_errno(r, "Failed to enumerate binfmt.d files: %m");
188 goto finish;
189 }
190
191 /* Flush out all rules */
192 write_string_file("/proc/sys/fs/binfmt_misc/status", "-1", 0);
193
194 STRV_FOREACH(f, files) {
195 k = apply_file(*f, true);
196 if (k < 0 && r == 0)
197 r = k;
198 }
199 }
200
201 finish:
202 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
203 }