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