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