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"
36 #define BUS_MANAGER_INTERFACE_BEGIN \
37 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
39 #define BUS_MANAGER_INTERFACE_METHODS \
40 " <method name=\"GetUnit\">\n" \
41 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
42 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
44 " <method name=\"GetUnitByPID\">\n" \
45 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
46 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
48 " <method name=\"LoadUnit\">\n" \
49 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
50 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
52 " <method name=\"StartUnit\">\n" \
53 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
54 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
55 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
57 " <method name=\"StartUnitReplace\">\n" \
58 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
59 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
60 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
61 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
63 " <method name=\"StopUnit\">\n" \
64 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
65 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
66 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
68 " <method name=\"ReloadUnit\">\n" \
69 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
70 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
71 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
73 " <method name=\"RestartUnit\">\n" \
74 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
75 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
76 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
78 " <method name=\"TryRestartUnit\">\n" \
79 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
80 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
81 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
83 " <method name=\"ReloadOrRestartUnit\">\n" \
84 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
85 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
86 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
88 " <method name=\"ReloadOrTryRestartUnit\">\n" \
89 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
90 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
91 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
93 " <method name=\"KillUnit\">\n" \
94 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
96 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
97 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
99 " <method name=\"ResetFailedUnit\">\n" \
100 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
102 " <method name=\"GetJob\">\n" \
103 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
104 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
106 " <method name=\"ClearJobs\"/>\n" \
107 " <method name=\"ResetFailed\"/>\n" \
108 " <method name=\"ListUnits\">\n" \
109 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
111 " <method name=\"ListJobs\">\n" \
112 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
114 " <method name=\"Subscribe\"/>\n" \
115 " <method name=\"Unsubscribe\"/>\n" \
116 " <method name=\"Dump\"/>\n" \
117 " <method name=\"CreateSnapshot\">\n" \
118 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
119 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
120 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
122 " <method name=\"Reload\"/>\n" \
123 " <method name=\"Reexecute\"/>\n" \
124 " <method name=\"Exit\"/>\n" \
125 " <method name=\"Reboot\"/>\n" \
126 " <method name=\"PowerOff\"/>\n" \
127 " <method name=\"Halt\"/>\n" \
128 " <method name=\"KExec\"/>\n" \
129 " <method name=\"SetEnvironment\">\n" \
130 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
132 " <method name=\"UnsetEnvironment\">\n" \
133 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
135 " <method name=\"UnsetAndSetEnvironment\">\n" \
136 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
137 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
139 " <method name=\"ListUnitFiles\">\n" \
140 " <arg name=\"changes\" type=\"a(ss)\" direction=\"out\"/>\n" \
142 " <method name=\"GetUnitFileState\">\n" \
143 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
144 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
146 " <method name=\"EnableUnitFiles\">\n" \
147 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
148 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
149 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
150 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
151 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
153 " <method name=\"DisableUnitFiles\">\n" \
154 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
155 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
156 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
158 " <method name=\"ReenableUnitFiles\">\n" \
159 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
160 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
161 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
162 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
163 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
165 " <method name=\"LinkUnitFiles\">\n" \
166 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
167 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
168 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
169 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
171 " <method name=\"PresetUnitFiles\">\n" \
172 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
173 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
174 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
175 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
176 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
178 " <method name=\"MaskUnitFiles\">\n" \
179 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
180 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
181 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
182 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
184 " <method name=\"UnmaskUnitFiles\">\n" \
185 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
186 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
187 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
190 #define BUS_MANAGER_INTERFACE_SIGNALS \
191 " <signal name=\"UnitNew\">\n" \
192 " <arg name=\"id\" type=\"s\"/>\n" \
193 " <arg name=\"unit\" type=\"o\"/>\n" \
195 " <signal name=\"UnitRemoved\">\n" \
196 " <arg name=\"id\" type=\"s\"/>\n" \
197 " <arg name=\"unit\" type=\"o\"/>\n" \
199 " <signal name=\"JobNew\">\n" \
200 " <arg name=\"id\" type=\"u\"/>\n" \
201 " <arg name=\"job\" type=\"o\"/>\n" \
202 " <arg name=\"unit\" type=\"s\"/>\n" \
204 " <signal name=\"JobRemoved\">\n" \
205 " <arg name=\"id\" type=\"u\"/>\n" \
206 " <arg name=\"job\" type=\"o\"/>\n" \
207 " <arg name=\"unit\" type=\"s\"/>\n" \
208 " <arg name=\"result\" type=\"s\"/>\n" \
210 " <signal name=\"StartupFinished\">\n" \
211 " <arg name=\"kernel\" type=\"t\"/>\n" \
212 " <arg name=\"initrd\" type=\"t\"/>\n" \
213 " <arg name=\"userspace\" type=\"t\"/>\n" \
214 " <arg name=\"total\" type=\"t\"/>\n" \
216 " <signal name=\"UnitFilesChanged\"/>\n"
218 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
219 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
221 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
222 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
223 " <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
224 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
225 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
227 " <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
228 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
229 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
230 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
231 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
232 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
233 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
234 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
235 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
236 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
237 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
238 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
239 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
240 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
241 " <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
242 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
243 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
244 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
245 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
246 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
247 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
248 " <property name=\"HaveWatchdog\" type=\"b\" access=\"read\"/>\n"
250 #ifdef HAVE_SYSV_COMPAT
251 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
252 " <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
253 " <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
254 " <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
256 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
259 #define BUS_MANAGER_INTERFACE_END \
262 #define BUS_MANAGER_INTERFACE \
263 BUS_MANAGER_INTERFACE_BEGIN \
264 BUS_MANAGER_INTERFACE_METHODS \
265 BUS_MANAGER_INTERFACE_SIGNALS \
266 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
267 BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
268 BUS_MANAGER_INTERFACE_END
270 #define INTROSPECTION_BEGIN \
271 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
273 BUS_MANAGER_INTERFACE \
274 BUS_PROPERTIES_INTERFACE \
276 BUS_INTROSPECTABLE_INTERFACE
278 #define INTROSPECTION_END \
281 #define INTERFACES_LIST \
282 BUS_GENERIC_INTERFACES_LIST \
283 "org.freedesktop.systemd1.Manager\0"
285 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
287 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as, manager_running_as, ManagerRunningAs);
288 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
290 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
293 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
300 e = stpcpy(e, "split-usr:");
302 if (readlink_malloc("/etc/mtab", &p) < 0)
303 e = stpcpy(e, "mtab-not-symlink:");
307 if (access("/proc/cgroups", F_OK) < 0)
308 stpcpy(e, "cgroups-missing:");
310 if (hwclock_is_localtime() > 0)
311 stpcpy(e, "local-hwclock:");
313 if (endswith(buf, ":"))
314 buf[strlen(buf)-1] = 0;
318 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
324 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
330 t = log_target_to_string(log_get_target());
332 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
338 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
344 dbus_message_iter_get_basic(i, &t);
346 return log_set_target_from_string(t);
349 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
355 t = log_level_to_string(log_get_max_level());
357 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
363 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
369 dbus_message_iter_get_basic(i, &t);
371 return log_set_max_level_from_string(t);
374 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
382 u = hashmap_size(m->units);
384 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
390 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
398 u = hashmap_size(m->jobs);
400 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
406 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
414 if (dual_timestamp_is_set(&m->finish_timestamp))
417 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
419 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
425 static const char *message_get_sender_with_fallback(DBusMessage *m) {
430 if ((s = dbus_message_get_sender(m)))
433 /* When the message came in from a direct connection the
434 * message will have no sender. We fix that here. */
439 static DBusMessage *message_from_file_changes(
441 UnitFileChange *changes,
443 int carries_install_info) {
445 DBusMessageIter iter, sub, sub2;
449 reply = dbus_message_new_method_return(m);
453 dbus_message_iter_init_append(reply, &iter);
455 if (carries_install_info >= 0) {
458 b = !!carries_install_info;
459 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
463 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
466 for (i = 0; i < n_changes; i++) {
467 const char *type, *path, *source;
469 type = unit_file_change_type_to_string(changes[i].type);
470 path = strempty(changes[i].path);
471 source = strempty(changes[i].source);
473 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
474 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
475 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
477 !dbus_message_iter_close_container(&sub, &sub2))
481 if (!dbus_message_iter_close_container(&iter, &sub))
487 dbus_message_unref(reply);
491 static int bus_manager_send_unit_files_changed(Manager *m) {
495 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
499 r = bus_broadcast(m, s);
500 dbus_message_unref(s);
505 static int bus_manager_append_have_watchdog(DBusMessageIter *i, const char *property, void *data) {
511 b = access("/dev/watchdog", F_OK) >= 0;
513 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
519 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
525 dbus_message_iter_get_basic(i, t);
527 return watchdog_set_timeout(t);
530 static const char systemd_property_string[] =
535 static const BusProperty bus_systemd_properties[] = {
536 { "Version", bus_property_append_string, "s", 0 },
537 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
538 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
542 static const BusProperty bus_manager_properties[] = {
543 { "RunningAs", bus_manager_append_running_as, "s", offsetof(Manager, running_as) },
544 { "Tainted", bus_manager_append_tainted, "s", 0 },
545 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
546 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
547 { "StartupTimestamp", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.realtime) },
548 { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
549 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
550 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
551 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
552 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
553 { "NNames", bus_manager_append_n_names, "u", 0 },
554 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
555 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
556 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
557 { "Progress", bus_manager_append_progress, "d", 0 },
558 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
559 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
560 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
561 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
562 { "NotifySocket", bus_property_append_string, "s", offsetof(Manager, notify_socket), true },
563 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
564 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
565 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
566 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
567 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
568 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
569 { "HaveWatchdog", bus_manager_append_have_watchdog, "b", 0 },
570 #ifdef HAVE_SYSV_COMPAT
571 { "SysVConsole", bus_property_append_bool, "b", offsetof(Manager, sysv_console) },
572 { "SysVInitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
573 { "SysVRcndPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
578 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
583 DBusMessage *reply = NULL;
585 JobType job_type = _JOB_TYPE_INVALID;
586 bool reload_if_possible = false;
593 dbus_error_init(&error);
595 member = dbus_message_get_member(message);
597 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
601 if (!dbus_message_get_args(
604 DBUS_TYPE_STRING, &name,
606 return bus_send_error_reply(connection, message, &error, -EINVAL);
608 if (!(u = manager_get_unit(m, name))) {
609 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
610 return bus_send_error_reply(connection, message, &error, -ENOENT);
613 if (!(reply = dbus_message_new_method_return(message)))
616 if (!(path = unit_dbus_path(u)))
619 if (!dbus_message_append_args(
621 DBUS_TYPE_OBJECT_PATH, &path,
624 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
628 if (!dbus_message_get_args(
631 DBUS_TYPE_UINT32, &pid,
633 return bus_send_error_reply(connection, message, &error, -EINVAL);
635 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
636 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
637 return bus_send_error_reply(connection, message, &error, -ENOENT);
640 if (!(reply = dbus_message_new_method_return(message)))
643 if (!(path = unit_dbus_path(u)))
646 if (!dbus_message_append_args(
648 DBUS_TYPE_OBJECT_PATH, &path,
651 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
655 if (!dbus_message_get_args(
658 DBUS_TYPE_STRING, &name,
660 return bus_send_error_reply(connection, message, &error, -EINVAL);
662 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
663 return bus_send_error_reply(connection, message, &error, r);
665 if (!(reply = dbus_message_new_method_return(message)))
668 if (!(path = unit_dbus_path(u)))
671 if (!dbus_message_append_args(
673 DBUS_TYPE_OBJECT_PATH, &path,
677 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
678 job_type = JOB_START;
679 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
680 job_type = JOB_START;
681 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
683 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
684 job_type = JOB_RELOAD;
685 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
686 job_type = JOB_RESTART;
687 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
688 job_type = JOB_TRY_RESTART;
689 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
690 reload_if_possible = true;
691 job_type = JOB_RESTART;
692 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
693 reload_if_possible = true;
694 job_type = JOB_TRY_RESTART;
695 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
696 const char *name, *swho, *smode;
702 if (!dbus_message_get_args(
705 DBUS_TYPE_STRING, &name,
706 DBUS_TYPE_STRING, &swho,
707 DBUS_TYPE_STRING, &smode,
708 DBUS_TYPE_INT32, &signo,
710 return bus_send_error_reply(connection, message, &error, -EINVAL);
715 who = kill_who_from_string(swho);
717 return bus_send_error_reply(connection, message, &error, -EINVAL);
721 mode = KILL_CONTROL_GROUP;
723 mode = kill_mode_from_string(smode);
725 return bus_send_error_reply(connection, message, &error, -EINVAL);
728 if (signo <= 0 || signo >= _NSIG)
729 return bus_send_error_reply(connection, message, &error, -EINVAL);
731 if (!(u = manager_get_unit(m, name))) {
732 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
733 return bus_send_error_reply(connection, message, &error, -ENOENT);
736 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
737 return bus_send_error_reply(connection, message, &error, r);
739 if (!(reply = dbus_message_new_method_return(message)))
742 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
746 if (!dbus_message_get_args(
749 DBUS_TYPE_UINT32, &id,
751 return bus_send_error_reply(connection, message, &error, -EINVAL);
753 if (!(j = manager_get_job(m, id))) {
754 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
755 return bus_send_error_reply(connection, message, &error, -ENOENT);
758 if (!(reply = dbus_message_new_method_return(message)))
761 if (!(path = job_dbus_path(j)))
764 if (!dbus_message_append_args(
766 DBUS_TYPE_OBJECT_PATH, &path,
770 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
772 manager_clear_jobs(m);
774 if (!(reply = dbus_message_new_method_return(message)))
777 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
779 manager_reset_failed(m);
781 if (!(reply = dbus_message_new_method_return(message)))
784 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
788 if (!dbus_message_get_args(
791 DBUS_TYPE_STRING, &name,
793 return bus_send_error_reply(connection, message, &error, -EINVAL);
795 if (!(u = manager_get_unit(m, name))) {
796 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
797 return bus_send_error_reply(connection, message, &error, -ENOENT);
800 unit_reset_failed(u);
802 if (!(reply = dbus_message_new_method_return(message)))
805 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
806 DBusMessageIter iter, sub;
811 if (!(reply = dbus_message_new_method_return(message)))
814 dbus_message_iter_init_append(reply, &iter);
816 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
819 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
820 char *u_path, *j_path;
821 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
822 DBusMessageIter sub2;
829 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
832 description = unit_description(u);
833 load_state = unit_load_state_to_string(u->load_state);
834 active_state = unit_active_state_to_string(unit_active_state(u));
835 sub_state = unit_sub_state_to_string(u);
837 f = unit_following(u);
838 following = f ? f->id : "";
840 if (!(u_path = unit_dbus_path(u)))
844 job_id = (uint32_t) u->job->id;
846 if (!(j_path = job_dbus_path(u->job))) {
851 sjob_type = job_type_to_string(u->job->type);
858 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
859 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
860 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
861 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
862 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
863 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
864 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
865 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
866 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
867 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
878 if (!dbus_message_iter_close_container(&sub, &sub2))
882 if (!dbus_message_iter_close_container(&iter, &sub))
885 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
886 DBusMessageIter iter, sub;
890 if (!(reply = dbus_message_new_method_return(message)))
893 dbus_message_iter_init_append(reply, &iter);
895 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
898 HASHMAP_FOREACH(j, m->jobs, i) {
899 char *u_path, *j_path;
900 const char *state, *type;
902 DBusMessageIter sub2;
904 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
907 id = (uint32_t) j->id;
908 state = job_state_to_string(j->state);
909 type = job_type_to_string(j->type);
911 if (!(j_path = job_dbus_path(j)))
914 if (!(u_path = unit_dbus_path(j->unit))) {
919 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
920 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
921 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
922 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
923 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
924 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
933 if (!dbus_message_iter_close_container(&sub, &sub2))
937 if (!dbus_message_iter_close_container(&iter, &sub))
940 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
944 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
945 if (!(s = set_new(string_hash_func, string_compare_func)))
948 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
954 if (!(client = strdup(message_get_sender_with_fallback(message))))
957 if ((r = set_put(s, client)) < 0) {
959 return bus_send_error_reply(connection, message, NULL, r);
962 if (!(reply = dbus_message_new_method_return(message)))
965 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
968 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
969 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
970 return bus_send_error_reply(connection, message, &error, -ENOENT);
975 if (!(reply = dbus_message_new_method_return(message)))
978 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
983 if (!(reply = dbus_message_new_method_return(message)))
986 if (!(f = open_memstream(&dump, &size)))
989 manager_dump_units(m, f, NULL);
990 manager_dump_jobs(m, f, NULL);
1000 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1006 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1008 dbus_bool_t cleanup;
1011 if (!dbus_message_get_args(
1014 DBUS_TYPE_STRING, &name,
1015 DBUS_TYPE_BOOLEAN, &cleanup,
1017 return bus_send_error_reply(connection, message, &error, -EINVAL);
1019 if (name && name[0] == 0)
1022 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1023 return bus_send_error_reply(connection, message, &error, r);
1025 if (!(reply = dbus_message_new_method_return(message)))
1028 if (!(path = unit_dbus_path(UNIT(s))))
1031 if (!dbus_message_append_args(
1033 DBUS_TYPE_OBJECT_PATH, &path,
1037 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1038 char *introspection = NULL;
1046 if (!(reply = dbus_message_new_method_return(message)))
1049 /* We roll our own introspection code here, instead of
1050 * relying on bus_default_message_handler() because we
1051 * need to generate our introspection string
1054 if (!(f = open_memstream(&introspection, &size)))
1057 fputs(INTROSPECTION_BEGIN, f);
1059 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1065 if (!(p = bus_path_escape(k))) {
1067 free(introspection);
1071 fprintf(f, "<node name=\"unit/%s\"/>", p);
1075 HASHMAP_FOREACH(j, m->jobs, i)
1076 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1078 fputs(INTROSPECTION_END, f);
1082 free(introspection);
1091 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1092 free(introspection);
1096 free(introspection);
1098 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1100 assert(!m->queued_message);
1102 /* Instead of sending the reply back right away, we
1103 * just remember that we need to and then send it
1104 * after the reload is finished. That way the caller
1105 * knows when the reload finished. */
1107 if (!(m->queued_message = dbus_message_new_method_return(message)))
1110 m->queued_message_connection = connection;
1111 m->exit_code = MANAGER_RELOAD;
1113 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1115 /* We don't send a reply back here, the client should
1116 * just wait for us disconnecting. */
1118 m->exit_code = MANAGER_REEXECUTE;
1120 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1122 if (m->running_as == MANAGER_SYSTEM) {
1123 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1124 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1127 if (!(reply = dbus_message_new_method_return(message)))
1130 m->exit_code = MANAGER_EXIT;
1132 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1134 if (m->running_as != MANAGER_SYSTEM) {
1135 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1136 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1139 if (!(reply = dbus_message_new_method_return(message)))
1142 m->exit_code = MANAGER_REBOOT;
1144 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1146 if (m->running_as != MANAGER_SYSTEM) {
1147 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1148 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1151 if (!(reply = dbus_message_new_method_return(message)))
1154 m->exit_code = MANAGER_POWEROFF;
1156 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1158 if (m->running_as != MANAGER_SYSTEM) {
1159 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1160 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1163 if (!(reply = dbus_message_new_method_return(message)))
1166 m->exit_code = MANAGER_HALT;
1168 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1170 if (m->running_as != MANAGER_SYSTEM) {
1171 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1172 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1175 if (!(reply = dbus_message_new_method_return(message)))
1178 m->exit_code = MANAGER_KEXEC;
1180 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1181 char **l = NULL, **e = NULL;
1183 if ((r = bus_parse_strv(message, &l)) < 0) {
1187 return bus_send_error_reply(connection, message, NULL, r);
1190 e = strv_env_merge(2, m->environment, l);
1196 if (!(reply = dbus_message_new_method_return(message))) {
1201 strv_free(m->environment);
1204 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1205 char **l = NULL, **e = NULL;
1207 if ((r = bus_parse_strv(message, &l)) < 0) {
1211 return bus_send_error_reply(connection, message, NULL, r);
1214 e = strv_env_delete(m->environment, 1, l);
1220 if (!(reply = dbus_message_new_method_return(message))) {
1225 strv_free(m->environment);
1228 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1229 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1230 DBusMessageIter iter;
1232 if (!dbus_message_iter_init(message, &iter))
1235 r = bus_parse_strv_iter(&iter, &l_unset);
1240 return bus_send_error_reply(connection, message, NULL, r);
1243 if (!dbus_message_iter_next(&iter)) {
1245 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1248 r = bus_parse_strv_iter(&iter, &l_set);
1254 return bus_send_error_reply(connection, message, NULL, r);
1257 e = strv_env_delete(m->environment, 1, l_unset);
1265 f = strv_env_merge(2, e, l_set);
1272 if (!(reply = dbus_message_new_method_return(message))) {
1277 strv_free(m->environment);
1279 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1280 DBusMessageIter iter, sub, sub2;
1285 reply = dbus_message_new_method_return(message);
1289 h = hashmap_new(string_hash_func, string_compare_func);
1293 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1295 unit_file_list_free(h);
1296 dbus_message_unref(reply);
1297 return bus_send_error_reply(connection, message, NULL, r);
1300 dbus_message_iter_init_append(reply, &iter);
1302 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1303 unit_file_list_free(h);
1307 HASHMAP_FOREACH(item, h, i) {
1310 state = unit_file_state_to_string(item->state);
1313 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1314 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1315 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1316 !dbus_message_iter_close_container(&sub, &sub2)) {
1317 unit_file_list_free(h);
1322 unit_file_list_free(h);
1324 if (!dbus_message_iter_close_container(&iter, &sub))
1327 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1329 UnitFileState state;
1332 if (!dbus_message_get_args(
1335 DBUS_TYPE_STRING, &name,
1337 return bus_send_error_reply(connection, message, &error, -EINVAL);
1339 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1341 return bus_send_error_reply(connection, message, NULL, state);
1343 s = unit_file_state_to_string(state);
1346 reply = dbus_message_new_method_return(message);
1350 if (!dbus_message_append_args(
1352 DBUS_TYPE_STRING, &s,
1355 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1356 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1357 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1358 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1359 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1362 DBusMessageIter iter;
1363 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1364 UnitFileChange *changes = NULL;
1365 unsigned n_changes = 0;
1366 dbus_bool_t runtime, force;
1367 int carries_install_info = -1;
1369 if (!dbus_message_iter_init(message, &iter))
1372 r = bus_parse_strv_iter(&iter, &l);
1377 return bus_send_error_reply(connection, message, NULL, r);
1380 if (!dbus_message_iter_next(&iter) ||
1381 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1382 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1384 return bus_send_error_reply(connection, message, NULL, -EIO);
1387 if (streq(member, "EnableUnitFiles")) {
1388 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1389 carries_install_info = r;
1390 } else if (streq(member, "ReenableUnitFiles")) {
1391 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1392 carries_install_info = r;
1393 } else if (streq(member, "LinkUnitFiles"))
1394 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1395 else if (streq(member, "PresetUnitFiles")) {
1396 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1397 carries_install_info = r;
1398 } else if (streq(member, "MaskUnitFiles"))
1399 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1401 assert_not_reached("Uh? Wrong method");
1404 bus_manager_send_unit_files_changed(m);
1407 unit_file_changes_free(changes, n_changes);
1408 return bus_send_error_reply(connection, message, NULL, r);
1411 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1412 unit_file_changes_free(changes, n_changes);
1417 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1418 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1421 DBusMessageIter iter;
1422 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1423 UnitFileChange *changes = NULL;
1424 unsigned n_changes = 0;
1425 dbus_bool_t runtime;
1427 if (!dbus_message_iter_init(message, &iter))
1430 r = bus_parse_strv_iter(&iter, &l);
1435 return bus_send_error_reply(connection, message, NULL, r);
1438 if (!dbus_message_iter_next(&iter) ||
1439 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1441 return bus_send_error_reply(connection, message, NULL, -EIO);
1444 if (streq(member, "DisableUnitFiles"))
1445 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1446 else if (streq(member, "UnmaskUnitFiles"))
1447 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1449 assert_not_reached("Uh? Wrong method");
1452 bus_manager_send_unit_files_changed(m);
1455 unit_file_changes_free(changes, n_changes);
1456 return bus_send_error_reply(connection, message, NULL, r);
1459 reply = message_from_file_changes(message, changes, n_changes, -1);
1460 unit_file_changes_free(changes, n_changes);
1466 const BusBoundProperties bps[] = {
1467 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1468 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1471 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1474 if (job_type != _JOB_TYPE_INVALID) {
1475 const char *name, *smode, *old_name = NULL;
1482 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1483 b = dbus_message_get_args(
1486 DBUS_TYPE_STRING, &old_name,
1487 DBUS_TYPE_STRING, &name,
1488 DBUS_TYPE_STRING, &smode,
1491 b = dbus_message_get_args(
1494 DBUS_TYPE_STRING, &name,
1495 DBUS_TYPE_STRING, &smode,
1499 return bus_send_error_reply(connection, message, &error, -EINVAL);
1502 if (!(u = manager_get_unit(m, old_name)) ||
1504 u->job->type != JOB_START) {
1505 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1506 return bus_send_error_reply(connection, message, &error, -ENOENT);
1510 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1511 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1512 return bus_send_error_reply(connection, message, &error, -EINVAL);
1515 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1516 return bus_send_error_reply(connection, message, &error, r);
1518 if (reload_if_possible && unit_can_reload(u)) {
1519 if (job_type == JOB_RESTART)
1520 job_type = JOB_RELOAD_OR_START;
1521 else if (job_type == JOB_TRY_RESTART)
1522 job_type = JOB_RELOAD;
1525 if ((job_type == JOB_START && u->refuse_manual_start) ||
1526 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1527 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1528 (u->refuse_manual_start || u->refuse_manual_stop))) {
1529 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1530 return bus_send_error_reply(connection, message, &error, -EPERM);
1533 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1534 return bus_send_error_reply(connection, message, &error, r);
1536 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1540 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1542 if (!(reply = dbus_message_new_method_return(message)))
1545 if (!(path = job_dbus_path(j)))
1548 if (!dbus_message_append_args(
1550 DBUS_TYPE_OBJECT_PATH, &path,
1556 if (!dbus_connection_send(connection, reply, NULL))
1559 dbus_message_unref(reply);
1564 return DBUS_HANDLER_RESULT_HANDLED;
1570 dbus_message_unref(reply);
1572 dbus_error_free(&error);
1574 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1577 const DBusObjectPathVTable bus_manager_vtable = {
1578 .message_function = bus_manager_message_handler