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