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" \
238 " <method name=\"SetUnitProperties\">\n" \
239 " <arg name=\"name\" type=\"s\" direction=\"out\"/>\n" \
240 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
241 " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
244 #define BUS_MANAGER_INTERFACE_SIGNALS \
245 " <signal name=\"UnitNew\">\n" \
246 " <arg name=\"id\" type=\"s\"/>\n" \
247 " <arg name=\"unit\" type=\"o\"/>\n" \
249 " <signal name=\"UnitRemoved\">\n" \
250 " <arg name=\"id\" type=\"s\"/>\n" \
251 " <arg name=\"unit\" type=\"o\"/>\n" \
253 " <signal name=\"JobNew\">\n" \
254 " <arg name=\"id\" type=\"u\"/>\n" \
255 " <arg name=\"job\" type=\"o\"/>\n" \
256 " <arg name=\"unit\" type=\"s\"/>\n" \
258 " <signal name=\"JobRemoved\">\n" \
259 " <arg name=\"id\" type=\"u\"/>\n" \
260 " <arg name=\"job\" type=\"o\"/>\n" \
261 " <arg name=\"unit\" type=\"s\"/>\n" \
262 " <arg name=\"result\" type=\"s\"/>\n" \
264 " <signal name=\"StartupFinished\">\n" \
265 " <arg name=\"firmware\" type=\"t\"/>\n" \
266 " <arg name=\"loader\" type=\"t\"/>\n" \
267 " <arg name=\"kernel\" type=\"t\"/>\n" \
268 " <arg name=\"initrd\" type=\"t\"/>\n" \
269 " <arg name=\"userspace\" type=\"t\"/>\n" \
270 " <arg name=\"total\" type=\"t\"/>\n" \
272 " <signal name=\"UnitFilesChanged\"/>\n"
274 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
275 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
276 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
277 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
278 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
279 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
280 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
281 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
282 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
283 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
284 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
285 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
286 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
287 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
288 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
289 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
290 " <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
291 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
292 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
293 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
294 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
295 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
296 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
297 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
298 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
299 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
300 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
301 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
302 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
303 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
304 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
305 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
306 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
307 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
308 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
309 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
310 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
311 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
312 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
313 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
314 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
316 #define BUS_MANAGER_INTERFACE_END \
319 #define BUS_MANAGER_INTERFACE \
320 BUS_MANAGER_INTERFACE_BEGIN \
321 BUS_MANAGER_INTERFACE_METHODS \
322 BUS_MANAGER_INTERFACE_SIGNALS \
323 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
324 BUS_MANAGER_INTERFACE_END
326 #define INTROSPECTION_BEGIN \
327 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
329 BUS_MANAGER_INTERFACE \
330 BUS_PROPERTIES_INTERFACE \
332 BUS_INTROSPECTABLE_INTERFACE
334 #define INTROSPECTION_END \
337 #define INTERFACES_LIST \
338 BUS_GENERIC_INTERFACES_LIST \
339 "org.freedesktop.systemd1.Manager\0"
341 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
343 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
345 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
348 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
355 e = stpcpy(e, "split-usr:");
357 if (readlink_malloc("/etc/mtab", &p) < 0)
358 e = stpcpy(e, "mtab-not-symlink:");
362 if (access("/proc/cgroups", F_OK) < 0)
363 e = stpcpy(e, "cgroups-missing:");
365 if (hwclock_is_localtime() > 0)
366 e = stpcpy(e, "local-hwclock:");
368 /* remove the last ':' */
374 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
380 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
386 t = log_target_to_string(log_get_target());
388 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
394 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
400 dbus_message_iter_get_basic(i, &t);
402 return log_set_target_from_string(t);
405 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
412 r = log_level_to_string_alloc(log_get_max_level(), &t);
416 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
423 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
429 dbus_message_iter_get_basic(i, &t);
431 return log_set_max_level_from_string(t);
434 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
442 u = hashmap_size(m->units);
444 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
450 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
458 u = hashmap_size(m->jobs);
460 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
466 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
474 if (dual_timestamp_is_set(&m->finish_timestamp))
477 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
479 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
485 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
493 detect_virtualization(&id);
495 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
501 static DBusMessage *message_from_file_changes(
503 UnitFileChange *changes,
505 int carries_install_info) {
507 DBusMessageIter iter, sub, sub2;
511 reply = dbus_message_new_method_return(m);
515 dbus_message_iter_init_append(reply, &iter);
517 if (carries_install_info >= 0) {
520 b = !!carries_install_info;
521 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
525 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
528 for (i = 0; i < n_changes; i++) {
529 const char *type, *path, *source;
531 type = unit_file_change_type_to_string(changes[i].type);
532 path = strempty(changes[i].path);
533 source = strempty(changes[i].source);
535 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
536 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
537 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
538 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
539 !dbus_message_iter_close_container(&sub, &sub2))
543 if (!dbus_message_iter_close_container(&iter, &sub))
549 dbus_message_unref(reply);
553 static int bus_manager_send_unit_files_changed(Manager *m) {
557 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
561 r = bus_broadcast(m, s);
562 dbus_message_unref(s);
567 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
573 dbus_message_iter_get_basic(i, t);
575 return watchdog_set_timeout(t);
578 static const char systemd_property_string[] =
582 static const BusProperty bus_systemd_properties[] = {
583 { "Version", bus_property_append_string, "s", 0 },
584 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
588 static const BusProperty bus_manager_properties[] = {
589 { "Tainted", bus_manager_append_tainted, "s", 0 },
590 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
591 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
592 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
593 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
594 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
595 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
596 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
597 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
598 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
599 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
600 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
601 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
602 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
603 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
604 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
605 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
606 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
607 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
608 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
609 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
610 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
611 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
612 { "NNames", bus_manager_append_n_names, "u", 0 },
613 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
614 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
615 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
616 { "Progress", bus_manager_append_progress, "d", 0 },
617 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
618 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
619 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
620 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
621 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
622 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
623 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
624 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
625 { "Virtualization", bus_manager_append_virt, "s", 0, },
629 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
630 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
631 _cleanup_free_ char * path = NULL;
635 JobType job_type = _JOB_TYPE_INVALID;
636 bool reload_if_possible = false;
643 dbus_error_init(&error);
645 member = dbus_message_get_member(message);
647 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
651 if (!dbus_message_get_args(
654 DBUS_TYPE_STRING, &name,
656 return bus_send_error_reply(connection, message, &error, -EINVAL);
658 u = manager_get_unit(m, name);
660 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
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", "GetUnitByPID")) {
683 if (!dbus_message_get_args(
686 DBUS_TYPE_UINT32, &pid,
688 return bus_send_error_reply(connection, message, &error, -EINVAL);
690 u = manager_get_unit_by_pid(m, (pid_t) pid);
692 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
693 return bus_send_error_reply(connection, message, &error, -ENOENT);
696 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
698 reply = dbus_message_new_method_return(message);
702 path = unit_dbus_path(u);
706 if (!dbus_message_append_args(
708 DBUS_TYPE_OBJECT_PATH, &path,
711 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
715 if (!dbus_message_get_args(
718 DBUS_TYPE_STRING, &name,
720 return bus_send_error_reply(connection, message, &error, -EINVAL);
722 r = manager_load_unit(m, name, NULL, &error, &u);
724 return bus_send_error_reply(connection, message, &error, r);
726 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
728 reply = dbus_message_new_method_return(message);
732 path = unit_dbus_path(u);
736 if (!dbus_message_append_args(
738 DBUS_TYPE_OBJECT_PATH, &path,
742 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
743 job_type = JOB_START;
744 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
745 job_type = JOB_START;
746 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
748 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
749 job_type = JOB_RELOAD;
750 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
751 job_type = JOB_RESTART;
752 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
753 job_type = JOB_TRY_RESTART;
754 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
755 reload_if_possible = true;
756 job_type = JOB_RESTART;
757 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
758 reload_if_possible = true;
759 job_type = JOB_TRY_RESTART;
760 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
761 const char *name, *swho;
766 if (!dbus_message_get_args(
769 DBUS_TYPE_STRING, &name,
770 DBUS_TYPE_STRING, &swho,
771 DBUS_TYPE_INT32, &signo,
773 return bus_send_error_reply(connection, message, &error, -EINVAL);
778 who = kill_who_from_string(swho);
780 return bus_send_error_reply(connection, message, &error, -EINVAL);
783 if (signo <= 0 || signo >= _NSIG)
784 return bus_send_error_reply(connection, message, &error, -EINVAL);
786 u = manager_get_unit(m, name);
788 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
789 return bus_send_error_reply(connection, message, &error, -ENOENT);
792 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
794 r = unit_kill(u, who, signo, &error);
796 return bus_send_error_reply(connection, message, &error, r);
798 reply = dbus_message_new_method_return(message);
802 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
806 if (!dbus_message_get_args(
809 DBUS_TYPE_UINT32, &id,
811 return bus_send_error_reply(connection, message, &error, -EINVAL);
813 j = manager_get_job(m, id);
815 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
816 return bus_send_error_reply(connection, message, &error, -ENOENT);
819 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
821 reply = dbus_message_new_method_return(message);
825 path = job_dbus_path(j);
829 if (!dbus_message_append_args(
831 DBUS_TYPE_OBJECT_PATH, &path,
835 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
839 if (!dbus_message_get_args(
842 DBUS_TYPE_UINT32, &id,
844 return bus_send_error_reply(connection, message, &error, -EINVAL);
846 j = manager_get_job(m, id);
848 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
849 return bus_send_error_reply(connection, message, &error, -ENOENT);
852 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
853 job_finish_and_invalidate(j, JOB_CANCELED, true);
855 reply = dbus_message_new_method_return(message);
859 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
861 SELINUX_ACCESS_CHECK(connection, message, "reboot");
862 manager_clear_jobs(m);
864 reply = dbus_message_new_method_return(message);
868 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
870 SELINUX_ACCESS_CHECK(connection, message, "reload");
872 manager_reset_failed(m);
874 reply = dbus_message_new_method_return(message);
878 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
882 if (!dbus_message_get_args(
885 DBUS_TYPE_STRING, &name,
887 return bus_send_error_reply(connection, message, &error, -EINVAL);
889 u = manager_get_unit(m, name);
891 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
892 return bus_send_error_reply(connection, message, &error, -ENOENT);
895 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
897 unit_reset_failed(u);
899 reply = dbus_message_new_method_return(message);
903 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
904 DBusMessageIter iter, sub;
909 SELINUX_ACCESS_CHECK(connection, message, "status");
911 reply = dbus_message_new_method_return(message);
915 dbus_message_iter_init_append(reply, &iter);
917 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
920 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
921 char *u_path, *j_path;
922 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
923 DBusMessageIter sub2;
930 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
933 description = unit_description(u);
934 load_state = unit_load_state_to_string(u->load_state);
935 active_state = unit_active_state_to_string(unit_active_state(u));
936 sub_state = unit_sub_state_to_string(u);
938 f = unit_following(u);
939 following = f ? f->id : "";
941 u_path = unit_dbus_path(u);
946 job_id = (uint32_t) u->job->id;
948 if (!(j_path = job_dbus_path(u->job))) {
953 sjob_type = job_type_to_string(u->job->type);
960 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
961 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
962 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
963 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
964 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
965 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
966 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
967 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
968 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
969 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
980 if (!dbus_message_iter_close_container(&sub, &sub2))
984 if (!dbus_message_iter_close_container(&iter, &sub))
987 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
988 DBusMessageIter iter, sub;
992 SELINUX_ACCESS_CHECK(connection, message, "status");
994 reply = dbus_message_new_method_return(message);
998 dbus_message_iter_init_append(reply, &iter);
1000 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1003 HASHMAP_FOREACH(j, m->jobs, i) {
1004 char *u_path, *j_path;
1005 const char *state, *type;
1007 DBusMessageIter sub2;
1009 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1012 id = (uint32_t) j->id;
1013 state = job_state_to_string(j->state);
1014 type = job_type_to_string(j->type);
1016 j_path = job_dbus_path(j);
1020 u_path = unit_dbus_path(j->unit);
1026 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1027 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1028 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1029 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1030 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1031 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1040 if (!dbus_message_iter_close_container(&sub, &sub2))
1044 if (!dbus_message_iter_close_container(&iter, &sub))
1047 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1051 SELINUX_ACCESS_CHECK(connection, message, "status");
1053 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1055 s = set_new(string_hash_func, string_compare_func);
1059 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1065 client = strdup(bus_message_get_sender_with_fallback(message));
1069 r = set_consume(s, client);
1071 return bus_send_error_reply(connection, message, NULL, r);
1073 reply = dbus_message_new_method_return(message);
1077 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1080 SELINUX_ACCESS_CHECK(connection, message, "status");
1082 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1084 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1085 return bus_send_error_reply(connection, message, &error, -ENOENT);
1090 reply = dbus_message_new_method_return(message);
1094 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1099 SELINUX_ACCESS_CHECK(connection, message, "status");
1101 reply = dbus_message_new_method_return(message);
1105 f = open_memstream(&dump, &size);
1109 manager_dump_units(m, f, NULL);
1110 manager_dump_jobs(m, f, NULL);
1120 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1126 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1128 dbus_bool_t cleanup;
1131 SELINUX_ACCESS_CHECK(connection, message, "start");
1133 if (!dbus_message_get_args(
1136 DBUS_TYPE_STRING, &name,
1137 DBUS_TYPE_BOOLEAN, &cleanup,
1139 return bus_send_error_reply(connection, message, &error, -EINVAL);
1144 r = snapshot_create(m, name, cleanup, &error, &s);
1146 return bus_send_error_reply(connection, message, &error, r);
1148 reply = dbus_message_new_method_return(message);
1152 path = unit_dbus_path(UNIT(s));
1156 if (!dbus_message_append_args(
1158 DBUS_TYPE_OBJECT_PATH, &path,
1162 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1166 if (!dbus_message_get_args(
1169 DBUS_TYPE_STRING, &name,
1171 return bus_send_error_reply(connection, message, &error, -EINVAL);
1173 u = manager_get_unit(m, name);
1175 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1176 return bus_send_error_reply(connection, message, &error, -ENOENT);
1179 if (u->type != UNIT_SNAPSHOT) {
1180 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1181 return bus_send_error_reply(connection, message, &error, -ENOENT);
1184 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1185 snapshot_remove(SNAPSHOT(u));
1187 reply = dbus_message_new_method_return(message);
1191 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1192 char *introspection = NULL;
1200 SELINUX_ACCESS_CHECK(connection, message, "status");
1202 reply = dbus_message_new_method_return(message);
1206 /* We roll our own introspection code here, instead of
1207 * relying on bus_default_message_handler() because we
1208 * need to generate our introspection string
1211 f = open_memstream(&introspection, &size);
1215 fputs(INTROSPECTION_BEGIN, f);
1217 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1223 p = bus_path_escape(k);
1226 free(introspection);
1230 fprintf(f, "<node name=\"unit/%s\"/>", p);
1234 HASHMAP_FOREACH(j, m->jobs, i)
1235 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1237 fputs(INTROSPECTION_END, f);
1241 free(introspection);
1250 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1251 free(introspection);
1255 free(introspection);
1257 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1259 SELINUX_ACCESS_CHECK(connection, message, "reload");
1261 assert(!m->queued_message);
1263 /* Instead of sending the reply back right away, we
1264 * just remember that we need to and then send it
1265 * after the reload is finished. That way the caller
1266 * knows when the reload finished. */
1268 m->queued_message = dbus_message_new_method_return(message);
1269 if (!m->queued_message)
1272 m->queued_message_connection = connection;
1273 m->exit_code = MANAGER_RELOAD;
1275 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1277 SELINUX_ACCESS_CHECK(connection, message, "reload");
1279 /* We don't send a reply back here, the client should
1280 * just wait for us disconnecting. */
1282 m->exit_code = MANAGER_REEXECUTE;
1284 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1286 SELINUX_ACCESS_CHECK(connection, message, "halt");
1288 if (m->running_as == SYSTEMD_SYSTEM) {
1289 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1290 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1293 reply = dbus_message_new_method_return(message);
1297 m->exit_code = MANAGER_EXIT;
1299 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1301 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1303 if (m->running_as != SYSTEMD_SYSTEM) {
1304 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1305 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1308 reply = dbus_message_new_method_return(message);
1312 m->exit_code = MANAGER_REBOOT;
1314 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1316 SELINUX_ACCESS_CHECK(connection, message, "halt");
1318 if (m->running_as != SYSTEMD_SYSTEM) {
1319 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1320 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1323 reply = dbus_message_new_method_return(message);
1327 m->exit_code = MANAGER_POWEROFF;
1329 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1331 SELINUX_ACCESS_CHECK(connection, message, "halt");
1333 if (m->running_as != SYSTEMD_SYSTEM) {
1334 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1335 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1338 reply = dbus_message_new_method_return(message);
1342 m->exit_code = MANAGER_HALT;
1344 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1346 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1348 if (m->running_as != SYSTEMD_SYSTEM) {
1349 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1350 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1353 reply = dbus_message_new_method_return(message);
1357 m->exit_code = MANAGER_KEXEC;
1359 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1360 const char *switch_root, *switch_root_init;
1364 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1366 if (!dbus_message_get_args(
1369 DBUS_TYPE_STRING, &switch_root,
1370 DBUS_TYPE_STRING, &switch_root_init,
1372 return bus_send_error_reply(connection, message, &error, -EINVAL);
1374 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1375 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1377 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1378 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1380 if (m->running_as != SYSTEMD_SYSTEM) {
1381 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1382 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1386 if (isempty(switch_root_init)) {
1387 good = path_is_os_tree(switch_root);
1389 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1392 _cleanup_free_ char *p = NULL;
1394 p = strjoin(switch_root, "/", switch_root_init, NULL);
1398 good = access(p, X_OK) >= 0;
1400 log_error("Not switching root: cannot execute new init %s", p);
1403 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1405 u = strdup(switch_root);
1409 if (!isempty(switch_root_init)) {
1410 v = strdup(switch_root_init);
1418 free(m->switch_root);
1419 free(m->switch_root_init);
1421 m->switch_root_init = v;
1423 reply = dbus_message_new_method_return(message);
1427 m->exit_code = MANAGER_SWITCH_ROOT;
1429 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1430 _cleanup_strv_free_ char **l = NULL;
1433 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1435 r = bus_parse_strv(message, &l);
1439 return bus_send_error_reply(connection, message, NULL, r);
1440 if (!strv_env_is_valid(l))
1441 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1443 e = strv_env_merge(2, m->environment, l);
1447 reply = dbus_message_new_method_return(message);
1453 strv_free(m->environment);
1456 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1457 _cleanup_strv_free_ char **l = NULL;
1460 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1462 r = bus_parse_strv(message, &l);
1466 return bus_send_error_reply(connection, message, NULL, r);
1467 if (!strv_env_name_or_assignment_is_valid(l))
1468 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1470 e = strv_env_delete(m->environment, 1, l);
1474 reply = dbus_message_new_method_return(message);
1480 strv_free(m->environment);
1483 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1484 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1486 DBusMessageIter iter;
1488 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1490 if (!dbus_message_iter_init(message, &iter))
1493 r = bus_parse_strv_iter(&iter, &l_unset);
1497 return bus_send_error_reply(connection, message, NULL, r);
1498 if (!strv_env_name_or_assignment_is_valid(l_unset))
1499 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1501 if (!dbus_message_iter_next(&iter))
1502 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1504 r = bus_parse_strv_iter(&iter, &l_set);
1508 return bus_send_error_reply(connection, message, NULL, r);
1509 if (!strv_env_is_valid(l_set))
1510 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1512 e = strv_env_delete(m->environment, 1, l_unset);
1516 f = strv_env_merge(2, e, l_set);
1520 reply = dbus_message_new_method_return(message);
1526 strv_free(m->environment);
1528 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1529 DBusMessageIter iter, sub, sub2;
1534 SELINUX_ACCESS_CHECK(connection, message, "status");
1536 reply = dbus_message_new_method_return(message);
1540 h = hashmap_new(string_hash_func, string_compare_func);
1544 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1546 unit_file_list_free(h);
1547 return bus_send_error_reply(connection, message, NULL, r);
1550 dbus_message_iter_init_append(reply, &iter);
1552 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1553 unit_file_list_free(h);
1557 HASHMAP_FOREACH(item, h, i) {
1560 state = unit_file_state_to_string(item->state);
1563 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1565 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1566 !dbus_message_iter_close_container(&sub, &sub2)) {
1567 unit_file_list_free(h);
1572 unit_file_list_free(h);
1574 if (!dbus_message_iter_close_container(&iter, &sub))
1577 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1579 UnitFileState state;
1582 SELINUX_ACCESS_CHECK(connection, message, "status");
1584 if (!dbus_message_get_args(
1587 DBUS_TYPE_STRING, &name,
1589 return bus_send_error_reply(connection, message, &error, -EINVAL);
1591 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1593 return bus_send_error_reply(connection, message, NULL, state);
1595 s = unit_file_state_to_string(state);
1598 reply = dbus_message_new_method_return(message);
1602 if (!dbus_message_append_args(
1604 DBUS_TYPE_STRING, &s,
1607 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1608 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1609 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1610 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1611 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1612 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1615 DBusMessageIter iter;
1616 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1617 UnitFileChange *changes = NULL;
1618 unsigned n_changes = 0;
1619 dbus_bool_t runtime, force;
1620 int carries_install_info = -1;
1622 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1624 if (!dbus_message_iter_init(message, &iter))
1627 r = bus_parse_strv_iter(&iter, &l);
1632 return bus_send_error_reply(connection, message, NULL, r);
1635 if (!dbus_message_iter_next(&iter) ||
1636 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1637 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1639 return bus_send_error_reply(connection, message, NULL, -EIO);
1642 if (streq(member, "EnableUnitFiles")) {
1643 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1644 carries_install_info = r;
1645 } else if (streq(member, "ReenableUnitFiles")) {
1646 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1647 carries_install_info = r;
1648 } else if (streq(member, "LinkUnitFiles"))
1649 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1650 else if (streq(member, "PresetUnitFiles")) {
1651 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1652 carries_install_info = r;
1653 } else if (streq(member, "MaskUnitFiles"))
1654 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1655 else if (streq(member, "SetDefaultTarget"))
1656 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1658 assert_not_reached("Uh? Wrong method");
1661 bus_manager_send_unit_files_changed(m);
1664 unit_file_changes_free(changes, n_changes);
1665 return bus_send_error_reply(connection, message, NULL, r);
1668 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1669 unit_file_changes_free(changes, n_changes);
1674 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1675 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1678 DBusMessageIter iter;
1679 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1680 UnitFileChange *changes = NULL;
1681 unsigned n_changes = 0;
1682 dbus_bool_t runtime;
1684 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1686 if (!dbus_message_iter_init(message, &iter))
1689 r = bus_parse_strv_iter(&iter, &l);
1694 return bus_send_error_reply(connection, message, NULL, r);
1697 if (!dbus_message_iter_next(&iter) ||
1698 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1700 return bus_send_error_reply(connection, message, NULL, -EIO);
1703 if (streq(member, "DisableUnitFiles"))
1704 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1705 else if (streq(member, "UnmaskUnitFiles"))
1706 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1708 assert_not_reached("Uh? Wrong method");
1711 bus_manager_send_unit_files_changed(m);
1714 unit_file_changes_free(changes, n_changes);
1715 return bus_send_error_reply(connection, message, NULL, r);
1718 reply = message_from_file_changes(message, changes, n_changes, -1);
1719 unit_file_changes_free(changes, n_changes);
1724 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1725 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1726 _cleanup_free_ char *default_target = NULL;
1728 reply = dbus_message_new_method_return(message);
1732 r = unit_file_get_default(scope, NULL, &default_target);
1734 return bus_send_error_reply(connection, message, NULL, r);
1736 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1740 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1741 DBusMessageIter iter;
1742 dbus_bool_t runtime;
1746 if (!dbus_message_iter_init(message, &iter))
1749 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1750 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1751 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1753 u = manager_get_unit(m, name);
1755 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1756 return bus_send_error_reply(connection, message, &error, -ENOENT);
1759 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1761 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, &error);
1763 return bus_send_error_reply(connection, message, &error, r);
1765 reply = dbus_message_new_method_return(message);
1770 const BusBoundProperties bps[] = {
1771 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1772 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1776 SELINUX_ACCESS_CHECK(connection, message, "status");
1778 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1781 if (job_type != _JOB_TYPE_INVALID) {
1782 const char *name, *smode, *old_name = NULL;
1787 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1788 b = dbus_message_get_args(
1791 DBUS_TYPE_STRING, &old_name,
1792 DBUS_TYPE_STRING, &name,
1793 DBUS_TYPE_STRING, &smode,
1796 b = dbus_message_get_args(
1799 DBUS_TYPE_STRING, &name,
1800 DBUS_TYPE_STRING, &smode,
1803 return bus_send_error_reply(connection, message, &error, -EINVAL);
1806 u = manager_get_unit(m, old_name);
1807 if (!u || !u->job || u->job->type != JOB_START) {
1808 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1809 return bus_send_error_reply(connection, message, &error, -ENOENT);
1813 mode = job_mode_from_string(smode);
1815 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1816 return bus_send_error_reply(connection, message, &error, -EINVAL);
1819 r = manager_load_unit(m, name, NULL, &error, &u);
1821 return bus_send_error_reply(connection, message, &error, r);
1823 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1827 if (!bus_maybe_send_reply(connection, message, reply))
1830 return DBUS_HANDLER_RESULT_HANDLED;
1833 dbus_error_free(&error);
1835 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1838 const DBusObjectPathVTable bus_manager_vtable = {
1839 .message_function = bus_manager_message_handler