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 e = stpcpy(e, "cgroups-missing:");
315 if (hwclock_is_localtime() > 0)
316 e = stpcpy(e, "local-hwclock:");
318 /* remove the last ':' */
324 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
330 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
336 t = log_target_to_string(log_get_target());
338 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
344 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
350 dbus_message_iter_get_basic(i, &t);
352 return log_set_target_from_string(t);
355 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
361 t = log_level_to_string(log_get_max_level());
363 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
369 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
375 dbus_message_iter_get_basic(i, &t);
377 return log_set_max_level_from_string(t);
380 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
388 u = hashmap_size(m->units);
390 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
396 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
404 u = hashmap_size(m->jobs);
406 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
412 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
420 if (dual_timestamp_is_set(&m->finish_timestamp))
423 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
425 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
431 static const char *message_get_sender_with_fallback(DBusMessage *m) {
436 if ((s = dbus_message_get_sender(m)))
439 /* When the message came in from a direct connection the
440 * message will have no sender. We fix that here. */
445 static DBusMessage *message_from_file_changes(
447 UnitFileChange *changes,
449 int carries_install_info) {
451 DBusMessageIter iter, sub, sub2;
455 reply = dbus_message_new_method_return(m);
459 dbus_message_iter_init_append(reply, &iter);
461 if (carries_install_info >= 0) {
464 b = !!carries_install_info;
465 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
469 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
472 for (i = 0; i < n_changes; i++) {
473 const char *type, *path, *source;
475 type = unit_file_change_type_to_string(changes[i].type);
476 path = strempty(changes[i].path);
477 source = strempty(changes[i].source);
479 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
480 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
481 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
482 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
483 !dbus_message_iter_close_container(&sub, &sub2))
487 if (!dbus_message_iter_close_container(&iter, &sub))
493 dbus_message_unref(reply);
497 static int bus_manager_send_unit_files_changed(Manager *m) {
501 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
505 r = bus_broadcast(m, s);
506 dbus_message_unref(s);
511 static int bus_manager_append_have_watchdog(DBusMessageIter *i, const char *property, void *data) {
517 b = access("/dev/watchdog", F_OK) >= 0;
519 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
525 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
531 dbus_message_iter_get_basic(i, t);
533 return watchdog_set_timeout(t);
536 static const char systemd_property_string[] =
541 static const BusProperty bus_systemd_properties[] = {
542 { "Version", bus_property_append_string, "s", 0 },
543 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
544 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
548 static const BusProperty bus_manager_properties[] = {
549 { "RunningAs", bus_manager_append_running_as, "s", offsetof(Manager, running_as) },
550 { "Tainted", bus_manager_append_tainted, "s", 0 },
551 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
552 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
553 { "StartupTimestamp", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.realtime) },
554 { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
555 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
556 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
557 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
558 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
559 { "NNames", bus_manager_append_n_names, "u", 0 },
560 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
561 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
562 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
563 { "Progress", bus_manager_append_progress, "d", 0 },
564 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
565 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
566 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
567 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
568 { "NotifySocket", bus_property_append_string, "s", offsetof(Manager, notify_socket), true },
569 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
570 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
571 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
572 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
573 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
574 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
575 { "HaveWatchdog", bus_manager_append_have_watchdog, "b", 0 },
576 #ifdef HAVE_SYSV_COMPAT
577 { "SysVConsole", bus_property_append_bool, "b", offsetof(Manager, sysv_console) },
578 { "SysVInitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
579 { "SysVRcndPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
584 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
589 DBusMessage *reply = NULL;
591 JobType job_type = _JOB_TYPE_INVALID;
592 bool reload_if_possible = false;
599 dbus_error_init(&error);
601 member = dbus_message_get_member(message);
603 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
607 if (!dbus_message_get_args(
610 DBUS_TYPE_STRING, &name,
612 return bus_send_error_reply(connection, message, &error, -EINVAL);
614 if (!(u = manager_get_unit(m, name))) {
615 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
616 return bus_send_error_reply(connection, message, &error, -ENOENT);
619 if (!(reply = dbus_message_new_method_return(message)))
622 if (!(path = unit_dbus_path(u)))
625 if (!dbus_message_append_args(
627 DBUS_TYPE_OBJECT_PATH, &path,
630 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
634 if (!dbus_message_get_args(
637 DBUS_TYPE_UINT32, &pid,
639 return bus_send_error_reply(connection, message, &error, -EINVAL);
641 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
642 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
643 return bus_send_error_reply(connection, message, &error, -ENOENT);
646 if (!(reply = dbus_message_new_method_return(message)))
649 if (!(path = unit_dbus_path(u)))
652 if (!dbus_message_append_args(
654 DBUS_TYPE_OBJECT_PATH, &path,
657 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
661 if (!dbus_message_get_args(
664 DBUS_TYPE_STRING, &name,
666 return bus_send_error_reply(connection, message, &error, -EINVAL);
668 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
669 return bus_send_error_reply(connection, message, &error, r);
671 if (!(reply = dbus_message_new_method_return(message)))
674 if (!(path = unit_dbus_path(u)))
677 if (!dbus_message_append_args(
679 DBUS_TYPE_OBJECT_PATH, &path,
683 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
684 job_type = JOB_START;
685 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
686 job_type = JOB_START;
687 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
689 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
690 job_type = JOB_RELOAD;
691 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
692 job_type = JOB_RESTART;
693 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
694 job_type = JOB_TRY_RESTART;
695 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
696 reload_if_possible = true;
697 job_type = JOB_RESTART;
698 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
699 reload_if_possible = true;
700 job_type = JOB_TRY_RESTART;
701 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
702 const char *name, *swho, *smode;
708 if (!dbus_message_get_args(
711 DBUS_TYPE_STRING, &name,
712 DBUS_TYPE_STRING, &swho,
713 DBUS_TYPE_STRING, &smode,
714 DBUS_TYPE_INT32, &signo,
716 return bus_send_error_reply(connection, message, &error, -EINVAL);
721 who = kill_who_from_string(swho);
723 return bus_send_error_reply(connection, message, &error, -EINVAL);
727 mode = KILL_CONTROL_GROUP;
729 mode = kill_mode_from_string(smode);
731 return bus_send_error_reply(connection, message, &error, -EINVAL);
734 if (signo <= 0 || signo >= _NSIG)
735 return bus_send_error_reply(connection, message, &error, -EINVAL);
737 if (!(u = manager_get_unit(m, name))) {
738 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
739 return bus_send_error_reply(connection, message, &error, -ENOENT);
742 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
743 return bus_send_error_reply(connection, message, &error, r);
745 if (!(reply = dbus_message_new_method_return(message)))
748 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
752 if (!dbus_message_get_args(
755 DBUS_TYPE_UINT32, &id,
757 return bus_send_error_reply(connection, message, &error, -EINVAL);
759 if (!(j = manager_get_job(m, id))) {
760 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
761 return bus_send_error_reply(connection, message, &error, -ENOENT);
764 if (!(reply = dbus_message_new_method_return(message)))
767 if (!(path = job_dbus_path(j)))
770 if (!dbus_message_append_args(
772 DBUS_TYPE_OBJECT_PATH, &path,
776 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
778 manager_clear_jobs(m);
780 if (!(reply = dbus_message_new_method_return(message)))
783 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
785 manager_reset_failed(m);
787 if (!(reply = dbus_message_new_method_return(message)))
790 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
794 if (!dbus_message_get_args(
797 DBUS_TYPE_STRING, &name,
799 return bus_send_error_reply(connection, message, &error, -EINVAL);
801 if (!(u = manager_get_unit(m, name))) {
802 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
803 return bus_send_error_reply(connection, message, &error, -ENOENT);
806 unit_reset_failed(u);
808 if (!(reply = dbus_message_new_method_return(message)))
811 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
812 DBusMessageIter iter, sub;
817 if (!(reply = dbus_message_new_method_return(message)))
820 dbus_message_iter_init_append(reply, &iter);
822 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
825 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
826 char *u_path, *j_path;
827 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
828 DBusMessageIter sub2;
835 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
838 description = unit_description(u);
839 load_state = unit_load_state_to_string(u->load_state);
840 active_state = unit_active_state_to_string(unit_active_state(u));
841 sub_state = unit_sub_state_to_string(u);
843 f = unit_following(u);
844 following = f ? f->id : "";
846 if (!(u_path = unit_dbus_path(u)))
850 job_id = (uint32_t) u->job->id;
852 if (!(j_path = job_dbus_path(u->job))) {
857 sjob_type = job_type_to_string(u->job->type);
864 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
865 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
866 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
867 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
868 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
869 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
870 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
871 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
872 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
873 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
884 if (!dbus_message_iter_close_container(&sub, &sub2))
888 if (!dbus_message_iter_close_container(&iter, &sub))
891 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
892 DBusMessageIter iter, sub;
896 if (!(reply = dbus_message_new_method_return(message)))
899 dbus_message_iter_init_append(reply, &iter);
901 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
904 HASHMAP_FOREACH(j, m->jobs, i) {
905 char *u_path, *j_path;
906 const char *state, *type;
908 DBusMessageIter sub2;
910 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
913 id = (uint32_t) j->id;
914 state = job_state_to_string(j->state);
915 type = job_type_to_string(j->type);
917 if (!(j_path = job_dbus_path(j)))
920 if (!(u_path = unit_dbus_path(j->unit))) {
925 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
926 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
927 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
928 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
929 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
930 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
939 if (!dbus_message_iter_close_container(&sub, &sub2))
943 if (!dbus_message_iter_close_container(&iter, &sub))
946 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
950 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
951 if (!(s = set_new(string_hash_func, string_compare_func)))
954 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
960 if (!(client = strdup(message_get_sender_with_fallback(message))))
963 if ((r = set_put(s, client)) < 0) {
965 return bus_send_error_reply(connection, message, NULL, r);
968 if (!(reply = dbus_message_new_method_return(message)))
971 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
974 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
975 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
976 return bus_send_error_reply(connection, message, &error, -ENOENT);
981 if (!(reply = dbus_message_new_method_return(message)))
984 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
989 if (!(reply = dbus_message_new_method_return(message)))
992 if (!(f = open_memstream(&dump, &size)))
995 manager_dump_units(m, f, NULL);
996 manager_dump_jobs(m, f, NULL);
1006 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1012 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1014 dbus_bool_t cleanup;
1017 if (!dbus_message_get_args(
1020 DBUS_TYPE_STRING, &name,
1021 DBUS_TYPE_BOOLEAN, &cleanup,
1023 return bus_send_error_reply(connection, message, &error, -EINVAL);
1025 if (name && name[0] == 0)
1028 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1029 return bus_send_error_reply(connection, message, &error, r);
1031 if (!(reply = dbus_message_new_method_return(message)))
1034 if (!(path = unit_dbus_path(UNIT(s))))
1037 if (!dbus_message_append_args(
1039 DBUS_TYPE_OBJECT_PATH, &path,
1043 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1044 char *introspection = NULL;
1052 if (!(reply = dbus_message_new_method_return(message)))
1055 /* We roll our own introspection code here, instead of
1056 * relying on bus_default_message_handler() because we
1057 * need to generate our introspection string
1060 if (!(f = open_memstream(&introspection, &size)))
1063 fputs(INTROSPECTION_BEGIN, f);
1065 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1071 if (!(p = bus_path_escape(k))) {
1073 free(introspection);
1077 fprintf(f, "<node name=\"unit/%s\"/>", p);
1081 HASHMAP_FOREACH(j, m->jobs, i)
1082 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1084 fputs(INTROSPECTION_END, f);
1088 free(introspection);
1097 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1098 free(introspection);
1102 free(introspection);
1104 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1106 assert(!m->queued_message);
1108 /* Instead of sending the reply back right away, we
1109 * just remember that we need to and then send it
1110 * after the reload is finished. That way the caller
1111 * knows when the reload finished. */
1113 if (!(m->queued_message = dbus_message_new_method_return(message)))
1116 m->queued_message_connection = connection;
1117 m->exit_code = MANAGER_RELOAD;
1119 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1121 /* We don't send a reply back here, the client should
1122 * just wait for us disconnecting. */
1124 m->exit_code = MANAGER_REEXECUTE;
1126 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1128 if (m->running_as == MANAGER_SYSTEM) {
1129 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1130 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1133 if (!(reply = dbus_message_new_method_return(message)))
1136 m->exit_code = MANAGER_EXIT;
1138 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1140 if (m->running_as != MANAGER_SYSTEM) {
1141 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1142 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1145 if (!(reply = dbus_message_new_method_return(message)))
1148 m->exit_code = MANAGER_REBOOT;
1150 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1152 if (m->running_as != MANAGER_SYSTEM) {
1153 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1154 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1157 if (!(reply = dbus_message_new_method_return(message)))
1160 m->exit_code = MANAGER_POWEROFF;
1162 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1164 if (m->running_as != MANAGER_SYSTEM) {
1165 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1166 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1169 if (!(reply = dbus_message_new_method_return(message)))
1172 m->exit_code = MANAGER_HALT;
1174 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1176 if (m->running_as != MANAGER_SYSTEM) {
1177 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1178 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1181 if (!(reply = dbus_message_new_method_return(message)))
1184 m->exit_code = MANAGER_KEXEC;
1186 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1187 const char *switch_root, *switch_root_init;
1190 if (!dbus_message_get_args(
1193 DBUS_TYPE_STRING, &switch_root,
1194 DBUS_TYPE_STRING, &switch_root_init,
1196 return bus_send_error_reply(connection, message, &error, -EINVAL);
1198 if (path_equal(switch_root, "/") || !is_path(switch_root))
1199 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1201 if (!isempty(switch_root_init) && !is_path(switch_root_init))
1202 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1204 if (m->running_as != MANAGER_SYSTEM) {
1205 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1206 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1209 u = strdup(switch_root);
1213 if (!isempty(switch_root_init)) {
1214 v = strdup(switch_root_init);
1222 free(m->switch_root);
1223 free(m->switch_root_init);
1225 m->switch_root_init = v;
1227 reply = dbus_message_new_method_return(message);
1231 m->exit_code = MANAGER_SWITCH_ROOT;
1233 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1234 char **l = NULL, **e = NULL;
1236 if ((r = bus_parse_strv(message, &l)) < 0) {
1240 return bus_send_error_reply(connection, message, NULL, r);
1243 e = strv_env_merge(2, m->environment, l);
1249 if (!(reply = dbus_message_new_method_return(message))) {
1254 strv_free(m->environment);
1257 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1258 char **l = NULL, **e = NULL;
1260 if ((r = bus_parse_strv(message, &l)) < 0) {
1264 return bus_send_error_reply(connection, message, NULL, r);
1267 e = strv_env_delete(m->environment, 1, l);
1273 if (!(reply = dbus_message_new_method_return(message))) {
1278 strv_free(m->environment);
1281 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1282 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1283 DBusMessageIter iter;
1285 if (!dbus_message_iter_init(message, &iter))
1288 r = bus_parse_strv_iter(&iter, &l_unset);
1293 return bus_send_error_reply(connection, message, NULL, r);
1296 if (!dbus_message_iter_next(&iter)) {
1298 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1301 r = bus_parse_strv_iter(&iter, &l_set);
1307 return bus_send_error_reply(connection, message, NULL, r);
1310 e = strv_env_delete(m->environment, 1, l_unset);
1318 f = strv_env_merge(2, e, l_set);
1325 if (!(reply = dbus_message_new_method_return(message))) {
1330 strv_free(m->environment);
1332 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1333 DBusMessageIter iter, sub, sub2;
1338 reply = dbus_message_new_method_return(message);
1342 h = hashmap_new(string_hash_func, string_compare_func);
1346 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1348 unit_file_list_free(h);
1349 dbus_message_unref(reply);
1350 return bus_send_error_reply(connection, message, NULL, r);
1353 dbus_message_iter_init_append(reply, &iter);
1355 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1356 unit_file_list_free(h);
1360 HASHMAP_FOREACH(item, h, i) {
1363 state = unit_file_state_to_string(item->state);
1366 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1367 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1368 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1369 !dbus_message_iter_close_container(&sub, &sub2)) {
1370 unit_file_list_free(h);
1375 unit_file_list_free(h);
1377 if (!dbus_message_iter_close_container(&iter, &sub))
1380 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1382 UnitFileState state;
1385 if (!dbus_message_get_args(
1388 DBUS_TYPE_STRING, &name,
1390 return bus_send_error_reply(connection, message, &error, -EINVAL);
1392 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1394 return bus_send_error_reply(connection, message, NULL, state);
1396 s = unit_file_state_to_string(state);
1399 reply = dbus_message_new_method_return(message);
1403 if (!dbus_message_append_args(
1405 DBUS_TYPE_STRING, &s,
1408 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1409 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1410 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1411 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1412 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1415 DBusMessageIter iter;
1416 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1417 UnitFileChange *changes = NULL;
1418 unsigned n_changes = 0;
1419 dbus_bool_t runtime, force;
1420 int carries_install_info = -1;
1422 if (!dbus_message_iter_init(message, &iter))
1425 r = bus_parse_strv_iter(&iter, &l);
1430 return bus_send_error_reply(connection, message, NULL, r);
1433 if (!dbus_message_iter_next(&iter) ||
1434 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1435 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1437 return bus_send_error_reply(connection, message, NULL, -EIO);
1440 if (streq(member, "EnableUnitFiles")) {
1441 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1442 carries_install_info = r;
1443 } else if (streq(member, "ReenableUnitFiles")) {
1444 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1445 carries_install_info = r;
1446 } else if (streq(member, "LinkUnitFiles"))
1447 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1448 else if (streq(member, "PresetUnitFiles")) {
1449 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1450 carries_install_info = r;
1451 } else if (streq(member, "MaskUnitFiles"))
1452 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1454 assert_not_reached("Uh? Wrong method");
1457 bus_manager_send_unit_files_changed(m);
1460 unit_file_changes_free(changes, n_changes);
1461 return bus_send_error_reply(connection, message, NULL, r);
1464 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1465 unit_file_changes_free(changes, n_changes);
1470 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1471 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1474 DBusMessageIter iter;
1475 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1476 UnitFileChange *changes = NULL;
1477 unsigned n_changes = 0;
1478 dbus_bool_t runtime;
1480 if (!dbus_message_iter_init(message, &iter))
1483 r = bus_parse_strv_iter(&iter, &l);
1488 return bus_send_error_reply(connection, message, NULL, r);
1491 if (!dbus_message_iter_next(&iter) ||
1492 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1494 return bus_send_error_reply(connection, message, NULL, -EIO);
1497 if (streq(member, "DisableUnitFiles"))
1498 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1499 else if (streq(member, "UnmaskUnitFiles"))
1500 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1502 assert_not_reached("Uh? Wrong method");
1505 bus_manager_send_unit_files_changed(m);
1508 unit_file_changes_free(changes, n_changes);
1509 return bus_send_error_reply(connection, message, NULL, r);
1512 reply = message_from_file_changes(message, changes, n_changes, -1);
1513 unit_file_changes_free(changes, n_changes);
1519 const BusBoundProperties bps[] = {
1520 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1521 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1524 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1527 if (job_type != _JOB_TYPE_INVALID) {
1528 const char *name, *smode, *old_name = NULL;
1535 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1536 b = dbus_message_get_args(
1539 DBUS_TYPE_STRING, &old_name,
1540 DBUS_TYPE_STRING, &name,
1541 DBUS_TYPE_STRING, &smode,
1544 b = dbus_message_get_args(
1547 DBUS_TYPE_STRING, &name,
1548 DBUS_TYPE_STRING, &smode,
1552 return bus_send_error_reply(connection, message, &error, -EINVAL);
1555 if (!(u = manager_get_unit(m, old_name)) ||
1557 u->job->type != JOB_START) {
1558 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1559 return bus_send_error_reply(connection, message, &error, -ENOENT);
1563 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1564 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1565 return bus_send_error_reply(connection, message, &error, -EINVAL);
1568 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1569 return bus_send_error_reply(connection, message, &error, r);
1571 if (reload_if_possible && unit_can_reload(u)) {
1572 if (job_type == JOB_RESTART)
1573 job_type = JOB_RELOAD_OR_START;
1574 else if (job_type == JOB_TRY_RESTART)
1575 job_type = JOB_RELOAD;
1578 if ((job_type == JOB_START && u->refuse_manual_start) ||
1579 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1580 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1581 (u->refuse_manual_start || u->refuse_manual_stop))) {
1582 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1583 return bus_send_error_reply(connection, message, &error, -EPERM);
1586 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1587 return bus_send_error_reply(connection, message, &error, r);
1589 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1593 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1595 if (!(reply = dbus_message_new_method_return(message)))
1598 if (!(path = job_dbus_path(j)))
1601 if (!dbus_message_append_args(
1603 DBUS_TYPE_OBJECT_PATH, &path,
1609 if (!dbus_connection_send(connection, reply, NULL))
1612 dbus_message_unref(reply);
1617 return DBUS_HANDLER_RESULT_HANDLED;
1623 dbus_message_unref(reply);
1625 dbus_error_free(&error);
1627 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1630 const DBusObjectPathVTable bus_manager_vtable = {
1631 .message_function = bus_manager_message_handler