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-errors.h"
44 #include "dbus-client-track.h"
45 #include "bus-internal.h"
46 #include "selinux-access.h"
48 #define CONNECTIONS_MAX 512
50 static void destroy_bus(Manager *m, sd_bus **bus);
52 int bus_send_queued_message(Manager *m) {
57 if (!m->queued_message)
60 assert(m->queued_message_bus);
62 /* If we cannot get rid of this message we won't dispatch any
63 * D-Bus messages, so that we won't end up wanting to queue
66 r = sd_bus_send(m->queued_message_bus, m->queued_message, NULL);
68 log_warning("Failed to send queued message: %s", strerror(-r));
70 m->queued_message = sd_bus_message_unref(m->queued_message);
71 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
76 static int signal_agent_released(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
77 Manager *m = userdata;
85 r = sd_bus_message_read(message, "s", &cgroup);
87 bus_log_parse_error(r);
91 manager_notify_cgroup_empty(m, cgroup);
93 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus) {
94 /* If we are running as system manager, forward the
95 * message to the system bus */
97 r = sd_bus_send(m->system_bus, message, NULL);
99 log_warning("Failed to forward Released message: %s", strerror(-r));
105 static int signal_disconnected(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
106 Manager *m = userdata;
112 if (bus == m->api_bus)
113 destroy_bus(m, &m->api_bus);
114 if (bus == m->system_bus)
115 destroy_bus(m, &m->system_bus);
116 if (set_remove(m->private_buses, bus)) {
117 log_debug("Got disconnect on private connection.");
118 destroy_bus(m, &bus);
124 static int signal_name_owner_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
125 const char *name, *old_owner, *new_owner;
126 Manager *m = userdata;
133 r = sd_bus_message_read(message, "sss", &name, &old_owner, &new_owner);
135 bus_log_parse_error(r);
139 manager_dispatch_bus_name_owner_changed(
141 isempty(old_owner) ? NULL : old_owner,
142 isempty(new_owner) ? NULL : new_owner);
147 static int signal_activation_request(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *ret_error) {
148 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
149 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
150 Manager *m = userdata;
159 r = sd_bus_message_read(message, "s", &name);
161 bus_log_parse_error(r);
165 if (manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SERVICE) ||
166 manager_unit_inactive_or_pending(m, SPECIAL_DBUS_SOCKET)) {
167 r = sd_bus_error_setf(&error, BUS_ERROR_SHUTTING_DOWN, "Refusing activation, D-Bus is shutting down.");
171 r = manager_load_unit(m, name, NULL, &error, &u);
175 if (u->refuse_manual_start) {
176 r = sd_bus_error_setf(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, %u may be requested by dependency only.", u->id);
180 r = manager_add_job(m, JOB_START, u, JOB_REPLACE, true, &error, NULL);
184 /* Successfully queued, that's it for us */
188 if (!sd_bus_error_is_set(&error))
189 sd_bus_error_set_errno(&error, r);
191 log_debug("D-Bus activation failed for %s: %s", name, bus_error_message(&error, r));
193 r = sd_bus_message_new_signal(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Activator", "ActivationFailure", &reply);
195 bus_log_create_error(r);
199 r = sd_bus_message_append(reply, "sss", name, error.name, error.message);
201 bus_log_create_error(r);
205 r = sd_bus_send_to(bus, reply, "org.freedesktop.DBus", NULL);
207 log_error("Failed to respond with to bus activation request: %s", strerror(-r));
214 static int selinux_filter(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
215 Manager *m = userdata;
216 const char *verb, *path;
224 /* Our own method calls are all protected individually with
225 * selinux checks, but the built-in interfaces need to be
228 if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", "Set"))
230 else if (sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", NULL) ||
231 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Properties", NULL) ||
232 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.ObjectManager", NULL) ||
233 sd_bus_message_is_method_call(message, "org.freedesktop.DBus.Peer", NULL))
238 path = sd_bus_message_get_path(message);
240 if (object_path_startswith("/org/freedesktop/systemd1", path)) {
242 r = selinux_access_check(bus, message, verb, error);
249 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
252 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
256 u = manager_get_unit_by_pid(m, pid);
258 r = manager_get_job_from_dbus_path(m, path, &j);
262 manager_load_unit_from_dbus_path(m, path, NULL, &u);
268 r = selinux_unit_access_check(u, bus, message, verb, error);
275 static int bus_job_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
276 Manager *m = userdata;
286 r = manager_get_job_from_dbus_path(m, path, &j);
294 static int find_unit(Manager *m, sd_bus *bus, const char *path, Unit **unit, sd_bus_error *error) {
302 if (streq_ptr(path, "/org/freedesktop/systemd1/unit/self")) {
303 sd_bus_message *message;
306 message = sd_bus_get_current(bus);
310 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
314 u = manager_get_unit_by_pid(m, pid);
316 r = manager_load_unit_from_dbus_path(m, path, error, &u);
328 static int bus_unit_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
329 Manager *m = userdata;
337 return find_unit(m, bus, path, (Unit**) found, error);
340 static int bus_unit_interface_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
341 Manager *m = userdata;
351 r = find_unit(m, bus, path, &u, error);
355 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
362 static int bus_unit_cgroup_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
363 Manager *m = userdata;
373 r = find_unit(m, bus, path, &u, error);
377 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
380 if (!unit_get_cgroup_context(u))
387 static int bus_cgroup_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
388 Manager *m = userdata;
399 r = find_unit(m, bus, path, &u, error);
403 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
406 c = unit_get_cgroup_context(u);
414 static int bus_exec_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
415 Manager *m = userdata;
426 r = find_unit(m, bus, path, &u, error);
430 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
433 c = unit_get_exec_context(u);
441 static int bus_kill_context_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
442 Manager *m = userdata;
453 r = find_unit(m, bus, path, &u, error);
457 if (!streq_ptr(interface, UNIT_VTABLE(u)->bus_interface))
460 c = unit_get_kill_context(u);
468 static int bus_job_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
469 _cleanup_free_ char **l = NULL;
470 Manager *m = userdata;
475 l = new0(char*, hashmap_size(m->jobs)+1);
479 HASHMAP_FOREACH(j, m->jobs, i) {
480 l[k] = job_dbus_path(j);
487 assert(hashmap_size(m->jobs) == k);
495 static int bus_unit_enumerate(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
496 _cleanup_free_ char **l = NULL;
497 Manager *m = userdata;
502 l = new0(char*, hashmap_size(m->units)+1);
506 HASHMAP_FOREACH(u, m->units, i) {
507 l[k] = unit_dbus_path(u);
520 static int bus_setup_api_vtables(Manager *m, sd_bus *bus) {
527 r = sd_bus_add_filter(bus, selinux_filter, m);
529 log_error("Failed to add SELinux access filter: %s", strerror(-r));
533 r = sd_bus_add_object_vtable(bus, "/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", bus_manager_vtable, m);
535 log_error("Failed to register Manager vtable: %s", strerror(-r));
539 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/job", "org.freedesktop.systemd1.Job", bus_job_vtable, bus_job_find, m);
541 log_error("Failed to register Job vtable: %s", strerror(-r));
545 r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/job", bus_job_enumerate, m);
547 log_error("Failed to add job enumerator: %s", strerror(-r));
551 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", "org.freedesktop.systemd1.Unit", bus_unit_vtable, bus_unit_find, m);
553 log_error("Failed to register Unit vtable: %s", strerror(-r));
557 r = sd_bus_add_node_enumerator(bus, "/org/freedesktop/systemd1/unit", bus_unit_enumerate, m);
559 log_error("Failed to add job enumerator: %s", strerror(-r));
563 for (t = 0; t < _UNIT_TYPE_MAX; t++) {
564 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, unit_vtable[t]->bus_vtable, bus_unit_interface_find, m);
566 log_error("Failed to register type specific vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
570 if (unit_vtable[t]->cgroup_context_offset > 0) {
571 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_unit_cgroup_vtable, bus_unit_cgroup_find, m);
573 log_error("Failed to register control group unit vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
577 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_cgroup_vtable, bus_cgroup_context_find, m);
579 log_error("Failed to register control group vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
584 if (unit_vtable[t]->exec_context_offset > 0) {
585 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_exec_vtable, bus_exec_context_find, m);
587 log_error("Failed to register execute vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
592 if (unit_vtable[t]->kill_context_offset > 0) {
593 r = sd_bus_add_fallback_vtable(bus, "/org/freedesktop/systemd1/unit", unit_vtable[t]->bus_interface, bus_kill_vtable, bus_kill_context_find, m);
595 log_error("Failed to register kill vtable for %s: %s", unit_vtable[t]->bus_interface, strerror(-r));
604 static int bus_setup_disconnected_match(Manager *m, sd_bus *bus) {
610 r = sd_bus_add_match(
613 "path='/org/freedesktop/DBus/Local',"
614 "interface='org.freedesktop.DBus.Local',"
615 "member='Disconnected'",
616 signal_disconnected, m);
619 log_error("Failed to register match for Disconnected message: %s", strerror(-r));
626 static int bus_on_connection(sd_event_source *s, int fd, uint32_t revents, void *userdata) {
627 _cleanup_bus_unref_ sd_bus *bus = NULL;
628 _cleanup_close_ int nfd = -1;
629 Manager *m = userdata;
636 nfd = accept4(fd, NULL, NULL, SOCK_NONBLOCK|SOCK_CLOEXEC);
638 log_warning("Failed to accept private connection, ignoring: %m");
642 if (set_size(m->private_buses) >= CONNECTIONS_MAX) {
643 log_warning("Too many concurrent connections, refusing");
647 r = set_ensure_allocated(&m->private_buses, trivial_hash_func, trivial_compare_func);
653 r = sd_bus_new(&bus);
655 log_warning("Failed to allocate new private connection bus: %s", strerror(-r));
659 r = sd_bus_set_fd(bus, nfd, nfd);
661 log_warning("Failed to set fd on new connection bus: %s", strerror(-r));
667 r = bus_check_peercred(bus);
669 log_warning("Incoming private connection from unprivileged client, refusing: %s", strerror(-r));
673 assert_se(sd_id128_randomize(&id) >= 0);
675 r = sd_bus_set_server(bus, 1, id);
677 log_warning("Failed to enable server support for new connection bus: %s", strerror(-r));
681 r = sd_bus_start(bus);
683 log_warning("Failed to start new connection bus: %s", strerror(-r));
687 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
689 log_warning("Failed to attach new connection bus to event loop: %s", strerror(-r));
693 if (m->running_as == SYSTEMD_SYSTEM) {
694 /* When we run as system instance we get the Released
695 * signal via a direct connection */
697 r = sd_bus_add_match(
700 "interface='org.freedesktop.systemd1.Agent',"
702 "path='/org/freedesktop/systemd1/agent'",
703 signal_agent_released, m);
706 log_warning("Failed to register Released match on new connection bus: %s", strerror(-r));
711 r = bus_setup_disconnected_match(m, bus);
715 r = bus_setup_api_vtables(m, bus);
717 log_warning("Failed to set up API vtables on new connection bus: %s", strerror(-r));
721 r = set_put(m->private_buses, bus);
723 log_warning("Failed to add new conenction bus to set: %s", strerror(-r));
729 log_debug("Accepted new private connection.");
734 static int bus_list_names(Manager *m, sd_bus *bus) {
735 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
736 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
743 r = sd_bus_call_method(
745 "org.freedesktop.DBus",
746 "/org/freedesktop/DBus",
747 "org.freedesktop.DBus",
752 log_error("Failed to get initial list of names: %s", bus_error_message(&error, r));
756 r = sd_bus_message_enter_container(reply, 'a', "s");
758 return bus_log_parse_error(r);
760 /* This is a bit hacky, we say the owner of the name is the
761 * name itself, because we don't want the extra traffic to
762 * figure out the real owner. */
763 while ((r = sd_bus_message_read(reply, "s", &name)) > 0)
764 manager_dispatch_bus_name_owner_changed(m, name, NULL, name);
766 return bus_log_parse_error(r);
768 r = sd_bus_message_exit_container(reply);
770 return bus_log_parse_error(r);
775 static int bus_setup_api(Manager *m, sd_bus *bus) {
781 r = bus_setup_api_vtables(m, bus);
785 r = sd_bus_add_match(
788 "sender='org.freedesktop.DBus',"
789 "path='/org/freedesktop/DBus',"
790 "interface='org.freedesktop.DBus',"
791 "member='NameOwnerChanged'",
792 signal_name_owner_changed, m);
794 log_warning("Failed to subscribe to NameOwnerChanged signal: %s", strerror(-r));
796 r = sd_bus_add_match(
799 "sender='org.freedesktop.DBus',"
800 "path='/org/freedesktop/DBus',"
801 "interface='org.freedesktop.systemd1.Activator',"
802 "member='ActivationRequest'",
803 signal_activation_request, m);
805 log_warning("Failed to subscribe to activation signal: %s", strerror(-r));
807 /* Allow replacing of our name, to ease implementation of
808 * reexecution, where we keep the old connection open until
809 * after the new connection is set up and the name installed
810 * to allow clients to synchronously wait for reexecution to
812 r = sd_bus_request_name(bus,"org.freedesktop.systemd1", SD_BUS_NAME_ALLOW_REPLACEMENT|SD_BUS_NAME_REPLACE_EXISTING);
814 log_error("Failed to register name: %s", strerror(-r));
818 if (r != SD_BUS_NAME_PRIMARY_OWNER) {
819 log_error("Failed to acquire name.");
823 bus_list_names(m, bus);
825 log_debug("Successfully connected to API bus.");
829 static int bus_init_api(Manager *m) {
830 _cleanup_bus_unref_ sd_bus *bus = NULL;
836 /* The API and system bus is the same if we are running in system mode */
837 if (m->running_as == SYSTEMD_SYSTEM && m->system_bus)
838 bus = sd_bus_ref(m->system_bus);
840 if (m->running_as == SYSTEMD_SYSTEM)
841 r = sd_bus_open_system(&bus);
843 r = sd_bus_open_user(&bus);
846 log_debug("Failed to connect to API bus, retrying later...");
850 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
852 log_error("Failed to attach API bus to event loop: %s", strerror(-r));
856 r = bus_setup_disconnected_match(m, bus);
861 r = bus_setup_api(m, bus);
863 log_error("Failed to set up API bus: %s", strerror(-r));
873 static int bus_setup_system(Manager *m, sd_bus *bus) {
879 if (m->running_as == SYSTEMD_SYSTEM)
882 /* If we are a user instance we get the Released message via
884 r = sd_bus_add_match(
887 "interface='org.freedesktop.systemd1.Agent',"
889 "path='/org/freedesktop/systemd1/agent'",
890 signal_agent_released, m);
893 log_warning("Failed to register Released match on system bus: %s", strerror(-r));
895 log_debug("Successfully connected to system bus.");
899 static int bus_init_system(Manager *m) {
900 _cleanup_bus_unref_ sd_bus *bus = NULL;
906 /* The API and system bus is the same if we are running in system mode */
907 if (m->running_as == SYSTEMD_SYSTEM && m->api_bus) {
908 m->system_bus = sd_bus_ref(m->api_bus);
912 r = sd_bus_open_system(&bus);
914 log_debug("Failed to connect to system bus, retrying later...");
918 r = bus_setup_disconnected_match(m, bus);
922 r = sd_bus_attach_event(bus, m->event, SD_EVENT_PRIORITY_NORMAL);
924 log_error("Failed to attach system bus to event loop: %s", strerror(-r));
928 r = bus_setup_system(m, bus);
930 log_error("Fauiled to set up system bus: %s", strerror(-r));
940 static int bus_init_private(Manager *m) {
941 _cleanup_close_ int fd = -1;
942 union sockaddr_union sa = {
943 .un.sun_family = AF_UNIX
951 if (m->private_listen_fd >= 0)
954 if (m->running_as == SYSTEMD_SYSTEM) {
956 /* We want the private bus only when running as init */
960 strcpy(sa.un.sun_path, "/run/systemd/private");
961 salen = offsetof(union sockaddr_union, un.sun_path) + sizeof("/run/systemd/private") - 1;
963 size_t left = sizeof(sa.un.sun_path);
964 char *p = sa.un.sun_path;
967 e = secure_getenv("XDG_RUNTIME_DIR");
969 log_error("Failed to determine XDG_RUNTIME_DIR");
973 left = strpcpy(&p, left, e);
974 left = strpcpy(&p, left, "/systemd/private");
976 salen = sizeof(sa.un) - left;
978 mkdir_parents_label(sa.un.sun_path, 0755);
981 unlink(sa.un.sun_path);
983 fd = socket(AF_UNIX, SOCK_STREAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
985 log_error("Failed to allocate private socket: %m");
989 r = bind(fd, &sa.sa, salen);
991 log_error("Failed to bind private socket: %m");
995 r = listen(fd, SOMAXCONN);
997 log_error("Failed to make private socket listening: %m");
1001 r = sd_event_add_io(m->event, fd, EPOLLIN, bus_on_connection, m, &s);
1003 log_error("Failed to allocate event source: %s", strerror(-r));
1007 m->private_listen_fd = fd;
1008 m->private_listen_event_source = s;
1011 log_debug("Successfully created private D-Bus server.");
1016 int bus_init(Manager *m, bool try_bus_connect) {
1019 if (try_bus_connect) {
1020 r = bus_init_system(m);
1024 r = bus_init_api(m);
1029 r = bus_init_private(m);
1036 static void destroy_bus(Manager *m, sd_bus **bus) {
1046 /* Get rid of tracked clients on this bus */
1047 bus_client_untrack_bus(m->subscribed, *bus);
1048 HASHMAP_FOREACH(j, m->jobs, i)
1049 bus_client_untrack_bus(j->subscribed, *bus);
1051 /* Get rid of queued message on this bus */
1052 if (m->queued_message_bus == *bus) {
1053 m->queued_message_bus = sd_bus_unref(m->queued_message_bus);
1055 if (m->queued_message)
1056 m->queued_message = sd_bus_message_unref(m->queued_message);
1059 /* Possibly flush unwritten data, but only if we are
1060 * unprivileged, since we don't want to sync here */
1061 if (m->running_as != SYSTEMD_SYSTEM)
1064 /* And destroy the object */
1066 *bus = sd_bus_unref(*bus);
1069 void bus_done(Manager *m) {
1075 destroy_bus(m, &m->api_bus);
1077 destroy_bus(m, &m->system_bus);
1078 while ((b = set_steal_first(m->private_buses)))
1081 set_free(m->private_buses);
1082 set_free(m->subscribed);
1084 if (m->private_listen_event_source)
1085 m->private_listen_event_source = sd_event_source_unref(m->private_listen_event_source);
1087 if (m->private_listen_fd >= 0) {
1088 close_nointr_nofail(m->private_listen_fd);
1089 m->private_listen_fd = -1;
1093 int bus_fdset_add_all(Manager *m, FDSet *fds) {
1101 /* When we are about to reexecute we add all D-Bus fds to the
1102 * set to pass over to the newly executed systemd. They won't
1103 * be used there however, except thatt they are closed at the
1104 * very end of deserialization, those making it possible for
1105 * clients to synchronously wait for systemd to reexec by
1106 * simply waiting for disconnection */
1109 fd = sd_bus_get_fd(m->api_bus);
1111 fd = fdset_put_dup(fds, fd);
1117 SET_FOREACH(b, m->private_buses, i) {
1118 fd = sd_bus_get_fd(b);
1120 fd = fdset_put_dup(fds, fd);
1126 /* We don't offer any APIs on the system bus (well, unless it
1127 * is the same as the API bus) hence we don't bother with it
1133 void bus_serialize(Manager *m, FILE *f) {
1137 bus_client_track_serialize(m, f, m->subscribed);
1140 int bus_deserialize_item(Manager *m, const char *line) {
1144 return bus_client_track_deserialize_item(m, &m->subscribed, line);