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=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
286 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
287 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
288 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
289 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
290 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
291 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
292 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
293 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
294 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
295 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
296 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
297 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
298 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
299 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
300 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
301 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
302 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
303 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
304 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
305 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
306 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
307 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
308 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
309 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
310 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
312 #define BUS_MANAGER_INTERFACE_END \
315 #define BUS_MANAGER_INTERFACE \
316 BUS_MANAGER_INTERFACE_BEGIN \
317 BUS_MANAGER_INTERFACE_METHODS \
318 BUS_MANAGER_INTERFACE_SIGNALS \
319 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
320 BUS_MANAGER_INTERFACE_END
322 #define INTROSPECTION_BEGIN \
323 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
325 BUS_MANAGER_INTERFACE \
326 BUS_PROPERTIES_INTERFACE \
328 BUS_INTROSPECTABLE_INTERFACE
330 #define INTROSPECTION_END \
333 #define INTERFACES_LIST \
334 BUS_GENERIC_INTERFACES_LIST \
335 "org.freedesktop.systemd1.Manager\0"
337 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
339 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
341 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
344 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
351 e = stpcpy(e, "split-usr:");
353 if (readlink_malloc("/etc/mtab", &p) < 0)
354 e = stpcpy(e, "mtab-not-symlink:");
358 if (access("/proc/cgroups", F_OK) < 0)
359 e = stpcpy(e, "cgroups-missing:");
361 if (hwclock_is_localtime() > 0)
362 e = stpcpy(e, "local-hwclock:");
364 /* remove the last ':' */
370 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
376 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
382 t = log_target_to_string(log_get_target());
384 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
390 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
396 dbus_message_iter_get_basic(i, &t);
398 return log_set_target_from_string(t);
401 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
408 r = log_level_to_string_alloc(log_get_max_level(), &t);
412 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
419 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
425 dbus_message_iter_get_basic(i, &t);
427 return log_set_max_level_from_string(t);
430 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
438 u = hashmap_size(m->units);
440 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
446 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
454 u = hashmap_size(m->jobs);
456 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
462 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
470 if (dual_timestamp_is_set(&m->finish_timestamp))
473 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
475 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
481 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
489 detect_virtualization(&id);
491 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
497 static DBusMessage *message_from_file_changes(
499 UnitFileChange *changes,
501 int carries_install_info) {
503 DBusMessageIter iter, sub, sub2;
507 reply = dbus_message_new_method_return(m);
511 dbus_message_iter_init_append(reply, &iter);
513 if (carries_install_info >= 0) {
516 b = !!carries_install_info;
517 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
521 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
524 for (i = 0; i < n_changes; i++) {
525 const char *type, *path, *source;
527 type = unit_file_change_type_to_string(changes[i].type);
528 path = strempty(changes[i].path);
529 source = strempty(changes[i].source);
531 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
532 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
533 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
534 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
535 !dbus_message_iter_close_container(&sub, &sub2))
539 if (!dbus_message_iter_close_container(&iter, &sub))
545 dbus_message_unref(reply);
549 static int bus_manager_send_unit_files_changed(Manager *m) {
553 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
557 r = bus_broadcast(m, s);
558 dbus_message_unref(s);
563 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
569 dbus_message_iter_get_basic(i, t);
571 return watchdog_set_timeout(t);
574 static const char systemd_property_string[] =
578 static const BusProperty bus_systemd_properties[] = {
579 { "Version", bus_property_append_string, "s", 0 },
580 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
584 static const BusProperty bus_manager_properties[] = {
585 { "Tainted", bus_manager_append_tainted, "s", 0 },
586 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
587 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
588 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
589 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
590 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
591 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
592 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
593 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
594 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
595 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
596 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
597 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
598 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
599 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
600 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
601 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
602 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
603 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
604 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
605 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
606 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
607 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
608 { "NNames", bus_manager_append_n_names, "u", 0 },
609 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
610 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
611 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
612 { "Progress", bus_manager_append_progress, "d", 0 },
613 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
614 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
615 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
616 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
617 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
618 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
619 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
620 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
621 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
622 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
623 { "Virtualization", bus_manager_append_virt, "s", 0, },
627 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
628 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
629 _cleanup_free_ char * path = NULL;
633 JobType job_type = _JOB_TYPE_INVALID;
634 bool reload_if_possible = false;
641 dbus_error_init(&error);
643 member = dbus_message_get_member(message);
645 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
649 if (!dbus_message_get_args(
652 DBUS_TYPE_STRING, &name,
654 return bus_send_error_reply(connection, message, &error, -EINVAL);
656 u = manager_get_unit(m, name);
658 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
659 return bus_send_error_reply(connection, message, &error, -ENOENT);
662 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
664 reply = dbus_message_new_method_return(message);
668 path = unit_dbus_path(u);
672 if (!dbus_message_append_args(
674 DBUS_TYPE_OBJECT_PATH, &path,
677 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
681 if (!dbus_message_get_args(
684 DBUS_TYPE_UINT32, &pid,
686 return bus_send_error_reply(connection, message, &error, -EINVAL);
688 u = cgroup_unit_by_pid(m, (pid_t) pid);
690 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
691 return bus_send_error_reply(connection, message, &error, -ENOENT);
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,
709 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
713 if (!dbus_message_get_args(
716 DBUS_TYPE_STRING, &name,
718 return bus_send_error_reply(connection, message, &error, -EINVAL);
720 r = manager_load_unit(m, name, NULL, &error, &u);
722 return bus_send_error_reply(connection, message, &error, r);
724 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
726 reply = dbus_message_new_method_return(message);
730 path = unit_dbus_path(u);
734 if (!dbus_message_append_args(
736 DBUS_TYPE_OBJECT_PATH, &path,
740 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
741 job_type = JOB_START;
742 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
743 job_type = JOB_START;
744 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
746 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
747 job_type = JOB_RELOAD;
748 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
749 job_type = JOB_RESTART;
750 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
751 job_type = JOB_TRY_RESTART;
752 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
753 reload_if_possible = true;
754 job_type = JOB_RESTART;
755 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
756 reload_if_possible = true;
757 job_type = JOB_TRY_RESTART;
758 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
759 const char *name, *swho;
764 if (!dbus_message_get_args(
767 DBUS_TYPE_STRING, &name,
768 DBUS_TYPE_STRING, &swho,
769 DBUS_TYPE_INT32, &signo,
771 return bus_send_error_reply(connection, message, &error, -EINVAL);
776 who = kill_who_from_string(swho);
778 return bus_send_error_reply(connection, message, &error, -EINVAL);
781 if (signo <= 0 || signo >= _NSIG)
782 return bus_send_error_reply(connection, message, &error, -EINVAL);
784 u = manager_get_unit(m, name);
786 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
787 return bus_send_error_reply(connection, message, &error, -ENOENT);
790 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
792 r = unit_kill(u, who, signo, &error);
794 return bus_send_error_reply(connection, message, &error, r);
796 reply = dbus_message_new_method_return(message);
800 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
804 if (!dbus_message_get_args(
807 DBUS_TYPE_UINT32, &id,
809 return bus_send_error_reply(connection, message, &error, -EINVAL);
811 j = manager_get_job(m, id);
813 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
814 return bus_send_error_reply(connection, message, &error, -ENOENT);
817 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
819 reply = dbus_message_new_method_return(message);
823 path = job_dbus_path(j);
827 if (!dbus_message_append_args(
829 DBUS_TYPE_OBJECT_PATH, &path,
833 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
837 if (!dbus_message_get_args(
840 DBUS_TYPE_UINT32, &id,
842 return bus_send_error_reply(connection, message, &error, -EINVAL);
844 j = manager_get_job(m, id);
846 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
847 return bus_send_error_reply(connection, message, &error, -ENOENT);
850 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
851 job_finish_and_invalidate(j, JOB_CANCELED, true);
853 reply = dbus_message_new_method_return(message);
857 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
859 SELINUX_ACCESS_CHECK(connection, message, "reboot");
860 manager_clear_jobs(m);
862 reply = dbus_message_new_method_return(message);
866 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
868 SELINUX_ACCESS_CHECK(connection, message, "reload");
870 manager_reset_failed(m);
872 reply = dbus_message_new_method_return(message);
876 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
880 if (!dbus_message_get_args(
883 DBUS_TYPE_STRING, &name,
885 return bus_send_error_reply(connection, message, &error, -EINVAL);
887 u = manager_get_unit(m, name);
889 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
890 return bus_send_error_reply(connection, message, &error, -ENOENT);
893 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
895 unit_reset_failed(u);
897 reply = dbus_message_new_method_return(message);
901 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroup")) {
904 DBusMessageIter iter;
906 if (!dbus_message_iter_init(message, &iter))
909 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
911 return bus_send_error_reply(connection, message, NULL, r);
913 u = manager_get_unit(m, name);
915 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
916 return bus_send_error_reply(connection, message, &error, -ENOENT);
919 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
921 r = bus_unit_cgroup_set(u, &iter);
923 return bus_send_error_reply(connection, message, NULL, r);
925 reply = dbus_message_new_method_return(message);
929 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroup")) {
932 DBusMessageIter iter;
934 if (!dbus_message_iter_init(message, &iter))
937 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
939 return bus_send_error_reply(connection, message, NULL, r);
941 u = manager_get_unit(m, name);
943 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
944 return bus_send_error_reply(connection, message, &error, -ENOENT);
947 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
949 r = bus_unit_cgroup_unset(u, &iter);
951 return bus_send_error_reply(connection, message, NULL, r);
953 reply = dbus_message_new_method_return(message);
957 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitControlGroupAttribute")) {
960 DBusMessageIter iter;
962 if (!dbus_message_iter_init(message, &iter))
965 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
967 return bus_send_error_reply(connection, message, NULL, r);
969 u = manager_get_unit(m, name);
971 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
972 return bus_send_error_reply(connection, message, &error, -ENOENT);
975 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
977 r = bus_unit_cgroup_attribute_set(u, &iter);
979 return bus_send_error_reply(connection, message, NULL, r);
981 reply = dbus_message_new_method_return(message);
985 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetUnitControlGroupAttribute")) {
988 DBusMessageIter iter;
990 if (!dbus_message_iter_init(message, &iter))
993 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
995 return bus_send_error_reply(connection, message, NULL, r);
997 u = manager_get_unit(m, name);
999 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1000 return bus_send_error_reply(connection, message, &error, -ENOENT);
1003 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1005 r = bus_unit_cgroup_attribute_unset(u, &iter);
1007 return bus_send_error_reply(connection, message, NULL, r);
1009 reply = dbus_message_new_method_return(message);
1013 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitControlGroupAttribute")) {
1016 DBusMessageIter iter;
1017 _cleanup_strv_free_ char **list = NULL;
1019 if (!dbus_message_iter_init(message, &iter))
1022 r = bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true);
1024 return bus_send_error_reply(connection, message, NULL, r);
1026 u = manager_get_unit(m, name);
1028 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1029 return bus_send_error_reply(connection, message, &error, -ENOENT);
1032 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
1034 r = bus_unit_cgroup_attribute_get(u, &iter, &list);
1036 return bus_send_error_reply(connection, message, NULL, r);
1038 reply = dbus_message_new_method_return(message);
1042 dbus_message_iter_init_append(reply, &iter);
1043 if (bus_append_strv_iter(&iter, list) < 0)
1046 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
1047 DBusMessageIter iter, sub;
1052 SELINUX_ACCESS_CHECK(connection, message, "status");
1054 reply = dbus_message_new_method_return(message);
1058 dbus_message_iter_init_append(reply, &iter);
1060 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
1063 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1064 char *u_path, *j_path;
1065 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
1066 DBusMessageIter sub2;
1073 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1076 description = unit_description(u);
1077 load_state = unit_load_state_to_string(u->load_state);
1078 active_state = unit_active_state_to_string(unit_active_state(u));
1079 sub_state = unit_sub_state_to_string(u);
1081 f = unit_following(u);
1082 following = f ? f->id : "";
1084 u_path = unit_dbus_path(u);
1089 job_id = (uint32_t) u->job->id;
1091 if (!(j_path = job_dbus_path(u->job))) {
1096 sjob_type = job_type_to_string(u->job->type);
1103 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
1104 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
1105 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
1106 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
1107 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
1108 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
1109 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
1110 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
1111 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
1112 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
1123 if (!dbus_message_iter_close_container(&sub, &sub2))
1127 if (!dbus_message_iter_close_container(&iter, &sub))
1130 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
1131 DBusMessageIter iter, sub;
1135 SELINUX_ACCESS_CHECK(connection, message, "status");
1137 reply = dbus_message_new_method_return(message);
1141 dbus_message_iter_init_append(reply, &iter);
1143 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1146 HASHMAP_FOREACH(j, m->jobs, i) {
1147 char *u_path, *j_path;
1148 const char *state, *type;
1150 DBusMessageIter sub2;
1152 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1155 id = (uint32_t) j->id;
1156 state = job_state_to_string(j->state);
1157 type = job_type_to_string(j->type);
1159 j_path = job_dbus_path(j);
1163 u_path = unit_dbus_path(j->unit);
1169 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1170 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1171 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1172 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1173 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1174 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1183 if (!dbus_message_iter_close_container(&sub, &sub2))
1187 if (!dbus_message_iter_close_container(&iter, &sub))
1190 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1194 SELINUX_ACCESS_CHECK(connection, message, "status");
1196 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1198 s = set_new(string_hash_func, string_compare_func);
1202 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1208 client = strdup(bus_message_get_sender_with_fallback(message));
1212 r = set_consume(s, client);
1214 return bus_send_error_reply(connection, message, NULL, r);
1216 reply = dbus_message_new_method_return(message);
1220 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1223 SELINUX_ACCESS_CHECK(connection, message, "status");
1225 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1227 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1228 return bus_send_error_reply(connection, message, &error, -ENOENT);
1233 reply = dbus_message_new_method_return(message);
1237 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1242 SELINUX_ACCESS_CHECK(connection, message, "status");
1244 reply = dbus_message_new_method_return(message);
1248 f = open_memstream(&dump, &size);
1252 manager_dump_units(m, f, NULL);
1253 manager_dump_jobs(m, f, NULL);
1263 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1269 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1271 dbus_bool_t cleanup;
1274 SELINUX_ACCESS_CHECK(connection, message, "start");
1276 if (!dbus_message_get_args(
1279 DBUS_TYPE_STRING, &name,
1280 DBUS_TYPE_BOOLEAN, &cleanup,
1282 return bus_send_error_reply(connection, message, &error, -EINVAL);
1287 r = snapshot_create(m, name, cleanup, &error, &s);
1289 return bus_send_error_reply(connection, message, &error, r);
1291 reply = dbus_message_new_method_return(message);
1295 path = unit_dbus_path(UNIT(s));
1299 if (!dbus_message_append_args(
1301 DBUS_TYPE_OBJECT_PATH, &path,
1305 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1309 if (!dbus_message_get_args(
1312 DBUS_TYPE_STRING, &name,
1314 return bus_send_error_reply(connection, message, &error, -EINVAL);
1316 u = manager_get_unit(m, name);
1318 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1319 return bus_send_error_reply(connection, message, &error, -ENOENT);
1322 if (u->type != UNIT_SNAPSHOT) {
1323 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1324 return bus_send_error_reply(connection, message, &error, -ENOENT);
1327 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1328 snapshot_remove(SNAPSHOT(u));
1330 reply = dbus_message_new_method_return(message);
1334 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1335 char *introspection = NULL;
1343 SELINUX_ACCESS_CHECK(connection, message, "status");
1345 reply = dbus_message_new_method_return(message);
1349 /* We roll our own introspection code here, instead of
1350 * relying on bus_default_message_handler() because we
1351 * need to generate our introspection string
1354 f = open_memstream(&introspection, &size);
1358 fputs(INTROSPECTION_BEGIN, f);
1360 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1366 p = bus_path_escape(k);
1369 free(introspection);
1373 fprintf(f, "<node name=\"unit/%s\"/>", p);
1377 HASHMAP_FOREACH(j, m->jobs, i)
1378 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1380 fputs(INTROSPECTION_END, f);
1384 free(introspection);
1393 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1394 free(introspection);
1398 free(introspection);
1400 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1402 SELINUX_ACCESS_CHECK(connection, message, "reload");
1404 assert(!m->queued_message);
1406 /* Instead of sending the reply back right away, we
1407 * just remember that we need to and then send it
1408 * after the reload is finished. That way the caller
1409 * knows when the reload finished. */
1411 m->queued_message = dbus_message_new_method_return(message);
1412 if (!m->queued_message)
1415 m->queued_message_connection = connection;
1416 m->exit_code = MANAGER_RELOAD;
1418 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1420 SELINUX_ACCESS_CHECK(connection, message, "reload");
1422 /* We don't send a reply back here, the client should
1423 * just wait for us disconnecting. */
1425 m->exit_code = MANAGER_REEXECUTE;
1427 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1429 SELINUX_ACCESS_CHECK(connection, message, "halt");
1431 if (m->running_as == SYSTEMD_SYSTEM) {
1432 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1433 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1436 reply = dbus_message_new_method_return(message);
1440 m->exit_code = MANAGER_EXIT;
1442 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1444 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1446 if (m->running_as != SYSTEMD_SYSTEM) {
1447 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1448 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1451 reply = dbus_message_new_method_return(message);
1455 m->exit_code = MANAGER_REBOOT;
1457 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1459 SELINUX_ACCESS_CHECK(connection, message, "halt");
1461 if (m->running_as != SYSTEMD_SYSTEM) {
1462 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1463 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1466 reply = dbus_message_new_method_return(message);
1470 m->exit_code = MANAGER_POWEROFF;
1472 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1474 SELINUX_ACCESS_CHECK(connection, message, "halt");
1476 if (m->running_as != SYSTEMD_SYSTEM) {
1477 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1478 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1481 reply = dbus_message_new_method_return(message);
1485 m->exit_code = MANAGER_HALT;
1487 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1489 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1491 if (m->running_as != SYSTEMD_SYSTEM) {
1492 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1493 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1496 reply = dbus_message_new_method_return(message);
1500 m->exit_code = MANAGER_KEXEC;
1502 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1503 const char *switch_root, *switch_root_init;
1507 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1509 if (!dbus_message_get_args(
1512 DBUS_TYPE_STRING, &switch_root,
1513 DBUS_TYPE_STRING, &switch_root_init,
1515 return bus_send_error_reply(connection, message, &error, -EINVAL);
1517 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1518 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1520 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1521 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1523 if (m->running_as != SYSTEMD_SYSTEM) {
1524 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1525 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1529 if (isempty(switch_root_init)) {
1530 good = path_is_os_tree(switch_root);
1532 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1535 _cleanup_free_ char *p = NULL;
1537 p = strjoin(switch_root, "/", switch_root_init, NULL);
1541 good = access(p, X_OK) >= 0;
1543 log_error("Not switching root: cannot execute new init %s", p);
1546 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1548 u = strdup(switch_root);
1552 if (!isempty(switch_root_init)) {
1553 v = strdup(switch_root_init);
1561 free(m->switch_root);
1562 free(m->switch_root_init);
1564 m->switch_root_init = v;
1566 reply = dbus_message_new_method_return(message);
1570 m->exit_code = MANAGER_SWITCH_ROOT;
1572 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1573 _cleanup_strv_free_ char **l = NULL;
1576 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1578 r = bus_parse_strv(message, &l);
1582 return bus_send_error_reply(connection, message, NULL, r);
1583 if (!strv_env_is_valid(l))
1584 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1586 e = strv_env_merge(2, m->environment, l);
1590 reply = dbus_message_new_method_return(message);
1596 strv_free(m->environment);
1599 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1600 _cleanup_strv_free_ char **l = NULL;
1603 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1605 r = bus_parse_strv(message, &l);
1609 return bus_send_error_reply(connection, message, NULL, r);
1610 if (!strv_env_name_or_assignment_is_valid(l))
1611 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1613 e = strv_env_delete(m->environment, 1, l);
1617 reply = dbus_message_new_method_return(message);
1623 strv_free(m->environment);
1626 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1627 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1629 DBusMessageIter iter;
1631 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1633 if (!dbus_message_iter_init(message, &iter))
1636 r = bus_parse_strv_iter(&iter, &l_unset);
1640 return bus_send_error_reply(connection, message, NULL, r);
1641 if (!strv_env_name_or_assignment_is_valid(l_unset))
1642 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1644 if (!dbus_message_iter_next(&iter))
1645 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1647 r = bus_parse_strv_iter(&iter, &l_set);
1651 return bus_send_error_reply(connection, message, NULL, r);
1652 if (!strv_env_is_valid(l_set))
1653 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1655 e = strv_env_delete(m->environment, 1, l_unset);
1659 f = strv_env_merge(2, e, l_set);
1663 reply = dbus_message_new_method_return(message);
1669 strv_free(m->environment);
1671 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1672 DBusMessageIter iter, sub, sub2;
1677 SELINUX_ACCESS_CHECK(connection, message, "status");
1679 reply = dbus_message_new_method_return(message);
1683 h = hashmap_new(string_hash_func, string_compare_func);
1687 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1689 unit_file_list_free(h);
1690 return bus_send_error_reply(connection, message, NULL, r);
1693 dbus_message_iter_init_append(reply, &iter);
1695 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1696 unit_file_list_free(h);
1700 HASHMAP_FOREACH(item, h, i) {
1703 state = unit_file_state_to_string(item->state);
1706 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1707 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1708 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1709 !dbus_message_iter_close_container(&sub, &sub2)) {
1710 unit_file_list_free(h);
1715 unit_file_list_free(h);
1717 if (!dbus_message_iter_close_container(&iter, &sub))
1720 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1722 UnitFileState state;
1725 SELINUX_ACCESS_CHECK(connection, message, "status");
1727 if (!dbus_message_get_args(
1730 DBUS_TYPE_STRING, &name,
1732 return bus_send_error_reply(connection, message, &error, -EINVAL);
1734 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1736 return bus_send_error_reply(connection, message, NULL, state);
1738 s = unit_file_state_to_string(state);
1741 reply = dbus_message_new_method_return(message);
1745 if (!dbus_message_append_args(
1747 DBUS_TYPE_STRING, &s,
1750 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1751 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1752 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1753 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1754 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1755 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1758 DBusMessageIter iter;
1759 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1760 UnitFileChange *changes = NULL;
1761 unsigned n_changes = 0;
1762 dbus_bool_t runtime, force;
1763 int carries_install_info = -1;
1765 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1767 if (!dbus_message_iter_init(message, &iter))
1770 r = bus_parse_strv_iter(&iter, &l);
1775 return bus_send_error_reply(connection, message, NULL, r);
1778 if (!dbus_message_iter_next(&iter) ||
1779 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1780 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1782 return bus_send_error_reply(connection, message, NULL, -EIO);
1785 if (streq(member, "EnableUnitFiles")) {
1786 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1787 carries_install_info = r;
1788 } else if (streq(member, "ReenableUnitFiles")) {
1789 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1790 carries_install_info = r;
1791 } else if (streq(member, "LinkUnitFiles"))
1792 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1793 else if (streq(member, "PresetUnitFiles")) {
1794 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1795 carries_install_info = r;
1796 } else if (streq(member, "MaskUnitFiles"))
1797 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1798 else if (streq(member, "SetDefaultTarget"))
1799 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1801 assert_not_reached("Uh? Wrong method");
1804 bus_manager_send_unit_files_changed(m);
1807 unit_file_changes_free(changes, n_changes);
1808 return bus_send_error_reply(connection, message, NULL, r);
1811 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1812 unit_file_changes_free(changes, n_changes);
1817 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1818 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1821 DBusMessageIter iter;
1822 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1823 UnitFileChange *changes = NULL;
1824 unsigned n_changes = 0;
1825 dbus_bool_t runtime;
1827 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1829 if (!dbus_message_iter_init(message, &iter))
1832 r = bus_parse_strv_iter(&iter, &l);
1837 return bus_send_error_reply(connection, message, NULL, r);
1840 if (!dbus_message_iter_next(&iter) ||
1841 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1843 return bus_send_error_reply(connection, message, NULL, -EIO);
1846 if (streq(member, "DisableUnitFiles"))
1847 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1848 else if (streq(member, "UnmaskUnitFiles"))
1849 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1851 assert_not_reached("Uh? Wrong method");
1854 bus_manager_send_unit_files_changed(m);
1857 unit_file_changes_free(changes, n_changes);
1858 return bus_send_error_reply(connection, message, NULL, r);
1861 reply = message_from_file_changes(message, changes, n_changes, -1);
1862 unit_file_changes_free(changes, n_changes);
1867 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1868 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1869 _cleanup_free_ char *default_target = NULL;
1871 reply = dbus_message_new_method_return(message);
1875 r = unit_file_get_default(scope, NULL, &default_target);
1878 return bus_send_error_reply(connection, message, NULL, r);
1880 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1884 const BusBoundProperties bps[] = {
1885 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1886 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1890 SELINUX_ACCESS_CHECK(connection, message, "status");
1892 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1895 if (job_type != _JOB_TYPE_INVALID) {
1896 const char *name, *smode, *old_name = NULL;
1901 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1902 b = dbus_message_get_args(
1905 DBUS_TYPE_STRING, &old_name,
1906 DBUS_TYPE_STRING, &name,
1907 DBUS_TYPE_STRING, &smode,
1910 b = dbus_message_get_args(
1913 DBUS_TYPE_STRING, &name,
1914 DBUS_TYPE_STRING, &smode,
1917 return bus_send_error_reply(connection, message, &error, -EINVAL);
1920 u = manager_get_unit(m, old_name);
1921 if (!u || !u->job || u->job->type != JOB_START) {
1922 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1923 return bus_send_error_reply(connection, message, &error, -ENOENT);
1927 mode = job_mode_from_string(smode);
1929 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1930 return bus_send_error_reply(connection, message, &error, -EINVAL);
1933 r = manager_load_unit(m, name, NULL, &error, &u);
1935 return bus_send_error_reply(connection, message, &error, r);
1937 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1941 if (!bus_maybe_send_reply(connection, message, reply))
1944 return DBUS_HANDLER_RESULT_HANDLED;
1947 dbus_error_free(&error);
1949 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1952 const DBusObjectPathVTable bus_manager_vtable = {
1953 .message_function = bus_manager_message_handler