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"
38 #define BUS_MANAGER_INTERFACE_BEGIN \
39 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
41 #define BUS_MANAGER_INTERFACE_METHODS \
42 " <method name=\"GetUnit\">\n" \
43 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
44 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
46 " <method name=\"GetUnitByPID\">\n" \
47 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
48 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
50 " <method name=\"LoadUnit\">\n" \
51 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
52 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
54 " <method name=\"StartUnit\">\n" \
55 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
56 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
57 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
59 " <method name=\"StartUnitReplace\">\n" \
60 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
61 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
62 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
63 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
65 " <method name=\"StopUnit\">\n" \
66 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
70 " <method name=\"ReloadUnit\">\n" \
71 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
75 " <method name=\"RestartUnit\">\n" \
76 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
80 " <method name=\"TryRestartUnit\">\n" \
81 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
82 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
83 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
85 " <method name=\"ReloadOrRestartUnit\">\n" \
86 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
90 " <method name=\"ReloadOrTryRestartUnit\">\n" \
91 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
95 " <method name=\"KillUnit\">\n" \
96 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
97 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
98 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
100 " <method name=\"ResetFailedUnit\">\n" \
101 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
103 " <method name=\"GetJob\">\n" \
104 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
105 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
107 " <method name=\"ClearJobs\"/>\n" \
108 " <method name=\"ResetFailed\"/>\n" \
109 " <method name=\"ListUnits\">\n" \
110 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
112 " <method name=\"ListJobs\">\n" \
113 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
115 " <method name=\"Subscribe\"/>\n" \
116 " <method name=\"Unsubscribe\"/>\n" \
117 " <method name=\"Dump\">\n" \
118 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
120 " <method name=\"CreateSnapshot\">\n" \
121 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
122 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
123 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
125 " <method name=\"Reload\"/>\n" \
126 " <method name=\"Reexecute\"/>\n" \
127 " <method name=\"Exit\"/>\n" \
128 " <method name=\"Reboot\"/>\n" \
129 " <method name=\"PowerOff\"/>\n" \
130 " <method name=\"Halt\"/>\n" \
131 " <method name=\"KExec\"/>\n" \
132 " <method name=\"SwitchRoot\">\n" \
133 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
134 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
136 " <method name=\"SetEnvironment\">\n" \
137 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
139 " <method name=\"UnsetEnvironment\">\n" \
140 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
142 " <method name=\"UnsetAndSetEnvironment\">\n" \
143 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
144 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
146 " <method name=\"ListUnitFiles\">\n" \
147 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
149 " <method name=\"GetUnitFileState\">\n" \
150 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
151 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
153 " <method name=\"EnableUnitFiles\">\n" \
154 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
155 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
156 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
157 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
158 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
160 " <method name=\"DisableUnitFiles\">\n" \
161 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
162 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
163 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
165 " <method name=\"ReenableUnitFiles\">\n" \
166 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
167 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
168 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
169 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
170 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
172 " <method name=\"LinkUnitFiles\">\n" \
173 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
174 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
175 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
176 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
178 " <method name=\"PresetUnitFiles\">\n" \
179 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
180 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
181 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
182 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
183 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
185 " <method name=\"MaskUnitFiles\">\n" \
186 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
187 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
188 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
189 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
191 " <method name=\"UnmaskUnitFiles\">\n" \
192 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
193 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
194 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
197 #define BUS_MANAGER_INTERFACE_SIGNALS \
198 " <signal name=\"UnitNew\">\n" \
199 " <arg name=\"id\" type=\"s\"/>\n" \
200 " <arg name=\"unit\" type=\"o\"/>\n" \
202 " <signal name=\"UnitRemoved\">\n" \
203 " <arg name=\"id\" type=\"s\"/>\n" \
204 " <arg name=\"unit\" type=\"o\"/>\n" \
206 " <signal name=\"JobNew\">\n" \
207 " <arg name=\"id\" type=\"u\"/>\n" \
208 " <arg name=\"job\" type=\"o\"/>\n" \
209 " <arg name=\"unit\" type=\"s\"/>\n" \
211 " <signal name=\"JobRemoved\">\n" \
212 " <arg name=\"id\" type=\"u\"/>\n" \
213 " <arg name=\"job\" type=\"o\"/>\n" \
214 " <arg name=\"unit\" type=\"s\"/>\n" \
215 " <arg name=\"result\" type=\"s\"/>\n" \
217 " <signal name=\"StartupFinished\">\n" \
218 " <arg name=\"firmware\" type=\"t\"/>\n" \
219 " <arg name=\"loader\" type=\"t\"/>\n" \
220 " <arg name=\"kernel\" type=\"t\"/>\n" \
221 " <arg name=\"initrd\" type=\"t\"/>\n" \
222 " <arg name=\"userspace\" type=\"t\"/>\n" \
223 " <arg name=\"total\" type=\"t\"/>\n" \
225 " <signal name=\"UnitFilesChanged\"/>\n"
227 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
228 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
230 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
232 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
233 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
234 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
235 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
236 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
237 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
238 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
239 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
240 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
241 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
242 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
243 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
244 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
245 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
246 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
247 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
248 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
249 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
250 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
251 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
252 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
253 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
254 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
255 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
256 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
257 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
258 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
259 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
260 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n"
262 #define BUS_MANAGER_INTERFACE_END \
265 #define BUS_MANAGER_INTERFACE \
266 BUS_MANAGER_INTERFACE_BEGIN \
267 BUS_MANAGER_INTERFACE_METHODS \
268 BUS_MANAGER_INTERFACE_SIGNALS \
269 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
270 BUS_MANAGER_INTERFACE_END
272 #define INTROSPECTION_BEGIN \
273 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
275 BUS_MANAGER_INTERFACE \
276 BUS_PROPERTIES_INTERFACE \
278 BUS_INTROSPECTABLE_INTERFACE
280 #define INTROSPECTION_END \
283 #define INTERFACES_LIST \
284 BUS_GENERIC_INTERFACES_LIST \
285 "org.freedesktop.systemd1.Manager\0"
287 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
289 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
291 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
294 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
301 e = stpcpy(e, "split-usr:");
303 if (readlink_malloc("/etc/mtab", &p) < 0)
304 e = stpcpy(e, "mtab-not-symlink:");
308 if (access("/proc/cgroups", F_OK) < 0)
309 e = stpcpy(e, "cgroups-missing:");
311 if (hwclock_is_localtime() > 0)
312 e = stpcpy(e, "local-hwclock:");
314 /* remove the last ':' */
320 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
326 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
332 t = log_target_to_string(log_get_target());
334 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
340 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
346 dbus_message_iter_get_basic(i, &t);
348 return log_set_target_from_string(t);
351 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
357 t = log_level_to_string(log_get_max_level());
359 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
365 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
371 dbus_message_iter_get_basic(i, &t);
373 return log_set_max_level_from_string(t);
376 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
384 u = hashmap_size(m->units);
386 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
392 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
400 u = hashmap_size(m->jobs);
402 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
408 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
416 if (dual_timestamp_is_set(&m->finish_timestamp))
419 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
421 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
427 static const char *message_get_sender_with_fallback(DBusMessage *m) {
432 if ((s = dbus_message_get_sender(m)))
435 /* When the message came in from a direct connection the
436 * message will have no sender. We fix that here. */
441 static DBusMessage *message_from_file_changes(
443 UnitFileChange *changes,
445 int carries_install_info) {
447 DBusMessageIter iter, sub, sub2;
451 reply = dbus_message_new_method_return(m);
455 dbus_message_iter_init_append(reply, &iter);
457 if (carries_install_info >= 0) {
460 b = !!carries_install_info;
461 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
465 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
468 for (i = 0; i < n_changes; i++) {
469 const char *type, *path, *source;
471 type = unit_file_change_type_to_string(changes[i].type);
472 path = strempty(changes[i].path);
473 source = strempty(changes[i].source);
475 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
477 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
478 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
479 !dbus_message_iter_close_container(&sub, &sub2))
483 if (!dbus_message_iter_close_container(&iter, &sub))
489 dbus_message_unref(reply);
493 static int bus_manager_send_unit_files_changed(Manager *m) {
497 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
501 r = bus_broadcast(m, s);
502 dbus_message_unref(s);
507 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
513 dbus_message_iter_get_basic(i, t);
515 return watchdog_set_timeout(t);
518 static const char systemd_property_string[] =
523 static const BusProperty bus_systemd_properties[] = {
524 { "Version", bus_property_append_string, "s", 0 },
525 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
526 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
530 static const BusProperty bus_manager_properties[] = {
531 { "Tainted", bus_manager_append_tainted, "s", 0 },
532 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
533 { "FirmwareTimestampMonotonic", bus_property_append_uint64,"t", offsetof(Manager, firmware_timestamp.monotonic)},
534 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
535 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
536 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
537 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
538 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
539 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
540 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime)},
541 { "UserspaceTimestampMonotonic", bus_property_append_uint64,"t",offsetof(Manager, userspace_timestamp.monotonic)},
542 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
543 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
544 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
545 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
546 { "NNames", bus_manager_append_n_names, "u", 0 },
547 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
548 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
549 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
550 { "Progress", bus_manager_append_progress, "d", 0 },
551 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
552 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
553 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
554 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
555 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
556 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
557 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
558 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
559 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
560 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
564 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
569 DBusMessage *reply = NULL;
571 JobType job_type = _JOB_TYPE_INVALID;
572 bool reload_if_possible = false;
579 dbus_error_init(&error);
581 member = dbus_message_get_member(message);
582 r = selinux_manager_access_check(connection, message, m, &error);
584 return bus_send_error_reply(connection, message, &error, r);
586 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
590 if (!dbus_message_get_args(
593 DBUS_TYPE_STRING, &name,
595 return bus_send_error_reply(connection, message, &error, -EINVAL);
597 if (!(u = manager_get_unit(m, name))) {
598 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
599 return bus_send_error_reply(connection, message, &error, -ENOENT);
602 if (!(reply = dbus_message_new_method_return(message)))
605 if (!(path = unit_dbus_path(u)))
608 if (!dbus_message_append_args(
610 DBUS_TYPE_OBJECT_PATH, &path,
613 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
617 if (!dbus_message_get_args(
620 DBUS_TYPE_UINT32, &pid,
622 return bus_send_error_reply(connection, message, &error, -EINVAL);
624 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
625 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
626 return bus_send_error_reply(connection, message, &error, -ENOENT);
629 if (!(reply = dbus_message_new_method_return(message)))
632 if (!(path = unit_dbus_path(u)))
635 if (!dbus_message_append_args(
637 DBUS_TYPE_OBJECT_PATH, &path,
640 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
644 if (!dbus_message_get_args(
647 DBUS_TYPE_STRING, &name,
649 return bus_send_error_reply(connection, message, &error, -EINVAL);
651 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
652 return bus_send_error_reply(connection, message, &error, r);
654 if (!(reply = dbus_message_new_method_return(message)))
657 if (!(path = unit_dbus_path(u)))
660 if (!dbus_message_append_args(
662 DBUS_TYPE_OBJECT_PATH, &path,
666 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
667 job_type = JOB_START;
668 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
669 job_type = JOB_START;
670 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
672 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
673 job_type = JOB_RELOAD;
674 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
675 job_type = JOB_RESTART;
676 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
677 job_type = JOB_TRY_RESTART;
678 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
679 reload_if_possible = true;
680 job_type = JOB_RESTART;
681 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
682 reload_if_possible = true;
683 job_type = JOB_TRY_RESTART;
684 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
685 const char *name, *swho;
690 if (!dbus_message_get_args(
693 DBUS_TYPE_STRING, &name,
694 DBUS_TYPE_STRING, &swho,
695 DBUS_TYPE_INT32, &signo,
697 return bus_send_error_reply(connection, message, &error, -EINVAL);
702 who = kill_who_from_string(swho);
704 return bus_send_error_reply(connection, message, &error, -EINVAL);
707 if (signo <= 0 || signo >= _NSIG)
708 return bus_send_error_reply(connection, message, &error, -EINVAL);
710 u = manager_get_unit(m, name);
712 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
713 return bus_send_error_reply(connection, message, &error, -ENOENT);
716 r = unit_kill(u, who, signo, &error);
718 return bus_send_error_reply(connection, message, &error, r);
720 if (!(reply = dbus_message_new_method_return(message)))
723 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
727 if (!dbus_message_get_args(
730 DBUS_TYPE_UINT32, &id,
732 return bus_send_error_reply(connection, message, &error, -EINVAL);
734 if (!(j = manager_get_job(m, id))) {
735 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
736 return bus_send_error_reply(connection, message, &error, -ENOENT);
739 if (!(reply = dbus_message_new_method_return(message)))
742 if (!(path = job_dbus_path(j)))
745 if (!dbus_message_append_args(
747 DBUS_TYPE_OBJECT_PATH, &path,
751 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
753 manager_clear_jobs(m);
755 if (!(reply = dbus_message_new_method_return(message)))
758 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
760 manager_reset_failed(m);
762 if (!(reply = dbus_message_new_method_return(message)))
765 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
769 if (!dbus_message_get_args(
772 DBUS_TYPE_STRING, &name,
774 return bus_send_error_reply(connection, message, &error, -EINVAL);
776 if (!(u = manager_get_unit(m, name))) {
777 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
778 return bus_send_error_reply(connection, message, &error, -ENOENT);
781 unit_reset_failed(u);
783 if (!(reply = dbus_message_new_method_return(message)))
786 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
787 DBusMessageIter iter, sub;
792 if (!(reply = dbus_message_new_method_return(message)))
795 dbus_message_iter_init_append(reply, &iter);
797 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
800 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
801 char *u_path, *j_path;
802 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
803 DBusMessageIter sub2;
810 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
813 description = unit_description(u);
814 load_state = unit_load_state_to_string(u->load_state);
815 active_state = unit_active_state_to_string(unit_active_state(u));
816 sub_state = unit_sub_state_to_string(u);
818 f = unit_following(u);
819 following = f ? f->id : "";
821 if (!(u_path = unit_dbus_path(u)))
825 job_id = (uint32_t) u->job->id;
827 if (!(j_path = job_dbus_path(u->job))) {
832 sjob_type = job_type_to_string(u->job->type);
839 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
840 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
841 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
842 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
843 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
844 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
845 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
846 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
847 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
848 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
859 if (!dbus_message_iter_close_container(&sub, &sub2))
863 if (!dbus_message_iter_close_container(&iter, &sub))
866 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
867 DBusMessageIter iter, sub;
871 if (!(reply = dbus_message_new_method_return(message)))
874 dbus_message_iter_init_append(reply, &iter);
876 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
879 HASHMAP_FOREACH(j, m->jobs, i) {
880 char *u_path, *j_path;
881 const char *state, *type;
883 DBusMessageIter sub2;
885 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
888 id = (uint32_t) j->id;
889 state = job_state_to_string(j->state);
890 type = job_type_to_string(j->type);
892 if (!(j_path = job_dbus_path(j)))
895 if (!(u_path = unit_dbus_path(j->unit))) {
900 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
901 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
902 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
903 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
904 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
905 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
914 if (!dbus_message_iter_close_container(&sub, &sub2))
918 if (!dbus_message_iter_close_container(&iter, &sub))
921 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
925 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
926 if (!(s = set_new(string_hash_func, string_compare_func)))
929 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
935 if (!(client = strdup(message_get_sender_with_fallback(message))))
938 if ((r = set_put(s, client)) < 0) {
940 return bus_send_error_reply(connection, message, NULL, r);
943 if (!(reply = dbus_message_new_method_return(message)))
946 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
949 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
950 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
951 return bus_send_error_reply(connection, message, &error, -ENOENT);
956 if (!(reply = dbus_message_new_method_return(message)))
959 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
964 if (!(reply = dbus_message_new_method_return(message)))
967 if (!(f = open_memstream(&dump, &size)))
970 manager_dump_units(m, f, NULL);
971 manager_dump_jobs(m, f, NULL);
981 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
987 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
992 if (!dbus_message_get_args(
995 DBUS_TYPE_STRING, &name,
996 DBUS_TYPE_BOOLEAN, &cleanup,
998 return bus_send_error_reply(connection, message, &error, -EINVAL);
1000 if (name && name[0] == 0)
1003 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1004 return bus_send_error_reply(connection, message, &error, r);
1006 if (!(reply = dbus_message_new_method_return(message)))
1009 if (!(path = unit_dbus_path(UNIT(s))))
1012 if (!dbus_message_append_args(
1014 DBUS_TYPE_OBJECT_PATH, &path,
1018 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1019 char *introspection = NULL;
1027 if (!(reply = dbus_message_new_method_return(message)))
1030 /* We roll our own introspection code here, instead of
1031 * relying on bus_default_message_handler() because we
1032 * need to generate our introspection string
1035 if (!(f = open_memstream(&introspection, &size)))
1038 fputs(INTROSPECTION_BEGIN, f);
1040 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1046 if (!(p = bus_path_escape(k))) {
1048 free(introspection);
1052 fprintf(f, "<node name=\"unit/%s\"/>", p);
1056 HASHMAP_FOREACH(j, m->jobs, i)
1057 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1059 fputs(INTROSPECTION_END, f);
1063 free(introspection);
1072 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1073 free(introspection);
1077 free(introspection);
1079 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1081 assert(!m->queued_message);
1083 /* Instead of sending the reply back right away, we
1084 * just remember that we need to and then send it
1085 * after the reload is finished. That way the caller
1086 * knows when the reload finished. */
1088 if (!(m->queued_message = dbus_message_new_method_return(message)))
1091 m->queued_message_connection = connection;
1092 m->exit_code = MANAGER_RELOAD;
1094 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1096 /* We don't send a reply back here, the client should
1097 * just wait for us disconnecting. */
1099 m->exit_code = MANAGER_REEXECUTE;
1101 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1103 if (m->running_as == SYSTEMD_SYSTEM) {
1104 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1105 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1108 if (!(reply = dbus_message_new_method_return(message)))
1111 m->exit_code = MANAGER_EXIT;
1113 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1115 if (m->running_as != SYSTEMD_SYSTEM) {
1116 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1117 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1120 if (!(reply = dbus_message_new_method_return(message)))
1123 m->exit_code = MANAGER_REBOOT;
1125 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1127 if (m->running_as != SYSTEMD_SYSTEM) {
1128 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1129 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1132 if (!(reply = dbus_message_new_method_return(message)))
1135 m->exit_code = MANAGER_POWEROFF;
1137 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1139 if (m->running_as != SYSTEMD_SYSTEM) {
1140 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1141 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1144 if (!(reply = dbus_message_new_method_return(message)))
1147 m->exit_code = MANAGER_HALT;
1149 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1151 if (m->running_as != SYSTEMD_SYSTEM) {
1152 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1153 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1156 if (!(reply = dbus_message_new_method_return(message)))
1159 m->exit_code = MANAGER_KEXEC;
1161 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1162 const char *switch_root, *switch_root_init;
1166 if (!dbus_message_get_args(
1169 DBUS_TYPE_STRING, &switch_root,
1170 DBUS_TYPE_STRING, &switch_root_init,
1172 return bus_send_error_reply(connection, message, &error, -EINVAL);
1174 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1175 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1177 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1178 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1180 if (m->running_as != SYSTEMD_SYSTEM) {
1181 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1182 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1186 if (isempty(switch_root_init))
1187 k = access(switch_root, F_OK);
1191 p = strjoin(switch_root, "/", switch_root_init, NULL);
1195 k = access(p, X_OK);
1199 return bus_send_error_reply(connection, message, NULL, -errno);
1201 u = strdup(switch_root);
1205 if (!isempty(switch_root_init)) {
1206 v = strdup(switch_root_init);
1214 free(m->switch_root);
1215 free(m->switch_root_init);
1217 m->switch_root_init = v;
1219 reply = dbus_message_new_method_return(message);
1223 m->exit_code = MANAGER_SWITCH_ROOT;
1225 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1226 char **l = NULL, **e = NULL;
1228 if ((r = bus_parse_strv(message, &l)) < 0) {
1232 return bus_send_error_reply(connection, message, NULL, r);
1235 e = strv_env_merge(2, m->environment, l);
1241 if (!(reply = dbus_message_new_method_return(message))) {
1246 strv_free(m->environment);
1249 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1250 char **l = NULL, **e = NULL;
1252 if ((r = bus_parse_strv(message, &l)) < 0) {
1256 return bus_send_error_reply(connection, message, NULL, r);
1259 e = strv_env_delete(m->environment, 1, l);
1265 if (!(reply = dbus_message_new_method_return(message))) {
1270 strv_free(m->environment);
1273 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1274 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1275 DBusMessageIter iter;
1277 if (!dbus_message_iter_init(message, &iter))
1280 r = bus_parse_strv_iter(&iter, &l_unset);
1285 return bus_send_error_reply(connection, message, NULL, r);
1288 if (!dbus_message_iter_next(&iter)) {
1290 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1293 r = bus_parse_strv_iter(&iter, &l_set);
1299 return bus_send_error_reply(connection, message, NULL, r);
1302 e = strv_env_delete(m->environment, 1, l_unset);
1310 f = strv_env_merge(2, e, l_set);
1317 if (!(reply = dbus_message_new_method_return(message))) {
1322 strv_free(m->environment);
1324 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1325 DBusMessageIter iter, sub, sub2;
1330 reply = dbus_message_new_method_return(message);
1334 h = hashmap_new(string_hash_func, string_compare_func);
1338 r = unit_file_get_list(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1340 unit_file_list_free(h);
1341 dbus_message_unref(reply);
1342 return bus_send_error_reply(connection, message, NULL, r);
1345 dbus_message_iter_init_append(reply, &iter);
1347 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1348 unit_file_list_free(h);
1352 HASHMAP_FOREACH(item, h, i) {
1355 state = unit_file_state_to_string(item->state);
1358 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1359 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1360 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1361 !dbus_message_iter_close_container(&sub, &sub2)) {
1362 unit_file_list_free(h);
1367 unit_file_list_free(h);
1369 if (!dbus_message_iter_close_container(&iter, &sub))
1372 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1374 UnitFileState state;
1377 if (!dbus_message_get_args(
1380 DBUS_TYPE_STRING, &name,
1382 return bus_send_error_reply(connection, message, &error, -EINVAL);
1384 state = unit_file_get_state(m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1386 return bus_send_error_reply(connection, message, NULL, state);
1388 s = unit_file_state_to_string(state);
1391 reply = dbus_message_new_method_return(message);
1395 if (!dbus_message_append_args(
1397 DBUS_TYPE_STRING, &s,
1400 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1401 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1402 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1403 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1404 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1407 DBusMessageIter iter;
1408 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1409 UnitFileChange *changes = NULL;
1410 unsigned n_changes = 0;
1411 dbus_bool_t runtime, force;
1412 int carries_install_info = -1;
1414 if (!dbus_message_iter_init(message, &iter))
1417 r = bus_parse_strv_iter(&iter, &l);
1422 return bus_send_error_reply(connection, message, NULL, r);
1425 if (!dbus_message_iter_next(&iter) ||
1426 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1427 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1429 return bus_send_error_reply(connection, message, NULL, -EIO);
1432 if (streq(member, "EnableUnitFiles")) {
1433 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1434 carries_install_info = r;
1435 } else if (streq(member, "ReenableUnitFiles")) {
1436 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1437 carries_install_info = r;
1438 } else if (streq(member, "LinkUnitFiles"))
1439 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1440 else if (streq(member, "PresetUnitFiles")) {
1441 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1442 carries_install_info = r;
1443 } else if (streq(member, "MaskUnitFiles"))
1444 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1446 assert_not_reached("Uh? Wrong method");
1449 bus_manager_send_unit_files_changed(m);
1452 unit_file_changes_free(changes, n_changes);
1453 return bus_send_error_reply(connection, message, NULL, r);
1456 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1457 unit_file_changes_free(changes, n_changes);
1462 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1463 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1466 DBusMessageIter iter;
1467 UnitFileScope scope = m->running_as == SYSTEMD_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1468 UnitFileChange *changes = NULL;
1469 unsigned n_changes = 0;
1470 dbus_bool_t runtime;
1472 if (!dbus_message_iter_init(message, &iter))
1475 r = bus_parse_strv_iter(&iter, &l);
1480 return bus_send_error_reply(connection, message, NULL, r);
1483 if (!dbus_message_iter_next(&iter) ||
1484 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1486 return bus_send_error_reply(connection, message, NULL, -EIO);
1489 if (streq(member, "DisableUnitFiles"))
1490 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1491 else if (streq(member, "UnmaskUnitFiles"))
1492 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1494 assert_not_reached("Uh? Wrong method");
1497 bus_manager_send_unit_files_changed(m);
1500 unit_file_changes_free(changes, n_changes);
1501 return bus_send_error_reply(connection, message, NULL, r);
1504 reply = message_from_file_changes(message, changes, n_changes, -1);
1505 unit_file_changes_free(changes, n_changes);
1511 const BusBoundProperties bps[] = {
1512 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1513 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1516 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1519 if (job_type != _JOB_TYPE_INVALID) {
1520 const char *name, *smode, *old_name = NULL;
1527 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1528 b = dbus_message_get_args(
1531 DBUS_TYPE_STRING, &old_name,
1532 DBUS_TYPE_STRING, &name,
1533 DBUS_TYPE_STRING, &smode,
1536 b = dbus_message_get_args(
1539 DBUS_TYPE_STRING, &name,
1540 DBUS_TYPE_STRING, &smode,
1544 return bus_send_error_reply(connection, message, &error, -EINVAL);
1547 if (!(u = manager_get_unit(m, old_name)) ||
1549 u->job->type != JOB_START) {
1550 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1551 return bus_send_error_reply(connection, message, &error, -ENOENT);
1555 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1556 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1557 return bus_send_error_reply(connection, message, &error, -EINVAL);
1560 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1561 return bus_send_error_reply(connection, message, &error, r);
1563 if (reload_if_possible && unit_can_reload(u)) {
1564 if (job_type == JOB_RESTART)
1565 job_type = JOB_RELOAD_OR_START;
1566 else if (job_type == JOB_TRY_RESTART)
1567 job_type = JOB_RELOAD;
1570 if (job_type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) {
1571 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
1572 return bus_send_error_reply(connection, message, &error, -EPERM);
1575 if ((job_type == JOB_START && u->refuse_manual_start) ||
1576 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1577 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1578 (u->refuse_manual_start || u->refuse_manual_stop))) {
1579 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1580 return bus_send_error_reply(connection, message, &error, -EPERM);
1583 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1584 return bus_send_error_reply(connection, message, &error, r);
1586 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1590 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1592 if (!(reply = dbus_message_new_method_return(message)))
1595 if (!(path = job_dbus_path(j)))
1598 if (!dbus_message_append_args(
1600 DBUS_TYPE_OBJECT_PATH, &path,
1606 if (!dbus_connection_send(connection, reply, NULL))
1609 dbus_message_unref(reply);
1614 return DBUS_HANDLER_RESULT_HANDLED;
1620 dbus_message_unref(reply);
1622 dbus_error_free(&error);
1624 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1627 const DBusObjectPathVTable bus_manager_vtable = {
1628 .message_function = bus_manager_message_handler