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=\"GetJob\">\n" \
107 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
108 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
110 " <method name=\"CancelJob\">\n" \
111 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
113 " <method name=\"ClearJobs\"/>\n" \
114 " <method name=\"ResetFailed\"/>\n" \
115 " <method name=\"ListUnits\">\n" \
116 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
118 " <method name=\"ListJobs\">\n" \
119 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
121 " <method name=\"Subscribe\"/>\n" \
122 " <method name=\"Unsubscribe\"/>\n" \
123 " <method name=\"Dump\">\n" \
124 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
126 " <method name=\"CreateSnapshot\">\n" \
127 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
128 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
129 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
131 " <method name=\"RemoveSnapshot\">\n" \
132 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
134 " <method name=\"Reload\"/>\n" \
135 " <method name=\"Reexecute\"/>\n" \
136 " <method name=\"Exit\"/>\n" \
137 " <method name=\"Reboot\"/>\n" \
138 " <method name=\"PowerOff\"/>\n" \
139 " <method name=\"Halt\"/>\n" \
140 " <method name=\"KExec\"/>\n" \
141 " <method name=\"SwitchRoot\">\n" \
142 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
143 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
145 " <method name=\"SetEnvironment\">\n" \
146 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
148 " <method name=\"UnsetEnvironment\">\n" \
149 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
151 " <method name=\"UnsetAndSetEnvironment\">\n" \
152 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
153 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
155 " <method name=\"ListUnitFiles\">\n" \
156 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
158 " <method name=\"GetUnitFileState\">\n" \
159 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
160 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
162 " <method name=\"EnableUnitFiles\">\n" \
163 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
164 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
165 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
166 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
167 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
169 " <method name=\"DisableUnitFiles\">\n" \
170 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
171 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
172 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
174 " <method name=\"ReenableUnitFiles\">\n" \
175 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
176 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
177 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
178 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
179 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
181 " <method name=\"LinkUnitFiles\">\n" \
182 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
183 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
184 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
185 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
187 " <method name=\"PresetUnitFiles\">\n" \
188 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
189 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
190 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
191 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
192 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
194 " <method name=\"MaskUnitFiles\">\n" \
195 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
196 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
197 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
198 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
200 " <method name=\"UnmaskUnitFiles\">\n" \
201 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
202 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
203 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
205 " <method name=\"SetDefaultTarget\">\n" \
206 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
207 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
209 " <method name=\"GetDefaultTarget\">\n" \
210 " <arg name=\"name\" type=\"s\" direction=\"out\"/>\n" \
212 " <method name=\"SetUnitProperties\">\n" \
213 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
214 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
215 " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
217 " <method name=\"StartTransientUnit\">\n" \
218 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
219 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
220 " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
221 " <arg name=\"aux\" type=\"a(sa(sv))\" direction=\"in\"/>\n" \
222 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
225 #define BUS_MANAGER_INTERFACE_SIGNALS \
226 " <signal name=\"UnitNew\">\n" \
227 " <arg name=\"id\" type=\"s\"/>\n" \
228 " <arg name=\"unit\" type=\"o\"/>\n" \
230 " <signal name=\"UnitRemoved\">\n" \
231 " <arg name=\"id\" type=\"s\"/>\n" \
232 " <arg name=\"unit\" type=\"o\"/>\n" \
234 " <signal name=\"JobNew\">\n" \
235 " <arg name=\"id\" type=\"u\"/>\n" \
236 " <arg name=\"job\" type=\"o\"/>\n" \
237 " <arg name=\"unit\" type=\"s\"/>\n" \
239 " <signal name=\"JobRemoved\">\n" \
240 " <arg name=\"id\" type=\"u\"/>\n" \
241 " <arg name=\"job\" type=\"o\"/>\n" \
242 " <arg name=\"unit\" type=\"s\"/>\n" \
243 " <arg name=\"result\" type=\"s\"/>\n" \
245 " <signal name=\"StartupFinished\">\n" \
246 " <arg name=\"firmware\" type=\"t\"/>\n" \
247 " <arg name=\"loader\" type=\"t\"/>\n" \
248 " <arg name=\"kernel\" type=\"t\"/>\n" \
249 " <arg name=\"initrd\" type=\"t\"/>\n" \
250 " <arg name=\"userspace\" type=\"t\"/>\n" \
251 " <arg name=\"total\" type=\"t\"/>\n" \
253 " <signal name=\"UnitFilesChanged\"/>\n" \
254 " <signal name=\"Reloading\">\n" \
255 " <arg name=\"active\" type=\"b\"/>\n" \
258 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
259 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
260 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
261 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
262 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
263 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
264 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
265 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
266 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
267 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
268 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
269 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
270 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
271 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
272 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
273 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
274 " <property name=\"SecurityStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
275 " <property name=\"SecurityStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
276 " <property name=\"SecurityFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
277 " <property name=\"SecurityFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
278 " <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
279 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
280 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
281 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
282 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
283 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
284 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
285 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
286 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
287 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
288 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
289 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
290 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
291 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
292 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
293 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
294 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
295 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
296 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
297 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
298 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
299 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
300 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
301 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
303 #define BUS_MANAGER_INTERFACE_END \
306 #define BUS_MANAGER_INTERFACE \
307 BUS_MANAGER_INTERFACE_BEGIN \
308 BUS_MANAGER_INTERFACE_METHODS \
309 BUS_MANAGER_INTERFACE_SIGNALS \
310 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
311 BUS_MANAGER_INTERFACE_END
313 #define INTROSPECTION_BEGIN \
314 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
316 BUS_MANAGER_INTERFACE \
317 BUS_PROPERTIES_INTERFACE \
319 BUS_INTROSPECTABLE_INTERFACE
321 #define INTROSPECTION_END \
324 #define INTERFACES_LIST \
325 BUS_GENERIC_INTERFACES_LIST \
326 "org.freedesktop.systemd1.Manager\0"
328 const char bus_manager_interface[] = BUS_MANAGER_INTERFACE;
330 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
332 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
335 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
342 e = stpcpy(e, "split-usr:");
344 if (readlink_malloc("/etc/mtab", &p) < 0)
345 e = stpcpy(e, "mtab-not-symlink:");
349 if (access("/proc/cgroups", F_OK) < 0)
350 e = stpcpy(e, "cgroups-missing:");
352 if (hwclock_is_localtime() > 0)
353 e = stpcpy(e, "local-hwclock:");
355 /* remove the last ':' */
361 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
367 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
373 t = log_target_to_string(log_get_target());
375 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
381 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
387 dbus_message_iter_get_basic(i, &t);
389 return log_set_target_from_string(t);
392 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
393 _cleanup_free_ char *t = NULL;
399 r = log_level_to_string_alloc(log_get_max_level(), &t);
403 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
409 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
415 dbus_message_iter_get_basic(i, &t);
417 return log_set_max_level_from_string(t);
420 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
428 u = hashmap_size(m->units);
430 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
436 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
444 u = hashmap_size(m->jobs);
446 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
452 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
460 if (dual_timestamp_is_set(&m->finish_timestamp))
463 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
465 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
471 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
473 const char *id = NULL;
479 detect_virtualization(&id);
483 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
489 static DBusMessage *message_from_file_changes(
491 UnitFileChange *changes,
493 int carries_install_info) {
495 DBusMessageIter iter, sub, sub2;
499 reply = dbus_message_new_method_return(m);
503 dbus_message_iter_init_append(reply, &iter);
505 if (carries_install_info >= 0) {
508 b = !!carries_install_info;
509 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
513 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
516 for (i = 0; i < n_changes; i++) {
517 const char *type, *path, *source;
519 type = unit_file_change_type_to_string(changes[i].type);
520 path = strempty(changes[i].path);
521 source = strempty(changes[i].source);
523 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
524 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
525 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
526 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
527 !dbus_message_iter_close_container(&sub, &sub2))
531 if (!dbus_message_iter_close_container(&iter, &sub))
537 dbus_message_unref(reply);
541 static int bus_manager_send_unit_files_changed(Manager *m) {
545 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
549 r = bus_broadcast(m, s);
550 dbus_message_unref(s);
555 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
561 dbus_message_iter_get_basic(i, t);
563 return watchdog_set_timeout(t);
566 static const char systemd_property_string[] =
570 static const BusProperty bus_systemd_properties[] = {
571 { "Version", bus_property_append_string, "s", 0 },
572 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
576 static const BusProperty bus_manager_properties[] = {
577 { "Tainted", bus_manager_append_tainted, "s", 0 },
578 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
579 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
580 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
581 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
582 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
583 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
584 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
585 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
586 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
587 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
588 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
589 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
590 { "SecurityStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.realtime) },
591 { "SecurityStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_start_timestamp.monotonic) },
592 { "SecurityFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.realtime) },
593 { "SecurityFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, security_finish_timestamp.monotonic) },
594 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
595 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
596 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
597 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
598 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
599 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
600 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
601 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
602 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
603 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
604 { "NNames", bus_manager_append_n_names, "u", 0 },
605 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
606 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
607 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
608 { "Progress", bus_manager_append_progress, "d", 0 },
609 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
610 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
611 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
612 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
613 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
614 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
615 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
616 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
617 { "Virtualization", bus_manager_append_virt, "s", 0, },
621 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
622 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
623 _cleanup_free_ char * path = NULL;
627 JobType job_type = _JOB_TYPE_INVALID;
628 bool reload_if_possible = false;
635 dbus_error_init(&error);
637 member = dbus_message_get_member(message);
639 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
643 if (!dbus_message_get_args(
646 DBUS_TYPE_STRING, &name,
648 return bus_send_error_reply(connection, message, &error, -EINVAL);
650 u = manager_get_unit(m, name);
652 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
653 return bus_send_error_reply(connection, message, &error, -ENOENT);
656 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
658 reply = dbus_message_new_method_return(message);
662 path = unit_dbus_path(u);
666 if (!dbus_message_append_args(
668 DBUS_TYPE_OBJECT_PATH, &path,
671 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
675 if (!dbus_message_get_args(
678 DBUS_TYPE_UINT32, &pid,
680 return bus_send_error_reply(connection, message, &error, -EINVAL);
682 u = manager_get_unit_by_pid(m, (pid_t) pid);
684 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
685 return bus_send_error_reply(connection, message, &error, -ENOENT);
688 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
690 reply = dbus_message_new_method_return(message);
694 path = unit_dbus_path(u);
698 if (!dbus_message_append_args(
700 DBUS_TYPE_OBJECT_PATH, &path,
703 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
707 if (!dbus_message_get_args(
710 DBUS_TYPE_STRING, &name,
712 return bus_send_error_reply(connection, message, &error, -EINVAL);
714 r = manager_load_unit(m, name, NULL, &error, &u);
716 return bus_send_error_reply(connection, message, &error, r);
718 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
720 reply = dbus_message_new_method_return(message);
724 path = unit_dbus_path(u);
728 if (!dbus_message_append_args(
730 DBUS_TYPE_OBJECT_PATH, &path,
734 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
735 job_type = JOB_START;
736 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
737 job_type = JOB_START;
738 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
740 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
741 job_type = JOB_RELOAD;
742 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
743 job_type = JOB_RESTART;
744 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
745 job_type = JOB_TRY_RESTART;
746 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
747 reload_if_possible = true;
748 job_type = JOB_RESTART;
749 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
750 reload_if_possible = true;
751 job_type = JOB_TRY_RESTART;
752 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
753 const char *name, *swho;
758 if (!dbus_message_get_args(
761 DBUS_TYPE_STRING, &name,
762 DBUS_TYPE_STRING, &swho,
763 DBUS_TYPE_INT32, &signo,
765 return bus_send_error_reply(connection, message, &error, -EINVAL);
770 who = kill_who_from_string(swho);
772 return bus_send_error_reply(connection, message, &error, -EINVAL);
775 if (signo <= 0 || signo >= _NSIG)
776 return bus_send_error_reply(connection, message, &error, -EINVAL);
778 u = manager_get_unit(m, name);
780 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
781 return bus_send_error_reply(connection, message, &error, -ENOENT);
784 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
786 r = unit_kill(u, who, signo, &error);
788 return bus_send_error_reply(connection, message, &error, r);
790 reply = dbus_message_new_method_return(message);
794 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
798 if (!dbus_message_get_args(
801 DBUS_TYPE_UINT32, &id,
803 return bus_send_error_reply(connection, message, &error, -EINVAL);
805 j = manager_get_job(m, id);
807 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
808 return bus_send_error_reply(connection, message, &error, -ENOENT);
811 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
813 reply = dbus_message_new_method_return(message);
817 path = job_dbus_path(j);
821 if (!dbus_message_append_args(
823 DBUS_TYPE_OBJECT_PATH, &path,
827 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
831 if (!dbus_message_get_args(
834 DBUS_TYPE_UINT32, &id,
836 return bus_send_error_reply(connection, message, &error, -EINVAL);
838 j = manager_get_job(m, id);
840 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
841 return bus_send_error_reply(connection, message, &error, -ENOENT);
844 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
845 job_finish_and_invalidate(j, JOB_CANCELED, true);
847 reply = dbus_message_new_method_return(message);
851 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
853 SELINUX_ACCESS_CHECK(connection, message, "reboot");
854 manager_clear_jobs(m);
856 reply = dbus_message_new_method_return(message);
860 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
862 SELINUX_ACCESS_CHECK(connection, message, "reload");
864 manager_reset_failed(m);
866 reply = dbus_message_new_method_return(message);
870 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
874 if (!dbus_message_get_args(
877 DBUS_TYPE_STRING, &name,
879 return bus_send_error_reply(connection, message, &error, -EINVAL);
881 u = manager_get_unit(m, name);
883 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
884 return bus_send_error_reply(connection, message, &error, -ENOENT);
887 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
889 unit_reset_failed(u);
891 reply = dbus_message_new_method_return(message);
895 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
896 DBusMessageIter iter, sub;
901 SELINUX_ACCESS_CHECK(connection, message, "status");
903 reply = dbus_message_new_method_return(message);
907 dbus_message_iter_init_append(reply, &iter);
909 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
912 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
913 char *u_path, *j_path;
914 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
915 DBusMessageIter sub2;
922 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
925 description = unit_description(u);
926 load_state = unit_load_state_to_string(u->load_state);
927 active_state = unit_active_state_to_string(unit_active_state(u));
928 sub_state = unit_sub_state_to_string(u);
930 f = unit_following(u);
931 following = f ? f->id : "";
933 u_path = unit_dbus_path(u);
938 job_id = (uint32_t) u->job->id;
940 if (!(j_path = job_dbus_path(u->job))) {
945 sjob_type = job_type_to_string(u->job->type);
952 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
953 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
954 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
955 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
956 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
957 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
958 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
959 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
960 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
961 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
972 if (!dbus_message_iter_close_container(&sub, &sub2))
976 if (!dbus_message_iter_close_container(&iter, &sub))
979 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
980 DBusMessageIter iter, sub;
984 SELINUX_ACCESS_CHECK(connection, message, "status");
986 reply = dbus_message_new_method_return(message);
990 dbus_message_iter_init_append(reply, &iter);
992 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
995 HASHMAP_FOREACH(j, m->jobs, i) {
996 char *u_path, *j_path;
997 const char *state, *type;
999 DBusMessageIter sub2;
1001 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1004 id = (uint32_t) j->id;
1005 state = job_state_to_string(j->state);
1006 type = job_type_to_string(j->type);
1008 j_path = job_dbus_path(j);
1012 u_path = unit_dbus_path(j->unit);
1018 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1019 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1020 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1021 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1022 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1023 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1032 if (!dbus_message_iter_close_container(&sub, &sub2))
1036 if (!dbus_message_iter_close_container(&iter, &sub))
1039 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1043 SELINUX_ACCESS_CHECK(connection, message, "status");
1045 s = bus_acquire_subscribed(m, connection);
1049 client = strdup(bus_message_get_sender_with_fallback(message));
1053 r = set_consume(s, client);
1055 return bus_send_error_reply(connection, message, NULL, r);
1057 reply = dbus_message_new_method_return(message);
1061 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1064 SELINUX_ACCESS_CHECK(connection, message, "status");
1066 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1068 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1069 return bus_send_error_reply(connection, message, &error, -ENOENT);
1074 reply = dbus_message_new_method_return(message);
1078 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1083 SELINUX_ACCESS_CHECK(connection, message, "status");
1085 reply = dbus_message_new_method_return(message);
1089 f = open_memstream(&dump, &size);
1093 manager_dump_units(m, f, NULL);
1094 manager_dump_jobs(m, f, NULL);
1104 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1110 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1112 dbus_bool_t cleanup;
1115 SELINUX_ACCESS_CHECK(connection, message, "start");
1117 if (!dbus_message_get_args(
1120 DBUS_TYPE_STRING, &name,
1121 DBUS_TYPE_BOOLEAN, &cleanup,
1123 return bus_send_error_reply(connection, message, &error, -EINVAL);
1128 r = snapshot_create(m, name, cleanup, &error, &s);
1130 return bus_send_error_reply(connection, message, &error, r);
1132 reply = dbus_message_new_method_return(message);
1136 path = unit_dbus_path(UNIT(s));
1140 if (!dbus_message_append_args(
1142 DBUS_TYPE_OBJECT_PATH, &path,
1146 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1150 if (!dbus_message_get_args(
1153 DBUS_TYPE_STRING, &name,
1155 return bus_send_error_reply(connection, message, &error, -EINVAL);
1157 u = manager_get_unit(m, name);
1159 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1160 return bus_send_error_reply(connection, message, &error, -ENOENT);
1163 if (u->type != UNIT_SNAPSHOT) {
1164 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1165 return bus_send_error_reply(connection, message, &error, -ENOENT);
1168 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1169 snapshot_remove(SNAPSHOT(u));
1171 reply = dbus_message_new_method_return(message);
1175 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1176 _cleanup_free_ char *introspection = NULL;
1184 SELINUX_ACCESS_CHECK(connection, message, "status");
1186 reply = dbus_message_new_method_return(message);
1190 /* We roll our own introspection code here, instead of
1191 * relying on bus_default_message_handler() because we
1192 * need to generate our introspection string
1195 f = open_memstream(&introspection, &size);
1199 fputs(INTROSPECTION_BEGIN, f);
1201 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1202 _cleanup_free_ char *p = NULL;
1207 p = bus_path_escape(k);
1213 fprintf(f, "<node name=\"unit/%s\"/>", p);
1216 HASHMAP_FOREACH(j, m->jobs, i)
1217 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1219 fputs(INTROSPECTION_END, f);
1231 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1234 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1236 SELINUX_ACCESS_CHECK(connection, message, "reload");
1238 assert(!m->queued_message);
1240 /* Instead of sending the reply back right away, we
1241 * just remember that we need to and then send it
1242 * after the reload is finished. That way the caller
1243 * knows when the reload finished. */
1245 m->queued_message = dbus_message_new_method_return(message);
1246 if (!m->queued_message)
1249 m->queued_message_connection = connection;
1250 m->exit_code = MANAGER_RELOAD;
1252 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1254 SELINUX_ACCESS_CHECK(connection, message, "reload");
1256 /* We don't send a reply back here, the client should
1257 * just wait for us disconnecting. */
1259 m->exit_code = MANAGER_REEXECUTE;
1261 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1263 SELINUX_ACCESS_CHECK(connection, message, "halt");
1265 if (m->running_as == SYSTEMD_SYSTEM) {
1266 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1267 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1270 reply = dbus_message_new_method_return(message);
1274 m->exit_code = MANAGER_EXIT;
1276 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1278 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1280 if (m->running_as != SYSTEMD_SYSTEM) {
1281 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1282 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1285 reply = dbus_message_new_method_return(message);
1289 m->exit_code = MANAGER_REBOOT;
1291 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1293 SELINUX_ACCESS_CHECK(connection, message, "halt");
1295 if (m->running_as != SYSTEMD_SYSTEM) {
1296 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1297 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1300 reply = dbus_message_new_method_return(message);
1304 m->exit_code = MANAGER_POWEROFF;
1306 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1308 SELINUX_ACCESS_CHECK(connection, message, "halt");
1310 if (m->running_as != SYSTEMD_SYSTEM) {
1311 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1312 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1315 reply = dbus_message_new_method_return(message);
1319 m->exit_code = MANAGER_HALT;
1321 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1323 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1325 if (m->running_as != SYSTEMD_SYSTEM) {
1326 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1327 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1330 reply = dbus_message_new_method_return(message);
1334 m->exit_code = MANAGER_KEXEC;
1336 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1337 const char *switch_root, *switch_root_init;
1341 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1343 if (!dbus_message_get_args(
1346 DBUS_TYPE_STRING, &switch_root,
1347 DBUS_TYPE_STRING, &switch_root_init,
1349 return bus_send_error_reply(connection, message, &error, -EINVAL);
1351 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1352 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1354 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1355 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1357 if (m->running_as != SYSTEMD_SYSTEM) {
1358 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1359 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1363 if (isempty(switch_root_init)) {
1364 good = path_is_os_tree(switch_root);
1366 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1369 _cleanup_free_ char *p = NULL;
1371 p = strjoin(switch_root, "/", switch_root_init, NULL);
1375 good = access(p, X_OK) >= 0;
1377 log_error("Not switching root: cannot execute new init %s", p);
1380 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1382 u = strdup(switch_root);
1386 if (!isempty(switch_root_init)) {
1387 v = strdup(switch_root_init);
1395 free(m->switch_root);
1396 free(m->switch_root_init);
1398 m->switch_root_init = v;
1400 reply = dbus_message_new_method_return(message);
1404 m->exit_code = MANAGER_SWITCH_ROOT;
1406 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1407 _cleanup_strv_free_ char **l = NULL;
1410 SELINUX_ACCESS_CHECK(connection, message, "reload");
1412 r = bus_parse_strv(message, &l);
1416 return bus_send_error_reply(connection, message, NULL, r);
1417 if (!strv_env_is_valid(l))
1418 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1420 e = strv_env_merge(2, m->environment, l);
1424 reply = dbus_message_new_method_return(message);
1430 strv_free(m->environment);
1433 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1434 _cleanup_strv_free_ char **l = NULL;
1437 SELINUX_ACCESS_CHECK(connection, message, "reload");
1439 r = bus_parse_strv(message, &l);
1443 return bus_send_error_reply(connection, message, NULL, r);
1444 if (!strv_env_name_or_assignment_is_valid(l))
1445 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1447 e = strv_env_delete(m->environment, 1, l);
1451 reply = dbus_message_new_method_return(message);
1457 strv_free(m->environment);
1460 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1461 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1463 DBusMessageIter iter;
1465 SELINUX_ACCESS_CHECK(connection, message, "reload");
1467 if (!dbus_message_iter_init(message, &iter))
1470 r = bus_parse_strv_iter(&iter, &l_unset);
1474 return bus_send_error_reply(connection, message, NULL, r);
1475 if (!strv_env_name_or_assignment_is_valid(l_unset))
1476 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1478 if (!dbus_message_iter_next(&iter))
1479 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1481 r = bus_parse_strv_iter(&iter, &l_set);
1485 return bus_send_error_reply(connection, message, NULL, r);
1486 if (!strv_env_is_valid(l_set))
1487 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1489 e = strv_env_delete(m->environment, 1, l_unset);
1493 f = strv_env_merge(2, e, l_set);
1497 reply = dbus_message_new_method_return(message);
1503 strv_free(m->environment);
1505 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1506 DBusMessageIter iter, sub, sub2;
1511 SELINUX_ACCESS_CHECK(connection, message, "status");
1513 reply = dbus_message_new_method_return(message);
1517 h = hashmap_new(string_hash_func, string_compare_func);
1521 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1523 unit_file_list_free(h);
1524 return bus_send_error_reply(connection, message, NULL, r);
1527 dbus_message_iter_init_append(reply, &iter);
1529 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1530 unit_file_list_free(h);
1534 HASHMAP_FOREACH(item, h, i) {
1537 state = unit_file_state_to_string(item->state);
1540 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1541 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1542 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1543 !dbus_message_iter_close_container(&sub, &sub2)) {
1544 unit_file_list_free(h);
1549 unit_file_list_free(h);
1551 if (!dbus_message_iter_close_container(&iter, &sub))
1554 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1556 UnitFileState state;
1559 SELINUX_ACCESS_CHECK(connection, message, "status");
1561 if (!dbus_message_get_args(
1564 DBUS_TYPE_STRING, &name,
1566 return bus_send_error_reply(connection, message, &error, -EINVAL);
1568 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1570 return bus_send_error_reply(connection, message, NULL, state);
1572 s = unit_file_state_to_string(state);
1575 reply = dbus_message_new_method_return(message);
1579 if (!dbus_message_append_args(
1581 DBUS_TYPE_STRING, &s,
1584 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1585 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1586 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1587 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1588 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1589 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1592 DBusMessageIter iter;
1593 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1594 UnitFileChange *changes = NULL;
1595 unsigned n_changes = 0;
1596 dbus_bool_t runtime, force;
1597 int carries_install_info = -1;
1599 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1601 if (!dbus_message_iter_init(message, &iter))
1604 r = bus_parse_strv_iter(&iter, &l);
1609 return bus_send_error_reply(connection, message, NULL, r);
1612 if (!dbus_message_iter_next(&iter) ||
1613 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1614 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1616 return bus_send_error_reply(connection, message, NULL, -EIO);
1619 if (streq(member, "EnableUnitFiles")) {
1620 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1621 carries_install_info = r;
1622 } else if (streq(member, "ReenableUnitFiles")) {
1623 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1624 carries_install_info = r;
1625 } else if (streq(member, "LinkUnitFiles"))
1626 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1627 else if (streq(member, "PresetUnitFiles")) {
1628 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1629 carries_install_info = r;
1630 } else if (streq(member, "MaskUnitFiles"))
1631 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1632 else if (streq(member, "SetDefaultTarget"))
1633 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1635 assert_not_reached("Uh? Wrong method");
1638 bus_manager_send_unit_files_changed(m);
1641 unit_file_changes_free(changes, n_changes);
1642 return bus_send_error_reply(connection, message, NULL, r);
1645 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1646 unit_file_changes_free(changes, n_changes);
1651 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1652 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1655 DBusMessageIter iter;
1656 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1657 UnitFileChange *changes = NULL;
1658 unsigned n_changes = 0;
1659 dbus_bool_t runtime;
1661 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1663 if (!dbus_message_iter_init(message, &iter))
1666 r = bus_parse_strv_iter(&iter, &l);
1671 return bus_send_error_reply(connection, message, NULL, r);
1674 if (!dbus_message_iter_next(&iter) ||
1675 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1677 return bus_send_error_reply(connection, message, NULL, -EIO);
1680 if (streq(member, "DisableUnitFiles"))
1681 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1682 else if (streq(member, "UnmaskUnitFiles"))
1683 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1685 assert_not_reached("Uh? Wrong method");
1688 bus_manager_send_unit_files_changed(m);
1691 unit_file_changes_free(changes, n_changes);
1692 return bus_send_error_reply(connection, message, NULL, r);
1695 reply = message_from_file_changes(message, changes, n_changes, -1);
1696 unit_file_changes_free(changes, n_changes);
1701 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1702 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1703 _cleanup_free_ char *default_target = NULL;
1705 reply = dbus_message_new_method_return(message);
1709 r = unit_file_get_default(scope, NULL, &default_target);
1711 return bus_send_error_reply(connection, message, NULL, r);
1713 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1717 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1718 DBusMessageIter iter;
1719 dbus_bool_t runtime;
1723 if (!dbus_message_iter_init(message, &iter))
1726 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1727 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1728 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1730 u = manager_get_unit(m, name);
1732 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1733 return bus_send_error_reply(connection, message, &error, -ENOENT);
1736 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1738 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1740 return bus_send_error_reply(connection, message, &error, r);
1742 reply = dbus_message_new_method_return(message);
1746 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1747 const char *name, *smode;
1748 DBusMessageIter iter;
1753 if (!dbus_message_iter_init(message, &iter))
1756 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1757 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1758 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1760 t = unit_name_to_type(name);
1762 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1763 if (!unit_vtable[t]->can_transient) {
1764 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1765 return bus_send_error_reply(connection, message, &error, -EINVAL);
1768 mode = job_mode_from_string(smode);
1770 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1771 return bus_send_error_reply(connection, message, &error, -EINVAL);
1774 r = manager_load_unit(m, name, NULL, NULL, &u);
1776 return bus_send_error_reply(connection, message, &error, r);
1778 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1780 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1781 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1782 return bus_send_error_reply(connection, message, &error, -EEXIST);
1785 /* OK, the unit failed to load and is unreferenced,
1786 * now let's fill in the transient data instead */
1787 r = unit_make_transient(u);
1789 return bus_send_error_reply(connection, message, &error, r);
1791 /* Set our properties */
1792 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1794 return bus_send_error_reply(connection, message, &error, r);
1796 /* And load this stub fully */
1799 return bus_send_error_reply(connection, message, &error, r);
1801 manager_dispatch_load_queue(m);
1803 /* Finally, start it */
1804 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1807 const BusBoundProperties bps[] = {
1808 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1809 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1813 SELINUX_ACCESS_CHECK(connection, message, "status");
1815 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1818 if (job_type != _JOB_TYPE_INVALID) {
1819 const char *name, *smode, *old_name = NULL;
1824 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1825 b = dbus_message_get_args(
1828 DBUS_TYPE_STRING, &old_name,
1829 DBUS_TYPE_STRING, &name,
1830 DBUS_TYPE_STRING, &smode,
1833 b = dbus_message_get_args(
1836 DBUS_TYPE_STRING, &name,
1837 DBUS_TYPE_STRING, &smode,
1840 return bus_send_error_reply(connection, message, &error, -EINVAL);
1843 u = manager_get_unit(m, old_name);
1844 if (!u || !u->job || u->job->type != JOB_START) {
1845 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1846 return bus_send_error_reply(connection, message, &error, -ENOENT);
1850 mode = job_mode_from_string(smode);
1852 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1853 return bus_send_error_reply(connection, message, &error, -EINVAL);
1856 r = manager_load_unit(m, name, NULL, &error, &u);
1858 return bus_send_error_reply(connection, message, &error, r);
1860 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1864 if (!bus_maybe_send_reply(connection, message, reply))
1867 return DBUS_HANDLER_RESULT_HANDLED;
1870 dbus_error_free(&error);
1872 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1875 const DBusObjectPathVTable bus_manager_vtable = {
1876 .message_function = bus_manager_message_handler