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 "alloc-util.h"
25 #include "bus-common-errors.h"
26 #include "cgroup-util.h"
27 #include "dbus-unit.h"
29 #include "locale-util.h"
31 #include "selinux-access.h"
33 #include "string-util.h"
35 #include "user-util.h"
37 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state
, unit_load_state
, UnitLoadState
);
38 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode
, job_mode
, JobMode
);
39 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action
, failure_action
, FailureAction
);
41 static int property_get_names(
44 const char *interface
,
46 sd_bus_message
*reply
,
48 sd_bus_error
*error
) {
59 r
= sd_bus_message_open_container(reply
, 'a', "s");
63 SET_FOREACH(t
, u
->names
, i
) {
64 r
= sd_bus_message_append(reply
, "s", t
);
69 return sd_bus_message_close_container(reply
);
72 static int property_get_following(
75 const char *interface
,
77 sd_bus_message
*reply
,
79 sd_bus_error
*error
) {
81 Unit
*u
= userdata
, *f
;
87 f
= unit_following(u
);
88 return sd_bus_message_append(reply
, "s", f
? f
->id
: "");
91 static int property_get_dependencies(
94 const char *interface
,
96 sd_bus_message
*reply
,
98 sd_bus_error
*error
) {
100 Set
*s
= *(Set
**) userdata
;
108 r
= sd_bus_message_open_container(reply
, 'a', "s");
112 SET_FOREACH(u
, s
, j
) {
113 r
= sd_bus_message_append(reply
, "s", u
->id
);
118 return sd_bus_message_close_container(reply
);
121 static int property_get_obsolete_dependencies(
124 const char *interface
,
125 const char *property
,
126 sd_bus_message
*reply
,
128 sd_bus_error
*error
) {
133 /* For dependency types we don't support anymore always return an empty array */
134 return sd_bus_message_append(reply
, "as", 0);
137 static int property_get_description(
140 const char *interface
,
141 const char *property
,
142 sd_bus_message
*reply
,
144 sd_bus_error
*error
) {
152 return sd_bus_message_append(reply
, "s", unit_description(u
));
155 static int property_get_active_state(
158 const char *interface
,
159 const char *property
,
160 sd_bus_message
*reply
,
162 sd_bus_error
*error
) {
170 return sd_bus_message_append(reply
, "s", unit_active_state_to_string(unit_active_state(u
)));
173 static int property_get_sub_state(
176 const char *interface
,
177 const char *property
,
178 sd_bus_message
*reply
,
180 sd_bus_error
*error
) {
188 return sd_bus_message_append(reply
, "s", unit_sub_state_to_string(u
));
191 static int property_get_unit_file_preset(
194 const char *interface
,
195 const char *property
,
196 sd_bus_message
*reply
,
198 sd_bus_error
*error
) {
207 r
= unit_get_unit_file_preset(u
);
209 return sd_bus_message_append(reply
, "s",
211 r
> 0 ? "enabled" : "disabled");
214 static int property_get_unit_file_state(
217 const char *interface
,
218 const char *property
,
219 sd_bus_message
*reply
,
221 sd_bus_error
*error
) {
229 return sd_bus_message_append(reply
, "s", unit_file_state_to_string(unit_get_unit_file_state(u
)));
232 static int property_get_can_start(
235 const char *interface
,
236 const char *property
,
237 sd_bus_message
*reply
,
239 sd_bus_error
*error
) {
247 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_start
);
250 static int property_get_can_stop(
253 const char *interface
,
254 const char *property
,
255 sd_bus_message
*reply
,
257 sd_bus_error
*error
) {
265 /* On the lower levels we assume that every unit we can start
266 * we can also stop */
268 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_stop
);
271 static int property_get_can_reload(
274 const char *interface
,
275 const char *property
,
276 sd_bus_message
*reply
,
278 sd_bus_error
*error
) {
286 return sd_bus_message_append(reply
, "b", unit_can_reload(u
));
289 static int property_get_can_isolate(
292 const char *interface
,
293 const char *property
,
294 sd_bus_message
*reply
,
296 sd_bus_error
*error
) {
304 return sd_bus_message_append(reply
, "b", unit_can_isolate(u
) && !u
->refuse_manual_start
);
307 static int property_get_job(
310 const char *interface
,
311 const char *property
,
312 sd_bus_message
*reply
,
314 sd_bus_error
*error
) {
316 _cleanup_free_
char *p
= NULL
;
324 return sd_bus_message_append(reply
, "(uo)", 0, "/");
326 p
= job_dbus_path(u
->job
);
330 return sd_bus_message_append(reply
, "(uo)", u
->job
->id
, p
);
333 static int property_get_need_daemon_reload(
336 const char *interface
,
337 const char *property
,
338 sd_bus_message
*reply
,
340 sd_bus_error
*error
) {
348 return sd_bus_message_append(reply
, "b", unit_need_daemon_reload(u
));
351 static int property_get_conditions(
354 const char *interface
,
355 const char *property
,
356 sd_bus_message
*reply
,
358 sd_bus_error
*error
) {
360 const char *(*to_string
)(ConditionType type
) = NULL
;
361 Condition
**list
= userdata
, *c
;
368 to_string
= streq(property
, "Asserts") ? assert_type_to_string
: condition_type_to_string
;
370 r
= sd_bus_message_open_container(reply
, 'a', "(sbbsi)");
374 LIST_FOREACH(conditions
, c
, *list
) {
378 c
->result
== CONDITION_UNTESTED
? 0 :
379 c
->result
== CONDITION_SUCCEEDED
? 1 : -1;
381 r
= sd_bus_message_append(reply
, "(sbbsi)",
383 c
->trigger
, c
->negate
,
384 c
->parameter
, tristate
);
390 return sd_bus_message_close_container(reply
);
393 static int property_get_load_error(
396 const char *interface
,
397 const char *property
,
398 sd_bus_message
*reply
,
400 sd_bus_error
*error
) {
402 _cleanup_(sd_bus_error_free
) sd_bus_error e
= SD_BUS_ERROR_NULL
;
409 if (u
->load_error
!= 0)
410 sd_bus_error_set_errno(&e
, u
->load_error
);
412 return sd_bus_message_append(reply
, "(ss)", e
.name
, e
.message
);
415 static int bus_verify_manage_units_async_full(
419 const char *polkit_message
,
420 sd_bus_message
*call
,
421 sd_bus_error
*error
) {
423 const char *details
[9] = {
428 if (polkit_message
) {
429 details
[4] = "polkit.message";
430 details
[5] = polkit_message
;
431 details
[6] = "polkit.gettext_domain";
432 details
[7] = GETTEXT_PACKAGE
;
435 return bus_verify_polkit_async(call
, capability
, "org.freedesktop.systemd1.manage-units", details
, false, UID_INVALID
, &u
->manager
->polkit_registry
, error
);
438 int bus_unit_method_start_generic(
439 sd_bus_message
*message
,
442 bool reload_if_possible
,
443 sd_bus_error
*error
) {
447 _cleanup_free_
char *verb
= NULL
;
448 static const char *const polkit_message_for_job
[_JOB_TYPE_MAX
] = {
449 [JOB_START
] = N_("Authentication is required to start '$(unit)'."),
450 [JOB_STOP
] = N_("Authentication is required to stop '$(unit)'."),
451 [JOB_RELOAD
] = N_("Authentication is required to reload '$(unit)'."),
452 [JOB_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
453 [JOB_TRY_RESTART
] = N_("Authentication is required to restart '$(unit)'."),
459 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
461 r
= mac_selinux_unit_access_check(u
, message
, job_type
== JOB_STOP
? "stop" : "start", error
);
465 r
= sd_bus_message_read(message
, "s", &smode
);
469 mode
= job_mode_from_string(smode
);
471 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
473 if (reload_if_possible
)
474 verb
= strjoin("reload-or-", job_type_to_string(job_type
), NULL
);
476 verb
= strdup(job_type_to_string(job_type
));
480 r
= bus_verify_manage_units_async_full(
484 job_type
< _JOB_TYPE_MAX
? polkit_message_for_job
[job_type
] : NULL
,
490 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
492 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
495 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
496 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
499 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
500 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
503 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
504 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
507 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
508 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
511 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
512 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
515 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
516 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
519 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
520 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
523 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
533 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
537 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
544 who
= kill_who_from_string(swho
);
546 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
549 if (signo
<= 0 || signo
>= _NSIG
)
550 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
552 r
= bus_verify_manage_units_async_full(
556 N_("Authentication is required to kill '$(unit)'."),
562 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
564 r
= unit_kill(u
, who
, signo
, error
);
568 return sd_bus_reply_method_return(message
, NULL
);
571 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
578 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
582 r
= bus_verify_manage_units_async_full(
586 N_("Authentication is required to reset the \"failed\" state of '$(unit)'."),
592 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
594 unit_reset_failed(u
);
596 return sd_bus_reply_method_return(message
, NULL
);
599 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
606 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
610 r
= sd_bus_message_read(message
, "b", &runtime
);
614 r
= bus_verify_manage_units_async_full(
618 N_("Authentication is required to set properties on '$(unit)'."),
624 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
626 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
630 return sd_bus_reply_method_return(message
, NULL
);
633 const sd_bus_vtable bus_unit_vtable
[] = {
634 SD_BUS_VTABLE_START(0),
636 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
637 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
638 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
639 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
640 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
641 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
642 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
643 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
644 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
645 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
646 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
647 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
648 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
649 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
650 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
651 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
652 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
653 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
654 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
655 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
656 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
657 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
658 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
659 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
660 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
661 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
662 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies
, 0, SD_BUS_VTABLE_HIDDEN
),
663 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
664 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
665 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
666 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
667 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
668 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
669 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
670 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
671 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
672 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
673 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
674 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
675 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
676 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
677 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
678 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
679 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
680 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
681 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
682 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
683 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
684 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
685 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
686 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
687 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
688 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
689 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
690 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
691 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
692 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
693 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
694 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
695 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
696 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
697 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
698 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
699 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
700 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
701 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
702 SD_BUS_PROPERTY("NetClass", "u", NULL
, offsetof(Unit
, cgroup_netclass_id
), 0),
704 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
705 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
706 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
707 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
708 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
709 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
710 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
711 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
712 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
713 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
718 static int property_get_slice(
721 const char *interface
,
722 const char *property
,
723 sd_bus_message
*reply
,
725 sd_bus_error
*error
) {
733 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
736 static int property_get_current_memory(
739 const char *interface
,
740 const char *property
,
741 sd_bus_message
*reply
,
743 sd_bus_error
*error
) {
745 uint64_t sz
= (uint64_t) -1;
753 r
= unit_get_memory_current(u
, &sz
);
754 if (r
< 0 && r
!= -ENODATA
)
755 log_unit_warning_errno(u
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
757 return sd_bus_message_append(reply
, "t", sz
);
760 static int property_get_current_tasks(
763 const char *interface
,
764 const char *property
,
765 sd_bus_message
*reply
,
767 sd_bus_error
*error
) {
769 uint64_t cn
= (uint64_t) -1;
777 r
= unit_get_tasks_current(u
, &cn
);
778 if (r
< 0 && r
!= -ENODATA
)
779 log_unit_warning_errno(u
, r
, "Failed to get pids.current attribute: %m");
781 return sd_bus_message_append(reply
, "t", cn
);
784 static int property_get_cpu_usage(
787 const char *interface
,
788 const char *property
,
789 sd_bus_message
*reply
,
791 sd_bus_error
*error
) {
793 nsec_t ns
= (nsec_t
) -1;
801 r
= unit_get_cpu_usage(u
, &ns
);
802 if (r
< 0 && r
!= -ENODATA
)
803 log_unit_warning_errno(u
, r
, "Failed to get cpuacct.usage attribute: %m");
805 return sd_bus_message_append(reply
, "t", ns
);
808 static int property_get_cgroup(
811 const char *interface
,
812 const char *property
,
813 sd_bus_message
*reply
,
815 sd_bus_error
*error
) {
824 /* Three cases: a) u->cgroup_path is NULL, in which case the
825 * unit has no control group, which we report as the empty
826 * string. b) u->cgroup_path is the empty string, which
827 * indicates the root cgroup, which we report as "/". c) all
828 * other cases we report as-is. */
831 t
= isempty(u
->cgroup_path
) ? "/" : u
->cgroup_path
;
835 return sd_bus_message_append(reply
, "s", t
);
838 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
839 SD_BUS_VTABLE_START(0),
840 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
841 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup
, 0, 0),
842 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
843 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
844 SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks
, 0, 0),
848 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
849 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
850 _cleanup_free_
char *p
= NULL
;
857 p
= unit_dbus_path(u
);
861 r
= sd_bus_message_new_signal(
864 "/org/freedesktop/systemd1",
865 "org.freedesktop.systemd1.Manager",
870 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
874 return sd_bus_send(bus
, m
, NULL
);
877 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
878 _cleanup_free_
char *p
= NULL
;
885 p
= unit_dbus_path(u
);
889 /* Send a properties changed signal. First for the specific
890 * type, then for the generic unit. The clients may rely on
891 * this order to get atomic behavior if needed. */
893 r
= sd_bus_emit_properties_changed_strv(
895 unit_dbus_interface_from_type(u
->type
),
900 return sd_bus_emit_properties_changed_strv(
902 "org.freedesktop.systemd1.Unit",
906 void bus_unit_send_change_signal(Unit
*u
) {
910 if (u
->in_dbus_queue
) {
911 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
912 u
->in_dbus_queue
= false;
918 r
= bus_foreach_bus(u
->manager
, NULL
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
920 log_unit_debug_errno(u
, r
, "Failed to send unit change signal for %s: %m", u
->id
);
922 u
->sent_dbus_new_signal
= true;
925 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
926 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
927 _cleanup_free_
char *p
= NULL
;
934 p
= unit_dbus_path(u
);
938 r
= sd_bus_message_new_signal(
941 "/org/freedesktop/systemd1",
942 "org.freedesktop.systemd1.Manager",
947 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
951 return sd_bus_send(bus
, m
, NULL
);
954 void bus_unit_send_removed_signal(Unit
*u
) {
958 if (!u
->sent_dbus_new_signal
)
959 bus_unit_send_change_signal(u
);
964 r
= bus_foreach_bus(u
->manager
, NULL
, send_removed_signal
, u
);
966 log_unit_debug_errno(u
, r
, "Failed to send unit remove signal for %s: %m", u
->id
);
969 int bus_unit_queue_job(
970 sd_bus_message
*message
,
974 bool reload_if_possible
,
975 sd_bus_error
*error
) {
977 _cleanup_free_
char *path
= NULL
;
983 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
984 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
986 if (reload_if_possible
&& unit_can_reload(u
)) {
987 if (type
== JOB_RESTART
)
988 type
= JOB_RELOAD_OR_START
;
989 else if (type
== JOB_TRY_RESTART
)
993 r
= mac_selinux_unit_access_check(
995 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
996 type
== JOB_STOP
? "stop" : "reload", error
);
1000 if (type
== JOB_STOP
&&
1001 (u
->load_state
== UNIT_NOT_FOUND
|| u
->load_state
== UNIT_ERROR
) &&
1002 unit_active_state(u
) == UNIT_INACTIVE
)
1003 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
1005 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
1006 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
1007 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)) ||
1008 (type
== JOB_RELOAD_OR_START
&& job_type_collapse(type
, u
) == JOB_START
&& u
->refuse_manual_start
))
1009 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only.", u
->id
);
1011 r
= manager_add_job(u
->manager
, type
, u
, mode
, error
, &j
);
1015 if (sd_bus_message_get_bus(message
) == u
->manager
->api_bus
) {
1017 r
= sd_bus_track_new(sd_bus_message_get_bus(message
), &j
->clients
, NULL
, NULL
);
1022 r
= sd_bus_track_add_sender(j
->clients
, message
);
1027 path
= job_dbus_path(j
);
1031 return sd_bus_reply_method_return(message
, "o", path
);
1034 static int bus_unit_set_transient_property(
1037 sd_bus_message
*message
,
1038 UnitSetPropertiesMode mode
,
1039 sd_bus_error
*error
) {
1047 if (streq(name
, "Description")) {
1050 r
= sd_bus_message_read(message
, "s", &d
);
1054 if (mode
!= UNIT_CHECK
) {
1055 r
= unit_set_description(u
, d
);
1059 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDescription=%s\n", d
);
1064 } else if (streq(name
, "DefaultDependencies")) {
1067 r
= sd_bus_message_read(message
, "b", &b
);
1071 if (mode
!= UNIT_CHECK
) {
1072 u
->default_dependencies
= b
;
1073 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDefaultDependencies=%s\n", yes_no(b
));
1078 } else if (streq(name
, "Slice")) {
1082 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
1083 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "The slice property is only available for units with control groups.");
1084 if (u
->type
== UNIT_SLICE
)
1085 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Slice may not be set for slice units.");
1086 if (unit_has_name(u
, SPECIAL_INIT_SCOPE
))
1087 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Cannot set slice for init.scope");
1089 r
= sd_bus_message_read(message
, "s", &s
);
1093 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
))
1094 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name '%s'", s
);
1096 r
= manager_load_unit(u
->manager
, s
, NULL
, error
, &slice
);
1100 if (slice
->type
!= UNIT_SLICE
)
1101 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name '%s' is not a slice", s
);
1103 if (mode
!= UNIT_CHECK
) {
1104 r
= unit_set_slice(u
, slice
);
1108 unit_write_drop_in_private_format(u
, mode
, name
, "Slice=%s\n", s
);
1113 } else if (STR_IN_SET(name
,
1114 "Requires", "RequiresOverridable",
1115 "Requisite", "RequisiteOverridable",
1121 "PropagatesReloadTo", "ReloadPropagatedFrom",
1127 if (streq(name
, "RequiresOverridable"))
1128 d
= UNIT_REQUIRES
; /* redirect for obsolete unit dependency type */
1129 else if (streq(name
, "RequisiteOverridable"))
1130 d
= UNIT_REQUISITE
; /* same here */
1132 d
= unit_dependency_from_string(name
);
1134 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit dependency: %s", name
);
1137 r
= sd_bus_message_enter_container(message
, 'a', "s");
1141 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
1142 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1143 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
1145 if (mode
!= UNIT_CHECK
) {
1146 _cleanup_free_
char *label
= NULL
;
1148 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true);
1152 label
= strjoin(name
, "-", other
, NULL
);
1156 unit_write_drop_in_format(u
, mode
, label
, "[Unit]\n%s=%s\n", name
, other
);
1163 r
= sd_bus_message_exit_container(message
);
1173 int bus_unit_set_properties(
1175 sd_bus_message
*message
,
1176 UnitSetPropertiesMode mode
,
1178 sd_bus_error
*error
) {
1180 bool for_real
= false;
1187 /* We iterate through the array twice. First run we just check
1188 * if all passed data is valid, second run actually applies
1189 * it. This is to implement transaction-like behaviour without
1190 * actually providing full transactions. */
1192 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1199 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1203 if (for_real
|| mode
== UNIT_CHECK
)
1206 /* Reached EOF. Let's try again, and this time for realz... */
1207 r
= sd_bus_message_rewind(message
, false);
1215 r
= sd_bus_message_read(message
, "s", &name
);
1219 if (!UNIT_VTABLE(u
)->bus_set_property
)
1220 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1222 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1226 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1227 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1228 r
= bus_unit_set_transient_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1232 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1234 r
= sd_bus_message_exit_container(message
);
1238 r
= sd_bus_message_exit_container(message
);
1245 r
= sd_bus_message_exit_container(message
);
1249 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1250 UNIT_VTABLE(u
)->bus_commit_properties(u
);
1255 int bus_unit_check_load_state(Unit
*u
, sd_bus_error
*error
) {
1257 if (u
->load_state
== UNIT_LOADED
)
1260 /* Give a better description of the unit error when
1261 * possible. Note that in the case of UNIT_MASKED, load_error
1263 if (u
->load_state
== UNIT_MASKED
)
1264 return sd_bus_error_setf(error
, BUS_ERROR_UNIT_MASKED
, "Unit is masked.");
1266 if (u
->load_state
== UNIT_NOT_FOUND
)
1267 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit not found.");
1269 return sd_bus_error_set_errnof(error
, u
->load_error
, "Unit is not loaded properly: %m.");