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"
40 #define BUS_MANAGER_INTERFACE_BEGIN \
41 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
43 #define BUS_MANAGER_INTERFACE_METHODS \
44 " <method name=\"GetUnit\">\n" \
45 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
46 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
48 " <method name=\"GetUnitByPID\">\n" \
49 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
50 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
52 " <method name=\"LoadUnit\">\n" \
53 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
54 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
56 " <method name=\"StartUnit\">\n" \
57 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
58 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
59 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
61 " <method name=\"StartUnitReplace\">\n" \
62 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
63 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
67 " <method name=\"StopUnit\">\n" \
68 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
72 " <method name=\"ReloadUnit\">\n" \
73 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
77 " <method name=\"RestartUnit\">\n" \
78 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
82 " <method name=\"TryRestartUnit\">\n" \
83 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
87 " <method name=\"ReloadOrRestartUnit\">\n" \
88 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
89 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
92 " <method name=\"ReloadOrTryRestartUnit\">\n" \
93 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
94 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
97 " <method name=\"KillUnit\">\n" \
98 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
99 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
100 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
102 " <method name=\"ResetFailedUnit\">\n" \
103 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
105 " <method name=\"SetUnitControlGroups\">\n" \
106 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
107 " <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n" \
108 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
110 " <method name=\"UnsetUnitControlGroups\">\n" \
111 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
112 " <arg name=\"groups\" type=\"as\" direction=\"in\"/>\n" \
113 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
115 " <method name=\"SetUnitControlGroupAttributes\">\n" \
116 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
117 " <arg name=\"attributes\" type=\"a(sss)\" direction=\"in\"/>\n" \
118 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
120 " <method name=\"UnsetUnitControlGroupAttributes\">\n" \
121 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
122 " <arg name=\"attributes\" type=\"a(ss)\" direction=\"in\"/>\n" \
123 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
125 " <method name=\"GetJob\">\n" \
126 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
127 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
129 " <method name=\"CancelJob\">\n" \
130 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
132 " <method name=\"ClearJobs\"/>\n" \
133 " <method name=\"ResetFailed\"/>\n" \
134 " <method name=\"ListUnits\">\n" \
135 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
137 " <method name=\"ListJobs\">\n" \
138 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
140 " <method name=\"Subscribe\"/>\n" \
141 " <method name=\"Unsubscribe\"/>\n" \
142 " <method name=\"Dump\">\n" \
143 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
145 " <method name=\"CreateSnapshot\">\n" \
146 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
147 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
148 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
150 " <method name=\"RemoveSnapshot\">\n" \
151 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
153 " <method name=\"Reload\"/>\n" \
154 " <method name=\"Reexecute\"/>\n" \
155 " <method name=\"Exit\"/>\n" \
156 " <method name=\"Reboot\"/>\n" \
157 " <method name=\"PowerOff\"/>\n" \
158 " <method name=\"Halt\"/>\n" \
159 " <method name=\"KExec\"/>\n" \
160 " <method name=\"SwitchRoot\">\n" \
161 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
162 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
164 " <method name=\"SetEnvironment\">\n" \
165 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
167 " <method name=\"UnsetEnvironment\">\n" \
168 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
170 " <method name=\"UnsetAndSetEnvironment\">\n" \
171 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
172 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
174 " <method name=\"ListUnitFiles\">\n" \
175 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
177 " <method name=\"GetUnitFileState\">\n" \
178 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
179 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
181 " <method name=\"EnableUnitFiles\">\n" \
182 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
183 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
184 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
185 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
186 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
188 " <method name=\"DisableUnitFiles\">\n" \
189 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
190 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
191 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
193 " <method name=\"ReenableUnitFiles\">\n" \
194 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
195 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
196 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
197 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
198 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
200 " <method name=\"LinkUnitFiles\">\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=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
206 " <method name=\"PresetUnitFiles\">\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=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
211 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
213 " <method name=\"MaskUnitFiles\">\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=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
219 " <method name=\"UnmaskUnitFiles\">\n" \
220 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
221 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
222 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
225 #define BUS_MANAGER_INTERFACE_SIGNALS \
226 " <signal name=\"UnitNew\">\n" \
227 " <arg name=\"id\" type=\"s\"/>\n" \
228 " <arg name=\"unit\" type=\"o\"/>\n" \
230 " <signal name=\"UnitRemoved\">\n" \
231 " <arg name=\"id\" type=\"s\"/>\n" \
232 " <arg name=\"unit\" type=\"o\"/>\n" \
234 " <signal name=\"JobNew\">\n" \
235 " <arg name=\"id\" type=\"u\"/>\n" \
236 " <arg name=\"job\" type=\"o\"/>\n" \
237 " <arg name=\"unit\" type=\"s\"/>\n" \
239 " <signal name=\"JobRemoved\">\n" \
240 " <arg name=\"id\" type=\"u\"/>\n" \
241 " <arg name=\"job\" type=\"o\"/>\n" \
242 " <arg name=\"unit\" type=\"s\"/>\n" \
243 " <arg name=\"result\" type=\"s\"/>\n" \
245 " <signal name=\"StartupFinished\">\n" \
246 " <arg name=\"firmware\" type=\"t\"/>\n" \
247 " <arg name=\"loader\" type=\"t\"/>\n" \
248 " <arg name=\"kernel\" type=\"t\"/>\n" \
249 " <arg name=\"initrd\" type=\"t\"/>\n" \
250 " <arg name=\"userspace\" type=\"t\"/>\n" \
251 " <arg name=\"total\" type=\"t\"/>\n" \
253 " <signal name=\"UnitFilesChanged\"/>\n"
255 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
256 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
257 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
258 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
259 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
260 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
261 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
262 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
263 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
264 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
265 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
266 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
267 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
268 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
269 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
270 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
271 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
272 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
273 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
274 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
275 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
276 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
277 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
278 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
279 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
280 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
281 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
282 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
283 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
284 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
285 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
286 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
287 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
288 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
290 #define BUS_MANAGER_INTERFACE_END \
293 #define BUS_MANAGER_INTERFACE \
294 BUS_MANAGER_INTERFACE_BEGIN \
295 BUS_MANAGER_INTERFACE_METHODS \
296 BUS_MANAGER_INTERFACE_SIGNALS \
297 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
298 BUS_MANAGER_INTERFACE_END
300 #define INTROSPECTION_BEGIN \
301 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
303 BUS_MANAGER_INTERFACE \
304 BUS_PROPERTIES_INTERFACE \
306 BUS_INTROSPECTABLE_INTERFACE
308 #define INTROSPECTION_END \
311 #define INTERFACES_LIST \
312 BUS_GENERIC_INTERFACES_LIST \
313 "org.freedesktop.systemd1.Manager\0"
315 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
317 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
319 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
322 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
329 e = stpcpy(e, "split-usr:");
331 if (readlink_malloc("/etc/mtab", &p) < 0)
332 e = stpcpy(e, "mtab-not-symlink:");
336 if (access("/proc/cgroups", F_OK) < 0)
337 e = stpcpy(e, "cgroups-missing:");
339 if (hwclock_is_localtime() > 0)
340 e = stpcpy(e, "local-hwclock:");
342 /* remove the last ':' */
348 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
354 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
360 t = log_target_to_string(log_get_target());
362 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
368 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
374 dbus_message_iter_get_basic(i, &t);
376 return log_set_target_from_string(t);
379 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
386 r = log_level_to_string_alloc(log_get_max_level(), &t);
390 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
397 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
403 dbus_message_iter_get_basic(i, &t);
405 return log_set_max_level_from_string(t);
408 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
416 u = hashmap_size(m->units);
418 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
424 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
432 u = hashmap_size(m->jobs);
434 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
440 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
448 if (dual_timestamp_is_set(&m->finish_timestamp))
451 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
453 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
459 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
467 detect_virtualization(&id);
469 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
475 static DBusMessage *message_from_file_changes(
477 UnitFileChange *changes,
479 int carries_install_info) {
481 DBusMessageIter iter, sub, sub2;
485 reply = dbus_message_new_method_return(m);
489 dbus_message_iter_init_append(reply, &iter);
491 if (carries_install_info >= 0) {
494 b = !!carries_install_info;
495 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
499 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
502 for (i = 0; i < n_changes; i++) {
503 const char *type, *path, *source;
505 type = unit_file_change_type_to_string(changes[i].type);
506 path = strempty(changes[i].path);
507 source = strempty(changes[i].source);
509 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
510 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
511 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
512 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
513 !dbus_message_iter_close_container(&sub, &sub2))
517 if (!dbus_message_iter_close_container(&iter, &sub))
523 dbus_message_unref(reply);
527 static int bus_manager_send_unit_files_changed(Manager *m) {
531 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
535 r = bus_broadcast(m, s);
536 dbus_message_unref(s);
541 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
547 dbus_message_iter_get_basic(i, t);
549 return watchdog_set_timeout(t);
552 static const char systemd_property_string[] =
556 static const BusProperty bus_systemd_properties[] = {
557 { "Version", bus_property_append_string, "s", 0 },
558 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
562 static const BusProperty bus_manager_properties[] = {
563 { "Tainted", bus_manager_append_tainted, "s", 0 },
564 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
565 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
566 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
567 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
568 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
569 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
570 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
571 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
572 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
573 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
574 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
575 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
576 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
577 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
578 { "NNames", bus_manager_append_n_names, "u", 0 },
579 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
580 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
581 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
582 { "Progress", bus_manager_append_progress, "d", 0 },
583 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
584 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
585 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
586 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
587 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
588 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
589 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
590 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
591 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
592 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
593 { "Virtualization", bus_manager_append_virt, "s", 0, },
597 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
598 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
599 _cleanup_free_ char * path = NULL;
603 JobType job_type = _JOB_TYPE_INVALID;
604 bool reload_if_possible = false;
611 dbus_error_init(&error);
613 member = dbus_message_get_member(message);
615 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
619 if (!dbus_message_get_args(
622 DBUS_TYPE_STRING, &name,
624 return bus_send_error_reply(connection, message, &error, -EINVAL);
626 u = manager_get_unit(m, name);
628 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
629 return bus_send_error_reply(connection, message, &error, -ENOENT);
632 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
634 reply = dbus_message_new_method_return(message);
638 path = unit_dbus_path(u);
642 if (!dbus_message_append_args(
644 DBUS_TYPE_OBJECT_PATH, &path,
647 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
651 if (!dbus_message_get_args(
654 DBUS_TYPE_UINT32, &pid,
656 return bus_send_error_reply(connection, message, &error, -EINVAL);
658 u = cgroup_unit_by_pid(m, (pid_t) pid);
660 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
661 return bus_send_error_reply(connection, message, &error, -ENOENT);
664 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
666 reply = dbus_message_new_method_return(message);
670 path = unit_dbus_path(u);
674 if (!dbus_message_append_args(
676 DBUS_TYPE_OBJECT_PATH, &path,
679 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
683 if (!dbus_message_get_args(
686 DBUS_TYPE_STRING, &name,
688 return bus_send_error_reply(connection, message, &error, -EINVAL);
690 r = manager_load_unit(m, name, NULL, &error, &u);
692 return bus_send_error_reply(connection, message, &error, r);
694 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
696 reply = dbus_message_new_method_return(message);
700 path = unit_dbus_path(u);
704 if (!dbus_message_append_args(
706 DBUS_TYPE_OBJECT_PATH, &path,
710 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
711 job_type = JOB_START;
712 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
713 job_type = JOB_START;
714 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
716 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
717 job_type = JOB_RELOAD;
718 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
719 job_type = JOB_RESTART;
720 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
721 job_type = JOB_TRY_RESTART;
722 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
723 reload_if_possible = true;
724 job_type = JOB_RESTART;
725 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
726 reload_if_possible = true;
727 job_type = JOB_TRY_RESTART;
728 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
729 const char *name, *swho;
734 if (!dbus_message_get_args(
737 DBUS_TYPE_STRING, &name,
738 DBUS_TYPE_STRING, &swho,
739 DBUS_TYPE_INT32, &signo,
741 return bus_send_error_reply(connection, message, &error, -EINVAL);
746 who = kill_who_from_string(swho);
748 return bus_send_error_reply(connection, message, &error, -EINVAL);
751 if (signo <= 0 || signo >= _NSIG)
752 return bus_send_error_reply(connection, message, &error, -EINVAL);
754 u = manager_get_unit(m, name);
756 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
757 return bus_send_error_reply(connection, message, &error, -ENOENT);
760 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
762 r = unit_kill(u, who, signo, &error);
764 return bus_send_error_reply(connection, message, &error, r);
766 reply = dbus_message_new_method_return(message);
770 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
774 if (!dbus_message_get_args(
777 DBUS_TYPE_UINT32, &id,
779 return bus_send_error_reply(connection, message, &error, -EINVAL);
781 j = manager_get_job(m, id);
783 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
784 return bus_send_error_reply(connection, message, &error, -ENOENT);
787 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
789 reply = dbus_message_new_method_return(message);
793 path = job_dbus_path(j);
797 if (!dbus_message_append_args(
799 DBUS_TYPE_OBJECT_PATH, &path,
803 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
807 if (!dbus_message_get_args(
810 DBUS_TYPE_UINT32, &id,
812 return bus_send_error_reply(connection, message, &error, -EINVAL);
814 j = manager_get_job(m, id);
816 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
817 return bus_send_error_reply(connection, message, &error, -ENOENT);
820 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
821 job_finish_and_invalidate(j, JOB_CANCELED, true);
823 reply = dbus_message_new_method_return(message);
827 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
829 SELINUX_ACCESS_CHECK(connection, message, "reboot");
830 manager_clear_jobs(m);
832 reply = dbus_message_new_method_return(message);
836 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
838 SELINUX_ACCESS_CHECK(connection, message, "reload");
840 manager_reset_failed(m);
842 reply = dbus_message_new_method_return(message);
846 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
850 if (!dbus_message_get_args(
853 DBUS_TYPE_STRING, &name,
855 return bus_send_error_reply(connection, message, &error, -EINVAL);
857 u = manager_get_unit(m, name);
859 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
860 return bus_send_error_reply(connection, message, &error, -ENOENT);
863 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
865 unit_reset_failed(u);
867 reply = dbus_message_new_method_return(message);
871 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroups")) {
874 DBusMessageIter iter;
876 if (!dbus_message_iter_init(message, &iter))
879 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
881 return bus_send_error_reply(connection, message, NULL, r);
883 u = manager_get_unit(m, name);
885 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
886 return bus_send_error_reply(connection, message, &error, -ENOENT);
889 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
891 r = bus_unit_cgroup_set(u, &iter);
893 return bus_send_error_reply(connection, message, NULL, r);
895 reply = dbus_message_new_method_return(message);
899 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroups")) {
902 DBusMessageIter iter;
904 if (!dbus_message_iter_init(message, &iter))
907 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
909 return bus_send_error_reply(connection, message, NULL, r);
911 u = manager_get_unit(m, name);
913 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
914 return bus_send_error_reply(connection, message, &error, -ENOENT);
917 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
919 r = bus_unit_cgroup_unset(u, &iter);
921 return bus_send_error_reply(connection, message, NULL, r);
923 reply = dbus_message_new_method_return(message);
927 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttributes")) {
930 DBusMessageIter iter;
932 if (!dbus_message_iter_init(message, &iter))
935 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
937 return bus_send_error_reply(connection, message, NULL, r);
939 u = manager_get_unit(m, name);
941 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
942 return bus_send_error_reply(connection, message, &error, -ENOENT);
945 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
946 r = bus_unit_cgroup_attribute_set(u, &iter);
948 return bus_send_error_reply(connection, message, NULL, r);
950 reply = dbus_message_new_method_return(message);
954 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttributes")) {
957 DBusMessageIter iter;
959 if (!dbus_message_iter_init(message, &iter))
962 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
964 return bus_send_error_reply(connection, message, NULL, r);
966 u = manager_get_unit(m, name);
968 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
969 return bus_send_error_reply(connection, message, &error, -ENOENT);
972 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
974 r = bus_unit_cgroup_attribute_unset(u, &iter);
976 return bus_send_error_reply(connection, message, NULL, r);
978 reply = dbus_message_new_method_return(message);
982 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
983 DBusMessageIter iter, sub;
988 SELINUX_ACCESS_CHECK(connection, message, "status");
990 reply = dbus_message_new_method_return(message);
994 dbus_message_iter_init_append(reply, &iter);
996 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
999 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1000 char *u_path, *j_path;
1001 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
1002 DBusMessageIter sub2;
1009 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1012 description = unit_description(u);
1013 load_state = unit_load_state_to_string(u->load_state);
1014 active_state = unit_active_state_to_string(unit_active_state(u));
1015 sub_state = unit_sub_state_to_string(u);
1017 f = unit_following(u);
1018 following = f ? f->id : "";
1020 u_path = unit_dbus_path(u);
1025 job_id = (uint32_t) u->job->id;
1027 if (!(j_path = job_dbus_path(u->job))) {
1032 sjob_type = job_type_to_string(u->job->type);
1039 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
1040 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
1041 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
1042 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
1043 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
1044 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
1045 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
1046 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
1047 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
1048 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
1059 if (!dbus_message_iter_close_container(&sub, &sub2))
1063 if (!dbus_message_iter_close_container(&iter, &sub))
1066 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
1067 DBusMessageIter iter, sub;
1071 SELINUX_ACCESS_CHECK(connection, message, "status");
1073 reply = dbus_message_new_method_return(message);
1077 dbus_message_iter_init_append(reply, &iter);
1079 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1082 HASHMAP_FOREACH(j, m->jobs, i) {
1083 char *u_path, *j_path;
1084 const char *state, *type;
1086 DBusMessageIter sub2;
1088 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1091 id = (uint32_t) j->id;
1092 state = job_state_to_string(j->state);
1093 type = job_type_to_string(j->type);
1095 j_path = job_dbus_path(j);
1099 u_path = unit_dbus_path(j->unit);
1105 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1106 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1107 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1108 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1109 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1110 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1119 if (!dbus_message_iter_close_container(&sub, &sub2))
1123 if (!dbus_message_iter_close_container(&iter, &sub))
1126 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1130 SELINUX_ACCESS_CHECK(connection, message, "status");
1132 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1134 s = set_new(string_hash_func, string_compare_func);
1138 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1144 client = strdup(bus_message_get_sender_with_fallback(message));
1148 r = set_put(s, client);
1151 return bus_send_error_reply(connection, message, NULL, r);
1154 reply = dbus_message_new_method_return(message);
1158 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1161 SELINUX_ACCESS_CHECK(connection, message, "status");
1163 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1165 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1166 return bus_send_error_reply(connection, message, &error, -ENOENT);
1171 reply = dbus_message_new_method_return(message);
1175 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1180 SELINUX_ACCESS_CHECK(connection, message, "status");
1182 reply = dbus_message_new_method_return(message);
1186 f = open_memstream(&dump, &size);
1190 manager_dump_units(m, f, NULL);
1191 manager_dump_jobs(m, f, NULL);
1201 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1207 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1209 dbus_bool_t cleanup;
1212 SELINUX_ACCESS_CHECK(connection, message, "start");
1214 if (!dbus_message_get_args(
1217 DBUS_TYPE_STRING, &name,
1218 DBUS_TYPE_BOOLEAN, &cleanup,
1220 return bus_send_error_reply(connection, message, &error, -EINVAL);
1225 r = snapshot_create(m, name, cleanup, &error, &s);
1227 return bus_send_error_reply(connection, message, &error, r);
1229 reply = dbus_message_new_method_return(message);
1233 path = unit_dbus_path(UNIT(s));
1237 if (!dbus_message_append_args(
1239 DBUS_TYPE_OBJECT_PATH, &path,
1243 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1247 if (!dbus_message_get_args(
1250 DBUS_TYPE_STRING, &name,
1252 return bus_send_error_reply(connection, message, &error, -EINVAL);
1254 u = manager_get_unit(m, name);
1256 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1257 return bus_send_error_reply(connection, message, &error, -ENOENT);
1260 if (u->type != UNIT_SNAPSHOT) {
1261 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1262 return bus_send_error_reply(connection, message, &error, -ENOENT);
1265 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1266 snapshot_remove(SNAPSHOT(u));
1268 reply = dbus_message_new_method_return(message);
1272 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1273 char *introspection = NULL;
1281 SELINUX_ACCESS_CHECK(connection, message, "status");
1283 reply = dbus_message_new_method_return(message);
1287 /* We roll our own introspection code here, instead of
1288 * relying on bus_default_message_handler() because we
1289 * need to generate our introspection string
1292 f = open_memstream(&introspection, &size);
1296 fputs(INTROSPECTION_BEGIN, f);
1298 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1304 p = bus_path_escape(k);
1307 free(introspection);
1311 fprintf(f, "<node name=\"unit/%s\"/>", p);
1315 HASHMAP_FOREACH(j, m->jobs, i)
1316 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1318 fputs(INTROSPECTION_END, f);
1322 free(introspection);
1331 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1332 free(introspection);
1336 free(introspection);
1338 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1340 SELINUX_ACCESS_CHECK(connection, message, "reload");
1342 assert(!m->queued_message);
1344 /* Instead of sending the reply back right away, we
1345 * just remember that we need to and then send it
1346 * after the reload is finished. That way the caller
1347 * knows when the reload finished. */
1349 m->queued_message = dbus_message_new_method_return(message);
1350 if (!m->queued_message)
1353 m->queued_message_connection = connection;
1354 m->exit_code = MANAGER_RELOAD;
1356 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1358 SELINUX_ACCESS_CHECK(connection, message, "reload");
1360 /* We don't send a reply back here, the client should
1361 * just wait for us disconnecting. */
1363 m->exit_code = MANAGER_REEXECUTE;
1365 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1367 SELINUX_ACCESS_CHECK(connection, message, "halt");
1369 if (m->running_as == SYSTEMD_SYSTEM) {
1370 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1371 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1374 reply = dbus_message_new_method_return(message);
1378 m->exit_code = MANAGER_EXIT;
1380 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1382 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1384 if (m->running_as != SYSTEMD_SYSTEM) {
1385 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1386 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1389 reply = dbus_message_new_method_return(message);
1393 m->exit_code = MANAGER_REBOOT;
1395 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1397 SELINUX_ACCESS_CHECK(connection, message, "halt");
1399 if (m->running_as != SYSTEMD_SYSTEM) {
1400 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1401 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1404 reply = dbus_message_new_method_return(message);
1408 m->exit_code = MANAGER_POWEROFF;
1410 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1412 SELINUX_ACCESS_CHECK(connection, message, "halt");
1414 if (m->running_as != SYSTEMD_SYSTEM) {
1415 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1416 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1419 reply = dbus_message_new_method_return(message);
1423 m->exit_code = MANAGER_HALT;
1425 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1427 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1429 if (m->running_as != SYSTEMD_SYSTEM) {
1430 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1431 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1434 reply = dbus_message_new_method_return(message);
1438 m->exit_code = MANAGER_KEXEC;
1440 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1441 const char *switch_root, *switch_root_init;
1445 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1447 if (!dbus_message_get_args(
1450 DBUS_TYPE_STRING, &switch_root,
1451 DBUS_TYPE_STRING, &switch_root_init,
1453 return bus_send_error_reply(connection, message, &error, -EINVAL);
1455 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1456 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1458 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1459 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1461 if (m->running_as != SYSTEMD_SYSTEM) {
1462 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1463 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1467 if (isempty(switch_root_init))
1468 k = access(switch_root, F_OK);
1472 p = strjoin(switch_root, "/", switch_root_init, NULL);
1476 k = access(p, X_OK);
1480 return bus_send_error_reply(connection, message, NULL, -errno);
1482 u = strdup(switch_root);
1486 if (!isempty(switch_root_init)) {
1487 v = strdup(switch_root_init);
1495 free(m->switch_root);
1496 free(m->switch_root_init);
1498 m->switch_root_init = v;
1500 reply = dbus_message_new_method_return(message);
1504 m->exit_code = MANAGER_SWITCH_ROOT;
1506 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1507 char **l = NULL, **e = NULL;
1509 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1511 r = bus_parse_strv(message, &l);
1515 return bus_send_error_reply(connection, message, NULL, r);
1517 e = strv_env_merge(2, m->environment, l);
1522 reply = dbus_message_new_method_return(message);
1528 strv_free(m->environment);
1531 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1532 char **l = NULL, **e = NULL;
1534 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1536 r = bus_parse_strv(message, &l);
1540 return bus_send_error_reply(connection, message, NULL, r);
1542 e = strv_env_delete(m->environment, 1, l);
1548 reply = dbus_message_new_method_return(message);
1554 strv_free(m->environment);
1557 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1558 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1559 DBusMessageIter iter;
1561 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1563 if (!dbus_message_iter_init(message, &iter))
1566 r = bus_parse_strv_iter(&iter, &l_unset);
1570 return bus_send_error_reply(connection, message, NULL, r);
1572 if (!dbus_message_iter_next(&iter)) {
1574 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1577 r = bus_parse_strv_iter(&iter, &l_set);
1583 return bus_send_error_reply(connection, message, NULL, r);
1586 e = strv_env_delete(m->environment, 1, l_unset);
1594 f = strv_env_merge(2, e, l_set);
1601 reply = dbus_message_new_method_return(message);
1607 strv_free(m->environment);
1609 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1610 DBusMessageIter iter, sub, sub2;
1615 SELINUX_ACCESS_CHECK(connection, message, "status");
1617 reply = dbus_message_new_method_return(message);
1621 h = hashmap_new(string_hash_func, string_compare_func);
1625 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1627 unit_file_list_free(h);
1628 return bus_send_error_reply(connection, message, NULL, r);
1631 dbus_message_iter_init_append(reply, &iter);
1633 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1634 unit_file_list_free(h);
1638 HASHMAP_FOREACH(item, h, i) {
1641 state = unit_file_state_to_string(item->state);
1644 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1645 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1646 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1647 !dbus_message_iter_close_container(&sub, &sub2)) {
1648 unit_file_list_free(h);
1653 unit_file_list_free(h);
1655 if (!dbus_message_iter_close_container(&iter, &sub))
1658 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1660 UnitFileState state;
1663 SELINUX_ACCESS_CHECK(connection, message, "status");
1665 if (!dbus_message_get_args(
1668 DBUS_TYPE_STRING, &name,
1670 return bus_send_error_reply(connection, message, &error, -EINVAL);
1672 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1674 return bus_send_error_reply(connection, message, NULL, state);
1676 s = unit_file_state_to_string(state);
1679 reply = dbus_message_new_method_return(message);
1683 if (!dbus_message_append_args(
1685 DBUS_TYPE_STRING, &s,
1688 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1689 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1690 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1691 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1692 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1695 DBusMessageIter iter;
1696 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1697 UnitFileChange *changes = NULL;
1698 unsigned n_changes = 0;
1699 dbus_bool_t runtime, force;
1700 int carries_install_info = -1;
1702 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1704 if (!dbus_message_iter_init(message, &iter))
1707 r = bus_parse_strv_iter(&iter, &l);
1712 return bus_send_error_reply(connection, message, NULL, r);
1715 if (!dbus_message_iter_next(&iter) ||
1716 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1717 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1719 return bus_send_error_reply(connection, message, NULL, -EIO);
1722 if (streq(member, "EnableUnitFiles")) {
1723 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1724 carries_install_info = r;
1725 } else if (streq(member, "ReenableUnitFiles")) {
1726 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1727 carries_install_info = r;
1728 } else if (streq(member, "LinkUnitFiles"))
1729 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1730 else if (streq(member, "PresetUnitFiles")) {
1731 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1732 carries_install_info = r;
1733 } else if (streq(member, "MaskUnitFiles"))
1734 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1736 assert_not_reached("Uh? Wrong method");
1739 bus_manager_send_unit_files_changed(m);
1742 unit_file_changes_free(changes, n_changes);
1743 return bus_send_error_reply(connection, message, NULL, r);
1746 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1747 unit_file_changes_free(changes, n_changes);
1752 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1753 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1756 DBusMessageIter iter;
1757 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1758 UnitFileChange *changes = NULL;
1759 unsigned n_changes = 0;
1760 dbus_bool_t runtime;
1762 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1764 if (!dbus_message_iter_init(message, &iter))
1767 r = bus_parse_strv_iter(&iter, &l);
1772 return bus_send_error_reply(connection, message, NULL, r);
1775 if (!dbus_message_iter_next(&iter) ||
1776 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1778 return bus_send_error_reply(connection, message, NULL, -EIO);
1781 if (streq(member, "DisableUnitFiles"))
1782 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1783 else if (streq(member, "UnmaskUnitFiles"))
1784 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1786 assert_not_reached("Uh? Wrong method");
1789 bus_manager_send_unit_files_changed(m);
1792 unit_file_changes_free(changes, n_changes);
1793 return bus_send_error_reply(connection, message, NULL, r);
1796 reply = message_from_file_changes(message, changes, n_changes, -1);
1797 unit_file_changes_free(changes, n_changes);
1803 const BusBoundProperties bps[] = {
1804 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1805 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1809 SELINUX_ACCESS_CHECK(connection, message, "status");
1811 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1814 if (job_type != _JOB_TYPE_INVALID) {
1815 const char *name, *smode, *old_name = NULL;
1820 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1821 b = dbus_message_get_args(
1824 DBUS_TYPE_STRING, &old_name,
1825 DBUS_TYPE_STRING, &name,
1826 DBUS_TYPE_STRING, &smode,
1829 b = dbus_message_get_args(
1832 DBUS_TYPE_STRING, &name,
1833 DBUS_TYPE_STRING, &smode,
1836 return bus_send_error_reply(connection, message, &error, -EINVAL);
1839 u = manager_get_unit(m, old_name);
1840 if (!u || !u->job || u->job->type != JOB_START) {
1841 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1842 return bus_send_error_reply(connection, message, &error, -ENOENT);
1846 mode = job_mode_from_string(smode);
1848 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1849 return bus_send_error_reply(connection, message, &error, -EINVAL);
1852 r = manager_load_unit(m, name, NULL, &error, &u);
1854 return bus_send_error_reply(connection, message, &error, r);
1856 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1860 if (!dbus_connection_send(connection, reply, NULL))
1863 return DBUS_HANDLER_RESULT_HANDLED;
1866 dbus_error_free(&error);
1868 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1871 const DBusObjectPathVTable bus_manager_vtable = {
1872 .message_function = bus_manager_message_handler