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