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 int bus_unit_method_start_generic(
395 sd_bus_message
*message
,
398 bool reload_if_possible
,
399 sd_bus_error
*error
) {
407 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
409 r
= mac_selinux_unit_access_check(u
, message
, job_type
== JOB_STOP
? "stop" : "start", error
);
413 r
= sd_bus_message_read(message
, "s", &smode
);
417 mode
= job_mode_from_string(smode
);
419 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
421 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
425 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
427 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
430 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
431 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
434 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
435 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
438 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
439 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
442 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
443 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
446 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
447 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
450 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
451 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
454 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
455 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
458 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
468 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
472 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
479 who
= kill_who_from_string(swho
);
481 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
484 if (signo
<= 0 || signo
>= _NSIG
)
485 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
487 r
= bus_verify_manage_units_async_for_kill(u
->manager
, message
, error
);
491 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
493 r
= unit_kill(u
, who
, signo
, error
);
497 return sd_bus_reply_method_return(message
, NULL
);
500 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
507 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
511 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
515 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
517 unit_reset_failed(u
);
519 return sd_bus_reply_method_return(message
, NULL
);
522 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
529 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
533 r
= sd_bus_message_read(message
, "b", &runtime
);
537 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
541 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
543 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
547 return sd_bus_reply_method_return(message
, NULL
);
550 const sd_bus_vtable bus_unit_vtable
[] = {
551 SD_BUS_VTABLE_START(0),
553 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
554 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
555 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
556 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
557 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
558 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
559 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
560 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
561 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
562 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
563 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
564 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
565 SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
566 SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OF_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
567 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
568 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
569 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
570 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
571 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
572 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
573 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
574 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
575 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
576 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
577 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
578 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
579 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
580 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
581 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
582 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
583 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
584 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
585 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
586 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
587 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
588 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
589 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
590 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
591 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
592 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
593 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
594 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
595 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
596 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
597 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
598 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
599 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
600 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
601 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
602 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
603 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
604 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
605 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
606 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
607 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_snapshot
), SD_BUS_VTABLE_PROPERTY_CONST
),
608 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
609 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
610 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
611 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
612 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
613 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
614 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
615 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
616 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
617 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
618 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
619 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
621 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
622 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
623 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
624 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
625 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
626 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
627 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
628 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
629 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
630 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
635 static int property_get_slice(
638 const char *interface
,
639 const char *property
,
640 sd_bus_message
*reply
,
642 sd_bus_error
*error
) {
650 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
653 static int property_get_current_memory(
656 const char *interface
,
657 const char *property
,
658 sd_bus_message
*reply
,
660 sd_bus_error
*error
) {
662 uint64_t sz
= (uint64_t) -1;
670 r
= unit_get_memory_current(u
, &sz
);
671 if (r
< 0 && r
!= -ENODATA
)
672 log_unit_warning_errno(u
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
674 return sd_bus_message_append(reply
, "t", sz
);
677 static int property_get_cpu_usage(
680 const char *interface
,
681 const char *property
,
682 sd_bus_message
*reply
,
684 sd_bus_error
*error
) {
686 nsec_t ns
= (nsec_t
) -1;
694 r
= unit_get_cpu_usage(u
, &ns
);
695 if (r
< 0 && r
!= -ENODATA
)
696 log_unit_warning_errno(u
, r
, "Failed to get cpuacct.usage attribute: %m");
698 return sd_bus_message_append(reply
, "t", ns
);
701 static int property_get_cgroup(
704 const char *interface
,
705 const char *property
,
706 sd_bus_message
*reply
,
708 sd_bus_error
*error
) {
717 /* Three cases: a) u->cgroup_path is NULL, in which case the
718 * unit has no control group, which we report as the empty
719 * string. b) u->cgroup_path is the empty string, which
720 * indicates the root cgroup, which we report as "/". c) all
721 * other cases we report as-is. */
724 t
= isempty(u
->cgroup_path
) ? "/" : u
->cgroup_path
;
728 return sd_bus_message_append(reply
, "s", t
);
731 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
732 SD_BUS_VTABLE_START(0),
733 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
734 SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup
, 0, 0),
735 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
736 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
740 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
741 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
742 _cleanup_free_
char *p
= NULL
;
749 p
= unit_dbus_path(u
);
753 r
= sd_bus_message_new_signal(
756 "/org/freedesktop/systemd1",
757 "org.freedesktop.systemd1.Manager",
762 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
766 return sd_bus_send(bus
, m
, NULL
);
769 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
770 _cleanup_free_
char *p
= NULL
;
777 p
= unit_dbus_path(u
);
781 /* Send a properties changed signal. First for the specific
782 * type, then for the generic unit. The clients may rely on
783 * this order to get atomic behavior if needed. */
785 r
= sd_bus_emit_properties_changed_strv(
787 unit_dbus_interface_from_type(u
->type
),
792 return sd_bus_emit_properties_changed_strv(
794 "org.freedesktop.systemd1.Unit",
798 void bus_unit_send_change_signal(Unit
*u
) {
802 if (u
->in_dbus_queue
) {
803 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
804 u
->in_dbus_queue
= false;
810 r
= bus_foreach_bus(u
->manager
, NULL
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
812 log_unit_debug_errno(u
, r
, "Failed to send unit change signal for %s: %m", u
->id
);
814 u
->sent_dbus_new_signal
= true;
817 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
818 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
819 _cleanup_free_
char *p
= NULL
;
826 p
= unit_dbus_path(u
);
830 r
= sd_bus_message_new_signal(
833 "/org/freedesktop/systemd1",
834 "org.freedesktop.systemd1.Manager",
839 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
843 return sd_bus_send(bus
, m
, NULL
);
846 void bus_unit_send_removed_signal(Unit
*u
) {
850 if (!u
->sent_dbus_new_signal
)
851 bus_unit_send_change_signal(u
);
856 r
= bus_foreach_bus(u
->manager
, NULL
, send_removed_signal
, u
);
858 log_unit_debug_errno(u
, r
, "Failed to send unit remove signal for %s: %m", u
->id
);
861 int bus_unit_queue_job(
862 sd_bus_message
*message
,
866 bool reload_if_possible
,
867 sd_bus_error
*error
) {
869 _cleanup_free_
char *path
= NULL
;
875 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
876 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
878 if (reload_if_possible
&& unit_can_reload(u
)) {
879 if (type
== JOB_RESTART
)
880 type
= JOB_RELOAD_OR_START
;
881 else if (type
== JOB_TRY_RESTART
)
885 r
= mac_selinux_unit_access_check(
887 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
888 type
== JOB_STOP
? "stop" : "reload", error
);
892 if (type
== JOB_STOP
&&
893 (u
->load_state
== UNIT_NOT_FOUND
|| u
->load_state
== UNIT_ERROR
) &&
894 unit_active_state(u
) == UNIT_INACTIVE
)
895 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
897 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
898 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
899 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)))
900 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only.", u
->id
);
902 r
= manager_add_job(u
->manager
, type
, u
, mode
, true, error
, &j
);
906 if (sd_bus_message_get_bus(message
) == u
->manager
->api_bus
) {
908 r
= sd_bus_track_new(sd_bus_message_get_bus(message
), &j
->clients
, NULL
, NULL
);
913 r
= sd_bus_track_add_sender(j
->clients
, message
);
918 path
= job_dbus_path(j
);
922 return sd_bus_reply_method_return(message
, "o", path
);
925 static int bus_unit_set_transient_property(
928 sd_bus_message
*message
,
929 UnitSetPropertiesMode mode
,
930 sd_bus_error
*error
) {
938 if (streq(name
, "Description")) {
941 r
= sd_bus_message_read(message
, "s", &d
);
945 if (mode
!= UNIT_CHECK
) {
946 r
= unit_set_description(u
, d
);
950 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDescription=%s\n", d
);
955 } else if (streq(name
, "DefaultDependencies")) {
958 r
= sd_bus_message_read(message
, "b", &b
);
962 if (mode
!= UNIT_CHECK
) {
963 u
->default_dependencies
= b
;
964 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDefaultDependencies=%s\n", yes_no(b
));
969 } else if (streq(name
, "Slice")) {
973 if (!UNIT_HAS_CGROUP_CONTEXT(u
))
974 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "The slice property is only available for units with control groups.");
975 if (u
->type
== UNIT_SLICE
)
976 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Slice may not be set for slice units.");
977 if (unit_has_name(u
, SPECIAL_INIT_SCOPE
))
978 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Cannot set slice for init.scope");
980 r
= sd_bus_message_read(message
, "s", &s
);
984 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
))
985 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name '%s'", s
);
987 r
= manager_load_unit(u
->manager
, s
, NULL
, error
, &slice
);
991 if (slice
->type
!= UNIT_SLICE
)
992 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Unit name '%s' is not a slice", s
);
994 if (mode
!= UNIT_CHECK
) {
995 r
= unit_set_slice(u
, slice
);
999 unit_write_drop_in_private_format(u
, mode
, name
, "Slice=%s\n", s
);
1004 } else if (STR_IN_SET(name
,
1005 "Requires", "RequiresOverridable",
1006 "Requisite", "RequisiteOverridable",
1012 "PropagatesReloadTo", "ReloadPropagatedFrom",
1018 d
= unit_dependency_from_string(name
);
1022 r
= sd_bus_message_enter_container(message
, 'a', "s");
1026 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
1027 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
1028 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
1030 if (mode
!= UNIT_CHECK
) {
1031 _cleanup_free_
char *label
= NULL
;
1033 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true);
1037 label
= strjoin(name
, "-", other
, NULL
);
1041 unit_write_drop_in_format(u
, mode
, label
, "[Unit]\n%s=%s\n", name
, other
);
1048 r
= sd_bus_message_exit_container(message
);
1058 int bus_unit_set_properties(
1060 sd_bus_message
*message
,
1061 UnitSetPropertiesMode mode
,
1063 sd_bus_error
*error
) {
1065 bool for_real
= false;
1072 /* We iterate through the array twice. First run we just check
1073 * if all passed data is valid, second run actually applies
1074 * it. This is to implement transaction-like behaviour without
1075 * actually providing full transactions. */
1077 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1084 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1088 if (for_real
|| mode
== UNIT_CHECK
)
1091 /* Reached EOF. Let's try again, and this time for realz... */
1092 r
= sd_bus_message_rewind(message
, false);
1100 r
= sd_bus_message_read(message
, "s", &name
);
1104 if (!UNIT_VTABLE(u
)->bus_set_property
)
1105 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1107 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1111 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1112 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1113 r
= bus_unit_set_transient_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1117 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1119 r
= sd_bus_message_exit_container(message
);
1123 r
= sd_bus_message_exit_container(message
);
1130 r
= sd_bus_message_exit_container(message
);
1134 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1135 UNIT_VTABLE(u
)->bus_commit_properties(u
);