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