]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/dbus1-generator/dbus1-generator.c
util-lib: split out fd-related operations into fd-util.[ch]
[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
3ffd4af2
LP
22#include "bus-internal.h"
23#include "bus-util.h"
24#include "cgroup-util.h"
674eb685 25#include "conf-parser.h"
3ffd4af2 26#include "fd-util.h"
674eb685 27#include "mkdir.h"
3ffd4af2 28#include "special.h"
674eb685 29#include "unit-name.h"
3ffd4af2 30#include "util.h"
674eb685 31
7c9a6f90 32static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
674eb685
LP
33
34static int create_dbus_files(
35 const char *path,
36 const char *name,
37 const char *service,
38 const char *exec,
39 const char *user,
40 const char *type) {
41
42 _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
43 _cleanup_fclose_ FILE *f = NULL;
0975b63f 44 int r;
674eb685
LP
45
46 assert(path);
47 assert(name);
5c817d31 48 assert(service || exec);
674eb685
LP
49
50 if (!service) {
51 _cleanup_free_ char *a = NULL;
52
53 s = strjoin("dbus-", name, ".service", NULL);
54 if (!s)
55 return log_oom();
56
7c9a6f90 57 a = strjoin(arg_dest_late, "/", s, NULL);
674eb685
LP
58 if (!a)
59 return log_oom();
60
61 f = fopen(a, "wxe");
4a62c710
MS
62 if (!f)
63 return log_error_errno(errno, "Failed to create %s: %m", a);
674eb685
LP
64
65 fprintf(f,
66 "# Automatically generated by systemd-dbus1-generator\n\n"
67 "[Unit]\n"
5c817d31 68 "SourcePath=%s\n"
c3834f9b
LP
69 "Description=DBUS1: %s\n"
70 "Documentation=man:systemd-dbus1-generator(8)\n\n"
674eb685
LP
71 "[Service]\n"
72 "ExecStart=%s\n"
73 "Type=dbus\n"
74 "BusName=%s\n",
75 path,
76 name,
77 exec,
78 name);
79
80 if (user)
81 fprintf(f, "User=%s\n", user);
82
83
84 if (type) {
85 fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
86
87 if (streq(type, "system"))
057171ef 88 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS "\n");
62cfb98a
KS
89 else if (streq(type, "session")) {
90 char *run;
91
92 run = getenv("XDG_RUNTIME_DIR");
93 if (!run) {
94 log_error("XDG_RUNTIME_DIR not set.");
95 return -EINVAL;
96 }
97
057171ef
DH
98 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT ";" UNIX_USER_BUS_ADDRESS_FMT "\n",
99 getuid(), run);
62cfb98a 100 }
674eb685
LP
101 }
102
0975b63f 103 r = fflush_and_check(f);
23bbb0de
MS
104 if (r < 0)
105 return log_error_errno(r, "Failed to write %s: %m", a);
674eb685 106
74ca738f 107 f = safe_fclose(f);
0975b63f 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 },
34a317e1 158 { },
674eb685
LP
159 };
160
36f822c4 161 char *p;
674eb685
LP
162 int r;
163
164 assert(path);
165 assert(fname);
166
63c372cb 167 p = strjoina(path, "/", fname);
36f822c4
ZJS
168 r = config_parse(NULL, p, NULL,
169 "D-BUS Service\0",
170 config_item_table_lookup, table,
171 true, false, true, NULL);
674eb685
LP
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
4c3a127c
LP
185 if (streq(name, "org.freedesktop.systemd1")) {
186 log_debug("Skipping %s, identified as systemd.", p);
187 return 0;
188 }
189
674eb685 190 if (service) {
7410616c 191 if (!unit_name_is_valid(service, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) {
674eb685
LP
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 {
4c3a127c 200 if (streq(exec, "/bin/false") || !exec) {
674eb685
LP
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
5c817d31 214static int parse_dbus_fragments(const char *path, const char *type) {
674eb685
LP
215 _cleanup_closedir_ DIR *d = NULL;
216 struct dirent *de;
674eb685
LP
217 int r;
218
5c817d31
LP
219 assert(path);
220 assert(type);
674eb685 221
5c817d31 222 d = opendir(path);
674eb685
LP
223 if (!d) {
224 if (errno == -ENOENT)
225 return 0;
226
56f64d95 227 log_error_errno(errno, "Failed to enumerate D-Bus activated services: %m");
674eb685
LP
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
5c817d31 238 q = add_dbus(path, de->d_name, type);
674eb685
LP
239 if (q < 0)
240 r = q;
241 }
242
243 return r;
244
245fail:
56f64d95 246 log_error_errno(errno, "Failed to read D-Bus services directory: %m");
674eb685
LP
247 return -errno;
248}
249
5c817d31
LP
250static int link_busnames_target(const char *units) {
251 const char *f, *t;
252
63c372cb
LP
253 f = strjoina(units, "/" SPECIAL_BUSNAMES_TARGET);
254 t = strjoina(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
5c817d31
LP
255
256 mkdir_parents_label(t, 0755);
4a62c710
MS
257 if (symlink(f, t) < 0)
258 return log_error_errno(errno, "Failed to create symlink %s: %m", t);
5c817d31
LP
259
260 return 0;
261}
262
7c9a6f90
LP
263static int link_compatibility(const char *units) {
264 const char *f, *t;
265
63c372cb
LP
266 f = strjoina(units, "/systemd-bus-proxyd.socket");
267 t = strjoina(arg_dest, "/" SPECIAL_DBUS_SOCKET);
7c9a6f90 268 mkdir_parents_label(t, 0755);
4a62c710
MS
269 if (symlink(f, t) < 0)
270 return log_error_errno(errno, "Failed to create symlink %s: %m", t);
7c9a6f90 271
63c372cb
LP
272 f = strjoina(units, "/systemd-bus-proxyd.socket");
273 t = strjoina(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
ac12cf5b 274 mkdir_parents_label(t, 0755);
4a62c710
MS
275 if (symlink(f, t) < 0)
276 return log_error_errno(errno, "Failed to create symlink %s: %m", t);
ac12cf5b 277
63c372cb 278 t = strjoina(arg_dest, "/" SPECIAL_DBUS_SERVICE);
4a62c710
MS
279 if (symlink("/dev/null", t) < 0)
280 return log_error_errno(errno, "Failed to mask %s: %m", t);
010b2b8d 281
7c9a6f90
LP
282 return 0;
283}
284
674eb685 285int main(int argc, char *argv[]) {
5c817d31
LP
286 const char *path, *type, *units;
287 int r, q;
674eb685
LP
288
289 if (argc > 1 && argc != 4) {
290 log_error("This program takes three or no arguments.");
291 return EXIT_FAILURE;
292 }
293
7c9a6f90
LP
294 if (argc > 1) {
295 arg_dest = argv[1];
296 arg_dest_late = argv[3];
297 }
674eb685
LP
298
299 log_set_target(LOG_TARGET_SAFE);
300 log_parse_environment();
301 log_open();
302
303 umask(0022);
304
d79acc30 305 if (!is_kdbus_available())
674eb685
LP
306 return 0;
307
5c817d31
LP
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;
d79acc30 313 } else if (r == -ENXIO) {
5c817d31
LP
314 path = "/usr/share/dbus-1/system-services";
315 type = "system";
316 units = SYSTEM_DATA_UNIT_PATH;
23bbb0de
MS
317 } else
318 return log_error_errno(r, "Failed to determine whether we are running as user or system instance: %m");
5c817d31
LP
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;
674eb685 326
7c9a6f90
LP
327 q = link_compatibility(units);
328 if (q < 0)
329 r = q;
330
674eb685
LP
331 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
332}