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) {
422 r = log_level_to_string_alloc(log_get_max_level(), &t);
426 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
433 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
439 dbus_message_iter_get_basic(i, &t);
441 return log_set_max_level_from_string(t);
444 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
452 u = hashmap_size(m->units);
454 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
460 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
468 u = hashmap_size(m->jobs);
470 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
476 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
484 if (dual_timestamp_is_set(&m->finish_timestamp))
487 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
489 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
495 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
503 detect_virtualization(&id);
505 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
511 static DBusMessage *message_from_file_changes(
513 UnitFileChange *changes,
515 int carries_install_info) {
517 DBusMessageIter iter, sub, sub2;
521 reply = dbus_message_new_method_return(m);
525 dbus_message_iter_init_append(reply, &iter);
527 if (carries_install_info >= 0) {
530 b = !!carries_install_info;
531 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
535 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
538 for (i = 0; i < n_changes; i++) {
539 const char *type, *path, *source;
541 type = unit_file_change_type_to_string(changes[i].type);
542 path = strempty(changes[i].path);
543 source = strempty(changes[i].source);
545 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
546 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
547 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
548 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
549 !dbus_message_iter_close_container(&sub, &sub2))
553 if (!dbus_message_iter_close_container(&iter, &sub))
559 dbus_message_unref(reply);
563 static int bus_manager_send_unit_files_changed(Manager *m) {
567 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
571 r = bus_broadcast(m, s);
572 dbus_message_unref(s);
577 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
583 dbus_message_iter_get_basic(i, t);
585 return watchdog_set_timeout(t);
588 static const char systemd_property_string[] =
592 static const BusProperty bus_systemd_properties[] = {
593 { "Version", bus_property_append_string, "s", 0 },
594 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
598 static const BusProperty bus_manager_properties[] = {
599 { "Tainted", bus_manager_append_tainted, "s", 0 },
600 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
601 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
602 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
603 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
604 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
605 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
606 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
607 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
608 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
609 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
610 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
611 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
612 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
613 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
614 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
615 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
616 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
617 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
618 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
619 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
620 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
621 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
622 { "NNames", bus_manager_append_n_names, "u", 0 },
623 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
624 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
625 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
626 { "Progress", bus_manager_append_progress, "d", 0 },
627 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
628 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
629 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
630 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
631 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
632 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
633 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
634 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
635 { "Virtualization", bus_manager_append_virt, "s", 0, },
639 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
640 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
641 _cleanup_free_ char * path = NULL;
645 JobType job_type = _JOB_TYPE_INVALID;
646 bool reload_if_possible = false;
653 dbus_error_init(&error);
655 member = dbus_message_get_member(message);
657 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
661 if (!dbus_message_get_args(
664 DBUS_TYPE_STRING, &name,
666 return bus_send_error_reply(connection, message, &error, -EINVAL);
668 u = manager_get_unit(m, name);
670 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
671 return bus_send_error_reply(connection, message, &error, -ENOENT);
674 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
676 reply = dbus_message_new_method_return(message);
680 path = unit_dbus_path(u);
684 if (!dbus_message_append_args(
686 DBUS_TYPE_OBJECT_PATH, &path,
689 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
693 if (!dbus_message_get_args(
696 DBUS_TYPE_UINT32, &pid,
698 return bus_send_error_reply(connection, message, &error, -EINVAL);
700 u = manager_get_unit_by_pid(m, (pid_t) pid);
702 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
703 return bus_send_error_reply(connection, message, &error, -ENOENT);
706 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
708 reply = dbus_message_new_method_return(message);
712 path = unit_dbus_path(u);
716 if (!dbus_message_append_args(
718 DBUS_TYPE_OBJECT_PATH, &path,
721 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
725 if (!dbus_message_get_args(
728 DBUS_TYPE_STRING, &name,
730 return bus_send_error_reply(connection, message, &error, -EINVAL);
732 r = manager_load_unit(m, name, NULL, &error, &u);
734 return bus_send_error_reply(connection, message, &error, r);
736 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
738 reply = dbus_message_new_method_return(message);
742 path = unit_dbus_path(u);
746 if (!dbus_message_append_args(
748 DBUS_TYPE_OBJECT_PATH, &path,
752 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
753 job_type = JOB_START;
754 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
755 job_type = JOB_START;
756 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
758 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
759 job_type = JOB_RELOAD;
760 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
761 job_type = JOB_RESTART;
762 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
763 job_type = JOB_TRY_RESTART;
764 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
765 reload_if_possible = true;
766 job_type = JOB_RESTART;
767 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
768 reload_if_possible = true;
769 job_type = JOB_TRY_RESTART;
770 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
771 const char *name, *swho;
776 if (!dbus_message_get_args(
779 DBUS_TYPE_STRING, &name,
780 DBUS_TYPE_STRING, &swho,
781 DBUS_TYPE_INT32, &signo,
783 return bus_send_error_reply(connection, message, &error, -EINVAL);
788 who = kill_who_from_string(swho);
790 return bus_send_error_reply(connection, message, &error, -EINVAL);
793 if (signo <= 0 || signo >= _NSIG)
794 return bus_send_error_reply(connection, message, &error, -EINVAL);
796 u = manager_get_unit(m, name);
798 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
799 return bus_send_error_reply(connection, message, &error, -ENOENT);
802 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
804 r = unit_kill(u, who, signo, &error);
806 return bus_send_error_reply(connection, message, &error, r);
808 reply = dbus_message_new_method_return(message);
812 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
816 if (!dbus_message_get_args(
819 DBUS_TYPE_UINT32, &id,
821 return bus_send_error_reply(connection, message, &error, -EINVAL);
823 j = manager_get_job(m, id);
825 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
826 return bus_send_error_reply(connection, message, &error, -ENOENT);
829 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
831 reply = dbus_message_new_method_return(message);
835 path = job_dbus_path(j);
839 if (!dbus_message_append_args(
841 DBUS_TYPE_OBJECT_PATH, &path,
845 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
849 if (!dbus_message_get_args(
852 DBUS_TYPE_UINT32, &id,
854 return bus_send_error_reply(connection, message, &error, -EINVAL);
856 j = manager_get_job(m, id);
858 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
859 return bus_send_error_reply(connection, message, &error, -ENOENT);
862 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
863 job_finish_and_invalidate(j, JOB_CANCELED, true);
865 reply = dbus_message_new_method_return(message);
869 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
871 SELINUX_ACCESS_CHECK(connection, message, "reboot");
872 manager_clear_jobs(m);
874 reply = dbus_message_new_method_return(message);
878 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
880 SELINUX_ACCESS_CHECK(connection, message, "reload");
882 manager_reset_failed(m);
884 reply = dbus_message_new_method_return(message);
888 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
892 if (!dbus_message_get_args(
895 DBUS_TYPE_STRING, &name,
897 return bus_send_error_reply(connection, message, &error, -EINVAL);
899 u = manager_get_unit(m, name);
901 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
902 return bus_send_error_reply(connection, message, &error, -ENOENT);
905 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
907 unit_reset_failed(u);
909 reply = dbus_message_new_method_return(message);
913 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
914 DBusMessageIter iter, sub;
919 SELINUX_ACCESS_CHECK(connection, message, "status");
921 reply = dbus_message_new_method_return(message);
925 dbus_message_iter_init_append(reply, &iter);
927 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
930 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
931 char *u_path, *j_path;
932 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
933 DBusMessageIter sub2;
940 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
943 description = unit_description(u);
944 load_state = unit_load_state_to_string(u->load_state);
945 active_state = unit_active_state_to_string(unit_active_state(u));
946 sub_state = unit_sub_state_to_string(u);
948 f = unit_following(u);
949 following = f ? f->id : "";
951 u_path = unit_dbus_path(u);
956 job_id = (uint32_t) u->job->id;
958 if (!(j_path = job_dbus_path(u->job))) {
963 sjob_type = job_type_to_string(u->job->type);
970 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
971 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
972 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
973 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
974 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
975 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
976 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
977 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
978 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
979 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
990 if (!dbus_message_iter_close_container(&sub, &sub2))
994 if (!dbus_message_iter_close_container(&iter, &sub))
997 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
998 DBusMessageIter iter, sub;
1002 SELINUX_ACCESS_CHECK(connection, message, "status");
1004 reply = dbus_message_new_method_return(message);
1008 dbus_message_iter_init_append(reply, &iter);
1010 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1013 HASHMAP_FOREACH(j, m->jobs, i) {
1014 char *u_path, *j_path;
1015 const char *state, *type;
1017 DBusMessageIter sub2;
1019 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1022 id = (uint32_t) j->id;
1023 state = job_state_to_string(j->state);
1024 type = job_type_to_string(j->type);
1026 j_path = job_dbus_path(j);
1030 u_path = unit_dbus_path(j->unit);
1036 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1037 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1038 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1039 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1040 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1041 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1050 if (!dbus_message_iter_close_container(&sub, &sub2))
1054 if (!dbus_message_iter_close_container(&iter, &sub))
1057 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1061 SELINUX_ACCESS_CHECK(connection, message, "status");
1063 s = bus_acquire_subscribed(m, connection);
1067 client = strdup(bus_message_get_sender_with_fallback(message));
1071 r = set_consume(s, client);
1073 return bus_send_error_reply(connection, message, NULL, r);
1075 reply = dbus_message_new_method_return(message);
1079 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1082 SELINUX_ACCESS_CHECK(connection, message, "status");
1084 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1086 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1087 return bus_send_error_reply(connection, message, &error, -ENOENT);
1092 reply = dbus_message_new_method_return(message);
1096 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1101 SELINUX_ACCESS_CHECK(connection, message, "status");
1103 reply = dbus_message_new_method_return(message);
1107 f = open_memstream(&dump, &size);
1111 manager_dump_units(m, f, NULL);
1112 manager_dump_jobs(m, f, NULL);
1122 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1128 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1130 dbus_bool_t cleanup;
1133 SELINUX_ACCESS_CHECK(connection, message, "start");
1135 if (!dbus_message_get_args(
1138 DBUS_TYPE_STRING, &name,
1139 DBUS_TYPE_BOOLEAN, &cleanup,
1141 return bus_send_error_reply(connection, message, &error, -EINVAL);
1146 r = snapshot_create(m, name, cleanup, &error, &s);
1148 return bus_send_error_reply(connection, message, &error, r);
1150 reply = dbus_message_new_method_return(message);
1154 path = unit_dbus_path(UNIT(s));
1158 if (!dbus_message_append_args(
1160 DBUS_TYPE_OBJECT_PATH, &path,
1164 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1168 if (!dbus_message_get_args(
1171 DBUS_TYPE_STRING, &name,
1173 return bus_send_error_reply(connection, message, &error, -EINVAL);
1175 u = manager_get_unit(m, name);
1177 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1178 return bus_send_error_reply(connection, message, &error, -ENOENT);
1181 if (u->type != UNIT_SNAPSHOT) {
1182 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1183 return bus_send_error_reply(connection, message, &error, -ENOENT);
1186 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1187 snapshot_remove(SNAPSHOT(u));
1189 reply = dbus_message_new_method_return(message);
1193 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1194 char *introspection = NULL;
1202 SELINUX_ACCESS_CHECK(connection, message, "status");
1204 reply = dbus_message_new_method_return(message);
1208 /* We roll our own introspection code here, instead of
1209 * relying on bus_default_message_handler() because we
1210 * need to generate our introspection string
1213 f = open_memstream(&introspection, &size);
1217 fputs(INTROSPECTION_BEGIN, f);
1219 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1225 p = bus_path_escape(k);
1228 free(introspection);
1232 fprintf(f, "<node name=\"unit/%s\"/>", p);
1236 HASHMAP_FOREACH(j, m->jobs, i)
1237 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1239 fputs(INTROSPECTION_END, f);
1243 free(introspection);
1252 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1253 free(introspection);
1257 free(introspection);
1259 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1261 SELINUX_ACCESS_CHECK(connection, message, "reload");
1263 assert(!m->queued_message);
1265 /* Instead of sending the reply back right away, we
1266 * just remember that we need to and then send it
1267 * after the reload is finished. That way the caller
1268 * knows when the reload finished. */
1270 m->queued_message = dbus_message_new_method_return(message);
1271 if (!m->queued_message)
1274 m->queued_message_connection = connection;
1275 m->exit_code = MANAGER_RELOAD;
1277 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1279 SELINUX_ACCESS_CHECK(connection, message, "reload");
1281 /* We don't send a reply back here, the client should
1282 * just wait for us disconnecting. */
1284 m->exit_code = MANAGER_REEXECUTE;
1286 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1288 SELINUX_ACCESS_CHECK(connection, message, "halt");
1290 if (m->running_as == SYSTEMD_SYSTEM) {
1291 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1292 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1295 reply = dbus_message_new_method_return(message);
1299 m->exit_code = MANAGER_EXIT;
1301 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1303 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1305 if (m->running_as != SYSTEMD_SYSTEM) {
1306 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1307 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1310 reply = dbus_message_new_method_return(message);
1314 m->exit_code = MANAGER_REBOOT;
1316 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1318 SELINUX_ACCESS_CHECK(connection, message, "halt");
1320 if (m->running_as != SYSTEMD_SYSTEM) {
1321 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1322 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1325 reply = dbus_message_new_method_return(message);
1329 m->exit_code = MANAGER_POWEROFF;
1331 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1333 SELINUX_ACCESS_CHECK(connection, message, "halt");
1335 if (m->running_as != SYSTEMD_SYSTEM) {
1336 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1337 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1340 reply = dbus_message_new_method_return(message);
1344 m->exit_code = MANAGER_HALT;
1346 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1348 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1350 if (m->running_as != SYSTEMD_SYSTEM) {
1351 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1352 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1355 reply = dbus_message_new_method_return(message);
1359 m->exit_code = MANAGER_KEXEC;
1361 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1362 const char *switch_root, *switch_root_init;
1366 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1368 if (!dbus_message_get_args(
1371 DBUS_TYPE_STRING, &switch_root,
1372 DBUS_TYPE_STRING, &switch_root_init,
1374 return bus_send_error_reply(connection, message, &error, -EINVAL);
1376 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1377 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1379 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1380 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1382 if (m->running_as != SYSTEMD_SYSTEM) {
1383 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1384 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1388 if (isempty(switch_root_init)) {
1389 good = path_is_os_tree(switch_root);
1391 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1394 _cleanup_free_ char *p = NULL;
1396 p = strjoin(switch_root, "/", switch_root_init, NULL);
1400 good = access(p, X_OK) >= 0;
1402 log_error("Not switching root: cannot execute new init %s", p);
1405 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1407 u = strdup(switch_root);
1411 if (!isempty(switch_root_init)) {
1412 v = strdup(switch_root_init);
1420 free(m->switch_root);
1421 free(m->switch_root_init);
1423 m->switch_root_init = v;
1425 reply = dbus_message_new_method_return(message);
1429 m->exit_code = MANAGER_SWITCH_ROOT;
1431 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1432 _cleanup_strv_free_ char **l = NULL;
1435 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1437 r = bus_parse_strv(message, &l);
1441 return bus_send_error_reply(connection, message, NULL, r);
1442 if (!strv_env_is_valid(l))
1443 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1445 e = strv_env_merge(2, m->environment, l);
1449 reply = dbus_message_new_method_return(message);
1455 strv_free(m->environment);
1458 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1459 _cleanup_strv_free_ char **l = NULL;
1462 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1464 r = bus_parse_strv(message, &l);
1468 return bus_send_error_reply(connection, message, NULL, r);
1469 if (!strv_env_name_or_assignment_is_valid(l))
1470 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1472 e = strv_env_delete(m->environment, 1, l);
1476 reply = dbus_message_new_method_return(message);
1482 strv_free(m->environment);
1485 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1486 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1488 DBusMessageIter iter;
1490 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1492 if (!dbus_message_iter_init(message, &iter))
1495 r = bus_parse_strv_iter(&iter, &l_unset);
1499 return bus_send_error_reply(connection, message, NULL, r);
1500 if (!strv_env_name_or_assignment_is_valid(l_unset))
1501 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1503 if (!dbus_message_iter_next(&iter))
1504 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1506 r = bus_parse_strv_iter(&iter, &l_set);
1510 return bus_send_error_reply(connection, message, NULL, r);
1511 if (!strv_env_is_valid(l_set))
1512 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1514 e = strv_env_delete(m->environment, 1, l_unset);
1518 f = strv_env_merge(2, e, l_set);
1522 reply = dbus_message_new_method_return(message);
1528 strv_free(m->environment);
1530 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1531 DBusMessageIter iter, sub, sub2;
1536 SELINUX_ACCESS_CHECK(connection, message, "status");
1538 reply = dbus_message_new_method_return(message);
1542 h = hashmap_new(string_hash_func, string_compare_func);
1546 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1548 unit_file_list_free(h);
1549 return bus_send_error_reply(connection, message, NULL, r);
1552 dbus_message_iter_init_append(reply, &iter);
1554 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1555 unit_file_list_free(h);
1559 HASHMAP_FOREACH(item, h, i) {
1562 state = unit_file_state_to_string(item->state);
1565 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1566 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1567 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1568 !dbus_message_iter_close_container(&sub, &sub2)) {
1569 unit_file_list_free(h);
1574 unit_file_list_free(h);
1576 if (!dbus_message_iter_close_container(&iter, &sub))
1579 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1581 UnitFileState state;
1584 SELINUX_ACCESS_CHECK(connection, message, "status");
1586 if (!dbus_message_get_args(
1589 DBUS_TYPE_STRING, &name,
1591 return bus_send_error_reply(connection, message, &error, -EINVAL);
1593 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1595 return bus_send_error_reply(connection, message, NULL, state);
1597 s = unit_file_state_to_string(state);
1600 reply = dbus_message_new_method_return(message);
1604 if (!dbus_message_append_args(
1606 DBUS_TYPE_STRING, &s,
1609 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1610 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1611 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1612 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1613 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1614 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1617 DBusMessageIter iter;
1618 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1619 UnitFileChange *changes = NULL;
1620 unsigned n_changes = 0;
1621 dbus_bool_t runtime, force;
1622 int carries_install_info = -1;
1624 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1626 if (!dbus_message_iter_init(message, &iter))
1629 r = bus_parse_strv_iter(&iter, &l);
1634 return bus_send_error_reply(connection, message, NULL, r);
1637 if (!dbus_message_iter_next(&iter) ||
1638 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1639 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1641 return bus_send_error_reply(connection, message, NULL, -EIO);
1644 if (streq(member, "EnableUnitFiles")) {
1645 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1646 carries_install_info = r;
1647 } else if (streq(member, "ReenableUnitFiles")) {
1648 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1649 carries_install_info = r;
1650 } else if (streq(member, "LinkUnitFiles"))
1651 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1652 else if (streq(member, "PresetUnitFiles")) {
1653 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1654 carries_install_info = r;
1655 } else if (streq(member, "MaskUnitFiles"))
1656 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1657 else if (streq(member, "SetDefaultTarget"))
1658 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1660 assert_not_reached("Uh? Wrong method");
1663 bus_manager_send_unit_files_changed(m);
1666 unit_file_changes_free(changes, n_changes);
1667 return bus_send_error_reply(connection, message, NULL, r);
1670 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1671 unit_file_changes_free(changes, n_changes);
1676 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1677 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1680 DBusMessageIter iter;
1681 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1682 UnitFileChange *changes = NULL;
1683 unsigned n_changes = 0;
1684 dbus_bool_t runtime;
1686 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1688 if (!dbus_message_iter_init(message, &iter))
1691 r = bus_parse_strv_iter(&iter, &l);
1696 return bus_send_error_reply(connection, message, NULL, r);
1699 if (!dbus_message_iter_next(&iter) ||
1700 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1702 return bus_send_error_reply(connection, message, NULL, -EIO);
1705 if (streq(member, "DisableUnitFiles"))
1706 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1707 else if (streq(member, "UnmaskUnitFiles"))
1708 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1710 assert_not_reached("Uh? Wrong method");
1713 bus_manager_send_unit_files_changed(m);
1716 unit_file_changes_free(changes, n_changes);
1717 return bus_send_error_reply(connection, message, NULL, r);
1720 reply = message_from_file_changes(message, changes, n_changes, -1);
1721 unit_file_changes_free(changes, n_changes);
1726 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1727 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1728 _cleanup_free_ char *default_target = NULL;
1730 reply = dbus_message_new_method_return(message);
1734 r = unit_file_get_default(scope, NULL, &default_target);
1736 return bus_send_error_reply(connection, message, NULL, r);
1738 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1742 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1743 DBusMessageIter iter;
1744 dbus_bool_t runtime;
1748 if (!dbus_message_iter_init(message, &iter))
1751 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1752 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1753 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1755 u = manager_get_unit(m, name);
1757 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1758 return bus_send_error_reply(connection, message, &error, -ENOENT);
1761 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1763 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1765 return bus_send_error_reply(connection, message, &error, r);
1767 reply = dbus_message_new_method_return(message);
1771 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1772 const char *name, *smode;
1773 DBusMessageIter iter;
1778 if (!dbus_message_iter_init(message, &iter))
1781 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1782 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1783 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1785 t = unit_name_to_type(name);
1787 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1788 if (!unit_vtable[t]->can_transient) {
1789 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1790 return bus_send_error_reply(connection, message, &error, -EINVAL);
1793 mode = job_mode_from_string(smode);
1795 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1796 return bus_send_error_reply(connection, message, &error, -EINVAL);
1799 r = manager_load_unit(m, name, NULL, NULL, &u);
1801 return bus_send_error_reply(connection, message, &error, r);
1803 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1805 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1806 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1807 return bus_send_error_reply(connection, message, &error, -EEXIST);
1810 /* OK, the unit failed to load and is unreferenced,
1811 * now let's fill in the transient data instead */
1812 r = unit_make_transient(u);
1814 return bus_send_error_reply(connection, message, &error, r);
1816 /* Set our properties */
1817 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1819 return bus_send_error_reply(connection, message, &error, r);
1821 /* And load this stub fully */
1824 return bus_send_error_reply(connection, message, &error, r);
1826 manager_dispatch_load_queue(m);
1828 /* Finally, start it */
1829 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1832 const BusBoundProperties bps[] = {
1833 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1834 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1838 SELINUX_ACCESS_CHECK(connection, message, "status");
1840 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1843 if (job_type != _JOB_TYPE_INVALID) {
1844 const char *name, *smode, *old_name = NULL;
1849 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1850 b = dbus_message_get_args(
1853 DBUS_TYPE_STRING, &old_name,
1854 DBUS_TYPE_STRING, &name,
1855 DBUS_TYPE_STRING, &smode,
1858 b = dbus_message_get_args(
1861 DBUS_TYPE_STRING, &name,
1862 DBUS_TYPE_STRING, &smode,
1865 return bus_send_error_reply(connection, message, &error, -EINVAL);
1868 u = manager_get_unit(m, old_name);
1869 if (!u || !u->job || u->job->type != JOB_START) {
1870 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1871 return bus_send_error_reply(connection, message, &error, -ENOENT);
1875 mode = job_mode_from_string(smode);
1877 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1878 return bus_send_error_reply(connection, message, &error, -EINVAL);
1881 r = manager_load_unit(m, name, NULL, &error, &u);
1883 return bus_send_error_reply(connection, message, &error, r);
1885 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1889 if (!bus_maybe_send_reply(connection, message, reply))
1892 return DBUS_HANDLER_RESULT_HANDLED;
1895 dbus_error_free(&error);
1897 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1900 const DBusObjectPathVTable bus_manager_vtable = {
1901 .message_function = bus_manager_message_handler