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/>.
24 #include "bus-common-errors.h"
25 #include "cgroup-util.h"
28 #include "selinux-access.h"
30 #include "string-util.h"
32 #include "dbus-unit.h"
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state
, unit_load_state
, UnitLoadState
);
35 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode
, job_mode
, JobMode
);
36 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action
, failure_action
, FailureAction
);
38 static int property_get_names(
41 const char *interface
,
43 sd_bus_message
*reply
,
45 sd_bus_error
*error
) {
56 r
= sd_bus_message_open_container(reply
, 'a', "s");
60 SET_FOREACH(t
, u
->names
, i
) {
61 r
= sd_bus_message_append(reply
, "s", t
);
66 return sd_bus_message_close_container(reply
);
69 static int property_get_following(
72 const char *interface
,
74 sd_bus_message
*reply
,
76 sd_bus_error
*error
) {
78 Unit
*u
= userdata
, *f
;
84 f
= unit_following(u
);
85 return sd_bus_message_append(reply
, "s", f
? f
->id
: "");
88 static int property_get_dependencies(
91 const char *interface
,
93 sd_bus_message
*reply
,
95 sd_bus_error
*error
) {
97 Set
*s
= *(Set
**) userdata
;
105 r
= sd_bus_message_open_container(reply
, 'a', "s");
109 SET_FOREACH(u
, s
, j
) {
110 r
= sd_bus_message_append(reply
, "s", u
->id
);
115 return sd_bus_message_close_container(reply
);
118 static int property_get_description(
121 const char *interface
,
122 const char *property
,
123 sd_bus_message
*reply
,
125 sd_bus_error
*error
) {
133 return sd_bus_message_append(reply
, "s", unit_description(u
));
136 static int property_get_active_state(
139 const char *interface
,
140 const char *property
,
141 sd_bus_message
*reply
,
143 sd_bus_error
*error
) {
151 return sd_bus_message_append(reply
, "s", unit_active_state_to_string(unit_active_state(u
)));
154 static int property_get_sub_state(
157 const char *interface
,
158 const char *property
,
159 sd_bus_message
*reply
,
161 sd_bus_error
*error
) {
169 return sd_bus_message_append(reply
, "s", unit_sub_state_to_string(u
));
172 static int property_get_unit_file_preset(
175 const char *interface
,
176 const char *property
,
177 sd_bus_message
*reply
,
179 sd_bus_error
*error
) {
188 r
= unit_get_unit_file_preset(u
);
190 return sd_bus_message_append(reply
, "s",
192 r
> 0 ? "enabled" : "disabled");
195 static int property_get_unit_file_state(
198 const char *interface
,
199 const char *property
,
200 sd_bus_message
*reply
,
202 sd_bus_error
*error
) {
210 return sd_bus_message_append(reply
, "s", unit_file_state_to_string(unit_get_unit_file_state(u
)));
213 static int property_get_can_start(
216 const char *interface
,
217 const char *property
,
218 sd_bus_message
*reply
,
220 sd_bus_error
*error
) {
228 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_start
);
231 static int property_get_can_stop(
234 const char *interface
,
235 const char *property
,
236 sd_bus_message
*reply
,
238 sd_bus_error
*error
) {
246 /* On the lower levels we assume that every unit we can start
247 * we can also stop */
249 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_stop
);
252 static int property_get_can_reload(
255 const char *interface
,
256 const char *property
,
257 sd_bus_message
*reply
,
259 sd_bus_error
*error
) {
267 return sd_bus_message_append(reply
, "b", unit_can_reload(u
));
270 static int property_get_can_isolate(
273 const char *interface
,
274 const char *property
,
275 sd_bus_message
*reply
,
277 sd_bus_error
*error
) {
285 return sd_bus_message_append(reply
, "b", unit_can_isolate(u
) && !u
->refuse_manual_start
);
288 static int property_get_job(
291 const char *interface
,
292 const char *property
,
293 sd_bus_message
*reply
,
295 sd_bus_error
*error
) {
297 _cleanup_free_
char *p
= NULL
;
305 return sd_bus_message_append(reply
, "(uo)", 0, "/");
307 p
= job_dbus_path(u
->job
);
311 return sd_bus_message_append(reply
, "(uo)", u
->job
->id
, p
);
314 static int property_get_need_daemon_reload(
317 const char *interface
,
318 const char *property
,
319 sd_bus_message
*reply
,
321 sd_bus_error
*error
) {
329 return sd_bus_message_append(reply
, "b", unit_need_daemon_reload(u
));
332 static int property_get_conditions(
335 const char *interface
,
336 const char *property
,
337 sd_bus_message
*reply
,
339 sd_bus_error
*error
) {
341 const char *(*to_string
)(ConditionType type
) = NULL
;
342 Condition
**list
= userdata
, *c
;
349 to_string
= streq(property
, "Asserts") ? assert_type_to_string
: condition_type_to_string
;
351 r
= sd_bus_message_open_container(reply
, 'a', "(sbbsi)");
355 LIST_FOREACH(conditions
, c
, *list
) {
359 c
->result
== CONDITION_UNTESTED
? 0 :
360 c
->result
== CONDITION_SUCCEEDED
? 1 : -1;
362 r
= sd_bus_message_append(reply
, "(sbbsi)",
364 c
->trigger
, c
->negate
,
365 c
->parameter
, tristate
);
371 return sd_bus_message_close_container(reply
);
374 static int property_get_load_error(
377 const char *interface
,
378 const char *property
,
379 sd_bus_message
*reply
,
381 sd_bus_error
*error
) {
383 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
390 if (u
->load_error
!= 0)
391 sd_bus_error_set_errno(&e
, u
->load_error
);
393 return sd_bus_message_append(reply
, "(ss)", e
.name
, e
.message
);
396 static int bus_verify_manage_units_async_full(
400 const char *polkit_message
,
401 sd_bus_message
*call
,
402 sd_bus_error
*error
) {
404 const char *details
[9] = {
409 if (polkit_message
) {
410 details
[4] = "polkit.message";
411 details
[5] = polkit_message
;
412 details
[6] = "polkit.gettext_domain";
413 details
[7] = GETTEXT_PACKAGE
;
416 return bus_verify_polkit_async(call
, capability
, "org.freedesktop.systemd1.manage-units", details
, false, UID_INVALID
, &u
->manager
->polkit_registry
, error
);
419 int bus_unit_method_start_generic(
420 sd_bus_message
*message
,
423 bool reload_if_possible
,
424 sd_bus_error
*error
) {
428 _cleanup_free_
char *verb
= NULL
;
429 static const char *const polkit_message_for_job
[_JOB_TYPE_MAX
] = {
430 [JOB_START
] = N_("Authentication is required to start '$(unit)'."),
431 [JOB_STOP
] = N_("Authentication is required to stop '$(unit)'."),
432 [JOB_RELOAD
] = N_("Authentication is required to reload '$(unit)'."),
433 [JOB_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
434 [JOB_TRY_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
440 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
442 r
= mac_selinux_unit_access_check(u
, message
, job_type
== JOB_STOP
? "stop" : "start", error
);
446 r
= sd_bus_message_read(message
, "s", &smode
);
450 mode
= job_mode_from_string(smode
);
452 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
454 if (reload_if_possible
)
455 verb
= strjoin("reload-or-", job_type_to_string(job_type
), NULL
);
457 verb
= strdup(job_type_to_string(job_type
));
461 r
= bus_verify_manage_units_async_full(
465 job_type
< _JOB_TYPE_MAX
? polkit_message_for_job
[job_type
] : NULL
,
471 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
473 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
476 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
477 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
480 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
481 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
484 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
485 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
488 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
489 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
492 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
493 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
496 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
497 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
500 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
501 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
504 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
514 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
518 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
525 who
= kill_who_from_string(swho
);
527 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
530 if (signo
<= 0 || signo
>= _NSIG
)
531 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
533 r
= bus_verify_manage_units_async_full(
537 N_("Authentication is required to kill '$(unit)'."),
543 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
545 r
= unit_kill(u
, who
, signo
, error
);
549 return sd_bus_reply_method_return(message
, NULL
);
552 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
559 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
563 r
= bus_verify_manage_units_async_full(
567 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
573 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
575 unit_reset_failed(u
);
577 return sd_bus_reply_method_return(message
, NULL
);
580 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
587 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
591 r
= sd_bus_message_read(message
, "b", &runtime
);
595 r
= bus_verify_manage_units_async_full(
599 N_("Authentication is required to set properties on '$(unit)'."),
605 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
607 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
611 return sd_bus_reply_method_return(message
, NULL
);
614 const sd_bus_vtable bus_unit_vtable
[] = {
615 SD_BUS_VTABLE_START(0),
617 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
618 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
619 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
620 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
621 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
622 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
623 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
624 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
625 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
626 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
627 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
628 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
629 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
630 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
631 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
632 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
633 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
634 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
635 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
636 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
637 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
638 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
639 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
640 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
641 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
642 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
643 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
644 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
645 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
646 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
647 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
648 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
649 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
650 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
651 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
652 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
653 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
654 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
655 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
656 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
657 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
658 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
659 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
660 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
661 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
662 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
663 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
664 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
665 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
666 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
667 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
668 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
669 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
670 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
671 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_snapshot
), SD_BUS_VTABLE_PROPERTY_CONST
),
672 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
673 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
674 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
675 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
676 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
677 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
678 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
679 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
680 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
681 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
682 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
683 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
684 SD_BUS_PROPERTY("NetClass", "u", NULL
, offsetof(Unit
, cgroup_netclass_id
), 0),
686 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
687 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
688 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
689 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
690 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
691 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
692 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
693 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
694 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
695 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
700 static int property_get_slice(
703 const char *interface
,
704 const char *property
,
705 sd_bus_message
*reply
,
707 sd_bus_error
*error
) {
715 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
718 static int property_get_current_memory(
721 const char *interface
,
722 const char *property
,
723 sd_bus_message
*reply
,
725 sd_bus_error
*error
) {
727 uint64_t sz
= (uint64_t) -1;
735 r
= unit_get_memory_current(u
, &sz
);
736 if (r
< 0 && r
!= -ENODATA
)
737 log_unit_warning_errno(u
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
739 return sd_bus_message_append(reply
, "t", sz
);
742 static int property_get_current_tasks(
745 const char *interface
,
746 const char *property
,
747 sd_bus_message
*reply
,
749 sd_bus_error
*error
) {
751 uint64_t cn
= (uint64_t) -1;
759 r
= unit_get_tasks_current(u
, &cn
);
760 if (r
< 0 && r
!= -ENODATA
)
761 log_unit_warning_errno(u
, r
, "Failed to get pids.current attribute: %m");
763 return sd_bus_message_append(reply
, "t", cn
);
766 static int property_get_cpu_usage(
769 const char *interface
,
770 const char *property
,
771 sd_bus_message
*reply
,
773 sd_bus_error
*error
) {
775 nsec_t ns
= (nsec_t
) -1;
783 r
= unit_get_cpu_usage(u
, &ns
);
784 if (r
< 0 && r
!= -ENODATA
)
785 log_unit_warning_errno(u
, r
, "Failed to get cpuacct.usage attribute: %m");
787 return sd_bus_message_append(reply
, "t", ns
);
790 static int property_get_cgroup(
793 const char *interface
,
794 const char *property
,
795 sd_bus_message
*reply
,
797 sd_bus_error
*error
) {
806 /* Three cases: a) u->cgroup_path is NULL, in which case the
807 * unit has no control group, which we report as the empty
808 * string. b) u->cgroup_path is the empty string, which
809 * indicates the root cgroup, which we report as "/". c) all
810 * other cases we report as-is. */
813 t
= isempty(u
->cgroup_path
) ? "/" : u
->cgroup_path
;
817 return sd_bus_message_append(reply
, "s", t
);
820 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
821 SD_BUS_VTABLE_START(0),
822 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
823 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup
, 0, 0),
824 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
825 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
826 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks
, 0, 0),
830 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
831 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
832 _cleanup_free_
char *p
= NULL
;
839 p
= unit_dbus_path(u
);
843 r
= sd_bus_message_new_signal(
846 "/org/freedesktop/systemd1",
847 "org.freedesktop.systemd1.Manager",
852 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
856 return sd_bus_send(bus
, m
, NULL
);
859 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
860 _cleanup_free_
char *p
= NULL
;
867 p
= unit_dbus_path(u
);
871 /* Send a properties changed signal. First for the specific
872 * type, then for the generic unit. The clients may rely on
873 * this order to get atomic behavior if needed. */
875 r
= sd_bus_emit_properties_changed_strv(
877 unit_dbus_interface_from_type(u
->type
),
882 return sd_bus_emit_properties_changed_strv(
884 "org.freedesktop.systemd1.Unit",
888 void bus_unit_send_change_signal(Unit
*u
) {
892 if (u
->in_dbus_queue
) {
893 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
894 u
->in_dbus_queue
= false;
900 r
= bus_foreach_bus(u
->manager
, NULL
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
902 log_unit_debug_errno(u
, r
, "Failed to send unit change signal for %s: %m", u
->id
);
904 u
->sent_dbus_new_signal
= true;
907 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
908 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
909 _cleanup_free_
char *p
= NULL
;
916 p
= unit_dbus_path(u
);
920 r
= sd_bus_message_new_signal(
923 "/org/freedesktop/systemd1",
924 "org.freedesktop.systemd1.Manager",
929 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
933 return sd_bus_send(bus
, m
, NULL
);
936 void bus_unit_send_removed_signal(Unit
*u
) {
940 if (!u
->sent_dbus_new_signal
)
941 bus_unit_send_change_signal(u
);
946 r
= bus_foreach_bus(u
->manager
, NULL
, send_removed_signal
, u
);
948 log_unit_debug_errno(u
, r
, "Failed to send unit remove signal for %s: %m", u
->id
);
951 int bus_unit_queue_job(
952 sd_bus_message
*message
,
956 bool reload_if_possible
,
957 sd_bus_error
*error
) {
959 _cleanup_free_
char *path
= NULL
;
965 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
966 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
968 if (reload_if_possible
&& unit_can_reload(u
)) {
969 if (type
== JOB_RESTART
)
970 type
= JOB_RELOAD_OR_START
;
971 else if (type
== JOB_TRY_RESTART
)
975 r
= mac_selinux_unit_access_check(
977 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
978 type
== JOB_STOP
? "stop" : "reload", error
);
982 if (type
== JOB_STOP
&&
983 (u
->load_state
== UNIT_NOT_FOUND
|| u
->load_state
== UNIT_ERROR
) &&
984 unit_active_state(u
) == UNIT_INACTIVE
)
985 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
987 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
988 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
989 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)))
990 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only.", u
->id
);
992 r
= manager_add_job(u
->manager
, type
, u
, mode
, true, error
, &j
);
996 if (sd_bus_message_get_bus(message
) == u
->manager
->api_bus
) {
998 r
= sd_bus_track_new(sd_bus_message_get_bus(message
), &j
->clients
, NULL
, NULL
);
1003 r
= sd_bus_track_add_sender(j
->clients
, message
);
1008 path
= job_dbus_path(j
);
1012 return sd_bus_reply_method_return(message
, "o", path
);
1015 static int bus_unit_set_transient_property(
1018 sd_bus_message
*message
,
1019 UnitSetPropertiesMode mode
,
1020 sd_bus_error
*error
) {
1028 if (streq(name
, "Description")) {
1031 r
= sd_bus_message_read(message
, "s", &d
);
1035 if (mode
!= UNIT_CHECK
) {
1036 r
= unit_set_description(u
, d
);
1040 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDescription=%s\n", d
);
1045 } else if (streq(name
, "DefaultDependencies")) {
1048 r
= sd_bus_message_read(message
, "b", &b
);
1052 if (mode
!= UNIT_CHECK
) {
1053 u
->default_dependencies
= b
;
1054 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDefaultDependencies=%s\n", yes_no(b
));
1059 } else if (streq(name
, "Slice")) {
1063 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
1064 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "The slice property is only available for units with control groups.");
1065 if (u
->type
== UNIT_SLICE
)
1066 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Slice may not be set for slice units.");
1067 if (unit_has_name(u
, SPECIAL_INIT_SCOPE
))
1068 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Cannot set slice for init.scope");
1070 r
= sd_bus_message_read(message
, "s", &s
);
1074 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
))
1075 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name '%s'", s
);
1077 r
= manager_load_unit(u
->manager
, s
, NULL
, error
, &slice
);
1081 if (slice
->type
!= UNIT_SLICE
)
1082 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name '%s' is not a slice", s
);
1084 if (mode
!= UNIT_CHECK
) {
1085 r
= unit_set_slice(u
, slice
);
1089 unit_write_drop_in_private_format(u
, mode
, name
, "Slice=%s\n", s
);
1094 } else if (STR_IN_SET(name
,
1095 "Requires", "RequiresOverridable",
1096 "Requisite", "RequisiteOverridable",
1102 "PropagatesReloadTo", "ReloadPropagatedFrom",
1108 d
= unit_dependency_from_string(name
);
1112 r
= sd_bus_message_enter_container(message
, 'a', "s");
1116 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
1117 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1118 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
1120 if (mode
!= UNIT_CHECK
) {
1121 _cleanup_free_
char *label
= NULL
;
1123 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true);
1127 label
= strjoin(name
, "-", other
, NULL
);
1131 unit_write_drop_in_format(u
, mode
, label
, "[Unit]\n%s=%s\n", name
, other
);
1138 r
= sd_bus_message_exit_container(message
);
1148 int bus_unit_set_properties(
1150 sd_bus_message
*message
,
1151 UnitSetPropertiesMode mode
,
1153 sd_bus_error
*error
) {
1155 bool for_real
= false;
1162 /* We iterate through the array twice. First run we just check
1163 * if all passed data is valid, second run actually applies
1164 * it. This is to implement transaction-like behaviour without
1165 * actually providing full transactions. */
1167 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1174 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1178 if (for_real
|| mode
== UNIT_CHECK
)
1181 /* Reached EOF. Let's try again, and this time for realz... */
1182 r
= sd_bus_message_rewind(message
, false);
1190 r
= sd_bus_message_read(message
, "s", &name
);
1194 if (!UNIT_VTABLE(u
)->bus_set_property
)
1195 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1197 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1201 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1202 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1203 r
= bus_unit_set_transient_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1207 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1209 r
= sd_bus_message_exit_container(message
);
1213 r
= sd_bus_message_exit_container(message
);
1220 r
= sd_bus_message_exit_container(message
);
1224 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1225 UNIT_VTABLE(u
)->bus_commit_properties(u
);