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/>.
27 #include "dbus-manager.h"
29 #include "bus-errors.h"
31 #include "dbus-common.h"
33 #include "selinux-access.h"
36 #include "path-util.h"
37 #include "dbus-unit.h"
41 #define BUS_MANAGER_INTERFACE_BEGIN \
42 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
44 #define BUS_MANAGER_INTERFACE_METHODS \
45 " <method name=\"GetUnit\">\n" \
46 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
47 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUnitByPID\">\n" \
50 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"LoadUnit\">\n" \
54 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"StartUnit\">\n" \
58 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
59 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
62 " <method name=\"StartUnitReplace\">\n" \
63 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
68 " <method name=\"StopUnit\">\n" \
69 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
73 " <method name=\"ReloadUnit\">\n" \
74 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
78 " <method name=\"RestartUnit\">\n" \
79 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
83 " <method name=\"TryRestartUnit\">\n" \
84 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
86 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
88 " <method name=\"ReloadOrRestartUnit\">\n" \
89 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
93 " <method name=\"ReloadOrTryRestartUnit\">\n" \
94 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
98 " <method name=\"KillUnit\">\n" \
99 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
100 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
101 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
103 " <method name=\"ResetFailedUnit\">\n" \
104 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"GetUnitControlGroupAttributes\">\n" \
107 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"attributes\" type=\"as\" direction=\"in\"/>\n" \
109 " <arg name=\"values\" type=\"as\" direction=\"out\"/>\n" \
111 " <method name=\"SetUnitControlGroupAttributes\">\n" \
112 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
113 " <arg name=\"attributes\" type=\"a(sss)\" direction=\"in\"/>\n" \
114 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
116 " <method name=\"UnsetUnitControlGroupAttributes\">\n" \
117 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"attributes\" type=\"a(ss)\" direction=\"in\"/>\n" \
119 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
121 " <method name=\"SetUnitControlGroups\">\n" \
122 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
123 " <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n" \
124 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
126 " <method name=\"UnsetUnitControlGroups\">\n" \
127 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
128 " <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n" \
129 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
131 " <method name=\"GetJob\">\n" \
132 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
133 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
135 " <method name=\"CancelJob\">\n" \
136 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
138 " <method name=\"ClearJobs\"/>\n" \
139 " <method name=\"ResetFailed\"/>\n" \
140 " <method name=\"ListUnits\">\n" \
141 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
143 " <method name=\"ListJobs\">\n" \
144 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
146 " <method name=\"Subscribe\"/>\n" \
147 " <method name=\"Unsubscribe\"/>\n" \
148 " <method name=\"Dump\">\n" \
149 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
151 " <method name=\"CreateSnapshot\">\n" \
152 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
153 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
154 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
156 " <method name=\"RemoveSnapshot\">\n" \
157 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
159 " <method name=\"Reload\"/>\n" \
160 " <method name=\"Reexecute\"/>\n" \
161 " <method name=\"Exit\"/>\n" \
162 " <method name=\"Reboot\"/>\n" \
163 " <method name=\"PowerOff\"/>\n" \
164 " <method name=\"Halt\"/>\n" \
165 " <method name=\"KExec\"/>\n" \
166 " <method name=\"SwitchRoot\">\n" \
167 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
168 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
170 " <method name=\"SetEnvironment\">\n" \
171 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
173 " <method name=\"UnsetEnvironment\">\n" \
174 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
176 " <method name=\"UnsetAndSetEnvironment\">\n" \
177 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
178 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
180 " <method name=\"ListUnitFiles\">\n" \
181 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
183 " <method name=\"GetUnitFileState\">\n" \
184 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
185 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
187 " <method name=\"EnableUnitFiles\">\n" \
188 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
189 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
190 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
191 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
192 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
194 " <method name=\"DisableUnitFiles\">\n" \
195 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
196 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
197 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
199 " <method name=\"ReenableUnitFiles\">\n" \
200 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
201 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
202 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
203 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
204 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
206 " <method name=\"LinkUnitFiles\">\n" \
207 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
208 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
209 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
210 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
212 " <method name=\"PresetUnitFiles\">\n" \
213 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
214 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
215 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
216 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
217 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
219 " <method name=\"MaskUnitFiles\">\n" \
220 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
221 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
222 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
223 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
225 " <method name=\"UnmaskUnitFiles\">\n" \
226 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
227 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
228 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
231 #define BUS_MANAGER_INTERFACE_SIGNALS \
232 " <signal name=\"UnitNew\">\n" \
233 " <arg name=\"id\" type=\"s\"/>\n" \
234 " <arg name=\"unit\" type=\"o\"/>\n" \
236 " <signal name=\"UnitRemoved\">\n" \
237 " <arg name=\"id\" type=\"s\"/>\n" \
238 " <arg name=\"unit\" type=\"o\"/>\n" \
240 " <signal name=\"JobNew\">\n" \
241 " <arg name=\"id\" type=\"u\"/>\n" \
242 " <arg name=\"job\" type=\"o\"/>\n" \
243 " <arg name=\"unit\" type=\"s\"/>\n" \
245 " <signal name=\"JobRemoved\">\n" \
246 " <arg name=\"id\" type=\"u\"/>\n" \
247 " <arg name=\"job\" type=\"o\"/>\n" \
248 " <arg name=\"unit\" type=\"s\"/>\n" \
249 " <arg name=\"result\" type=\"s\"/>\n" \
251 " <signal name=\"StartupFinished\">\n" \
252 " <arg name=\"firmware\" type=\"t\"/>\n" \
253 " <arg name=\"loader\" type=\"t\"/>\n" \
254 " <arg name=\"kernel\" type=\"t\"/>\n" \
255 " <arg name=\"initrd\" type=\"t\"/>\n" \
256 " <arg name=\"userspace\" type=\"t\"/>\n" \
257 " <arg name=\"total\" type=\"t\"/>\n" \
259 " <signal name=\"UnitFilesChanged\"/>\n"
261 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
262 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
263 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
264 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
265 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
266 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
267 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
268 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
269 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
270 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
271 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
272 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
273 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
274 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
275 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
276 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
277 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
278 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
279 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
280 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
281 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
282 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
283 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
284 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
285 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
286 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
287 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
288 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
289 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
290 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
291 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
292 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
293 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
294 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
296 #define BUS_MANAGER_INTERFACE_END \
299 #define BUS_MANAGER_INTERFACE \
300 BUS_MANAGER_INTERFACE_BEGIN \
301 BUS_MANAGER_INTERFACE_METHODS \
302 BUS_MANAGER_INTERFACE_SIGNALS \
303 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
304 BUS_MANAGER_INTERFACE_END
306 #define INTROSPECTION_BEGIN \
307 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
309 BUS_MANAGER_INTERFACE \
310 BUS_PROPERTIES_INTERFACE \
312 BUS_INTROSPECTABLE_INTERFACE
314 #define INTROSPECTION_END \
317 #define INTERFACES_LIST \
318 BUS_GENERIC_INTERFACES_LIST \
319 "org.freedesktop.systemd1.Manager\0"
321 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
323 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
325 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
328 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
335 e = stpcpy(e, "split-usr:");
337 if (readlink_malloc("/etc/mtab", &p) < 0)
338 e = stpcpy(e, "mtab-not-symlink:");
342 if (access("/proc/cgroups", F_OK) < 0)
343 e = stpcpy(e, "cgroups-missing:");
345 if (hwclock_is_localtime() > 0)
346 e = stpcpy(e, "local-hwclock:");
348 /* remove the last ':' */
354 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
360 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
366 t = log_target_to_string(log_get_target());
368 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
374 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
380 dbus_message_iter_get_basic(i, &t);
382 return log_set_target_from_string(t);
385 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
392 r = log_level_to_string_alloc(log_get_max_level(), &t);
396 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
403 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
409 dbus_message_iter_get_basic(i, &t);
411 return log_set_max_level_from_string(t);
414 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
422 u = hashmap_size(m->units);
424 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
430 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
438 u = hashmap_size(m->jobs);
440 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
446 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
454 if (dual_timestamp_is_set(&m->finish_timestamp))
457 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
459 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
465 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
473 detect_virtualization(&id);
475 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
481 static DBusMessage *message_from_file_changes(
483 UnitFileChange *changes,
485 int carries_install_info) {
487 DBusMessageIter iter, sub, sub2;
491 reply = dbus_message_new_method_return(m);
495 dbus_message_iter_init_append(reply, &iter);
497 if (carries_install_info >= 0) {
500 b = !!carries_install_info;
501 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
505 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
508 for (i = 0; i < n_changes; i++) {
509 const char *type, *path, *source;
511 type = unit_file_change_type_to_string(changes[i].type);
512 path = strempty(changes[i].path);
513 source = strempty(changes[i].source);
515 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
516 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
517 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
518 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
519 !dbus_message_iter_close_container(&sub, &sub2))
523 if (!dbus_message_iter_close_container(&iter, &sub))
529 dbus_message_unref(reply);
533 static int bus_manager_send_unit_files_changed(Manager *m) {
537 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
541 r = bus_broadcast(m, s);
542 dbus_message_unref(s);
547 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
553 dbus_message_iter_get_basic(i, t);
555 return watchdog_set_timeout(t);
558 static const char systemd_property_string[] =
562 static const BusProperty bus_systemd_properties[] = {
563 { "Version", bus_property_append_string, "s", 0 },
564 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
568 static const BusProperty bus_manager_properties[] = {
569 { "Tainted", bus_manager_append_tainted, "s", 0 },
570 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
571 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
572 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
573 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
574 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
575 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
576 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
577 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
578 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
579 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
580 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
581 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
582 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
583 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
584 { "NNames", bus_manager_append_n_names, "u", 0 },
585 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
586 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
587 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
588 { "Progress", bus_manager_append_progress, "d", 0 },
589 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
590 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
591 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
592 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
593 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
594 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
595 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
596 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
597 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
598 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
599 { "Virtualization", bus_manager_append_virt, "s", 0, },
603 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
604 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
605 _cleanup_free_ char * path = NULL;
609 JobType job_type = _JOB_TYPE_INVALID;
610 bool reload_if_possible = false;
617 dbus_error_init(&error);
619 member = dbus_message_get_member(message);
621 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
625 if (!dbus_message_get_args(
628 DBUS_TYPE_STRING, &name,
630 return bus_send_error_reply(connection, message, &error, -EINVAL);
632 u = manager_get_unit(m, name);
634 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
635 return bus_send_error_reply(connection, message, &error, -ENOENT);
638 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
640 reply = dbus_message_new_method_return(message);
644 path = unit_dbus_path(u);
648 if (!dbus_message_append_args(
650 DBUS_TYPE_OBJECT_PATH, &path,
653 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
657 if (!dbus_message_get_args(
660 DBUS_TYPE_UINT32, &pid,
662 return bus_send_error_reply(connection, message, &error, -EINVAL);
664 u = cgroup_unit_by_pid(m, (pid_t) pid);
666 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
667 return bus_send_error_reply(connection, message, &error, -ENOENT);
670 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
672 reply = dbus_message_new_method_return(message);
676 path = unit_dbus_path(u);
680 if (!dbus_message_append_args(
682 DBUS_TYPE_OBJECT_PATH, &path,
685 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
689 if (!dbus_message_get_args(
692 DBUS_TYPE_STRING, &name,
694 return bus_send_error_reply(connection, message, &error, -EINVAL);
696 r = manager_load_unit(m, name, NULL, &error, &u);
698 return bus_send_error_reply(connection, message, &error, r);
700 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
702 reply = dbus_message_new_method_return(message);
706 path = unit_dbus_path(u);
710 if (!dbus_message_append_args(
712 DBUS_TYPE_OBJECT_PATH, &path,
716 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
717 job_type = JOB_START;
718 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
719 job_type = JOB_START;
720 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
722 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
723 job_type = JOB_RELOAD;
724 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
725 job_type = JOB_RESTART;
726 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
727 job_type = JOB_TRY_RESTART;
728 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
729 reload_if_possible = true;
730 job_type = JOB_RESTART;
731 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
732 reload_if_possible = true;
733 job_type = JOB_TRY_RESTART;
734 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
735 const char *name, *swho;
740 if (!dbus_message_get_args(
743 DBUS_TYPE_STRING, &name,
744 DBUS_TYPE_STRING, &swho,
745 DBUS_TYPE_INT32, &signo,
747 return bus_send_error_reply(connection, message, &error, -EINVAL);
752 who = kill_who_from_string(swho);
754 return bus_send_error_reply(connection, message, &error, -EINVAL);
757 if (signo <= 0 || signo >= _NSIG)
758 return bus_send_error_reply(connection, message, &error, -EINVAL);
760 u = manager_get_unit(m, name);
762 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
763 return bus_send_error_reply(connection, message, &error, -ENOENT);
766 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
768 r = unit_kill(u, who, signo, &error);
770 return bus_send_error_reply(connection, message, &error, r);
772 reply = dbus_message_new_method_return(message);
776 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
780 if (!dbus_message_get_args(
783 DBUS_TYPE_UINT32, &id,
785 return bus_send_error_reply(connection, message, &error, -EINVAL);
787 j = manager_get_job(m, id);
789 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
790 return bus_send_error_reply(connection, message, &error, -ENOENT);
793 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
795 reply = dbus_message_new_method_return(message);
799 path = job_dbus_path(j);
803 if (!dbus_message_append_args(
805 DBUS_TYPE_OBJECT_PATH, &path,
809 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
813 if (!dbus_message_get_args(
816 DBUS_TYPE_UINT32, &id,
818 return bus_send_error_reply(connection, message, &error, -EINVAL);
820 j = manager_get_job(m, id);
822 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
823 return bus_send_error_reply(connection, message, &error, -ENOENT);
826 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
827 job_finish_and_invalidate(j, JOB_CANCELED, true);
829 reply = dbus_message_new_method_return(message);
833 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
835 SELINUX_ACCESS_CHECK(connection, message, "reboot");
836 manager_clear_jobs(m);
838 reply = dbus_message_new_method_return(message);
842 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
844 SELINUX_ACCESS_CHECK(connection, message, "reload");
846 manager_reset_failed(m);
848 reply = dbus_message_new_method_return(message);
852 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
856 if (!dbus_message_get_args(
859 DBUS_TYPE_STRING, &name,
861 return bus_send_error_reply(connection, message, &error, -EINVAL);
863 u = manager_get_unit(m, name);
865 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
866 return bus_send_error_reply(connection, message, &error, -ENOENT);
869 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
871 unit_reset_failed(u);
873 reply = dbus_message_new_method_return(message);
877 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroups")) {
880 DBusMessageIter iter;
882 if (!dbus_message_iter_init(message, &iter))
885 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
887 return bus_send_error_reply(connection, message, NULL, r);
889 u = manager_get_unit(m, name);
891 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
892 return bus_send_error_reply(connection, message, &error, -ENOENT);
895 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
897 r = bus_unit_cgroup_set(u, &iter);
899 return bus_send_error_reply(connection, message, NULL, r);
901 reply = dbus_message_new_method_return(message);
905 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroups")) {
908 DBusMessageIter iter;
910 if (!dbus_message_iter_init(message, &iter))
913 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
915 return bus_send_error_reply(connection, message, NULL, r);
917 u = manager_get_unit(m, name);
919 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
920 return bus_send_error_reply(connection, message, &error, -ENOENT);
923 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
925 r = bus_unit_cgroup_unset(u, &iter);
927 return bus_send_error_reply(connection, message, NULL, r);
929 reply = dbus_message_new_method_return(message);
933 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttributes")) {
936 DBusMessageIter iter;
938 if (!dbus_message_iter_init(message, &iter))
941 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
943 return bus_send_error_reply(connection, message, NULL, r);
945 u = manager_get_unit(m, name);
947 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
948 return bus_send_error_reply(connection, message, &error, -ENOENT);
951 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
952 r = bus_unit_cgroup_attribute_set(u, &iter);
954 return bus_send_error_reply(connection, message, NULL, r);
956 reply = dbus_message_new_method_return(message);
960 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttributes")) {
963 DBusMessageIter iter;
965 if (!dbus_message_iter_init(message, &iter))
968 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
970 return bus_send_error_reply(connection, message, NULL, r);
972 u = manager_get_unit(m, name);
974 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
975 return bus_send_error_reply(connection, message, &error, -ENOENT);
978 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
980 r = bus_unit_cgroup_attribute_unset(u, &iter);
982 return bus_send_error_reply(connection, message, NULL, r);
984 reply = dbus_message_new_method_return(message);
988 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttributes")) {
991 DBusMessageIter iter;
992 _cleanup_strv_free_ char **list = NULL;
994 if (!dbus_message_iter_init(message, &iter))
997 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
999 return bus_send_error_reply(connection, message, NULL, r);
1001 u = manager_get_unit(m, name);
1003 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1004 return bus_send_error_reply(connection, message, &error, -ENOENT);
1007 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
1008 r = bus_unit_cgroup_attribute_get(u, &iter, &list);
1010 return bus_send_error_reply(connection, message, NULL, r);
1012 reply = dbus_message_new_method_return(message);
1016 dbus_message_iter_init_append(reply, &iter);
1017 if (bus_append_strv_iter(&iter, list) < 0)
1020 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
1021 DBusMessageIter iter, sub;
1026 SELINUX_ACCESS_CHECK(connection, message, "status");
1028 reply = dbus_message_new_method_return(message);
1032 dbus_message_iter_init_append(reply, &iter);
1034 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
1037 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1038 char *u_path, *j_path;
1039 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
1040 DBusMessageIter sub2;
1047 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1050 description = unit_description(u);
1051 load_state = unit_load_state_to_string(u->load_state);
1052 active_state = unit_active_state_to_string(unit_active_state(u));
1053 sub_state = unit_sub_state_to_string(u);
1055 f = unit_following(u);
1056 following = f ? f->id : "";
1058 u_path = unit_dbus_path(u);
1063 job_id = (uint32_t) u->job->id;
1065 if (!(j_path = job_dbus_path(u->job))) {
1070 sjob_type = job_type_to_string(u->job->type);
1077 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
1078 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
1079 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
1080 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
1081 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
1082 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
1083 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
1084 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
1085 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
1086 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
1097 if (!dbus_message_iter_close_container(&sub, &sub2))
1101 if (!dbus_message_iter_close_container(&iter, &sub))
1104 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
1105 DBusMessageIter iter, sub;
1109 SELINUX_ACCESS_CHECK(connection, message, "status");
1111 reply = dbus_message_new_method_return(message);
1115 dbus_message_iter_init_append(reply, &iter);
1117 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1120 HASHMAP_FOREACH(j, m->jobs, i) {
1121 char *u_path, *j_path;
1122 const char *state, *type;
1124 DBusMessageIter sub2;
1126 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1129 id = (uint32_t) j->id;
1130 state = job_state_to_string(j->state);
1131 type = job_type_to_string(j->type);
1133 j_path = job_dbus_path(j);
1137 u_path = unit_dbus_path(j->unit);
1143 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1144 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1145 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1146 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1147 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1148 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1157 if (!dbus_message_iter_close_container(&sub, &sub2))
1161 if (!dbus_message_iter_close_container(&iter, &sub))
1164 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1168 SELINUX_ACCESS_CHECK(connection, message, "status");
1170 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1172 s = set_new(string_hash_func, string_compare_func);
1176 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1182 client = strdup(bus_message_get_sender_with_fallback(message));
1186 r = set_put(s, client);
1189 return bus_send_error_reply(connection, message, NULL, r);
1192 reply = dbus_message_new_method_return(message);
1196 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1199 SELINUX_ACCESS_CHECK(connection, message, "status");
1201 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1203 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1204 return bus_send_error_reply(connection, message, &error, -ENOENT);
1209 reply = dbus_message_new_method_return(message);
1213 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1218 SELINUX_ACCESS_CHECK(connection, message, "status");
1220 reply = dbus_message_new_method_return(message);
1224 f = open_memstream(&dump, &size);
1228 manager_dump_units(m, f, NULL);
1229 manager_dump_jobs(m, f, NULL);
1239 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1245 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1247 dbus_bool_t cleanup;
1250 SELINUX_ACCESS_CHECK(connection, message, "start");
1252 if (!dbus_message_get_args(
1255 DBUS_TYPE_STRING, &name,
1256 DBUS_TYPE_BOOLEAN, &cleanup,
1258 return bus_send_error_reply(connection, message, &error, -EINVAL);
1263 r = snapshot_create(m, name, cleanup, &error, &s);
1265 return bus_send_error_reply(connection, message, &error, r);
1267 reply = dbus_message_new_method_return(message);
1271 path = unit_dbus_path(UNIT(s));
1275 if (!dbus_message_append_args(
1277 DBUS_TYPE_OBJECT_PATH, &path,
1281 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1285 if (!dbus_message_get_args(
1288 DBUS_TYPE_STRING, &name,
1290 return bus_send_error_reply(connection, message, &error, -EINVAL);
1292 u = manager_get_unit(m, name);
1294 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1295 return bus_send_error_reply(connection, message, &error, -ENOENT);
1298 if (u->type != UNIT_SNAPSHOT) {
1299 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1300 return bus_send_error_reply(connection, message, &error, -ENOENT);
1303 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1304 snapshot_remove(SNAPSHOT(u));
1306 reply = dbus_message_new_method_return(message);
1310 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1311 char *introspection = NULL;
1319 SELINUX_ACCESS_CHECK(connection, message, "status");
1321 reply = dbus_message_new_method_return(message);
1325 /* We roll our own introspection code here, instead of
1326 * relying on bus_default_message_handler() because we
1327 * need to generate our introspection string
1330 f = open_memstream(&introspection, &size);
1334 fputs(INTROSPECTION_BEGIN, f);
1336 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1342 p = bus_path_escape(k);
1345 free(introspection);
1349 fprintf(f, "<node name=\"unit/%s\"/>", p);
1353 HASHMAP_FOREACH(j, m->jobs, i)
1354 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1356 fputs(INTROSPECTION_END, f);
1360 free(introspection);
1369 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1370 free(introspection);
1374 free(introspection);
1376 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1378 SELINUX_ACCESS_CHECK(connection, message, "reload");
1380 assert(!m->queued_message);
1382 /* Instead of sending the reply back right away, we
1383 * just remember that we need to and then send it
1384 * after the reload is finished. That way the caller
1385 * knows when the reload finished. */
1387 m->queued_message = dbus_message_new_method_return(message);
1388 if (!m->queued_message)
1391 m->queued_message_connection = connection;
1392 m->exit_code = MANAGER_RELOAD;
1394 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1396 SELINUX_ACCESS_CHECK(connection, message, "reload");
1398 /* We don't send a reply back here, the client should
1399 * just wait for us disconnecting. */
1401 m->exit_code = MANAGER_REEXECUTE;
1403 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1405 SELINUX_ACCESS_CHECK(connection, message, "halt");
1407 if (m->running_as == SYSTEMD_SYSTEM) {
1408 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1409 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1412 reply = dbus_message_new_method_return(message);
1416 m->exit_code = MANAGER_EXIT;
1418 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1420 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1422 if (m->running_as != SYSTEMD_SYSTEM) {
1423 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1424 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1427 reply = dbus_message_new_method_return(message);
1431 m->exit_code = MANAGER_REBOOT;
1433 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1435 SELINUX_ACCESS_CHECK(connection, message, "halt");
1437 if (m->running_as != SYSTEMD_SYSTEM) {
1438 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1439 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1442 reply = dbus_message_new_method_return(message);
1446 m->exit_code = MANAGER_POWEROFF;
1448 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1450 SELINUX_ACCESS_CHECK(connection, message, "halt");
1452 if (m->running_as != SYSTEMD_SYSTEM) {
1453 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1454 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1457 reply = dbus_message_new_method_return(message);
1461 m->exit_code = MANAGER_HALT;
1463 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1465 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1467 if (m->running_as != SYSTEMD_SYSTEM) {
1468 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1469 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1472 reply = dbus_message_new_method_return(message);
1476 m->exit_code = MANAGER_KEXEC;
1478 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1479 const char *switch_root, *switch_root_init;
1483 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1485 if (!dbus_message_get_args(
1488 DBUS_TYPE_STRING, &switch_root,
1489 DBUS_TYPE_STRING, &switch_root_init,
1491 return bus_send_error_reply(connection, message, &error, -EINVAL);
1493 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1494 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1496 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1497 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1499 if (m->running_as != SYSTEMD_SYSTEM) {
1500 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1501 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1505 if (isempty(switch_root_init))
1506 k = access(switch_root, F_OK);
1510 p = strjoin(switch_root, "/", switch_root_init, NULL);
1514 k = access(p, X_OK);
1518 return bus_send_error_reply(connection, message, NULL, -errno);
1520 u = strdup(switch_root);
1524 if (!isempty(switch_root_init)) {
1525 v = strdup(switch_root_init);
1533 free(m->switch_root);
1534 free(m->switch_root_init);
1536 m->switch_root_init = v;
1538 reply = dbus_message_new_method_return(message);
1542 m->exit_code = MANAGER_SWITCH_ROOT;
1544 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1545 _cleanup_strv_free_ char **l = NULL;
1548 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1550 r = bus_parse_strv(message, &l);
1554 return bus_send_error_reply(connection, message, NULL, r);
1555 if (!strv_env_is_valid(l))
1556 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1558 e = strv_env_merge(2, m->environment, l);
1562 reply = dbus_message_new_method_return(message);
1568 strv_free(m->environment);
1571 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1572 _cleanup_strv_free_ char **l = NULL;
1575 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1577 r = bus_parse_strv(message, &l);
1581 return bus_send_error_reply(connection, message, NULL, r);
1582 if (!strv_env_name_or_assignment_is_valid(l))
1583 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1585 e = strv_env_delete(m->environment, 1, l);
1589 reply = dbus_message_new_method_return(message);
1595 strv_free(m->environment);
1598 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1599 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1601 DBusMessageIter iter;
1603 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1605 if (!dbus_message_iter_init(message, &iter))
1608 r = bus_parse_strv_iter(&iter, &l_unset);
1612 return bus_send_error_reply(connection, message, NULL, r);
1613 if (!strv_env_name_or_assignment_is_valid(l_unset))
1614 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1616 if (!dbus_message_iter_next(&iter))
1617 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1619 r = bus_parse_strv_iter(&iter, &l_set);
1623 return bus_send_error_reply(connection, message, NULL, r);
1624 if (!strv_env_is_valid(l_set))
1625 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1627 e = strv_env_delete(m->environment, 1, l_unset);
1631 f = strv_env_merge(2, e, l_set);
1635 reply = dbus_message_new_method_return(message);
1641 strv_free(m->environment);
1643 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1644 DBusMessageIter iter, sub, sub2;
1649 SELINUX_ACCESS_CHECK(connection, message, "status");
1651 reply = dbus_message_new_method_return(message);
1655 h = hashmap_new(string_hash_func, string_compare_func);
1659 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1661 unit_file_list_free(h);
1662 return bus_send_error_reply(connection, message, NULL, r);
1665 dbus_message_iter_init_append(reply, &iter);
1667 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1668 unit_file_list_free(h);
1672 HASHMAP_FOREACH(item, h, i) {
1675 state = unit_file_state_to_string(item->state);
1678 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1679 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1680 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1681 !dbus_message_iter_close_container(&sub, &sub2)) {
1682 unit_file_list_free(h);
1687 unit_file_list_free(h);
1689 if (!dbus_message_iter_close_container(&iter, &sub))
1692 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1694 UnitFileState state;
1697 SELINUX_ACCESS_CHECK(connection, message, "status");
1699 if (!dbus_message_get_args(
1702 DBUS_TYPE_STRING, &name,
1704 return bus_send_error_reply(connection, message, &error, -EINVAL);
1706 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1708 return bus_send_error_reply(connection, message, NULL, state);
1710 s = unit_file_state_to_string(state);
1713 reply = dbus_message_new_method_return(message);
1717 if (!dbus_message_append_args(
1719 DBUS_TYPE_STRING, &s,
1722 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1723 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1724 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1725 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1726 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1729 DBusMessageIter iter;
1730 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1731 UnitFileChange *changes = NULL;
1732 unsigned n_changes = 0;
1733 dbus_bool_t runtime, force;
1734 int carries_install_info = -1;
1736 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1738 if (!dbus_message_iter_init(message, &iter))
1741 r = bus_parse_strv_iter(&iter, &l);
1746 return bus_send_error_reply(connection, message, NULL, r);
1749 if (!dbus_message_iter_next(&iter) ||
1750 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1751 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1753 return bus_send_error_reply(connection, message, NULL, -EIO);
1756 if (streq(member, "EnableUnitFiles")) {
1757 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1758 carries_install_info = r;
1759 } else if (streq(member, "ReenableUnitFiles")) {
1760 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1761 carries_install_info = r;
1762 } else if (streq(member, "LinkUnitFiles"))
1763 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1764 else if (streq(member, "PresetUnitFiles")) {
1765 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1766 carries_install_info = r;
1767 } else if (streq(member, "MaskUnitFiles"))
1768 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1770 assert_not_reached("Uh? Wrong method");
1773 bus_manager_send_unit_files_changed(m);
1776 unit_file_changes_free(changes, n_changes);
1777 return bus_send_error_reply(connection, message, NULL, r);
1780 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1781 unit_file_changes_free(changes, n_changes);
1786 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1787 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1790 DBusMessageIter iter;
1791 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1792 UnitFileChange *changes = NULL;
1793 unsigned n_changes = 0;
1794 dbus_bool_t runtime;
1796 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1798 if (!dbus_message_iter_init(message, &iter))
1801 r = bus_parse_strv_iter(&iter, &l);
1806 return bus_send_error_reply(connection, message, NULL, r);
1809 if (!dbus_message_iter_next(&iter) ||
1810 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1812 return bus_send_error_reply(connection, message, NULL, -EIO);
1815 if (streq(member, "DisableUnitFiles"))
1816 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1817 else if (streq(member, "UnmaskUnitFiles"))
1818 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1820 assert_not_reached("Uh? Wrong method");
1823 bus_manager_send_unit_files_changed(m);
1826 unit_file_changes_free(changes, n_changes);
1827 return bus_send_error_reply(connection, message, NULL, r);
1830 reply = message_from_file_changes(message, changes, n_changes, -1);
1831 unit_file_changes_free(changes, n_changes);
1837 const BusBoundProperties bps[] = {
1838 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1839 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1843 SELINUX_ACCESS_CHECK(connection, message, "status");
1845 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1848 if (job_type != _JOB_TYPE_INVALID) {
1849 const char *name, *smode, *old_name = NULL;
1854 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1855 b = dbus_message_get_args(
1858 DBUS_TYPE_STRING, &old_name,
1859 DBUS_TYPE_STRING, &name,
1860 DBUS_TYPE_STRING, &smode,
1863 b = dbus_message_get_args(
1866 DBUS_TYPE_STRING, &name,
1867 DBUS_TYPE_STRING, &smode,
1870 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 u = manager_get_unit(m, old_name);
1874 if (!u || !u->job || u->job->type != JOB_START) {
1875 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1876 return bus_send_error_reply(connection, message, &error, -ENOENT);
1880 mode = job_mode_from_string(smode);
1882 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1883 return bus_send_error_reply(connection, message, &error, -EINVAL);
1886 r = manager_load_unit(m, name, NULL, &error, &u);
1888 return bus_send_error_reply(connection, message, &error, r);
1890 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1894 if (!dbus_connection_send(connection, reply, NULL))
1897 return DBUS_HANDLER_RESULT_HANDLED;
1900 dbus_error_free(&error);
1902 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1905 const DBusObjectPathVTable bus_manager_vtable = {
1906 .message_function = bus_manager_message_handler