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=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
229 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
230 " <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
231 " <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
232 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
233 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
234 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
235 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
236 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
237 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
238 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
239 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
240 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
241 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
242 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
243 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
244 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
245 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
246 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
247 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
248 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n" \
249 " <property name=\"RuntimeWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
250 " <property name=\"ShutdownWatchdogUSec\" type=\"s\" access=\"readwrite\"/>\n" \
251 " <property name=\"HaveWatchdog\" type=\"b\" access=\"read\"/>\n"
253 #ifdef HAVE_SYSV_COMPAT
254 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
255 " <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
256 " <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
258 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
261 #define BUS_MANAGER_INTERFACE_END \
264 #define BUS_MANAGER_INTERFACE \
265 BUS_MANAGER_INTERFACE_BEGIN \
266 BUS_MANAGER_INTERFACE_METHODS \
267 BUS_MANAGER_INTERFACE_SIGNALS \
268 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
269 BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
270 BUS_MANAGER_INTERFACE_END
272 #define INTROSPECTION_BEGIN \
273 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
275 BUS_MANAGER_INTERFACE \
276 BUS_PROPERTIES_INTERFACE \
278 BUS_INTROSPECTABLE_INTERFACE
280 #define INTROSPECTION_END \
283 #define INTERFACES_LIST \
284 BUS_GENERIC_INTERFACES_LIST \
285 "org.freedesktop.systemd1.Manager\0"
287 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
289 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
291 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
294 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
301 e = stpcpy(e, "split-usr:");
303 if (readlink_malloc("/etc/mtab", &p) < 0)
304 e = stpcpy(e, "mtab-not-symlink:");
308 if (access("/proc/cgroups", F_OK) < 0)
309 e = stpcpy(e, "cgroups-missing:");
311 if (hwclock_is_localtime() > 0)
312 e = stpcpy(e, "local-hwclock:");
314 /* remove the last ':' */
320 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
326 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
332 t = log_target_to_string(log_get_target());
334 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
340 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
346 dbus_message_iter_get_basic(i, &t);
348 return log_set_target_from_string(t);
351 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
357 t = log_level_to_string(log_get_max_level());
359 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
365 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
371 dbus_message_iter_get_basic(i, &t);
373 return log_set_max_level_from_string(t);
376 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
384 u = hashmap_size(m->units);
386 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
392 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
400 u = hashmap_size(m->jobs);
402 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
408 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
416 if (dual_timestamp_is_set(&m->finish_timestamp))
419 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
421 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
427 static const char *message_get_sender_with_fallback(DBusMessage *m) {
432 if ((s = dbus_message_get_sender(m)))
435 /* When the message came in from a direct connection the
436 * message will have no sender. We fix that here. */
441 static DBusMessage *message_from_file_changes(
443 UnitFileChange *changes,
445 int carries_install_info) {
447 DBusMessageIter iter, sub, sub2;
451 reply = dbus_message_new_method_return(m);
455 dbus_message_iter_init_append(reply, &iter);
457 if (carries_install_info >= 0) {
460 b = !!carries_install_info;
461 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
465 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
468 for (i = 0; i < n_changes; i++) {
469 const char *type, *path, *source;
471 type = unit_file_change_type_to_string(changes[i].type);
472 path = strempty(changes[i].path);
473 source = strempty(changes[i].source);
475 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
476 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
477 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
478 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
479 !dbus_message_iter_close_container(&sub, &sub2))
483 if (!dbus_message_iter_close_container(&iter, &sub))
489 dbus_message_unref(reply);
493 static int bus_manager_send_unit_files_changed(Manager *m) {
497 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
501 r = bus_broadcast(m, s);
502 dbus_message_unref(s);
507 static int bus_manager_append_have_watchdog(DBusMessageIter *i, const char *property, void *data) {
513 b = access("/dev/watchdog", F_OK) >= 0;
515 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
521 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
527 dbus_message_iter_get_basic(i, t);
529 return watchdog_set_timeout(t);
532 static const char systemd_property_string[] =
537 static const BusProperty bus_systemd_properties[] = {
538 { "Version", bus_property_append_string, "s", 0 },
539 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
540 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
544 static const BusProperty bus_manager_properties[] = {
545 { "Tainted", bus_manager_append_tainted, "s", 0 },
546 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
547 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
548 { "StartupTimestamp", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.realtime) },
549 { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
550 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
551 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
552 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
553 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
554 { "NNames", bus_manager_append_n_names, "u", 0 },
555 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
556 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
557 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
558 { "Progress", bus_manager_append_progress, "d", 0 },
559 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
560 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
561 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
562 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), 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 { "SysVInitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvinit_path), true },
572 { "SysVRcndPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.sysvrcnd_path), true },
577 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
582 DBusMessage *reply = NULL;
584 JobType job_type = _JOB_TYPE_INVALID;
585 bool reload_if_possible = false;
592 dbus_error_init(&error);
594 member = dbus_message_get_member(message);
596 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
600 if (!dbus_message_get_args(
603 DBUS_TYPE_STRING, &name,
605 return bus_send_error_reply(connection, message, &error, -EINVAL);
607 if (!(u = manager_get_unit(m, name))) {
608 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
609 return bus_send_error_reply(connection, message, &error, -ENOENT);
612 if (!(reply = dbus_message_new_method_return(message)))
615 if (!(path = unit_dbus_path(u)))
618 if (!dbus_message_append_args(
620 DBUS_TYPE_OBJECT_PATH, &path,
623 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
627 if (!dbus_message_get_args(
630 DBUS_TYPE_UINT32, &pid,
632 return bus_send_error_reply(connection, message, &error, -EINVAL);
634 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
635 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
636 return bus_send_error_reply(connection, message, &error, -ENOENT);
639 if (!(reply = dbus_message_new_method_return(message)))
642 if (!(path = unit_dbus_path(u)))
645 if (!dbus_message_append_args(
647 DBUS_TYPE_OBJECT_PATH, &path,
650 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
654 if (!dbus_message_get_args(
657 DBUS_TYPE_STRING, &name,
659 return bus_send_error_reply(connection, message, &error, -EINVAL);
661 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
662 return bus_send_error_reply(connection, message, &error, r);
664 if (!(reply = dbus_message_new_method_return(message)))
667 if (!(path = unit_dbus_path(u)))
670 if (!dbus_message_append_args(
672 DBUS_TYPE_OBJECT_PATH, &path,
676 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
677 job_type = JOB_START;
678 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
679 job_type = JOB_START;
680 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
682 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
683 job_type = JOB_RELOAD;
684 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
685 job_type = JOB_RESTART;
686 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
687 job_type = JOB_TRY_RESTART;
688 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
689 reload_if_possible = true;
690 job_type = JOB_RESTART;
691 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
692 reload_if_possible = true;
693 job_type = JOB_TRY_RESTART;
694 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
695 const char *name, *swho, *smode;
701 if (!dbus_message_get_args(
704 DBUS_TYPE_STRING, &name,
705 DBUS_TYPE_STRING, &swho,
706 DBUS_TYPE_STRING, &smode,
707 DBUS_TYPE_INT32, &signo,
709 return bus_send_error_reply(connection, message, &error, -EINVAL);
714 who = kill_who_from_string(swho);
716 return bus_send_error_reply(connection, message, &error, -EINVAL);
720 mode = KILL_CONTROL_GROUP;
722 mode = kill_mode_from_string(smode);
724 return bus_send_error_reply(connection, message, &error, -EINVAL);
727 if (signo <= 0 || signo >= _NSIG)
728 return bus_send_error_reply(connection, message, &error, -EINVAL);
730 if (!(u = manager_get_unit(m, name))) {
731 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
732 return bus_send_error_reply(connection, message, &error, -ENOENT);
735 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
736 return bus_send_error_reply(connection, message, &error, r);
738 if (!(reply = dbus_message_new_method_return(message)))
741 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
745 if (!dbus_message_get_args(
748 DBUS_TYPE_UINT32, &id,
750 return bus_send_error_reply(connection, message, &error, -EINVAL);
752 if (!(j = manager_get_job(m, id))) {
753 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
754 return bus_send_error_reply(connection, message, &error, -ENOENT);
757 if (!(reply = dbus_message_new_method_return(message)))
760 if (!(path = job_dbus_path(j)))
763 if (!dbus_message_append_args(
765 DBUS_TYPE_OBJECT_PATH, &path,
769 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
771 manager_clear_jobs(m);
773 if (!(reply = dbus_message_new_method_return(message)))
776 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
778 manager_reset_failed(m);
780 if (!(reply = dbus_message_new_method_return(message)))
783 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
787 if (!dbus_message_get_args(
790 DBUS_TYPE_STRING, &name,
792 return bus_send_error_reply(connection, message, &error, -EINVAL);
794 if (!(u = manager_get_unit(m, name))) {
795 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
796 return bus_send_error_reply(connection, message, &error, -ENOENT);
799 unit_reset_failed(u);
801 if (!(reply = dbus_message_new_method_return(message)))
804 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
805 DBusMessageIter iter, sub;
810 if (!(reply = dbus_message_new_method_return(message)))
813 dbus_message_iter_init_append(reply, &iter);
815 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
818 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
819 char *u_path, *j_path;
820 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
821 DBusMessageIter sub2;
828 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
831 description = unit_description(u);
832 load_state = unit_load_state_to_string(u->load_state);
833 active_state = unit_active_state_to_string(unit_active_state(u));
834 sub_state = unit_sub_state_to_string(u);
836 f = unit_following(u);
837 following = f ? f->id : "";
839 if (!(u_path = unit_dbus_path(u)))
843 job_id = (uint32_t) u->job->id;
845 if (!(j_path = job_dbus_path(u->job))) {
850 sjob_type = job_type_to_string(u->job->type);
857 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
858 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
859 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
860 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
861 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
862 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
863 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
864 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
865 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
866 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
877 if (!dbus_message_iter_close_container(&sub, &sub2))
881 if (!dbus_message_iter_close_container(&iter, &sub))
884 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
885 DBusMessageIter iter, sub;
889 if (!(reply = dbus_message_new_method_return(message)))
892 dbus_message_iter_init_append(reply, &iter);
894 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
897 HASHMAP_FOREACH(j, m->jobs, i) {
898 char *u_path, *j_path;
899 const char *state, *type;
901 DBusMessageIter sub2;
903 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
906 id = (uint32_t) j->id;
907 state = job_state_to_string(j->state);
908 type = job_type_to_string(j->type);
910 if (!(j_path = job_dbus_path(j)))
913 if (!(u_path = unit_dbus_path(j->unit))) {
918 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
919 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
920 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
921 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
922 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
923 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
932 if (!dbus_message_iter_close_container(&sub, &sub2))
936 if (!dbus_message_iter_close_container(&iter, &sub))
939 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
943 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
944 if (!(s = set_new(string_hash_func, string_compare_func)))
947 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
953 if (!(client = strdup(message_get_sender_with_fallback(message))))
956 if ((r = set_put(s, client)) < 0) {
958 return bus_send_error_reply(connection, message, NULL, r);
961 if (!(reply = dbus_message_new_method_return(message)))
964 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
967 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
968 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
969 return bus_send_error_reply(connection, message, &error, -ENOENT);
974 if (!(reply = dbus_message_new_method_return(message)))
977 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
982 if (!(reply = dbus_message_new_method_return(message)))
985 if (!(f = open_memstream(&dump, &size)))
988 manager_dump_units(m, f, NULL);
989 manager_dump_jobs(m, f, NULL);
999 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
1005 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
1007 dbus_bool_t cleanup;
1010 if (!dbus_message_get_args(
1013 DBUS_TYPE_STRING, &name,
1014 DBUS_TYPE_BOOLEAN, &cleanup,
1016 return bus_send_error_reply(connection, message, &error, -EINVAL);
1018 if (name && name[0] == 0)
1021 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1022 return bus_send_error_reply(connection, message, &error, r);
1024 if (!(reply = dbus_message_new_method_return(message)))
1027 if (!(path = unit_dbus_path(UNIT(s))))
1030 if (!dbus_message_append_args(
1032 DBUS_TYPE_OBJECT_PATH, &path,
1036 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1037 char *introspection = NULL;
1045 if (!(reply = dbus_message_new_method_return(message)))
1048 /* We roll our own introspection code here, instead of
1049 * relying on bus_default_message_handler() because we
1050 * need to generate our introspection string
1053 if (!(f = open_memstream(&introspection, &size)))
1056 fputs(INTROSPECTION_BEGIN, f);
1058 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1064 if (!(p = bus_path_escape(k))) {
1066 free(introspection);
1070 fprintf(f, "<node name=\"unit/%s\"/>", p);
1074 HASHMAP_FOREACH(j, m->jobs, i)
1075 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1077 fputs(INTROSPECTION_END, f);
1081 free(introspection);
1090 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1091 free(introspection);
1095 free(introspection);
1097 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1099 assert(!m->queued_message);
1101 /* Instead of sending the reply back right away, we
1102 * just remember that we need to and then send it
1103 * after the reload is finished. That way the caller
1104 * knows when the reload finished. */
1106 if (!(m->queued_message = dbus_message_new_method_return(message)))
1109 m->queued_message_connection = connection;
1110 m->exit_code = MANAGER_RELOAD;
1112 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1114 /* We don't send a reply back here, the client should
1115 * just wait for us disconnecting. */
1117 m->exit_code = MANAGER_REEXECUTE;
1119 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1121 if (m->running_as == MANAGER_SYSTEM) {
1122 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1123 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1126 if (!(reply = dbus_message_new_method_return(message)))
1129 m->exit_code = MANAGER_EXIT;
1131 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1133 if (m->running_as != MANAGER_SYSTEM) {
1134 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1135 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1138 if (!(reply = dbus_message_new_method_return(message)))
1141 m->exit_code = MANAGER_REBOOT;
1143 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1145 if (m->running_as != MANAGER_SYSTEM) {
1146 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1147 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1150 if (!(reply = dbus_message_new_method_return(message)))
1153 m->exit_code = MANAGER_POWEROFF;
1155 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1157 if (m->running_as != MANAGER_SYSTEM) {
1158 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1159 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1162 if (!(reply = dbus_message_new_method_return(message)))
1165 m->exit_code = MANAGER_HALT;
1167 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1169 if (m->running_as != MANAGER_SYSTEM) {
1170 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1171 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1174 if (!(reply = dbus_message_new_method_return(message)))
1177 m->exit_code = MANAGER_KEXEC;
1179 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1180 const char *switch_root, *switch_root_init;
1184 if (!dbus_message_get_args(
1187 DBUS_TYPE_STRING, &switch_root,
1188 DBUS_TYPE_STRING, &switch_root_init,
1190 return bus_send_error_reply(connection, message, &error, -EINVAL);
1192 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1193 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1195 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1196 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1198 if (m->running_as != MANAGER_SYSTEM) {
1199 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1200 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1204 if (isempty(switch_root_init))
1205 k = access(switch_root, F_OK);
1209 p = join(switch_root, "/", switch_root_init, NULL);
1213 k = access(p, X_OK);
1217 return bus_send_error_reply(connection, message, NULL, -errno);
1219 u = strdup(switch_root);
1223 if (!isempty(switch_root_init)) {
1224 v = strdup(switch_root_init);
1232 free(m->switch_root);
1233 free(m->switch_root_init);
1235 m->switch_root_init = v;
1237 reply = dbus_message_new_method_return(message);
1241 m->exit_code = MANAGER_SWITCH_ROOT;
1243 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1244 char **l = NULL, **e = NULL;
1246 if ((r = bus_parse_strv(message, &l)) < 0) {
1250 return bus_send_error_reply(connection, message, NULL, r);
1253 e = strv_env_merge(2, m->environment, l);
1259 if (!(reply = dbus_message_new_method_return(message))) {
1264 strv_free(m->environment);
1267 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1268 char **l = NULL, **e = NULL;
1270 if ((r = bus_parse_strv(message, &l)) < 0) {
1274 return bus_send_error_reply(connection, message, NULL, r);
1277 e = strv_env_delete(m->environment, 1, l);
1283 if (!(reply = dbus_message_new_method_return(message))) {
1288 strv_free(m->environment);
1291 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1292 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1293 DBusMessageIter iter;
1295 if (!dbus_message_iter_init(message, &iter))
1298 r = bus_parse_strv_iter(&iter, &l_unset);
1303 return bus_send_error_reply(connection, message, NULL, r);
1306 if (!dbus_message_iter_next(&iter)) {
1308 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1311 r = bus_parse_strv_iter(&iter, &l_set);
1317 return bus_send_error_reply(connection, message, NULL, r);
1320 e = strv_env_delete(m->environment, 1, l_unset);
1328 f = strv_env_merge(2, e, l_set);
1335 if (!(reply = dbus_message_new_method_return(message))) {
1340 strv_free(m->environment);
1342 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1343 DBusMessageIter iter, sub, sub2;
1348 reply = dbus_message_new_method_return(message);
1352 h = hashmap_new(string_hash_func, string_compare_func);
1356 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1358 unit_file_list_free(h);
1359 dbus_message_unref(reply);
1360 return bus_send_error_reply(connection, message, NULL, r);
1363 dbus_message_iter_init_append(reply, &iter);
1365 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1366 unit_file_list_free(h);
1370 HASHMAP_FOREACH(item, h, i) {
1373 state = unit_file_state_to_string(item->state);
1376 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1377 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1378 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1379 !dbus_message_iter_close_container(&sub, &sub2)) {
1380 unit_file_list_free(h);
1385 unit_file_list_free(h);
1387 if (!dbus_message_iter_close_container(&iter, &sub))
1390 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1392 UnitFileState state;
1395 if (!dbus_message_get_args(
1398 DBUS_TYPE_STRING, &name,
1400 return bus_send_error_reply(connection, message, &error, -EINVAL);
1402 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1404 return bus_send_error_reply(connection, message, NULL, state);
1406 s = unit_file_state_to_string(state);
1409 reply = dbus_message_new_method_return(message);
1413 if (!dbus_message_append_args(
1415 DBUS_TYPE_STRING, &s,
1418 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1419 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1420 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1421 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1422 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1425 DBusMessageIter iter;
1426 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1427 UnitFileChange *changes = NULL;
1428 unsigned n_changes = 0;
1429 dbus_bool_t runtime, force;
1430 int carries_install_info = -1;
1432 if (!dbus_message_iter_init(message, &iter))
1435 r = bus_parse_strv_iter(&iter, &l);
1440 return bus_send_error_reply(connection, message, NULL, r);
1443 if (!dbus_message_iter_next(&iter) ||
1444 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1445 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1447 return bus_send_error_reply(connection, message, NULL, -EIO);
1450 if (streq(member, "EnableUnitFiles")) {
1451 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1452 carries_install_info = r;
1453 } else if (streq(member, "ReenableUnitFiles")) {
1454 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1455 carries_install_info = r;
1456 } else if (streq(member, "LinkUnitFiles"))
1457 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1458 else if (streq(member, "PresetUnitFiles")) {
1459 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1460 carries_install_info = r;
1461 } else if (streq(member, "MaskUnitFiles"))
1462 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1464 assert_not_reached("Uh? Wrong method");
1467 bus_manager_send_unit_files_changed(m);
1470 unit_file_changes_free(changes, n_changes);
1471 return bus_send_error_reply(connection, message, NULL, r);
1474 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1475 unit_file_changes_free(changes, n_changes);
1480 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1481 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1484 DBusMessageIter iter;
1485 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1486 UnitFileChange *changes = NULL;
1487 unsigned n_changes = 0;
1488 dbus_bool_t runtime;
1490 if (!dbus_message_iter_init(message, &iter))
1493 r = bus_parse_strv_iter(&iter, &l);
1498 return bus_send_error_reply(connection, message, NULL, r);
1501 if (!dbus_message_iter_next(&iter) ||
1502 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1504 return bus_send_error_reply(connection, message, NULL, -EIO);
1507 if (streq(member, "DisableUnitFiles"))
1508 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1509 else if (streq(member, "UnmaskUnitFiles"))
1510 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1512 assert_not_reached("Uh? Wrong method");
1515 bus_manager_send_unit_files_changed(m);
1518 unit_file_changes_free(changes, n_changes);
1519 return bus_send_error_reply(connection, message, NULL, r);
1522 reply = message_from_file_changes(message, changes, n_changes, -1);
1523 unit_file_changes_free(changes, n_changes);
1529 const BusBoundProperties bps[] = {
1530 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1531 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1534 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1537 if (job_type != _JOB_TYPE_INVALID) {
1538 const char *name, *smode, *old_name = NULL;
1545 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1546 b = dbus_message_get_args(
1549 DBUS_TYPE_STRING, &old_name,
1550 DBUS_TYPE_STRING, &name,
1551 DBUS_TYPE_STRING, &smode,
1554 b = dbus_message_get_args(
1557 DBUS_TYPE_STRING, &name,
1558 DBUS_TYPE_STRING, &smode,
1562 return bus_send_error_reply(connection, message, &error, -EINVAL);
1565 if (!(u = manager_get_unit(m, old_name)) ||
1567 u->job->type != JOB_START) {
1568 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1569 return bus_send_error_reply(connection, message, &error, -ENOENT);
1573 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1574 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1575 return bus_send_error_reply(connection, message, &error, -EINVAL);
1578 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1579 return bus_send_error_reply(connection, message, &error, r);
1581 if (reload_if_possible && unit_can_reload(u)) {
1582 if (job_type == JOB_RESTART)
1583 job_type = JOB_RELOAD_OR_START;
1584 else if (job_type == JOB_TRY_RESTART)
1585 job_type = JOB_RELOAD;
1588 if (job_type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) {
1589 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
1590 return bus_send_error_reply(connection, message, &error, -EPERM);
1593 if ((job_type == JOB_START && u->refuse_manual_start) ||
1594 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1595 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1596 (u->refuse_manual_start || u->refuse_manual_stop))) {
1597 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1598 return bus_send_error_reply(connection, message, &error, -EPERM);
1601 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1602 return bus_send_error_reply(connection, message, &error, r);
1604 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1608 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1610 if (!(reply = dbus_message_new_method_return(message)))
1613 if (!(path = job_dbus_path(j)))
1616 if (!dbus_message_append_args(
1618 DBUS_TYPE_OBJECT_PATH, &path,
1624 if (!dbus_connection_send(connection, reply, NULL))
1627 dbus_message_unref(reply);
1632 return DBUS_HANDLER_RESULT_HANDLED;
1638 dbus_message_unref(reply);
1640 dbus_error_free(&error);
1642 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1645 const DBusObjectPathVTable bus_manager_vtable = {
1646 .message_function = bus_manager_message_handler