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