]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/dbus1-generator/dbus1-generator.c
dbus1-generator: always pull proxy socket into sockets.target
[thirdparty/systemd.git] / src / dbus1-generator / dbus1-generator.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2013 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 "util.h"
23 #include "conf-parser.h"
24 #include "special.h"
25 #include "mkdir.h"
26 #include "bus-util.h"
27 #include "bus-internal.h"
28 #include "unit-name.h"
29 #include "cgroup-util.h"
30
31 static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
32
33 static int create_dbus_files(
34 const char *path,
35 const char *name,
36 const char *service,
37 const char *exec,
38 const char *user,
39 const char *type) {
40
41 _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
42 _cleanup_fclose_ FILE *f = NULL;
43
44 assert(path);
45 assert(name);
46 assert(service || exec);
47
48 if (!service) {
49 _cleanup_free_ char *a = NULL;
50
51 s = strjoin("dbus-", name, ".service", NULL);
52 if (!s)
53 return log_oom();
54
55 a = strjoin(arg_dest_late, "/", s, NULL);
56 if (!a)
57 return log_oom();
58
59 f = fopen(a, "wxe");
60 if (!f) {
61 log_error("Failed to create %s: %m", a);
62 return -errno;
63 }
64
65 fprintf(f,
66 "# Automatically generated by systemd-dbus1-generator\n\n"
67 "[Unit]\n"
68 "SourcePath=%s\n"
69 "Description=DBUS1: %s\n\n"
70 "[Service]\n"
71 "ExecStart=%s\n"
72 "Type=dbus\n"
73 "BusName=%s\n",
74 path,
75 name,
76 exec,
77 name);
78
79 if (user)
80 fprintf(f, "User=%s\n", user);
81
82
83 if (type) {
84 fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
85
86 if (streq(type, "system"))
87 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=kernel:/dev/kdbus/0-system\n");
88 else if (streq(type, "session"))
89 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=kernel:/dev/kdbus/%lu-user\n", (unsigned long) getuid());
90 }
91
92 fflush(f);
93 if (ferror(f)) {
94 log_error("Failed to write %s: %m", a);
95 return -errno;
96 }
97
98 service = s;
99 }
100
101 b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
102 if (!b)
103 return log_oom();
104
105 f = fopen(b, "wxe");
106 if (!f) {
107 log_error("Failed to create %s: %m", b);
108 return -errno;
109 }
110
111 fprintf(f,
112 "# Automatically generated by systemd-dbus1-generator\n\n"
113 "[Unit]\n"
114 "SourcePath=%s\n"
115 "Description=DBUS1: %s\n\n"
116 "[BusName]\n"
117 "Name=%s\n"
118 "Service=%s\n",
119 path,
120 name,
121 name,
122 service);
123
124 fflush(f);
125 if (ferror(f)) {
126 log_error("Failed to write %s: %m", b);
127 return -errno;
128 }
129
130 lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
131 if (!lnk)
132 return log_oom();
133
134 mkdir_parents_label(lnk, 0755);
135 if (symlink(b, lnk)) {
136 log_error("Failed to create symlink %s: %m", lnk);
137 return -errno;
138 }
139
140 return 0;
141 }
142
143 static int add_dbus(const char *path, const char *fname, const char *type) {
144 _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
145
146 ConfigTableItem table[] = {
147 { "D-BUS Service", "Name", config_parse_string, 0, &name },
148 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
149 { "D-BUS Service", "User", config_parse_string, 0, &user },
150 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
151 };
152
153 _cleanup_fclose_ FILE *f = NULL;
154 _cleanup_free_ char *p = NULL;
155 int r;
156
157 assert(path);
158 assert(fname);
159
160 p = strjoin(path, "/", fname, NULL);
161 if (!p)
162 return log_oom();
163
164 f = fopen(p, "re");
165 if (!f) {
166 if (errno == -ENOENT)
167 return 0;
168
169 log_error("Failed to read %s: %m", p);
170 return -errno;
171 }
172
173 r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
174 if (r < 0)
175 return r;
176
177 if (!name) {
178 log_warning("Activation file %s lacks name setting, ignoring.", p);
179 return 0;
180 }
181
182 if (!service_name_is_valid(name)) {
183 log_warning("Bus service name %s is not valid, ignoring.", name);
184 return 0;
185 }
186
187 if (streq(name, "org.freedesktop.systemd1")) {
188 log_debug("Skipping %s, identified as systemd.", p);
189 return 0;
190 }
191
192 if (service) {
193 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
194 log_warning("Unit name %s is not valid, ignoring.", service);
195 return 0;
196 }
197 if (!endswith(service, ".service")) {
198 log_warning("Bus names can only activate services, ignoring %s.", p);
199 return 0;
200 }
201 } else {
202 if (streq(exec, "/bin/false") || !exec) {
203 log_warning("Neither service name nor binary path specified, ignoring %s.", p);
204 return 0;
205 }
206
207 if (exec[0] != '/') {
208 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
209 return 0;
210 }
211 }
212
213 return create_dbus_files(p, name, service, exec, user, type);
214 }
215
216 static int parse_dbus_fragments(const char *path, const char *type) {
217 _cleanup_closedir_ DIR *d = NULL;
218 struct dirent *de;
219 int r;
220
221 assert(path);
222 assert(type);
223
224 d = opendir(path);
225 if (!d) {
226 if (errno == -ENOENT)
227 return 0;
228
229 log_error("Failed to enumerate D-Bus activated services: %m");
230 return -errno;
231 }
232
233 r = 0;
234 FOREACH_DIRENT(de, d, goto fail) {
235 int q;
236
237 if (!endswith(de->d_name, ".service"))
238 continue;
239
240 q = add_dbus(path, de->d_name, type);
241 if (q < 0)
242 r = q;
243 }
244
245 return r;
246
247 fail:
248 log_error("Failed to read D-Bus services directory: %m");
249 return -errno;
250 }
251
252 static int link_busnames_target(const char *units) {
253 const char *f, *t;
254
255 f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
256 t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
257
258 mkdir_parents_label(t, 0755);
259 if (symlink(f, t) < 0) {
260 log_error("Failed to create symlink %s: %m", t);
261 return -errno;
262 }
263
264 return 0;
265 }
266
267 static int link_compatibility(const char *units) {
268 const char *f, *t;
269
270 f = strappenda(units, "/systemd-bus-proxyd.socket");
271 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
272 mkdir_parents_label(t, 0755);
273 if (symlink(f, t) < 0) {
274 log_error("Failed to create symlink %s: %m", t);
275 return -errno;
276 }
277
278 f = strappenda(units, "/systemd-bus-proxyd.socket");
279 t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
280 mkdir_parents_label(t, 0755);
281 if (symlink(f, t) < 0) {
282 log_error("Failed to mask %s: %m", t);
283 return -errno;
284 }
285
286 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
287 if (symlink("/dev/null", t) < 0) {
288 log_error("Failed to mask %s: %m", t);
289 return -errno;
290 }
291
292 return 0;
293 }
294
295 int main(int argc, char *argv[]) {
296 const char *path, *type, *units;
297 int r, q;
298
299 if (argc > 1 && argc != 4) {
300 log_error("This program takes three or no arguments.");
301 return EXIT_FAILURE;
302 }
303
304 if (argc > 1) {
305 arg_dest = argv[1];
306 arg_dest_late = argv[3];
307 }
308
309 log_set_target(LOG_TARGET_SAFE);
310 log_parse_environment();
311 log_open();
312
313 umask(0022);
314
315 if (access("/dev/kdbus/control", F_OK) < 0)
316 return 0;
317
318 r = cg_pid_get_owner_uid(0, NULL);
319 if (r >= 0) {
320 path = "/usr/share/dbus-1/services";
321 type = "session";
322 units = USER_DATA_UNIT_PATH;
323 } else if (r == -ENOENT) {
324 path = "/usr/share/dbus-1/system-services";
325 type = "system";
326 units = SYSTEM_DATA_UNIT_PATH;
327 } else {
328 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
329 return r;
330 }
331
332 r = parse_dbus_fragments(path, type);
333
334 /* FIXME: One day this should just be pulled in statically from basic.target */
335 q = link_busnames_target(units);
336 if (q < 0)
337 r = q;
338
339 q = link_compatibility(units);
340 if (q < 0)
341 r = q;
342
343 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
344 }