1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2010 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include "dbus-manager.h"
29 #include "bus-errors.h"
31 #include "dbus-common.h"
33 #include "selinux-access.h"
36 #include "path-util.h"
37 #include "dbus-unit.h"
41 #define BUS_MANAGER_INTERFACE_BEGIN \
42 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
44 #define BUS_MANAGER_INTERFACE_METHODS \
45 " <method name=\"GetUnit\">\n" \
46 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
47 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"GetUnitByPID\">\n" \
50 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
51 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"LoadUnit\">\n" \
54 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"StartUnit\">\n" \
58 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
59 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
62 " <method name=\"StartUnitReplace\">\n" \
63 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
68 " <method name=\"StopUnit\">\n" \
69 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
73 " <method name=\"ReloadUnit\">\n" \
74 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
78 " <method name=\"RestartUnit\">\n" \
79 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
83 " <method name=\"TryRestartUnit\">\n" \
84 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
86 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
88 " <method name=\"ReloadOrRestartUnit\">\n" \
89 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
93 " <method name=\"ReloadOrTryRestartUnit\">\n" \
94 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
98 " <method name=\"KillUnit\">\n" \
99 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
100 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
101 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
103 " <method name=\"ResetFailedUnit\">\n" \
104 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
106 " <method name=\"SetUnitControlGroup\">\n" \
107 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
108 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
109 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
111 " <method name=\"UnsetUnitControlGroup\">\n" \
112 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
113 " <arg name=\"group\" type=\"s\" direction=\"in\"/>\n" \
114 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
116 " <method name=\"GetUnitControlGroupAttribute\">\n" \
117 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
118 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
119 " <arg name=\"values\" type=\"as\" direction=\"out\"/>\n" \
121 " <method name=\"SetUnitControlGroupAttribute\">\n" \
122 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
123 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
124 " <arg name=\"values\" type=\"as\" direction=\"in\"/>\n" \
125 " <arg name=\"mode\" type=\"s\" direction=\"in\"\n/>" \
127 " <method name=\"UnsetUnitControlGroupAttributes\">\n" \
128 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
129 " <arg name=\"attribute\" type=\"s\" direction=\"in\"/>\n" \
130 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
132 " <method name=\"GetJob\">\n" \
133 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
134 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
136 " <method name=\"CancelJob\">\n" \
137 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
139 " <method name=\"ClearJobs\"/>\n" \
140 " <method name=\"ResetFailed\"/>\n" \
141 " <method name=\"ListUnits\">\n" \
142 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
144 " <method name=\"ListJobs\">\n" \
145 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
147 " <method name=\"Subscribe\"/>\n" \
148 " <method name=\"Unsubscribe\"/>\n" \
149 " <method name=\"Dump\">\n" \
150 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
152 " <method name=\"CreateSnapshot\">\n" \
153 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
154 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
155 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
157 " <method name=\"RemoveSnapshot\">\n" \
158 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
160 " <method name=\"Reload\"/>\n" \
161 " <method name=\"Reexecute\"/>\n" \
162 " <method name=\"Exit\"/>\n" \
163 " <method name=\"Reboot\"/>\n" \
164 " <method name=\"PowerOff\"/>\n" \
165 " <method name=\"Halt\"/>\n" \
166 " <method name=\"KExec\"/>\n" \
167 " <method name=\"SwitchRoot\">\n" \
168 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
169 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
171 " <method name=\"SetEnvironment\">\n" \
172 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
174 " <method name=\"UnsetEnvironment\">\n" \
175 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
177 " <method name=\"UnsetAndSetEnvironment\">\n" \
178 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
179 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
181 " <method name=\"ListUnitFiles\">\n" \
182 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
184 " <method name=\"GetUnitFileState\">\n" \
185 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
186 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
188 " <method name=\"EnableUnitFiles\">\n" \
189 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
190 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
191 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
192 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
193 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
195 " <method name=\"DisableUnitFiles\">\n" \
196 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
197 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
198 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
200 " <method name=\"ReenableUnitFiles\">\n" \
201 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
202 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
203 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
204 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
205 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
207 " <method name=\"LinkUnitFiles\">\n" \
208 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
209 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
210 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
211 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
213 " <method name=\"PresetUnitFiles\">\n" \
214 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
215 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
216 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
217 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
218 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
220 " <method name=\"MaskUnitFiles\">\n" \
221 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
222 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
223 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
224 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
226 " <method name=\"UnmaskUnitFiles\">\n" \
227 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
228 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
229 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
231 " <method name=\"SetDefaultTarget\">\n" \
232 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
233 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
235 " <method name=\"GetDefaultTarget\">\n" \
236 " <arg name=\"name\" type=\"s\" direction=\"out\"/>\n" \
238 " <method name=\"SetUnitProperties\">\n" \
239 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
240 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
241 " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
243 " <method name=\"StartTransientUnit\">\n" \
244 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
245 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
246 " <arg name=\"properties\" type=\"a(sv)\" direction=\"in\"/>\n" \
247 " <arg name=\"aux\" type=\"a(sa(sv))\" direction=\"in\"/>\n" \
248 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
251 #define BUS_MANAGER_INTERFACE_SIGNALS \
252 " <signal name=\"UnitNew\">\n" \
253 " <arg name=\"id\" type=\"s\"/>\n" \
254 " <arg name=\"unit\" type=\"o\"/>\n" \
256 " <signal name=\"UnitRemoved\">\n" \
257 " <arg name=\"id\" type=\"s\"/>\n" \
258 " <arg name=\"unit\" type=\"o\"/>\n" \
260 " <signal name=\"JobNew\">\n" \
261 " <arg name=\"id\" type=\"u\"/>\n" \
262 " <arg name=\"job\" type=\"o\"/>\n" \
263 " <arg name=\"unit\" type=\"s\"/>\n" \
265 " <signal name=\"JobRemoved\">\n" \
266 " <arg name=\"id\" type=\"u\"/>\n" \
267 " <arg name=\"job\" type=\"o\"/>\n" \
268 " <arg name=\"unit\" type=\"s\"/>\n" \
269 " <arg name=\"result\" type=\"s\"/>\n" \
271 " <signal name=\"StartupFinished\">\n" \
272 " <arg name=\"firmware\" type=\"t\"/>\n" \
273 " <arg name=\"loader\" type=\"t\"/>\n" \
274 " <arg name=\"kernel\" type=\"t\"/>\n" \
275 " <arg name=\"initrd\" type=\"t\"/>\n" \
276 " <arg name=\"userspace\" type=\"t\"/>\n" \
277 " <arg name=\"total\" type=\"t\"/>\n" \
279 " <signal name=\"UnitFilesChanged\"/>\n" \
280 " <signal name=\"Reloading\">\n" \
281 " <arg name=\"active\" type=\"b\"/>\n" \
284 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
285 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
286 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
287 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
288 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
289 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
290 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
291 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
292 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
293 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
294 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
295 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
296 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
297 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
298 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
299 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
300 " <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
301 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
302 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
303 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
304 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
305 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
306 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
307 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
308 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
309 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
310 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
311 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
312 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
313 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
314 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
315 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
316 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
317 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
318 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
319 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
320 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
321 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
322 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
323 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
324 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
326 #define BUS_MANAGER_INTERFACE_END \
329 #define BUS_MANAGER_INTERFACE \
330 BUS_MANAGER_INTERFACE_BEGIN \
331 BUS_MANAGER_INTERFACE_METHODS \
332 BUS_MANAGER_INTERFACE_SIGNALS \
333 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
334 BUS_MANAGER_INTERFACE_END
336 #define INTROSPECTION_BEGIN \
337 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
339 BUS_MANAGER_INTERFACE \
340 BUS_PROPERTIES_INTERFACE \
342 BUS_INTROSPECTABLE_INTERFACE
344 #define INTROSPECTION_END \
347 #define INTERFACES_LIST \
348 BUS_GENERIC_INTERFACES_LIST \
349 "org.freedesktop.systemd1.Manager\0"
351 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
353 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
355 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
358 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
365 e = stpcpy(e, "split-usr:");
367 if (readlink_malloc("/etc/mtab", &p) < 0)
368 e = stpcpy(e, "mtab-not-symlink:");
372 if (access("/proc/cgroups", F_OK) < 0)
373 e = stpcpy(e, "cgroups-missing:");
375 if (hwclock_is_localtime() > 0)
376 e = stpcpy(e, "local-hwclock:");
378 /* remove the last ':' */
384 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
390 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
396 t = log_target_to_string(log_get_target());
398 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
404 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
410 dbus_message_iter_get_basic(i, &t);
412 return log_set_target_from_string(t);
415 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
416 _cleanup_free_ char *t = NULL;
422 r = log_level_to_string_alloc(log_get_max_level(), &t);
426 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
432 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
438 dbus_message_iter_get_basic(i, &t);
440 return log_set_max_level_from_string(t);
443 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
451 u = hashmap_size(m->units);
453 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
459 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
467 u = hashmap_size(m->jobs);
469 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
475 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
483 if (dual_timestamp_is_set(&m->finish_timestamp))
486 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
488 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
494 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
502 detect_virtualization(&id);
504 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
510 static DBusMessage *message_from_file_changes(
512 UnitFileChange *changes,
514 int carries_install_info) {
516 DBusMessageIter iter, sub, sub2;
520 reply = dbus_message_new_method_return(m);
524 dbus_message_iter_init_append(reply, &iter);
526 if (carries_install_info >= 0) {
529 b = !!carries_install_info;
530 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
534 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
537 for (i = 0; i < n_changes; i++) {
538 const char *type, *path, *source;
540 type = unit_file_change_type_to_string(changes[i].type);
541 path = strempty(changes[i].path);
542 source = strempty(changes[i].source);
544 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
545 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
546 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
547 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
548 !dbus_message_iter_close_container(&sub, &sub2))
552 if (!dbus_message_iter_close_container(&iter, &sub))
558 dbus_message_unref(reply);
562 static int bus_manager_send_unit_files_changed(Manager *m) {
566 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
570 r = bus_broadcast(m, s);
571 dbus_message_unref(s);
576 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
582 dbus_message_iter_get_basic(i, t);
584 return watchdog_set_timeout(t);
587 static const char systemd_property_string[] =
591 static const BusProperty bus_systemd_properties[] = {
592 { "Version", bus_property_append_string, "s", 0 },
593 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
597 static const BusProperty bus_manager_properties[] = {
598 { "Tainted", bus_manager_append_tainted, "s", 0 },
599 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
600 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
601 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
602 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
603 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
604 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
605 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
606 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
607 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
608 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
609 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
610 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
611 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
612 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
613 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
614 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
615 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
616 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
617 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
618 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
619 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
620 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
621 { "NNames", bus_manager_append_n_names, "u", 0 },
622 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
623 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
624 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
625 { "Progress", bus_manager_append_progress, "d", 0 },
626 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
627 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
628 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
629 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
630 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
631 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
632 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
633 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
634 { "Virtualization", bus_manager_append_virt, "s", 0, },
638 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
639 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
640 _cleanup_free_ char * path = NULL;
644 JobType job_type = _JOB_TYPE_INVALID;
645 bool reload_if_possible = false;
652 dbus_error_init(&error);
654 member = dbus_message_get_member(message);
656 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
660 if (!dbus_message_get_args(
663 DBUS_TYPE_STRING, &name,
665 return bus_send_error_reply(connection, message, &error, -EINVAL);
667 u = manager_get_unit(m, name);
669 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
670 return bus_send_error_reply(connection, message, &error, -ENOENT);
673 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
675 reply = dbus_message_new_method_return(message);
679 path = unit_dbus_path(u);
683 if (!dbus_message_append_args(
685 DBUS_TYPE_OBJECT_PATH, &path,
688 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
692 if (!dbus_message_get_args(
695 DBUS_TYPE_UINT32, &pid,
697 return bus_send_error_reply(connection, message, &error, -EINVAL);
699 u = manager_get_unit_by_pid(m, (pid_t) pid);
701 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
702 return bus_send_error_reply(connection, message, &error, -ENOENT);
705 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
707 reply = dbus_message_new_method_return(message);
711 path = unit_dbus_path(u);
715 if (!dbus_message_append_args(
717 DBUS_TYPE_OBJECT_PATH, &path,
720 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
724 if (!dbus_message_get_args(
727 DBUS_TYPE_STRING, &name,
729 return bus_send_error_reply(connection, message, &error, -EINVAL);
731 r = manager_load_unit(m, name, NULL, &error, &u);
733 return bus_send_error_reply(connection, message, &error, r);
735 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
737 reply = dbus_message_new_method_return(message);
741 path = unit_dbus_path(u);
745 if (!dbus_message_append_args(
747 DBUS_TYPE_OBJECT_PATH, &path,
751 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
752 job_type = JOB_START;
753 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
754 job_type = JOB_START;
755 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
757 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
758 job_type = JOB_RELOAD;
759 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
760 job_type = JOB_RESTART;
761 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
762 job_type = JOB_TRY_RESTART;
763 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
764 reload_if_possible = true;
765 job_type = JOB_RESTART;
766 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
767 reload_if_possible = true;
768 job_type = JOB_TRY_RESTART;
769 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
770 const char *name, *swho;
775 if (!dbus_message_get_args(
778 DBUS_TYPE_STRING, &name,
779 DBUS_TYPE_STRING, &swho,
780 DBUS_TYPE_INT32, &signo,
782 return bus_send_error_reply(connection, message, &error, -EINVAL);
787 who = kill_who_from_string(swho);
789 return bus_send_error_reply(connection, message, &error, -EINVAL);
792 if (signo <= 0 || signo >= _NSIG)
793 return bus_send_error_reply(connection, message, &error, -EINVAL);
795 u = manager_get_unit(m, name);
797 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
798 return bus_send_error_reply(connection, message, &error, -ENOENT);
801 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
803 r = unit_kill(u, who, signo, &error);
805 return bus_send_error_reply(connection, message, &error, r);
807 reply = dbus_message_new_method_return(message);
811 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
815 if (!dbus_message_get_args(
818 DBUS_TYPE_UINT32, &id,
820 return bus_send_error_reply(connection, message, &error, -EINVAL);
822 j = manager_get_job(m, id);
824 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
825 return bus_send_error_reply(connection, message, &error, -ENOENT);
828 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
830 reply = dbus_message_new_method_return(message);
834 path = job_dbus_path(j);
838 if (!dbus_message_append_args(
840 DBUS_TYPE_OBJECT_PATH, &path,
844 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
848 if (!dbus_message_get_args(
851 DBUS_TYPE_UINT32, &id,
853 return bus_send_error_reply(connection, message, &error, -EINVAL);
855 j = manager_get_job(m, id);
857 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
858 return bus_send_error_reply(connection, message, &error, -ENOENT);
861 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
862 job_finish_and_invalidate(j, JOB_CANCELED, true);
864 reply = dbus_message_new_method_return(message);
868 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
870 SELINUX_ACCESS_CHECK(connection, message, "reboot");
871 manager_clear_jobs(m);
873 reply = dbus_message_new_method_return(message);
877 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
879 SELINUX_ACCESS_CHECK(connection, message, "reload");
881 manager_reset_failed(m);
883 reply = dbus_message_new_method_return(message);
887 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
891 if (!dbus_message_get_args(
894 DBUS_TYPE_STRING, &name,
896 return bus_send_error_reply(connection, message, &error, -EINVAL);
898 u = manager_get_unit(m, name);
900 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
901 return bus_send_error_reply(connection, message, &error, -ENOENT);
904 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
906 unit_reset_failed(u);
908 reply = dbus_message_new_method_return(message);
912 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
913 DBusMessageIter iter, sub;
918 SELINUX_ACCESS_CHECK(connection, message, "status");
920 reply = dbus_message_new_method_return(message);
924 dbus_message_iter_init_append(reply, &iter);
926 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
929 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
930 char *u_path, *j_path;
931 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
932 DBusMessageIter sub2;
939 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
942 description = unit_description(u);
943 load_state = unit_load_state_to_string(u->load_state);
944 active_state = unit_active_state_to_string(unit_active_state(u));
945 sub_state = unit_sub_state_to_string(u);
947 f = unit_following(u);
948 following = f ? f->id : "";
950 u_path = unit_dbus_path(u);
955 job_id = (uint32_t) u->job->id;
957 if (!(j_path = job_dbus_path(u->job))) {
962 sjob_type = job_type_to_string(u->job->type);
969 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
970 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
971 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
972 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
973 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
974 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
975 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
976 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
977 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
978 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
989 if (!dbus_message_iter_close_container(&sub, &sub2))
993 if (!dbus_message_iter_close_container(&iter, &sub))
996 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
997 DBusMessageIter iter, sub;
1001 SELINUX_ACCESS_CHECK(connection, message, "status");
1003 reply = dbus_message_new_method_return(message);
1007 dbus_message_iter_init_append(reply, &iter);
1009 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1012 HASHMAP_FOREACH(j, m->jobs, i) {
1013 char *u_path, *j_path;
1014 const char *state, *type;
1016 DBusMessageIter sub2;
1018 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1021 id = (uint32_t) j->id;
1022 state = job_state_to_string(j->state);
1023 type = job_type_to_string(j->type);
1025 j_path = job_dbus_path(j);
1029 u_path = unit_dbus_path(j->unit);
1035 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1036 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1037 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1038 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1039 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1040 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1049 if (!dbus_message_iter_close_container(&sub, &sub2))
1053 if (!dbus_message_iter_close_container(&iter, &sub))
1056 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1060 SELINUX_ACCESS_CHECK(connection, message, "status");
1062 s = bus_acquire_subscribed(m, connection);
1066 client = strdup(bus_message_get_sender_with_fallback(message));
1070 r = set_consume(s, client);
1072 return bus_send_error_reply(connection, message, NULL, r);
1074 reply = dbus_message_new_method_return(message);
1078 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1081 SELINUX_ACCESS_CHECK(connection, message, "status");
1083 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1085 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1086 return bus_send_error_reply(connection, message, &error, -ENOENT);
1091 reply = dbus_message_new_method_return(message);
1095 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1100 SELINUX_ACCESS_CHECK(connection, message, "status");
1102 reply = dbus_message_new_method_return(message);
1106 f = open_memstream(&dump, &size);
1110 manager_dump_units(m, f, NULL);
1111 manager_dump_jobs(m, f, NULL);
1121 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1127 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1129 dbus_bool_t cleanup;
1132 SELINUX_ACCESS_CHECK(connection, message, "start");
1134 if (!dbus_message_get_args(
1137 DBUS_TYPE_STRING, &name,
1138 DBUS_TYPE_BOOLEAN, &cleanup,
1140 return bus_send_error_reply(connection, message, &error, -EINVAL);
1145 r = snapshot_create(m, name, cleanup, &error, &s);
1147 return bus_send_error_reply(connection, message, &error, r);
1149 reply = dbus_message_new_method_return(message);
1153 path = unit_dbus_path(UNIT(s));
1157 if (!dbus_message_append_args(
1159 DBUS_TYPE_OBJECT_PATH, &path,
1163 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1167 if (!dbus_message_get_args(
1170 DBUS_TYPE_STRING, &name,
1172 return bus_send_error_reply(connection, message, &error, -EINVAL);
1174 u = manager_get_unit(m, name);
1176 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1177 return bus_send_error_reply(connection, message, &error, -ENOENT);
1180 if (u->type != UNIT_SNAPSHOT) {
1181 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1182 return bus_send_error_reply(connection, message, &error, -ENOENT);
1185 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1186 snapshot_remove(SNAPSHOT(u));
1188 reply = dbus_message_new_method_return(message);
1192 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1193 _cleanup_free_ char *introspection = NULL;
1201 SELINUX_ACCESS_CHECK(connection, message, "status");
1203 reply = dbus_message_new_method_return(message);
1207 /* We roll our own introspection code here, instead of
1208 * relying on bus_default_message_handler() because we
1209 * need to generate our introspection string
1212 f = open_memstream(&introspection, &size);
1216 fputs(INTROSPECTION_BEGIN, f);
1218 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1219 _cleanup_free_ char *p = NULL;
1224 p = bus_path_escape(k);
1230 fprintf(f, "<node name=\"unit/%s\"/>", p);
1233 HASHMAP_FOREACH(j, m->jobs, i)
1234 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1236 fputs(INTROSPECTION_END, f);
1248 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1251 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1253 SELINUX_ACCESS_CHECK(connection, message, "reload");
1255 assert(!m->queued_message);
1257 /* Instead of sending the reply back right away, we
1258 * just remember that we need to and then send it
1259 * after the reload is finished. That way the caller
1260 * knows when the reload finished. */
1262 m->queued_message = dbus_message_new_method_return(message);
1263 if (!m->queued_message)
1266 m->queued_message_connection = connection;
1267 m->exit_code = MANAGER_RELOAD;
1269 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1271 SELINUX_ACCESS_CHECK(connection, message, "reload");
1273 /* We don't send a reply back here, the client should
1274 * just wait for us disconnecting. */
1276 m->exit_code = MANAGER_REEXECUTE;
1278 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1280 SELINUX_ACCESS_CHECK(connection, message, "halt");
1282 if (m->running_as == SYSTEMD_SYSTEM) {
1283 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1284 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1287 reply = dbus_message_new_method_return(message);
1291 m->exit_code = MANAGER_EXIT;
1293 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1295 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1297 if (m->running_as != SYSTEMD_SYSTEM) {
1298 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1299 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1302 reply = dbus_message_new_method_return(message);
1306 m->exit_code = MANAGER_REBOOT;
1308 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1310 SELINUX_ACCESS_CHECK(connection, message, "halt");
1312 if (m->running_as != SYSTEMD_SYSTEM) {
1313 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1314 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1317 reply = dbus_message_new_method_return(message);
1321 m->exit_code = MANAGER_POWEROFF;
1323 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1325 SELINUX_ACCESS_CHECK(connection, message, "halt");
1327 if (m->running_as != SYSTEMD_SYSTEM) {
1328 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1329 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1332 reply = dbus_message_new_method_return(message);
1336 m->exit_code = MANAGER_HALT;
1338 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1340 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1342 if (m->running_as != SYSTEMD_SYSTEM) {
1343 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1344 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1347 reply = dbus_message_new_method_return(message);
1351 m->exit_code = MANAGER_KEXEC;
1353 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1354 const char *switch_root, *switch_root_init;
1358 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1360 if (!dbus_message_get_args(
1363 DBUS_TYPE_STRING, &switch_root,
1364 DBUS_TYPE_STRING, &switch_root_init,
1366 return bus_send_error_reply(connection, message, &error, -EINVAL);
1368 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1369 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1371 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1372 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1374 if (m->running_as != SYSTEMD_SYSTEM) {
1375 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1376 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1380 if (isempty(switch_root_init)) {
1381 good = path_is_os_tree(switch_root);
1383 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1386 _cleanup_free_ char *p = NULL;
1388 p = strjoin(switch_root, "/", switch_root_init, NULL);
1392 good = access(p, X_OK) >= 0;
1394 log_error("Not switching root: cannot execute new init %s", p);
1397 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1399 u = strdup(switch_root);
1403 if (!isempty(switch_root_init)) {
1404 v = strdup(switch_root_init);
1412 free(m->switch_root);
1413 free(m->switch_root_init);
1415 m->switch_root_init = v;
1417 reply = dbus_message_new_method_return(message);
1421 m->exit_code = MANAGER_SWITCH_ROOT;
1423 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1424 _cleanup_strv_free_ char **l = NULL;
1427 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1429 r = bus_parse_strv(message, &l);
1433 return bus_send_error_reply(connection, message, NULL, r);
1434 if (!strv_env_is_valid(l))
1435 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1437 e = strv_env_merge(2, m->environment, 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", "UnsetEnvironment")) {
1451 _cleanup_strv_free_ char **l = NULL;
1454 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1456 r = bus_parse_strv(message, &l);
1460 return bus_send_error_reply(connection, message, NULL, r);
1461 if (!strv_env_name_or_assignment_is_valid(l))
1462 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1464 e = strv_env_delete(m->environment, 1, l);
1468 reply = dbus_message_new_method_return(message);
1474 strv_free(m->environment);
1477 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1478 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1480 DBusMessageIter iter;
1482 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1484 if (!dbus_message_iter_init(message, &iter))
1487 r = bus_parse_strv_iter(&iter, &l_unset);
1491 return bus_send_error_reply(connection, message, NULL, r);
1492 if (!strv_env_name_or_assignment_is_valid(l_unset))
1493 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1495 if (!dbus_message_iter_next(&iter))
1496 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1498 r = bus_parse_strv_iter(&iter, &l_set);
1502 return bus_send_error_reply(connection, message, NULL, r);
1503 if (!strv_env_is_valid(l_set))
1504 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1506 e = strv_env_delete(m->environment, 1, l_unset);
1510 f = strv_env_merge(2, e, l_set);
1514 reply = dbus_message_new_method_return(message);
1520 strv_free(m->environment);
1522 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1523 DBusMessageIter iter, sub, sub2;
1528 SELINUX_ACCESS_CHECK(connection, message, "status");
1530 reply = dbus_message_new_method_return(message);
1534 h = hashmap_new(string_hash_func, string_compare_func);
1538 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1540 unit_file_list_free(h);
1541 return bus_send_error_reply(connection, message, NULL, r);
1544 dbus_message_iter_init_append(reply, &iter);
1546 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1547 unit_file_list_free(h);
1551 HASHMAP_FOREACH(item, h, i) {
1554 state = unit_file_state_to_string(item->state);
1557 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1558 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1559 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1560 !dbus_message_iter_close_container(&sub, &sub2)) {
1561 unit_file_list_free(h);
1566 unit_file_list_free(h);
1568 if (!dbus_message_iter_close_container(&iter, &sub))
1571 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1573 UnitFileState state;
1576 SELINUX_ACCESS_CHECK(connection, message, "status");
1578 if (!dbus_message_get_args(
1581 DBUS_TYPE_STRING, &name,
1583 return bus_send_error_reply(connection, message, &error, -EINVAL);
1585 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1587 return bus_send_error_reply(connection, message, NULL, state);
1589 s = unit_file_state_to_string(state);
1592 reply = dbus_message_new_method_return(message);
1596 if (!dbus_message_append_args(
1598 DBUS_TYPE_STRING, &s,
1601 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1602 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1603 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1604 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1605 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1606 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1609 DBusMessageIter iter;
1610 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1611 UnitFileChange *changes = NULL;
1612 unsigned n_changes = 0;
1613 dbus_bool_t runtime, force;
1614 int carries_install_info = -1;
1616 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1618 if (!dbus_message_iter_init(message, &iter))
1621 r = bus_parse_strv_iter(&iter, &l);
1626 return bus_send_error_reply(connection, message, NULL, r);
1629 if (!dbus_message_iter_next(&iter) ||
1630 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1631 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1633 return bus_send_error_reply(connection, message, NULL, -EIO);
1636 if (streq(member, "EnableUnitFiles")) {
1637 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1638 carries_install_info = r;
1639 } else if (streq(member, "ReenableUnitFiles")) {
1640 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1641 carries_install_info = r;
1642 } else if (streq(member, "LinkUnitFiles"))
1643 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1644 else if (streq(member, "PresetUnitFiles")) {
1645 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1646 carries_install_info = r;
1647 } else if (streq(member, "MaskUnitFiles"))
1648 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1649 else if (streq(member, "SetDefaultTarget"))
1650 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1652 assert_not_reached("Uh? Wrong method");
1655 bus_manager_send_unit_files_changed(m);
1658 unit_file_changes_free(changes, n_changes);
1659 return bus_send_error_reply(connection, message, NULL, r);
1662 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1663 unit_file_changes_free(changes, n_changes);
1668 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1669 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1672 DBusMessageIter iter;
1673 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1674 UnitFileChange *changes = NULL;
1675 unsigned n_changes = 0;
1676 dbus_bool_t runtime;
1678 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1680 if (!dbus_message_iter_init(message, &iter))
1683 r = bus_parse_strv_iter(&iter, &l);
1688 return bus_send_error_reply(connection, message, NULL, r);
1691 if (!dbus_message_iter_next(&iter) ||
1692 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1694 return bus_send_error_reply(connection, message, NULL, -EIO);
1697 if (streq(member, "DisableUnitFiles"))
1698 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1699 else if (streq(member, "UnmaskUnitFiles"))
1700 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1702 assert_not_reached("Uh? Wrong method");
1705 bus_manager_send_unit_files_changed(m);
1708 unit_file_changes_free(changes, n_changes);
1709 return bus_send_error_reply(connection, message, NULL, r);
1712 reply = message_from_file_changes(message, changes, n_changes, -1);
1713 unit_file_changes_free(changes, n_changes);
1718 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1719 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1720 _cleanup_free_ char *default_target = NULL;
1722 reply = dbus_message_new_method_return(message);
1726 r = unit_file_get_default(scope, NULL, &default_target);
1728 return bus_send_error_reply(connection, message, NULL, r);
1730 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1734 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1735 DBusMessageIter iter;
1736 dbus_bool_t runtime;
1740 if (!dbus_message_iter_init(message, &iter))
1743 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1744 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1745 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1747 u = manager_get_unit(m, name);
1749 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1750 return bus_send_error_reply(connection, message, &error, -ENOENT);
1753 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1755 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1757 return bus_send_error_reply(connection, message, &error, r);
1759 reply = dbus_message_new_method_return(message);
1763 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1764 const char *name, *smode;
1765 DBusMessageIter iter;
1770 if (!dbus_message_iter_init(message, &iter))
1773 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1774 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1775 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1777 t = unit_name_to_type(name);
1779 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1780 if (!unit_vtable[t]->can_transient) {
1781 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1782 return bus_send_error_reply(connection, message, &error, -EINVAL);
1785 mode = job_mode_from_string(smode);
1787 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1788 return bus_send_error_reply(connection, message, &error, -EINVAL);
1791 r = manager_load_unit(m, name, NULL, NULL, &u);
1793 return bus_send_error_reply(connection, message, &error, r);
1795 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1797 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1798 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1799 return bus_send_error_reply(connection, message, &error, -EEXIST);
1802 /* OK, the unit failed to load and is unreferenced,
1803 * now let's fill in the transient data instead */
1804 r = unit_make_transient(u);
1806 return bus_send_error_reply(connection, message, &error, r);
1808 /* Set our properties */
1809 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1811 return bus_send_error_reply(connection, message, &error, r);
1813 /* And load this stub fully */
1816 return bus_send_error_reply(connection, message, &error, r);
1818 manager_dispatch_load_queue(m);
1820 /* Finally, start it */
1821 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1824 const BusBoundProperties bps[] = {
1825 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1826 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1830 SELINUX_ACCESS_CHECK(connection, message, "status");
1832 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1835 if (job_type != _JOB_TYPE_INVALID) {
1836 const char *name, *smode, *old_name = NULL;
1841 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1842 b = dbus_message_get_args(
1845 DBUS_TYPE_STRING, &old_name,
1846 DBUS_TYPE_STRING, &name,
1847 DBUS_TYPE_STRING, &smode,
1850 b = dbus_message_get_args(
1853 DBUS_TYPE_STRING, &name,
1854 DBUS_TYPE_STRING, &smode,
1857 return bus_send_error_reply(connection, message, &error, -EINVAL);
1860 u = manager_get_unit(m, old_name);
1861 if (!u || !u->job || u->job->type != JOB_START) {
1862 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1863 return bus_send_error_reply(connection, message, &error, -ENOENT);
1867 mode = job_mode_from_string(smode);
1869 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1870 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 r = manager_load_unit(m, name, NULL, &error, &u);
1875 return bus_send_error_reply(connection, message, &error, r);
1877 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1881 if (!bus_maybe_send_reply(connection, message, reply))
1884 return DBUS_HANDLER_RESULT_HANDLED;
1887 dbus_error_free(&error);
1889 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1892 const DBusObjectPathVTable bus_manager_vtable = {
1893 .message_function = bus_manager_message_handler