1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
23 #include "conf-parser.h"
27 #include "bus-internal.h"
28 #include "unit-name.h"
29 #include "cgroup-util.h"
31 static const char *arg_dest_late = "/tmp", *arg_dest = "/tmp";
33 static int create_dbus_files(
41 _cleanup_free_ char *b = NULL, *s = NULL, *lnk = NULL;
42 _cleanup_fclose_ FILE *f = NULL;
46 assert(service || exec);
49 _cleanup_free_ char *a = NULL;
51 s = strjoin("dbus-", name, ".service", NULL);
55 a = strjoin(arg_dest_late, "/", s, NULL);
61 log_error("Failed to create %s: %m", a);
66 "# Automatically generated by systemd-dbus1-generator\n\n"
69 "Description=DBUS1: %s\n"
70 "Documentation=man:systemd-dbus1-generator(8)\n\n"
81 fprintf(f, "User=%s\n", user);
85 fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
87 if (streq(type, "system"))
88 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
89 else if (streq(type, "session")) {
92 run = getenv("XDG_RUNTIME_DIR");
94 log_error("XDG_RUNTIME_DIR not set.");
98 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
99 (unsigned long) getuid(), run);
105 log_error("Failed to write %s: %m", a);
112 b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
118 log_error("Failed to create %s: %m", b);
123 "# Automatically generated by systemd-dbus1-generator\n\n"
126 "Description=DBUS1: %s\n"
127 "Documentation=man:systemd-dbus1-generator(8)\n\n"
131 "AllowUser=root own\n"
140 log_error("Failed to write %s: %m", b);
144 lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
148 mkdir_parents_label(lnk, 0755);
149 if (symlink(b, lnk)) {
150 log_error("Failed to create symlink %s: %m", lnk);
157 static int add_dbus(const char *path, const char *fname, const char *type) {
158 _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
160 ConfigTableItem table[] = {
161 { "D-BUS Service", "Name", config_parse_string, 0, &name },
162 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
163 { "D-BUS Service", "User", config_parse_string, 0, &user },
164 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
167 _cleanup_fclose_ FILE *f = NULL;
168 _cleanup_free_ char *p = NULL;
174 p = strjoin(path, "/", fname, NULL);
180 if (errno == -ENOENT)
183 log_error("Failed to read %s: %m", p);
187 r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
192 log_warning("Activation file %s lacks name setting, ignoring.", p);
196 if (!service_name_is_valid(name)) {
197 log_warning("Bus service name %s is not valid, ignoring.", name);
201 if (streq(name, "org.freedesktop.systemd1")) {
202 log_debug("Skipping %s, identified as systemd.", p);
207 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
208 log_warning("Unit name %s is not valid, ignoring.", service);
211 if (!endswith(service, ".service")) {
212 log_warning("Bus names can only activate services, ignoring %s.", p);
216 if (streq(exec, "/bin/false") || !exec) {
217 log_warning("Neither service name nor binary path specified, ignoring %s.", p);
221 if (exec[0] != '/') {
222 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
227 return create_dbus_files(p, name, service, exec, user, type);
230 static int parse_dbus_fragments(const char *path, const char *type) {
231 _cleanup_closedir_ DIR *d = NULL;
240 if (errno == -ENOENT)
243 log_error("Failed to enumerate D-Bus activated services: %m");
248 FOREACH_DIRENT(de, d, goto fail) {
251 if (!endswith(de->d_name, ".service"))
254 q = add_dbus(path, de->d_name, type);
262 log_error("Failed to read D-Bus services directory: %m");
266 static int link_busnames_target(const char *units) {
269 f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
270 t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
272 mkdir_parents_label(t, 0755);
273 if (symlink(f, t) < 0) {
274 log_error("Failed to create symlink %s: %m", t);
281 static int link_compatibility(const char *units) {
284 f = strappenda(units, "/systemd-bus-proxyd.socket");
285 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
286 mkdir_parents_label(t, 0755);
287 if (symlink(f, t) < 0) {
288 log_error("Failed to create symlink %s: %m", t);
292 f = strappenda(units, "/systemd-bus-proxyd.socket");
293 t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
294 mkdir_parents_label(t, 0755);
295 if (symlink(f, t) < 0) {
296 log_error("Failed to create symlink %s: %m", t);
300 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
301 if (symlink("/dev/null", t) < 0) {
302 log_error("Failed to mask %s: %m", t);
309 int main(int argc, char *argv[]) {
310 const char *path, *type, *units;
313 if (argc > 1 && argc != 4) {
314 log_error("This program takes three or no arguments.");
320 arg_dest_late = argv[3];
323 log_set_target(LOG_TARGET_SAFE);
324 log_parse_environment();
329 if (access("/dev/kdbus/control", F_OK) < 0)
332 r = cg_pid_get_owner_uid(0, NULL);
334 path = "/usr/share/dbus-1/services";
336 units = USER_DATA_UNIT_PATH;
337 } else if (r == -ENOENT) {
338 path = "/usr/share/dbus-1/system-services";
340 units = SYSTEM_DATA_UNIT_PATH;
342 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
346 r = parse_dbus_fragments(path, type);
348 /* FIXME: One day this should just be pulled in statically from basic.target */
349 q = link_busnames_target(units);
353 q = link_compatibility(units);
357 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;