chiark / gitweb /
sd-login: beef up login api, to add monitoring and enumerating
[elogind.git] / src / 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, *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         if (argc > 2) {
122                 log_error("This program expects one or no arguments.");
123                 return EXIT_FAILURE;
124         }
125
126         log_set_target(LOG_TARGET_AUTO);
127         log_parse_environment();
128         log_open();
129
130         if (argc > 1) {
131                 r = apply_file(argv[1], false);
132         } else {
133                 char **files, **f;
134
135                 /* Flush out all rules */
136                 write_one_line_file("/proc/sys/fs/binfmt_misc/status", "-1");
137
138                 r = conf_files_list(&files, ".conf",
139                                     "/run/binfmt.d",
140                                     "/etc/binfmt.d",
141                                     "/usr/local/lib/binfmt.d",
142                                     "/usr/lib/binfmt.d",
143                                     NULL);
144
145                 if (r < 0) {
146                         log_error("Failed to enumerate binfmt.d files: %s", strerror(-r));
147                         goto finish;
148                 }
149
150                 STRV_FOREACH(f, files) {
151                         int k;
152
153                         k = apply_file(*f, true);
154                         if (k < 0 && r == 0)
155                                 r = k;
156                 }
157
158                 strv_free(files);
159         }
160 finish:
161         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
162 }