]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/dbus1-generator/dbus1-generator.c
bus: also mask dbus.service in generator if kdbus is found
[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, false)) {
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
273 mkdir_parents_label(t, 0755);
274 if (symlink(f, t) < 0) {
275 log_error("Failed to create symlink %s: %m", t);
276 return -errno;
277 }
278
279 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
280 if (symlink("/dev/null", t) < 0) {
281 log_error("Failed to mask %s: %m", t);
282 return -errno;
283 }
284
285 return 0;
286 }
287
288 int main(int argc, char *argv[]) {
289 const char *path, *type, *units;
290 int r, q;
291
292 if (argc > 1 && argc != 4) {
293 log_error("This program takes three or no arguments.");
294 return EXIT_FAILURE;
295 }
296
297 if (argc > 1) {
298 arg_dest = argv[1];
299 arg_dest_late = argv[3];
300 }
301
302 log_set_target(LOG_TARGET_SAFE);
303 log_parse_environment();
304 log_open();
305
306 umask(0022);
307
308 if (access("/dev/kdbus/control", F_OK) < 0)
309 return 0;
310
311 r = cg_pid_get_owner_uid(0, NULL);
312 if (r >= 0) {
313 path = "/usr/share/dbus-1/services";
314 type = "session";
315 units = USER_DATA_UNIT_PATH;
316 } else if (r == -ENOENT) {
317 path = "/usr/share/dbus-1/system-services";
318 type = "system";
319 units = SYSTEM_DATA_UNIT_PATH;
320 } else {
321 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
322 return r;
323 }
324
325 r = parse_dbus_fragments(path, type);
326
327 /* FIXME: One day this should just be pulled in statically from basic.target */
328 q = link_busnames_target(units);
329 if (q < 0)
330 r = q;
331
332 q = link_compatibility(units);
333 if (q < 0)
334 r = q;
335
336 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
337 }