1 /*-*- Mode: C; c-basic-offset: 8 -*-*/
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/>.
26 #include "dbus-unit.h"
27 #include "bus-errors.h"
29 const char bus_unit_interface
[] = BUS_UNIT_INTERFACE
;
31 int bus_unit_append_names(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
37 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
40 SET_FOREACH(t
, u
->meta
.names
, j
)
41 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &t
))
44 if (!dbus_message_iter_close_container(i
, &sub
))
50 int bus_unit_append_dependencies(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
56 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
60 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &u
->meta
.id
))
63 if (!dbus_message_iter_close_container(i
, &sub
))
69 int bus_unit_append_description(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
78 d
= unit_description(u
);
80 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &d
))
86 DEFINE_BUS_PROPERTY_APPEND_ENUM(bus_unit_append_load_state
, unit_load_state
, UnitLoadState
);
88 int bus_unit_append_active_state(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
97 state
= unit_active_state_to_string(unit_active_state(u
));
99 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
105 int bus_unit_append_sub_state(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
114 state
= unit_sub_state_to_string(u
);
116 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &state
))
122 int bus_unit_append_can_start(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
131 b
= unit_can_start(u
) &&
132 !u
->meta
.only_by_dependency
;
134 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
140 int bus_unit_append_can_reload(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
149 b
= unit_can_reload(u
);
151 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
157 int bus_unit_append_job(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
167 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_STRUCT
, NULL
, &sub
))
172 if (!(p
= job_dbus_path(u
->meta
.job
)))
175 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &u
->meta
.job
->id
) ||
176 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
183 /* No job, so let's fill in some placeholder
184 * data. Since we need to fill in a valid path we
185 * simple point to ourselves. */
187 if (!(p
= unit_dbus_path(u
)))
190 if (!dbus_message_iter_append_basic(&sub
, DBUS_TYPE_UINT32
, &id
) ||
191 !dbus_message_iter_append_basic(&sub
, DBUS_TYPE_OBJECT_PATH
, &p
)) {
199 if (!dbus_message_iter_close_container(i
, &sub
))
205 int bus_unit_append_default_cgroup(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
216 if ((cgb
= unit_get_default_cgroup(u
))) {
217 if (!(t
= cgroup_bonding_to_string(cgb
)))
222 success
= dbus_message_iter_append_basic(i
, DBUS_TYPE_STRING
, &t
);
227 return success
? 0 : -ENOMEM
;
230 int bus_unit_append_cgroups(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
235 if (!dbus_message_iter_open_container(i
, DBUS_TYPE_ARRAY
, "s", &sub
))
238 LIST_FOREACH(by_unit
, cgb
, u
->meta
.cgroup_bondings
) {
242 if (!(t
= cgroup_bonding_to_string(cgb
)))
245 success
= dbus_message_iter_append_basic(&sub
, DBUS_TYPE_STRING
, &t
);
252 if (!dbus_message_iter_close_container(i
, &sub
))
258 int bus_unit_append_need_daemon_reload(Manager
*m
, DBusMessageIter
*i
, const char *property
, void *data
) {
267 b
= unit_need_daemon_reload(u
);
269 if (!dbus_message_iter_append_basic(i
, DBUS_TYPE_BOOLEAN
, &b
))
275 static DBusHandlerResult
bus_unit_message_dispatch(Unit
*u
, DBusConnection
*connection
, DBusMessage
*message
) {
276 DBusMessage
*reply
= NULL
;
277 Manager
*m
= u
->meta
.manager
;
279 JobType job_type
= _JOB_TYPE_INVALID
;
281 bool reload_if_possible
= false;
283 dbus_error_init(&error
);
285 if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Start"))
286 job_type
= JOB_START
;
287 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Stop"))
289 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Reload"))
290 job_type
= JOB_RELOAD
;
291 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "Restart"))
292 job_type
= JOB_RESTART
;
293 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "TryRestart"))
294 job_type
= JOB_TRY_RESTART
;
295 else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrRestart")) {
296 reload_if_possible
= true;
297 job_type
= JOB_RESTART
;
298 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ReloadOrTryRestart")) {
299 reload_if_possible
= true;
300 job_type
= JOB_TRY_RESTART
;
301 } else if (dbus_message_is_method_call(message
, "org.freedesktop.systemd1.Unit", "ResetMaintenance")) {
303 unit_reset_maintenance(u
);
305 if (!(reply
= dbus_message_new_method_return(message
)))
308 } else if (UNIT_VTABLE(u
)->bus_message_handler
)
309 return UNIT_VTABLE(u
)->bus_message_handler(u
, connection
, message
);
311 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
313 if (job_type
!= _JOB_TYPE_INVALID
) {
319 if (job_type
== JOB_START
&& u
->meta
.only_by_dependency
) {
320 dbus_set_error(&error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Unit may be activated by dependency only.");
321 return bus_send_error_reply(m
, connection
, message
, &error
, -EPERM
);
324 if (!dbus_message_get_args(
327 DBUS_TYPE_STRING
, &smode
,
329 return bus_send_error_reply(m
, connection
, message
, &error
, -EINVAL
);
331 if (reload_if_possible
&& unit_can_reload(u
)) {
332 if (job_type
== JOB_RESTART
)
333 job_type
= JOB_RELOAD_OR_START
;
334 else if (job_type
== JOB_TRY_RESTART
)
335 job_type
= JOB_RELOAD
;
338 if ((mode
= job_mode_from_string(smode
)) == _JOB_MODE_INVALID
) {
339 dbus_set_error(&error
, BUS_ERROR_INVALID_JOB_MODE
, "Job mode %s is invalid.", smode
);
340 return bus_send_error_reply(m
, connection
, message
, &error
, -EINVAL
);
343 if ((r
= manager_add_job(m
, job_type
, u
, mode
, true, &error
, &j
)) < 0)
344 return bus_send_error_reply(m
, connection
, message
, &error
, r
);
346 if (!(reply
= dbus_message_new_method_return(message
)))
349 if (!(path
= job_dbus_path(j
)))
352 if (!dbus_message_append_args(
354 DBUS_TYPE_OBJECT_PATH
, &path
,
362 if (!dbus_connection_send(connection
, reply
, NULL
))
365 dbus_message_unref(reply
);
368 return DBUS_HANDLER_RESULT_HANDLED
;
374 dbus_message_unref(reply
);
376 dbus_error_free(&error
);
378 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
381 static DBusHandlerResult
bus_unit_message_handler(DBusConnection
*connection
, DBusMessage
*message
, void *data
) {
390 if ((r
= manager_get_unit_from_dbus_path(m
, dbus_message_get_path(message
), &u
)) < 0) {
393 return DBUS_HANDLER_RESULT_NEED_MEMORY
;
396 return DBUS_HANDLER_RESULT_NOT_YET_HANDLED
;
398 return bus_send_error_reply(m
, connection
, message
, NULL
, r
);
401 return bus_unit_message_dispatch(u
, connection
, message
);
404 const DBusObjectPathVTable bus_unit_vtable
= {
405 .message_function
= bus_unit_message_handler
408 void bus_unit_send_change_signal(Unit
*u
) {
410 DBusMessage
*m
= NULL
;
414 if (u
->meta
.in_dbus_queue
) {
415 LIST_REMOVE(Meta
, dbus_queue
, u
->meta
.manager
->dbus_unit_queue
, &u
->meta
);
416 u
->meta
.in_dbus_queue
= false;
419 if (!bus_has_subscriber(u
->meta
.manager
)) {
420 u
->meta
.sent_dbus_new_signal
= true;
424 if (!(p
= unit_dbus_path(u
)))
427 if (u
->meta
.sent_dbus_new_signal
) {
428 /* Send a change signal */
430 if (!(m
= dbus_message_new_signal(p
, "org.freedesktop.systemd1.Unit", "Changed")))
433 /* Send a new signal */
435 if (!(m
= dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitNew")))
438 if (!dbus_message_append_args(m
,
439 DBUS_TYPE_STRING
, &u
->meta
.id
,
440 DBUS_TYPE_OBJECT_PATH
, &p
,
445 if (bus_broadcast(u
->meta
.manager
, m
) < 0)
449 dbus_message_unref(m
);
451 u
->meta
.sent_dbus_new_signal
= true;
459 dbus_message_unref(m
);
461 log_error("Failed to allocate unit change/new signal.");
464 void bus_unit_send_removed_signal(Unit
*u
) {
466 DBusMessage
*m
= NULL
;
470 if (!bus_has_subscriber(u
->meta
.manager
))
473 if (!u
->meta
.sent_dbus_new_signal
)
474 bus_unit_send_change_signal(u
);
476 if (!(p
= unit_dbus_path(u
)))
479 if (!(m
= dbus_message_new_signal("/org/freedesktop/systemd1", "org.freedesktop.systemd1.Manager", "UnitRemoved")))
482 if (!dbus_message_append_args(m
,
483 DBUS_TYPE_STRING
, &u
->meta
.id
,
484 DBUS_TYPE_OBJECT_PATH
, &p
,
488 if (bus_broadcast(u
->meta
.manager
, m
) < 0)
492 dbus_message_unref(m
);
500 dbus_message_unref(m
);
502 log_error("Failed to allocate unit remove signal.");