]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/binfmt/binfmt.c
bmfmt: allow passing more than one config file name
[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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
17
18 You should have received a copy of the GNU 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
30 #include "log.h"
31 #include "hashmap.h"
32 #include "strv.h"
33 #include "util.h"
34
35 static int delete_rule(const char *rule) {
36 char *x, *fn = NULL, *e;
37 int r;
38
39 assert(rule[0]);
40
41 if (!(x = strdup(rule)))
42 return -ENOMEM;
43
44 e = strchrnul(x+1, x[0]);
45 *e = 0;
46
47 asprintf(&fn, "/proc/sys/fs/binfmt_misc/%s", x+1);
48 free(x);
49
50 if (!fn)
51 return -ENOMEM;
52
53 r = write_one_line_file(fn, "-1");
54 free(fn);
55
56 return r;
57 }
58
59 static int apply_rule(const char *rule) {
60 int r;
61
62 delete_rule(rule);
63
64 if ((r = write_one_line_file("/proc/sys/fs/binfmt_misc/register", rule)) < 0) {
65 log_error("Failed to add binary format: %s", strerror(-r));
66 return r;
67 }
68
69 return 0;
70 }
71
72 static int apply_file(const char *path, bool ignore_enoent) {
73 FILE *f;
74 int r = 0;
75
76 assert(path);
77
78 if (!(f = fopen(path, "re"))) {
79 if (ignore_enoent && errno == ENOENT)
80 return 0;
81
82 log_error("Failed to open file '%s', ignoring: %m", path);
83 return -errno;
84 }
85
86 log_debug("apply: %s\n", path);
87 while (!feof(f)) {
88 char l[LINE_MAX], *p;
89 int k;
90
91 if (!fgets(l, sizeof(l), f)) {
92 if (feof(f))
93 break;
94
95 log_error("Failed to read file '%s', ignoring: %m", path);
96 r = -errno;
97 goto finish;
98 }
99
100 p = strstrip(l);
101
102 if (!*p)
103 continue;
104
105 if (strchr(COMMENTS, *p))
106 continue;
107
108 if ((k = apply_rule(p)) < 0 && r == 0)
109 r = k;
110 }
111
112 finish:
113 fclose(f);
114
115 return r;
116 }
117
118 int main(int argc, char *argv[]) {
119 int r = 0;
120
121 log_set_target(LOG_TARGET_AUTO);
122 log_parse_environment();
123 log_open();
124
125 umask(0022);
126
127 if (argc > 1) {
128 int i;
129
130 for (i = 1; i < argc; i++) {
131 int k;
132
133 k = apply_file(argv[1], false);
134 if (k < 0 && r == 0)
135 r = k;
136 }
137 } else {
138 char **files, **f;
139
140 r = conf_files_list(&files, ".conf",
141 "/etc/binfmt.d",
142 "/run/binfmt.d",
143 "/usr/local/lib/binfmt.d",
144 "/usr/lib/binfmt.d",
145 #ifdef HAVE_SPLIT_USR
146 "/lib/binfmt.d",
147 #endif
148 NULL);
149 if (r < 0) {
150 log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
151 goto finish;
152 }
153
154 /* Flush out all rules */
155 write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
156
157 STRV_FOREACH(f, files) {
158 int k;
159
160 k = apply_file(*f, true);
161 if (k < 0 && r == 0)
162 r = k;
163 }
164
165 strv_free(files);
166 }
167 finish:
168 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
169 }