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\n"
80 fprintf(f, "User=%s\n", user);
84 fprintf(f, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type);
86 if (streq(type, "system"))
87 fprintf(f, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_PATH "\n");
88 else if (streq(type, "session")) {
91 run = getenv("XDG_RUNTIME_DIR");
93 log_error("XDG_RUNTIME_DIR not set.");
97 fprintf(f, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_FMT ";" UNIX_USER_BUS_FMT "\n",
98 (unsigned long) getuid(), run);
104 log_error("Failed to write %s: %m", a);
111 b = strjoin(arg_dest_late, "/", name, ".busname", NULL);
117 log_error("Failed to create %s: %m", b);
122 "# Automatically generated by systemd-dbus1-generator\n\n"
125 "Description=DBUS1: %s\n\n"
136 log_error("Failed to write %s: %m", b);
140 lnk = strjoin(arg_dest_late, "/" SPECIAL_BUSNAMES_TARGET ".wants/", name, ".busname", NULL);
144 mkdir_parents_label(lnk, 0755);
145 if (symlink(b, lnk)) {
146 log_error("Failed to create symlink %s: %m", lnk);
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;
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 },
163 _cleanup_fclose_ FILE *f = NULL;
164 _cleanup_free_ char *p = NULL;
170 p = strjoin(path, "/", fname, NULL);
176 if (errno == -ENOENT)
179 log_error("Failed to read %s: %m", p);
183 r = config_parse(NULL, p, f, "D-BUS Service\0", config_item_table_lookup, table, true, false, NULL);
188 log_warning("Activation file %s lacks name setting, ignoring.", p);
192 if (!service_name_is_valid(name)) {
193 log_warning("Bus service name %s is not valid, ignoring.", name);
197 if (streq(name, "org.freedesktop.systemd1")) {
198 log_debug("Skipping %s, identified as systemd.", p);
203 if (!unit_name_is_valid(service, TEMPLATE_INVALID)) {
204 log_warning("Unit name %s is not valid, ignoring.", service);
207 if (!endswith(service, ".service")) {
208 log_warning("Bus names can only activate services, ignoring %s.", p);
212 if (streq(exec, "/bin/false") || !exec) {
213 log_warning("Neither service name nor binary path specified, ignoring %s.", p);
217 if (exec[0] != '/') {
218 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p);
223 return create_dbus_files(p, name, service, exec, user, type);
226 static int parse_dbus_fragments(const char *path, const char *type) {
227 _cleanup_closedir_ DIR *d = NULL;
236 if (errno == -ENOENT)
239 log_error("Failed to enumerate D-Bus activated services: %m");
244 FOREACH_DIRENT(de, d, goto fail) {
247 if (!endswith(de->d_name, ".service"))
250 q = add_dbus(path, de->d_name, type);
258 log_error("Failed to read D-Bus services directory: %m");
262 static int link_busnames_target(const char *units) {
265 f = strappenda(units, "/" SPECIAL_BUSNAMES_TARGET);
266 t = strappenda(arg_dest, "/" SPECIAL_BASIC_TARGET ".wants/" SPECIAL_BUSNAMES_TARGET);
268 mkdir_parents_label(t, 0755);
269 if (symlink(f, t) < 0) {
270 log_error("Failed to create symlink %s: %m", t);
277 static int link_compatibility(const char *units) {
280 f = strappenda(units, "/systemd-bus-proxyd.socket");
281 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SOCKET);
282 mkdir_parents_label(t, 0755);
283 if (symlink(f, t) < 0) {
284 log_error("Failed to create symlink %s: %m", t);
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) {
292 log_error("Failed to create symlink %s: %m", t);
296 t = strappenda(arg_dest, "/" SPECIAL_DBUS_SERVICE);
297 if (symlink("/dev/null", t) < 0) {
298 log_error("Failed to mask %s: %m", t);
305 int main(int argc, char *argv[]) {
306 const char *path, *type, *units;
309 if (argc > 1 && argc != 4) {
310 log_error("This program takes three or no arguments.");
316 arg_dest_late = argv[3];
319 log_set_target(LOG_TARGET_SAFE);
320 log_parse_environment();
325 if (access("/dev/kdbus/control", F_OK) < 0)
328 r = cg_pid_get_owner_uid(0, NULL);
330 path = "/usr/share/dbus-1/services";
332 units = USER_DATA_UNIT_PATH;
333 } else if (r == -ENOENT) {
334 path = "/usr/share/dbus-1/system-services";
336 units = SYSTEM_DATA_UNIT_PATH;
338 log_error("Failed to determine whether we are running as user or system instance: %s", strerror(-r));
342 r = parse_dbus_fragments(path, type);
344 /* FIXME: One day this should just be pulled in statically from basic.target */
345 q = link_busnames_target(units);
349 q = link_compatibility(units);
353 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;