chiark / gitweb /
bus: properly handle if new objects are installed in the node tree while we are dispa...
[elogind.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
38 static const char conf_file_dirs[] =
39         "/etc/binfmt.d\0"
40         "/run/binfmt.d\0"
41         "/usr/local/lib/binfmt.d\0"
42         "/usr/lib/binfmt.d\0"
43 #ifdef HAVE_SPLIT_USR
44         "/lib/binfmt.d\0"
45 #endif
46         ;
47
48 static int delete_rule(const char *rule) {
49         _cleanup_free_ char *x = NULL, *fn = NULL;
50         char *e;
51
52         assert(rule[0]);
53
54         x = strdup(rule);
55         if (!x)
56                 return log_oom();
57
58         e = strchrnul(x+1, x[0]);
59         *e = 0;
60
61         fn = strappend("/proc/sys/fs/binfmt_misc/", x+1);
62         if (!fn)
63                 return log_oom();
64
65         return write_string_file(fn, "-1");
66 }
67
68 static int apply_rule(const char *rule) {
69         int r;
70
71         delete_rule(rule);
72
73         r = write_string_file("/proc/sys/fs/binfmt_misc/register", rule);
74         if (r < 0) {
75                 log_error("Failed to add binary format: %s", strerror(-r));
76                 return r;
77         }
78
79         return 0;
80 }
81
82 static int apply_file(const char *path, bool ignore_enoent) {
83         _cleanup_fclose_ FILE *f = NULL;
84         int r;
85
86         assert(path);
87
88         r = search_and_fopen_nulstr(path, "re", conf_file_dirs, &f);
89         if (r < 0) {
90                 if (ignore_enoent && r == -ENOENT)
91                         return 0;
92
93                 log_error("Failed to open file '%s', ignoring: %s", path, strerror(-r));
94                 return r;
95         }
96
97         log_debug("apply: %s\n", path);
98         for (;;) {
99                 char l[LINE_MAX], *p;
100                 int k;
101
102                 if (!fgets(l, sizeof(l), f)) {
103                         if (feof(f))
104                                 break;
105
106                         log_error("Failed to read file '%s', ignoring: %m", path);
107                         return -errno;
108                 }
109
110                 p = strstrip(l);
111                 if (!*p)
112                         continue;
113                 if (strchr(COMMENTS "\n", *p))
114                         continue;
115
116                 k = apply_rule(p);
117                 if (k < 0 && r == 0)
118                         r = k;
119         }
120
121         return r;
122 }
123
124 static int help(void) {
125
126         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
127                "Registers binary formats.\n\n"
128                "  -h --help             Show this help\n",
129                program_invocation_short_name);
130
131         return 0;
132 }
133
134 static int parse_argv(int argc, char *argv[]) {
135
136         static const struct option options[] = {
137                 { "help",      no_argument,       NULL, 'h'           },
138                 { NULL,        0,                 NULL, 0             }
139         };
140
141         int c;
142
143         assert(argc >= 0);
144         assert(argv);
145
146         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0) {
147
148                 switch (c) {
149
150                 case 'h':
151                         help();
152                         return 0;
153
154                 case '?':
155                         return -EINVAL;
156
157                 default:
158                         log_error("Unknown option code %c", c);
159                         return -EINVAL;
160                 }
161         }
162
163         return 1;
164 }
165
166 int main(int argc, char *argv[]) {
167         int r, k;
168
169         r = parse_argv(argc, argv);
170         if (r <= 0)
171                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
172
173         log_set_target(LOG_TARGET_AUTO);
174         log_parse_environment();
175         log_open();
176
177         umask(0022);
178
179         r = 0;
180
181         if (argc > optind) {
182                 int i;
183
184                 for (i = optind; i < argc; i++) {
185                         k = apply_file(argv[i], false);
186                         if (k < 0 && r == 0)
187                                 r = k;
188                 }
189         } else {
190                 _cleanup_strv_free_ char **files = NULL;
191                 char **f;
192
193                 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
194                 if (r < 0) {
195                         log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
196                         goto finish;
197                 }
198
199                 /* Flush out all rules */
200                 write_string_file("/proc/sys/fs/binfmt_misc/status", "-1");
201
202                 STRV_FOREACH(f, files) {
203                         k = apply_file(*f, true);
204                         if (k < 0 && r == 0)
205                                 r = k;
206                 }
207         }
208
209 finish:
210         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
211 }