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=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
305 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
306 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
307 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
308 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
309 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
311 #define BUS_MANAGER_INTERFACE_END \
314 #define BUS_MANAGER_INTERFACE \
315 BUS_MANAGER_INTERFACE_BEGIN \
316 BUS_MANAGER_INTERFACE_METHODS \
317 BUS_MANAGER_INTERFACE_SIGNALS \
318 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
319 BUS_MANAGER_INTERFACE_END
321 #define INTROSPECTION_BEGIN \
322 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
324 BUS_MANAGER_INTERFACE \
325 BUS_PROPERTIES_INTERFACE \
327 BUS_INTROSPECTABLE_INTERFACE
329 #define INTROSPECTION_END \
332 #define INTERFACES_LIST \
333 BUS_GENERIC_INTERFACES_LIST \
334 "org.freedesktop.systemd1.Manager\0"
336 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
338 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
340 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
343 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
350 e = stpcpy(e, "split-usr:");
352 if (readlink_malloc("/etc/mtab", &p) < 0)
353 e = stpcpy(e, "mtab-not-symlink:");
357 if (access("/proc/cgroups", F_OK) < 0)
358 e = stpcpy(e, "cgroups-missing:");
360 if (hwclock_is_localtime() > 0)
361 e = stpcpy(e, "local-hwclock:");
363 /* remove the last ':' */
369 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
375 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
381 t = log_target_to_string(log_get_target());
383 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
389 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
395 dbus_message_iter_get_basic(i, &t);
397 return log_set_target_from_string(t);
400 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
407 r = log_level_to_string_alloc(log_get_max_level(), &t);
411 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
418 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
424 dbus_message_iter_get_basic(i, &t);
426 return log_set_max_level_from_string(t);
429 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
437 u = hashmap_size(m->units);
439 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
445 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
453 u = hashmap_size(m->jobs);
455 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
461 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
469 if (dual_timestamp_is_set(&m->finish_timestamp))
472 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
474 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
480 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
488 detect_virtualization(&id);
490 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
496 static DBusMessage *message_from_file_changes(
498 UnitFileChange *changes,
500 int carries_install_info) {
502 DBusMessageIter iter, sub, sub2;
506 reply = dbus_message_new_method_return(m);
510 dbus_message_iter_init_append(reply, &iter);
512 if (carries_install_info >= 0) {
515 b = !!carries_install_info;
516 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
520 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
523 for (i = 0; i < n_changes; i++) {
524 const char *type, *path, *source;
526 type = unit_file_change_type_to_string(changes[i].type);
527 path = strempty(changes[i].path);
528 source = strempty(changes[i].source);
530 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
531 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
532 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
533 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
534 !dbus_message_iter_close_container(&sub, &sub2))
538 if (!dbus_message_iter_close_container(&iter, &sub))
544 dbus_message_unref(reply);
548 static int bus_manager_send_unit_files_changed(Manager *m) {
552 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
556 r = bus_broadcast(m, s);
557 dbus_message_unref(s);
562 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
568 dbus_message_iter_get_basic(i, t);
570 return watchdog_set_timeout(t);
573 static const char systemd_property_string[] =
577 static const BusProperty bus_systemd_properties[] = {
578 { "Version", bus_property_append_string, "s", 0 },
579 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
583 static const BusProperty bus_manager_properties[] = {
584 { "Tainted", bus_manager_append_tainted, "s", 0 },
585 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
586 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
587 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
588 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
589 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
590 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
591 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
592 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
593 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
594 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
595 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
596 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
597 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
598 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
599 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
600 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
601 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
602 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
603 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
604 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
605 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
606 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
607 { "NNames", bus_manager_append_n_names, "u", 0 },
608 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
609 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
610 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
611 { "Progress", bus_manager_append_progress, "d", 0 },
612 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
613 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
614 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
615 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
616 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
617 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
618 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
619 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
620 { "Virtualization", bus_manager_append_virt, "s", 0, },
624 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
625 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
626 _cleanup_free_ char * path = NULL;
630 JobType job_type = _JOB_TYPE_INVALID;
631 bool reload_if_possible = false;
638 dbus_error_init(&error);
640 member = dbus_message_get_member(message);
642 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
646 if (!dbus_message_get_args(
649 DBUS_TYPE_STRING, &name,
651 return bus_send_error_reply(connection, message, &error, -EINVAL);
653 u = manager_get_unit(m, name);
655 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
656 return bus_send_error_reply(connection, message, &error, -ENOENT);
659 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
661 reply = dbus_message_new_method_return(message);
665 path = unit_dbus_path(u);
669 if (!dbus_message_append_args(
671 DBUS_TYPE_OBJECT_PATH, &path,
674 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
678 if (!dbus_message_get_args(
681 DBUS_TYPE_UINT32, &pid,
683 return bus_send_error_reply(connection, message, &error, -EINVAL);
685 u = manager_get_unit_by_pid(m, (pid_t) pid);
687 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
688 return bus_send_error_reply(connection, message, &error, -ENOENT);
691 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
693 reply = dbus_message_new_method_return(message);
697 path = unit_dbus_path(u);
701 if (!dbus_message_append_args(
703 DBUS_TYPE_OBJECT_PATH, &path,
706 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
710 if (!dbus_message_get_args(
713 DBUS_TYPE_STRING, &name,
715 return bus_send_error_reply(connection, message, &error, -EINVAL);
717 r = manager_load_unit(m, name, NULL, &error, &u);
719 return bus_send_error_reply(connection, message, &error, r);
721 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
723 reply = dbus_message_new_method_return(message);
727 path = unit_dbus_path(u);
731 if (!dbus_message_append_args(
733 DBUS_TYPE_OBJECT_PATH, &path,
737 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
738 job_type = JOB_START;
739 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
740 job_type = JOB_START;
741 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
743 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
744 job_type = JOB_RELOAD;
745 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
746 job_type = JOB_RESTART;
747 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
748 job_type = JOB_TRY_RESTART;
749 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
750 reload_if_possible = true;
751 job_type = JOB_RESTART;
752 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
753 reload_if_possible = true;
754 job_type = JOB_TRY_RESTART;
755 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
756 const char *name, *swho;
761 if (!dbus_message_get_args(
764 DBUS_TYPE_STRING, &name,
765 DBUS_TYPE_STRING, &swho,
766 DBUS_TYPE_INT32, &signo,
768 return bus_send_error_reply(connection, message, &error, -EINVAL);
773 who = kill_who_from_string(swho);
775 return bus_send_error_reply(connection, message, &error, -EINVAL);
778 if (signo <= 0 || signo >= _NSIG)
779 return bus_send_error_reply(connection, message, &error, -EINVAL);
781 u = manager_get_unit(m, name);
783 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
784 return bus_send_error_reply(connection, message, &error, -ENOENT);
787 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
789 r = unit_kill(u, who, signo, &error);
791 return bus_send_error_reply(connection, message, &error, r);
793 reply = dbus_message_new_method_return(message);
797 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
801 if (!dbus_message_get_args(
804 DBUS_TYPE_UINT32, &id,
806 return bus_send_error_reply(connection, message, &error, -EINVAL);
808 j = manager_get_job(m, id);
810 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
811 return bus_send_error_reply(connection, message, &error, -ENOENT);
814 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
816 reply = dbus_message_new_method_return(message);
820 path = job_dbus_path(j);
824 if (!dbus_message_append_args(
826 DBUS_TYPE_OBJECT_PATH, &path,
830 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
834 if (!dbus_message_get_args(
837 DBUS_TYPE_UINT32, &id,
839 return bus_send_error_reply(connection, message, &error, -EINVAL);
841 j = manager_get_job(m, id);
843 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
844 return bus_send_error_reply(connection, message, &error, -ENOENT);
847 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
848 job_finish_and_invalidate(j, JOB_CANCELED, true);
850 reply = dbus_message_new_method_return(message);
854 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
856 SELINUX_ACCESS_CHECK(connection, message, "reboot");
857 manager_clear_jobs(m);
859 reply = dbus_message_new_method_return(message);
863 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
865 SELINUX_ACCESS_CHECK(connection, message, "reload");
867 manager_reset_failed(m);
869 reply = dbus_message_new_method_return(message);
873 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
877 if (!dbus_message_get_args(
880 DBUS_TYPE_STRING, &name,
882 return bus_send_error_reply(connection, message, &error, -EINVAL);
884 u = manager_get_unit(m, name);
886 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
887 return bus_send_error_reply(connection, message, &error, -ENOENT);
890 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
892 unit_reset_failed(u);
894 reply = dbus_message_new_method_return(message);
898 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
899 DBusMessageIter iter, sub;
904 SELINUX_ACCESS_CHECK(connection, message, "status");
906 reply = dbus_message_new_method_return(message);
910 dbus_message_iter_init_append(reply, &iter);
912 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
915 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
916 char *u_path, *j_path;
917 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
918 DBusMessageIter sub2;
925 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
928 description = unit_description(u);
929 load_state = unit_load_state_to_string(u->load_state);
930 active_state = unit_active_state_to_string(unit_active_state(u));
931 sub_state = unit_sub_state_to_string(u);
933 f = unit_following(u);
934 following = f ? f->id : "";
936 u_path = unit_dbus_path(u);
941 job_id = (uint32_t) u->job->id;
943 if (!(j_path = job_dbus_path(u->job))) {
948 sjob_type = job_type_to_string(u->job->type);
955 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
956 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
957 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
958 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
959 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
960 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
961 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
962 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
963 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
964 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
975 if (!dbus_message_iter_close_container(&sub, &sub2))
979 if (!dbus_message_iter_close_container(&iter, &sub))
982 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
983 DBusMessageIter iter, sub;
987 SELINUX_ACCESS_CHECK(connection, message, "status");
989 reply = dbus_message_new_method_return(message);
993 dbus_message_iter_init_append(reply, &iter);
995 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
998 HASHMAP_FOREACH(j, m->jobs, i) {
999 char *u_path, *j_path;
1000 const char *state, *type;
1002 DBusMessageIter sub2;
1004 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1007 id = (uint32_t) j->id;
1008 state = job_state_to_string(j->state);
1009 type = job_type_to_string(j->type);
1011 j_path = job_dbus_path(j);
1015 u_path = unit_dbus_path(j->unit);
1021 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1022 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1023 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1024 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1025 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1026 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1035 if (!dbus_message_iter_close_container(&sub, &sub2))
1039 if (!dbus_message_iter_close_container(&iter, &sub))
1042 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1046 SELINUX_ACCESS_CHECK(connection, message, "status");
1048 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1050 s = set_new(string_hash_func, string_compare_func);
1054 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1060 client = strdup(bus_message_get_sender_with_fallback(message));
1064 r = set_consume(s, client);
1066 return bus_send_error_reply(connection, message, NULL, r);
1068 reply = dbus_message_new_method_return(message);
1072 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1075 SELINUX_ACCESS_CHECK(connection, message, "status");
1077 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1079 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1080 return bus_send_error_reply(connection, message, &error, -ENOENT);
1085 reply = dbus_message_new_method_return(message);
1089 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1094 SELINUX_ACCESS_CHECK(connection, message, "status");
1096 reply = dbus_message_new_method_return(message);
1100 f = open_memstream(&dump, &size);
1104 manager_dump_units(m, f, NULL);
1105 manager_dump_jobs(m, f, NULL);
1115 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1121 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1123 dbus_bool_t cleanup;
1126 SELINUX_ACCESS_CHECK(connection, message, "start");
1128 if (!dbus_message_get_args(
1131 DBUS_TYPE_STRING, &name,
1132 DBUS_TYPE_BOOLEAN, &cleanup,
1134 return bus_send_error_reply(connection, message, &error, -EINVAL);
1139 r = snapshot_create(m, name, cleanup, &error, &s);
1141 return bus_send_error_reply(connection, message, &error, r);
1143 reply = dbus_message_new_method_return(message);
1147 path = unit_dbus_path(UNIT(s));
1151 if (!dbus_message_append_args(
1153 DBUS_TYPE_OBJECT_PATH, &path,
1157 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1161 if (!dbus_message_get_args(
1164 DBUS_TYPE_STRING, &name,
1166 return bus_send_error_reply(connection, message, &error, -EINVAL);
1168 u = manager_get_unit(m, name);
1170 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1171 return bus_send_error_reply(connection, message, &error, -ENOENT);
1174 if (u->type != UNIT_SNAPSHOT) {
1175 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1176 return bus_send_error_reply(connection, message, &error, -ENOENT);
1179 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1180 snapshot_remove(SNAPSHOT(u));
1182 reply = dbus_message_new_method_return(message);
1186 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1187 char *introspection = NULL;
1195 SELINUX_ACCESS_CHECK(connection, message, "status");
1197 reply = dbus_message_new_method_return(message);
1201 /* We roll our own introspection code here, instead of
1202 * relying on bus_default_message_handler() because we
1203 * need to generate our introspection string
1206 f = open_memstream(&introspection, &size);
1210 fputs(INTROSPECTION_BEGIN, f);
1212 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1218 p = bus_path_escape(k);
1221 free(introspection);
1225 fprintf(f, "<node name=\"unit/%s\"/>", p);
1229 HASHMAP_FOREACH(j, m->jobs, i)
1230 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1232 fputs(INTROSPECTION_END, f);
1236 free(introspection);
1245 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1246 free(introspection);
1250 free(introspection);
1252 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1254 SELINUX_ACCESS_CHECK(connection, message, "reload");
1256 assert(!m->queued_message);
1258 /* Instead of sending the reply back right away, we
1259 * just remember that we need to and then send it
1260 * after the reload is finished. That way the caller
1261 * knows when the reload finished. */
1263 m->queued_message = dbus_message_new_method_return(message);
1264 if (!m->queued_message)
1267 m->queued_message_connection = connection;
1268 m->exit_code = MANAGER_RELOAD;
1270 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1272 SELINUX_ACCESS_CHECK(connection, message, "reload");
1274 /* We don't send a reply back here, the client should
1275 * just wait for us disconnecting. */
1277 m->exit_code = MANAGER_REEXECUTE;
1279 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1281 SELINUX_ACCESS_CHECK(connection, message, "halt");
1283 if (m->running_as == SYSTEMD_SYSTEM) {
1284 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1285 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1288 reply = dbus_message_new_method_return(message);
1292 m->exit_code = MANAGER_EXIT;
1294 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1296 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1298 if (m->running_as != SYSTEMD_SYSTEM) {
1299 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1300 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1303 reply = dbus_message_new_method_return(message);
1307 m->exit_code = MANAGER_REBOOT;
1309 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1311 SELINUX_ACCESS_CHECK(connection, message, "halt");
1313 if (m->running_as != SYSTEMD_SYSTEM) {
1314 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1315 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1318 reply = dbus_message_new_method_return(message);
1322 m->exit_code = MANAGER_POWEROFF;
1324 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1326 SELINUX_ACCESS_CHECK(connection, message, "halt");
1328 if (m->running_as != SYSTEMD_SYSTEM) {
1329 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1330 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1333 reply = dbus_message_new_method_return(message);
1337 m->exit_code = MANAGER_HALT;
1339 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1341 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1343 if (m->running_as != SYSTEMD_SYSTEM) {
1344 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1345 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1348 reply = dbus_message_new_method_return(message);
1352 m->exit_code = MANAGER_KEXEC;
1354 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1355 const char *switch_root, *switch_root_init;
1359 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1361 if (!dbus_message_get_args(
1364 DBUS_TYPE_STRING, &switch_root,
1365 DBUS_TYPE_STRING, &switch_root_init,
1367 return bus_send_error_reply(connection, message, &error, -EINVAL);
1369 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1370 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1372 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1373 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1375 if (m->running_as != SYSTEMD_SYSTEM) {
1376 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1377 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1381 if (isempty(switch_root_init)) {
1382 good = path_is_os_tree(switch_root);
1384 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1387 _cleanup_free_ char *p = NULL;
1389 p = strjoin(switch_root, "/", switch_root_init, NULL);
1393 good = access(p, X_OK) >= 0;
1395 log_error("Not switching root: cannot execute new init %s", p);
1398 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1400 u = strdup(switch_root);
1404 if (!isempty(switch_root_init)) {
1405 v = strdup(switch_root_init);
1413 free(m->switch_root);
1414 free(m->switch_root_init);
1416 m->switch_root_init = v;
1418 reply = dbus_message_new_method_return(message);
1422 m->exit_code = MANAGER_SWITCH_ROOT;
1424 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1425 _cleanup_strv_free_ char **l = NULL;
1428 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1430 r = bus_parse_strv(message, &l);
1434 return bus_send_error_reply(connection, message, NULL, r);
1435 if (!strv_env_is_valid(l))
1436 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1438 e = strv_env_merge(2, m->environment, l);
1442 reply = dbus_message_new_method_return(message);
1448 strv_free(m->environment);
1451 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1452 _cleanup_strv_free_ char **l = NULL;
1455 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1457 r = bus_parse_strv(message, &l);
1461 return bus_send_error_reply(connection, message, NULL, r);
1462 if (!strv_env_name_or_assignment_is_valid(l))
1463 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1465 e = strv_env_delete(m->environment, 1, l);
1469 reply = dbus_message_new_method_return(message);
1475 strv_free(m->environment);
1478 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1479 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1481 DBusMessageIter iter;
1483 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1485 if (!dbus_message_iter_init(message, &iter))
1488 r = bus_parse_strv_iter(&iter, &l_unset);
1492 return bus_send_error_reply(connection, message, NULL, r);
1493 if (!strv_env_name_or_assignment_is_valid(l_unset))
1494 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1496 if (!dbus_message_iter_next(&iter))
1497 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1499 r = bus_parse_strv_iter(&iter, &l_set);
1503 return bus_send_error_reply(connection, message, NULL, r);
1504 if (!strv_env_is_valid(l_set))
1505 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1507 e = strv_env_delete(m->environment, 1, l_unset);
1511 f = strv_env_merge(2, e, l_set);
1515 reply = dbus_message_new_method_return(message);
1521 strv_free(m->environment);
1523 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1524 DBusMessageIter iter, sub, sub2;
1529 SELINUX_ACCESS_CHECK(connection, message, "status");
1531 reply = dbus_message_new_method_return(message);
1535 h = hashmap_new(string_hash_func, string_compare_func);
1539 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1541 unit_file_list_free(h);
1542 return bus_send_error_reply(connection, message, NULL, r);
1545 dbus_message_iter_init_append(reply, &iter);
1547 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1548 unit_file_list_free(h);
1552 HASHMAP_FOREACH(item, h, i) {
1555 state = unit_file_state_to_string(item->state);
1558 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1559 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1560 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1561 !dbus_message_iter_close_container(&sub, &sub2)) {
1562 unit_file_list_free(h);
1567 unit_file_list_free(h);
1569 if (!dbus_message_iter_close_container(&iter, &sub))
1572 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1574 UnitFileState state;
1577 SELINUX_ACCESS_CHECK(connection, message, "status");
1579 if (!dbus_message_get_args(
1582 DBUS_TYPE_STRING, &name,
1584 return bus_send_error_reply(connection, message, &error, -EINVAL);
1586 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1588 return bus_send_error_reply(connection, message, NULL, state);
1590 s = unit_file_state_to_string(state);
1593 reply = dbus_message_new_method_return(message);
1597 if (!dbus_message_append_args(
1599 DBUS_TYPE_STRING, &s,
1602 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1603 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1604 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1605 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1606 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1607 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1610 DBusMessageIter iter;
1611 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1612 UnitFileChange *changes = NULL;
1613 unsigned n_changes = 0;
1614 dbus_bool_t runtime, force;
1615 int carries_install_info = -1;
1617 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1619 if (!dbus_message_iter_init(message, &iter))
1622 r = bus_parse_strv_iter(&iter, &l);
1627 return bus_send_error_reply(connection, message, NULL, r);
1630 if (!dbus_message_iter_next(&iter) ||
1631 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1632 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1634 return bus_send_error_reply(connection, message, NULL, -EIO);
1637 if (streq(member, "EnableUnitFiles")) {
1638 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1639 carries_install_info = r;
1640 } else if (streq(member, "ReenableUnitFiles")) {
1641 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1642 carries_install_info = r;
1643 } else if (streq(member, "LinkUnitFiles"))
1644 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1645 else if (streq(member, "PresetUnitFiles")) {
1646 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1647 carries_install_info = r;
1648 } else if (streq(member, "MaskUnitFiles"))
1649 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1650 else if (streq(member, "SetDefaultTarget"))
1651 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1653 assert_not_reached("Uh? Wrong method");
1656 bus_manager_send_unit_files_changed(m);
1659 unit_file_changes_free(changes, n_changes);
1660 return bus_send_error_reply(connection, message, NULL, r);
1663 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1664 unit_file_changes_free(changes, n_changes);
1669 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1670 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1673 DBusMessageIter iter;
1674 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1675 UnitFileChange *changes = NULL;
1676 unsigned n_changes = 0;
1677 dbus_bool_t runtime;
1679 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1681 if (!dbus_message_iter_init(message, &iter))
1684 r = bus_parse_strv_iter(&iter, &l);
1689 return bus_send_error_reply(connection, message, NULL, r);
1692 if (!dbus_message_iter_next(&iter) ||
1693 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1695 return bus_send_error_reply(connection, message, NULL, -EIO);
1698 if (streq(member, "DisableUnitFiles"))
1699 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1700 else if (streq(member, "UnmaskUnitFiles"))
1701 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1703 assert_not_reached("Uh? Wrong method");
1706 bus_manager_send_unit_files_changed(m);
1709 unit_file_changes_free(changes, n_changes);
1710 return bus_send_error_reply(connection, message, NULL, r);
1713 reply = message_from_file_changes(message, changes, n_changes, -1);
1714 unit_file_changes_free(changes, n_changes);
1719 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1720 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1721 _cleanup_free_ char *default_target = NULL;
1723 reply = dbus_message_new_method_return(message);
1727 r = unit_file_get_default(scope, NULL, &default_target);
1730 return bus_send_error_reply(connection, message, NULL, r);
1732 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1736 const BusBoundProperties bps[] = {
1737 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1738 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1742 SELINUX_ACCESS_CHECK(connection, message, "status");
1744 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1747 if (job_type != _JOB_TYPE_INVALID) {
1748 const char *name, *smode, *old_name = NULL;
1753 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1754 b = dbus_message_get_args(
1757 DBUS_TYPE_STRING, &old_name,
1758 DBUS_TYPE_STRING, &name,
1759 DBUS_TYPE_STRING, &smode,
1762 b = dbus_message_get_args(
1765 DBUS_TYPE_STRING, &name,
1766 DBUS_TYPE_STRING, &smode,
1769 return bus_send_error_reply(connection, message, &error, -EINVAL);
1772 u = manager_get_unit(m, old_name);
1773 if (!u || !u->job || u->job->type != JOB_START) {
1774 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1775 return bus_send_error_reply(connection, message, &error, -ENOENT);
1779 mode = job_mode_from_string(smode);
1781 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1782 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 r = manager_load_unit(m, name, NULL, &error, &u);
1787 return bus_send_error_reply(connection, message, &error, r);
1789 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1793 if (!bus_maybe_send_reply(connection, message, reply))
1796 return DBUS_HANDLER_RESULT_HANDLED;
1799 dbus_error_free(&error);
1801 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1804 const DBusObjectPathVTable bus_manager_vtable = {
1805 .message_function = bus_manager_message_handler