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) {
469 const char *id = NULL;
475 detect_virtualization(&id);
479 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
485 static DBusMessage *message_from_file_changes(
487 UnitFileChange *changes,
489 int carries_install_info) {
491 DBusMessageIter iter, sub, sub2;
495 reply = dbus_message_new_method_return(m);
499 dbus_message_iter_init_append(reply, &iter);
501 if (carries_install_info >= 0) {
504 b = !!carries_install_info;
505 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
509 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
512 for (i = 0; i < n_changes; i++) {
513 const char *type, *path, *source;
515 type = unit_file_change_type_to_string(changes[i].type);
516 path = strempty(changes[i].path);
517 source = strempty(changes[i].source);
519 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
520 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
521 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
522 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
523 !dbus_message_iter_close_container(&sub, &sub2))
527 if (!dbus_message_iter_close_container(&iter, &sub))
533 dbus_message_unref(reply);
537 static int bus_manager_send_unit_files_changed(Manager *m) {
541 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
545 r = bus_broadcast(m, s);
546 dbus_message_unref(s);
551 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
557 dbus_message_iter_get_basic(i, t);
559 return watchdog_set_timeout(t);
562 static const char systemd_property_string[] =
566 static const BusProperty bus_systemd_properties[] = {
567 { "Version", bus_property_append_string, "s", 0 },
568 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
572 static const BusProperty bus_manager_properties[] = {
573 { "Tainted", bus_manager_append_tainted, "s", 0 },
574 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
575 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
576 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
577 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
578 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
579 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
580 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
581 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
582 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
583 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
584 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
585 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
586 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
587 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
588 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
589 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
590 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
591 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
592 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
593 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
594 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
595 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
596 { "NNames", bus_manager_append_n_names, "u", 0 },
597 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
598 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
599 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
600 { "Progress", bus_manager_append_progress, "d", 0 },
601 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
602 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
603 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
604 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
605 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
606 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
607 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
608 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
609 { "Virtualization", bus_manager_append_virt, "s", 0, },
613 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
614 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
615 _cleanup_free_ char * path = NULL;
619 JobType job_type = _JOB_TYPE_INVALID;
620 bool reload_if_possible = false;
627 dbus_error_init(&error);
629 member = dbus_message_get_member(message);
631 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
635 if (!dbus_message_get_args(
638 DBUS_TYPE_STRING, &name,
640 return bus_send_error_reply(connection, message, &error, -EINVAL);
642 u = manager_get_unit(m, name);
644 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
645 return bus_send_error_reply(connection, message, &error, -ENOENT);
648 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
650 reply = dbus_message_new_method_return(message);
654 path = unit_dbus_path(u);
658 if (!dbus_message_append_args(
660 DBUS_TYPE_OBJECT_PATH, &path,
663 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
667 if (!dbus_message_get_args(
670 DBUS_TYPE_UINT32, &pid,
672 return bus_send_error_reply(connection, message, &error, -EINVAL);
674 u = manager_get_unit_by_pid(m, (pid_t) pid);
676 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
677 return bus_send_error_reply(connection, message, &error, -ENOENT);
680 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
682 reply = dbus_message_new_method_return(message);
686 path = unit_dbus_path(u);
690 if (!dbus_message_append_args(
692 DBUS_TYPE_OBJECT_PATH, &path,
695 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
699 if (!dbus_message_get_args(
702 DBUS_TYPE_STRING, &name,
704 return bus_send_error_reply(connection, message, &error, -EINVAL);
706 r = manager_load_unit(m, name, NULL, &error, &u);
708 return bus_send_error_reply(connection, message, &error, r);
710 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
712 reply = dbus_message_new_method_return(message);
716 path = unit_dbus_path(u);
720 if (!dbus_message_append_args(
722 DBUS_TYPE_OBJECT_PATH, &path,
726 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
727 job_type = JOB_START;
728 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
729 job_type = JOB_START;
730 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
732 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
733 job_type = JOB_RELOAD;
734 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
735 job_type = JOB_RESTART;
736 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
737 job_type = JOB_TRY_RESTART;
738 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
739 reload_if_possible = true;
740 job_type = JOB_RESTART;
741 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
742 reload_if_possible = true;
743 job_type = JOB_TRY_RESTART;
744 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
745 const char *name, *swho;
750 if (!dbus_message_get_args(
753 DBUS_TYPE_STRING, &name,
754 DBUS_TYPE_STRING, &swho,
755 DBUS_TYPE_INT32, &signo,
757 return bus_send_error_reply(connection, message, &error, -EINVAL);
762 who = kill_who_from_string(swho);
764 return bus_send_error_reply(connection, message, &error, -EINVAL);
767 if (signo <= 0 || signo >= _NSIG)
768 return bus_send_error_reply(connection, message, &error, -EINVAL);
770 u = manager_get_unit(m, name);
772 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
773 return bus_send_error_reply(connection, message, &error, -ENOENT);
776 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
778 r = unit_kill(u, who, signo, &error);
780 return bus_send_error_reply(connection, message, &error, r);
782 reply = dbus_message_new_method_return(message);
786 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
790 if (!dbus_message_get_args(
793 DBUS_TYPE_UINT32, &id,
795 return bus_send_error_reply(connection, message, &error, -EINVAL);
797 j = manager_get_job(m, id);
799 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
800 return bus_send_error_reply(connection, message, &error, -ENOENT);
803 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
805 reply = dbus_message_new_method_return(message);
809 path = job_dbus_path(j);
813 if (!dbus_message_append_args(
815 DBUS_TYPE_OBJECT_PATH, &path,
819 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
823 if (!dbus_message_get_args(
826 DBUS_TYPE_UINT32, &id,
828 return bus_send_error_reply(connection, message, &error, -EINVAL);
830 j = manager_get_job(m, id);
832 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
833 return bus_send_error_reply(connection, message, &error, -ENOENT);
836 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
837 job_finish_and_invalidate(j, JOB_CANCELED, true);
839 reply = dbus_message_new_method_return(message);
843 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
845 SELINUX_ACCESS_CHECK(connection, message, "reboot");
846 manager_clear_jobs(m);
848 reply = dbus_message_new_method_return(message);
852 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
854 SELINUX_ACCESS_CHECK(connection, message, "reload");
856 manager_reset_failed(m);
858 reply = dbus_message_new_method_return(message);
862 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
866 if (!dbus_message_get_args(
869 DBUS_TYPE_STRING, &name,
871 return bus_send_error_reply(connection, message, &error, -EINVAL);
873 u = manager_get_unit(m, name);
875 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
876 return bus_send_error_reply(connection, message, &error, -ENOENT);
879 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
881 unit_reset_failed(u);
883 reply = dbus_message_new_method_return(message);
887 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
888 DBusMessageIter iter, sub;
893 SELINUX_ACCESS_CHECK(connection, message, "status");
895 reply = dbus_message_new_method_return(message);
899 dbus_message_iter_init_append(reply, &iter);
901 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
904 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
905 char *u_path, *j_path;
906 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
907 DBusMessageIter sub2;
914 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
917 description = unit_description(u);
918 load_state = unit_load_state_to_string(u->load_state);
919 active_state = unit_active_state_to_string(unit_active_state(u));
920 sub_state = unit_sub_state_to_string(u);
922 f = unit_following(u);
923 following = f ? f->id : "";
925 u_path = unit_dbus_path(u);
930 job_id = (uint32_t) u->job->id;
932 if (!(j_path = job_dbus_path(u->job))) {
937 sjob_type = job_type_to_string(u->job->type);
944 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
945 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
946 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
947 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
948 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
949 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
950 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
951 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
952 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
953 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
964 if (!dbus_message_iter_close_container(&sub, &sub2))
968 if (!dbus_message_iter_close_container(&iter, &sub))
971 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
972 DBusMessageIter iter, sub;
976 SELINUX_ACCESS_CHECK(connection, message, "status");
978 reply = dbus_message_new_method_return(message);
982 dbus_message_iter_init_append(reply, &iter);
984 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
987 HASHMAP_FOREACH(j, m->jobs, i) {
988 char *u_path, *j_path;
989 const char *state, *type;
991 DBusMessageIter sub2;
993 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
996 id = (uint32_t) j->id;
997 state = job_state_to_string(j->state);
998 type = job_type_to_string(j->type);
1000 j_path = job_dbus_path(j);
1004 u_path = unit_dbus_path(j->unit);
1010 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1011 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1012 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1013 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1014 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1015 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1024 if (!dbus_message_iter_close_container(&sub, &sub2))
1028 if (!dbus_message_iter_close_container(&iter, &sub))
1031 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1035 SELINUX_ACCESS_CHECK(connection, message, "status");
1037 s = bus_acquire_subscribed(m, connection);
1041 client = strdup(bus_message_get_sender_with_fallback(message));
1045 r = set_consume(s, client);
1047 return bus_send_error_reply(connection, message, NULL, r);
1049 reply = dbus_message_new_method_return(message);
1053 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1056 SELINUX_ACCESS_CHECK(connection, message, "status");
1058 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1060 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1061 return bus_send_error_reply(connection, message, &error, -ENOENT);
1066 reply = dbus_message_new_method_return(message);
1070 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1075 SELINUX_ACCESS_CHECK(connection, message, "status");
1077 reply = dbus_message_new_method_return(message);
1081 f = open_memstream(&dump, &size);
1085 manager_dump_units(m, f, NULL);
1086 manager_dump_jobs(m, f, NULL);
1096 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1102 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1104 dbus_bool_t cleanup;
1107 SELINUX_ACCESS_CHECK(connection, message, "start");
1109 if (!dbus_message_get_args(
1112 DBUS_TYPE_STRING, &name,
1113 DBUS_TYPE_BOOLEAN, &cleanup,
1115 return bus_send_error_reply(connection, message, &error, -EINVAL);
1120 r = snapshot_create(m, name, cleanup, &error, &s);
1122 return bus_send_error_reply(connection, message, &error, r);
1124 reply = dbus_message_new_method_return(message);
1128 path = unit_dbus_path(UNIT(s));
1132 if (!dbus_message_append_args(
1134 DBUS_TYPE_OBJECT_PATH, &path,
1138 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1142 if (!dbus_message_get_args(
1145 DBUS_TYPE_STRING, &name,
1147 return bus_send_error_reply(connection, message, &error, -EINVAL);
1149 u = manager_get_unit(m, name);
1151 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1152 return bus_send_error_reply(connection, message, &error, -ENOENT);
1155 if (u->type != UNIT_SNAPSHOT) {
1156 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1157 return bus_send_error_reply(connection, message, &error, -ENOENT);
1160 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1161 snapshot_remove(SNAPSHOT(u));
1163 reply = dbus_message_new_method_return(message);
1167 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1168 _cleanup_free_ char *introspection = NULL;
1176 SELINUX_ACCESS_CHECK(connection, message, "status");
1178 reply = dbus_message_new_method_return(message);
1182 /* We roll our own introspection code here, instead of
1183 * relying on bus_default_message_handler() because we
1184 * need to generate our introspection string
1187 f = open_memstream(&introspection, &size);
1191 fputs(INTROSPECTION_BEGIN, f);
1193 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1194 _cleanup_free_ char *p = NULL;
1199 p = bus_path_escape(k);
1205 fprintf(f, "<node name=\"unit/%s\"/>", p);
1208 HASHMAP_FOREACH(j, m->jobs, i)
1209 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1211 fputs(INTROSPECTION_END, f);
1223 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1226 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1228 SELINUX_ACCESS_CHECK(connection, message, "reload");
1230 assert(!m->queued_message);
1232 /* Instead of sending the reply back right away, we
1233 * just remember that we need to and then send it
1234 * after the reload is finished. That way the caller
1235 * knows when the reload finished. */
1237 m->queued_message = dbus_message_new_method_return(message);
1238 if (!m->queued_message)
1241 m->queued_message_connection = connection;
1242 m->exit_code = MANAGER_RELOAD;
1244 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1246 SELINUX_ACCESS_CHECK(connection, message, "reload");
1248 /* We don't send a reply back here, the client should
1249 * just wait for us disconnecting. */
1251 m->exit_code = MANAGER_REEXECUTE;
1253 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1255 SELINUX_ACCESS_CHECK(connection, message, "halt");
1257 if (m->running_as == SYSTEMD_SYSTEM) {
1258 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1259 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1262 reply = dbus_message_new_method_return(message);
1266 m->exit_code = MANAGER_EXIT;
1268 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1270 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1272 if (m->running_as != SYSTEMD_SYSTEM) {
1273 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1274 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1277 reply = dbus_message_new_method_return(message);
1281 m->exit_code = MANAGER_REBOOT;
1283 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1285 SELINUX_ACCESS_CHECK(connection, message, "halt");
1287 if (m->running_as != SYSTEMD_SYSTEM) {
1288 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1289 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1292 reply = dbus_message_new_method_return(message);
1296 m->exit_code = MANAGER_POWEROFF;
1298 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1300 SELINUX_ACCESS_CHECK(connection, message, "halt");
1302 if (m->running_as != SYSTEMD_SYSTEM) {
1303 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1304 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1307 reply = dbus_message_new_method_return(message);
1311 m->exit_code = MANAGER_HALT;
1313 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1315 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1317 if (m->running_as != SYSTEMD_SYSTEM) {
1318 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1319 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1322 reply = dbus_message_new_method_return(message);
1326 m->exit_code = MANAGER_KEXEC;
1328 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1329 const char *switch_root, *switch_root_init;
1333 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1335 if (!dbus_message_get_args(
1338 DBUS_TYPE_STRING, &switch_root,
1339 DBUS_TYPE_STRING, &switch_root_init,
1341 return bus_send_error_reply(connection, message, &error, -EINVAL);
1343 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1344 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1346 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1347 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1349 if (m->running_as != SYSTEMD_SYSTEM) {
1350 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1351 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1355 if (isempty(switch_root_init)) {
1356 good = path_is_os_tree(switch_root);
1358 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1361 _cleanup_free_ char *p = NULL;
1363 p = strjoin(switch_root, "/", switch_root_init, NULL);
1367 good = access(p, X_OK) >= 0;
1369 log_error("Not switching root: cannot execute new init %s", p);
1372 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1374 u = strdup(switch_root);
1378 if (!isempty(switch_root_init)) {
1379 v = strdup(switch_root_init);
1387 free(m->switch_root);
1388 free(m->switch_root_init);
1390 m->switch_root_init = v;
1392 reply = dbus_message_new_method_return(message);
1396 m->exit_code = MANAGER_SWITCH_ROOT;
1398 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1399 _cleanup_strv_free_ char **l = NULL;
1402 SELINUX_ACCESS_CHECK(connection, message, "reload");
1404 r = bus_parse_strv(message, &l);
1408 return bus_send_error_reply(connection, message, NULL, r);
1409 if (!strv_env_is_valid(l))
1410 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1412 e = strv_env_merge(2, m->environment, l);
1416 reply = dbus_message_new_method_return(message);
1422 strv_free(m->environment);
1425 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1426 _cleanup_strv_free_ char **l = NULL;
1429 SELINUX_ACCESS_CHECK(connection, message, "reload");
1431 r = bus_parse_strv(message, &l);
1435 return bus_send_error_reply(connection, message, NULL, r);
1436 if (!strv_env_name_or_assignment_is_valid(l))
1437 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1439 e = strv_env_delete(m->environment, 1, l);
1443 reply = dbus_message_new_method_return(message);
1449 strv_free(m->environment);
1452 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1453 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1455 DBusMessageIter iter;
1457 SELINUX_ACCESS_CHECK(connection, message, "reload");
1459 if (!dbus_message_iter_init(message, &iter))
1462 r = bus_parse_strv_iter(&iter, &l_unset);
1466 return bus_send_error_reply(connection, message, NULL, r);
1467 if (!strv_env_name_or_assignment_is_valid(l_unset))
1468 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1470 if (!dbus_message_iter_next(&iter))
1471 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1473 r = bus_parse_strv_iter(&iter, &l_set);
1477 return bus_send_error_reply(connection, message, NULL, r);
1478 if (!strv_env_is_valid(l_set))
1479 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1481 e = strv_env_delete(m->environment, 1, l_unset);
1485 f = strv_env_merge(2, e, l_set);
1489 reply = dbus_message_new_method_return(message);
1495 strv_free(m->environment);
1497 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1498 DBusMessageIter iter, sub, sub2;
1503 SELINUX_ACCESS_CHECK(connection, message, "status");
1505 reply = dbus_message_new_method_return(message);
1509 h = hashmap_new(string_hash_func, string_compare_func);
1513 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1515 unit_file_list_free(h);
1516 return bus_send_error_reply(connection, message, NULL, r);
1519 dbus_message_iter_init_append(reply, &iter);
1521 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1522 unit_file_list_free(h);
1526 HASHMAP_FOREACH(item, h, i) {
1529 state = unit_file_state_to_string(item->state);
1532 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1533 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1534 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1535 !dbus_message_iter_close_container(&sub, &sub2)) {
1536 unit_file_list_free(h);
1541 unit_file_list_free(h);
1543 if (!dbus_message_iter_close_container(&iter, &sub))
1546 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1548 UnitFileState state;
1551 SELINUX_ACCESS_CHECK(connection, message, "status");
1553 if (!dbus_message_get_args(
1556 DBUS_TYPE_STRING, &name,
1558 return bus_send_error_reply(connection, message, &error, -EINVAL);
1560 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1562 return bus_send_error_reply(connection, message, NULL, state);
1564 s = unit_file_state_to_string(state);
1567 reply = dbus_message_new_method_return(message);
1571 if (!dbus_message_append_args(
1573 DBUS_TYPE_STRING, &s,
1576 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1577 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1578 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1579 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1580 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1581 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1584 DBusMessageIter iter;
1585 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1586 UnitFileChange *changes = NULL;
1587 unsigned n_changes = 0;
1588 dbus_bool_t runtime, force;
1589 int carries_install_info = -1;
1591 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1593 if (!dbus_message_iter_init(message, &iter))
1596 r = bus_parse_strv_iter(&iter, &l);
1601 return bus_send_error_reply(connection, message, NULL, r);
1604 if (!dbus_message_iter_next(&iter) ||
1605 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1606 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1608 return bus_send_error_reply(connection, message, NULL, -EIO);
1611 if (streq(member, "EnableUnitFiles")) {
1612 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1613 carries_install_info = r;
1614 } else if (streq(member, "ReenableUnitFiles")) {
1615 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1616 carries_install_info = r;
1617 } else if (streq(member, "LinkUnitFiles"))
1618 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1619 else if (streq(member, "PresetUnitFiles")) {
1620 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1621 carries_install_info = r;
1622 } else if (streq(member, "MaskUnitFiles"))
1623 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1624 else if (streq(member, "SetDefaultTarget"))
1625 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1627 assert_not_reached("Uh? Wrong method");
1630 bus_manager_send_unit_files_changed(m);
1633 unit_file_changes_free(changes, n_changes);
1634 return bus_send_error_reply(connection, message, NULL, r);
1637 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1638 unit_file_changes_free(changes, n_changes);
1643 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1644 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1647 DBusMessageIter iter;
1648 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1649 UnitFileChange *changes = NULL;
1650 unsigned n_changes = 0;
1651 dbus_bool_t runtime;
1653 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1655 if (!dbus_message_iter_init(message, &iter))
1658 r = bus_parse_strv_iter(&iter, &l);
1663 return bus_send_error_reply(connection, message, NULL, r);
1666 if (!dbus_message_iter_next(&iter) ||
1667 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1669 return bus_send_error_reply(connection, message, NULL, -EIO);
1672 if (streq(member, "DisableUnitFiles"))
1673 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1674 else if (streq(member, "UnmaskUnitFiles"))
1675 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1677 assert_not_reached("Uh? Wrong method");
1680 bus_manager_send_unit_files_changed(m);
1683 unit_file_changes_free(changes, n_changes);
1684 return bus_send_error_reply(connection, message, NULL, r);
1687 reply = message_from_file_changes(message, changes, n_changes, -1);
1688 unit_file_changes_free(changes, n_changes);
1693 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1694 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1695 _cleanup_free_ char *default_target = NULL;
1697 reply = dbus_message_new_method_return(message);
1701 r = unit_file_get_default(scope, NULL, &default_target);
1703 return bus_send_error_reply(connection, message, NULL, r);
1705 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1709 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1710 DBusMessageIter iter;
1711 dbus_bool_t runtime;
1715 if (!dbus_message_iter_init(message, &iter))
1718 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1719 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1720 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1722 u = manager_get_unit(m, name);
1724 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1725 return bus_send_error_reply(connection, message, &error, -ENOENT);
1728 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1730 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1732 return bus_send_error_reply(connection, message, &error, r);
1734 reply = dbus_message_new_method_return(message);
1738 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1739 const char *name, *smode;
1740 DBusMessageIter iter;
1745 if (!dbus_message_iter_init(message, &iter))
1748 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1749 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1750 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1752 t = unit_name_to_type(name);
1754 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1755 if (!unit_vtable[t]->can_transient) {
1756 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1757 return bus_send_error_reply(connection, message, &error, -EINVAL);
1760 mode = job_mode_from_string(smode);
1762 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1763 return bus_send_error_reply(connection, message, &error, -EINVAL);
1766 r = manager_load_unit(m, name, NULL, NULL, &u);
1768 return bus_send_error_reply(connection, message, &error, r);
1770 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1772 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1773 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1774 return bus_send_error_reply(connection, message, &error, -EEXIST);
1777 /* OK, the unit failed to load and is unreferenced,
1778 * now let's fill in the transient data instead */
1779 r = unit_make_transient(u);
1781 return bus_send_error_reply(connection, message, &error, r);
1783 /* Set our properties */
1784 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1786 return bus_send_error_reply(connection, message, &error, r);
1788 /* And load this stub fully */
1791 return bus_send_error_reply(connection, message, &error, r);
1793 manager_dispatch_load_queue(m);
1795 /* Finally, start it */
1796 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1799 const BusBoundProperties bps[] = {
1800 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1801 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1805 SELINUX_ACCESS_CHECK(connection, message, "status");
1807 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1810 if (job_type != _JOB_TYPE_INVALID) {
1811 const char *name, *smode, *old_name = NULL;
1816 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1817 b = dbus_message_get_args(
1820 DBUS_TYPE_STRING, &old_name,
1821 DBUS_TYPE_STRING, &name,
1822 DBUS_TYPE_STRING, &smode,
1825 b = dbus_message_get_args(
1828 DBUS_TYPE_STRING, &name,
1829 DBUS_TYPE_STRING, &smode,
1832 return bus_send_error_reply(connection, message, &error, -EINVAL);
1835 u = manager_get_unit(m, old_name);
1836 if (!u || !u->job || u->job->type != JOB_START) {
1837 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1838 return bus_send_error_reply(connection, message, &error, -ENOENT);
1842 mode = job_mode_from_string(smode);
1844 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1845 return bus_send_error_reply(connection, message, &error, -EINVAL);
1848 r = manager_load_unit(m, name, NULL, &error, &u);
1850 return bus_send_error_reply(connection, message, &error, r);
1852 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1856 if (!bus_maybe_send_reply(connection, message, reply))
1859 return DBUS_HANDLER_RESULT_HANDLED;
1862 dbus_error_free(&error);
1864 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1867 const DBusObjectPathVTable bus_manager_vtable = {
1868 .message_function = bus_manager_message_handler