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;
47 assert(service || exec);
50 _cleanup_free_ char *a = NULL;
52 s = strjoin("dbus-", name, ".service", NULL);
56 a = strjoin(arg_dest_late, "/", s, NULL);
62 log_error("Failed to create %s: %m", a);
67 "# Automatically generated by systemd-dbus1-generator\n\n"
70 "Description=DBUS1: %s\n"
71 "Documentation=man:systemd-dbus1-generator(8)\n\n"
82 fprintf(f, "User=%s\n", user);
86 fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
88 if (streq(type, "system"))
89 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
90 else if (streq(type, "session")) {
93 run = getenv("XDG_RUNTIME_DIR");
95 log_error("XDG_RUNTIME_DIR not set.");
99 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
104 r = fflush_and_check(f);
106 log_error("Failed to write %s: %s", a, strerror(-r));
116 b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
122 log_error("Failed to create %s: %m", b);
127 "# Automatically generated by systemd-dbus1-generator\n\n"
130 "Description=DBUS1: %s\n"
131 "Documentation=man:systemd-dbus1-generator(8)\n\n"
141 r = fflush_and_check(f);
143 log_error("Failed to write %s: %s", b, strerror(-r));
147 lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
151 mkdir_parents_label(lnk, 0755);
152 if (symlink(b, lnk)) {
153 log_error("Failed to create symlink %s: %m", lnk);
160 static int add_dbus(const char *path, const char *fname, const char *type) {
161 _cleanup_free_ char *name = NULL, *exec = NULL, *user = NULL, *service = NULL;
163 const ConfigTableItem table[] = {
164 { "D-BUS Service", "Name", config_parse_string, 0, &name },
165 { "D-BUS Service", "Exec", config_parse_string, 0, &exec },
166 { "D-BUS Service", "User", config_parse_string, 0, &user },
167 { "D-BUS Service", "SystemdService", config_parse_string, 0, &service },
176 p = strappenda(path, "/", fname);
177 r = config_parse(NULL, p, NULL,
179 config_item_table_lookup, table,
180 true, false, true, NULL);
185 log_warning("Activation file %s lacks name setting, ignoring.", p);
189 if (!service_name_is_valid(name)) {
190 log_warning("Bus service name %s is not valid, ignoring.", name);
194 if (streq(name, "org.freedesktop.systemd1")) {
195 log_debug("Skipping %s, identified as systemd.", p);
200 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
201 log_warning("Unit name %s is not valid, ignoring.", service);
204 if (!endswith(service, ".service")) {
205 log_warning("Bus names can only activate services, ignoring %s.", p);
209 if (streq(exec, "/bin/false") || !exec) {
210 log_warning("Neither service name nor binary path specified, ignoring %s.", p);
214 if (exec[0] != '/') {
215 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
220 return create_dbus_files(p, name, service, exec, user, type);
223 static int parse_dbus_fragments(const char *path, const char *type) {
224 _cleanup_closedir_ DIR *d = NULL;
233 if (errno == -ENOENT)
236 log_error("Failed to enumerate D-Bus activated services: %m");
241 FOREACH_DIRENT(de, d, goto fail) {
244 if (!endswith(de->d_name, ".service"))
247 q = add_dbus(path, de->d_name, type);
255 log_error("Failed to read D-Bus services directory: %m");
259 static int link_busnames_target(const char *units) {
262 f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
263 t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
265 mkdir_parents_label(t, 0755);
266 if (symlink(f, t) < 0) {
267 log_error("Failed to create symlink %s: %m", t);
274 static int link_compatibility(const char *units) {
277 f = strappenda(units, "/systemd-bus-proxyd.socket");
278 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
279 mkdir_parents_label(t, 0755);
280 if (symlink(f, t) < 0) {
281 log_error("Failed to create symlink %s: %m", t);
285 f = strappenda(units, "/systemd-bus-proxyd.socket");
286 t = strappenda(arg_dest, "/" SPECIAL_SOCKETS_TARGET ".wants/systemd-bus-proxyd.socket");
287 mkdir_parents_label(t, 0755);
288 if (symlink(f, t) < 0) {
289 log_error("Failed to create symlink %s: %m", t);
293 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
294 if (symlink("/dev/null", t) < 0) {
295 log_error("Failed to mask %s: %m", t);
302 int main(int argc, char *argv[]) {
303 const char *path, *type, *units;
306 if (argc > 1 && argc != 4) {
307 log_error("This program takes three or no arguments.");
313 arg_dest_late = argv[3];
316 log_set_target(LOG_TARGET_SAFE);
317 log_parse_environment();
322 if (access("/dev/kdbus/control", F_OK) < 0)
325 r = cg_pid_get_owner_uid(0, NULL);
327 path = "/usr/share/dbus-1/services";
329 units = USER_DATA_UNIT_PATH;
330 } else if (r == -ENOENT) {
331 path = "/usr/share/dbus-1/system-services";
333 units = SYSTEM_DATA_UNIT_PATH;
335 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
339 r = parse_dbus_fragments(path, type);
341 /* FIXME: One day this should just be pulled in statically from basic.target */
342 q = link_busnames_target(units);
346 q = link_compatibility(units);
350 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;