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 #define BUS_MANAGER_INTERFACE_END \
256 #define BUS_MANAGER_INTERFACE \
257 BUS_MANAGER_INTERFACE_BEGIN \
258 BUS_MANAGER_INTERFACE_METHODS \
259 BUS_MANAGER_INTERFACE_SIGNALS \
260 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
261 BUS_MANAGER_INTERFACE_END
263 #define INTROSPECTION_BEGIN \
264 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
266 BUS_MANAGER_INTERFACE \
267 BUS_PROPERTIES_INTERFACE \
269 BUS_INTROSPECTABLE_INTERFACE
271 #define INTROSPECTION_END \
274 #define INTERFACES_LIST \
275 BUS_GENERIC_INTERFACES_LIST \
276 "org.freedesktop.systemd1.Manager\0"
278 const char bus_manager_interface[] _introspect_("Manager") = BUS_MANAGER_INTERFACE;
280 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output, exec_output, ExecOutput);
282 static int bus_manager_append_tainted(DBusMessageIter *i, const char *property, void *data) {
285 char buf[LINE_MAX] = "", *e = buf, *p = NULL;
292 e = stpcpy(e, "split-usr:");
294 if (readlink_malloc("/etc/mtab", &p) < 0)
295 e = stpcpy(e, "mtab-not-symlink:");
299 if (access("/proc/cgroups", F_OK) < 0)
300 e = stpcpy(e, "cgroups-missing:");
302 if (hwclock_is_localtime() > 0)
303 e = stpcpy(e, "local-hwclock:");
305 /* remove the last ':' */
311 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
317 static int bus_manager_append_log_target(DBusMessageIter *i, const char *property, void *data) {
323 t = log_target_to_string(log_get_target());
325 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
331 static int bus_manager_set_log_target(DBusMessageIter *i, const char *property, void *data) {
337 dbus_message_iter_get_basic(i, &t);
339 return log_set_target_from_string(t);
342 static int bus_manager_append_log_level(DBusMessageIter *i, const char *property, void *data) {
348 t = log_level_to_string(log_get_max_level());
350 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_STRING, &t))
356 static int bus_manager_set_log_level(DBusMessageIter *i, const char *property, void *data) {
362 dbus_message_iter_get_basic(i, &t);
364 return log_set_max_level_from_string(t);
367 static int bus_manager_append_n_names(DBusMessageIter *i, const char *property, void *data) {
375 u = hashmap_size(m->units);
377 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
383 static int bus_manager_append_n_jobs(DBusMessageIter *i, const char *property, void *data) {
391 u = hashmap_size(m->jobs);
393 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_UINT32, &u))
399 static int bus_manager_append_progress(DBusMessageIter *i, const char *property, void *data) {
407 if (dual_timestamp_is_set(&m->finish_timestamp))
410 d = 1.0 - ((double) hashmap_size(m->jobs) / (double) m->n_installed_jobs);
412 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_DOUBLE, &d))
418 static const char *message_get_sender_with_fallback(DBusMessage *m) {
423 if ((s = dbus_message_get_sender(m)))
426 /* When the message came in from a direct connection the
427 * message will have no sender. We fix that here. */
432 static DBusMessage *message_from_file_changes(
434 UnitFileChange *changes,
436 int carries_install_info) {
438 DBusMessageIter iter, sub, sub2;
442 reply = dbus_message_new_method_return(m);
446 dbus_message_iter_init_append(reply, &iter);
448 if (carries_install_info >= 0) {
451 b = !!carries_install_info;
452 if (!dbus_message_iter_append_basic(&iter, DBUS_TYPE_BOOLEAN, &b))
456 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(sss)", &sub))
459 for (i = 0; i < n_changes; i++) {
460 const char *type, *path, *source;
462 type = unit_file_change_type_to_string(changes[i].type);
463 path = strempty(changes[i].path);
464 source = strempty(changes[i].source);
466 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
467 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
468 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &path) ||
469 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &source) ||
470 !dbus_message_iter_close_container(&sub, &sub2))
474 if (!dbus_message_iter_close_container(&iter, &sub))
480 dbus_message_unref(reply);
484 static int bus_manager_send_unit_files_changed(Manager *m) {
488 s = dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
492 r = bus_broadcast(m, s);
493 dbus_message_unref(s);
498 static int bus_manager_append_have_watchdog(DBusMessageIter *i, const char *property, void *data) {
504 b = access("/dev/watchdog", F_OK) >= 0;
506 if (!dbus_message_iter_append_basic(i, DBUS_TYPE_BOOLEAN, &b))
512 static int bus_manager_set_runtime_watchdog_usec(DBusMessageIter *i, const char *property, void *data) {
518 dbus_message_iter_get_basic(i, t);
520 return watchdog_set_timeout(t);
523 static const char systemd_property_string[] =
528 static const BusProperty bus_systemd_properties[] = {
529 { "Version", bus_property_append_string, "s", 0 },
530 { "Distribution", bus_property_append_string, "s", sizeof(PACKAGE_STRING) },
531 { "Features", bus_property_append_string, "s", sizeof(PACKAGE_STRING) + sizeof(DISTRIBUTION) },
535 static const BusProperty bus_manager_properties[] = {
536 { "Tainted", bus_manager_append_tainted, "s", 0 },
537 { "InitRDTimestamp", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.realtime) },
538 { "InitRDTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, initrd_timestamp.monotonic) },
539 { "StartupTimestamp", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.realtime) },
540 { "StartupTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, startup_timestamp.monotonic) },
541 { "FinishTimestamp", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.realtime) },
542 { "FinishTimestampMonotonic", bus_property_append_uint64, "t", offsetof(Manager, finish_timestamp.monotonic) },
543 { "LogLevel", bus_manager_append_log_level, "s", 0, false, bus_manager_set_log_level },
544 { "LogTarget", bus_manager_append_log_target, "s", 0, false, bus_manager_set_log_target },
545 { "NNames", bus_manager_append_n_names, "u", 0 },
546 { "NJobs", bus_manager_append_n_jobs, "u", 0 },
547 { "NInstalledJobs",bus_property_append_uint32, "u", offsetof(Manager, n_installed_jobs) },
548 { "NFailedJobs", bus_property_append_uint32, "u", offsetof(Manager, n_failed_jobs) },
549 { "Progress", bus_manager_append_progress, "d", 0 },
550 { "Environment", bus_property_append_strv, "as", offsetof(Manager, environment), true },
551 { "ConfirmSpawn", bus_property_append_bool, "b", offsetof(Manager, confirm_spawn) },
552 { "ShowStatus", bus_property_append_bool, "b", offsetof(Manager, show_status) },
553 { "UnitPath", bus_property_append_strv, "as", offsetof(Manager, lookup_paths.unit_path), true },
554 { "ControlGroupHierarchy", bus_property_append_string, "s", offsetof(Manager, cgroup_hierarchy), true },
555 { "DefaultControllers", bus_property_append_strv, "as", offsetof(Manager, default_controllers), true },
556 { "DefaultStandardOutput", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_output) },
557 { "DefaultStandardError", bus_manager_append_exec_output, "s", offsetof(Manager, default_std_error) },
558 { "RuntimeWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, runtime_watchdog), false, bus_manager_set_runtime_watchdog_usec },
559 { "ShutdownWatchdogUSec", bus_property_append_usec, "t", offsetof(Manager, shutdown_watchdog), false, bus_property_set_usec },
560 { "HaveWatchdog", bus_manager_append_have_watchdog, "b", 0 },
564 static DBusHandlerResult bus_manager_message_handler(DBusConnection *connection, DBusMessage *message, void *data) {
569 DBusMessage *reply = NULL;
571 JobType job_type = _JOB_TYPE_INVALID;
572 bool reload_if_possible = false;
579 dbus_error_init(&error);
581 member = dbus_message_get_member(message);
583 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnit")) {
587 if (!dbus_message_get_args(
590 DBUS_TYPE_STRING, &name,
592 return bus_send_error_reply(connection, message, &error, -EINVAL);
594 if (!(u = manager_get_unit(m, name))) {
595 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
596 return bus_send_error_reply(connection, message, &error, -ENOENT);
599 if (!(reply = dbus_message_new_method_return(message)))
602 if (!(path = unit_dbus_path(u)))
605 if (!dbus_message_append_args(
607 DBUS_TYPE_OBJECT_PATH, &path,
610 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
614 if (!dbus_message_get_args(
617 DBUS_TYPE_UINT32, &pid,
619 return bus_send_error_reply(connection, message, &error, -EINVAL);
621 if (!(u = cgroup_unit_by_pid(m, (pid_t) pid))) {
622 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "No unit for PID %lu is loaded.", (unsigned long) pid);
623 return bus_send_error_reply(connection, message, &error, -ENOENT);
626 if (!(reply = dbus_message_new_method_return(message)))
629 if (!(path = unit_dbus_path(u)))
632 if (!dbus_message_append_args(
634 DBUS_TYPE_OBJECT_PATH, &path,
637 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
641 if (!dbus_message_get_args(
644 DBUS_TYPE_STRING, &name,
646 return bus_send_error_reply(connection, message, &error, -EINVAL);
648 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
649 return bus_send_error_reply(connection, message, &error, r);
651 if (!(reply = dbus_message_new_method_return(message)))
654 if (!(path = unit_dbus_path(u)))
657 if (!dbus_message_append_args(
659 DBUS_TYPE_OBJECT_PATH, &path,
663 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnit"))
664 job_type = JOB_START;
665 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
666 job_type = JOB_START;
667 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StopUnit"))
669 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
670 job_type = JOB_RELOAD;
671 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "RestartUnit"))
672 job_type = JOB_RESTART;
673 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
674 job_type = JOB_TRY_RESTART;
675 else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
676 reload_if_possible = true;
677 job_type = JOB_RESTART;
678 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
679 reload_if_possible = true;
680 job_type = JOB_TRY_RESTART;
681 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KillUnit")) {
682 const char *name, *swho, *smode;
688 if (!dbus_message_get_args(
691 DBUS_TYPE_STRING, &name,
692 DBUS_TYPE_STRING, &swho,
693 DBUS_TYPE_STRING, &smode,
694 DBUS_TYPE_INT32, &signo,
696 return bus_send_error_reply(connection, message, &error, -EINVAL);
701 who = kill_who_from_string(swho);
703 return bus_send_error_reply(connection, message, &error, -EINVAL);
707 mode = KILL_CONTROL_GROUP;
709 mode = kill_mode_from_string(smode);
711 return bus_send_error_reply(connection, message, &error, -EINVAL);
714 if (signo <= 0 || signo >= _NSIG)
715 return bus_send_error_reply(connection, message, &error, -EINVAL);
717 if (!(u = manager_get_unit(m, name))) {
718 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
719 return bus_send_error_reply(connection, message, &error, -ENOENT);
722 if ((r = unit_kill(u, who, mode, signo, &error)) < 0)
723 return bus_send_error_reply(connection, message, &error, r);
725 if (!(reply = dbus_message_new_method_return(message)))
728 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetJob")) {
732 if (!dbus_message_get_args(
735 DBUS_TYPE_UINT32, &id,
737 return bus_send_error_reply(connection, message, &error, -EINVAL);
739 if (!(j = manager_get_job(m, id))) {
740 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "Job %u does not exist.", (unsigned) id);
741 return bus_send_error_reply(connection, message, &error, -ENOENT);
744 if (!(reply = dbus_message_new_method_return(message)))
747 if (!(path = job_dbus_path(j)))
750 if (!dbus_message_append_args(
752 DBUS_TYPE_OBJECT_PATH, &path,
756 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
758 manager_clear_jobs(m);
760 if (!(reply = dbus_message_new_method_return(message)))
763 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
765 manager_reset_failed(m);
767 if (!(reply = dbus_message_new_method_return(message)))
770 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
774 if (!dbus_message_get_args(
777 DBUS_TYPE_STRING, &name,
779 return bus_send_error_reply(connection, message, &error, -EINVAL);
781 if (!(u = manager_get_unit(m, name))) {
782 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s is not loaded.", name);
783 return bus_send_error_reply(connection, message, &error, -ENOENT);
786 unit_reset_failed(u);
788 if (!(reply = dbus_message_new_method_return(message)))
791 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnits")) {
792 DBusMessageIter iter, sub;
797 if (!(reply = dbus_message_new_method_return(message)))
800 dbus_message_iter_init_append(reply, &iter);
802 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ssssssouso)", &sub))
805 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
806 char *u_path, *j_path;
807 const char *description, *load_state, *active_state, *sub_state, *sjob_type, *following;
808 DBusMessageIter sub2;
815 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
818 description = unit_description(u);
819 load_state = unit_load_state_to_string(u->load_state);
820 active_state = unit_active_state_to_string(unit_active_state(u));
821 sub_state = unit_sub_state_to_string(u);
823 f = unit_following(u);
824 following = f ? f->id : "";
826 if (!(u_path = unit_dbus_path(u)))
830 job_id = (uint32_t) u->job->id;
832 if (!(j_path = job_dbus_path(u->job))) {
837 sjob_type = job_type_to_string(u->job->type);
844 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &u->id) ||
845 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &description) ||
846 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &load_state) ||
847 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &active_state) ||
848 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sub_state) ||
849 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &following) ||
850 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path) ||
851 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &job_id) ||
852 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &sjob_type) ||
853 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path)) {
864 if (!dbus_message_iter_close_container(&sub, &sub2))
868 if (!dbus_message_iter_close_container(&iter, &sub))
871 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListJobs")) {
872 DBusMessageIter iter, sub;
876 if (!(reply = dbus_message_new_method_return(message)))
879 dbus_message_iter_init_append(reply, &iter);
881 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(usssoo)", &sub))
884 HASHMAP_FOREACH(j, m->jobs, i) {
885 char *u_path, *j_path;
886 const char *state, *type;
888 DBusMessageIter sub2;
890 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2))
893 id = (uint32_t) j->id;
894 state = job_state_to_string(j->state);
895 type = job_type_to_string(j->type);
897 if (!(j_path = job_dbus_path(j)))
900 if (!(u_path = unit_dbus_path(j->unit))) {
905 if (!dbus_message_iter_append_basic(&sub2, DBUS_TYPE_UINT32, &id) ||
906 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &j->unit->id) ||
907 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &type) ||
908 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
909 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &j_path) ||
910 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_OBJECT_PATH, &u_path)) {
919 if (!dbus_message_iter_close_container(&sub, &sub2))
923 if (!dbus_message_iter_close_container(&iter, &sub))
926 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Subscribe")) {
930 if (!(s = BUS_CONNECTION_SUBSCRIBED(m, connection))) {
931 if (!(s = set_new(string_hash_func, string_compare_func)))
934 if (!(dbus_connection_set_data(connection, m->subscribed_data_slot, s, NULL))) {
940 if (!(client = strdup(message_get_sender_with_fallback(message))))
943 if ((r = set_put(s, client)) < 0) {
945 return bus_send_error_reply(connection, message, NULL, r);
948 if (!(reply = dbus_message_new_method_return(message)))
951 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
954 if (!(client = set_remove(BUS_CONNECTION_SUBSCRIBED(m, connection), (char*) message_get_sender_with_fallback(message)))) {
955 dbus_set_error(&error, BUS_ERROR_NOT_SUBSCRIBED, "Client is not subscribed.");
956 return bus_send_error_reply(connection, message, &error, -ENOENT);
961 if (!(reply = dbus_message_new_method_return(message)))
964 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Dump")) {
969 if (!(reply = dbus_message_new_method_return(message)))
972 if (!(f = open_memstream(&dump, &size)))
975 manager_dump_units(m, f, NULL);
976 manager_dump_jobs(m, f, NULL);
986 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &dump, DBUS_TYPE_INVALID)) {
992 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
997 if (!dbus_message_get_args(
1000 DBUS_TYPE_STRING, &name,
1001 DBUS_TYPE_BOOLEAN, &cleanup,
1003 return bus_send_error_reply(connection, message, &error, -EINVAL);
1005 if (name && name[0] == 0)
1008 if ((r = snapshot_create(m, name, cleanup, &error, &s)) < 0)
1009 return bus_send_error_reply(connection, message, &error, r);
1011 if (!(reply = dbus_message_new_method_return(message)))
1014 if (!(path = unit_dbus_path(UNIT(s))))
1017 if (!dbus_message_append_args(
1019 DBUS_TYPE_OBJECT_PATH, &path,
1023 } else if (dbus_message_is_method_call(message, "org.freedesktop.DBus.Introspectable", "Introspect")) {
1024 char *introspection = NULL;
1032 if (!(reply = dbus_message_new_method_return(message)))
1035 /* We roll our own introspection code here, instead of
1036 * relying on bus_default_message_handler() because we
1037 * need to generate our introspection string
1040 if (!(f = open_memstream(&introspection, &size)))
1043 fputs(INTROSPECTION_BEGIN, f);
1045 HASHMAP_FOREACH_KEY(u, k, m->units, i) {
1051 if (!(p = bus_path_escape(k))) {
1053 free(introspection);
1057 fprintf(f, "<node name=\"unit/%s\"/>", p);
1061 HASHMAP_FOREACH(j, m->jobs, i)
1062 fprintf(f, "<node name=\"job/%lu\"/>", (unsigned long) j->id);
1064 fputs(INTROSPECTION_END, f);
1068 free(introspection);
1077 if (!dbus_message_append_args(reply, DBUS_TYPE_STRING, &introspection, DBUS_TYPE_INVALID)) {
1078 free(introspection);
1082 free(introspection);
1084 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reload")) {
1086 assert(!m->queued_message);
1088 /* Instead of sending the reply back right away, we
1089 * just remember that we need to and then send it
1090 * after the reload is finished. That way the caller
1091 * knows when the reload finished. */
1093 if (!(m->queued_message = dbus_message_new_method_return(message)))
1096 m->queued_message_connection = connection;
1097 m->exit_code = MANAGER_RELOAD;
1099 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1101 /* We don't send a reply back here, the client should
1102 * just wait for us disconnecting. */
1104 m->exit_code = MANAGER_REEXECUTE;
1106 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Exit")) {
1108 if (m->running_as == MANAGER_SYSTEM) {
1109 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Exit is only supported for user service managers.");
1110 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1113 if (!(reply = dbus_message_new_method_return(message)))
1116 m->exit_code = MANAGER_EXIT;
1118 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Reboot")) {
1120 if (m->running_as != MANAGER_SYSTEM) {
1121 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Reboot is only supported for system managers.");
1122 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1125 if (!(reply = dbus_message_new_method_return(message)))
1128 m->exit_code = MANAGER_REBOOT;
1130 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1132 if (m->running_as != MANAGER_SYSTEM) {
1133 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Powering off is only supported for system managers.");
1134 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1137 if (!(reply = dbus_message_new_method_return(message)))
1140 m->exit_code = MANAGER_POWEROFF;
1142 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "Halt")) {
1144 if (m->running_as != MANAGER_SYSTEM) {
1145 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Halting is only supported for system managers.");
1146 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1149 if (!(reply = dbus_message_new_method_return(message)))
1152 m->exit_code = MANAGER_HALT;
1154 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "KExec")) {
1156 if (m->running_as != MANAGER_SYSTEM) {
1157 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "kexec is only supported for system managers.");
1158 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1161 if (!(reply = dbus_message_new_method_return(message)))
1164 m->exit_code = MANAGER_KEXEC;
1166 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SwitchRoot")) {
1167 const char *switch_root, *switch_root_init;
1171 if (!dbus_message_get_args(
1174 DBUS_TYPE_STRING, &switch_root,
1175 DBUS_TYPE_STRING, &switch_root_init,
1177 return bus_send_error_reply(connection, message, &error, -EINVAL);
1179 if (path_equal(switch_root, "/") || !path_is_absolute(switch_root))
1180 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1182 if (!isempty(switch_root_init) && !path_is_absolute(switch_root_init))
1183 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1185 if (m->running_as != MANAGER_SYSTEM) {
1186 dbus_set_error(&error, BUS_ERROR_NOT_SUPPORTED, "Switching root is only supported for system managers.");
1187 return bus_send_error_reply(connection, message, &error, -ENOTSUP);
1191 if (isempty(switch_root_init))
1192 k = access(switch_root, F_OK);
1196 p = join(switch_root, "/", switch_root_init, NULL);
1200 k = access(p, X_OK);
1204 return bus_send_error_reply(connection, message, NULL, -errno);
1206 u = strdup(switch_root);
1210 if (!isempty(switch_root_init)) {
1211 v = strdup(switch_root_init);
1219 free(m->switch_root);
1220 free(m->switch_root_init);
1222 m->switch_root_init = v;
1224 reply = dbus_message_new_method_return(message);
1228 m->exit_code = MANAGER_SWITCH_ROOT;
1230 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1231 char **l = NULL, **e = NULL;
1233 if ((r = bus_parse_strv(message, &l)) < 0) {
1237 return bus_send_error_reply(connection, message, NULL, r);
1240 e = strv_env_merge(2, m->environment, l);
1246 if (!(reply = dbus_message_new_method_return(message))) {
1251 strv_free(m->environment);
1254 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1255 char **l = NULL, **e = NULL;
1257 if ((r = bus_parse_strv(message, &l)) < 0) {
1261 return bus_send_error_reply(connection, message, NULL, r);
1264 e = strv_env_delete(m->environment, 1, l);
1270 if (!(reply = dbus_message_new_method_return(message))) {
1275 strv_free(m->environment);
1278 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1279 char **l_set = NULL, **l_unset = NULL, **e = NULL, **f = NULL;
1280 DBusMessageIter iter;
1282 if (!dbus_message_iter_init(message, &iter))
1285 r = bus_parse_strv_iter(&iter, &l_unset);
1290 return bus_send_error_reply(connection, message, NULL, r);
1293 if (!dbus_message_iter_next(&iter)) {
1295 return bus_send_error_reply(connection, message, NULL, -EINVAL);
1298 r = bus_parse_strv_iter(&iter, &l_set);
1304 return bus_send_error_reply(connection, message, NULL, r);
1307 e = strv_env_delete(m->environment, 1, l_unset);
1315 f = strv_env_merge(2, e, l_set);
1322 if (!(reply = dbus_message_new_method_return(message))) {
1327 strv_free(m->environment);
1329 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1330 DBusMessageIter iter, sub, sub2;
1335 reply = dbus_message_new_method_return(message);
1339 h = hashmap_new(string_hash_func, string_compare_func);
1343 r = unit_file_get_list(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, h);
1345 unit_file_list_free(h);
1346 dbus_message_unref(reply);
1347 return bus_send_error_reply(connection, message, NULL, r);
1350 dbus_message_iter_init_append(reply, &iter);
1352 if (!dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(ss)", &sub)) {
1353 unit_file_list_free(h);
1357 HASHMAP_FOREACH(item, h, i) {
1360 state = unit_file_state_to_string(item->state);
1363 if (!dbus_message_iter_open_container(&sub, DBUS_TYPE_STRUCT, NULL, &sub2) ||
1364 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &item->path) ||
1365 !dbus_message_iter_append_basic(&sub2, DBUS_TYPE_STRING, &state) ||
1366 !dbus_message_iter_close_container(&sub, &sub2)) {
1367 unit_file_list_free(h);
1372 unit_file_list_free(h);
1374 if (!dbus_message_iter_close_container(&iter, &sub))
1377 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1379 UnitFileState state;
1382 if (!dbus_message_get_args(
1385 DBUS_TYPE_STRING, &name,
1387 return bus_send_error_reply(connection, message, &error, -EINVAL);
1389 state = unit_file_get_state(m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER, NULL, name);
1391 return bus_send_error_reply(connection, message, NULL, state);
1393 s = unit_file_state_to_string(state);
1396 reply = dbus_message_new_method_return(message);
1400 if (!dbus_message_append_args(
1402 DBUS_TYPE_STRING, &s,
1405 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1406 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1407 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1408 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1409 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1412 DBusMessageIter iter;
1413 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1414 UnitFileChange *changes = NULL;
1415 unsigned n_changes = 0;
1416 dbus_bool_t runtime, force;
1417 int carries_install_info = -1;
1419 if (!dbus_message_iter_init(message, &iter))
1422 r = bus_parse_strv_iter(&iter, &l);
1427 return bus_send_error_reply(connection, message, NULL, r);
1430 if (!dbus_message_iter_next(&iter) ||
1431 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, true) < 0 ||
1432 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &force, false) < 0) {
1434 return bus_send_error_reply(connection, message, NULL, -EIO);
1437 if (streq(member, "EnableUnitFiles")) {
1438 r = unit_file_enable(scope, runtime, NULL, l, force, &changes, &n_changes);
1439 carries_install_info = r;
1440 } else if (streq(member, "ReenableUnitFiles")) {
1441 r = unit_file_reenable(scope, runtime, NULL, l, force, &changes, &n_changes);
1442 carries_install_info = r;
1443 } else if (streq(member, "LinkUnitFiles"))
1444 r = unit_file_link(scope, runtime, NULL, l, force, &changes, &n_changes);
1445 else if (streq(member, "PresetUnitFiles")) {
1446 r = unit_file_preset(scope, runtime, NULL, l, force, &changes, &n_changes);
1447 carries_install_info = r;
1448 } else if (streq(member, "MaskUnitFiles"))
1449 r = unit_file_mask(scope, runtime, NULL, l, force, &changes, &n_changes);
1451 assert_not_reached("Uh? Wrong method");
1454 bus_manager_send_unit_files_changed(m);
1457 unit_file_changes_free(changes, n_changes);
1458 return bus_send_error_reply(connection, message, NULL, r);
1461 reply = message_from_file_changes(message, changes, n_changes, carries_install_info);
1462 unit_file_changes_free(changes, n_changes);
1467 } else if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1468 dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1471 DBusMessageIter iter;
1472 UnitFileScope scope = m->running_as == MANAGER_SYSTEM ? UNIT_FILE_SYSTEM : UNIT_FILE_USER;
1473 UnitFileChange *changes = NULL;
1474 unsigned n_changes = 0;
1475 dbus_bool_t runtime;
1477 if (!dbus_message_iter_init(message, &iter))
1480 r = bus_parse_strv_iter(&iter, &l);
1485 return bus_send_error_reply(connection, message, NULL, r);
1488 if (!dbus_message_iter_next(&iter) ||
1489 bus_iter_get_basic_and_next(&iter, DBUS_TYPE_BOOLEAN, &runtime, false) < 0) {
1491 return bus_send_error_reply(connection, message, NULL, -EIO);
1494 if (streq(member, "DisableUnitFiles"))
1495 r = unit_file_disable(scope, runtime, NULL, l, &changes, &n_changes);
1496 else if (streq(member, "UnmaskUnitFiles"))
1497 r = unit_file_unmask(scope, runtime, NULL, l, &changes, &n_changes);
1499 assert_not_reached("Uh? Wrong method");
1502 bus_manager_send_unit_files_changed(m);
1505 unit_file_changes_free(changes, n_changes);
1506 return bus_send_error_reply(connection, message, NULL, r);
1509 reply = message_from_file_changes(message, changes, n_changes, -1);
1510 unit_file_changes_free(changes, n_changes);
1516 const BusBoundProperties bps[] = {
1517 { "org.freedesktop.systemd1.Manager", bus_systemd_properties, systemd_property_string },
1518 { "org.freedesktop.systemd1.Manager", bus_manager_properties, m },
1521 return bus_default_message_handler(connection, message, NULL, INTERFACES_LIST, bps);
1524 if (job_type != _JOB_TYPE_INVALID) {
1525 const char *name, *smode, *old_name = NULL;
1532 if (dbus_message_is_method_call(message, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1533 b = dbus_message_get_args(
1536 DBUS_TYPE_STRING, &old_name,
1537 DBUS_TYPE_STRING, &name,
1538 DBUS_TYPE_STRING, &smode,
1541 b = dbus_message_get_args(
1544 DBUS_TYPE_STRING, &name,
1545 DBUS_TYPE_STRING, &smode,
1549 return bus_send_error_reply(connection, message, &error, -EINVAL);
1552 if (!(u = manager_get_unit(m, old_name)) ||
1554 u->job->type != JOB_START) {
1555 dbus_set_error(&error, BUS_ERROR_NO_SUCH_JOB, "No job queued for unit %s", old_name);
1556 return bus_send_error_reply(connection, message, &error, -ENOENT);
1560 if ((mode = job_mode_from_string(smode)) == _JOB_MODE_INVALID) {
1561 dbus_set_error(&error, BUS_ERROR_INVALID_JOB_MODE, "Job mode %s is invalid.", smode);
1562 return bus_send_error_reply(connection, message, &error, -EINVAL);
1565 if ((r = manager_load_unit(m, name, NULL, &error, &u)) < 0)
1566 return bus_send_error_reply(connection, message, &error, r);
1568 if (reload_if_possible && unit_can_reload(u)) {
1569 if (job_type == JOB_RESTART)
1570 job_type = JOB_RELOAD_OR_START;
1571 else if (job_type == JOB_TRY_RESTART)
1572 job_type = JOB_RELOAD;
1575 if (job_type == JOB_STOP && u->load_state == UNIT_ERROR && unit_active_state(u) == UNIT_INACTIVE) {
1576 dbus_set_error(&error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", name);
1577 return bus_send_error_reply(connection, message, &error, -EPERM);
1580 if ((job_type == JOB_START && u->refuse_manual_start) ||
1581 (job_type == JOB_STOP && u->refuse_manual_stop) ||
1582 ((job_type == JOB_RESTART || job_type == JOB_TRY_RESTART) &&
1583 (u->refuse_manual_start || u->refuse_manual_stop))) {
1584 dbus_set_error(&error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, may be requested by dependency only.");
1585 return bus_send_error_reply(connection, message, &error, -EPERM);
1588 if ((r = manager_add_job(m, job_type, u, mode, true, &error, &j)) < 0)
1589 return bus_send_error_reply(connection, message, &error, r);
1591 cl = job_bus_client_new(connection, message_get_sender_with_fallback(message));
1595 LIST_PREPEND(JobBusClient, client, j->bus_client_list, cl);
1597 if (!(reply = dbus_message_new_method_return(message)))
1600 if (!(path = job_dbus_path(j)))
1603 if (!dbus_message_append_args(
1605 DBUS_TYPE_OBJECT_PATH, &path,
1611 if (!dbus_connection_send(connection, reply, NULL))
1614 dbus_message_unref(reply);
1619 return DBUS_HANDLER_RESULT_HANDLED;
1625 dbus_message_unref(reply);
1627 dbus_error_free(&error);
1629 return DBUS_HANDLER_RESULT_NEED_MEMORY;
1632 const DBusObjectPathVTable bus_manager_vtable = {
1633 .message_function = bus_manager_message_handler