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"
29 #include "dbus-unit.h"
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state
, unit_load_state
, UnitLoadState
);
32 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode
, job_mode
, JobMode
);
33 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_failure_action
, failure_action
, FailureAction
);
35 static int property_get_names(
38 const char *interface
,
40 sd_bus_message
*reply
,
42 sd_bus_error
*error
) {
53 r
= sd_bus_message_open_container(reply
, 'a', "s");
57 SET_FOREACH(t
, u
->names
, i
) {
58 r
= sd_bus_message_append(reply
, "s", t
);
63 return sd_bus_message_close_container(reply
);
66 static int property_get_following(
69 const char *interface
,
71 sd_bus_message
*reply
,
73 sd_bus_error
*error
) {
75 Unit
*u
= userdata
, *f
;
81 f
= unit_following(u
);
82 return sd_bus_message_append(reply
, "s", f
? f
->id
: "");
85 static int property_get_dependencies(
88 const char *interface
,
90 sd_bus_message
*reply
,
92 sd_bus_error
*error
) {
94 Set
*s
= *(Set
**) userdata
;
102 r
= sd_bus_message_open_container(reply
, 'a', "s");
106 SET_FOREACH(u
, s
, j
) {
107 r
= sd_bus_message_append(reply
, "s", u
->id
);
112 return sd_bus_message_close_container(reply
);
115 static int property_get_description(
118 const char *interface
,
119 const char *property
,
120 sd_bus_message
*reply
,
122 sd_bus_error
*error
) {
130 return sd_bus_message_append(reply
, "s", unit_description(u
));
133 static int property_get_active_state(
136 const char *interface
,
137 const char *property
,
138 sd_bus_message
*reply
,
140 sd_bus_error
*error
) {
148 return sd_bus_message_append(reply
, "s", unit_active_state_to_string(unit_active_state(u
)));
151 static int property_get_sub_state(
154 const char *interface
,
155 const char *property
,
156 sd_bus_message
*reply
,
158 sd_bus_error
*error
) {
166 return sd_bus_message_append(reply
, "s", unit_sub_state_to_string(u
));
169 static int property_get_unit_file_preset(
172 const char *interface
,
173 const char *property
,
174 sd_bus_message
*reply
,
176 sd_bus_error
*error
) {
185 r
= unit_get_unit_file_preset(u
);
187 return sd_bus_message_append(reply
, "s",
189 r
> 0 ? "enabled" : "disabled");
192 static int property_get_unit_file_state(
195 const char *interface
,
196 const char *property
,
197 sd_bus_message
*reply
,
199 sd_bus_error
*error
) {
207 return sd_bus_message_append(reply
, "s", unit_file_state_to_string(unit_get_unit_file_state(u
)));
210 static int property_get_can_start(
213 const char *interface
,
214 const char *property
,
215 sd_bus_message
*reply
,
217 sd_bus_error
*error
) {
225 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_start
);
228 static int property_get_can_stop(
231 const char *interface
,
232 const char *property
,
233 sd_bus_message
*reply
,
235 sd_bus_error
*error
) {
243 /* On the lower levels we assume that every unit we can start
244 * we can also stop */
246 return sd_bus_message_append(reply
, "b", unit_can_start(u
) && !u
->refuse_manual_stop
);
249 static int property_get_can_reload(
252 const char *interface
,
253 const char *property
,
254 sd_bus_message
*reply
,
256 sd_bus_error
*error
) {
264 return sd_bus_message_append(reply
, "b", unit_can_reload(u
));
267 static int property_get_can_isolate(
270 const char *interface
,
271 const char *property
,
272 sd_bus_message
*reply
,
274 sd_bus_error
*error
) {
282 return sd_bus_message_append(reply
, "b", unit_can_isolate(u
) && !u
->refuse_manual_start
);
285 static int property_get_job(
288 const char *interface
,
289 const char *property
,
290 sd_bus_message
*reply
,
292 sd_bus_error
*error
) {
294 _cleanup_free_
char *p
= NULL
;
302 return sd_bus_message_append(reply
, "(uo)", 0, "/");
304 p
= job_dbus_path(u
->job
);
308 return sd_bus_message_append(reply
, "(uo)", u
->job
->id
, p
);
311 static int property_get_need_daemon_reload(
314 const char *interface
,
315 const char *property
,
316 sd_bus_message
*reply
,
318 sd_bus_error
*error
) {
326 return sd_bus_message_append(reply
, "b", unit_need_daemon_reload(u
));
329 static int property_get_conditions(
332 const char *interface
,
333 const char *property
,
334 sd_bus_message
*reply
,
336 sd_bus_error
*error
) {
338 const char *(*to_string
)(ConditionType type
) = NULL
;
339 Condition
**list
= userdata
, *c
;
346 to_string
= streq(property
, "Asserts") ? assert_type_to_string
: condition_type_to_string
;
348 r
= sd_bus_message_open_container(reply
, 'a', "(sbbsi)");
352 LIST_FOREACH(conditions
, c
, *list
) {
356 c
->result
== CONDITION_UNTESTED
? 0 :
357 c
->result
== CONDITION_SUCCEEDED
? 1 : -1;
359 r
= sd_bus_message_append(reply
, "(sbbsi)",
361 c
->trigger
, c
->negate
,
362 c
->parameter
, tristate
);
368 return sd_bus_message_close_container(reply
);
371 static int property_get_load_error(
374 const char *interface
,
375 const char *property
,
376 sd_bus_message
*reply
,
378 sd_bus_error
*error
) {
380 _cleanup_bus_error_free_ sd_bus_error e
= SD_BUS_ERROR_NULL
;
387 if (u
->load_error
!= 0)
388 sd_bus_error_set_errno(&e
, u
->load_error
);
390 return sd_bus_message_append(reply
, "(ss)", e
.name
, e
.message
);
393 int bus_unit_method_start_generic(
394 sd_bus_message
*message
,
397 bool reload_if_possible
,
398 sd_bus_error
*error
) {
406 assert(job_type
>= 0 && job_type
< _JOB_TYPE_MAX
);
408 r
= mac_selinux_unit_access_check(u
, message
, job_type
== JOB_STOP
? "stop" : "start", error
);
412 r
= sd_bus_message_read(message
, "s", &smode
);
416 mode
= job_mode_from_string(smode
);
418 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Job mode %s invalid", smode
);
420 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
424 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
426 return bus_unit_queue_job(message
, u
, job_type
, mode
, reload_if_possible
, error
);
429 static int method_start(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
430 return bus_unit_method_start_generic(message
, userdata
, JOB_START
, false, error
);
433 static int method_stop(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
434 return bus_unit_method_start_generic(message
, userdata
, JOB_STOP
, false, error
);
437 static int method_reload(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
438 return bus_unit_method_start_generic(message
, userdata
, JOB_RELOAD
, false, error
);
441 static int method_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
442 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, false, error
);
445 static int method_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
446 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, false, error
);
449 static int method_reload_or_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
450 return bus_unit_method_start_generic(message
, userdata
, JOB_RESTART
, true, error
);
453 static int method_reload_or_try_restart(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
454 return bus_unit_method_start_generic(message
, userdata
, JOB_TRY_RESTART
, true, error
);
457 int bus_unit_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
467 r
= mac_selinux_unit_access_check(u
, message
, "stop", error
);
471 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
478 who
= kill_who_from_string(swho
);
480 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid who argument %s", swho
);
483 if (signo
<= 0 || signo
>= _NSIG
)
484 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Signal number out of range.");
486 r
= bus_verify_manage_units_async_for_kill(u
->manager
, message
, error
);
490 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
492 r
= unit_kill(u
, who
, signo
, error
);
496 return sd_bus_reply_method_return(message
, NULL
);
499 int bus_unit_method_reset_failed(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
506 r
= mac_selinux_unit_access_check(u
, message
, "reload", error
);
510 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
514 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
516 unit_reset_failed(u
);
518 return sd_bus_reply_method_return(message
, NULL
);
521 int bus_unit_method_set_properties(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
528 r
= mac_selinux_unit_access_check(u
, message
, "start", error
);
532 r
= sd_bus_message_read(message
, "b", &runtime
);
536 r
= bus_verify_manage_units_async(u
->manager
, message
, error
);
540 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
542 r
= bus_unit_set_properties(u
, message
, runtime
? UNIT_RUNTIME
: UNIT_PERSISTENT
, true, error
);
546 return sd_bus_reply_method_return(message
, NULL
);
549 const sd_bus_vtable bus_unit_vtable
[] = {
550 SD_BUS_VTABLE_START(0),
552 SD_BUS_PROPERTY("Id", "s", NULL
, offsetof(Unit
, id
), SD_BUS_VTABLE_PROPERTY_CONST
),
553 SD_BUS_PROPERTY("Names", "as", property_get_names
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
554 SD_BUS_PROPERTY("Following", "s", property_get_following
, 0, 0),
555 SD_BUS_PROPERTY("Requires", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES
]), SD_BUS_VTABLE_PROPERTY_CONST
),
556 SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRES_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
557 SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
558 SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUISITE_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
559 SD_BUS_PROPERTY("Wants", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
560 SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BINDS_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
561 SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PART_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
562 SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
563 SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_REQUIRED_BY_OVERRIDABLE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
564 SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_WANTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
565 SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BOUND_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
566 SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONSISTS_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
567 SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
568 SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_CONFLICTED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
569 SD_BUS_PROPERTY("Before", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_BEFORE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
570 SD_BUS_PROPERTY("After", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_AFTER
]), SD_BUS_VTABLE_PROPERTY_CONST
),
571 SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_ON_FAILURE
]), SD_BUS_VTABLE_PROPERTY_CONST
),
572 SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERS
]), SD_BUS_VTABLE_PROPERTY_CONST
),
573 SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_TRIGGERED_BY
]), SD_BUS_VTABLE_PROPERTY_CONST
),
574 SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_PROPAGATES_RELOAD_TO
]), SD_BUS_VTABLE_PROPERTY_CONST
),
575 SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_RELOAD_PROPAGATED_FROM
]), SD_BUS_VTABLE_PROPERTY_CONST
),
576 SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies
, offsetof(Unit
, dependencies
[UNIT_JOINS_NAMESPACE_OF
]), SD_BUS_VTABLE_PROPERTY_CONST
),
577 SD_BUS_PROPERTY("RequiresMountsFor", "as", NULL
, offsetof(Unit
, requires_mounts_for
), SD_BUS_VTABLE_PROPERTY_CONST
),
578 SD_BUS_PROPERTY("Documentation", "as", NULL
, offsetof(Unit
, documentation
), SD_BUS_VTABLE_PROPERTY_CONST
),
579 SD_BUS_PROPERTY("Description", "s", property_get_description
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
580 SD_BUS_PROPERTY("LoadState", "s", property_get_load_state
, offsetof(Unit
, load_state
), SD_BUS_VTABLE_PROPERTY_CONST
),
581 SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
582 SD_BUS_PROPERTY("SubState", "s", property_get_sub_state
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
583 SD_BUS_PROPERTY("FragmentPath", "s", NULL
, offsetof(Unit
, fragment_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
584 SD_BUS_PROPERTY("SourcePath", "s", NULL
, offsetof(Unit
, source_path
), SD_BUS_VTABLE_PROPERTY_CONST
),
585 SD_BUS_PROPERTY("DropInPaths", "as", NULL
, offsetof(Unit
, dropin_paths
), SD_BUS_VTABLE_PROPERTY_CONST
),
586 SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state
, 0, 0),
587 SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset
, 0, 0),
588 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit
, inactive_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
589 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit
, active_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
590 BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit
, active_exit_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
591 BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit
, inactive_enter_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
592 SD_BUS_PROPERTY("CanStart", "b", property_get_can_start
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
593 SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
594 SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
595 SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
596 SD_BUS_PROPERTY("Job", "(uo)", property_get_job
, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
597 SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool
, offsetof(Unit
, stop_when_unneeded
), SD_BUS_VTABLE_PROPERTY_CONST
),
598 SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_start
), SD_BUS_VTABLE_PROPERTY_CONST
),
599 SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool
, offsetof(Unit
, refuse_manual_stop
), SD_BUS_VTABLE_PROPERTY_CONST
),
600 SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool
, offsetof(Unit
, allow_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
601 SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool
, offsetof(Unit
, default_dependencies
), SD_BUS_VTABLE_PROPERTY_CONST
),
602 SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode
, offsetof(Unit
, on_failure_job_mode
), SD_BUS_VTABLE_PROPERTY_CONST
),
603 SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_isolate
), SD_BUS_VTABLE_PROPERTY_CONST
),
604 SD_BUS_PROPERTY("IgnoreOnSnapshot", "b", bus_property_get_bool
, offsetof(Unit
, ignore_on_snapshot
), SD_BUS_VTABLE_PROPERTY_CONST
),
605 SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
606 SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec
, offsetof(Unit
, job_timeout
), SD_BUS_VTABLE_PROPERTY_CONST
),
607 SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_failure_action
, offsetof(Unit
, job_timeout_action
), SD_BUS_VTABLE_PROPERTY_CONST
),
608 SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL
, offsetof(Unit
, job_timeout_reboot_arg
), SD_BUS_VTABLE_PROPERTY_CONST
),
609 SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool
, offsetof(Unit
, condition_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
610 SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool
, offsetof(Unit
, assert_result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
611 BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit
, condition_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
612 BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit
, assert_timestamp
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
613 SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, conditions
), 0),
614 SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions
, offsetof(Unit
, asserts
), 0),
615 SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
616 SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool
, offsetof(Unit
, transient
), SD_BUS_VTABLE_PROPERTY_CONST
),
618 SD_BUS_METHOD("Start", "s", "o", method_start
, SD_BUS_VTABLE_UNPRIVILEGED
),
619 SD_BUS_METHOD("Stop", "s", "o", method_stop
, SD_BUS_VTABLE_UNPRIVILEGED
),
620 SD_BUS_METHOD("Reload", "s", "o", method_reload
, SD_BUS_VTABLE_UNPRIVILEGED
),
621 SD_BUS_METHOD("Restart", "s", "o", method_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
622 SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
623 SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
624 SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart
, SD_BUS_VTABLE_UNPRIVILEGED
),
625 SD_BUS_METHOD("Kill", "si", NULL
, bus_unit_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
626 SD_BUS_METHOD("ResetFailed", NULL
, NULL
, bus_unit_method_reset_failed
, SD_BUS_VTABLE_UNPRIVILEGED
),
627 SD_BUS_METHOD("SetProperties", "ba(sv)", NULL
, bus_unit_method_set_properties
, SD_BUS_VTABLE_UNPRIVILEGED
),
632 static int property_get_slice(
635 const char *interface
,
636 const char *property
,
637 sd_bus_message
*reply
,
639 sd_bus_error
*error
) {
647 return sd_bus_message_append(reply
, "s", unit_slice_name(u
));
650 static int property_get_current_memory(
653 const char *interface
,
654 const char *property
,
655 sd_bus_message
*reply
,
657 sd_bus_error
*error
) {
659 uint64_t sz
= (uint64_t) -1;
667 r
= unit_get_memory_current(u
, &sz
);
668 if (r
< 0 && r
!= -ENODATA
)
669 log_unit_warning_errno(u
->id
, r
, "Failed to get memory.usage_in_bytes attribute: %m");
671 return sd_bus_message_append(reply
, "t", sz
);
674 static int property_get_cpu_usage(
677 const char *interface
,
678 const char *property
,
679 sd_bus_message
*reply
,
681 sd_bus_error
*error
) {
683 nsec_t ns
= (nsec_t
) -1;
691 r
= unit_get_cpu_usage(u
, &ns
);
692 if (r
< 0 && r
!= -ENODATA
)
693 log_unit_warning_errno(u
->id
, r
, "Failed to get cpuacct.usage attribute: %m");
695 return sd_bus_message_append(reply
, "t", ns
);
698 const sd_bus_vtable bus_unit_cgroup_vtable
[] = {
699 SD_BUS_VTABLE_START(0),
700 SD_BUS_PROPERTY("Slice", "s", property_get_slice
, 0, 0),
701 SD_BUS_PROPERTY("ControlGroup", "s", NULL
, offsetof(Unit
, cgroup_path
), 0),
702 SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory
, 0, 0),
703 SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage
, 0, 0),
707 static int send_new_signal(sd_bus
*bus
, void *userdata
) {
708 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
709 _cleanup_free_
char *p
= NULL
;
716 p
= unit_dbus_path(u
);
720 r
= sd_bus_message_new_signal(
723 "/org/freedesktop/systemd1",
724 "org.freedesktop.systemd1.Manager",
729 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
733 return sd_bus_send(bus
, m
, NULL
);
736 static int send_changed_signal(sd_bus
*bus
, void *userdata
) {
737 _cleanup_free_
char *p
= NULL
;
744 p
= unit_dbus_path(u
);
748 /* Send a properties changed signal. First for the specific
749 * type, then for the generic unit. The clients may rely on
750 * this order to get atomic behavior if needed. */
752 r
= sd_bus_emit_properties_changed_strv(
754 UNIT_VTABLE(u
)->bus_interface
,
759 return sd_bus_emit_properties_changed_strv(
761 "org.freedesktop.systemd1.Unit",
765 void bus_unit_send_change_signal(Unit
*u
) {
769 if (u
->in_dbus_queue
) {
770 LIST_REMOVE(dbus_queue
, u
->manager
->dbus_unit_queue
, u
);
771 u
->in_dbus_queue
= false;
777 r
= bus_foreach_bus(u
->manager
, NULL
, u
->sent_dbus_new_signal
? send_changed_signal
: send_new_signal
, u
);
779 log_debug_errno(r
, "Failed to send unit change signal for %s: %m", u
->id
);
781 u
->sent_dbus_new_signal
= true;
784 static int send_removed_signal(sd_bus
*bus
, void *userdata
) {
785 _cleanup_bus_message_unref_ sd_bus_message
*m
= NULL
;
786 _cleanup_free_
char *p
= NULL
;
793 p
= unit_dbus_path(u
);
797 r
= sd_bus_message_new_signal(
800 "/org/freedesktop/systemd1",
801 "org.freedesktop.systemd1.Manager",
806 r
= sd_bus_message_append(m
, "so", u
->id
, p
);
810 return sd_bus_send(bus
, m
, NULL
);
813 void bus_unit_send_removed_signal(Unit
*u
) {
817 if (!u
->sent_dbus_new_signal
)
818 bus_unit_send_change_signal(u
);
823 r
= bus_foreach_bus(u
->manager
, NULL
, send_removed_signal
, u
);
825 log_debug_errno(r
, "Failed to send unit remove signal for %s: %m", u
->id
);
828 int bus_unit_queue_job(
829 sd_bus_message
*message
,
833 bool reload_if_possible
,
834 sd_bus_error
*error
) {
836 _cleanup_free_
char *path
= NULL
;
842 assert(type
>= 0 && type
< _JOB_TYPE_MAX
);
843 assert(mode
>= 0 && mode
< _JOB_MODE_MAX
);
845 if (reload_if_possible
&& unit_can_reload(u
)) {
846 if (type
== JOB_RESTART
)
847 type
= JOB_RELOAD_OR_START
;
848 else if (type
== JOB_TRY_RESTART
)
852 r
= mac_selinux_unit_access_check(
854 (type
== JOB_START
|| type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) ? "start" :
855 type
== JOB_STOP
? "stop" : "reload", error
);
859 if (type
== JOB_STOP
&&
860 (u
->load_state
== UNIT_NOT_FOUND
|| u
->load_state
== UNIT_ERROR
) &&
861 unit_active_state(u
) == UNIT_INACTIVE
)
862 return sd_bus_error_setf(error
, BUS_ERROR_NO_SUCH_UNIT
, "Unit %s not loaded.", u
->id
);
864 if ((type
== JOB_START
&& u
->refuse_manual_start
) ||
865 (type
== JOB_STOP
&& u
->refuse_manual_stop
) ||
866 ((type
== JOB_RESTART
|| type
== JOB_TRY_RESTART
) && (u
->refuse_manual_start
|| u
->refuse_manual_stop
)))
867 return sd_bus_error_setf(error
, BUS_ERROR_ONLY_BY_DEPENDENCY
, "Operation refused, unit %s may be requested by dependency only.", u
->id
);
869 r
= manager_add_job(u
->manager
, type
, u
, mode
, true, error
, &j
);
873 if (sd_bus_message_get_bus(message
) == u
->manager
->api_bus
) {
875 r
= sd_bus_track_new(sd_bus_message_get_bus(message
), &j
->clients
, NULL
, NULL
);
880 r
= sd_bus_track_add_sender(j
->clients
, message
);
885 path
= job_dbus_path(j
);
889 return sd_bus_reply_method_return(message
, "o", path
);
892 static int bus_unit_set_transient_property(
895 sd_bus_message
*message
,
896 UnitSetPropertiesMode mode
,
897 sd_bus_error
*error
) {
905 if (streq(name
, "Description")) {
908 r
= sd_bus_message_read(message
, "s", &d
);
912 if (mode
!= UNIT_CHECK
) {
913 r
= unit_set_description(u
, d
);
917 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDescription=%s\n", d
);
922 } else if (streq(name
, "DefaultDependencies")) {
925 r
= sd_bus_message_read(message
, "b", &b
);
929 if (mode
!= UNIT_CHECK
) {
930 u
->default_dependencies
= b
;
931 unit_write_drop_in_format(u
, mode
, name
, "[Unit]\nDefaultDependencies=%s\n", yes_no(b
));
936 } else if (streq(name
, "Slice") && unit_get_cgroup_context(u
)) {
939 r
= sd_bus_message_read(message
, "s", &s
);
943 if (!unit_name_is_valid(s
, UNIT_NAME_PLAIN
) || !endswith(s
, ".slice"))
944 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid slice name %s", s
);
947 if (mode
!= UNIT_CHECK
) {
948 unit_ref_unset(&u
->slice
);
949 unit_remove_drop_in(u
, mode
, name
);
954 r
= manager_load_unit(u
->manager
, s
, NULL
, error
, &slice
);
958 if (slice
->type
!= UNIT_SLICE
)
961 if (mode
!= UNIT_CHECK
) {
962 unit_ref_set(&u
->slice
, slice
);
963 unit_write_drop_in_private_format(u
, mode
, name
, "Slice=%s\n", s
);
968 } else if (STR_IN_SET(name
,
969 "Requires", "RequiresOverridable",
970 "Requisite", "RequisiteOverridable",
976 "PropagatesReloadTo", "ReloadPropagatedFrom",
982 d
= unit_dependency_from_string(name
);
986 r
= sd_bus_message_enter_container(message
, 'a', "s");
990 while ((r
= sd_bus_message_read(message
, "s", &other
)) > 0) {
991 if (!unit_name_is_valid(other
, UNIT_NAME_PLAIN
|UNIT_NAME_INSTANCE
))
992 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid unit name %s", other
);
994 if (mode
!= UNIT_CHECK
) {
995 _cleanup_free_
char *label
= NULL
;
997 r
= unit_add_dependency_by_name(u
, d
, other
, NULL
, true);
1001 label
= strjoin(name
, "-", other
, NULL
);
1005 unit_write_drop_in_format(u
, mode
, label
, "[Unit]\n%s=%s\n", name
, other
);
1012 r
= sd_bus_message_exit_container(message
);
1022 int bus_unit_set_properties(
1024 sd_bus_message
*message
,
1025 UnitSetPropertiesMode mode
,
1027 sd_bus_error
*error
) {
1029 bool for_real
= false;
1036 /* We iterate through the array twice. First run we just check
1037 * if all passed data is valid, second run actually applies
1038 * it. This is to implement transaction-like behaviour without
1039 * actually providing full transactions. */
1041 r
= sd_bus_message_enter_container(message
, 'a', "(sv)");
1048 r
= sd_bus_message_enter_container(message
, 'r', "sv");
1052 if (for_real
|| mode
== UNIT_CHECK
)
1055 /* Reached EOF. Let's try again, and this time for realz... */
1056 r
= sd_bus_message_rewind(message
, false);
1064 r
= sd_bus_message_read(message
, "s", &name
);
1068 if (!UNIT_VTABLE(u
)->bus_set_property
)
1069 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Objects of this type do not support setting properties.");
1071 r
= sd_bus_message_enter_container(message
, 'v', NULL
);
1075 r
= UNIT_VTABLE(u
)->bus_set_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1076 if (r
== 0 && u
->transient
&& u
->load_state
== UNIT_STUB
)
1077 r
= bus_unit_set_transient_property(u
, name
, message
, for_real
? mode
: UNIT_CHECK
, error
);
1081 return sd_bus_error_setf(error
, SD_BUS_ERROR_PROPERTY_READ_ONLY
, "Cannot set property %s, or unknown property.", name
);
1083 r
= sd_bus_message_exit_container(message
);
1087 r
= sd_bus_message_exit_container(message
);
1094 r
= sd_bus_message_exit_container(message
);
1098 if (commit
&& n
> 0 && UNIT_VTABLE(u
)->bus_commit_properties
)
1099 UNIT_VTABLE(u
)->bus_commit_properties(u
);