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_acquire_subscribed(m, connection);
1064 client = strdup(bus_message_get_sender_with_fallback(message));
1068 r = set_consume(s, client);
1070 return bus_send_error_reply(connection, message, NULL, r);
1072 reply = dbus_message_new_method_return(message);
1076 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
1079 SELINUX_ACCESS_CHECK(connection, message, "status");
1081 client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) bus_message_get_sender_with_fallback(message));
1083 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
1084 return bus_send_error_reply(connection, message, &error, -ENOENT);
1089 reply = dbus_message_new_method_return(message);
1093 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
1098 SELINUX_ACCESS_CHECK(connection, message, "status");
1100 reply = dbus_message_new_method_return(message);
1104 f = open_memstream(&dump, &size);
1108 manager_dump_units(m, f, NULL);
1109 manager_dump_jobs(m, f, NULL);
1119 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1125 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1127 dbus_bool_t cleanup;
1130 SELINUX_ACCESS_CHECK(connection, message, "start");
1132 if (!dbus_message_get_args(
1135 DBUS_TYPE_STRING, &name,
1136 DBUS_TYPE_BOOLEAN, &cleanup,
1138 return bus_send_error_reply(connection, message, &error, -EINVAL);
1143 r = snapshot_create(m, name, cleanup, &error, &s);
1145 return bus_send_error_reply(connection, message, &error, r);
1147 reply = dbus_message_new_method_return(message);
1151 path = unit_dbus_path(UNIT(s));
1155 if (!dbus_message_append_args(
1157 DBUS_TYPE_OBJECT_PATH, &path,
1161 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RemoveSnapshot")) {
1165 if (!dbus_message_get_args(
1168 DBUS_TYPE_STRING, &name,
1170 return bus_send_error_reply(connection, message, &error, -EINVAL);
1172 u = manager_get_unit(m, name);
1174 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s does not exist.", name);
1175 return bus_send_error_reply(connection, message, &error, -ENOENT);
1178 if (u->type != UNIT_SNAPSHOT) {
1179 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not a snapshot.", name);
1180 return bus_send_error_reply(connection, message, &error, -ENOENT);
1183 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "stop");
1184 snapshot_remove(SNAPSHOT(u));
1186 reply = dbus_message_new_method_return(message);
1190 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1191 char *introspection = NULL;
1199 SELINUX_ACCESS_CHECK(connection, message, "status");
1201 reply = dbus_message_new_method_return(message);
1205 /* We roll our own introspection code here, instead of
1206 * relying on bus_default_message_handler() because we
1207 * need to generate our introspection string
1210 f = open_memstream(&introspection, &size);
1214 fputs(INTROSPECTION_BEGIN, f);
1216 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1222 p = bus_path_escape(k);
1225 free(introspection);
1229 fprintf(f, "<node name=\"unit/%s\"/>", p);
1233 HASHMAP_FOREACH(j, m->jobs, i)
1234 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1236 fputs(INTROSPECTION_END, f);
1240 free(introspection);
1249 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1250 free(introspection);
1254 free(introspection);
1256 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1258 SELINUX_ACCESS_CHECK(connection, message, "reload");
1260 assert(!m->queued_message);
1262 /* Instead of sending the reply back right away, we
1263 * just remember that we need to and then send it
1264 * after the reload is finished. That way the caller
1265 * knows when the reload finished. */
1267 m->queued_message = dbus_message_new_method_return(message);
1268 if (!m->queued_message)
1271 m->queued_message_connection = connection;
1272 m->exit_code = MANAGER_RELOAD;
1274 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1276 SELINUX_ACCESS_CHECK(connection, message, "reload");
1278 /* We don't send a reply back here, the client should
1279 * just wait for us disconnecting. */
1281 m->exit_code = MANAGER_REEXECUTE;
1283 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1285 SELINUX_ACCESS_CHECK(connection, message, "halt");
1287 if (m->running_as == SYSTEMD_SYSTEM) {
1288 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1289 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1292 reply = dbus_message_new_method_return(message);
1296 m->exit_code = MANAGER_EXIT;
1298 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1300 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1302 if (m->running_as != SYSTEMD_SYSTEM) {
1303 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1304 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1307 reply = dbus_message_new_method_return(message);
1311 m->exit_code = MANAGER_REBOOT;
1313 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1315 SELINUX_ACCESS_CHECK(connection, message, "halt");
1317 if (m->running_as != SYSTEMD_SYSTEM) {
1318 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1319 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1322 reply = dbus_message_new_method_return(message);
1326 m->exit_code = MANAGER_POWEROFF;
1328 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1330 SELINUX_ACCESS_CHECK(connection, message, "halt");
1332 if (m->running_as != SYSTEMD_SYSTEM) {
1333 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1334 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1337 reply = dbus_message_new_method_return(message);
1341 m->exit_code = MANAGER_HALT;
1343 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1345 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1347 if (m->running_as != SYSTEMD_SYSTEM) {
1348 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1349 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1352 reply = dbus_message_new_method_return(message);
1356 m->exit_code = MANAGER_KEXEC;
1358 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1359 const char *switch_root, *switch_root_init;
1363 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1365 if (!dbus_message_get_args(
1368 DBUS_TYPE_STRING, &switch_root,
1369 DBUS_TYPE_STRING, &switch_root_init,
1371 return bus_send_error_reply(connection, message, &error, -EINVAL);
1373 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1374 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1376 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1377 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1379 if (m->running_as != SYSTEMD_SYSTEM) {
1380 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1381 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1385 if (isempty(switch_root_init)) {
1386 good = path_is_os_tree(switch_root);
1388 log_error("Not switching root: %s does not seem to be an OS tree. /etc/os-release is missing.", switch_root);
1391 _cleanup_free_ char *p = NULL;
1393 p = strjoin(switch_root, "/", switch_root_init, NULL);
1397 good = access(p, X_OK) >= 0;
1399 log_error("Not switching root: cannot execute new init %s", p);
1402 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1404 u = strdup(switch_root);
1408 if (!isempty(switch_root_init)) {
1409 v = strdup(switch_root_init);
1417 free(m->switch_root);
1418 free(m->switch_root_init);
1420 m->switch_root_init = v;
1422 reply = dbus_message_new_method_return(message);
1426 m->exit_code = MANAGER_SWITCH_ROOT;
1428 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1429 _cleanup_strv_free_ char **l = NULL;
1432 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1434 r = bus_parse_strv(message, &l);
1438 return bus_send_error_reply(connection, message, NULL, r);
1439 if (!strv_env_is_valid(l))
1440 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1442 e = strv_env_merge(2, m->environment, l);
1446 reply = dbus_message_new_method_return(message);
1452 strv_free(m->environment);
1455 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1456 _cleanup_strv_free_ char **l = NULL;
1459 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1461 r = bus_parse_strv(message, &l);
1465 return bus_send_error_reply(connection, message, NULL, r);
1466 if (!strv_env_name_or_assignment_is_valid(l))
1467 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1469 e = strv_env_delete(m->environment, 1, l);
1473 reply = dbus_message_new_method_return(message);
1479 strv_free(m->environment);
1482 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1483 _cleanup_strv_free_ char **l_set = NULL, **l_unset = NULL, **e = NULL;
1485 DBusMessageIter iter;
1487 SELINUX_ACCESS_CHECK(connection, message, "reboot");
1489 if (!dbus_message_iter_init(message, &iter))
1492 r = bus_parse_strv_iter(&iter, &l_unset);
1496 return bus_send_error_reply(connection, message, NULL, r);
1497 if (!strv_env_name_or_assignment_is_valid(l_unset))
1498 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1500 if (!dbus_message_iter_next(&iter))
1501 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1503 r = bus_parse_strv_iter(&iter, &l_set);
1507 return bus_send_error_reply(connection, message, NULL, r);
1508 if (!strv_env_is_valid(l_set))
1509 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1511 e = strv_env_delete(m->environment, 1, l_unset);
1515 f = strv_env_merge(2, e, l_set);
1519 reply = dbus_message_new_method_return(message);
1525 strv_free(m->environment);
1527 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1528 DBusMessageIter iter, sub, sub2;
1533 SELINUX_ACCESS_CHECK(connection, message, "status");
1535 reply = dbus_message_new_method_return(message);
1539 h = hashmap_new(string_hash_func, string_compare_func);
1543 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1545 unit_file_list_free(h);
1546 return bus_send_error_reply(connection, message, NULL, r);
1549 dbus_message_iter_init_append(reply, &iter);
1551 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1552 unit_file_list_free(h);
1556 HASHMAP_FOREACH(item, h, i) {
1559 state = unit_file_state_to_string(item->state);
1562 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1563 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1564 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1565 !dbus_message_iter_close_container(&sub, &sub2)) {
1566 unit_file_list_free(h);
1571 unit_file_list_free(h);
1573 if (!dbus_message_iter_close_container(&iter, &sub))
1576 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1578 UnitFileState state;
1581 SELINUX_ACCESS_CHECK(connection, message, "status");
1583 if (!dbus_message_get_args(
1586 DBUS_TYPE_STRING, &name,
1588 return bus_send_error_reply(connection, message, &error, -EINVAL);
1590 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1592 return bus_send_error_reply(connection, message, NULL, state);
1594 s = unit_file_state_to_string(state);
1597 reply = dbus_message_new_method_return(message);
1601 if (!dbus_message_append_args(
1603 DBUS_TYPE_STRING, &s,
1606 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1607 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1608 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1609 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1610 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles") ||
1611 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetDefaultTarget")) {
1614 DBusMessageIter iter;
1615 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1616 UnitFileChange *changes = NULL;
1617 unsigned n_changes = 0;
1618 dbus_bool_t runtime, force;
1619 int carries_install_info = -1;
1621 SELINUX_ACCESS_CHECK(connection, message, streq(member, "MaskUnitFiles") ? "disable" : "enable");
1623 if (!dbus_message_iter_init(message, &iter))
1626 r = bus_parse_strv_iter(&iter, &l);
1631 return bus_send_error_reply(connection, message, NULL, r);
1634 if (!dbus_message_iter_next(&iter) ||
1635 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1636 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1638 return bus_send_error_reply(connection, message, NULL, -EIO);
1641 if (streq(member, "EnableUnitFiles")) {
1642 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1643 carries_install_info = r;
1644 } else if (streq(member, "ReenableUnitFiles")) {
1645 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1646 carries_install_info = r;
1647 } else if (streq(member, "LinkUnitFiles"))
1648 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1649 else if (streq(member, "PresetUnitFiles")) {
1650 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1651 carries_install_info = r;
1652 } else if (streq(member, "MaskUnitFiles"))
1653 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1654 else if (streq(member, "SetDefaultTarget"))
1655 r = unit_file_set_default(scope, NULL, l[0], &changes, &n_changes);
1657 assert_not_reached("Uh? Wrong method");
1660 bus_manager_send_unit_files_changed(m);
1663 unit_file_changes_free(changes, n_changes);
1664 return bus_send_error_reply(connection, message, NULL, r);
1667 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1668 unit_file_changes_free(changes, n_changes);
1673 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1674 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1677 DBusMessageIter iter;
1678 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1679 UnitFileChange *changes = NULL;
1680 unsigned n_changes = 0;
1681 dbus_bool_t runtime;
1683 SELINUX_ACCESS_CHECK(connection, message, streq(member, "UnmaskUnitFiles") ? "enable" : "disable");
1685 if (!dbus_message_iter_init(message, &iter))
1688 r = bus_parse_strv_iter(&iter, &l);
1693 return bus_send_error_reply(connection, message, NULL, r);
1696 if (!dbus_message_iter_next(&iter) ||
1697 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1699 return bus_send_error_reply(connection, message, NULL, -EIO);
1702 if (streq(member, "DisableUnitFiles"))
1703 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1704 else if (streq(member, "UnmaskUnitFiles"))
1705 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1707 assert_not_reached("Uh? Wrong method");
1710 bus_manager_send_unit_files_changed(m);
1713 unit_file_changes_free(changes, n_changes);
1714 return bus_send_error_reply(connection, message, NULL, r);
1717 reply = message_from_file_changes(message, changes, n_changes, -1);
1718 unit_file_changes_free(changes, n_changes);
1723 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetDefaultTarget")) {
1724 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1725 _cleanup_free_ char *default_target = NULL;
1727 reply = dbus_message_new_method_return(message);
1731 r = unit_file_get_default(scope, NULL, &default_target);
1733 return bus_send_error_reply(connection, message, NULL, r);
1735 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &default_target, DBUS_TYPE_INVALID)) {
1739 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetUnitProperties")) {
1740 DBusMessageIter iter;
1741 dbus_bool_t runtime;
1745 if (!dbus_message_iter_init(message, &iter))
1748 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1749 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0)
1750 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1752 u = manager_get_unit(m, name);
1754 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
1755 return bus_send_error_reply(connection, message, &error, -ENOENT);
1758 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1760 r = bus_unit_set_properties(u, &iter, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, &error);
1762 return bus_send_error_reply(connection, message, &error, r);
1764 reply = dbus_message_new_method_return(message);
1768 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartTransientUnit")) {
1769 const char *name, *smode;
1770 DBusMessageIter iter;
1775 if (!dbus_message_iter_init(message, &iter))
1778 if (bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &name, true) < 0 ||
1779 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_STRING, &smode, true) < 0)
1780 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1782 t = unit_name_to_type(name);
1784 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1785 if (!unit_vtable[t]->can_transient) {
1786 dbus_set_error(&error, DBUS_ERROR_INVALID_ARGS, "Unit type %s does not support transient units.", unit_type_to_string(t));
1787 return bus_send_error_reply(connection, message, &error, -EINVAL);
1790 mode = job_mode_from_string(smode);
1792 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1793 return bus_send_error_reply(connection, message, &error, -EINVAL);
1796 r = manager_load_unit(m, name, NULL, NULL, &u);
1798 return bus_send_error_reply(connection, message, &error, r);
1800 SELINUX_UNIT_ACCESS_CHECK(u, connection, message, "start");
1802 if (u->load_state != UNIT_NOT_FOUND || set_size(u->dependencies[UNIT_REFERENCED_BY]) > 0) {
1803 dbus_set_error(&error, BUS_ERROR_UNIT_EXISTS, "Unit %s already exists.", name);
1804 return bus_send_error_reply(connection, message, &error, -EEXIST);
1807 /* OK, the unit failed to load and is unreferenced,
1808 * now let's fill in the transient data instead */
1809 r = unit_make_transient(u);
1811 return bus_send_error_reply(connection, message, &error, r);
1813 /* Set our properties */
1814 r = bus_unit_set_properties(u, &iter, UNIT_RUNTIME, false, &error);
1816 return bus_send_error_reply(connection, message, &error, r);
1818 /* And load this stub fully */
1821 return bus_send_error_reply(connection, message, &error, r);
1823 manager_dispatch_load_queue(m);
1825 /* Finally, start it */
1826 return bus_unit_queue_job(connection, message, u, JOB_START, mode, false);
1829 const BusBoundProperties bps[] = {
1830 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1831 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1835 SELINUX_ACCESS_CHECK(connection, message, "status");
1837 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1840 if (job_type != _JOB_TYPE_INVALID) {
1841 const char *name, *smode, *old_name = NULL;
1846 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1847 b = dbus_message_get_args(
1850 DBUS_TYPE_STRING, &old_name,
1851 DBUS_TYPE_STRING, &name,
1852 DBUS_TYPE_STRING, &smode,
1855 b = dbus_message_get_args(
1858 DBUS_TYPE_STRING, &name,
1859 DBUS_TYPE_STRING, &smode,
1862 return bus_send_error_reply(connection, message, &error, -EINVAL);
1865 u = manager_get_unit(m, old_name);
1866 if (!u || !u->job || u->job->type != JOB_START) {
1867 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1868 return bus_send_error_reply(connection, message, &error, -ENOENT);
1872 mode = job_mode_from_string(smode);
1874 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1875 return bus_send_error_reply(connection, message, &error, -EINVAL);
1878 r = manager_load_unit(m, name, NULL, &error, &u);
1880 return bus_send_error_reply(connection, message, &error, r);
1882 return bus_unit_queue_job(connection, message, u, job_type, mode, reload_if_possible);
1886 if (!bus_maybe_send_reply(connection, message, reply))
1889 return DBUS_HANDLER_RESULT_HANDLED;
1892 dbus_error_free(&error);
1894 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1897 const DBusObjectPathVTable bus_manager_vtable = {
1898 .message_function = bus_manager_message_handler