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