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=\"out\"/>\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"
281 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
282 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
283 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
284 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
285 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
286 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
287 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
288 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
289 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
290 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
291 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
292 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
293 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
294 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
295 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
296 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
297 " <property name=\"GeneratorsStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
298 " <property name=\"GeneratorsStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
299 " <property name=\"GeneratorsFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
300 " <property name=\"GeneratorsFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
301 " <property name=\"UnitsLoadStartTimestamp\" type=\"t\" access=\"read\"/>\n" \
302 " <property name=\"UnitsLoadStartTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
303 " <property name=\"UnitsLoadFinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
304 " <property name=\"UnitsLoadFinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
305 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
306 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
307 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
308 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
309 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
310 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
311 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
312 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
313 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
314 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
315 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
316 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
317 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
318 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
319 " <property name=\"RuntimeWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
320 " <property name=\"ShutdownWatchdogUSec\" type=\"t\" access=\"readwrite\"/>\n" \
321 " <property name=\"Virtualization\" type=\"s\" access=\"read\"/>\n"
323 #define BUS_MANAGER_INTERFACE_END \
326 #define BUS_MANAGER_INTERFACE \
327 BUS_MANAGER_INTERFACE_BEGIN \
328 BUS_MANAGER_INTERFACE_METHODS \
329 BUS_MANAGER_INTERFACE_SIGNALS \
330 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
331 BUS_MANAGER_INTERFACE_END
333 #define INTROSPECTION_BEGIN \
334 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
336 BUS_MANAGER_INTERFACE \
337 BUS_PROPERTIES_INTERFACE \
339 BUS_INTROSPECTABLE_INTERFACE
341 #define INTROSPECTION_END \
344 #define INTERFACES_LIST \
345 BUS_GENERIC_INTERFACES_LIST \
346 "org.freedesktop.systemd1.Manager\0"
348 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
350 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
352 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
355 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
362 e = stpcpy(e, "split-usr:");
364 if (readlink_malloc("/etc/mtab", &p) < 0)
365 e = stpcpy(e, "mtab-not-symlink:");
369 if (access("/proc/cgroups", F_OK) < 0)
370 e = stpcpy(e, "cgroups-missing:");
372 if (hwclock_is_localtime() > 0)
373 e = stpcpy(e, "local-hwclock:");
375 /* remove the last ':' */
381 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
387 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
393 t = log_target_to_string(log_get_target());
395 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
401 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
407 dbus_message_iter_get_basic(i, &t);
409 return log_set_target_from_string(t);
412 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
419 r = log_level_to_string_alloc(log_get_max_level(), &t);
423 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
430 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
436 dbus_message_iter_get_basic(i, &t);
438 return log_set_max_level_from_string(t);
441 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
449 u = hashmap_size(m->units);
451 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
457 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
465 u = hashmap_size(m->jobs);
467 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
473 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
481 if (dual_timestamp_is_set(&m->finish_timestamp))
484 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
486 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
492 static int bus_manager_append_virt(DBusMessageIter *i, const char *property, void *data) {
500 detect_virtualization(&id);
502 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &id))
508 static DBusMessage *message_from_file_changes(
510 UnitFileChange *changes,
512 int carries_install_info) {
514 DBusMessageIter iter, sub, sub2;
518 reply = dbus_message_new_method_return(m);
522 dbus_message_iter_init_append(reply, &iter);
524 if (carries_install_info >= 0) {
527 b = !!carries_install_info;
528 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
532 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
535 for (i = 0; i < n_changes; i++) {
536 const char *type, *path, *source;
538 type = unit_file_change_type_to_string(changes[i].type);
539 path = strempty(changes[i].path);
540 source = strempty(changes[i].source);
542 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
543 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
544 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
545 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
546 !dbus_message_iter_close_container(&sub, &sub2))
550 if (!dbus_message_iter_close_container(&iter, &sub))
556 dbus_message_unref(reply);
560 static int bus_manager_send_unit_files_changed(Manager *m) {
564 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
568 r = bus_broadcast(m, s);
569 dbus_message_unref(s);
574 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
580 dbus_message_iter_get_basic(i, t);
582 return watchdog_set_timeout(t);
585 static const char systemd_property_string[] =
589 static const BusProperty bus_systemd_properties[] = {
590 { "Version", bus_property_append_string, "s", 0 },
591 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
595 static const BusProperty bus_manager_properties[] = {
596 { "Tainted", bus_manager_append_tainted, "s", 0 },
597 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
598 { "FirmwareTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.monotonic) },
599 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
600 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
601 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
602 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
603 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
604 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
605 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime) },
606 { "UserspaceTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.monotonic) },
607 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
608 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
609 { "GeneratorsStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.realtime) },
610 { "GeneratorsStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_start_timestamp.monotonic) },
611 { "GeneratorsFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.realtime) },
612 { "GeneratorsFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, generators_finish_timestamp.monotonic) },
613 { "UnitsLoadStartTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.realtime) },
614 { "UnitsLoadStartTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_start_timestamp.monotonic) },
615 { "UnitsLoadFinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.realtime) },
616 { "UnitsLoadFinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, unitsload_finish_timestamp.monotonic) },
617 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
618 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
619 { "NNames", bus_manager_append_n_names, "u", 0 },
620 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
621 { "NInstalledJobs", bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
622 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
623 { "Progress", bus_manager_append_progress, "d", 0 },
624 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
625 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
626 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
627 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
628 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
629 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
630 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
631 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
632 { "Virtualization", bus_manager_append_virt, "s", 0, },
636 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
637 _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
638 _cleanup_free_ char * path = NULL;
642 JobType job_type = _JOB_TYPE_INVALID;
643 bool reload_if_possible = false;
650 dbus_error_init(&error);
652 member = dbus_message_get_member(message);
654 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
658 if (!dbus_message_get_args(
661 DBUS_TYPE_STRING, &name,
663 return bus_send_error_reply(connection, message, &error, -EINVAL);
665 u = manager_get_unit(m, name);
667 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
668 return bus_send_error_reply(connection, message, &error, -ENOENT);
671 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
673 reply = dbus_message_new_method_return(message);
677 path = unit_dbus_path(u);
681 if (!dbus_message_append_args(
683 DBUS_TYPE_OBJECT_PATH, &path,
686 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
690 if (!dbus_message_get_args(
693 DBUS_TYPE_UINT32, &pid,
695 return bus_send_error_reply(connection, message, &error, -EINVAL);
697 u = manager_get_unit_by_pid(m, (pid_t) pid);
699 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
700 return bus_send_error_reply(connection, message, &error, -ENOENT);
703 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
705 reply = dbus_message_new_method_return(message);
709 path = unit_dbus_path(u);
713 if (!dbus_message_append_args(
715 DBUS_TYPE_OBJECT_PATH, &path,
718 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
722 if (!dbus_message_get_args(
725 DBUS_TYPE_STRING, &name,
727 return bus_send_error_reply(connection, message, &error, -EINVAL);
729 r = manager_load_unit(m, name, NULL, &error, &u);
731 return bus_send_error_reply(connection, message, &error, r);
733 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "status");
735 reply = dbus_message_new_method_return(message);
739 path = unit_dbus_path(u);
743 if (!dbus_message_append_args(
745 DBUS_TYPE_OBJECT_PATH, &path,
749 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
750 job_type = JOB_START;
751 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
752 job_type = JOB_START;
753 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
755 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
756 job_type = JOB_RELOAD;
757 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
758 job_type = JOB_RESTART;
759 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
760 job_type = JOB_TRY_RESTART;
761 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
762 reload_if_possible = true;
763 job_type = JOB_RESTART;
764 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
765 reload_if_possible = true;
766 job_type = JOB_TRY_RESTART;
767 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
768 const char *name, *swho;
773 if (!dbus_message_get_args(
776 DBUS_TYPE_STRING, &name,
777 DBUS_TYPE_STRING, &swho,
778 DBUS_TYPE_INT32, &signo,
780 return bus_send_error_reply(connection, message, &error, -EINVAL);
785 who = kill_who_from_string(swho);
787 return bus_send_error_reply(connection, message, &error, -EINVAL);
790 if (signo <= 0 || signo >= _NSIG)
791 return bus_send_error_reply(connection, message, &error, -EINVAL);
793 u = manager_get_unit(m, name);
795 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
796 return bus_send_error_reply(connection, message, &error, -ENOENT);
799 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
801 r = unit_kill(u, who, signo, &error);
803 return bus_send_error_reply(connection, message, &error, r);
805 reply = dbus_message_new_method_return(message);
809 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
813 if (!dbus_message_get_args(
816 DBUS_TYPE_UINT32, &id,
818 return bus_send_error_reply(connection, message, &error, -EINVAL);
820 j = manager_get_job(m, id);
822 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
823 return bus_send_error_reply(connection, message, &error, -ENOENT);
826 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "status");
828 reply = dbus_message_new_method_return(message);
832 path = job_dbus_path(j);
836 if (!dbus_message_append_args(
838 DBUS_TYPE_OBJECT_PATH, &path,
842 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CancelJob")) {
846 if (!dbus_message_get_args(
849 DBUS_TYPE_UINT32, &id,
851 return bus_send_error_reply(connection, message, &error, -EINVAL);
853 j = manager_get_job(m, id);
855 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
856 return bus_send_error_reply(connection, message, &error, -ENOENT);
859 SELINUX_UNIT_ACCESS_CHECK(j->unit, connection, message, "stop");
860 job_finish_and_invalidate(j, JOB_CANCELED, true);
862 reply = dbus_message_new_method_return(message);
866 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
868 SELINUX_ACCESS_CHECK(connection, message, "reboot");
869 manager_clear_jobs(m);
871 reply = dbus_message_new_method_return(message);
875 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
877 SELINUX_ACCESS_CHECK(connection, message, "reload");
879 manager_reset_failed(m);
881 reply = dbus_message_new_method_return(message);
885 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
889 if (!dbus_message_get_args(
892 DBUS_TYPE_STRING, &name,
894 return bus_send_error_reply(connection, message, &error, -EINVAL);
896 u = manager_get_unit(m, name);
898 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
899 return bus_send_error_reply(connection, message, &error, -ENOENT);
902 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "reload");
904 unit_reset_failed(u);
906 reply = dbus_message_new_method_return(message);
910 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
911 DBusMessageIter iter, sub;
916 SELINUX_ACCESS_CHECK(connection, message, "status");
918 reply = dbus_message_new_method_return(message);
922 dbus_message_iter_init_append(reply, &iter);
924 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
927 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
928 char *u_path, *j_path;
929 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
930 DBusMessageIter sub2;
937 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
940 description = unit_description(u);
941 load_state = unit_load_state_to_string(u->load_state);
942 active_state = unit_active_state_to_string(unit_active_state(u));
943 sub_state = unit_sub_state_to_string(u);
945 f = unit_following(u);
946 following = f ? f->id : "";
948 u_path = unit_dbus_path(u);
953 job_id = (uint32_t) u->job->id;
955 if (!(j_path = job_dbus_path(u->job))) {
960 sjob_type = job_type_to_string(u->job->type);
967 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
968 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
969 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
970 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
971 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
972 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
973 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
974 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
975 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
976 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
987 if (!dbus_message_iter_close_container(&sub, &sub2))
991 if (!dbus_message_iter_close_container(&iter, &sub))
994 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
995 DBusMessageIter iter, sub;
999 SELINUX_ACCESS_CHECK(connection, message, "status");
1001 reply = dbus_message_new_method_return(message);
1005 dbus_message_iter_init_append(reply, &iter);
1007 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
1010 HASHMAP_FOREACH(j, m->jobs, i) {
1011 char *u_path, *j_path;
1012 const char *state, *type;
1014 DBusMessageIter sub2;
1016 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
1019 id = (uint32_t) j->id;
1020 state = job_state_to_string(j->state);
1021 type = job_type_to_string(j->type);
1023 j_path = job_dbus_path(j);
1027 u_path = unit_dbus_path(j->unit);
1033 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
1034 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
1035 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
1036 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1037 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
1038 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
1047 if (!dbus_message_iter_close_container(&sub, &sub2))
1051 if (!dbus_message_iter_close_container(&iter, &sub))
1054 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
1058 SELINUX_ACCESS_CHECK(connection, message, "status");
1060 s = BUS_CONNECTION_SUBSCRIBED(m, connection);
1062 s = set_new(string_hash_func, string_compare_func);
1066 if (!dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL)) {
1072 client = strdup(bus_message_get_sender_with_fallback(message));
1076 r = set_consume(s, client);
1078 return bus_send_error_reply(connection, message, NULL, r);
1080 reply = dbus_message_new_method_return(message);
1084 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1087 SELINUX_ACCESS_CHECK(connection, message, "status");
1089 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1091 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1092 return bus_send_error_reply(connection, message, &error, -ENOENT);
1097 reply = dbus_message_new_method_return(message);
1101 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1106 SELINUX_ACCESS_CHECK(connection, message, "status");
1108 reply = dbus_message_new_method_return(message);
1112 f = open_memstream(&dump, &size);
1116 manager_dump_units(m, f, NULL);
1117 manager_dump_jobs(m, f, NULL);
1127 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1133 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1135 dbus_bool_t cleanup;
1138 SELINUX_ACCESS_CHECK(connection, message, "start");
1140 if (!dbus_message_get_args(
1143 DBUS_TYPE_STRING, &name,
1144 DBUS_TYPE_BOOLEAN, &cleanup,
1146 return bus_send_error_reply(connection, message, &error, -EINVAL);
1151 r = snapshot_create(m, name, cleanup, &error, &s);
1153 return bus_send_error_reply(connection, message, &error, r);
1155 reply = dbus_message_new_method_return(message);
1159 path = unit_dbus_path(UNIT(s));
1163 if (!dbus_message_append_args(
1165 DBUS_TYPE_OBJECT_PATH, &path,
1169 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1173 if (!dbus_message_get_args(
1176 DBUS_TYPE_STRING, &name,
1178 return bus_send_error_reply(connection, message, &error, -EINVAL);
1180 u = manager_get_unit(m, name);
1182 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1183 return bus_send_error_reply(connection, message, &error, -ENOENT);
1186 if (u->type != UNIT_SNAPSHOT) {
1187 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1188 return bus_send_error_reply(connection, message, &error, -ENOENT);
1191 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1192 snapshot_remove(SNAPSHOT(u));
1194 reply = dbus_message_new_method_return(message);
1198 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1199 char *introspection = NULL;
1207 SELINUX_ACCESS_CHECK(connection, message, "status");
1209 reply = dbus_message_new_method_return(message);
1213 /* We roll our own introspection code here, instead of
1214 * relying on bus_default_message_handler() because we
1215 * need to generate our introspection string
1218 f = open_memstream(&introspection, &size);
1222 fputs(INTROSPECTION_BEGIN, f);
1224 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1230 p = bus_path_escape(k);
1233 free(introspection);
1237 fprintf(f, "<node name=\"unit/%s\"/>", p);
1241 HASHMAP_FOREACH(j, m->jobs, i)
1242 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1244 fputs(INTROSPECTION_END, f);
1248 free(introspection);
1257 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1258 free(introspection);
1262 free(introspection);
1264 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1266 SELINUX_ACCESS_CHECK(connection, message, "reload");
1268 assert(!m->queued_message);
1270 /* Instead of sending the reply back right away, we
1271 * just remember that we need to and then send it
1272 * after the reload is finished. That way the caller
1273 * knows when the reload finished. */
1275 m->queued_message = dbus_message_new_method_return(message);
1276 if (!m->queued_message)
1279 m->queued_message_connection = connection;
1280 m->exit_code = MANAGER_RELOAD;
1282 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1284 SELINUX_ACCESS_CHECK(connection, message, "reload");
1286 /* We don't send a reply back here, the client should
1287 * just wait for us disconnecting. */
1289 m->exit_code = MANAGER_REEXECUTE;
1291 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1293 SELINUX_ACCESS_CHECK(connection, message, "halt");
1295 if (m->running_as == SYSTEMD_SYSTEM) {
1296 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1297 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1300 reply = dbus_message_new_method_return(message);
1304 m->exit_code = MANAGER_EXIT;
1306 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1308 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1310 if (m->running_as != SYSTEMD_SYSTEM) {
1311 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1312 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1315 reply = dbus_message_new_method_return(message);
1319 m->exit_code = MANAGER_REBOOT;
1321 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1323 SELINUX_ACCESS_CHECK(connection, message, "halt");
1325 if (m->running_as != SYSTEMD_SYSTEM) {
1326 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1327 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1330 reply = dbus_message_new_method_return(message);
1334 m->exit_code = MANAGER_POWEROFF;
1336 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1338 SELINUX_ACCESS_CHECK(connection, message, "halt");
1340 if (m->running_as != SYSTEMD_SYSTEM) {
1341 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1342 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1345 reply = dbus_message_new_method_return(message);
1349 m->exit_code = MANAGER_HALT;
1351 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1353 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1355 if (m->running_as != SYSTEMD_SYSTEM) {
1356 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1357 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1360 reply = dbus_message_new_method_return(message);
1364 m->exit_code = MANAGER_KEXEC;
1366 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1367 const char *switch_root, *switch_root_init;
1371 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1373 if (!dbus_message_get_args(
1376 DBUS_TYPE_STRING, &switch_root,
1377 DBUS_TYPE_STRING, &switch_root_init,
1379 return bus_send_error_reply(connection, message, &error, -EINVAL);
1381 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1382 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1384 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1385 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1387 if (m->running_as != SYSTEMD_SYSTEM) {
1388 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1389 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1393 if (isempty(switch_root_init)) {
1394 good = path_is_os_tree(switch_root);
1396 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1399 _cleanup_free_ char *p = NULL;
1401 p = strjoin(switch_root, "/", switch_root_init, NULL);
1405 good = access(p, X_OK) >= 0;
1407 log_error("Not switching root: cannot execute new init %s", p);
1410 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1412 u = strdup(switch_root);
1416 if (!isempty(switch_root_init)) {
1417 v = strdup(switch_root_init);
1425 free(m->switch_root);
1426 free(m->switch_root_init);
1428 m->switch_root_init = v;
1430 reply = dbus_message_new_method_return(message);
1434 m->exit_code = MANAGER_SWITCH_ROOT;
1436 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1437 _cleanup_strv_free_ char **l = NULL;
1440 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1442 r = bus_parse_strv(message, &l);
1446 return bus_send_error_reply(connection, message, NULL, r);
1447 if (!strv_env_is_valid(l))
1448 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1450 e = strv_env_merge(2, m->environment, l);
1454 reply = dbus_message_new_method_return(message);
1460 strv_free(m->environment);
1463 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1464 _cleanup_strv_free_ char **l = NULL;
1467 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1469 r = bus_parse_strv(message, &l);
1473 return bus_send_error_reply(connection, message, NULL, r);
1474 if (!strv_env_name_or_assignment_is_valid(l))
1475 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1477 e = strv_env_delete(m->environment, 1, l);
1481 reply = dbus_message_new_method_return(message);
1487 strv_free(m->environment);
1490 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1491 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1493 DBusMessageIter iter;
1495 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1497 if (!dbus_message_iter_init(message, &iter))
1500 r = bus_parse_strv_iter(&iter, &l_unset);
1504 return bus_send_error_reply(connection, message, NULL, r);
1505 if (!strv_env_name_or_assignment_is_valid(l_unset))
1506 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1508 if (!dbus_message_iter_next(&iter))
1509 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1511 r = bus_parse_strv_iter(&iter, &l_set);
1515 return bus_send_error_reply(connection, message, NULL, r);
1516 if (!strv_env_is_valid(l_set))
1517 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1519 e = strv_env_delete(m->environment, 1, l_unset);
1523 f = strv_env_merge(2, e, l_set);
1527 reply = dbus_message_new_method_return(message);
1533 strv_free(m->environment);
1535 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1536 DBusMessageIter iter, sub, sub2;
1541 SELINUX_ACCESS_CHECK(connection, message, "status");
1543 reply = dbus_message_new_method_return(message);
1547 h = hashmap_new(string_hash_func, string_compare_func);
1551 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1553 unit_file_list_free(h);
1554 return bus_send_error_reply(connection, message, NULL, r);
1557 dbus_message_iter_init_append(reply, &iter);
1559 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1560 unit_file_list_free(h);
1564 HASHMAP_FOREACH(item, h, i) {
1567 state = unit_file_state_to_string(item->state);
1570 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1571 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1572 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1573 !dbus_message_iter_close_container(&sub, &sub2)) {
1574 unit_file_list_free(h);
1579 unit_file_list_free(h);
1581 if (!dbus_message_iter_close_container(&iter, &sub))
1584 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1586 UnitFileState state;
1589 SELINUX_ACCESS_CHECK(connection, message, "status");
1591 if (!dbus_message_get_args(
1594 DBUS_TYPE_STRING, &name,
1596 return bus_send_error_reply(connection, message, &error, -EINVAL);
1598 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1600 return bus_send_error_reply(connection, message, NULL, state);
1602 s = unit_file_state_to_string(state);
1605 reply = dbus_message_new_method_return(message);
1609 if (!dbus_message_append_args(
1611 DBUS_TYPE_STRING, &s,
1614 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1615 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1616 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1617 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1618 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1619 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1622 DBusMessageIter iter;
1623 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1624 UnitFileChange *changes = NULL;
1625 unsigned n_changes = 0;
1626 dbus_bool_t runtime, force;
1627 int carries_install_info = -1;
1629 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1631 if (!dbus_message_iter_init(message, &iter))
1634 r = bus_parse_strv_iter(&iter, &l);
1639 return bus_send_error_reply(connection, message, NULL, r);
1642 if (!dbus_message_iter_next(&iter) ||
1643 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1644 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1646 return bus_send_error_reply(connection, message, NULL, -EIO);
1649 if (streq(member, "EnableUnitFiles")) {
1650 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1651 carries_install_info = r;
1652 } else if (streq(member, "ReenableUnitFiles")) {
1653 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1654 carries_install_info = r;
1655 } else if (streq(member, "LinkUnitFiles"))
1656 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1657 else if (streq(member, "PresetUnitFiles")) {
1658 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1659 carries_install_info = r;
1660 } else if (streq(member, "MaskUnitFiles"))
1661 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1662 else if (streq(member, "SetDefaultTarget"))
1663 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1665 assert_not_reached("Uh? Wrong method");
1668 bus_manager_send_unit_files_changed(m);
1671 unit_file_changes_free(changes, n_changes);
1672 return bus_send_error_reply(connection, message, NULL, r);
1675 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1676 unit_file_changes_free(changes, n_changes);
1681 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1682 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1685 DBusMessageIter iter;
1686 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1687 UnitFileChange *changes = NULL;
1688 unsigned n_changes = 0;
1689 dbus_bool_t runtime;
1691 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1693 if (!dbus_message_iter_init(message, &iter))
1696 r = bus_parse_strv_iter(&iter, &l);
1701 return bus_send_error_reply(connection, message, NULL, r);
1704 if (!dbus_message_iter_next(&iter) ||
1705 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1707 return bus_send_error_reply(connection, message, NULL, -EIO);
1710 if (streq(member, "DisableUnitFiles"))
1711 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1712 else if (streq(member, "UnmaskUnitFiles"))
1713 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1715 assert_not_reached("Uh? Wrong method");
1718 bus_manager_send_unit_files_changed(m);
1721 unit_file_changes_free(changes, n_changes);
1722 return bus_send_error_reply(connection, message, NULL, r);
1725 reply = message_from_file_changes(message, changes, n_changes, -1);
1726 unit_file_changes_free(changes, n_changes);
1731 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1732 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1733 _cleanup_free_ char *default_target = NULL;
1735 reply = dbus_message_new_method_return(message);
1739 r = unit_file_get_default(scope, NULL, &default_target);
1741 return bus_send_error_reply(connection, message, NULL, r);
1743 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1747 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1748 DBusMessageIter iter;
1749 dbus_bool_t runtime;
1753 if (!dbus_message_iter_init(message, &iter))
1756 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1757 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1758 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1760 u = manager_get_unit(m, name);
1762 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1763 return bus_send_error_reply(connection, message, &error, -ENOENT);
1766 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1768 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1770 return bus_send_error_reply(connection, message, &error, r);
1772 reply = dbus_message_new_method_return(message);
1776 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1777 const char *name, *smode;
1778 DBusMessageIter iter;
1783 if (!dbus_message_iter_init(message, &iter))
1786 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1787 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1788 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1790 t = unit_name_to_type(name);
1792 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1793 if (!unit_vtable[t]->can_transient) {
1794 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1795 return bus_send_error_reply(connection, message, &error, -EINVAL);
1798 mode = job_mode_from_string(smode);
1800 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1801 return bus_send_error_reply(connection, message, &error, -EINVAL);
1804 r = manager_load_unit(m, name, NULL, NULL, &u);
1806 return bus_send_error_reply(connection, message, &error, r);
1808 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1810 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1811 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1812 return bus_send_error_reply(connection, message, &error, -EEXIST);
1815 /* OK, the unit failed to load and is unreferenced,
1816 * now let's fill in the transient data instead */
1817 r = unit_make_transient(u);
1819 return bus_send_error_reply(connection, message, &error, r);
1821 /* Set our properties */
1822 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1824 return bus_send_error_reply(connection, message, &error, r);
1826 /* And load this stub fully */
1829 return bus_send_error_reply(connection, message, &error, r);
1831 manager_dispatch_load_queue(m);
1833 /* Finally, start it */
1834 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1837 const BusBoundProperties bps[] = {
1838 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1839 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1843 SELINUX_ACCESS_CHECK(connection, message, "status");
1845 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1848 if (job_type != _JOB_TYPE_INVALID) {
1849 const char *name, *smode, *old_name = NULL;
1854 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1855 b = dbus_message_get_args(
1858 DBUS_TYPE_STRING, &old_name,
1859 DBUS_TYPE_STRING, &name,
1860 DBUS_TYPE_STRING, &smode,
1863 b = dbus_message_get_args(
1866 DBUS_TYPE_STRING, &name,
1867 DBUS_TYPE_STRING, &smode,
1870 return bus_send_error_reply(connection, message, &error, -EINVAL);
1873 u = manager_get_unit(m, old_name);
1874 if (!u || !u->job || u->job->type != JOB_START) {
1875 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1876 return bus_send_error_reply(connection, message, &error, -ENOENT);
1880 mode = job_mode_from_string(smode);
1882 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1883 return bus_send_error_reply(connection, message, &error, -EINVAL);
1886 r = manager_load_unit(m, name, NULL, &error, &u);
1888 return bus_send_error_reply(connection, message, &error, r);
1890 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1894 if (!bus_maybe_send_reply(connection, message, reply))
1897 return DBUS_HANDLER_RESULT_HANDLED;
1900 dbus_error_free(&error);
1902 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1905 const DBusObjectPathVTable bus_manager_vtable = {
1906 .message_function = bus_manager_message_handler