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"
35 #include "path-util.h"
37 #define BUS_MANAGER_INTERFACE_BEGIN \
38 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
40 #define BUS_MANAGER_INTERFACE_METHODS \
41 " <method name=\"GetUnit\">\n" \
42 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
43 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
45 " <method name=\"GetUnitByPID\">\n" \
46 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
47 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
49 " <method name=\"LoadUnit\">\n" \
50 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
51 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
53 " <method name=\"StartUnit\">\n" \
54 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
56 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
58 " <method name=\"StartUnitReplace\">\n" \
59 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
61 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
62 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
64 " <method name=\"StopUnit\">\n" \
65 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
67 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
69 " <method name=\"ReloadUnit\">\n" \
70 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
72 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
74 " <method name=\"RestartUnit\">\n" \
75 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
77 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
79 " <method name=\"TryRestartUnit\">\n" \
80 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
82 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
84 " <method name=\"ReloadOrRestartUnit\">\n" \
85 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
86 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
87 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
89 " <method name=\"ReloadOrTryRestartUnit\">\n" \
90 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
92 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
94 " <method name=\"KillUnit\">\n" \
95 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
97 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
99 " <method name=\"ResetFailedUnit\">\n" \
100 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
102 " <method name=\"GetJob\">\n" \
103 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
104 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
106 " <method name=\"ClearJobs\"/>\n" \
107 " <method name=\"ResetFailed\"/>\n" \
108 " <method name=\"ListUnits\">\n" \
109 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
111 " <method name=\"ListJobs\">\n" \
112 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
114 " <method name=\"Subscribe\"/>\n" \
115 " <method name=\"Unsubscribe\"/>\n" \
116 " <method name=\"Dump\">\n" \
117 " <arg name=\"dump\" type=\"s\" direction=\"out\"/>\n" \
119 " <method name=\"CreateSnapshot\">\n" \
120 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
121 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
122 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
124 " <method name=\"Reload\"/>\n" \
125 " <method name=\"Reexecute\"/>\n" \
126 " <method name=\"Exit\"/>\n" \
127 " <method name=\"Reboot\"/>\n" \
128 " <method name=\"PowerOff\"/>\n" \
129 " <method name=\"Halt\"/>\n" \
130 " <method name=\"KExec\"/>\n" \
131 " <method name=\"SwitchRoot\">\n" \
132 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
133 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
135 " <method name=\"SetEnvironment\">\n" \
136 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
138 " <method name=\"UnsetEnvironment\">\n" \
139 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
141 " <method name=\"UnsetAndSetEnvironment\">\n" \
142 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
143 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
145 " <method name=\"ListUnitFiles\">\n" \
146 " <arg name=\"files\" type=\"a(ss)\" direction=\"out\"/>\n" \
148 " <method name=\"GetUnitFileState\">\n" \
149 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
150 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
152 " <method name=\"EnableUnitFiles\">\n" \
153 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
154 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
155 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
156 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
157 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
159 " <method name=\"DisableUnitFiles\">\n" \
160 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
161 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
162 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
164 " <method name=\"ReenableUnitFiles\">\n" \
165 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
166 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
167 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
168 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
169 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
171 " <method name=\"LinkUnitFiles\">\n" \
172 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
173 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
174 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
175 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
177 " <method name=\"PresetUnitFiles\">\n" \
178 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
179 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
180 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
181 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
182 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
184 " <method name=\"MaskUnitFiles\">\n" \
185 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
186 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
187 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
188 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
190 " <method name=\"UnmaskUnitFiles\">\n" \
191 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
192 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
193 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
196 #define BUS_MANAGER_INTERFACE_SIGNALS \
197 " <signal name=\"UnitNew\">\n" \
198 " <arg name=\"id\" type=\"s\"/>\n" \
199 " <arg name=\"unit\" type=\"o\"/>\n" \
201 " <signal name=\"UnitRemoved\">\n" \
202 " <arg name=\"id\" type=\"s\"/>\n" \
203 " <arg name=\"unit\" type=\"o\"/>\n" \
205 " <signal name=\"JobNew\">\n" \
206 " <arg name=\"id\" type=\"u\"/>\n" \
207 " <arg name=\"job\" type=\"o\"/>\n" \
208 " <arg name=\"unit\" type=\"s\"/>\n" \
210 " <signal name=\"JobRemoved\">\n" \
211 " <arg name=\"id\" type=\"u\"/>\n" \
212 " <arg name=\"job\" type=\"o\"/>\n" \
213 " <arg name=\"unit\" type=\"s\"/>\n" \
214 " <arg name=\"result\" type=\"s\"/>\n" \
216 " <signal name=\"StartupFinished\">\n" \
217 " <arg name=\"firmware\" type=\"t\"/>\n" \
218 " <arg name=\"loader\" type=\"t\"/>\n" \
219 " <arg name=\"kernel\" type=\"t\"/>\n" \
220 " <arg name=\"initrd\" type=\"t\"/>\n" \
221 " <arg name=\"userspace\" type=\"t\"/>\n" \
222 " <arg name=\"total\" type=\"t\"/>\n" \
224 " <signal name=\"UnitFilesChanged\"/>\n"
226 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
227 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
230 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
231 " <property name=\"FirmwareTimestamp\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"FirmwareTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
233 " <property name=\"LoaderTimestamp\" type=\"t\" access=\"read\"/>\n" \
234 " <property name=\"LoaderTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
235 " <property name=\"KernelTimestamp\" type=\"t\" access=\"read\"/>\n" \
236 " <property name=\"KernelTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
237 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
238 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
239 " <property name=\"UserspaceTimestamp\" type=\"t\" access=\"read\"/>\n" \
240 " <property name=\"UserspaceTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
241 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
242 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
243 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
244 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
245 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
246 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
247 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
248 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
249 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
250 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
251 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
252 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
253 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
254 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
255 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
256 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
257 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
258 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
259 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n"
261 #define BUS_MANAGER_INTERFACE_END \
264 #define BUS_MANAGER_INTERFACE \
265 BUS_MANAGER_INTERFACE_BEGIN \
266 BUS_MANAGER_INTERFACE_METHODS \
267 BUS_MANAGER_INTERFACE_SIGNALS \
268 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
269 BUS_MANAGER_INTERFACE_END
271 #define INTROSPECTION_BEGIN \
272 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
274 BUS_MANAGER_INTERFACE \
275 BUS_PROPERTIES_INTERFACE \
277 BUS_INTROSPECTABLE_INTERFACE
279 #define INTROSPECTION_END \
282 #define INTERFACES_LIST \
283 BUS_GENERIC_INTERFACES_LIST \
284 "org.freedesktop.systemd1.Manager\0"
286 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
288 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
290 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
293 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
300 e = stpcpy(e, "split-usr:");
302 if (readlink_malloc("/etc/mtab", &p) < 0)
303 e = stpcpy(e, "mtab-not-symlink:");
307 if (access("/proc/cgroups", F_OK) < 0)
308 e = stpcpy(e, "cgroups-missing:");
310 if (hwclock_is_localtime() > 0)
311 e = stpcpy(e, "local-hwclock:");
313 /* remove the last ':' */
319 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
325 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
331 t = log_target_to_string(log_get_target());
333 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
339 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
345 dbus_message_iter_get_basic(i, &t);
347 return log_set_target_from_string(t);
350 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
356 t = log_level_to_string(log_get_max_level());
358 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
364 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
370 dbus_message_iter_get_basic(i, &t);
372 return log_set_max_level_from_string(t);
375 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
383 u = hashmap_size(m->units);
385 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
391 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
399 u = hashmap_size(m->jobs);
401 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
407 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
415 if (dual_timestamp_is_set(&m->finish_timestamp))
418 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
420 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
426 static const char *message_get_sender_with_fallback(DBusMessage *m) {
431 if ((s = dbus_message_get_sender(m)))
434 /* When the message came in from a direct connection the
435 * message will have no sender. We fix that here. */
440 static DBusMessage *message_from_file_changes(
442 UnitFileChange *changes,
444 int carries_install_info) {
446 DBusMessageIter iter, sub, sub2;
450 reply = dbus_message_new_method_return(m);
454 dbus_message_iter_init_append(reply, &iter);
456 if (carries_install_info >= 0) {
459 b = !!carries_install_info;
460 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
464 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
467 for (i = 0; i < n_changes; i++) {
468 const char *type, *path, *source;
470 type = unit_file_change_type_to_string(changes[i].type);
471 path = strempty(changes[i].path);
472 source = strempty(changes[i].source);
474 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
475 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
477 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
478 !dbus_message_iter_close_container(&sub, &sub2))
482 if (!dbus_message_iter_close_container(&iter, &sub))
488 dbus_message_unref(reply);
492 static int bus_manager_send_unit_files_changed(Manager *m) {
496 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
500 r = bus_broadcast(m, s);
501 dbus_message_unref(s);
506 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
512 dbus_message_iter_get_basic(i, t);
514 return watchdog_set_timeout(t);
517 static const char systemd_property_string[] =
522 static const BusProperty bus_systemd_properties[] = {
523 { "Version", bus_property_append_string, "s", 0 },
524 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
525 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
529 static const BusProperty bus_manager_properties[] = {
530 { "Tainted", bus_manager_append_tainted, "s", 0 },
531 { "FirmwareTimestamp", bus_property_append_uint64, "t", offsetof(Manager, firmware_timestamp.realtime) },
532 { "FirmwareTimestampMonotonic", bus_property_append_uint64,"t", offsetof(Manager, firmware_timestamp.monotonic)},
533 { "LoaderTimestamp", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.realtime) },
534 { "LoaderTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, loader_timestamp.monotonic) },
535 { "KernelTimestamp", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.realtime) },
536 { "KernelTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, kernel_timestamp.monotonic) },
537 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
538 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
539 { "UserspaceTimestamp", bus_property_append_uint64, "t", offsetof(Manager, userspace_timestamp.realtime)},
540 { "UserspaceTimestampMonotonic", bus_property_append_uint64,"t",offsetof(Manager, userspace_timestamp.monotonic)},
541 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
542 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
543 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
544 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
545 { "NNames", bus_manager_append_n_names, "u", 0 },
546 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
547 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
548 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
549 { "Progress", bus_manager_append_progress, "d", 0 },
550 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
551 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
552 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
553 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
554 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
555 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
556 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
557 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
558 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
559 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
563 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
568 DBusMessage *reply = NULL;
570 JobType job_type = _JOB_TYPE_INVALID;
571 bool reload_if_possible = false;
578 dbus_error_init(&error);
580 member = dbus_message_get_member(message);
582 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
586 if (!dbus_message_get_args(
589 DBUS_TYPE_STRING, &name,
591 return bus_send_error_reply(connection, message, &error, -EINVAL);
593 if (!(u = manager_get_unit(m, name))) {
594 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
595 return bus_send_error_reply(connection, message, &error, -ENOENT);
598 if (!(reply = dbus_message_new_method_return(message)))
601 if (!(path = unit_dbus_path(u)))
604 if (!dbus_message_append_args(
606 DBUS_TYPE_OBJECT_PATH, &path,
609 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
613 if (!dbus_message_get_args(
616 DBUS_TYPE_UINT32, &pid,
618 return bus_send_error_reply(connection, message, &error, -EINVAL);
620 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
621 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
622 return bus_send_error_reply(connection, message, &error, -ENOENT);
625 if (!(reply = dbus_message_new_method_return(message)))
628 if (!(path = unit_dbus_path(u)))
631 if (!dbus_message_append_args(
633 DBUS_TYPE_OBJECT_PATH, &path,
636 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
640 if (!dbus_message_get_args(
643 DBUS_TYPE_STRING, &name,
645 return bus_send_error_reply(connection, message, &error, -EINVAL);
647 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
648 return bus_send_error_reply(connection, message, &error, r);
650 if (!(reply = dbus_message_new_method_return(message)))
653 if (!(path = unit_dbus_path(u)))
656 if (!dbus_message_append_args(
658 DBUS_TYPE_OBJECT_PATH, &path,
662 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
663 job_type = JOB_START;
664 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
665 job_type = JOB_START;
666 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
668 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
669 job_type = JOB_RELOAD;
670 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
671 job_type = JOB_RESTART;
672 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
673 job_type = JOB_TRY_RESTART;
674 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
675 reload_if_possible = true;
676 job_type = JOB_RESTART;
677 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
678 reload_if_possible = true;
679 job_type = JOB_TRY_RESTART;
680 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
681 const char *name, *swho;
686 if (!dbus_message_get_args(
689 DBUS_TYPE_STRING, &name,
690 DBUS_TYPE_STRING, &swho,
691 DBUS_TYPE_INT32, &signo,
693 return bus_send_error_reply(connection, message, &error, -EINVAL);
698 who = kill_who_from_string(swho);
700 return bus_send_error_reply(connection, message, &error, -EINVAL);
703 if (signo <= 0 || signo >= _NSIG)
704 return bus_send_error_reply(connection, message, &error, -EINVAL);
706 u = manager_get_unit(m, name);
708 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
709 return bus_send_error_reply(connection, message, &error, -ENOENT);
712 r = unit_kill(u, who, signo, &error);
714 return bus_send_error_reply(connection, message, &error, r);
716 if (!(reply = dbus_message_new_method_return(message)))
719 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
723 if (!dbus_message_get_args(
726 DBUS_TYPE_UINT32, &id,
728 return bus_send_error_reply(connection, message, &error, -EINVAL);
730 if (!(j = manager_get_job(m, id))) {
731 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
732 return bus_send_error_reply(connection, message, &error, -ENOENT);
735 if (!(reply = dbus_message_new_method_return(message)))
738 if (!(path = job_dbus_path(j)))
741 if (!dbus_message_append_args(
743 DBUS_TYPE_OBJECT_PATH, &path,
747 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
749 manager_clear_jobs(m);
751 if (!(reply = dbus_message_new_method_return(message)))
754 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
756 manager_reset_failed(m);
758 if (!(reply = dbus_message_new_method_return(message)))
761 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
765 if (!dbus_message_get_args(
768 DBUS_TYPE_STRING, &name,
770 return bus_send_error_reply(connection, message, &error, -EINVAL);
772 if (!(u = manager_get_unit(m, name))) {
773 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
774 return bus_send_error_reply(connection, message, &error, -ENOENT);
777 unit_reset_failed(u);
779 if (!(reply = dbus_message_new_method_return(message)))
782 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
783 DBusMessageIter iter, sub;
788 if (!(reply = dbus_message_new_method_return(message)))
791 dbus_message_iter_init_append(reply, &iter);
793 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
796 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
797 char *u_path, *j_path;
798 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
799 DBusMessageIter sub2;
806 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
809 description = unit_description(u);
810 load_state = unit_load_state_to_string(u->load_state);
811 active_state = unit_active_state_to_string(unit_active_state(u));
812 sub_state = unit_sub_state_to_string(u);
814 f = unit_following(u);
815 following = f ? f->id : "";
817 if (!(u_path = unit_dbus_path(u)))
821 job_id = (uint32_t) u->job->id;
823 if (!(j_path = job_dbus_path(u->job))) {
828 sjob_type = job_type_to_string(u->job->type);
835 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
836 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
837 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
838 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
839 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
840 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
841 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
842 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
843 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
844 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
855 if (!dbus_message_iter_close_container(&sub, &sub2))
859 if (!dbus_message_iter_close_container(&iter, &sub))
862 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
863 DBusMessageIter iter, sub;
867 if (!(reply = dbus_message_new_method_return(message)))
870 dbus_message_iter_init_append(reply, &iter);
872 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
875 HASHMAP_FOREACH(j, m->jobs, i) {
876 char *u_path, *j_path;
877 const char *state, *type;
879 DBusMessageIter sub2;
881 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
884 id = (uint32_t) j->id;
885 state = job_state_to_string(j->state);
886 type = job_type_to_string(j->type);
888 if (!(j_path = job_dbus_path(j)))
891 if (!(u_path = unit_dbus_path(j->unit))) {
896 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
897 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
898 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
899 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
900 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
901 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
910 if (!dbus_message_iter_close_container(&sub, &sub2))
914 if (!dbus_message_iter_close_container(&iter, &sub))
917 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
921 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
922 if (!(s = set_new(string_hash_func, string_compare_func)))
925 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
931 if (!(client = strdup(message_get_sender_with_fallback(message))))
934 if ((r = set_put(s, client)) < 0) {
936 return bus_send_error_reply(connection, message, NULL, r);
939 if (!(reply = dbus_message_new_method_return(message)))
942 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
945 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
946 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
947 return bus_send_error_reply(connection, message, &error, -ENOENT);
952 if (!(reply = dbus_message_new_method_return(message)))
955 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
960 if (!(reply = dbus_message_new_method_return(message)))
963 if (!(f = open_memstream(&dump, &size)))
966 manager_dump_units(m, f, NULL);
967 manager_dump_jobs(m, f, NULL);
977 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
983 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
988 if (!dbus_message_get_args(
991 DBUS_TYPE_STRING, &name,
992 DBUS_TYPE_BOOLEAN, &cleanup,
994 return bus_send_error_reply(connection, message, &error, -EINVAL);
996 if (name && name[0] == 0)
999 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1000 return bus_send_error_reply(connection, message, &error, r);
1002 if (!(reply = dbus_message_new_method_return(message)))
1005 if (!(path = unit_dbus_path(UNIT(s))))
1008 if (!dbus_message_append_args(
1010 DBUS_TYPE_OBJECT_PATH, &path,
1014 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1015 char *introspection = NULL;
1023 if (!(reply = dbus_message_new_method_return(message)))
1026 /* We roll our own introspection code here, instead of
1027 * relying on bus_default_message_handler() because we
1028 * need to generate our introspection string
1031 if (!(f = open_memstream(&introspection, &size)))
1034 fputs(INTROSPECTION_BEGIN, f);
1036 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1042 if (!(p = bus_path_escape(k))) {
1044 free(introspection);
1048 fprintf(f, "<node name=\"unit/%s\"/>", p);
1052 HASHMAP_FOREACH(j, m->jobs, i)
1053 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1055 fputs(INTROSPECTION_END, f);
1059 free(introspection);
1068 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1069 free(introspection);
1073 free(introspection);
1075 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1077 assert(!m->queued_message);
1079 /* Instead of sending the reply back right away, we
1080 * just remember that we need to and then send it
1081 * after the reload is finished. That way the caller
1082 * knows when the reload finished. */
1084 if (!(m->queued_message = dbus_message_new_method_return(message)))
1087 m->queued_message_connection = connection;
1088 m->exit_code = MANAGER_RELOAD;
1090 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1092 /* We don't send a reply back here, the client should
1093 * just wait for us disconnecting. */
1095 m->exit_code = MANAGER_REEXECUTE;
1097 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1099 if (m->running_as == MANAGER_SYSTEM) {
1100 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1101 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1104 if (!(reply = dbus_message_new_method_return(message)))
1107 m->exit_code = MANAGER_EXIT;
1109 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1111 if (m->running_as != MANAGER_SYSTEM) {
1112 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1113 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1116 if (!(reply = dbus_message_new_method_return(message)))
1119 m->exit_code = MANAGER_REBOOT;
1121 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1123 if (m->running_as != MANAGER_SYSTEM) {
1124 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1125 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1128 if (!(reply = dbus_message_new_method_return(message)))
1131 m->exit_code = MANAGER_POWEROFF;
1133 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1135 if (m->running_as != MANAGER_SYSTEM) {
1136 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1137 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1140 if (!(reply = dbus_message_new_method_return(message)))
1143 m->exit_code = MANAGER_HALT;
1145 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1147 if (m->running_as != MANAGER_SYSTEM) {
1148 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1149 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1152 if (!(reply = dbus_message_new_method_return(message)))
1155 m->exit_code = MANAGER_KEXEC;
1157 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1158 const char *switch_root, *switch_root_init;
1162 if (!dbus_message_get_args(
1165 DBUS_TYPE_STRING, &switch_root,
1166 DBUS_TYPE_STRING, &switch_root_init,
1168 return bus_send_error_reply(connection, message, &error, -EINVAL);
1170 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1171 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1173 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1174 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1176 if (m->running_as != MANAGER_SYSTEM) {
1177 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1178 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1182 if (isempty(switch_root_init))
1183 k = access(switch_root, F_OK);
1187 p = strjoin(switch_root, "/", switch_root_init, NULL);
1191 k = access(p, X_OK);
1195 return bus_send_error_reply(connection, message, NULL, -errno);
1197 u = strdup(switch_root);
1201 if (!isempty(switch_root_init)) {
1202 v = strdup(switch_root_init);
1210 free(m->switch_root);
1211 free(m->switch_root_init);
1213 m->switch_root_init = v;
1215 reply = dbus_message_new_method_return(message);
1219 m->exit_code = MANAGER_SWITCH_ROOT;
1221 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1222 char **l = NULL, **e = NULL;
1224 if ((r = bus_parse_strv(message, &l)) < 0) {
1228 return bus_send_error_reply(connection, message, NULL, r);
1231 e = strv_env_merge(2, m->environment, l);
1237 if (!(reply = dbus_message_new_method_return(message))) {
1242 strv_free(m->environment);
1245 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1246 char **l = NULL, **e = NULL;
1248 if ((r = bus_parse_strv(message, &l)) < 0) {
1252 return bus_send_error_reply(connection, message, NULL, r);
1255 e = strv_env_delete(m->environment, 1, l);
1261 if (!(reply = dbus_message_new_method_return(message))) {
1266 strv_free(m->environment);
1269 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1270 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1271 DBusMessageIter iter;
1273 if (!dbus_message_iter_init(message, &iter))
1276 r = bus_parse_strv_iter(&iter, &l_unset);
1281 return bus_send_error_reply(connection, message, NULL, r);
1284 if (!dbus_message_iter_next(&iter)) {
1286 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1289 r = bus_parse_strv_iter(&iter, &l_set);
1295 return bus_send_error_reply(connection, message, NULL, r);
1298 e = strv_env_delete(m->environment, 1, l_unset);
1306 f = strv_env_merge(2, e, l_set);
1313 if (!(reply = dbus_message_new_method_return(message))) {
1318 strv_free(m->environment);
1320 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1321 DBusMessageIter iter, sub, sub2;
1326 reply = dbus_message_new_method_return(message);
1330 h = hashmap_new(string_hash_func, string_compare_func);
1334 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1336 unit_file_list_free(h);
1337 dbus_message_unref(reply);
1338 return bus_send_error_reply(connection, message, NULL, r);
1341 dbus_message_iter_init_append(reply, &iter);
1343 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1344 unit_file_list_free(h);
1348 HASHMAP_FOREACH(item, h, i) {
1351 state = unit_file_state_to_string(item->state);
1354 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1355 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1356 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1357 !dbus_message_iter_close_container(&sub, &sub2)) {
1358 unit_file_list_free(h);
1363 unit_file_list_free(h);
1365 if (!dbus_message_iter_close_container(&iter, &sub))
1368 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1370 UnitFileState state;
1373 if (!dbus_message_get_args(
1376 DBUS_TYPE_STRING, &name,
1378 return bus_send_error_reply(connection, message, &error, -EINVAL);
1380 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1382 return bus_send_error_reply(connection, message, NULL, state);
1384 s = unit_file_state_to_string(state);
1387 reply = dbus_message_new_method_return(message);
1391 if (!dbus_message_append_args(
1393 DBUS_TYPE_STRING, &s,
1396 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1397 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1398 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1399 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1400 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1403 DBusMessageIter iter;
1404 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1405 UnitFileChange *changes = NULL;
1406 unsigned n_changes = 0;
1407 dbus_bool_t runtime, force;
1408 int carries_install_info = -1;
1410 if (!dbus_message_iter_init(message, &iter))
1413 r = bus_parse_strv_iter(&iter, &l);
1418 return bus_send_error_reply(connection, message, NULL, r);
1421 if (!dbus_message_iter_next(&iter) ||
1422 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1423 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1425 return bus_send_error_reply(connection, message, NULL, -EIO);
1428 if (streq(member, "EnableUnitFiles")) {
1429 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1430 carries_install_info = r;
1431 } else if (streq(member, "ReenableUnitFiles")) {
1432 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1433 carries_install_info = r;
1434 } else if (streq(member, "LinkUnitFiles"))
1435 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1436 else if (streq(member, "PresetUnitFiles")) {
1437 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1438 carries_install_info = r;
1439 } else if (streq(member, "MaskUnitFiles"))
1440 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1442 assert_not_reached("Uh? Wrong method");
1445 bus_manager_send_unit_files_changed(m);
1448 unit_file_changes_free(changes, n_changes);
1449 return bus_send_error_reply(connection, message, NULL, r);
1452 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1453 unit_file_changes_free(changes, n_changes);
1458 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1459 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1462 DBusMessageIter iter;
1463 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1464 UnitFileChange *changes = NULL;
1465 unsigned n_changes = 0;
1466 dbus_bool_t runtime;
1468 if (!dbus_message_iter_init(message, &iter))
1471 r = bus_parse_strv_iter(&iter, &l);
1476 return bus_send_error_reply(connection, message, NULL, r);
1479 if (!dbus_message_iter_next(&iter) ||
1480 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1482 return bus_send_error_reply(connection, message, NULL, -EIO);
1485 if (streq(member, "DisableUnitFiles"))
1486 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1487 else if (streq(member, "UnmaskUnitFiles"))
1488 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1490 assert_not_reached("Uh? Wrong method");
1493 bus_manager_send_unit_files_changed(m);
1496 unit_file_changes_free(changes, n_changes);
1497 return bus_send_error_reply(connection, message, NULL, r);
1500 reply = message_from_file_changes(message, changes, n_changes, -1);
1501 unit_file_changes_free(changes, n_changes);
1507 const BusBoundProperties bps[] = {
1508 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1509 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1512 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1515 if (job_type != _JOB_TYPE_INVALID) {
1516 const char *name, *smode, *old_name = NULL;
1523 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1524 b = dbus_message_get_args(
1527 DBUS_TYPE_STRING, &old_name,
1528 DBUS_TYPE_STRING, &name,
1529 DBUS_TYPE_STRING, &smode,
1532 b = dbus_message_get_args(
1535 DBUS_TYPE_STRING, &name,
1536 DBUS_TYPE_STRING, &smode,
1540 return bus_send_error_reply(connection, message, &error, -EINVAL);
1543 if (!(u = manager_get_unit(m, old_name)) ||
1545 u->job->type != JOB_START) {
1546 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1547 return bus_send_error_reply(connection, message, &error, -ENOENT);
1551 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1552 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1553 return bus_send_error_reply(connection, message, &error, -EINVAL);
1556 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1557 return bus_send_error_reply(connection, message, &error, r);
1559 if (reload_if_possible && unit_can_reload(u)) {
1560 if (job_type == JOB_RESTART)
1561 job_type = JOB_RELOAD_OR_START;
1562 else if (job_type == JOB_TRY_RESTART)
1563 job_type = JOB_RELOAD;
1566 if (job_type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) {
1567 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
1568 return bus_send_error_reply(connection, message, &error, -EPERM);
1571 if ((job_type == JOB_START && u->refuse_manual_start) ||
1572 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1573 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1574 (u->refuse_manual_start || u->refuse_manual_stop))) {
1575 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1576 return bus_send_error_reply(connection, message, &error, -EPERM);
1579 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1580 return bus_send_error_reply(connection, message, &error, r);
1582 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1586 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1588 if (!(reply = dbus_message_new_method_return(message)))
1591 if (!(path = job_dbus_path(j)))
1594 if (!dbus_message_append_args(
1596 DBUS_TYPE_OBJECT_PATH, &path,
1602 if (!dbus_connection_send(connection, reply, NULL))
1605 dbus_message_unref(reply);
1610 return DBUS_HANDLER_RESULT_HANDLED;
1616 dbus_message_unref(reply);
1618 dbus_error_free(&error);
1620 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1623 const DBusObjectPathVTable bus_manager_vtable = {
1624 .message_function = bus_manager_message_handler