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/>.
22 #include "bus-internal.h"
24 #include "cgroup-util.h"
25 #include "conf-parser.h"
26 #include "dirent-util.h"
31 #include "unit-name.h"
34 static const char *arg_dest_late
= "/tmp", *arg_dest
= "/tmp";
36 static int create_dbus_files(
44 _cleanup_free_
char *b
= NULL
, *s
= NULL
, *lnk
= NULL
;
45 _cleanup_fclose_
FILE *f
= NULL
;
50 assert(service
|| exec
);
53 _cleanup_free_
char *a
= NULL
;
55 s
= strjoin("dbus-", name
, ".service", NULL
);
59 a
= strjoin(arg_dest_late
, "/", s
, NULL
);
65 return log_error_errno(errno
, "Failed to create %s: %m", a
);
68 "# Automatically generated by systemd-dbus1-generator\n\n"
71 "Description=DBUS1: %s\n"
72 "Documentation=man:systemd-dbus1-generator(8)\n\n"
83 fprintf(f
, "User=%s\n", user
);
87 fprintf(f
, "Environment=DBUS_STARTER_BUS_TYPE=%s\n", type
);
89 if (streq(type
, "system"))
90 fprintf(f
, "Environment=DBUS_STARTER_ADDRESS=" DEFAULT_SYSTEM_BUS_ADDRESS
"\n");
91 else if (streq(type
, "session")) {
94 run
= getenv("XDG_RUNTIME_DIR");
96 log_error("XDG_RUNTIME_DIR not set.");
100 fprintf(f
, "Environment=DBUS_STARTER_ADDRESS="KERNEL_USER_BUS_ADDRESS_FMT
";" UNIX_USER_BUS_ADDRESS_FMT
"\n",
105 r
= fflush_and_check(f
);
107 return log_error_errno(r
, "Failed to write %s: %m", a
);
114 b
= strjoin(arg_dest_late
, "/", name
, ".busname", NULL
);
120 return log_error_errno(errno
, "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"
137 r
= fflush_and_check(f
);
139 return log_error_errno(r
, "Failed to write %s: %m", b
);
141 lnk
= strjoin(arg_dest_late
, "/" SPECIAL_BUSNAMES_TARGET
".wants/", name
, ".busname", NULL
);
145 mkdir_parents_label(lnk
, 0755);
147 return log_error_errno(errno
, "Failed to create symlink %s: %m", lnk
);
152 static int add_dbus(const char *path
, const char *fname
, const char *type
) {
153 _cleanup_free_
char *name
= NULL
, *exec
= NULL
, *user
= NULL
, *service
= NULL
;
155 const ConfigTableItem table
[] = {
156 { "D-BUS Service", "Name", config_parse_string
, 0, &name
},
157 { "D-BUS Service", "Exec", config_parse_string
, 0, &exec
},
158 { "D-BUS Service", "User", config_parse_string
, 0, &user
},
159 { "D-BUS Service", "SystemdService", config_parse_string
, 0, &service
},
169 p
= strjoina(path
, "/", fname
);
170 r
= config_parse(NULL
, p
, NULL
,
172 config_item_table_lookup
, table
,
173 true, false, true, NULL
);
178 log_warning("Activation file %s lacks name setting, ignoring.", p
);
182 if (!service_name_is_valid(name
)) {
183 log_warning("Bus service name %s is not valid, ignoring.", name
);
187 if (streq(name
, "org.freedesktop.systemd1")) {
188 log_debug("Skipping %s, identified as systemd.", p
);
193 if (!unit_name_is_valid(service
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
)) {
194 log_warning("Unit name %s is not valid, ignoring.", service
);
197 if (!endswith(service
, ".service")) {
198 log_warning("Bus names can only activate services, ignoring %s.", p
);
202 if (streq(exec
, "/bin/false") || !exec
) {
203 log_warning("Neither service name nor binary path specified, ignoring %s.", p
);
207 if (exec
[0] != '/') {
208 log_warning("Exec= in %s does not start with an absolute path, ignoring.", p
);
213 return create_dbus_files(p
, name
, service
, exec
, user
, type
);
216 static int parse_dbus_fragments(const char *path
, const char *type
) {
217 _cleanup_closedir_
DIR *d
= NULL
;
226 if (errno
== -ENOENT
)
229 log_error_errno(errno
, "Failed to enumerate D-Bus activated services: %m");
234 FOREACH_DIRENT(de
, d
, goto fail
) {
237 if (!endswith(de
->d_name
, ".service"))
240 q
= add_dbus(path
, de
->d_name
, type
);
248 log_error_errno(errno
, "Failed to read D-Bus services directory: %m");
252 static int link_busnames_target(const char *units
) {
255 f
= strjoina(units
, "/" SPECIAL_BUSNAMES_TARGET
);
256 t
= strjoina(arg_dest
, "/" SPECIAL_BASIC_TARGET
".wants/" SPECIAL_BUSNAMES_TARGET
);
258 mkdir_parents_label(t
, 0755);
259 if (symlink(f
, t
) < 0)
260 return log_error_errno(errno
, "Failed to create symlink %s: %m", t
);
265 static int link_compatibility(const char *units
) {
268 f
= strjoina(units
, "/systemd-bus-proxyd.socket");
269 t
= strjoina(arg_dest
, "/" SPECIAL_DBUS_SOCKET
);
270 mkdir_parents_label(t
, 0755);
271 if (symlink(f
, t
) < 0)
272 return log_error_errno(errno
, "Failed to create symlink %s: %m", t
);
274 f
= strjoina(units
, "/systemd-bus-proxyd.socket");
275 t
= strjoina(arg_dest
, "/" SPECIAL_SOCKETS_TARGET
".wants/systemd-bus-proxyd.socket");
276 mkdir_parents_label(t
, 0755);
277 if (symlink(f
, t
) < 0)
278 return log_error_errno(errno
, "Failed to create symlink %s: %m", t
);
280 t
= strjoina(arg_dest
, "/" SPECIAL_DBUS_SERVICE
);
281 if (symlink("/dev/null", t
) < 0)
282 return log_error_errno(errno
, "Failed to mask %s: %m", t
);
287 int main(int argc
, char *argv
[]) {
288 const char *path
, *type
, *units
;
291 if (argc
> 1 && argc
!= 4) {
292 log_error("This program takes three or no arguments.");
298 arg_dest_late
= argv
[3];
301 log_set_target(LOG_TARGET_SAFE
);
302 log_parse_environment();
307 if (!is_kdbus_available())
310 r
= cg_pid_get_owner_uid(0, NULL
);
312 path
= "/usr/share/dbus-1/services";
314 units
= USER_DATA_UNIT_PATH
;
315 } else if (r
== -ENXIO
) {
316 path
= "/usr/share/dbus-1/system-services";
318 units
= SYSTEM_DATA_UNIT_PATH
;
320 return log_error_errno(r
, "Failed to determine whether we are running as user or system instance: %m");
322 r
= parse_dbus_fragments(path
, type
);
324 /* FIXME: One day this should just be pulled in statically from basic.target */
325 q
= link_busnames_target(units
);
329 q
= link_compatibility(units
);
333 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;