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