chiark / gitweb /
sd-bus: sync kdbus.h (API change: switch to absolute timeouts)
[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 #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", NULL, 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", 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 void help(void) {
126         printf("%s [OPTIONS...] [CONFIGURATION FILE...]\n\n"
127                "Registers binary formats.\n\n"
128                "  -h --help             Show this help\n"
129                "     --version          Show package version\n"
130                , program_invocation_short_name);
131 }
132
133 static int parse_argv(int argc, char *argv[]) {
134
135         enum {
136                 ARG_VERSION = 0x100,
137         };
138
139         static const struct option options[] = {
140                 { "help",      no_argument,       NULL, 'h'           },
141                 { "version",   no_argument,       NULL, ARG_VERSION   },
142                 {}
143         };
144
145         int c;
146
147         assert(argc >= 0);
148         assert(argv);
149
150         while ((c = getopt_long(argc, argv, "h", options, NULL)) >= 0)
151
152                 switch (c) {
153
154                 case 'h':
155                         help();
156                         return 0;
157
158                 case ARG_VERSION:
159                         puts(PACKAGE_STRING);
160                         puts(SYSTEMD_FEATURES);
161                         return 0;
162
163                 case '?':
164                         return -EINVAL;
165
166                 default:
167                         assert_not_reached("Unhandled option");
168                 }
169
170         return 1;
171 }
172
173 int main(int argc, char *argv[]) {
174         int r, k;
175
176         r = parse_argv(argc, argv);
177         if (r <= 0)
178                 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
179
180         log_set_target(LOG_TARGET_AUTO);
181         log_parse_environment();
182         log_open();
183
184         umask(0022);
185
186         r = 0;
187
188         if (argc > optind) {
189                 int i;
190
191                 for (i = optind; i < argc; i++) {
192                         k = apply_file(argv[i], false);
193                         if (k < 0 && r == 0)
194                                 r = k;
195                 }
196         } else {
197                 _cleanup_strv_free_ char **files = NULL;
198                 char **f;
199
200                 r = conf_files_list_nulstr(&files, ".conf", NULL, conf_file_dirs);
201                 if (r < 0) {
202                         log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
203                         goto finish;
204                 }
205
206                 /* Flush out all rules */
207                 write_string_file("/proc/sys/fs/binfmt_misc/status", "-1");
208
209                 STRV_FOREACH(f, files) {
210                         k = apply_file(*f, true);
211                         if (k < 0 && r == 0)
212                                 r = k;
213                 }
214         }
215
216 finish:
217         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
218 }