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=\"mode\" 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 " <method name=\"CreateSnapshot\">\n" \
119 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
120 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
121 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
123 " <method name=\"Reload\"/>\n" \
124 " <method name=\"Reexecute\"/>\n" \
125 " <method name=\"Exit\"/>\n" \
126 " <method name=\"Reboot\"/>\n" \
127 " <method name=\"PowerOff\"/>\n" \
128 " <method name=\"Halt\"/>\n" \
129 " <method name=\"KExec\"/>\n" \
130 " <method name=\"SwitchRoot\">\n" \
131 " <arg name=\"new_root\" type=\"s\" direction=\"in\"/>\n" \
132 " <arg name=\"init\" type=\"s\" direction=\"in\"/>\n" \
134 " <method name=\"SetEnvironment\">\n" \
135 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
137 " <method name=\"UnsetEnvironment\">\n" \
138 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
140 " <method name=\"UnsetAndSetEnvironment\">\n" \
141 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
142 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
144 " <method name=\"ListUnitFiles\">\n" \
145 " <arg name=\"changes\" type=\"a(ss)\" direction=\"out\"/>\n" \
147 " <method name=\"GetUnitFileState\">\n" \
148 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
149 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
151 " <method name=\"EnableUnitFiles\">\n" \
152 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
153 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
154 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
155 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
156 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
158 " <method name=\"DisableUnitFiles\">\n" \
159 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
160 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
161 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
163 " <method name=\"ReenableUnitFiles\">\n" \
164 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
165 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
166 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
167 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
168 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
170 " <method name=\"LinkUnitFiles\">\n" \
171 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
172 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
173 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
174 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
176 " <method name=\"PresetUnitFiles\">\n" \
177 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
178 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
179 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
180 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
181 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
183 " <method name=\"MaskUnitFiles\">\n" \
184 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
185 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
186 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
187 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
189 " <method name=\"UnmaskUnitFiles\">\n" \
190 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
191 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
192 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
195 #define BUS_MANAGER_INTERFACE_SIGNALS \
196 " <signal name=\"UnitNew\">\n" \
197 " <arg name=\"id\" type=\"s\"/>\n" \
198 " <arg name=\"unit\" type=\"o\"/>\n" \
200 " <signal name=\"UnitRemoved\">\n" \
201 " <arg name=\"id\" type=\"s\"/>\n" \
202 " <arg name=\"unit\" type=\"o\"/>\n" \
204 " <signal name=\"JobNew\">\n" \
205 " <arg name=\"id\" type=\"u\"/>\n" \
206 " <arg name=\"job\" type=\"o\"/>\n" \
207 " <arg name=\"unit\" type=\"s\"/>\n" \
209 " <signal name=\"JobRemoved\">\n" \
210 " <arg name=\"id\" type=\"u\"/>\n" \
211 " <arg name=\"job\" type=\"o\"/>\n" \
212 " <arg name=\"unit\" type=\"s\"/>\n" \
213 " <arg name=\"result\" type=\"s\"/>\n" \
215 " <signal name=\"StartupFinished\">\n" \
216 " <arg name=\"kernel\" type=\"t\"/>\n" \
217 " <arg name=\"initrd\" type=\"t\"/>\n" \
218 " <arg name=\"userspace\" type=\"t\"/>\n" \
219 " <arg name=\"total\" type=\"t\"/>\n" \
221 " <signal name=\"UnitFilesChanged\"/>\n"
223 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
224 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
225 " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
226 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
227 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
228 " <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
229 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
230 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
231 " <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
233 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
234 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
235 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
236 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
237 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
238 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
239 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
240 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
241 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
242 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
243 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
244 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
245 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
246 " <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
247 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
248 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
249 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
250 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
251 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
252 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
253 " <property name=\"HaveWatchdog\" type=\"b\" access=\"read\"/>\n"
255 #ifdef HAVE_SYSV_COMPAT
256 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
257 " <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
258 " <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
259 " <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
261 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
264 #define BUS_MANAGER_INTERFACE_END \
267 #define BUS_MANAGER_INTERFACE \
268 BUS_MANAGER_INTERFACE_BEGIN \
269 BUS_MANAGER_INTERFACE_METHODS \
270 BUS_MANAGER_INTERFACE_SIGNALS \
271 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
272 BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
273 BUS_MANAGER_INTERFACE_END
275 #define INTROSPECTION_BEGIN \
276 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
278 BUS_MANAGER_INTERFACE \
279 BUS_PROPERTIES_INTERFACE \
281 BUS_INTROSPECTABLE_INTERFACE
283 #define INTROSPECTION_END \
286 #define INTERFACES_LIST \
287 BUS_GENERIC_INTERFACES_LIST \
288 "org.freedesktop.systemd1.Manager\0"
290 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
292 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
293 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
295 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
298 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
305 e = stpcpy(e, "split-usr:");
307 if (readlink_malloc("/etc/mtab", &p) < 0)
308 e = stpcpy(e, "mtab-not-symlink:");
312 if (access("/proc/cgroups", F_OK) < 0)
313 stpcpy(e, "cgroups-missing:");
315 if (hwclock_is_localtime() > 0)
316 stpcpy(e, "local-hwclock:");
318 if (endswith(buf, ":"))
319 buf[strlen(buf)-1] = 0;
323 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
329 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
335 t = log_target_to_string(log_get_target());
337 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
343 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
349 dbus_message_iter_get_basic(i, &t);
351 return log_set_target_from_string(t);
354 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
360 t = log_level_to_string(log_get_max_level());
362 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
368 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
374 dbus_message_iter_get_basic(i, &t);
376 return log_set_max_level_from_string(t);
379 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
387 u = hashmap_size(m->units);
389 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
395 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
403 u = hashmap_size(m->jobs);
405 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
411 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
419 if (dual_timestamp_is_set(&m->finish_timestamp))
422 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
424 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
430 static const char *message_get_sender_with_fallback(DBusMessage *m) {
435 if ((s = dbus_message_get_sender(m)))
438 /* When the message came in from a direct connection the
439 * message will have no sender. We fix that here. */
444 static DBusMessage *message_from_file_changes(
446 UnitFileChange *changes,
448 int carries_install_info) {
450 DBusMessageIter iter, sub, sub2;
454 reply = dbus_message_new_method_return(m);
458 dbus_message_iter_init_append(reply, &iter);
460 if (carries_install_info >= 0) {
463 b = !!carries_install_info;
464 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
468 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
471 for (i = 0; i < n_changes; i++) {
472 const char *type, *path, *source;
474 type = unit_file_change_type_to_string(changes[i].type);
475 path = strempty(changes[i].path);
476 source = strempty(changes[i].source);
478 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
479 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
480 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
481 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
482 !dbus_message_iter_close_container(&sub, &sub2))
486 if (!dbus_message_iter_close_container(&iter, &sub))
492 dbus_message_unref(reply);
496 static int bus_manager_send_unit_files_changed(Manager *m) {
500 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
504 r = bus_broadcast(m, s);
505 dbus_message_unref(s);
510 static int bus_manager_append_have_watchdog(DBusMessageIter *i, const char *property, void *data) {
516 b = access("/dev/watchdog", F_OK) >= 0;
518 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
524 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
530 dbus_message_iter_get_basic(i, t);
532 return watchdog_set_timeout(t);
535 static const char systemd_property_string[] =
540 static const BusProperty bus_systemd_properties[] = {
541 { "Version", bus_property_append_string, "s", 0 },
542 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
543 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
547 static const BusProperty bus_manager_properties[] = {
548 { "RunningAs", bus_manager_append_running_as, "s", offsetof(Manager, running_as) },
549 { "Tainted", bus_manager_append_tainted, "s", 0 },
550 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
551 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
552 { "StartupTimestamp", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.realtime) },
553 { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
554 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
555 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
556 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
557 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
558 { "NNames", bus_manager_append_n_names, "u", 0 },
559 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
560 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
561 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
562 { "Progress", bus_manager_append_progress, "d", 0 },
563 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
564 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
565 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
566 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
567 { "NotifySocket", bus_property_append_string, "s", offsetof(Manager, notify_socket), true },
568 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
569 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
570 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
571 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
572 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
573 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
574 { "HaveWatchdog", bus_manager_append_have_watchdog, "b", 0 },
575 #ifdef HAVE_SYSV_COMPAT
576 { "SysVConsole", bus_property_append_bool, "b", offsetof(Manager, sysv_console) },
577 { "SysVInitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
578 { "SysVRcndPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
583 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
588 DBusMessage *reply = NULL;
590 JobType job_type = _JOB_TYPE_INVALID;
591 bool reload_if_possible = false;
598 dbus_error_init(&error);
600 member = dbus_message_get_member(message);
602 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
606 if (!dbus_message_get_args(
609 DBUS_TYPE_STRING, &name,
611 return bus_send_error_reply(connection, message, &error, -EINVAL);
613 if (!(u = manager_get_unit(m, name))) {
614 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
615 return bus_send_error_reply(connection, message, &error, -ENOENT);
618 if (!(reply = dbus_message_new_method_return(message)))
621 if (!(path = unit_dbus_path(u)))
624 if (!dbus_message_append_args(
626 DBUS_TYPE_OBJECT_PATH, &path,
629 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
633 if (!dbus_message_get_args(
636 DBUS_TYPE_UINT32, &pid,
638 return bus_send_error_reply(connection, message, &error, -EINVAL);
640 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
641 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
642 return bus_send_error_reply(connection, message, &error, -ENOENT);
645 if (!(reply = dbus_message_new_method_return(message)))
648 if (!(path = unit_dbus_path(u)))
651 if (!dbus_message_append_args(
653 DBUS_TYPE_OBJECT_PATH, &path,
656 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
660 if (!dbus_message_get_args(
663 DBUS_TYPE_STRING, &name,
665 return bus_send_error_reply(connection, message, &error, -EINVAL);
667 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
668 return bus_send_error_reply(connection, message, &error, r);
670 if (!(reply = dbus_message_new_method_return(message)))
673 if (!(path = unit_dbus_path(u)))
676 if (!dbus_message_append_args(
678 DBUS_TYPE_OBJECT_PATH, &path,
682 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
683 job_type = JOB_START;
684 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
685 job_type = JOB_START;
686 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
688 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
689 job_type = JOB_RELOAD;
690 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
691 job_type = JOB_RESTART;
692 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
693 job_type = JOB_TRY_RESTART;
694 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
695 reload_if_possible = true;
696 job_type = JOB_RESTART;
697 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
698 reload_if_possible = true;
699 job_type = JOB_TRY_RESTART;
700 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
701 const char *name, *swho, *smode;
707 if (!dbus_message_get_args(
710 DBUS_TYPE_STRING, &name,
711 DBUS_TYPE_STRING, &swho,
712 DBUS_TYPE_STRING, &smode,
713 DBUS_TYPE_INT32, &signo,
715 return bus_send_error_reply(connection, message, &error, -EINVAL);
720 who = kill_who_from_string(swho);
722 return bus_send_error_reply(connection, message, &error, -EINVAL);
726 mode = KILL_CONTROL_GROUP;
728 mode = kill_mode_from_string(smode);
730 return bus_send_error_reply(connection, message, &error, -EINVAL);
733 if (signo <= 0 || signo >= _NSIG)
734 return bus_send_error_reply(connection, message, &error, -EINVAL);
736 if (!(u = manager_get_unit(m, name))) {
737 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
738 return bus_send_error_reply(connection, message, &error, -ENOENT);
741 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
742 return bus_send_error_reply(connection, message, &error, r);
744 if (!(reply = dbus_message_new_method_return(message)))
747 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
751 if (!dbus_message_get_args(
754 DBUS_TYPE_UINT32, &id,
756 return bus_send_error_reply(connection, message, &error, -EINVAL);
758 if (!(j = manager_get_job(m, id))) {
759 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
760 return bus_send_error_reply(connection, message, &error, -ENOENT);
763 if (!(reply = dbus_message_new_method_return(message)))
766 if (!(path = job_dbus_path(j)))
769 if (!dbus_message_append_args(
771 DBUS_TYPE_OBJECT_PATH, &path,
775 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
777 manager_clear_jobs(m);
779 if (!(reply = dbus_message_new_method_return(message)))
782 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
784 manager_reset_failed(m);
786 if (!(reply = dbus_message_new_method_return(message)))
789 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
793 if (!dbus_message_get_args(
796 DBUS_TYPE_STRING, &name,
798 return bus_send_error_reply(connection, message, &error, -EINVAL);
800 if (!(u = manager_get_unit(m, name))) {
801 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
802 return bus_send_error_reply(connection, message, &error, -ENOENT);
805 unit_reset_failed(u);
807 if (!(reply = dbus_message_new_method_return(message)))
810 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
811 DBusMessageIter iter, sub;
816 if (!(reply = dbus_message_new_method_return(message)))
819 dbus_message_iter_init_append(reply, &iter);
821 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
824 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
825 char *u_path, *j_path;
826 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
827 DBusMessageIter sub2;
834 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
837 description = unit_description(u);
838 load_state = unit_load_state_to_string(u->load_state);
839 active_state = unit_active_state_to_string(unit_active_state(u));
840 sub_state = unit_sub_state_to_string(u);
842 f = unit_following(u);
843 following = f ? f->id : "";
845 if (!(u_path = unit_dbus_path(u)))
849 job_id = (uint32_t) u->job->id;
851 if (!(j_path = job_dbus_path(u->job))) {
856 sjob_type = job_type_to_string(u->job->type);
863 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
864 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
865 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
866 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
867 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
868 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
869 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
870 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
871 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
872 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
883 if (!dbus_message_iter_close_container(&sub, &sub2))
887 if (!dbus_message_iter_close_container(&iter, &sub))
890 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
891 DBusMessageIter iter, sub;
895 if (!(reply = dbus_message_new_method_return(message)))
898 dbus_message_iter_init_append(reply, &iter);
900 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
903 HASHMAP_FOREACH(j, m->jobs, i) {
904 char *u_path, *j_path;
905 const char *state, *type;
907 DBusMessageIter sub2;
909 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
912 id = (uint32_t) j->id;
913 state = job_state_to_string(j->state);
914 type = job_type_to_string(j->type);
916 if (!(j_path = job_dbus_path(j)))
919 if (!(u_path = unit_dbus_path(j->unit))) {
924 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
925 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
926 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
927 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
928 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
929 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
938 if (!dbus_message_iter_close_container(&sub, &sub2))
942 if (!dbus_message_iter_close_container(&iter, &sub))
945 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
949 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
950 if (!(s = set_new(string_hash_func, string_compare_func)))
953 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
959 if (!(client = strdup(message_get_sender_with_fallback(message))))
962 if ((r = set_put(s, client)) < 0) {
964 return bus_send_error_reply(connection, message, NULL, r);
967 if (!(reply = dbus_message_new_method_return(message)))
970 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
973 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
974 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
975 return bus_send_error_reply(connection, message, &error, -ENOENT);
980 if (!(reply = dbus_message_new_method_return(message)))
983 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
988 if (!(reply = dbus_message_new_method_return(message)))
991 if (!(f = open_memstream(&dump, &size)))
994 manager_dump_units(m, f, NULL);
995 manager_dump_jobs(m, f, NULL);
1005 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1011 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1013 dbus_bool_t cleanup;
1016 if (!dbus_message_get_args(
1019 DBUS_TYPE_STRING, &name,
1020 DBUS_TYPE_BOOLEAN, &cleanup,
1022 return bus_send_error_reply(connection, message, &error, -EINVAL);
1024 if (name && name[0] == 0)
1027 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1028 return bus_send_error_reply(connection, message, &error, r);
1030 if (!(reply = dbus_message_new_method_return(message)))
1033 if (!(path = unit_dbus_path(UNIT(s))))
1036 if (!dbus_message_append_args(
1038 DBUS_TYPE_OBJECT_PATH, &path,
1042 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1043 char *introspection = NULL;
1051 if (!(reply = dbus_message_new_method_return(message)))
1054 /* We roll our own introspection code here, instead of
1055 * relying on bus_default_message_handler() because we
1056 * need to generate our introspection string
1059 if (!(f = open_memstream(&introspection, &size)))
1062 fputs(INTROSPECTION_BEGIN, f);
1064 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1070 if (!(p = bus_path_escape(k))) {
1072 free(introspection);
1076 fprintf(f, "<node name=\"unit/%s\"/>", p);
1080 HASHMAP_FOREACH(j, m->jobs, i)
1081 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1083 fputs(INTROSPECTION_END, f);
1087 free(introspection);
1096 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1097 free(introspection);
1101 free(introspection);
1103 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1105 assert(!m->queued_message);
1107 /* Instead of sending the reply back right away, we
1108 * just remember that we need to and then send it
1109 * after the reload is finished. That way the caller
1110 * knows when the reload finished. */
1112 if (!(m->queued_message = dbus_message_new_method_return(message)))
1115 m->queued_message_connection = connection;
1116 m->exit_code = MANAGER_RELOAD;
1118 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1120 /* We don't send a reply back here, the client should
1121 * just wait for us disconnecting. */
1123 m->exit_code = MANAGER_REEXECUTE;
1125 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1127 if (m->running_as == MANAGER_SYSTEM) {
1128 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service 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_EXIT;
1137 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1139 if (m->running_as != MANAGER_SYSTEM) {
1140 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot 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_REBOOT;
1149 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1151 if (m->running_as != MANAGER_SYSTEM) {
1152 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off 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_POWEROFF;
1161 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1163 if (m->running_as != MANAGER_SYSTEM) {
1164 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1165 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1168 if (!(reply = dbus_message_new_method_return(message)))
1171 m->exit_code = MANAGER_HALT;
1173 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1175 if (m->running_as != MANAGER_SYSTEM) {
1176 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1177 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1180 if (!(reply = dbus_message_new_method_return(message)))
1183 m->exit_code = MANAGER_KEXEC;
1185 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1186 const char *switch_root, *switch_root_init;
1189 if (!dbus_message_get_args(
1192 DBUS_TYPE_STRING, &switch_root,
1193 DBUS_TYPE_STRING, &switch_root_init,
1195 return bus_send_error_reply(connection, message, &error, -EINVAL);
1197 if (path_equal(switch_root, "/") || !is_path(switch_root))
1198 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1200 if (!isempty(switch_root_init) && !is_path(switch_root_init))
1201 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1203 if (m->running_as != MANAGER_SYSTEM) {
1204 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1205 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1208 u = strdup(switch_root);
1212 if (!isempty(switch_root_init)) {
1213 v = strdup(switch_root_init);
1221 free(m->switch_root);
1222 free(m->switch_root_init);
1224 m->switch_root_init = v;
1226 reply = dbus_message_new_method_return(message);
1230 m->exit_code = MANAGER_SWITCH_ROOT;
1232 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1233 char **l = NULL, **e = NULL;
1235 if ((r = bus_parse_strv(message, &l)) < 0) {
1239 return bus_send_error_reply(connection, message, NULL, r);
1242 e = strv_env_merge(2, m->environment, l);
1248 if (!(reply = dbus_message_new_method_return(message))) {
1253 strv_free(m->environment);
1256 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1257 char **l = NULL, **e = NULL;
1259 if ((r = bus_parse_strv(message, &l)) < 0) {
1263 return bus_send_error_reply(connection, message, NULL, r);
1266 e = strv_env_delete(m->environment, 1, l);
1272 if (!(reply = dbus_message_new_method_return(message))) {
1277 strv_free(m->environment);
1280 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1281 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1282 DBusMessageIter iter;
1284 if (!dbus_message_iter_init(message, &iter))
1287 r = bus_parse_strv_iter(&iter, &l_unset);
1292 return bus_send_error_reply(connection, message, NULL, r);
1295 if (!dbus_message_iter_next(&iter)) {
1297 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1300 r = bus_parse_strv_iter(&iter, &l_set);
1306 return bus_send_error_reply(connection, message, NULL, r);
1309 e = strv_env_delete(m->environment, 1, l_unset);
1317 f = strv_env_merge(2, e, l_set);
1324 if (!(reply = dbus_message_new_method_return(message))) {
1329 strv_free(m->environment);
1331 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1332 DBusMessageIter iter, sub, sub2;
1337 reply = dbus_message_new_method_return(message);
1341 h = hashmap_new(string_hash_func, string_compare_func);
1345 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1347 unit_file_list_free(h);
1348 dbus_message_unref(reply);
1349 return bus_send_error_reply(connection, message, NULL, r);
1352 dbus_message_iter_init_append(reply, &iter);
1354 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1355 unit_file_list_free(h);
1359 HASHMAP_FOREACH(item, h, i) {
1362 state = unit_file_state_to_string(item->state);
1365 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1366 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1367 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1368 !dbus_message_iter_close_container(&sub, &sub2)) {
1369 unit_file_list_free(h);
1374 unit_file_list_free(h);
1376 if (!dbus_message_iter_close_container(&iter, &sub))
1379 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1381 UnitFileState state;
1384 if (!dbus_message_get_args(
1387 DBUS_TYPE_STRING, &name,
1389 return bus_send_error_reply(connection, message, &error, -EINVAL);
1391 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1393 return bus_send_error_reply(connection, message, NULL, state);
1395 s = unit_file_state_to_string(state);
1398 reply = dbus_message_new_method_return(message);
1402 if (!dbus_message_append_args(
1404 DBUS_TYPE_STRING, &s,
1407 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1408 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1409 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1410 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1411 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1414 DBusMessageIter iter;
1415 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1416 UnitFileChange *changes = NULL;
1417 unsigned n_changes = 0;
1418 dbus_bool_t runtime, force;
1419 int carries_install_info = -1;
1421 if (!dbus_message_iter_init(message, &iter))
1424 r = bus_parse_strv_iter(&iter, &l);
1429 return bus_send_error_reply(connection, message, NULL, r);
1432 if (!dbus_message_iter_next(&iter) ||
1433 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1434 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1436 return bus_send_error_reply(connection, message, NULL, -EIO);
1439 if (streq(member, "EnableUnitFiles")) {
1440 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1441 carries_install_info = r;
1442 } else if (streq(member, "ReenableUnitFiles")) {
1443 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1444 carries_install_info = r;
1445 } else if (streq(member, "LinkUnitFiles"))
1446 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1447 else if (streq(member, "PresetUnitFiles")) {
1448 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1449 carries_install_info = r;
1450 } else if (streq(member, "MaskUnitFiles"))
1451 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1453 assert_not_reached("Uh? Wrong method");
1456 bus_manager_send_unit_files_changed(m);
1459 unit_file_changes_free(changes, n_changes);
1460 return bus_send_error_reply(connection, message, NULL, r);
1463 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1464 unit_file_changes_free(changes, n_changes);
1469 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1470 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1473 DBusMessageIter iter;
1474 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1475 UnitFileChange *changes = NULL;
1476 unsigned n_changes = 0;
1477 dbus_bool_t runtime;
1479 if (!dbus_message_iter_init(message, &iter))
1482 r = bus_parse_strv_iter(&iter, &l);
1487 return bus_send_error_reply(connection, message, NULL, r);
1490 if (!dbus_message_iter_next(&iter) ||
1491 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1493 return bus_send_error_reply(connection, message, NULL, -EIO);
1496 if (streq(member, "DisableUnitFiles"))
1497 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1498 else if (streq(member, "UnmaskUnitFiles"))
1499 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1501 assert_not_reached("Uh? Wrong method");
1504 bus_manager_send_unit_files_changed(m);
1507 unit_file_changes_free(changes, n_changes);
1508 return bus_send_error_reply(connection, message, NULL, r);
1511 reply = message_from_file_changes(message, changes, n_changes, -1);
1512 unit_file_changes_free(changes, n_changes);
1518 const BusBoundProperties bps[] = {
1519 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1520 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1523 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1526 if (job_type != _JOB_TYPE_INVALID) {
1527 const char *name, *smode, *old_name = NULL;
1534 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1535 b = dbus_message_get_args(
1538 DBUS_TYPE_STRING, &old_name,
1539 DBUS_TYPE_STRING, &name,
1540 DBUS_TYPE_STRING, &smode,
1543 b = dbus_message_get_args(
1546 DBUS_TYPE_STRING, &name,
1547 DBUS_TYPE_STRING, &smode,
1551 return bus_send_error_reply(connection, message, &error, -EINVAL);
1554 if (!(u = manager_get_unit(m, old_name)) ||
1556 u->job->type != JOB_START) {
1557 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1558 return bus_send_error_reply(connection, message, &error, -ENOENT);
1562 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1563 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1564 return bus_send_error_reply(connection, message, &error, -EINVAL);
1567 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1568 return bus_send_error_reply(connection, message, &error, r);
1570 if (reload_if_possible && unit_can_reload(u)) {
1571 if (job_type == JOB_RESTART)
1572 job_type = JOB_RELOAD_OR_START;
1573 else if (job_type == JOB_TRY_RESTART)
1574 job_type = JOB_RELOAD;
1577 if ((job_type == JOB_START && u->refuse_manual_start) ||
1578 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1579 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1580 (u->refuse_manual_start || u->refuse_manual_stop))) {
1581 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1582 return bus_send_error_reply(connection, message, &error, -EPERM);
1585 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1586 return bus_send_error_reply(connection, message, &error, r);
1588 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1592 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1594 if (!(reply = dbus_message_new_method_return(message)))
1597 if (!(path = job_dbus_path(j)))
1600 if (!dbus_message_append_args(
1602 DBUS_TYPE_OBJECT_PATH, &path,
1608 if (!dbus_connection_send(connection, reply, NULL))
1611 dbus_message_unref(reply);
1616 return DBUS_HANDLER_RESULT_HANDLED;
1622 dbus_message_unref(reply);
1624 dbus_error_free(&error);
1626 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1629 const DBusObjectPathVTable bus_manager_vtable = {
1630 .message_function = bus_manager_message_handler