1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 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 <sys/epoll.h>
23 #include <sys/timerfd.h>
32 #include "dbus-unit.h"
34 #include "dbus-manager.h"
35 #include "dbus-execute.h"
36 #include "dbus-kill.h"
37 #include "dbus-cgroup.h"
41 #include "bus-error.h"
42 #include "bus-common-errors.h"
44 #include "bus-internal.h"
45 #include "selinux-access.h"
47 #define CONNECTIONS_MAX 512
49 static void destroy_bus(Manager
*m
, sd_bus
**bus
);
51 int bus_send_queued_message(Manager
*m
) {
56 if (!m
->queued_message
)
59 assert(m
->queued_message_bus
);
61 /* If we cannot get rid of this message we won't dispatch any
62 * D-Bus messages, so that we won't end up wanting to queue
65 r
= sd_bus_send(m
->queued_message_bus
, m
->queued_message
, NULL
);
67 log_warning_errno(r
, "Failed to send queued message: %m");
69 m
->queued_message
= sd_bus_message_unref(m
->queued_message
);
70 m
->queued_message_bus
= sd_bus_unref(m
->queued_message_bus
);
75 static int signal_agent_released(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
76 Manager
*m
= userdata
;
84 r
= sd_bus_message_read(message
, "s", &cgroup
);
86 bus_log_parse_error(r
);
90 manager_notify_cgroup_empty(m
, cgroup
);
92 if (m
->running_as
== SYSTEMD_SYSTEM
&& m
->system_bus
) {
93 /* If we are running as system manager, forward the
94 * message to the system bus */
96 r
= sd_bus_send(m
->system_bus
, message
, NULL
);
98 log_warning_errno(r
, "Failed to forward Released message: %m");
104 static int signal_disconnected(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
105 Manager
*m
= userdata
;
111 if (bus
== m
->api_bus
)
112 destroy_bus(m
, &m
->api_bus
);
113 if (bus
== m
->system_bus
)
114 destroy_bus(m
, &m
->system_bus
);
115 if (set_remove(m
->private_buses
, bus
)) {
116 log_debug("Got disconnect on private connection.");
117 destroy_bus(m
, &bus
);
123 static int signal_name_owner_changed(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
124 const char *name
, *old_owner
, *new_owner
;
125 Manager
*m
= userdata
;
132 r
= sd_bus_message_read(message
, "sss", &name
, &old_owner
, &new_owner
);
134 bus_log_parse_error(r
);
138 manager_dispatch_bus_name_owner_changed(
140 isempty(old_owner
) ? NULL
: old_owner
,
141 isempty(new_owner
) ? NULL
: new_owner
);
146 static int signal_activation_request(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*ret_error
) {
147 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
148 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
149 Manager
*m
= userdata
;
158 r
= sd_bus_message_read(message
, "s", &name
);
160 bus_log_parse_error(r
);
164 if (manager_unit_inactive_or_pending(m
, SPECIAL_DBUS_SERVICE
) ||
165 manager_unit_inactive_or_pending(m
, SPECIAL_DBUS_SOCKET
)) {
166 r
= sd_bus_error_setf(&error
, BUS_ERROR_SHUTTING_DOWN
, "Refusing activation, D-Bus is shutting down.");
170 r
= manager_load_unit(m
, name
, NULL
, &error
, &u
);
174 if (u
->refuse_manual_start
) {
175 r
= sd_bus_error_setf(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, %s may be requested by dependency only.", u
->id
);
179 r
= manager_add_job(m
, JOB_START
, u
, JOB_REPLACE
, true, &error
, NULL
);
183 /* Successfully queued, that's it for us */
187 if (!sd_bus_error_is_set(&error
))
188 sd_bus_error_set_errno(&error
, r
);
190 log_debug("D-Bus activation failed for %s: %s", name
, bus_error_message(&error
, r
));
192 r
= sd_bus_message_new_signal(bus
, &reply
, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure");
194 bus_log_create_error(r
);
198 r
= sd_bus_message_append(reply
, "sss", name
, error
.name
, error
.message
);
200 bus_log_create_error(r
);
204 r
= sd_bus_send_to(bus
, reply
, "org.freedesktop.DBus", NULL
);
206 return log_error_errno(r
, "Failed to respond with to bus activation request: %m");
212 static int mac_selinux_filter(sd_bus
*bus
, sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
213 Manager
*m
= userdata
;
214 const char *verb
, *path
;
222 /* Our own method calls are all protected individually with
223 * selinux checks, but the built-in interfaces need to be
226 if (sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Properties", "Set"))
228 else if (sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", NULL
) ||
229 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Properties", NULL
) ||
230 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.ObjectManager", NULL
) ||
231 sd_bus_message_is_method_call(message
, "org.freedesktop.DBus.Peer", NULL
))
236 path
= sd_bus_message_get_path(message
);
238 if (object_path_startswith("/org/freedesktop/systemd1", path
)) {
240 r
= mac_selinux_access_check(message
, verb
, error
);
247 if (streq_ptr(path
, "/org/freedesktop/systemd1/unit/self")) {
248 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
251 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
255 r
= sd_bus_creds_get_pid(creds
, &pid
);
259 u
= manager_get_unit_by_pid(m
, pid
);
261 r
= manager_get_job_from_dbus_path(m
, path
, &j
);
265 manager_load_unit_from_dbus_path(m
, path
, NULL
, &u
);
271 r
= mac_selinux_unit_access_check(u
, message
, verb
, error
);
279 static int bus_job_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
280 Manager
*m
= userdata
;
290 r
= manager_get_job_from_dbus_path(m
, path
, &j
);
298 static int find_unit(Manager
*m
, sd_bus
*bus
, const char *path
, Unit
**unit
, sd_bus_error
*error
) {
306 if (streq_ptr(path
, "/org/freedesktop/systemd1/unit/self")) {
307 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
308 sd_bus_message
*message
;
311 message
= sd_bus_get_current_message(bus
);
315 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
319 r
= sd_bus_creds_get_pid(creds
, &pid
);
323 u
= manager_get_unit_by_pid(m
, pid
);
325 r
= manager_load_unit_from_dbus_path(m
, path
, error
, &u
);
337 static int bus_unit_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
338 Manager
*m
= userdata
;
346 return find_unit(m
, bus
, path
, (Unit
**) found
, error
);
349 static int bus_unit_interface_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
350 Manager
*m
= userdata
;
360 r
= find_unit(m
, bus
, path
, &u
, error
);
364 if (!streq_ptr(interface
, UNIT_VTABLE(u
)->bus_interface
))
371 static int bus_unit_cgroup_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
372 Manager
*m
= userdata
;
382 r
= find_unit(m
, bus
, path
, &u
, error
);
386 if (!streq_ptr(interface
, UNIT_VTABLE(u
)->bus_interface
))
389 if (!unit_get_cgroup_context(u
))
396 static int bus_cgroup_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
397 Manager
*m
= userdata
;
408 r
= find_unit(m
, bus
, path
, &u
, error
);
412 if (!streq_ptr(interface
, UNIT_VTABLE(u
)->bus_interface
))
415 c
= unit_get_cgroup_context(u
);
423 static int bus_exec_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
424 Manager
*m
= userdata
;
435 r
= find_unit(m
, bus
, path
, &u
, error
);
439 if (!streq_ptr(interface
, UNIT_VTABLE(u
)->bus_interface
))
442 c
= unit_get_exec_context(u
);
450 static int bus_kill_context_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
451 Manager
*m
= userdata
;
462 r
= find_unit(m
, bus
, path
, &u
, error
);
466 if (!streq_ptr(interface
, UNIT_VTABLE(u
)->bus_interface
))
469 c
= unit_get_kill_context(u
);
477 static int bus_job_enumerate(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
478 _cleanup_free_
char **l
= NULL
;
479 Manager
*m
= userdata
;
484 l
= new0(char*, hashmap_size(m
->jobs
)+1);
488 HASHMAP_FOREACH(j
, m
->jobs
, i
) {
489 l
[k
] = job_dbus_path(j
);
496 assert(hashmap_size(m
->jobs
) == k
);
504 static int bus_unit_enumerate(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
505 _cleanup_free_
char **l
= NULL
;
506 Manager
*m
= userdata
;
511 l
= new0(char*, hashmap_size(m
->units
)+1);
515 HASHMAP_FOREACH(u
, m
->units
, i
) {
516 l
[k
] = unit_dbus_path(u
);
529 static int bus_setup_api_vtables(Manager
*m
, sd_bus
*bus
) {
537 r
= sd_bus_add_filter(bus
, NULL
, mac_selinux_filter
, m
);
539 return log_error_errno(r
, "Failed to add SELinux access filter: %m");
542 r
= sd_bus_add_object_vtable(bus
, NULL
, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable
, m
);
544 return log_error_errno(r
, "Failed to register Manager vtable: %m");
546 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable
, bus_job_find
, m
);
548 return log_error_errno(r
, "Failed to register Job vtable: %m");
550 r
= sd_bus_add_node_enumerator(bus
, NULL
, "/org/freedesktop/systemd1/job", bus_job_enumerate
, m
);
552 return log_error_errno(r
, "Failed to add job enumerator: %m");
554 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable
, bus_unit_find
, m
);
556 return log_error_errno(r
, "Failed to register Unit vtable: %m");
558 r
= sd_bus_add_node_enumerator(bus
, NULL
, "/org/freedesktop/systemd1/unit", bus_unit_enumerate
, m
);
560 return log_error_errno(r
, "Failed to add job enumerator: %m");
562 for (t
= 0; t
< _UNIT_TYPE_MAX
; t
++) {
563 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", unit_vtable
[t
]->bus_interface
, unit_vtable
[t
]->bus_vtable
, bus_unit_interface_find
, m
);
565 return log_error_errno(r
, "Failed to register type specific vtable for %s: %m", unit_vtable
[t
]->bus_interface
);
567 if (unit_vtable
[t
]->cgroup_context_offset
> 0) {
568 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", unit_vtable
[t
]->bus_interface
, bus_unit_cgroup_vtable
, bus_unit_cgroup_find
, m
);
570 return log_error_errno(r
, "Failed to register control group unit vtable for %s: %m", unit_vtable
[t
]->bus_interface
);
572 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", unit_vtable
[t
]->bus_interface
, bus_cgroup_vtable
, bus_cgroup_context_find
, m
);
574 return log_error_errno(r
, "Failed to register control group vtable for %s: %m", unit_vtable
[t
]->bus_interface
);
577 if (unit_vtable
[t
]->exec_context_offset
> 0) {
578 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", unit_vtable
[t
]->bus_interface
, bus_exec_vtable
, bus_exec_context_find
, m
);
580 return log_error_errno(r
, "Failed to register execute vtable for %s: %m", unit_vtable
[t
]->bus_interface
);
583 if (unit_vtable
[t
]->kill_context_offset
> 0) {
584 r
= sd_bus_add_fallback_vtable(bus
, NULL
, "/org/freedesktop/systemd1/unit", unit_vtable
[t
]->bus_interface
, bus_kill_vtable
, bus_kill_context_find
, m
);
586 return log_error_errno(r
, "Failed to register kill vtable for %s: %m", unit_vtable
[t
]->bus_interface
);
593 static int bus_setup_disconnected_match(Manager
*m
, sd_bus
*bus
) {
599 r
= sd_bus_add_match(
602 "sender='org.freedesktop.DBus.Local',"
604 "path='/org/freedesktop/DBus/Local',"
605 "interface='org.freedesktop.DBus.Local',"
606 "member='Disconnected'",
607 signal_disconnected
, m
);
610 return log_error_errno(r
, "Failed to register match for Disconnected message: %m");
615 static int bus_on_connection(sd_event_source
*s
, int fd
, uint32_t revents
, void *userdata
) {
616 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
617 _cleanup_close_
int nfd
= -1;
618 Manager
*m
= userdata
;
625 nfd
= accept4(fd
, NULL
, NULL
, SOCK_NONBLOCK
|SOCK_CLOEXEC
);
627 log_warning_errno(errno
, "Failed to accept private connection, ignoring: %m");
631 if (set_size(m
->private_buses
) >= CONNECTIONS_MAX
) {
632 log_warning("Too many concurrent connections, refusing");
636 r
= set_ensure_allocated(&m
->private_buses
, NULL
);
642 r
= sd_bus_new(&bus
);
644 log_warning_errno(r
, "Failed to allocate new private connection bus: %m");
648 r
= sd_bus_set_fd(bus
, nfd
, nfd
);
650 log_warning_errno(r
, "Failed to set fd on new connection bus: %m");
656 r
= bus_check_peercred(bus
);
658 log_warning_errno(r
, "Incoming private connection from unprivileged client, refusing: %m");
662 assert_se(sd_id128_randomize(&id
) >= 0);
664 r
= sd_bus_set_server(bus
, 1, id
);
666 log_warning_errno(r
, "Failed to enable server support for new connection bus: %m");
670 r
= sd_bus_start(bus
);
672 log_warning_errno(r
, "Failed to start new connection bus: %m");
676 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
678 log_warning_errno(r
, "Failed to attach new connection bus to event loop: %m");
682 if (m
->running_as
== SYSTEMD_SYSTEM
) {
683 /* When we run as system instance we get the Released
684 * signal via a direct connection */
686 r
= sd_bus_add_match(
690 "interface='org.freedesktop.systemd1.Agent',"
692 "path='/org/freedesktop/systemd1/agent'",
693 signal_agent_released
, m
);
696 log_warning_errno(r
, "Failed to register Released match on new connection bus: %m");
701 r
= bus_setup_disconnected_match(m
, bus
);
705 r
= bus_setup_api_vtables(m
, bus
);
707 log_warning_errno(r
, "Failed to set up API vtables on new connection bus: %m");
711 r
= set_put(m
->private_buses
, bus
);
713 log_warning_errno(r
, "Failed to add new conenction bus to set: %m");
719 log_debug("Accepted new private connection.");
724 static int bus_list_names(Manager
*m
, sd_bus
*bus
) {
725 _cleanup_strv_free_
char **names
= NULL
;
732 r
= sd_bus_list_names(bus
, &names
, NULL
);
734 return log_error_errno(r
, "Failed to get initial list of names: %m");
736 /* This is a bit hacky, we say the owner of the name is the
737 * name itself, because we don't want the extra traffic to
738 * figure out the real owner. */
739 STRV_FOREACH(i
, names
)
740 manager_dispatch_bus_name_owner_changed(m
, *i
, NULL
, *i
);
745 static int bus_setup_api(Manager
*m
, sd_bus
*bus
) {
751 /* Let's make sure we have enough credential bits so that we can make security and selinux decisions */
752 r
= sd_bus_negotiate_creds(bus
, 1,
753 SD_BUS_CREDS_PID
|SD_BUS_CREDS_UID
|
754 SD_BUS_CREDS_EUID
|SD_BUS_CREDS_EFFECTIVE_CAPS
|
755 SD_BUS_CREDS_SELINUX_CONTEXT
);
757 log_warning_errno(r
, "Failed to enable credential passing, ignoring: %m");
759 r
= bus_setup_api_vtables(m
, bus
);
763 r
= sd_bus_add_match(
767 "sender='org.freedesktop.DBus',"
768 "path='/org/freedesktop/DBus',"
769 "interface='org.freedesktop.DBus',"
770 "member='NameOwnerChanged'",
771 signal_name_owner_changed
, m
);
773 log_warning_errno(r
, "Failed to subscribe to NameOwnerChanged signal: %m");
775 r
= sd_bus_add_match(
779 "sender='org.freedesktop.DBus',"
780 "path='/org/freedesktop/DBus',"
781 "interface='org.freedesktop.systemd1.Activator',"
782 "member='ActivationRequest'",
783 signal_activation_request
, m
);
785 log_warning_errno(r
, "Failed to subscribe to activation signal: %m");
787 /* Allow replacing of our name, to ease implementation of
788 * reexecution, where we keep the old connection open until
789 * after the new connection is set up and the name installed
790 * to allow clients to synchronously wait for reexecution to
792 r
= sd_bus_request_name(bus
,"org.freedesktop.systemd1", SD_BUS_NAME_REPLACE_EXISTING
|SD_BUS_NAME_ALLOW_REPLACEMENT
);
794 return log_error_errno(r
, "Failed to register name: %m");
796 bus_list_names(m
, bus
);
798 log_debug("Successfully connected to API bus.");
802 static int bus_init_api(Manager
*m
) {
803 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
809 /* The API and system bus is the same if we are running in system mode */
810 if (m
->running_as
== SYSTEMD_SYSTEM
&& m
->system_bus
)
811 bus
= sd_bus_ref(m
->system_bus
);
813 if (m
->running_as
== SYSTEMD_SYSTEM
)
814 r
= sd_bus_open_system(&bus
);
816 r
= sd_bus_open_user(&bus
);
819 log_debug("Failed to connect to API bus, retrying later...");
823 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
825 log_error_errno(r
, "Failed to attach API bus to event loop: %m");
829 r
= bus_setup_disconnected_match(m
, bus
);
834 r
= bus_setup_api(m
, bus
);
836 log_error_errno(r
, "Failed to set up API bus: %m");
846 static int bus_setup_system(Manager
*m
, sd_bus
*bus
) {
852 if (m
->running_as
== SYSTEMD_SYSTEM
)
855 /* If we are a user instance we get the Released message via
857 r
= sd_bus_add_match(
861 "interface='org.freedesktop.systemd1.Agent',"
863 "path='/org/freedesktop/systemd1/agent'",
864 signal_agent_released
, m
);
867 log_warning_errno(r
, "Failed to register Released match on system bus: %m");
869 log_debug("Successfully connected to system bus.");
873 static int bus_init_system(Manager
*m
) {
874 _cleanup_bus_unref_ sd_bus
*bus
= NULL
;
880 /* The API and system bus is the same if we are running in system mode */
881 if (m
->running_as
== SYSTEMD_SYSTEM
&& m
->api_bus
) {
882 m
->system_bus
= sd_bus_ref(m
->api_bus
);
886 r
= sd_bus_open_system(&bus
);
888 log_debug("Failed to connect to system bus, retrying later...");
892 r
= bus_setup_disconnected_match(m
, bus
);
896 r
= sd_bus_attach_event(bus
, m
->event
, SD_EVENT_PRIORITY_NORMAL
);
898 log_error_errno(r
, "Failed to attach system bus to event loop: %m");
902 r
= bus_setup_system(m
, bus
);
904 log_error_errno(r
, "Failed to set up system bus: %m");
914 static int bus_init_private(Manager
*m
) {
915 _cleanup_close_
int fd
= -1;
916 union sockaddr_union sa
= {
917 .un
.sun_family
= AF_UNIX
925 if (m
->private_listen_fd
>= 0)
928 /* We don't need the private socket if we have kdbus */
929 if (m
->kdbus_fd
>= 0)
932 if (m
->running_as
== SYSTEMD_SYSTEM
) {
934 /* We want the private bus only when running as init */
938 strcpy(sa
.un
.sun_path
, "/run/systemd/private");
939 salen
= offsetof(union sockaddr_union
, un
.sun_path
) + strlen("/run/systemd/private");
941 size_t left
= sizeof(sa
.un
.sun_path
);
942 char *p
= sa
.un
.sun_path
;
945 e
= secure_getenv("XDG_RUNTIME_DIR");
947 log_error("Failed to determine XDG_RUNTIME_DIR");
951 left
= strpcpy(&p
, left
, e
);
952 left
= strpcpy(&p
, left
, "/systemd/private");
954 salen
= sizeof(sa
.un
) - left
;
957 (void) mkdir_parents_label(sa
.un
.sun_path
, 0755);
958 (void) unlink(sa
.un
.sun_path
);
960 fd
= socket(AF_UNIX
, SOCK_STREAM
|SOCK_CLOEXEC
|SOCK_NONBLOCK
, 0);
962 return log_error_errno(errno
, "Failed to allocate private socket: %m");
964 r
= bind(fd
, &sa
.sa
, salen
);
966 return log_error_errno(errno
, "Failed to bind private socket: %m");
968 r
= listen(fd
, SOMAXCONN
);
970 return log_error_errno(errno
, "Failed to make private socket listening: %m");
972 r
= sd_event_add_io(m
->event
, &s
, fd
, EPOLLIN
, bus_on_connection
, m
);
974 return log_error_errno(r
, "Failed to allocate event source: %m");
976 m
->private_listen_fd
= fd
;
977 m
->private_listen_event_source
= s
;
980 log_debug("Successfully created private D-Bus server.");
985 int bus_init(Manager
*m
, bool try_bus_connect
) {
988 if (try_bus_connect
) {
989 r
= bus_init_system(m
);
998 r
= bus_init_private(m
);
1005 static void destroy_bus(Manager
*m
, sd_bus
**bus
) {
1015 /* Get rid of tracked clients on this bus */
1016 if (m
->subscribed
&& sd_bus_track_get_bus(m
->subscribed
) == *bus
)
1017 m
->subscribed
= sd_bus_track_unref(m
->subscribed
);
1019 HASHMAP_FOREACH(j
, m
->jobs
, i
)
1020 if (j
->clients
&& sd_bus_track_get_bus(j
->clients
) == *bus
)
1021 j
->clients
= sd_bus_track_unref(j
->clients
);
1023 /* Get rid of queued message on this bus */
1024 if (m
->queued_message_bus
== *bus
) {
1025 m
->queued_message_bus
= sd_bus_unref(m
->queued_message_bus
);
1027 if (m
->queued_message
)
1028 m
->queued_message
= sd_bus_message_unref(m
->queued_message
);
1031 /* Possibly flush unwritten data, but only if we are
1032 * unprivileged, since we don't want to sync here */
1033 if (m
->running_as
!= SYSTEMD_SYSTEM
)
1036 /* And destroy the object */
1038 *bus
= sd_bus_unref(*bus
);
1041 void bus_done(Manager
*m
) {
1047 destroy_bus(m
, &m
->api_bus
);
1049 destroy_bus(m
, &m
->system_bus
);
1050 while ((b
= set_steal_first(m
->private_buses
)))
1053 set_free(m
->private_buses
);
1054 m
->private_buses
= NULL
;
1056 m
->subscribed
= sd_bus_track_unref(m
->subscribed
);
1057 strv_free(m
->deserialized_subscribed
);
1058 m
->deserialized_subscribed
= NULL
;
1060 if (m
->private_listen_event_source
)
1061 m
->private_listen_event_source
= sd_event_source_unref(m
->private_listen_event_source
);
1063 m
->private_listen_fd
= safe_close(m
->private_listen_fd
);
1065 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
1068 int bus_fdset_add_all(Manager
*m
, FDSet
*fds
) {
1076 /* When we are about to reexecute we add all D-Bus fds to the
1077 * set to pass over to the newly executed systemd. They won't
1078 * be used there however, except thatt they are closed at the
1079 * very end of deserialization, those making it possible for
1080 * clients to synchronously wait for systemd to reexec by
1081 * simply waiting for disconnection */
1084 fd
= sd_bus_get_fd(m
->api_bus
);
1086 fd
= fdset_put_dup(fds
, fd
);
1092 SET_FOREACH(b
, m
->private_buses
, i
) {
1093 fd
= sd_bus_get_fd(b
);
1095 fd
= fdset_put_dup(fds
, fd
);
1101 /* We don't offer any APIs on the system bus (well, unless it
1102 * is the same as the API bus) hence we don't bother with it
1108 int bus_foreach_bus(
1110 sd_bus_track
*subscribed2
,
1111 int (*send_message
)(sd_bus
*bus
, void *userdata
),
1118 /* Send to all direct busses, unconditionally */
1119 SET_FOREACH(b
, m
->private_buses
, i
) {
1120 r
= send_message(b
, userdata
);
1125 /* Send to API bus, but only if somebody is subscribed */
1126 if (sd_bus_track_count(m
->subscribed
) > 0 ||
1127 sd_bus_track_count(subscribed2
) > 0) {
1128 r
= send_message(m
->api_bus
, userdata
);
1136 void bus_track_serialize(sd_bus_track
*t
, FILE *f
) {
1141 for (n
= sd_bus_track_first(t
); n
; n
= sd_bus_track_next(t
))
1142 fprintf(f
, "subscribed=%s\n", n
);
1145 int bus_track_deserialize_item(char ***l
, const char *line
) {
1152 e
= startswith(line
, "subscribed=");
1156 r
= strv_extend(l
, e
);
1163 int bus_track_coldplug(Manager
*m
, sd_bus_track
**t
, char ***l
) {
1170 if (!strv_isempty(*l
) && m
->api_bus
) {
1174 r
= sd_bus_track_new(m
->api_bus
, t
, NULL
, NULL
);
1180 STRV_FOREACH(i
, *l
) {
1183 k
= sd_bus_track_add_name(*t
, *i
);
1195 int bus_verify_manage_unit_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1196 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.manage-units", false, &m
->polkit_registry
, error
);
1199 /* Same as bus_verify_manage_unit_async(), but checks for CAP_KILL instead of CAP_SYS_ADMIN */
1200 int bus_verify_manage_unit_async_for_kill(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1201 return bus_verify_polkit_async(call
, CAP_KILL
, "org.freedesktop.systemd1.manage-units", false, &m
->polkit_registry
, error
);
1204 int bus_verify_manage_unit_files_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1205 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.manage-unit-files", false, &m
->polkit_registry
, error
);
1208 int bus_verify_reload_daemon_async(Manager
*m
, sd_bus_message
*call
, sd_bus_error
*error
) {
1209 return bus_verify_polkit_async(call
, CAP_SYS_ADMIN
, "org.freedesktop.systemd1.reload-daemon", false, &m
->polkit_registry
, error
);