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 General Public License as published by
10 the Free Software Foundation; either version 2 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 General Public License for more details.
18 You should have received a copy of the GNU 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"
34 #define BUS_MANAGER_INTERFACE_BEGIN \
35 " <interface name=\"org.freedesktop.systemd1.Manager\">\n"
37 #define BUS_MANAGER_INTERFACE_METHODS \
38 " <method name=\"GetUnit\">\n" \
39 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
40 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
42 " <method name=\"GetUnitByPID\">\n" \
43 " <arg name=\"pid\" type=\"u\" direction=\"in\"/>\n" \
44 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
46 " <method name=\"LoadUnit\">\n" \
47 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
48 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
50 " <method name=\"StartUnit\">\n" \
51 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
52 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
53 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
55 " <method name=\"StartUnitReplace\">\n" \
56 " <arg name=\"old_unit\" type=\"s\" direction=\"in\"/>\n" \
57 " <arg name=\"new_unit\" type=\"s\" direction=\"in\"/>\n" \
58 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
59 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
61 " <method name=\"StopUnit\">\n" \
62 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
63 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
64 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
66 " <method name=\"ReloadUnit\">\n" \
67 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
68 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
69 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
71 " <method name=\"RestartUnit\">\n" \
72 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
73 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
74 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
76 " <method name=\"TryRestartUnit\">\n" \
77 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
78 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
79 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
81 " <method name=\"ReloadOrRestartUnit\">\n" \
82 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
83 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
84 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
86 " <method name=\"ReloadOrTryRestartUnit\">\n" \
87 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
88 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
89 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
91 " <method name=\"KillUnit\">\n" \
92 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
93 " <arg name=\"who\" type=\"s\" direction=\"in\"/>\n" \
94 " <arg name=\"mode\" type=\"s\" direction=\"in\"/>\n" \
95 " <arg name=\"signal\" type=\"i\" direction=\"in\"/>\n" \
97 " <method name=\"ResetFailedUnit\">\n" \
98 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
100 " <method name=\"GetJob\">\n" \
101 " <arg name=\"id\" type=\"u\" direction=\"in\"/>\n" \
102 " <arg name=\"job\" type=\"o\" direction=\"out\"/>\n" \
104 " <method name=\"ClearJobs\"/>\n" \
105 " <method name=\"ResetFailed\"/>\n" \
106 " <method name=\"ListUnits\">\n" \
107 " <arg name=\"units\" type=\"a(ssssssouso)\" direction=\"out\"/>\n" \
109 " <method name=\"ListJobs\">\n" \
110 " <arg name=\"jobs\" type=\"a(usssoo)\" direction=\"out\"/>\n" \
112 " <method name=\"Subscribe\"/>\n" \
113 " <method name=\"Unsubscribe\"/>\n" \
114 " <method name=\"Dump\"/>\n" \
115 " <method name=\"CreateSnapshot\">\n" \
116 " <arg name=\"name\" type=\"s\" direction=\"in\"/>\n" \
117 " <arg name=\"cleanup\" type=\"b\" direction=\"in\"/>\n" \
118 " <arg name=\"unit\" type=\"o\" direction=\"out\"/>\n" \
120 " <method name=\"Reload\"/>\n" \
121 " <method name=\"Reexecute\"/>\n" \
122 " <method name=\"Exit\"/>\n" \
123 " <method name=\"Reboot\"/>\n" \
124 " <method name=\"PowerOff\"/>\n" \
125 " <method name=\"Halt\"/>\n" \
126 " <method name=\"KExec\"/>\n" \
127 " <method name=\"SetEnvironment\">\n" \
128 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
130 " <method name=\"UnsetEnvironment\">\n" \
131 " <arg name=\"names\" type=\"as\" direction=\"in\"/>\n" \
133 " <method name=\"UnsetAndSetEnvironment\">\n" \
134 " <arg name=\"unset\" type=\"as\" direction=\"in\"/>\n" \
135 " <arg name=\"set\" type=\"as\" direction=\"in\"/>\n" \
137 " <method name=\"ListUnitFiles\">\n" \
138 " <arg name=\"changes\" type=\"a(ss)\" direction=\"out\"/>\n" \
140 " <method name=\"GetUnitFileState\">\n" \
141 " <arg name=\"file\" type=\"s\" direction=\"in\"/>\n" \
142 " <arg name=\"state\" type=\"s\" direction=\"out\"/>\n" \
144 " <method name=\"EnableUnitFiles\">\n" \
145 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
146 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
147 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
148 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
149 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
151 " <method name=\"DisableUnitFiles\">\n" \
152 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
153 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
154 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
156 " <method name=\"ReenableUnitFiles\">\n" \
157 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
158 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
159 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
160 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
161 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
163 " <method name=\"LinkUnitFiles\">\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=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
169 " <method name=\"PresetUnitFiles\">\n" \
170 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
171 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
172 " <arg name=\"force\" type=\"b\" direction=\"in\"/>\n" \
173 " <arg name=\"carries_install_info\" type=\"b\" direction=\"out\"/>\n" \
174 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
176 " <method name=\"MaskUnitFiles\">\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=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
182 " <method name=\"UnmaskUnitFiles\">\n" \
183 " <arg name=\"files\" type=\"as\" direction=\"in\"/>\n" \
184 " <arg name=\"runtime\" type=\"b\" direction=\"in\"/>\n" \
185 " <arg name=\"changes\" type=\"a(sss)\" direction=\"out\"/>\n" \
188 #define BUS_MANAGER_INTERFACE_SIGNALS \
189 " <signal name=\"UnitNew\">\n" \
190 " <arg name=\"id\" type=\"s\"/>\n" \
191 " <arg name=\"unit\" type=\"o\"/>\n" \
193 " <signal name=\"UnitRemoved\">\n" \
194 " <arg name=\"id\" type=\"s\"/>\n" \
195 " <arg name=\"unit\" type=\"o\"/>\n" \
197 " <signal name=\"JobNew\">\n" \
198 " <arg name=\"id\" type=\"u\"/>\n" \
199 " <arg name=\"job\" type=\"o\"/>\n" \
201 " <signal name=\"JobRemoved\">\n" \
202 " <arg name=\"id\" type=\"u\"/>\n" \
203 " <arg name=\"job\" type=\"o\"/>\n" \
204 " <arg name=\"result\" type=\"s\"/>\n" \
206 " <signal name=\"StartupFinished\">\n" \
207 " <arg name=\"kernel\" type=\"t\"/>\n" \
208 " <arg name=\"initrd\" type=\"t\"/>\n" \
209 " <arg name=\"userspace\" type=\"t\"/>\n" \
210 " <arg name=\"total\" type=\"t\"/>\n" \
212 " <signal name=\"UnitFilesChanged\"/>\n"
214 #define BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
215 " <property name=\"Version\" type=\"s\" access=\"read\"/>\n" \
216 " <property name=\"Distribution\" type=\"s\" access=\"read\"/>\n" \
217 " <property name=\"Features\" type=\"s\" access=\"read\"/>\n" \
218 " <property name=\"Tainted\" type=\"s\" access=\"read\"/>\n" \
219 " <property name=\"RunningAs\" type=\"s\" access=\"read\"/>\n" \
220 " <property name=\"InitRDTimestamp\" type=\"t\" access=\"read\"/>\n" \
221 " <property name=\"InitRDTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
222 " <property name=\"StartupTimestamp\" type=\"t\" access=\"read\"/>\n" \
223 " <property name=\"StartupTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
224 " <property name=\"FinishTimestamp\" type=\"t\" access=\"read\"/>\n" \
225 " <property name=\"FinishTimestampMonotonic\" type=\"t\" access=\"read\"/>\n" \
226 " <property name=\"LogLevel\" type=\"s\" access=\"readwrite\"/>\n" \
227 " <property name=\"LogTarget\" type=\"s\" access=\"readwrite\"/>\n" \
228 " <property name=\"NNames\" type=\"u\" access=\"read\"/>\n" \
229 " <property name=\"NJobs\" type=\"u\" access=\"read\"/>\n" \
230 " <property name=\"NInstalledJobs\" type=\"u\" access=\"read\"/>\n" \
231 " <property name=\"NFailedJobs\" type=\"u\" access=\"read\"/>\n" \
232 " <property name=\"Progress\" type=\"d\" access=\"read\"/>\n" \
233 " <property name=\"Environment\" type=\"as\" access=\"read\"/>\n" \
234 " <property name=\"ConfirmSpawn\" type=\"b\" access=\"read\"/>\n" \
235 " <property name=\"ShowStatus\" type=\"b\" access=\"read\"/>\n" \
236 " <property name=\"UnitPath\" type=\"as\" access=\"read\"/>\n" \
237 " <property name=\"NotifySocket\" type=\"s\" access=\"read\"/>\n" \
238 " <property name=\"ControlGroupHierarchy\" type=\"s\" access=\"read\"/>\n" \
239 " <property name=\"MountAuto\" type=\"b\" access=\"read\"/>\n" \
240 " <property name=\"SwapAuto\" type=\"b\" access=\"read\"/>\n" \
241 " <property name=\"DefaultControllers\" type=\"as\" access=\"read\"/>\n" \
242 " <property name=\"DefaultStandardOutput\" type=\"s\" access=\"read\"/>\n" \
243 " <property name=\"DefaultStandardError\" type=\"s\" access=\"read\"/>\n"
245 #ifdef HAVE_SYSV_COMPAT
246 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
247 " <property name=\"SysVConsole\" type=\"b\" access=\"read\"/>\n" \
248 " <property name=\"SysVInitPath\" type=\"as\" access=\"read\"/>\n" \
249 " <property name=\"SysVRcndPath\" type=\"as\" access=\"read\"/>\n"
251 #define BUS_MANAGER_INTERFACE_PROPERTIES_SYSV
254 #define BUS_MANAGER_INTERFACE_END \
257 #define BUS_MANAGER_INTERFACE \
258 BUS_MANAGER_INTERFACE_BEGIN \
259 BUS_MANAGER_INTERFACE_METHODS \
260 BUS_MANAGER_INTERFACE_SIGNALS \
261 BUS_MANAGER_INTERFACE_PROPERTIES_GENERAL \
262 BUS_MANAGER_INTERFACE_PROPERTIES_SYSV \
263 BUS_MANAGER_INTERFACE_END
265 #define INTROSPECTION_BEGIN \
266 DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE \
268 BUS_MANAGER_INTERFACE \
269 BUS_PROPERTIES_INTERFACE \
271 BUS_INTROSPECTABLE_INTERFACE
273 #define INTROSPECTION_END \
276 #define INTERFACES_LIST \
277 BUS_GENERIC_INTERFACES_LIST \
278 "org.freedesktop.systemd1.Manager\0"
280 const char bus_manager_interface
[] _introspect_("Manager") = BUS_MANAGER_INTERFACE
;
282 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_running_as
, manager_running_as
, ManagerRunningAs
);
283 static DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_manager_append_exec_output
, exec_output
, ExecOutput
);
285 static int bus_manager_append_tainted(DBusMessageIter
*i
, const char *property
, void *data
) {
288 char buf
[LINE_MAX
] = "", *e
= buf
, *p
= NULL
;
295 e
= stpcpy(e
, "usr-separate-fs ");
297 if (readlink_malloc("/etc/mtab", &p
) < 0)
298 e
= stpcpy(e
, "etc-mtab-not-symlink ");
302 if (access("/proc/cgroups", F_OK
) < 0)
303 stpcpy(e
, "cgroups-missing ");
307 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &t
))
313 static int bus_manager_append_log_target(DBusMessageIter
*i
, const char *property
, void *data
) {
319 t
= log_target_to_string(log_get_target());
321 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &t
))
327 static int bus_manager_set_log_target(DBusMessageIter
*i
, const char *property
) {
333 dbus_message_iter_get_basic(i
, &t
);
335 return log_set_target_from_string(t
);
338 static int bus_manager_append_log_level(DBusMessageIter
*i
, const char *property
, void *data
) {
344 t
= log_level_to_string(log_get_max_level());
346 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &t
))
352 static int bus_manager_set_log_level(DBusMessageIter
*i
, const char *property
) {
358 dbus_message_iter_get_basic(i
, &t
);
360 return log_set_max_level_from_string(t
);
363 static int bus_manager_append_n_names(DBusMessageIter
*i
, const char *property
, void *data
) {
371 u
= hashmap_size(m
->units
);
373 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT32
, &u
))
379 static int bus_manager_append_n_jobs(DBusMessageIter
*i
, const char *property
, void *data
) {
387 u
= hashmap_size(m
->jobs
);
389 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_UINT32
, &u
))
395 static int bus_manager_append_progress(DBusMessageIter
*i
, const char *property
, void *data
) {
403 if (dual_timestamp_is_set(&m
->finish_timestamp
))
406 d
= 1.0 - ((double) hashmap_size(m
->jobs
) / (double) m
->n_installed_jobs
);
408 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_DOUBLE
, &d
))
414 static const char *message_get_sender_with_fallback(DBusMessage
*m
) {
419 if ((s
= dbus_message_get_sender(m
)))
422 /* When the message came in from a direct connection the
423 * message will have no sender. We fix that here. */
428 static DBusMessage
*message_from_file_changes(
430 UnitFileChange
*changes
,
432 int carries_install_info
) {
434 DBusMessageIter iter
, sub
, sub2
;
438 reply
= dbus_message_new_method_return(m
);
442 dbus_message_iter_init_append(reply
, &iter
);
444 if (carries_install_info
>= 0) {
447 b
= !!carries_install_info
;
448 if (!dbus_message_iter_append_basic(&iter
, DBUS_TYPE_BOOLEAN
, &b
))
452 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(sss)", &sub
))
455 for (i
= 0; i
< n_changes
; i
++) {
456 const char *type
, *path
, *source
;
458 type
= unit_file_change_type_to_string(changes
[i
].type
);
459 path
= strempty(changes
[i
].path
);
460 source
= strempty(changes
[i
].source
);
462 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
) ||
463 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &type
) ||
464 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &path
) ||
465 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &source
) ||
466 !dbus_message_iter_close_container(&sub
, &sub2
))
470 if (!dbus_message_iter_close_container(&iter
, &sub
))
476 dbus_message_unref(reply
);
480 static int bus_manager_send_unit_files_changed(Manager
*m
) {
484 s
= dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitFilesChanged");
488 r
= bus_broadcast(m
, s
);
489 dbus_message_unref(s
);
494 static const char systemd_property_string
[] = PACKAGE_STRING
"\0" DISTRIBUTION
"\0" SYSTEMD_FEATURES
;
496 static const BusProperty bus_systemd_properties
[] = {
497 { "Version", bus_property_append_string
, "s", 0 },
498 { "Distribution", bus_property_append_string
, "s", sizeof(PACKAGE_STRING
) },
499 { "Features", bus_property_append_string
, "s", sizeof(PACKAGE_STRING
) + sizeof(DISTRIBUTION
) },
503 static const BusProperty bus_manager_properties
[] = {
504 { "RunningAs", bus_manager_append_running_as
, "s", offsetof(Manager
, running_as
) },
505 { "Tainted", bus_manager_append_tainted
, "s", 0 },
506 { "InitRDTimestamp", bus_property_append_uint64
, "t", offsetof(Manager
, initrd_timestamp
.realtime
) },
507 { "InitRDTimestampMonotonic", bus_property_append_uint64
, "t", offsetof(Manager
, initrd_timestamp
.monotonic
) },
508 { "StartupTimestamp", bus_property_append_uint64
, "t", offsetof(Manager
, startup_timestamp
.realtime
) },
509 { "StartupTimestampMonotonic", bus_property_append_uint64
, "t", offsetof(Manager
, startup_timestamp
.monotonic
) },
510 { "FinishTimestamp", bus_property_append_uint64
, "t", offsetof(Manager
, finish_timestamp
.realtime
) },
511 { "FinishTimestampMonotonic", bus_property_append_uint64
, "t", offsetof(Manager
, finish_timestamp
.monotonic
) },
512 { "LogLevel", bus_manager_append_log_level
, "s", 0, 0, bus_manager_set_log_level
},
513 { "LogTarget", bus_manager_append_log_target
, "s", 0, 0, bus_manager_set_log_target
},
514 { "NNames", bus_manager_append_n_names
, "u", 0 },
515 { "NJobs", bus_manager_append_n_jobs
, "u", 0 },
516 { "NInstalledJobs",bus_property_append_uint32
, "u", offsetof(Manager
, n_installed_jobs
) },
517 { "NFailedJobs", bus_property_append_uint32
, "u", offsetof(Manager
, n_failed_jobs
) },
518 { "Progress", bus_manager_append_progress
, "d", 0 },
519 { "Environment", bus_property_append_strv
, "as", offsetof(Manager
, environment
), true },
520 { "ConfirmSpawn", bus_property_append_bool
, "b", offsetof(Manager
, confirm_spawn
) },
521 { "ShowStatus", bus_property_append_bool
, "b", offsetof(Manager
, show_status
) },
522 { "UnitPath", bus_property_append_strv
, "as", offsetof(Manager
, lookup_paths
.unit_path
), true },
523 { "NotifySocket", bus_property_append_string
, "s", offsetof(Manager
, notify_socket
), true },
524 { "ControlGroupHierarchy", bus_property_append_string
, "s", offsetof(Manager
, cgroup_hierarchy
), true },
525 { "MountAuto", bus_property_append_bool
, "b", offsetof(Manager
, mount_auto
) },
526 { "SwapAuto", bus_property_append_bool
, "b", offsetof(Manager
, swap_auto
) },
527 { "DefaultControllers", bus_property_append_strv
, "as", offsetof(Manager
, default_controllers
), true },
528 { "DefaultStandardOutput", bus_manager_append_exec_output
, "s", offsetof(Manager
, default_std_output
) },
529 { "DefaultStandardError", bus_manager_append_exec_output
, "s", offsetof(Manager
, default_std_error
) },
530 #ifdef HAVE_SYSV_COMPAT
531 { "SysVConsole", bus_property_append_bool
, "b", offsetof(Manager
, sysv_console
) },
532 { "SysVInitPath", bus_property_append_strv
, "as", offsetof(Manager
, lookup_paths
.sysvinit_path
), true },
533 { "SysVRcndPath", bus_property_append_strv
, "as", offsetof(Manager
, lookup_paths
.sysvrcnd_path
), true },
538 static DBusHandlerResult
bus_manager_message_handler(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
543 DBusMessage
*reply
= NULL
;
545 JobType job_type
= _JOB_TYPE_INVALID
;
546 bool reload_if_possible
= false;
553 dbus_error_init(&error
);
555 member
= dbus_message_get_member(message
);
557 if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "GetUnit")) {
561 if (!dbus_message_get_args(
564 DBUS_TYPE_STRING
, &name
,
566 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
568 if (!(u
= manager_get_unit(m
, name
))) {
569 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s is not loaded.", name
);
570 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
573 if (!(reply
= dbus_message_new_method_return(message
)))
576 if (!(path
= unit_dbus_path(u
)))
579 if (!dbus_message_append_args(
581 DBUS_TYPE_OBJECT_PATH
, &path
,
584 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "GetUnitByPID")) {
588 if (!dbus_message_get_args(
591 DBUS_TYPE_UINT32
, &pid
,
593 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
595 if (!(u
= cgroup_unit_by_pid(m
, (pid_t
) pid
))) {
596 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_UNIT
, "No unit for PID %lu is loaded.", (unsigned long) pid
);
597 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
600 if (!(reply
= dbus_message_new_method_return(message
)))
603 if (!(path
= unit_dbus_path(u
)))
606 if (!dbus_message_append_args(
608 DBUS_TYPE_OBJECT_PATH
, &path
,
611 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "LoadUnit")) {
615 if (!dbus_message_get_args(
618 DBUS_TYPE_STRING
, &name
,
620 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
622 if ((r
= manager_load_unit(m
, name
, NULL
, &error
, &u
)) < 0)
623 return bus_send_error_reply(connection
, message
, &error
, r
);
625 if (!(reply
= dbus_message_new_method_return(message
)))
628 if (!(path
= unit_dbus_path(u
)))
631 if (!dbus_message_append_args(
633 DBUS_TYPE_OBJECT_PATH
, &path
,
637 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "StartUnit"))
638 job_type
= JOB_START
;
639 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
640 job_type
= JOB_START
;
641 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "StopUnit"))
643 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ReloadUnit"))
644 job_type
= JOB_RELOAD
;
645 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "RestartUnit"))
646 job_type
= JOB_RESTART
;
647 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "TryRestartUnit"))
648 job_type
= JOB_TRY_RESTART
;
649 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ReloadOrRestartUnit")) {
650 reload_if_possible
= true;
651 job_type
= JOB_RESTART
;
652 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ReloadOrTryRestartUnit")) {
653 reload_if_possible
= true;
654 job_type
= JOB_TRY_RESTART
;
655 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "KillUnit")) {
656 const char *name
, *swho
, *smode
;
662 if (!dbus_message_get_args(
665 DBUS_TYPE_STRING
, &name
,
666 DBUS_TYPE_STRING
, &swho
,
667 DBUS_TYPE_STRING
, &smode
,
668 DBUS_TYPE_INT32
, &signo
,
670 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
675 who
= kill_who_from_string(swho
);
677 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
681 mode
= KILL_CONTROL_GROUP
;
683 mode
= kill_mode_from_string(smode
);
685 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
688 if (signo
<= 0 || signo
>= _NSIG
)
689 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
691 if (!(u
= manager_get_unit(m
, name
))) {
692 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s is not loaded.", name
);
693 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
696 if ((r
= unit_kill(u
, who
, mode
, signo
, &error
)) < 0)
697 return bus_send_error_reply(connection
, message
, &error
, r
);
699 if (!(reply
= dbus_message_new_method_return(message
)))
702 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "GetJob")) {
706 if (!dbus_message_get_args(
709 DBUS_TYPE_UINT32
, &id
,
711 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
713 if (!(j
= manager_get_job(m
, id
))) {
714 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_JOB
, "Job %u does not exist.", (unsigned) id
);
715 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
718 if (!(reply
= dbus_message_new_method_return(message
)))
721 if (!(path
= job_dbus_path(j
)))
724 if (!dbus_message_append_args(
726 DBUS_TYPE_OBJECT_PATH
, &path
,
730 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ClearJobs")) {
732 manager_clear_jobs(m
);
734 if (!(reply
= dbus_message_new_method_return(message
)))
737 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ResetFailed")) {
739 manager_reset_failed(m
);
741 if (!(reply
= dbus_message_new_method_return(message
)))
744 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ResetFailedUnit")) {
748 if (!dbus_message_get_args(
751 DBUS_TYPE_STRING
, &name
,
753 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
755 if (!(u
= manager_get_unit(m
, name
))) {
756 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s is not loaded.", name
);
757 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
760 unit_reset_failed(u
);
762 if (!(reply
= dbus_message_new_method_return(message
)))
765 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ListUnits")) {
766 DBusMessageIter iter
, sub
;
771 if (!(reply
= dbus_message_new_method_return(message
)))
774 dbus_message_iter_init_append(reply
, &iter
);
776 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(ssssssouso)", &sub
))
779 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
780 char *u_path
, *j_path
;
781 const char *description
, *load_state
, *active_state
, *sub_state
, *sjob_type
, *following
;
782 DBusMessageIter sub2
;
789 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
792 description
= unit_description(u
);
793 load_state
= unit_load_state_to_string(u
->load_state
);
794 active_state
= unit_active_state_to_string(unit_active_state(u
));
795 sub_state
= unit_sub_state_to_string(u
);
797 f
= unit_following(u
);
798 following
= f
? f
->id
: "";
800 if (!(u_path
= unit_dbus_path(u
)))
804 job_id
= (uint32_t) u
->job
->id
;
806 if (!(j_path
= job_dbus_path(u
->job
))) {
811 sjob_type
= job_type_to_string(u
->job
->type
);
818 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &u
->id
) ||
819 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &description
) ||
820 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &load_state
) ||
821 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &active_state
) ||
822 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &sub_state
) ||
823 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &following
) ||
824 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u_path
) ||
825 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &job_id
) ||
826 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &sjob_type
) ||
827 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &j_path
)) {
838 if (!dbus_message_iter_close_container(&sub
, &sub2
))
842 if (!dbus_message_iter_close_container(&iter
, &sub
))
845 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ListJobs")) {
846 DBusMessageIter iter
, sub
;
850 if (!(reply
= dbus_message_new_method_return(message
)))
853 dbus_message_iter_init_append(reply
, &iter
);
855 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(usssoo)", &sub
))
858 HASHMAP_FOREACH(j
, m
->jobs
, i
) {
859 char *u_path
, *j_path
;
860 const char *state
, *type
;
862 DBusMessageIter sub2
;
864 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
))
867 id
= (uint32_t) j
->id
;
868 state
= job_state_to_string(j
->state
);
869 type
= job_type_to_string(j
->type
);
871 if (!(j_path
= job_dbus_path(j
)))
874 if (!(u_path
= unit_dbus_path(j
->unit
))) {
879 if (!dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_UINT32
, &id
) ||
880 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &j
->unit
->id
) ||
881 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &type
) ||
882 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &state
) ||
883 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &j_path
) ||
884 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_OBJECT_PATH
, &u_path
)) {
893 if (!dbus_message_iter_close_container(&sub
, &sub2
))
897 if (!dbus_message_iter_close_container(&iter
, &sub
))
900 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Subscribe")) {
904 if (!(s
= BUS_CONNECTION_SUBSCRIBED(m
, connection
))) {
905 if (!(s
= set_new(string_hash_func
, string_compare_func
)))
908 if (!(dbus_connection_set_data(connection
, m
->subscribed_data_slot
, s
, NULL
))) {
914 if (!(client
= strdup(message_get_sender_with_fallback(message
))))
917 if ((r
= set_put(s
, client
)) < 0) {
919 return bus_send_error_reply(connection
, message
, NULL
, r
);
922 if (!(reply
= dbus_message_new_method_return(message
)))
925 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Unsubscribe")) {
928 if (!(client
= set_remove(BUS_CONNECTION_SUBSCRIBED(m
, connection
), (char*) message_get_sender_with_fallback(message
)))) {
929 dbus_set_error(&error
, BUS_ERROR_NOT_SUBSCRIBED
, "Client is not subscribed.");
930 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
935 if (!(reply
= dbus_message_new_method_return(message
)))
938 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Dump")) {
943 if (!(reply
= dbus_message_new_method_return(message
)))
946 if (!(f
= open_memstream(&dump
, &size
)))
949 manager_dump_units(m
, f
, NULL
);
950 manager_dump_jobs(m
, f
, NULL
);
960 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &dump
, DBUS_TYPE_INVALID
)) {
966 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "CreateSnapshot")) {
971 if (!dbus_message_get_args(
974 DBUS_TYPE_STRING
, &name
,
975 DBUS_TYPE_BOOLEAN
, &cleanup
,
977 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
979 if (name
&& name
[0] == 0)
982 if ((r
= snapshot_create(m
, name
, cleanup
, &error
, &s
)) < 0)
983 return bus_send_error_reply(connection
, message
, &error
, r
);
985 if (!(reply
= dbus_message_new_method_return(message
)))
988 if (!(path
= unit_dbus_path(UNIT(s
))))
991 if (!dbus_message_append_args(
993 DBUS_TYPE_OBJECT_PATH
, &path
,
997 } else if (dbus_message_is_method_call(message
, "org.freedesktop.DBus.Introspectable", "Introspect")) {
998 char *introspection
= NULL
;
1006 if (!(reply
= dbus_message_new_method_return(message
)))
1009 /* We roll our own introspection code here, instead of
1010 * relying on bus_default_message_handler() because we
1011 * need to generate our introspection string
1014 if (!(f
= open_memstream(&introspection
, &size
)))
1017 fputs(INTROSPECTION_BEGIN
, f
);
1019 HASHMAP_FOREACH_KEY(u
, k
, m
->units
, i
) {
1025 if (!(p
= bus_path_escape(k
))) {
1027 free(introspection
);
1031 fprintf(f
, "<node name=\"unit/%s\"/>", p
);
1035 HASHMAP_FOREACH(j
, m
->jobs
, i
)
1036 fprintf(f
, "<node name=\"job/%lu\"/>", (unsigned long) j
->id
);
1038 fputs(INTROSPECTION_END
, f
);
1042 free(introspection
);
1051 if (!dbus_message_append_args(reply
, DBUS_TYPE_STRING
, &introspection
, DBUS_TYPE_INVALID
)) {
1052 free(introspection
);
1056 free(introspection
);
1058 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Reload")) {
1060 assert(!m
->queued_message
);
1062 /* Instead of sending the reply back right away, we
1063 * just remember that we need to and then send it
1064 * after the reload is finished. That way the caller
1065 * knows when the reload finished. */
1067 if (!(m
->queued_message
= dbus_message_new_method_return(message
)))
1070 m
->queued_message_connection
= connection
;
1071 m
->exit_code
= MANAGER_RELOAD
;
1073 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Reexecute")) {
1075 /* We don't send a reply back here, the client should
1076 * just wait for us disconnecting. */
1078 m
->exit_code
= MANAGER_REEXECUTE
;
1080 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Exit")) {
1082 if (m
->running_as
== MANAGER_SYSTEM
) {
1083 dbus_set_error(&error
, BUS_ERROR_NOT_SUPPORTED
, "Exit is only supported for user service managers.");
1084 return bus_send_error_reply(connection
, message
, &error
, -ENOTSUP
);
1087 if (!(reply
= dbus_message_new_method_return(message
)))
1090 m
->exit_code
= MANAGER_EXIT
;
1092 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Reboot")) {
1094 if (m
->running_as
!= MANAGER_SYSTEM
) {
1095 dbus_set_error(&error
, BUS_ERROR_NOT_SUPPORTED
, "Reboot is only supported for system managers.");
1096 return bus_send_error_reply(connection
, message
, &error
, -ENOTSUP
);
1099 if (!(reply
= dbus_message_new_method_return(message
)))
1102 m
->exit_code
= MANAGER_REBOOT
;
1104 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "PowerOff")) {
1106 if (m
->running_as
!= MANAGER_SYSTEM
) {
1107 dbus_set_error(&error
, BUS_ERROR_NOT_SUPPORTED
, "Powering off is only supported for system managers.");
1108 return bus_send_error_reply(connection
, message
, &error
, -ENOTSUP
);
1111 if (!(reply
= dbus_message_new_method_return(message
)))
1114 m
->exit_code
= MANAGER_POWEROFF
;
1116 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "Halt")) {
1118 if (m
->running_as
!= MANAGER_SYSTEM
) {
1119 dbus_set_error(&error
, BUS_ERROR_NOT_SUPPORTED
, "Halting is only supported for system managers.");
1120 return bus_send_error_reply(connection
, message
, &error
, -ENOTSUP
);
1123 if (!(reply
= dbus_message_new_method_return(message
)))
1126 m
->exit_code
= MANAGER_HALT
;
1128 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "KExec")) {
1130 if (m
->running_as
!= MANAGER_SYSTEM
) {
1131 dbus_set_error(&error
, BUS_ERROR_NOT_SUPPORTED
, "kexec is only supported for system managers.");
1132 return bus_send_error_reply(connection
, message
, &error
, -ENOTSUP
);
1135 if (!(reply
= dbus_message_new_method_return(message
)))
1138 m
->exit_code
= MANAGER_KEXEC
;
1140 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "SetEnvironment")) {
1141 char **l
= NULL
, **e
= NULL
;
1143 if ((r
= bus_parse_strv(message
, &l
)) < 0) {
1147 return bus_send_error_reply(connection
, message
, NULL
, r
);
1150 e
= strv_env_merge(2, m
->environment
, l
);
1156 if (!(reply
= dbus_message_new_method_return(message
))) {
1161 strv_free(m
->environment
);
1164 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "UnsetEnvironment")) {
1165 char **l
= NULL
, **e
= NULL
;
1167 if ((r
= bus_parse_strv(message
, &l
)) < 0) {
1171 return bus_send_error_reply(connection
, message
, NULL
, r
);
1174 e
= strv_env_delete(m
->environment
, 1, l
);
1180 if (!(reply
= dbus_message_new_method_return(message
))) {
1185 strv_free(m
->environment
);
1188 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "UnsetAndSetEnvironment")) {
1189 char **l_set
= NULL
, **l_unset
= NULL
, **e
= NULL
, **f
= NULL
;
1190 DBusMessageIter iter
;
1192 if (!dbus_message_iter_init(message
, &iter
))
1195 r
= bus_parse_strv_iter(&iter
, &l_unset
);
1200 return bus_send_error_reply(connection
, message
, NULL
, r
);
1203 if (!dbus_message_iter_next(&iter
)) {
1205 return bus_send_error_reply(connection
, message
, NULL
, -EINVAL
);
1208 r
= bus_parse_strv_iter(&iter
, &l_set
);
1214 return bus_send_error_reply(connection
, message
, NULL
, r
);
1217 e
= strv_env_delete(m
->environment
, 1, l_unset
);
1225 f
= strv_env_merge(2, e
, l_set
);
1232 if (!(reply
= dbus_message_new_method_return(message
))) {
1237 strv_free(m
->environment
);
1239 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ListUnitFiles")) {
1240 DBusMessageIter iter
, sub
, sub2
;
1245 reply
= dbus_message_new_method_return(message
);
1249 h
= hashmap_new(string_hash_func
, string_compare_func
);
1253 r
= unit_file_get_list(m
->running_as
== MANAGER_SYSTEM
? UNIT_FILE_SYSTEM
: UNIT_FILE_USER
, NULL
, h
);
1255 unit_file_list_free(h
);
1256 dbus_message_unref(reply
);
1257 return bus_send_error_reply(connection
, message
, NULL
, r
);
1260 dbus_message_iter_init_append(reply
, &iter
);
1262 if (!dbus_message_iter_open_container(&iter
, DBUS_TYPE_ARRAY
, "(ss)", &sub
)) {
1263 unit_file_list_free(h
);
1267 HASHMAP_FOREACH(item
, h
, i
) {
1270 state
= unit_file_state_to_string(item
->state
);
1273 if (!dbus_message_iter_open_container(&sub
, DBUS_TYPE_STRUCT
, NULL
, &sub2
) ||
1274 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &item
->path
) ||
1275 !dbus_message_iter_append_basic(&sub2
, DBUS_TYPE_STRING
, &state
) ||
1276 !dbus_message_iter_close_container(&sub
, &sub2
)) {
1277 unit_file_list_free(h
);
1282 unit_file_list_free(h
);
1284 if (!dbus_message_iter_close_container(&iter
, &sub
))
1287 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "GetUnitFileState")) {
1289 UnitFileState state
;
1292 if (!dbus_message_get_args(
1295 DBUS_TYPE_STRING
, &name
,
1297 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1299 state
= unit_file_get_state(m
->running_as
== MANAGER_SYSTEM
? UNIT_FILE_SYSTEM
: UNIT_FILE_USER
, NULL
, name
);
1301 return bus_send_error_reply(connection
, message
, NULL
, state
);
1303 s
= unit_file_state_to_string(state
);
1306 reply
= dbus_message_new_method_return(message
);
1310 if (!dbus_message_append_args(
1312 DBUS_TYPE_STRING
, &s
,
1315 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "EnableUnitFiles") ||
1316 dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "ReenableUnitFiles") ||
1317 dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "LinkUnitFiles") ||
1318 dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "PresetUnitFiles") ||
1319 dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "MaskUnitFiles")) {
1322 DBusMessageIter iter
;
1323 UnitFileScope scope
= m
->running_as
== MANAGER_SYSTEM
? UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
1324 UnitFileChange
*changes
= NULL
;
1325 unsigned n_changes
= 0;
1326 dbus_bool_t runtime
, force
;
1327 int carries_install_info
= -1;
1329 if (!dbus_message_iter_init(message
, &iter
))
1332 r
= bus_parse_strv_iter(&iter
, &l
);
1337 return bus_send_error_reply(connection
, message
, NULL
, r
);
1340 if (!dbus_message_iter_next(&iter
) ||
1341 bus_iter_get_basic_and_next(&iter
, DBUS_TYPE_BOOLEAN
, &runtime
, true) < 0 ||
1342 bus_iter_get_basic_and_next(&iter
, DBUS_TYPE_BOOLEAN
, &force
, false) < 0) {
1344 return bus_send_error_reply(connection
, message
, NULL
, -EIO
);
1347 if (streq(member
, "EnableUnitFiles")) {
1348 r
= unit_file_enable(scope
, runtime
, NULL
, l
, force
, &changes
, &n_changes
);
1349 carries_install_info
= r
;
1350 } else if (streq(member
, "ReenableUnitFiles")) {
1351 r
= unit_file_reenable(scope
, runtime
, NULL
, l
, force
, &changes
, &n_changes
);
1352 carries_install_info
= r
;
1353 } else if (streq(member
, "LinkUnitFiles"))
1354 r
= unit_file_link(scope
, runtime
, NULL
, l
, force
, &changes
, &n_changes
);
1355 else if (streq(member
, "PresetUnitFiles")) {
1356 r
= unit_file_preset(scope
, runtime
, NULL
, l
, force
, &changes
, &n_changes
);
1357 carries_install_info
= r
;
1358 } else if (streq(member
, "MaskUnitFiles"))
1359 r
= unit_file_mask(scope
, runtime
, NULL
, l
, force
, &changes
, &n_changes
);
1361 assert_not_reached("Uh? Wrong method");
1364 bus_manager_send_unit_files_changed(m
);
1367 unit_file_changes_free(changes
, n_changes
);
1368 return bus_send_error_reply(connection
, message
, NULL
, r
);
1371 reply
= message_from_file_changes(message
, changes
, n_changes
, carries_install_info
);
1372 unit_file_changes_free(changes
, n_changes
);
1377 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "DisableUnitFiles") ||
1378 dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "UnmaskUnitFiles")) {
1381 DBusMessageIter iter
;
1382 UnitFileScope scope
= m
->running_as
== MANAGER_SYSTEM
? UNIT_FILE_SYSTEM
: UNIT_FILE_USER
;
1383 UnitFileChange
*changes
= NULL
;
1384 unsigned n_changes
= 0;
1385 dbus_bool_t runtime
;
1387 if (!dbus_message_iter_init(message
, &iter
))
1390 r
= bus_parse_strv_iter(&iter
, &l
);
1395 return bus_send_error_reply(connection
, message
, NULL
, r
);
1398 if (!dbus_message_iter_next(&iter
) ||
1399 bus_iter_get_basic_and_next(&iter
, DBUS_TYPE_BOOLEAN
, &runtime
, false) < 0) {
1401 return bus_send_error_reply(connection
, message
, NULL
, -EIO
);
1404 if (streq(member
, "DisableUnitFiles"))
1405 r
= unit_file_disable(scope
, runtime
, NULL
, l
, &changes
, &n_changes
);
1406 else if (streq(member
, "UnmaskUnitFiles"))
1407 r
= unit_file_unmask(scope
, runtime
, NULL
, l
, &changes
, &n_changes
);
1409 assert_not_reached("Uh? Wrong method");
1412 bus_manager_send_unit_files_changed(m
);
1415 unit_file_changes_free(changes
, n_changes
);
1416 return bus_send_error_reply(connection
, message
, NULL
, r
);
1419 reply
= message_from_file_changes(message
, changes
, n_changes
, -1);
1420 unit_file_changes_free(changes
, n_changes
);
1426 const BusBoundProperties bps
[] = {
1427 { "org.freedesktop.systemd1.Manager", bus_systemd_properties
, systemd_property_string
},
1428 { "org.freedesktop.systemd1.Manager", bus_manager_properties
, m
},
1431 return bus_default_message_handler(connection
, message
, NULL
, INTERFACES_LIST
, bps
);
1434 if (job_type
!= _JOB_TYPE_INVALID
) {
1435 const char *name
, *smode
, *old_name
= NULL
;
1441 if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Manager", "StartUnitReplace"))
1442 b
= dbus_message_get_args(
1445 DBUS_TYPE_STRING
, &old_name
,
1446 DBUS_TYPE_STRING
, &name
,
1447 DBUS_TYPE_STRING
, &smode
,
1450 b
= dbus_message_get_args(
1453 DBUS_TYPE_STRING
, &name
,
1454 DBUS_TYPE_STRING
, &smode
,
1458 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1461 if (!(u
= manager_get_unit(m
, old_name
)) ||
1463 u
->job
->type
!= JOB_START
) {
1464 dbus_set_error(&error
, BUS_ERROR_NO_SUCH_JOB
, "No job queued for unit %s", old_name
);
1465 return bus_send_error_reply(connection
, message
, &error
, -ENOENT
);
1469 if ((mode
= job_mode_from_string(smode
)) == _JOB_MODE_INVALID
) {
1470 dbus_set_error(&error
, BUS_ERROR_INVALID_JOB_MODE
, "Job mode %s is invalid.", smode
);
1471 return bus_send_error_reply(connection
, message
, &error
, -EINVAL
);
1474 if ((r
= manager_load_unit(m
, name
, NULL
, &error
, &u
)) < 0)
1475 return bus_send_error_reply(connection
, message
, &error
, r
);
1477 if (reload_if_possible
&& unit_can_reload(u
)) {
1478 if (job_type
== JOB_RESTART
)
1479 job_type
= JOB_RELOAD_OR_START
;
1480 else if (job_type
== JOB_TRY_RESTART
)
1481 job_type
= JOB_RELOAD
;
1484 if ((job_type
== JOB_START
&& u
->refuse_manual_start
) ||
1485 (job_type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
1486 ((job_type
== JOB_RESTART
|| job_type
== JOB_TRY_RESTART
) &&
1487 (u
->refuse_manual_start
|| u
->refuse_manual_stop
))) {
1488 dbus_set_error(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, may be requested by dependency only.");
1489 return bus_send_error_reply(connection
, message
, &error
, -EPERM
);
1492 if ((r
= manager_add_job(m
, job_type
, u
, mode
, true, &error
, &j
)) < 0)
1493 return bus_send_error_reply(connection
, message
, &error
, r
);
1495 if (!(j
->bus_client
= strdup(message_get_sender_with_fallback(message
))))
1498 j
->bus
= connection
;
1500 if (!(reply
= dbus_message_new_method_return(message
)))
1503 if (!(path
= job_dbus_path(j
)))
1506 if (!dbus_message_append_args(
1508 DBUS_TYPE_OBJECT_PATH
, &path
,
1514 if (!dbus_connection_send(connection
, reply
, NULL
))
1517 dbus_message_unref(reply
);
1522 return DBUS_HANDLER_RESULT_HANDLED
;
1528 dbus_message_unref(reply
);
1530 dbus_error_free(&error
);
1532 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
1535 const DBusObjectPathVTable bus_manager_vtable
= {
1536 .message_function
= bus_manager_message_handler