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;
1191 if (!dbus_message_get_args(
1194 DBUS_TYPE_STRING, &switch_root,
1195 DBUS_TYPE_STRING, &switch_root_init,
1197 return bus_send_error_reply(connection, message, &error, -EINVAL);
1199 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1200 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1202 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1203 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1205 if (m->running_as != MANAGER_SYSTEM) {
1206 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1207 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1211 if (isempty(switch_root_init))
1212 k = access(switch_root, F_OK);
1216 p = join(switch_root, "/", switch_root_init, NULL);
1220 k = access(p, X_OK);
1224 return bus_send_error_reply(connection, message, NULL, -errno);
1226 u = strdup(switch_root);
1230 if (!isempty(switch_root_init)) {
1231 v = strdup(switch_root_init);
1239 free(m->switch_root);
1240 free(m->switch_root_init);
1242 m->switch_root_init = v;
1244 reply = dbus_message_new_method_return(message);
1248 m->exit_code = MANAGER_SWITCH_ROOT;
1250 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1251 char **l = NULL, **e = NULL;
1253 if ((r = bus_parse_strv(message, &l)) < 0) {
1257 return bus_send_error_reply(connection, message, NULL, r);
1260 e = strv_env_merge(2, m->environment, l);
1266 if (!(reply = dbus_message_new_method_return(message))) {
1271 strv_free(m->environment);
1274 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1275 char **l = NULL, **e = NULL;
1277 if ((r = bus_parse_strv(message, &l)) < 0) {
1281 return bus_send_error_reply(connection, message, NULL, r);
1284 e = strv_env_delete(m->environment, 1, l);
1290 if (!(reply = dbus_message_new_method_return(message))) {
1295 strv_free(m->environment);
1298 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1299 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1300 DBusMessageIter iter;
1302 if (!dbus_message_iter_init(message, &iter))
1305 r = bus_parse_strv_iter(&iter, &l_unset);
1310 return bus_send_error_reply(connection, message, NULL, r);
1313 if (!dbus_message_iter_next(&iter)) {
1315 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1318 r = bus_parse_strv_iter(&iter, &l_set);
1324 return bus_send_error_reply(connection, message, NULL, r);
1327 e = strv_env_delete(m->environment, 1, l_unset);
1335 f = strv_env_merge(2, e, l_set);
1342 if (!(reply = dbus_message_new_method_return(message))) {
1347 strv_free(m->environment);
1349 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1350 DBusMessageIter iter, sub, sub2;
1355 reply = dbus_message_new_method_return(message);
1359 h = hashmap_new(string_hash_func, string_compare_func);
1363 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1365 unit_file_list_free(h);
1366 dbus_message_unref(reply);
1367 return bus_send_error_reply(connection, message, NULL, r);
1370 dbus_message_iter_init_append(reply, &iter);
1372 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1373 unit_file_list_free(h);
1377 HASHMAP_FOREACH(item, h, i) {
1380 state = unit_file_state_to_string(item->state);
1383 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1384 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1385 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1386 !dbus_message_iter_close_container(&sub, &sub2)) {
1387 unit_file_list_free(h);
1392 unit_file_list_free(h);
1394 if (!dbus_message_iter_close_container(&iter, &sub))
1397 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1399 UnitFileState state;
1402 if (!dbus_message_get_args(
1405 DBUS_TYPE_STRING, &name,
1407 return bus_send_error_reply(connection, message, &error, -EINVAL);
1409 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1411 return bus_send_error_reply(connection, message, NULL, state);
1413 s = unit_file_state_to_string(state);
1416 reply = dbus_message_new_method_return(message);
1420 if (!dbus_message_append_args(
1422 DBUS_TYPE_STRING, &s,
1425 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1426 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1427 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1428 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1429 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1432 DBusMessageIter iter;
1433 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1434 UnitFileChange *changes = NULL;
1435 unsigned n_changes = 0;
1436 dbus_bool_t runtime, force;
1437 int carries_install_info = -1;
1439 if (!dbus_message_iter_init(message, &iter))
1442 r = bus_parse_strv_iter(&iter, &l);
1447 return bus_send_error_reply(connection, message, NULL, r);
1450 if (!dbus_message_iter_next(&iter) ||
1451 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1452 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1454 return bus_send_error_reply(connection, message, NULL, -EIO);
1457 if (streq(member, "EnableUnitFiles")) {
1458 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1459 carries_install_info = r;
1460 } else if (streq(member, "ReenableUnitFiles")) {
1461 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1462 carries_install_info = r;
1463 } else if (streq(member, "LinkUnitFiles"))
1464 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1465 else if (streq(member, "PresetUnitFiles")) {
1466 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1467 carries_install_info = r;
1468 } else if (streq(member, "MaskUnitFiles"))
1469 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1471 assert_not_reached("Uh? Wrong method");
1474 bus_manager_send_unit_files_changed(m);
1477 unit_file_changes_free(changes, n_changes);
1478 return bus_send_error_reply(connection, message, NULL, r);
1481 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1482 unit_file_changes_free(changes, n_changes);
1487 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1488 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1491 DBusMessageIter iter;
1492 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1493 UnitFileChange *changes = NULL;
1494 unsigned n_changes = 0;
1495 dbus_bool_t runtime;
1497 if (!dbus_message_iter_init(message, &iter))
1500 r = bus_parse_strv_iter(&iter, &l);
1505 return bus_send_error_reply(connection, message, NULL, r);
1508 if (!dbus_message_iter_next(&iter) ||
1509 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1511 return bus_send_error_reply(connection, message, NULL, -EIO);
1514 if (streq(member, "DisableUnitFiles"))
1515 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1516 else if (streq(member, "UnmaskUnitFiles"))
1517 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1519 assert_not_reached("Uh? Wrong method");
1522 bus_manager_send_unit_files_changed(m);
1525 unit_file_changes_free(changes, n_changes);
1526 return bus_send_error_reply(connection, message, NULL, r);
1529 reply = message_from_file_changes(message, changes, n_changes, -1);
1530 unit_file_changes_free(changes, n_changes);
1536 const BusBoundProperties bps[] = {
1537 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1538 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1541 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1544 if (job_type != _JOB_TYPE_INVALID) {
1545 const char *name, *smode, *old_name = NULL;
1552 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1553 b = dbus_message_get_args(
1556 DBUS_TYPE_STRING, &old_name,
1557 DBUS_TYPE_STRING, &name,
1558 DBUS_TYPE_STRING, &smode,
1561 b = dbus_message_get_args(
1564 DBUS_TYPE_STRING, &name,
1565 DBUS_TYPE_STRING, &smode,
1569 return bus_send_error_reply(connection, message, &error, -EINVAL);
1572 if (!(u = manager_get_unit(m, old_name)) ||
1574 u->job->type != JOB_START) {
1575 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1576 return bus_send_error_reply(connection, message, &error, -ENOENT);
1580 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1581 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1582 return bus_send_error_reply(connection, message, &error, -EINVAL);
1585 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1586 return bus_send_error_reply(connection, message, &error, r);
1588 if (reload_if_possible && unit_can_reload(u)) {
1589 if (job_type == JOB_RESTART)
1590 job_type = JOB_RELOAD_OR_START;
1591 else if (job_type == JOB_TRY_RESTART)
1592 job_type = JOB_RELOAD;
1595 if ((job_type == JOB_START && u->refuse_manual_start) ||
1596 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1597 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1598 (u->refuse_manual_start || u->refuse_manual_stop))) {
1599 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1600 return bus_send_error_reply(connection, message, &error, -EPERM);
1603 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1604 return bus_send_error_reply(connection, message, &error, r);
1606 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1610 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1612 if (!(reply = dbus_message_new_method_return(message)))
1615 if (!(path = job_dbus_path(j)))
1618 if (!dbus_message_append_args(
1620 DBUS_TYPE_OBJECT_PATH, &path,
1626 if (!dbus_connection_send(connection, reply, NULL))
1629 dbus_message_unref(reply);
1634 return DBUS_HANDLER_RESULT_HANDLED;
1640 dbus_message_unref(reply);
1642 dbus_error_free(&error);
1644 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1647 const DBusObjectPathVTable bus_manager_vtable = {
1648 .message_function = bus_manager_message_handler