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"
139 log_error("Failed to write %s: %m", b);
143 lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
147 mkdir_parents_label(lnk, 0755);
148 if (symlink(b, lnk)) {
149 log_error("Failed to create symlink %s: %m", lnk);
156 static int add_dbus(const char *path, const char *fname, const char *type) {
157 _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
159 ConfigTableItem table[] = {
160 { "D-BUS Service", "Name", config_parse_string, 0, &name },
161 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
162 { "D-BUS Service", "User", config_parse_string, 0, &user },
163 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
166 _cleanup_fclose_ FILE *f = NULL;
167 _cleanup_free_ char *p = NULL;
173 p = strjoin(path, "/", fname, NULL);
179 if (errno == -ENOENT)
182 log_error("Failed to read %s: %m", p);
186 r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
191 log_warning("Activation file %s lacks name setting, ignoring.", p);
195 if (!service_name_is_valid(name)) {
196 log_warning("Bus service name %s is not valid, ignoring.", name);
200 if (streq(name, "org.freedesktop.systemd1")) {
201 log_debug("Skipping %s, identified as systemd.", p);
206 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
207 log_warning("Unit name %s is not valid, ignoring.", service);
210 if (!endswith(service, ".service")) {
211 log_warning("Bus names can only activate services, ignoring %s.", p);
215 if (streq(exec, "/bin/false") || !exec) {
216 log_warning("Neither service name nor binary path specified, ignoring %s.", p);
220 if (exec[0] != '/') {
221 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
226 return create_dbus_files(p, name, service, exec, user, type);
229 static int parse_dbus_fragments(const char *path, const char *type) {
230 _cleanup_closedir_ DIR *d = NULL;
239 if (errno == -ENOENT)
242 log_error("Failed to enumerate D-Bus activated services: %m");
247 FOREACH_DIRENT(de, d, goto fail) {
250 if (!endswith(de->d_name, ".service"))
253 q = add_dbus(path, de->d_name, type);
261 log_error("Failed to read D-Bus services directory: %m");
265 static int link_busnames_target(const char *units) {
268 f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
269 t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
271 mkdir_parents_label(t, 0755);
272 if (symlink(f, t) < 0) {
273 log_error("Failed to create symlink %s: %m", t);
280 static int link_compatibility(const char *units) {
283 f = strappenda(units, "/systemd-bus-proxyd.socket");
284 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
285 mkdir_parents_label(t, 0755);
286 if (symlink(f, t) < 0) {
287 log_error("Failed to create symlink %s: %m", t);
291 f = strappenda(units, "/systemd-bus-proxyd.socket");
292 t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
293 mkdir_parents_label(t, 0755);
294 if (symlink(f, t) < 0) {
295 log_error("Failed to create symlink %s: %m", t);
299 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
300 if (symlink("/dev/null", t) < 0) {
301 log_error("Failed to mask %s: %m", t);
308 int main(int argc, char *argv[]) {
309 const char *path, *type, *units;
312 if (argc > 1 && argc != 4) {
313 log_error("This program takes three or no arguments.");
319 arg_dest_late = argv[3];
322 log_set_target(LOG_TARGET_SAFE);
323 log_parse_environment();
328 if (access("/dev/kdbus/control", F_OK) < 0)
331 r = cg_pid_get_owner_uid(0, NULL);
333 path = "/usr/share/dbus-1/services";
335 units = USER_DATA_UNIT_PATH;
336 } else if (r == -ENOENT) {
337 path = "/usr/share/dbus-1/system-services";
339 units = SYSTEM_DATA_UNIT_PATH;
341 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
345 r = parse_dbus_fragments(path, type);
347 /* FIXME: One day this should just be pulled in statically from basic.target */
348 q = link_busnames_target(units);
352 q = link_compatibility(units);
356 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;