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=\"SetUnitControlGroup\">\n" \
107 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
109 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
111 " <method name=\"UnsetUnitControlGroup\">\n" \
112 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
113 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
114 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
116 " <method name=\"GetUnitControlGroupAttribute\">\n" \
117 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
119 " <arg name=\"values\" type=\"as\" direction=\"out\"/>\n" \
121 " <method name=\"SetUnitControlGroupAttribute\">\n" \
122 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
123 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
124 " <arg name=\"values\" type=\"as\" direction=\"in\"/>\n" \
125 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
127 " <method name=\"UnsetUnitControlGroupAttributes\">\n" \
128 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
129 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
132 " <method name=\"GetJob\">\n" \
133 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
134 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
136 " <method name=\"CancelJob\">\n" \
137 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
139 " <method name=\"ClearJobs\"/>\n" \
140 " <method name=\"ResetFailed\"/>\n" \
141 " <method name=\"ListUnits\">\n" \
142 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
144 " <method name=\"ListJobs\">\n" \
145 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
147 " <method name=\"Subscribe\"/>\n" \
148 " <method name=\"Unsubscribe\"/>\n" \
149 " <method name=\"Dump\">\n" \
150 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
152 " <method name=\"CreateSnapshot\">\n" \
153 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
154 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
155 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
157 " <method name=\"RemoveSnapshot\">\n" \
158 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
160 " <method name=\"Reload\"/>\n" \
161 " <method name=\"Reexecute\"/>\n" \
162 " <method name=\"Exit\"/>\n" \
163 " <method name=\"Reboot\"/>\n" \
164 " <method name=\"PowerOff\"/>\n" \
165 " <method name=\"Halt\"/>\n" \
166 " <method name=\"KExec\"/>\n" \
167 " <method name=\"SwitchRoot\">\n" \
168 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
171 " <method name=\"SetEnvironment\">\n" \
172 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
174 " <method name=\"UnsetEnvironment\">\n" \
175 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
177 " <method name=\"UnsetAndSetEnvironment\">\n" \
178 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
179 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
181 " <method name=\"ListUnitFiles\">\n" \
182 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
184 " <method name=\"GetUnitFileState\">\n" \
185 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
186 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
188 " <method name=\"EnableUnitFiles\">\n" \
189 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
190 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
191 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
192 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
193 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
195 " <method name=\"DisableUnitFiles\">\n" \
196 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
197 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
198 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
200 " <method name=\"ReenableUnitFiles\">\n" \
201 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
202 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
203 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
204 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
205 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
207 " <method name=\"LinkUnitFiles\">\n" \
208 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
209 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
210 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
211 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
213 " <method name=\"PresetUnitFiles\">\n" \
214 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
215 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
216 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
217 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
218 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
220 " <method name=\"MaskUnitFiles\">\n" \
221 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
222 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
223 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
224 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
226 " <method name=\"UnmaskUnitFiles\">\n" \
227 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
228 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
229 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
231 " <method name=\"SetDefaultTarget\">\n" \
232 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
233 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
235 " <method name=\"GetDefaultTarget\">\n" \
236 " <arg name=\"name\" type=\"s\" direction=\"out\"/>\n" \
239 #define BUS_MANAGER_INTERFACE_SIGNALS \
240 " <signal name=\"UnitNew\">\n" \
241 " <arg name=\"id\" type=\"s\"/>\n" \
242 " <arg name=\"unit\" type=\"o\"/>\n" \
244 " <signal name=\"UnitRemoved\">\n" \
245 " <arg name=\"id\" type=\"s\"/>\n" \
246 " <arg name=\"unit\" type=\"o\"/>\n" \
248 " <signal name=\"JobNew\">\n" \
249 " <arg name=\"id\" type=\"u\"/>\n" \
250 " <arg name=\"job\" type=\"o\"/>\n" \
251 " <arg name=\"unit\" type=\"s\"/>\n" \
253 " <signal name=\"JobRemoved\">\n" \
254 " <arg name=\"id\" type=\"u\"/>\n" \
255 " <arg name=\"job\" type=\"o\"/>\n" \
256 " <arg name=\"unit\" type=\"s\"/>\n" \
257 " <arg name=\"result\" type=\"s\"/>\n" \
259 " <signal name=\"StartupFinished\">\n" \
260 " <arg name=\"firmware\" type=\"t\"/>\n" \
261 " <arg name=\"loader\" type=\"t\"/>\n" \
262 " <arg name=\"kernel\" type=\"t\"/>\n" \
263 " <arg name=\"initrd\" type=\"t\"/>\n" \
264 " <arg name=\"userspace\" type=\"t\"/>\n" \
265 " <arg name=\"total\" type=\"t\"/>\n" \
267 " <signal name=\"UnitFilesChanged\"/>\n"
269 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
270 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
271 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
272 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
273 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
274 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
275 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
276 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
277 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
278 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
279 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
280 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
281 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
282 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
283 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
284 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
285 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
286 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
287 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
288 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
289 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
290 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
291 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
292 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
293 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
294 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
295 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
296 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
297 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
298 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
299 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
300 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
301 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
302 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
304 #define BUS_MANAGER_INTERFACE_END \
307 #define BUS_MANAGER_INTERFACE \
308 BUS_MANAGER_INTERFACE_BEGIN \
309 BUS_MANAGER_INTERFACE_METHODS \
310 BUS_MANAGER_INTERFACE_SIGNALS \
311 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
312 BUS_MANAGER_INTERFACE_END
314 #define INTROSPECTION_BEGIN \
315 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
317 BUS_MANAGER_INTERFACE \
318 BUS_PROPERTIES_INTERFACE \
320 BUS_INTROSPECTABLE_INTERFACE
322 #define INTROSPECTION_END \
325 #define INTERFACES_LIST \
326 BUS_GENERIC_INTERFACES_LIST \
327 "org.freedesktop.systemd1.Manager\0"
329 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
331 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
333 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
336 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
343 e = stpcpy(e, "split-usr:");
345 if (readlink_malloc("/etc/mtab", &p) < 0)
346 e = stpcpy(e, "mtab-not-symlink:");
350 if (access("/proc/cgroups", F_OK) < 0)
351 e = stpcpy(e, "cgroups-missing:");
353 if (hwclock_is_localtime() > 0)
354 e = stpcpy(e, "local-hwclock:");
356 /* remove the last ':' */
362 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
368 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
374 t = log_target_to_string(log_get_target());
376 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
382 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
388 dbus_message_iter_get_basic(i, &t);
390 return log_set_target_from_string(t);
393 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
400 r = log_level_to_string_alloc(log_get_max_level(), &t);
404 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
411 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
417 dbus_message_iter_get_basic(i, &t);
419 return log_set_max_level_from_string(t);
422 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
430 u = hashmap_size(m->units);
432 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
438 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
446 u = hashmap_size(m->jobs);
448 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
454 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
462 if (dual_timestamp_is_set(&m->finish_timestamp))
465 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
467 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
473 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
481 detect_virtualization(&id);
483 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
489 static DBusMessage *message_from_file_changes(
491 UnitFileChange *changes,
493 int carries_install_info) {
495 DBusMessageIter iter, sub, sub2;
499 reply = dbus_message_new_method_return(m);
503 dbus_message_iter_init_append(reply, &iter);
505 if (carries_install_info >= 0) {
508 b = !!carries_install_info;
509 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
513 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
516 for (i = 0; i < n_changes; i++) {
517 const char *type, *path, *source;
519 type = unit_file_change_type_to_string(changes[i].type);
520 path = strempty(changes[i].path);
521 source = strempty(changes[i].source);
523 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
524 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
525 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
526 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
527 !dbus_message_iter_close_container(&sub, &sub2))
531 if (!dbus_message_iter_close_container(&iter, &sub))
537 dbus_message_unref(reply);
541 static int bus_manager_send_unit_files_changed(Manager *m) {
545 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
549 r = bus_broadcast(m, s);
550 dbus_message_unref(s);
555 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
561 dbus_message_iter_get_basic(i, t);
563 return watchdog_set_timeout(t);
566 static const char systemd_property_string[] =
570 static const BusProperty bus_systemd_properties[] = {
571 { "Version", bus_property_append_string, "s", 0 },
572 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
576 static const BusProperty bus_manager_properties[] = {
577 { "Tainted", bus_manager_append_tainted, "s", 0 },
578 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
579 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
580 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
581 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
582 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
583 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
584 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
585 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
586 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
587 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
588 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
589 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
590 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
591 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
592 { "NNames", bus_manager_append_n_names, "u", 0 },
593 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
594 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
595 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
596 { "Progress", bus_manager_append_progress, "d", 0 },
597 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
598 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
599 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
600 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
601 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
602 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
603 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
604 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
605 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
606 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
607 { "Virtualization", bus_manager_append_virt, "s", 0, },
611 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
612 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
613 _cleanup_free_ char * path = NULL;
617 JobType job_type = _JOB_TYPE_INVALID;
618 bool reload_if_possible = false;
625 dbus_error_init(&error);
627 member = dbus_message_get_member(message);
629 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
633 if (!dbus_message_get_args(
636 DBUS_TYPE_STRING, &name,
638 return bus_send_error_reply(connection, message, &error, -EINVAL);
640 u = manager_get_unit(m, name);
642 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
643 return bus_send_error_reply(connection, message, &error, -ENOENT);
646 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
648 reply = dbus_message_new_method_return(message);
652 path = unit_dbus_path(u);
656 if (!dbus_message_append_args(
658 DBUS_TYPE_OBJECT_PATH, &path,
661 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
665 if (!dbus_message_get_args(
668 DBUS_TYPE_UINT32, &pid,
670 return bus_send_error_reply(connection, message, &error, -EINVAL);
672 u = cgroup_unit_by_pid(m, (pid_t) pid);
674 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
675 return bus_send_error_reply(connection, message, &error, -ENOENT);
678 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
680 reply = dbus_message_new_method_return(message);
684 path = unit_dbus_path(u);
688 if (!dbus_message_append_args(
690 DBUS_TYPE_OBJECT_PATH, &path,
693 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
697 if (!dbus_message_get_args(
700 DBUS_TYPE_STRING, &name,
702 return bus_send_error_reply(connection, message, &error, -EINVAL);
704 r = manager_load_unit(m, name, NULL, &error, &u);
706 return bus_send_error_reply(connection, message, &error, r);
708 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
710 reply = dbus_message_new_method_return(message);
714 path = unit_dbus_path(u);
718 if (!dbus_message_append_args(
720 DBUS_TYPE_OBJECT_PATH, &path,
724 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
725 job_type = JOB_START;
726 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
727 job_type = JOB_START;
728 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
730 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
731 job_type = JOB_RELOAD;
732 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
733 job_type = JOB_RESTART;
734 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
735 job_type = JOB_TRY_RESTART;
736 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
737 reload_if_possible = true;
738 job_type = JOB_RESTART;
739 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
740 reload_if_possible = true;
741 job_type = JOB_TRY_RESTART;
742 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
743 const char *name, *swho;
748 if (!dbus_message_get_args(
751 DBUS_TYPE_STRING, &name,
752 DBUS_TYPE_STRING, &swho,
753 DBUS_TYPE_INT32, &signo,
755 return bus_send_error_reply(connection, message, &error, -EINVAL);
760 who = kill_who_from_string(swho);
762 return bus_send_error_reply(connection, message, &error, -EINVAL);
765 if (signo <= 0 || signo >= _NSIG)
766 return bus_send_error_reply(connection, message, &error, -EINVAL);
768 u = manager_get_unit(m, name);
770 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
771 return bus_send_error_reply(connection, message, &error, -ENOENT);
774 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
776 r = unit_kill(u, who, signo, &error);
778 return bus_send_error_reply(connection, message, &error, r);
780 reply = dbus_message_new_method_return(message);
784 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
788 if (!dbus_message_get_args(
791 DBUS_TYPE_UINT32, &id,
793 return bus_send_error_reply(connection, message, &error, -EINVAL);
795 j = manager_get_job(m, id);
797 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
798 return bus_send_error_reply(connection, message, &error, -ENOENT);
801 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
803 reply = dbus_message_new_method_return(message);
807 path = job_dbus_path(j);
811 if (!dbus_message_append_args(
813 DBUS_TYPE_OBJECT_PATH, &path,
817 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
821 if (!dbus_message_get_args(
824 DBUS_TYPE_UINT32, &id,
826 return bus_send_error_reply(connection, message, &error, -EINVAL);
828 j = manager_get_job(m, id);
830 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
831 return bus_send_error_reply(connection, message, &error, -ENOENT);
834 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
835 job_finish_and_invalidate(j, JOB_CANCELED, true);
837 reply = dbus_message_new_method_return(message);
841 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
843 SELINUX_ACCESS_CHECK(connection, message, "reboot");
844 manager_clear_jobs(m);
846 reply = dbus_message_new_method_return(message);
850 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
852 SELINUX_ACCESS_CHECK(connection, message, "reload");
854 manager_reset_failed(m);
856 reply = dbus_message_new_method_return(message);
860 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
864 if (!dbus_message_get_args(
867 DBUS_TYPE_STRING, &name,
869 return bus_send_error_reply(connection, message, &error, -EINVAL);
871 u = manager_get_unit(m, name);
873 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
874 return bus_send_error_reply(connection, message, &error, -ENOENT);
877 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
879 unit_reset_failed(u);
881 reply = dbus_message_new_method_return(message);
885 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroup")) {
888 DBusMessageIter iter;
890 if (!dbus_message_iter_init(message, &iter))
893 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
895 return bus_send_error_reply(connection, message, NULL, r);
897 u = manager_get_unit(m, name);
899 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
900 return bus_send_error_reply(connection, message, &error, -ENOENT);
903 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
905 r = bus_unit_cgroup_set(u, &iter);
907 return bus_send_error_reply(connection, message, NULL, r);
909 reply = dbus_message_new_method_return(message);
913 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroup")) {
916 DBusMessageIter iter;
918 if (!dbus_message_iter_init(message, &iter))
921 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
923 return bus_send_error_reply(connection, message, NULL, r);
925 u = manager_get_unit(m, name);
927 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
928 return bus_send_error_reply(connection, message, &error, -ENOENT);
931 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
933 r = bus_unit_cgroup_unset(u, &iter);
935 return bus_send_error_reply(connection, message, NULL, r);
937 reply = dbus_message_new_method_return(message);
941 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttribute")) {
944 DBusMessageIter iter;
946 if (!dbus_message_iter_init(message, &iter))
949 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
951 return bus_send_error_reply(connection, message, NULL, r);
953 u = manager_get_unit(m, name);
955 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
956 return bus_send_error_reply(connection, message, &error, -ENOENT);
959 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
961 r = bus_unit_cgroup_attribute_set(u, &iter);
963 return bus_send_error_reply(connection, message, NULL, r);
965 reply = dbus_message_new_method_return(message);
969 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttribute")) {
972 DBusMessageIter iter;
974 if (!dbus_message_iter_init(message, &iter))
977 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
979 return bus_send_error_reply(connection, message, NULL, r);
981 u = manager_get_unit(m, name);
983 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
984 return bus_send_error_reply(connection, message, &error, -ENOENT);
987 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
989 r = bus_unit_cgroup_attribute_unset(u, &iter);
991 return bus_send_error_reply(connection, message, NULL, r);
993 reply = dbus_message_new_method_return(message);
997 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttribute")) {
1000 DBusMessageIter iter;
1001 _cleanup_strv_free_ char **list = NULL;
1003 if (!dbus_message_iter_init(message, &iter))
1006 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
1008 return bus_send_error_reply(connection, message, NULL, r);
1010 u = manager_get_unit(m, name);
1012 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1013 return bus_send_error_reply(connection, message, &error, -ENOENT);
1016 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
1018 r = bus_unit_cgroup_attribute_get(u, &iter, &list);
1020 return bus_send_error_reply(connection, message, NULL, r);
1022 reply = dbus_message_new_method_return(message);
1026 dbus_message_iter_init_append(reply, &iter);
1027 if (bus_append_strv_iter(&iter, list) < 0)
1030 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
1031 DBusMessageIter iter, sub;
1036 SELINUX_ACCESS_CHECK(connection, message, "status");
1038 reply = dbus_message_new_method_return(message);
1042 dbus_message_iter_init_append(reply, &iter);
1044 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
1047 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1048 char *u_path, *j_path;
1049 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
1050 DBusMessageIter sub2;
1057 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1060 description = unit_description(u);
1061 load_state = unit_load_state_to_string(u->load_state);
1062 active_state = unit_active_state_to_string(unit_active_state(u));
1063 sub_state = unit_sub_state_to_string(u);
1065 f = unit_following(u);
1066 following = f ? f->id : "";
1068 u_path = unit_dbus_path(u);
1073 job_id = (uint32_t) u->job->id;
1075 if (!(j_path = job_dbus_path(u->job))) {
1080 sjob_type = job_type_to_string(u->job->type);
1087 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
1088 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
1089 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
1090 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
1091 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
1092 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
1093 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
1094 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
1095 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
1096 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
1107 if (!dbus_message_iter_close_container(&sub, &sub2))
1111 if (!dbus_message_iter_close_container(&iter, &sub))
1114 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
1115 DBusMessageIter iter, sub;
1119 SELINUX_ACCESS_CHECK(connection, message, "status");
1121 reply = dbus_message_new_method_return(message);
1125 dbus_message_iter_init_append(reply, &iter);
1127 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1130 HASHMAP_FOREACH(j, m->jobs, i) {
1131 char *u_path, *j_path;
1132 const char *state, *type;
1134 DBusMessageIter sub2;
1136 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1139 id = (uint32_t) j->id;
1140 state = job_state_to_string(j->state);
1141 type = job_type_to_string(j->type);
1143 j_path = job_dbus_path(j);
1147 u_path = unit_dbus_path(j->unit);
1153 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1154 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1155 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1156 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1157 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1158 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1167 if (!dbus_message_iter_close_container(&sub, &sub2))
1171 if (!dbus_message_iter_close_container(&iter, &sub))
1174 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1178 SELINUX_ACCESS_CHECK(connection, message, "status");
1180 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1182 s = set_new(string_hash_func, string_compare_func);
1186 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1192 client = strdup(bus_message_get_sender_with_fallback(message));
1196 r = set_consume(s, client);
1198 return bus_send_error_reply(connection, message, NULL, r);
1200 reply = dbus_message_new_method_return(message);
1204 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1207 SELINUX_ACCESS_CHECK(connection, message, "status");
1209 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1211 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1212 return bus_send_error_reply(connection, message, &error, -ENOENT);
1217 reply = dbus_message_new_method_return(message);
1221 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1226 SELINUX_ACCESS_CHECK(connection, message, "status");
1228 reply = dbus_message_new_method_return(message);
1232 f = open_memstream(&dump, &size);
1236 manager_dump_units(m, f, NULL);
1237 manager_dump_jobs(m, f, NULL);
1247 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1253 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1255 dbus_bool_t cleanup;
1258 SELINUX_ACCESS_CHECK(connection, message, "start");
1260 if (!dbus_message_get_args(
1263 DBUS_TYPE_STRING, &name,
1264 DBUS_TYPE_BOOLEAN, &cleanup,
1266 return bus_send_error_reply(connection, message, &error, -EINVAL);
1271 r = snapshot_create(m, name, cleanup, &error, &s);
1273 return bus_send_error_reply(connection, message, &error, r);
1275 reply = dbus_message_new_method_return(message);
1279 path = unit_dbus_path(UNIT(s));
1283 if (!dbus_message_append_args(
1285 DBUS_TYPE_OBJECT_PATH, &path,
1289 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1293 if (!dbus_message_get_args(
1296 DBUS_TYPE_STRING, &name,
1298 return bus_send_error_reply(connection, message, &error, -EINVAL);
1300 u = manager_get_unit(m, name);
1302 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1303 return bus_send_error_reply(connection, message, &error, -ENOENT);
1306 if (u->type != UNIT_SNAPSHOT) {
1307 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1308 return bus_send_error_reply(connection, message, &error, -ENOENT);
1311 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1312 snapshot_remove(SNAPSHOT(u));
1314 reply = dbus_message_new_method_return(message);
1318 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1319 char *introspection = NULL;
1327 SELINUX_ACCESS_CHECK(connection, message, "status");
1329 reply = dbus_message_new_method_return(message);
1333 /* We roll our own introspection code here, instead of
1334 * relying on bus_default_message_handler() because we
1335 * need to generate our introspection string
1338 f = open_memstream(&introspection, &size);
1342 fputs(INTROSPECTION_BEGIN, f);
1344 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1350 p = bus_path_escape(k);
1353 free(introspection);
1357 fprintf(f, "<node name=\"unit/%s\"/>", p);
1361 HASHMAP_FOREACH(j, m->jobs, i)
1362 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1364 fputs(INTROSPECTION_END, f);
1368 free(introspection);
1377 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1378 free(introspection);
1382 free(introspection);
1384 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1386 SELINUX_ACCESS_CHECK(connection, message, "reload");
1388 assert(!m->queued_message);
1390 /* Instead of sending the reply back right away, we
1391 * just remember that we need to and then send it
1392 * after the reload is finished. That way the caller
1393 * knows when the reload finished. */
1395 m->queued_message = dbus_message_new_method_return(message);
1396 if (!m->queued_message)
1399 m->queued_message_connection = connection;
1400 m->exit_code = MANAGER_RELOAD;
1402 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1404 SELINUX_ACCESS_CHECK(connection, message, "reload");
1406 /* We don't send a reply back here, the client should
1407 * just wait for us disconnecting. */
1409 m->exit_code = MANAGER_REEXECUTE;
1411 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1413 SELINUX_ACCESS_CHECK(connection, message, "halt");
1415 if (m->running_as == SYSTEMD_SYSTEM) {
1416 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1417 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1420 reply = dbus_message_new_method_return(message);
1424 m->exit_code = MANAGER_EXIT;
1426 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1428 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1430 if (m->running_as != SYSTEMD_SYSTEM) {
1431 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1432 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1435 reply = dbus_message_new_method_return(message);
1439 m->exit_code = MANAGER_REBOOT;
1441 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1443 SELINUX_ACCESS_CHECK(connection, message, "halt");
1445 if (m->running_as != SYSTEMD_SYSTEM) {
1446 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1447 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1450 reply = dbus_message_new_method_return(message);
1454 m->exit_code = MANAGER_POWEROFF;
1456 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1458 SELINUX_ACCESS_CHECK(connection, message, "halt");
1460 if (m->running_as != SYSTEMD_SYSTEM) {
1461 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1462 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1465 reply = dbus_message_new_method_return(message);
1469 m->exit_code = MANAGER_HALT;
1471 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1473 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1475 if (m->running_as != SYSTEMD_SYSTEM) {
1476 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1477 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1480 reply = dbus_message_new_method_return(message);
1484 m->exit_code = MANAGER_KEXEC;
1486 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1487 const char *switch_root, *switch_root_init;
1491 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1493 if (!dbus_message_get_args(
1496 DBUS_TYPE_STRING, &switch_root,
1497 DBUS_TYPE_STRING, &switch_root_init,
1499 return bus_send_error_reply(connection, message, &error, -EINVAL);
1501 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1502 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1504 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1505 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1507 if (m->running_as != SYSTEMD_SYSTEM) {
1508 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1509 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1513 if (isempty(switch_root_init)) {
1514 good = path_is_os_tree(switch_root);
1516 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1519 _cleanup_free_ char *p = NULL;
1521 p = strjoin(switch_root, "/", switch_root_init, NULL);
1525 good = access(p, X_OK) >= 0;
1527 log_error("Not switching root: cannot execute new init %s", p);
1530 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1532 u = strdup(switch_root);
1536 if (!isempty(switch_root_init)) {
1537 v = strdup(switch_root_init);
1545 free(m->switch_root);
1546 free(m->switch_root_init);
1548 m->switch_root_init = v;
1550 reply = dbus_message_new_method_return(message);
1554 m->exit_code = MANAGER_SWITCH_ROOT;
1556 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1557 _cleanup_strv_free_ char **l = NULL;
1560 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1562 r = bus_parse_strv(message, &l);
1566 return bus_send_error_reply(connection, message, NULL, r);
1567 if (!strv_env_is_valid(l))
1568 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1570 e = strv_env_merge(2, m->environment, l);
1574 reply = dbus_message_new_method_return(message);
1580 strv_free(m->environment);
1583 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1584 _cleanup_strv_free_ char **l = NULL;
1587 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1589 r = bus_parse_strv(message, &l);
1593 return bus_send_error_reply(connection, message, NULL, r);
1594 if (!strv_env_name_or_assignment_is_valid(l))
1595 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1597 e = strv_env_delete(m->environment, 1, l);
1601 reply = dbus_message_new_method_return(message);
1607 strv_free(m->environment);
1610 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1611 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1613 DBusMessageIter iter;
1615 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1617 if (!dbus_message_iter_init(message, &iter))
1620 r = bus_parse_strv_iter(&iter, &l_unset);
1624 return bus_send_error_reply(connection, message, NULL, r);
1625 if (!strv_env_name_or_assignment_is_valid(l_unset))
1626 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1628 if (!dbus_message_iter_next(&iter))
1629 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1631 r = bus_parse_strv_iter(&iter, &l_set);
1635 return bus_send_error_reply(connection, message, NULL, r);
1636 if (!strv_env_is_valid(l_set))
1637 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1639 e = strv_env_delete(m->environment, 1, l_unset);
1643 f = strv_env_merge(2, e, l_set);
1647 reply = dbus_message_new_method_return(message);
1653 strv_free(m->environment);
1655 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1656 DBusMessageIter iter, sub, sub2;
1661 SELINUX_ACCESS_CHECK(connection, message, "status");
1663 reply = dbus_message_new_method_return(message);
1667 h = hashmap_new(string_hash_func, string_compare_func);
1671 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1673 unit_file_list_free(h);
1674 return bus_send_error_reply(connection, message, NULL, r);
1677 dbus_message_iter_init_append(reply, &iter);
1679 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1680 unit_file_list_free(h);
1684 HASHMAP_FOREACH(item, h, i) {
1687 state = unit_file_state_to_string(item->state);
1690 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1691 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1692 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1693 !dbus_message_iter_close_container(&sub, &sub2)) {
1694 unit_file_list_free(h);
1699 unit_file_list_free(h);
1701 if (!dbus_message_iter_close_container(&iter, &sub))
1704 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1706 UnitFileState state;
1709 SELINUX_ACCESS_CHECK(connection, message, "status");
1711 if (!dbus_message_get_args(
1714 DBUS_TYPE_STRING, &name,
1716 return bus_send_error_reply(connection, message, &error, -EINVAL);
1718 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1720 return bus_send_error_reply(connection, message, NULL, state);
1722 s = unit_file_state_to_string(state);
1725 reply = dbus_message_new_method_return(message);
1729 if (!dbus_message_append_args(
1731 DBUS_TYPE_STRING, &s,
1734 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1735 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1736 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1737 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1738 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1739 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1742 DBusMessageIter iter;
1743 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1744 UnitFileChange *changes = NULL;
1745 unsigned n_changes = 0;
1746 dbus_bool_t runtime, force;
1747 int carries_install_info = -1;
1749 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1751 if (!dbus_message_iter_init(message, &iter))
1754 r = bus_parse_strv_iter(&iter, &l);
1759 return bus_send_error_reply(connection, message, NULL, r);
1762 if (!dbus_message_iter_next(&iter) ||
1763 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1764 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1766 return bus_send_error_reply(connection, message, NULL, -EIO);
1769 if (streq(member, "EnableUnitFiles")) {
1770 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1771 carries_install_info = r;
1772 } else if (streq(member, "ReenableUnitFiles")) {
1773 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1774 carries_install_info = r;
1775 } else if (streq(member, "LinkUnitFiles"))
1776 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1777 else if (streq(member, "PresetUnitFiles")) {
1778 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1779 carries_install_info = r;
1780 } else if (streq(member, "MaskUnitFiles"))
1781 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1782 else if (streq(member, "SetDefaultTarget"))
1783 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1785 assert_not_reached("Uh? Wrong method");
1788 bus_manager_send_unit_files_changed(m);
1791 unit_file_changes_free(changes, n_changes);
1792 return bus_send_error_reply(connection, message, NULL, r);
1795 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1796 unit_file_changes_free(changes, n_changes);
1801 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1802 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1805 DBusMessageIter iter;
1806 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1807 UnitFileChange *changes = NULL;
1808 unsigned n_changes = 0;
1809 dbus_bool_t runtime;
1811 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1813 if (!dbus_message_iter_init(message, &iter))
1816 r = bus_parse_strv_iter(&iter, &l);
1821 return bus_send_error_reply(connection, message, NULL, r);
1824 if (!dbus_message_iter_next(&iter) ||
1825 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1827 return bus_send_error_reply(connection, message, NULL, -EIO);
1830 if (streq(member, "DisableUnitFiles"))
1831 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1832 else if (streq(member, "UnmaskUnitFiles"))
1833 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1835 assert_not_reached("Uh? Wrong method");
1838 bus_manager_send_unit_files_changed(m);
1841 unit_file_changes_free(changes, n_changes);
1842 return bus_send_error_reply(connection, message, NULL, r);
1845 reply = message_from_file_changes(message, changes, n_changes, -1);
1846 unit_file_changes_free(changes, n_changes);
1851 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1852 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1853 _cleanup_free_ char *default_target = NULL;
1855 reply = dbus_message_new_method_return(message);
1859 r = unit_file_get_default(scope, NULL, &default_target);
1862 return bus_send_error_reply(connection, message, NULL, r);
1864 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1868 const BusBoundProperties bps[] = {
1869 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1870 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1874 SELINUX_ACCESS_CHECK(connection, message, "status");
1876 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1879 if (job_type != _JOB_TYPE_INVALID) {
1880 const char *name, *smode, *old_name = NULL;
1885 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1886 b = dbus_message_get_args(
1889 DBUS_TYPE_STRING, &old_name,
1890 DBUS_TYPE_STRING, &name,
1891 DBUS_TYPE_STRING, &smode,
1894 b = dbus_message_get_args(
1897 DBUS_TYPE_STRING, &name,
1898 DBUS_TYPE_STRING, &smode,
1901 return bus_send_error_reply(connection, message, &error, -EINVAL);
1904 u = manager_get_unit(m, old_name);
1905 if (!u || !u->job || u->job->type != JOB_START) {
1906 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1907 return bus_send_error_reply(connection, message, &error, -ENOENT);
1911 mode = job_mode_from_string(smode);
1913 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1914 return bus_send_error_reply(connection, message, &error, -EINVAL);
1917 r = manager_load_unit(m, name, NULL, &error, &u);
1919 return bus_send_error_reply(connection, message, &error, r);
1921 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1925 if (!bus_maybe_send_reply(connection, message, reply))
1928 return DBUS_HANDLER_RESULT_HANDLED;
1931 dbus_error_free(&error);
1933 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1936 const DBusObjectPathVTable bus_manager_vtable = {
1937 .message_function = bus_manager_message_handler