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=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
275 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
276 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
277 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
278 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
279 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
280 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
281 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
282 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
283 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
284 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
285 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
286 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
287 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
288 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
289 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
290 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
291 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
292 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
293 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
294 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
295 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
296 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
297 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
299 #define BUS_MANAGER_INTERFACE_END \
302 #define BUS_MANAGER_INTERFACE \
303 BUS_MANAGER_INTERFACE_BEGIN \
304 BUS_MANAGER_INTERFACE_METHODS \
305 BUS_MANAGER_INTERFACE_SIGNALS \
306 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
307 BUS_MANAGER_INTERFACE_END
309 #define INTROSPECTION_BEGIN \
310 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
312 BUS_MANAGER_INTERFACE \
313 BUS_PROPERTIES_INTERFACE \
315 BUS_INTROSPECTABLE_INTERFACE
317 #define INTROSPECTION_END \
320 #define INTERFACES_LIST \
321 BUS_GENERIC_INTERFACES_LIST \
322 "org.freedesktop.systemd1.Manager\0"
324 const char bus_manager_interface[] = BUS_MANAGER_INTERFACE;
326 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
328 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
331 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
338 e = stpcpy(e, "split-usr:");
340 if (readlink_malloc("/etc/mtab", &p) < 0)
341 e = stpcpy(e, "mtab-not-symlink:");
345 if (access("/proc/cgroups", F_OK) < 0)
346 e = stpcpy(e, "cgroups-missing:");
348 if (hwclock_is_localtime() > 0)
349 e = stpcpy(e, "local-hwclock:");
351 /* remove the last ':' */
357 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
363 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
369 t = log_target_to_string(log_get_target());
371 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
377 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
383 dbus_message_iter_get_basic(i, &t);
385 return log_set_target_from_string(t);
388 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
389 _cleanup_free_ char *t = NULL;
395 r = log_level_to_string_alloc(log_get_max_level(), &t);
399 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
405 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
411 dbus_message_iter_get_basic(i, &t);
413 return log_set_max_level_from_string(t);
416 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
424 u = hashmap_size(m->units);
426 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
432 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
440 u = hashmap_size(m->jobs);
442 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
448 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
456 if (dual_timestamp_is_set(&m->finish_timestamp))
459 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
461 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
467 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
475 detect_virtualization(&id);
477 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
483 static DBusMessage *message_from_file_changes(
485 UnitFileChange *changes,
487 int carries_install_info) {
489 DBusMessageIter iter, sub, sub2;
493 reply = dbus_message_new_method_return(m);
497 dbus_message_iter_init_append(reply, &iter);
499 if (carries_install_info >= 0) {
502 b = !!carries_install_info;
503 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
507 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
510 for (i = 0; i < n_changes; i++) {
511 const char *type, *path, *source;
513 type = unit_file_change_type_to_string(changes[i].type);
514 path = strempty(changes[i].path);
515 source = strempty(changes[i].source);
517 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
518 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
519 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
520 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
521 !dbus_message_iter_close_container(&sub, &sub2))
525 if (!dbus_message_iter_close_container(&iter, &sub))
531 dbus_message_unref(reply);
535 static int bus_manager_send_unit_files_changed(Manager *m) {
539 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
543 r = bus_broadcast(m, s);
544 dbus_message_unref(s);
549 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
555 dbus_message_iter_get_basic(i, t);
557 return watchdog_set_timeout(t);
560 static const char systemd_property_string[] =
564 static const BusProperty bus_systemd_properties[] = {
565 { "Version", bus_property_append_string, "s", 0 },
566 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
570 static const BusProperty bus_manager_properties[] = {
571 { "Tainted", bus_manager_append_tainted, "s", 0 },
572 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
573 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
574 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
575 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
576 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
577 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
578 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
579 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
580 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
581 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
582 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
583 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
584 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
585 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
586 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
587 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
588 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
589 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
590 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
591 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
592 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
593 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
594 { "NNames", bus_manager_append_n_names, "u", 0 },
595 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
596 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
597 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
598 { "Progress", bus_manager_append_progress, "d", 0 },
599 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
600 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
601 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
602 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
603 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
604 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
605 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
606 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
607 { "Virtualization", bus_manager_append_virt, "s", 0, },
611 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
612 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
613 _cleanup_free_ char * path = NULL;
617 JobType job_type = _JOB_TYPE_INVALID;
618 bool reload_if_possible = false;
625 dbus_error_init(&error);
627 member = dbus_message_get_member(message);
629 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
633 if (!dbus_message_get_args(
636 DBUS_TYPE_STRING, &name,
638 return bus_send_error_reply(connection, message, &error, -EINVAL);
640 u = manager_get_unit(m, name);
642 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
643 return bus_send_error_reply(connection, message, &error, -ENOENT);
646 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
648 reply = dbus_message_new_method_return(message);
652 path = unit_dbus_path(u);
656 if (!dbus_message_append_args(
658 DBUS_TYPE_OBJECT_PATH, &path,
661 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
665 if (!dbus_message_get_args(
668 DBUS_TYPE_UINT32, &pid,
670 return bus_send_error_reply(connection, message, &error, -EINVAL);
672 u = manager_get_unit_by_pid(m, (pid_t) pid);
674 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
675 return bus_send_error_reply(connection, message, &error, -ENOENT);
678 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
680 reply = dbus_message_new_method_return(message);
684 path = unit_dbus_path(u);
688 if (!dbus_message_append_args(
690 DBUS_TYPE_OBJECT_PATH, &path,
693 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
697 if (!dbus_message_get_args(
700 DBUS_TYPE_STRING, &name,
702 return bus_send_error_reply(connection, message, &error, -EINVAL);
704 r = manager_load_unit(m, name, NULL, &error, &u);
706 return bus_send_error_reply(connection, message, &error, r);
708 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
710 reply = dbus_message_new_method_return(message);
714 path = unit_dbus_path(u);
718 if (!dbus_message_append_args(
720 DBUS_TYPE_OBJECT_PATH, &path,
724 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
725 job_type = JOB_START;
726 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
727 job_type = JOB_START;
728 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
730 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
731 job_type = JOB_RELOAD;
732 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
733 job_type = JOB_RESTART;
734 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
735 job_type = JOB_TRY_RESTART;
736 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
737 reload_if_possible = true;
738 job_type = JOB_RESTART;
739 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
740 reload_if_possible = true;
741 job_type = JOB_TRY_RESTART;
742 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
743 const char *name, *swho;
748 if (!dbus_message_get_args(
751 DBUS_TYPE_STRING, &name,
752 DBUS_TYPE_STRING, &swho,
753 DBUS_TYPE_INT32, &signo,
755 return bus_send_error_reply(connection, message, &error, -EINVAL);
760 who = kill_who_from_string(swho);
762 return bus_send_error_reply(connection, message, &error, -EINVAL);
765 if (signo <= 0 || signo >= _NSIG)
766 return bus_send_error_reply(connection, message, &error, -EINVAL);
768 u = manager_get_unit(m, name);
770 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
771 return bus_send_error_reply(connection, message, &error, -ENOENT);
774 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
776 r = unit_kill(u, who, signo, &error);
778 return bus_send_error_reply(connection, message, &error, r);
780 reply = dbus_message_new_method_return(message);
784 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
788 if (!dbus_message_get_args(
791 DBUS_TYPE_UINT32, &id,
793 return bus_send_error_reply(connection, message, &error, -EINVAL);
795 j = manager_get_job(m, id);
797 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
798 return bus_send_error_reply(connection, message, &error, -ENOENT);
801 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
803 reply = dbus_message_new_method_return(message);
807 path = job_dbus_path(j);
811 if (!dbus_message_append_args(
813 DBUS_TYPE_OBJECT_PATH, &path,
817 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
821 if (!dbus_message_get_args(
824 DBUS_TYPE_UINT32, &id,
826 return bus_send_error_reply(connection, message, &error, -EINVAL);
828 j = manager_get_job(m, id);
830 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
831 return bus_send_error_reply(connection, message, &error, -ENOENT);
834 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
835 job_finish_and_invalidate(j, JOB_CANCELED, true);
837 reply = dbus_message_new_method_return(message);
841 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
843 SELINUX_ACCESS_CHECK(connection, message, "reboot");
844 manager_clear_jobs(m);
846 reply = dbus_message_new_method_return(message);
850 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
852 SELINUX_ACCESS_CHECK(connection, message, "reload");
854 manager_reset_failed(m);
856 reply = dbus_message_new_method_return(message);
860 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
864 if (!dbus_message_get_args(
867 DBUS_TYPE_STRING, &name,
869 return bus_send_error_reply(connection, message, &error, -EINVAL);
871 u = manager_get_unit(m, name);
873 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
874 return bus_send_error_reply(connection, message, &error, -ENOENT);
877 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
879 unit_reset_failed(u);
881 reply = dbus_message_new_method_return(message);
885 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
886 DBusMessageIter iter, sub;
891 SELINUX_ACCESS_CHECK(connection, message, "status");
893 reply = dbus_message_new_method_return(message);
897 dbus_message_iter_init_append(reply, &iter);
899 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
902 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
903 char *u_path, *j_path;
904 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
905 DBusMessageIter sub2;
912 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
915 description = unit_description(u);
916 load_state = unit_load_state_to_string(u->load_state);
917 active_state = unit_active_state_to_string(unit_active_state(u));
918 sub_state = unit_sub_state_to_string(u);
920 f = unit_following(u);
921 following = f ? f->id : "";
923 u_path = unit_dbus_path(u);
928 job_id = (uint32_t) u->job->id;
930 if (!(j_path = job_dbus_path(u->job))) {
935 sjob_type = job_type_to_string(u->job->type);
942 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
943 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
944 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
945 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
946 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
947 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
948 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
949 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
950 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
951 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
962 if (!dbus_message_iter_close_container(&sub, &sub2))
966 if (!dbus_message_iter_close_container(&iter, &sub))
969 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
970 DBusMessageIter iter, sub;
974 SELINUX_ACCESS_CHECK(connection, message, "status");
976 reply = dbus_message_new_method_return(message);
980 dbus_message_iter_init_append(reply, &iter);
982 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
985 HASHMAP_FOREACH(j, m->jobs, i) {
986 char *u_path, *j_path;
987 const char *state, *type;
989 DBusMessageIter sub2;
991 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
994 id = (uint32_t) j->id;
995 state = job_state_to_string(j->state);
996 type = job_type_to_string(j->type);
998 j_path = job_dbus_path(j);
1002 u_path = unit_dbus_path(j->unit);
1008 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1009 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1010 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1011 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1012 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1013 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1022 if (!dbus_message_iter_close_container(&sub, &sub2))
1026 if (!dbus_message_iter_close_container(&iter, &sub))
1029 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1033 SELINUX_ACCESS_CHECK(connection, message, "status");
1035 s = bus_acquire_subscribed(m, connection);
1039 client = strdup(bus_message_get_sender_with_fallback(message));
1043 r = set_consume(s, client);
1045 return bus_send_error_reply(connection, message, NULL, r);
1047 reply = dbus_message_new_method_return(message);
1051 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1054 SELINUX_ACCESS_CHECK(connection, message, "status");
1056 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1058 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1059 return bus_send_error_reply(connection, message, &error, -ENOENT);
1064 reply = dbus_message_new_method_return(message);
1068 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1073 SELINUX_ACCESS_CHECK(connection, message, "status");
1075 reply = dbus_message_new_method_return(message);
1079 f = open_memstream(&dump, &size);
1083 manager_dump_units(m, f, NULL);
1084 manager_dump_jobs(m, f, NULL);
1094 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1100 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1102 dbus_bool_t cleanup;
1105 SELINUX_ACCESS_CHECK(connection, message, "start");
1107 if (!dbus_message_get_args(
1110 DBUS_TYPE_STRING, &name,
1111 DBUS_TYPE_BOOLEAN, &cleanup,
1113 return bus_send_error_reply(connection, message, &error, -EINVAL);
1118 r = snapshot_create(m, name, cleanup, &error, &s);
1120 return bus_send_error_reply(connection, message, &error, r);
1122 reply = dbus_message_new_method_return(message);
1126 path = unit_dbus_path(UNIT(s));
1130 if (!dbus_message_append_args(
1132 DBUS_TYPE_OBJECT_PATH, &path,
1136 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1140 if (!dbus_message_get_args(
1143 DBUS_TYPE_STRING, &name,
1145 return bus_send_error_reply(connection, message, &error, -EINVAL);
1147 u = manager_get_unit(m, name);
1149 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1150 return bus_send_error_reply(connection, message, &error, -ENOENT);
1153 if (u->type != UNIT_SNAPSHOT) {
1154 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1155 return bus_send_error_reply(connection, message, &error, -ENOENT);
1158 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1159 snapshot_remove(SNAPSHOT(u));
1161 reply = dbus_message_new_method_return(message);
1165 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1166 _cleanup_free_ char *introspection = NULL;
1174 SELINUX_ACCESS_CHECK(connection, message, "status");
1176 reply = dbus_message_new_method_return(message);
1180 /* We roll our own introspection code here, instead of
1181 * relying on bus_default_message_handler() because we
1182 * need to generate our introspection string
1185 f = open_memstream(&introspection, &size);
1189 fputs(INTROSPECTION_BEGIN, f);
1191 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1192 _cleanup_free_ char *p = NULL;
1197 p = bus_path_escape(k);
1203 fprintf(f, "<node name=\"unit/%s\"/>", p);
1206 HASHMAP_FOREACH(j, m->jobs, i)
1207 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1209 fputs(INTROSPECTION_END, f);
1221 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1224 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1226 SELINUX_ACCESS_CHECK(connection, message, "reload");
1228 assert(!m->queued_message);
1230 /* Instead of sending the reply back right away, we
1231 * just remember that we need to and then send it
1232 * after the reload is finished. That way the caller
1233 * knows when the reload finished. */
1235 m->queued_message = dbus_message_new_method_return(message);
1236 if (!m->queued_message)
1239 m->queued_message_connection = connection;
1240 m->exit_code = MANAGER_RELOAD;
1242 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1244 SELINUX_ACCESS_CHECK(connection, message, "reload");
1246 /* We don't send a reply back here, the client should
1247 * just wait for us disconnecting. */
1249 m->exit_code = MANAGER_REEXECUTE;
1251 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1253 SELINUX_ACCESS_CHECK(connection, message, "halt");
1255 if (m->running_as == SYSTEMD_SYSTEM) {
1256 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1257 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1260 reply = dbus_message_new_method_return(message);
1264 m->exit_code = MANAGER_EXIT;
1266 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1268 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1270 if (m->running_as != SYSTEMD_SYSTEM) {
1271 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1272 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1275 reply = dbus_message_new_method_return(message);
1279 m->exit_code = MANAGER_REBOOT;
1281 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1283 SELINUX_ACCESS_CHECK(connection, message, "halt");
1285 if (m->running_as != SYSTEMD_SYSTEM) {
1286 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1287 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1290 reply = dbus_message_new_method_return(message);
1294 m->exit_code = MANAGER_POWEROFF;
1296 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1298 SELINUX_ACCESS_CHECK(connection, message, "halt");
1300 if (m->running_as != SYSTEMD_SYSTEM) {
1301 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1302 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1305 reply = dbus_message_new_method_return(message);
1309 m->exit_code = MANAGER_HALT;
1311 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1313 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1315 if (m->running_as != SYSTEMD_SYSTEM) {
1316 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1317 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1320 reply = dbus_message_new_method_return(message);
1324 m->exit_code = MANAGER_KEXEC;
1326 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1327 const char *switch_root, *switch_root_init;
1331 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1333 if (!dbus_message_get_args(
1336 DBUS_TYPE_STRING, &switch_root,
1337 DBUS_TYPE_STRING, &switch_root_init,
1339 return bus_send_error_reply(connection, message, &error, -EINVAL);
1341 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1342 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1344 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1345 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1347 if (m->running_as != SYSTEMD_SYSTEM) {
1348 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1349 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1353 if (isempty(switch_root_init)) {
1354 good = path_is_os_tree(switch_root);
1356 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1359 _cleanup_free_ char *p = NULL;
1361 p = strjoin(switch_root, "/", switch_root_init, NULL);
1365 good = access(p, X_OK) >= 0;
1367 log_error("Not switching root: cannot execute new init %s", p);
1370 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1372 u = strdup(switch_root);
1376 if (!isempty(switch_root_init)) {
1377 v = strdup(switch_root_init);
1385 free(m->switch_root);
1386 free(m->switch_root_init);
1388 m->switch_root_init = v;
1390 reply = dbus_message_new_method_return(message);
1394 m->exit_code = MANAGER_SWITCH_ROOT;
1396 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1397 _cleanup_strv_free_ char **l = NULL;
1400 SELINUX_ACCESS_CHECK(connection, message, "reload");
1402 r = bus_parse_strv(message, &l);
1406 return bus_send_error_reply(connection, message, NULL, r);
1407 if (!strv_env_is_valid(l))
1408 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1410 e = strv_env_merge(2, m->environment, l);
1414 reply = dbus_message_new_method_return(message);
1420 strv_free(m->environment);
1423 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1424 _cleanup_strv_free_ char **l = NULL;
1427 SELINUX_ACCESS_CHECK(connection, message, "reload");
1429 r = bus_parse_strv(message, &l);
1433 return bus_send_error_reply(connection, message, NULL, r);
1434 if (!strv_env_name_or_assignment_is_valid(l))
1435 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1437 e = strv_env_delete(m->environment, 1, l);
1441 reply = dbus_message_new_method_return(message);
1447 strv_free(m->environment);
1450 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1451 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1453 DBusMessageIter iter;
1455 SELINUX_ACCESS_CHECK(connection, message, "reload");
1457 if (!dbus_message_iter_init(message, &iter))
1460 r = bus_parse_strv_iter(&iter, &l_unset);
1464 return bus_send_error_reply(connection, message, NULL, r);
1465 if (!strv_env_name_or_assignment_is_valid(l_unset))
1466 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1468 if (!dbus_message_iter_next(&iter))
1469 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1471 r = bus_parse_strv_iter(&iter, &l_set);
1475 return bus_send_error_reply(connection, message, NULL, r);
1476 if (!strv_env_is_valid(l_set))
1477 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1479 e = strv_env_delete(m->environment, 1, l_unset);
1483 f = strv_env_merge(2, e, l_set);
1487 reply = dbus_message_new_method_return(message);
1493 strv_free(m->environment);
1495 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1496 DBusMessageIter iter, sub, sub2;
1501 SELINUX_ACCESS_CHECK(connection, message, "status");
1503 reply = dbus_message_new_method_return(message);
1507 h = hashmap_new(string_hash_func, string_compare_func);
1511 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1513 unit_file_list_free(h);
1514 return bus_send_error_reply(connection, message, NULL, r);
1517 dbus_message_iter_init_append(reply, &iter);
1519 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1520 unit_file_list_free(h);
1524 HASHMAP_FOREACH(item, h, i) {
1527 state = unit_file_state_to_string(item->state);
1530 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1531 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1532 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1533 !dbus_message_iter_close_container(&sub, &sub2)) {
1534 unit_file_list_free(h);
1539 unit_file_list_free(h);
1541 if (!dbus_message_iter_close_container(&iter, &sub))
1544 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1546 UnitFileState state;
1549 SELINUX_ACCESS_CHECK(connection, message, "status");
1551 if (!dbus_message_get_args(
1554 DBUS_TYPE_STRING, &name,
1556 return bus_send_error_reply(connection, message, &error, -EINVAL);
1558 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1560 return bus_send_error_reply(connection, message, NULL, state);
1562 s = unit_file_state_to_string(state);
1565 reply = dbus_message_new_method_return(message);
1569 if (!dbus_message_append_args(
1571 DBUS_TYPE_STRING, &s,
1574 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1575 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1576 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1577 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1578 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1579 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1582 DBusMessageIter iter;
1583 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1584 UnitFileChange *changes = NULL;
1585 unsigned n_changes = 0;
1586 dbus_bool_t runtime, force;
1587 int carries_install_info = -1;
1589 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1591 if (!dbus_message_iter_init(message, &iter))
1594 r = bus_parse_strv_iter(&iter, &l);
1599 return bus_send_error_reply(connection, message, NULL, r);
1602 if (!dbus_message_iter_next(&iter) ||
1603 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1604 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1606 return bus_send_error_reply(connection, message, NULL, -EIO);
1609 if (streq(member, "EnableUnitFiles")) {
1610 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1611 carries_install_info = r;
1612 } else if (streq(member, "ReenableUnitFiles")) {
1613 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1614 carries_install_info = r;
1615 } else if (streq(member, "LinkUnitFiles"))
1616 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1617 else if (streq(member, "PresetUnitFiles")) {
1618 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1619 carries_install_info = r;
1620 } else if (streq(member, "MaskUnitFiles"))
1621 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1622 else if (streq(member, "SetDefaultTarget"))
1623 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1625 assert_not_reached("Uh? Wrong method");
1628 bus_manager_send_unit_files_changed(m);
1631 unit_file_changes_free(changes, n_changes);
1632 return bus_send_error_reply(connection, message, NULL, r);
1635 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1636 unit_file_changes_free(changes, n_changes);
1641 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1642 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1645 DBusMessageIter iter;
1646 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1647 UnitFileChange *changes = NULL;
1648 unsigned n_changes = 0;
1649 dbus_bool_t runtime;
1651 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1653 if (!dbus_message_iter_init(message, &iter))
1656 r = bus_parse_strv_iter(&iter, &l);
1661 return bus_send_error_reply(connection, message, NULL, r);
1664 if (!dbus_message_iter_next(&iter) ||
1665 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1667 return bus_send_error_reply(connection, message, NULL, -EIO);
1670 if (streq(member, "DisableUnitFiles"))
1671 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1672 else if (streq(member, "UnmaskUnitFiles"))
1673 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1675 assert_not_reached("Uh? Wrong method");
1678 bus_manager_send_unit_files_changed(m);
1681 unit_file_changes_free(changes, n_changes);
1682 return bus_send_error_reply(connection, message, NULL, r);
1685 reply = message_from_file_changes(message, changes, n_changes, -1);
1686 unit_file_changes_free(changes, n_changes);
1691 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1692 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1693 _cleanup_free_ char *default_target = NULL;
1695 reply = dbus_message_new_method_return(message);
1699 r = unit_file_get_default(scope, NULL, &default_target);
1701 return bus_send_error_reply(connection, message, NULL, r);
1703 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1707 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1708 DBusMessageIter iter;
1709 dbus_bool_t runtime;
1713 if (!dbus_message_iter_init(message, &iter))
1716 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1717 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1718 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1720 u = manager_get_unit(m, name);
1722 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1723 return bus_send_error_reply(connection, message, &error, -ENOENT);
1726 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1728 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1730 return bus_send_error_reply(connection, message, &error, r);
1732 reply = dbus_message_new_method_return(message);
1736 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1737 const char *name, *smode;
1738 DBusMessageIter iter;
1743 if (!dbus_message_iter_init(message, &iter))
1746 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1747 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1748 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1750 t = unit_name_to_type(name);
1752 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1753 if (!unit_vtable[t]->can_transient) {
1754 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1755 return bus_send_error_reply(connection, message, &error, -EINVAL);
1758 mode = job_mode_from_string(smode);
1760 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1761 return bus_send_error_reply(connection, message, &error, -EINVAL);
1764 r = manager_load_unit(m, name, NULL, NULL, &u);
1766 return bus_send_error_reply(connection, message, &error, r);
1768 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1770 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1771 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1772 return bus_send_error_reply(connection, message, &error, -EEXIST);
1775 /* OK, the unit failed to load and is unreferenced,
1776 * now let's fill in the transient data instead */
1777 r = unit_make_transient(u);
1779 return bus_send_error_reply(connection, message, &error, r);
1781 /* Set our properties */
1782 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1784 return bus_send_error_reply(connection, message, &error, r);
1786 /* And load this stub fully */
1789 return bus_send_error_reply(connection, message, &error, r);
1791 manager_dispatch_load_queue(m);
1793 /* Finally, start it */
1794 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1797 const BusBoundProperties bps[] = {
1798 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1799 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1803 SELINUX_ACCESS_CHECK(connection, message, "status");
1805 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1808 if (job_type != _JOB_TYPE_INVALID) {
1809 const char *name, *smode, *old_name = NULL;
1814 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1815 b = dbus_message_get_args(
1818 DBUS_TYPE_STRING, &old_name,
1819 DBUS_TYPE_STRING, &name,
1820 DBUS_TYPE_STRING, &smode,
1823 b = dbus_message_get_args(
1826 DBUS_TYPE_STRING, &name,
1827 DBUS_TYPE_STRING, &smode,
1830 return bus_send_error_reply(connection, message, &error, -EINVAL);
1833 u = manager_get_unit(m, old_name);
1834 if (!u || !u->job || u->job->type != JOB_START) {
1835 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1836 return bus_send_error_reply(connection, message, &error, -ENOENT);
1840 mode = job_mode_from_string(smode);
1842 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1843 return bus_send_error_reply(connection, message, &error, -EINVAL);
1846 r = manager_load_unit(m, name, NULL, &error, &u);
1848 return bus_send_error_reply(connection, message, &error, r);
1850 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1854 if (!bus_maybe_send_reply(connection, message, reply))
1857 return DBUS_HANDLER_RESULT_HANDLED;
1860 dbus_error_free(&error);
1862 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1865 const DBusObjectPathVTable bus_manager_vtable = {
1866 .message_function = bus_manager_message_handler