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