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 "selinux-access.h"
25 #include "cgroup-util.h"
27 #include "bus-common-errors.h"
30 #include "dbus-unit.h"
32 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state
, unit_load_state
, UnitLoadState
);
33 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode
, job_mode
, JobMode
);
34 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action
, failure_action
, FailureAction
);
36 static int property_get_names(
39 const char *interface
,
41 sd_bus_message
*reply
,
43 sd_bus_error
*error
) {
54 r
= sd_bus_message_open_container(reply
, 'a', "s");
58 SET_FOREACH(t
, u
->names
, i
) {
59 r
= sd_bus_message_append(reply
, "s", t
);
64 return sd_bus_message_close_container(reply
);
67 static int property_get_following(
70 const char *interface
,
72 sd_bus_message
*reply
,
74 sd_bus_error
*error
) {
76 Unit
*u
= userdata
, *f
;
82 f
= unit_following(u
);
83 return sd_bus_message_append(reply
, "s", f
? f
->id
: "");
86 static int property_get_dependencies(
89 const char *interface
,
91 sd_bus_message
*reply
,
93 sd_bus_error
*error
) {
95 Set
*s
= *(Set
**) userdata
;
103 r
= sd_bus_message_open_container(reply
, 'a', "s");
107 SET_FOREACH(u
, s
, j
) {
108 r
= sd_bus_message_append(reply
, "s", u
->id
);
113 return sd_bus_message_close_container(reply
);
116 static int property_get_description(
119 const char *interface
,
120 const char *property
,
121 sd_bus_message
*reply
,
123 sd_bus_error
*error
) {
131 return sd_bus_message_append(reply
, "s", unit_description(u
));
134 static int property_get_active_state(
137 const char *interface
,
138 const char *property
,
139 sd_bus_message
*reply
,
141 sd_bus_error
*error
) {
149 return sd_bus_message_append(reply
, "s", unit_active_state_to_string(unit_active_state(u
)));
152 static int property_get_sub_state(
155 const char *interface
,
156 const char *property
,
157 sd_bus_message
*reply
,
159 sd_bus_error
*error
) {
167 return sd_bus_message_append(reply
, "s", unit_sub_state_to_string(u
));
170 static int property_get_unit_file_preset(
173 const char *interface
,
174 const char *property
,
175 sd_bus_message
*reply
,
177 sd_bus_error
*error
) {
186 r
= unit_get_unit_file_preset(u
);
188 return sd_bus_message_append(reply
, "s",
190 r
> 0 ? "enabled" : "disabled");
193 static int property_get_unit_file_state(
196 const char *interface
,
197 const char *property
,
198 sd_bus_message
*reply
,
200 sd_bus_error
*error
) {
208 return sd_bus_message_append(reply
, "s", unit_file_state_to_string(unit_get_unit_file_state(u
)));
211 static int property_get_can_start(
214 const char *interface
,
215 const char *property
,
216 sd_bus_message
*reply
,
218 sd_bus_error
*error
) {
226 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_start
);
229 static int property_get_can_stop(
232 const char *interface
,
233 const char *property
,
234 sd_bus_message
*reply
,
236 sd_bus_error
*error
) {
244 /* On the lower levels we assume that every unit we can start
245 * we can also stop */
247 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_stop
);
250 static int property_get_can_reload(
253 const char *interface
,
254 const char *property
,
255 sd_bus_message
*reply
,
257 sd_bus_error
*error
) {
265 return sd_bus_message_append(reply
, "b", unit_can_reload(u
));
268 static int property_get_can_isolate(
271 const char *interface
,
272 const char *property
,
273 sd_bus_message
*reply
,
275 sd_bus_error
*error
) {
283 return sd_bus_message_append(reply
, "b", unit_can_isolate(u
) && !u
->refuse_manual_start
);
286 static int property_get_job(
289 const char *interface
,
290 const char *property
,
291 sd_bus_message
*reply
,
293 sd_bus_error
*error
) {
295 _cleanup_free_
char *p
= NULL
;
303 return sd_bus_message_append(reply
, "(uo)", 0, "/");
305 p
= job_dbus_path(u
->job
);
309 return sd_bus_message_append(reply
, "(uo)", u
->job
->id
, p
);
312 static int property_get_need_daemon_reload(
315 const char *interface
,
316 const char *property
,
317 sd_bus_message
*reply
,
319 sd_bus_error
*error
) {
327 return sd_bus_message_append(reply
, "b", unit_need_daemon_reload(u
));
330 static int property_get_conditions(
333 const char *interface
,
334 const char *property
,
335 sd_bus_message
*reply
,
337 sd_bus_error
*error
) {
339 const char *(*to_string
)(ConditionType type
) = NULL
;
340 Condition
**list
= userdata
, *c
;
347 to_string
= streq(property
, "Asserts") ? assert_type_to_string
: condition_type_to_string
;
349 r
= sd_bus_message_open_container(reply
, 'a', "(sbbsi)");
353 LIST_FOREACH(conditions
, c
, *list
) {
357 c
->result
== CONDITION_UNTESTED
? 0 :
358 c
->result
== CONDITION_SUCCEEDED
? 1 : -1;
360 r
= sd_bus_message_append(reply
, "(sbbsi)",
362 c
->trigger
, c
->negate
,
363 c
->parameter
, tristate
);
369 return sd_bus_message_close_container(reply
);
372 static int property_get_load_error(
375 const char *interface
,
376 const char *property
,
377 sd_bus_message
*reply
,
379 sd_bus_error
*error
) {
381 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
388 if (u
->load_error
!= 0)
389 sd_bus_error_set_errno(&e
, u
->load_error
);
391 return sd_bus_message_append(reply
, "(ss)", e
.name
, e
.message
);
394 static int bus_verify_manage_units_async_full(
398 const char *polkit_message
,
399 sd_bus_message
*call
,
400 sd_bus_error
*error
) {
402 const char *details
[9] = {
407 if (polkit_message
) {
408 details
[4] = "polkit.message";
409 details
[5] = polkit_message
;
410 details
[6] = "polkit.gettext_domain";
411 details
[7] = GETTEXT_PACKAGE
;
414 return bus_verify_polkit_async(call
, capability
, "org.freedesktop.systemd1.manage-units", details
, false, UID_INVALID
, &u
->manager
->polkit_registry
, error
);
417 int bus_unit_method_start_generic(
418 sd_bus_message
*message
,
421 bool reload_if_possible
,
422 sd_bus_error
*error
) {
426 _cleanup_free_
char *verb
= NULL
;
427 static const char *const polkit_message_for_job
[_JOB_TYPE_MAX
] = {
428 [JOB_START
] = N_("Authentication is required to start '$(unit)'."),
429 [JOB_STOP
] = N_("Authentication is required to stop '$(unit)'."),
430 [JOB_RELOAD
] = N_("Authentication is required to reload '$(unit)'."),
431 [JOB_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
432 [JOB_TRY_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
438 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
440 r
= mac_selinux_unit_access_check(u
, message
, job_type
== JOB_STOP
? "stop" : "start", error
);
444 r
= sd_bus_message_read(message
, "s", &smode
);
448 mode
= job_mode_from_string(smode
);
450 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
452 if (reload_if_possible
)
453 verb
= strjoin("reload-or-", job_type_to_string(job_type
), NULL
);
455 verb
= strdup(job_type_to_string(job_type
));
459 r
= bus_verify_manage_units_async_full(
463 job_type
< _JOB_TYPE_MAX
? polkit_message_for_job
[job_type
] : NULL
,
469 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
471 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
474 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
475 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
478 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
479 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
482 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
483 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
486 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
487 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
490 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
491 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
494 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
495 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
498 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
499 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
502 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
512 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
516 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
523 who
= kill_who_from_string(swho
);
525 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
528 if (signo
<= 0 || signo
>= _NSIG
)
529 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
531 r
= bus_verify_manage_units_async_full(
535 N_("Authentication is required to kill '$(unit)'."),
541 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
543 r
= unit_kill(u
, who
, signo
, error
);
547 return sd_bus_reply_method_return(message
, NULL
);
550 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
557 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
561 r
= bus_verify_manage_units_async_full(
565 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
571 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
573 unit_reset_failed(u
);
575 return sd_bus_reply_method_return(message
, NULL
);
578 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
585 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
589 r
= sd_bus_message_read(message
, "b", &runtime
);
593 r
= bus_verify_manage_units_async_full(
597 N_("Authentication is required to set properties on '$(unit)'."),
603 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
605 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
609 return sd_bus_reply_method_return(message
, NULL
);
612 const sd_bus_vtable bus_unit_vtable
[] = {
613 SD_BUS_VTABLE_START(0),
615 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
616 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
617 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
618 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
619 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
620 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
621 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
622 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
623 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
624 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
625 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
626 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
627 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
628 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
629 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
630 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
631 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
632 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
633 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
634 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
635 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
636 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
637 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
638 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
639 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
640 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
641 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
642 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
643 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
644 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
645 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
646 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
647 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
648 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
649 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
650 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
651 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
652 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
653 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
654 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
655 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
656 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
657 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
658 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
659 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
660 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
661 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
662 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
663 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
664 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
665 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
666 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
667 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
668 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
669 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_snapshot
), SD_BUS_VTABLE_PROPERTY_CONST
),
670 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
671 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
672 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
673 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
674 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
675 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
676 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
677 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
678 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
679 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
680 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
681 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
683 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
684 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
685 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
686 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
687 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
688 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
689 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
690 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
691 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
692 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
697 static int property_get_slice(
700 const char *interface
,
701 const char *property
,
702 sd_bus_message
*reply
,
704 sd_bus_error
*error
) {
712 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
715 static int property_get_current_memory(
718 const char *interface
,
719 const char *property
,
720 sd_bus_message
*reply
,
722 sd_bus_error
*error
) {
724 uint64_t sz
= (uint64_t) -1;
732 r
= unit_get_memory_current(u
, &sz
);
733 if (r
< 0 && r
!= -ENODATA
)
734 log_unit_warning_errno(u
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
736 return sd_bus_message_append(reply
, "t", sz
);
739 static int property_get_current_tasks(
742 const char *interface
,
743 const char *property
,
744 sd_bus_message
*reply
,
746 sd_bus_error
*error
) {
748 uint64_t cn
= (uint64_t) -1;
756 r
= unit_get_tasks_current(u
, &cn
);
757 if (r
< 0 && r
!= -ENODATA
)
758 log_unit_warning_errno(u
, r
, "Failed to get pids.current attribute: %m");
760 return sd_bus_message_append(reply
, "t", cn
);
763 static int property_get_cpu_usage(
766 const char *interface
,
767 const char *property
,
768 sd_bus_message
*reply
,
770 sd_bus_error
*error
) {
772 nsec_t ns
= (nsec_t
) -1;
780 r
= unit_get_cpu_usage(u
, &ns
);
781 if (r
< 0 && r
!= -ENODATA
)
782 log_unit_warning_errno(u
, r
, "Failed to get cpuacct.usage attribute: %m");
784 return sd_bus_message_append(reply
, "t", ns
);
787 static int property_get_cgroup(
790 const char *interface
,
791 const char *property
,
792 sd_bus_message
*reply
,
794 sd_bus_error
*error
) {
803 /* Three cases: a) u->cgroup_path is NULL, in which case the
804 * unit has no control group, which we report as the empty
805 * string. b) u->cgroup_path is the empty string, which
806 * indicates the root cgroup, which we report as "/". c) all
807 * other cases we report as-is. */
810 t
= isempty(u
->cgroup_path
) ? "/" : u
->cgroup_path
;
814 return sd_bus_message_append(reply
, "s", t
);
817 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
818 SD_BUS_VTABLE_START(0),
819 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
820 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup
, 0, 0),
821 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
822 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
823 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks
, 0, 0),
827 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
828 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
829 _cleanup_free_
char *p
= NULL
;
836 p
= unit_dbus_path(u
);
840 r
= sd_bus_message_new_signal(
843 "/org/freedesktop/systemd1",
844 "org.freedesktop.systemd1.Manager",
849 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
853 return sd_bus_send(bus
, m
, NULL
);
856 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
857 _cleanup_free_
char *p
= NULL
;
864 p
= unit_dbus_path(u
);
868 /* Send a properties changed signal. First for the specific
869 * type, then for the generic unit. The clients may rely on
870 * this order to get atomic behavior if needed. */
872 r
= sd_bus_emit_properties_changed_strv(
874 unit_dbus_interface_from_type(u
->type
),
879 return sd_bus_emit_properties_changed_strv(
881 "org.freedesktop.systemd1.Unit",
885 void bus_unit_send_change_signal(Unit
*u
) {
889 if (u
->in_dbus_queue
) {
890 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
891 u
->in_dbus_queue
= false;
897 r
= bus_foreach_bus(u
->manager
, NULL
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
899 log_unit_debug_errno(u
, r
, "Failed to send unit change signal for %s: %m", u
->id
);
901 u
->sent_dbus_new_signal
= true;
904 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
905 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
906 _cleanup_free_
char *p
= NULL
;
913 p
= unit_dbus_path(u
);
917 r
= sd_bus_message_new_signal(
920 "/org/freedesktop/systemd1",
921 "org.freedesktop.systemd1.Manager",
926 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
930 return sd_bus_send(bus
, m
, NULL
);
933 void bus_unit_send_removed_signal(Unit
*u
) {
937 if (!u
->sent_dbus_new_signal
)
938 bus_unit_send_change_signal(u
);
943 r
= bus_foreach_bus(u
->manager
, NULL
, send_removed_signal
, u
);
945 log_unit_debug_errno(u
, r
, "Failed to send unit remove signal for %s: %m", u
->id
);
948 int bus_unit_queue_job(
949 sd_bus_message
*message
,
953 bool reload_if_possible
,
954 sd_bus_error
*error
) {
956 _cleanup_free_
char *path
= NULL
;
962 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
963 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
965 if (reload_if_possible
&& unit_can_reload(u
)) {
966 if (type
== JOB_RESTART
)
967 type
= JOB_RELOAD_OR_START
;
968 else if (type
== JOB_TRY_RESTART
)
972 r
= mac_selinux_unit_access_check(
974 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
975 type
== JOB_STOP
? "stop" : "reload", error
);
979 if (type
== JOB_STOP
&&
980 (u
->load_state
== UNIT_NOT_FOUND
|| u
->load_state
== UNIT_ERROR
) &&
981 unit_active_state(u
) == UNIT_INACTIVE
)
982 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
984 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
985 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
986 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)))
987 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only.", u
->id
);
989 r
= manager_add_job(u
->manager
, type
, u
, mode
, true, error
, &j
);
993 if (sd_bus_message_get_bus(message
) == u
->manager
->api_bus
) {
995 r
= sd_bus_track_new(sd_bus_message_get_bus(message
), &j
->clients
, NULL
, NULL
);
1000 r
= sd_bus_track_add_sender(j
->clients
, message
);
1005 path
= job_dbus_path(j
);
1009 return sd_bus_reply_method_return(message
, "o", path
);
1012 static int bus_unit_set_transient_property(
1015 sd_bus_message
*message
,
1016 UnitSetPropertiesMode mode
,
1017 sd_bus_error
*error
) {
1025 if (streq(name
, "Description")) {
1028 r
= sd_bus_message_read(message
, "s", &d
);
1032 if (mode
!= UNIT_CHECK
) {
1033 r
= unit_set_description(u
, d
);
1037 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDescription=%s\n", d
);
1042 } else if (streq(name
, "DefaultDependencies")) {
1045 r
= sd_bus_message_read(message
, "b", &b
);
1049 if (mode
!= UNIT_CHECK
) {
1050 u
->default_dependencies
= b
;
1051 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDefaultDependencies=%s\n", yes_no(b
));
1056 } else if (streq(name
, "Slice")) {
1060 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
1061 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "The slice property is only available for units with control groups.");
1062 if (u
->type
== UNIT_SLICE
)
1063 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Slice may not be set for slice units.");
1064 if (unit_has_name(u
, SPECIAL_INIT_SCOPE
))
1065 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Cannot set slice for init.scope");
1067 r
= sd_bus_message_read(message
, "s", &s
);
1071 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
))
1072 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name '%s'", s
);
1074 r
= manager_load_unit(u
->manager
, s
, NULL
, error
, &slice
);
1078 if (slice
->type
!= UNIT_SLICE
)
1079 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name '%s' is not a slice", s
);
1081 if (mode
!= UNIT_CHECK
) {
1082 r
= unit_set_slice(u
, slice
);
1086 unit_write_drop_in_private_format(u
, mode
, name
, "Slice=%s\n", s
);
1091 } else if (STR_IN_SET(name
,
1092 "Requires", "RequiresOverridable",
1093 "Requisite", "RequisiteOverridable",
1099 "PropagatesReloadTo", "ReloadPropagatedFrom",
1105 d
= unit_dependency_from_string(name
);
1109 r
= sd_bus_message_enter_container(message
, 'a', "s");
1113 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
1114 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1115 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
1117 if (mode
!= UNIT_CHECK
) {
1118 _cleanup_free_
char *label
= NULL
;
1120 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true);
1124 label
= strjoin(name
, "-", other
, NULL
);
1128 unit_write_drop_in_format(u
, mode
, label
, "[Unit]\n%s=%s\n", name
, other
);
1135 r
= sd_bus_message_exit_container(message
);
1145 int bus_unit_set_properties(
1147 sd_bus_message
*message
,
1148 UnitSetPropertiesMode mode
,
1150 sd_bus_error
*error
) {
1152 bool for_real
= false;
1159 /* We iterate through the array twice. First run we just check
1160 * if all passed data is valid, second run actually applies
1161 * it. This is to implement transaction-like behaviour without
1162 * actually providing full transactions. */
1164 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1171 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1175 if (for_real
|| mode
== UNIT_CHECK
)
1178 /* Reached EOF. Let's try again, and this time for realz... */
1179 r
= sd_bus_message_rewind(message
, false);
1187 r
= sd_bus_message_read(message
, "s", &name
);
1191 if (!UNIT_VTABLE(u
)->bus_set_property
)
1192 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1194 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1198 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1199 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1200 r
= bus_unit_set_transient_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1204 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1206 r
= sd_bus_message_exit_container(message
);
1210 r
= sd_bus_message_exit_container(message
);
1217 r
= sd_bus_message_exit_container(message
);
1221 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1222 UNIT_VTABLE(u
)->bus_commit_properties(u
);