1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include "alloc-util.h"
4 #include "bus-common-errors.h"
5 #include "bus-get-properties.h"
7 #include "dbus-cgroup.h"
9 #include "dbus-manager.h"
10 #include "dbus-scope.h"
11 #include "dbus-util.h"
15 #include "selinux-access.h"
16 #include "string-util.h"
19 int bus_scope_method_abandon(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
20 Scope
*s
= ASSERT_PTR(userdata
);
25 r
= mac_selinux_unit_access_check(UNIT(s
), message
, "stop", error
);
29 r
= bus_verify_manage_units_async(UNIT(s
)->manager
, message
, error
);
33 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
37 return sd_bus_error_setf(error
, BUS_ERROR_SCOPE_NOT_RUNNING
, "Scope %s is not running, cannot abandon.", UNIT(s
)->id
);
41 return sd_bus_reply_method_return(message
, NULL
);
44 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result
, scope_result
, ScopeResult
);
45 static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy
, OOMPolicy
, oom_policy_from_string
);
47 const sd_bus_vtable bus_scope_vtable
[] = {
48 SD_BUS_VTABLE_START(0),
49 SD_BUS_PROPERTY("Controller", "s", NULL
, offsetof(Scope
, controller
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
50 SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec
, offsetof(Scope
, timeout_stop_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
51 SD_BUS_PROPERTY("Result", "s", property_get_result
, offsetof(Scope
, result
), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE
),
52 SD_BUS_PROPERTY("RuntimeMaxUSec", "t", bus_property_get_usec
, offsetof(Scope
, runtime_max_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
53 SD_BUS_PROPERTY("RuntimeRandomizedExtraUSec", "t", bus_property_get_usec
, offsetof(Scope
, runtime_rand_extra_usec
), SD_BUS_VTABLE_PROPERTY_CONST
),
54 SD_BUS_PROPERTY("OOMPolicy", "s", bus_property_get_oom_policy
, offsetof(Scope
, oom_policy
), SD_BUS_VTABLE_PROPERTY_CONST
),
55 SD_BUS_SIGNAL("RequestStop", NULL
, 0),
56 SD_BUS_METHOD("Abandon", NULL
, NULL
, bus_scope_method_abandon
, SD_BUS_VTABLE_UNPRIVILEGED
),
60 static int bus_scope_set_transient_property(
63 sd_bus_message
*message
,
65 sd_bus_error
*error
) {
74 flags
|= UNIT_PRIVATE
;
76 if (streq(name
, "TimeoutStopUSec"))
77 return bus_set_transient_usec(u
, name
, &s
->timeout_stop_usec
, message
, flags
, error
);
79 if (streq(name
, "RuntimeMaxUSec"))
80 return bus_set_transient_usec(u
, name
, &s
->runtime_max_usec
, message
, flags
, error
);
82 if (streq(name
, "RuntimeRandomizedExtraUSec"))
83 return bus_set_transient_usec(u
, name
, &s
->runtime_rand_extra_usec
, message
, flags
, error
);
85 if (streq(name
, "OOMPolicy"))
86 return bus_set_transient_oom_policy(u
, name
, &s
->oom_policy
, message
, flags
, error
);
88 if (streq(name
, "PIDs")) {
89 _cleanup_(pidref_done
) PidRef sender_pidref
= PIDREF_NULL
;
92 r
= sd_bus_message_enter_container(message
, 'a', "u");
97 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
101 r
= sd_bus_message_read(message
, "u", &upid
);
108 if (!pidref_is_set(&sender_pidref
)) {
109 r
= bus_query_sender_pidref(message
, &sender_pidref
);
116 r
= pidref_set_pid(&pidref
, upid
);
123 r
= unit_pid_attachable(u
, p
, error
);
127 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
128 r
= unit_watch_pidref(u
, p
, /* exclusive= */ false);
136 r
= sd_bus_message_exit_container(message
);
140 return n
<= 0 ? -EINVAL
: 1;
143 if (streq(name
, "PIDFDs")) {
146 r
= sd_bus_message_enter_container(message
, 'a', "h");
151 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
154 r
= sd_bus_message_read(message
, "h", &fd
);
160 r
= pidref_set_pidfd(&pidref
, fd
);
164 r
= unit_pid_attachable(u
, &pidref
, error
);
168 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
169 r
= unit_watch_pidref(u
, &pidref
, /* exclusive= */ false);
177 r
= sd_bus_message_exit_container(message
);
181 return n
<= 0 ? -EINVAL
: 1;
184 if (streq(name
, "Controller")) {
185 const char *controller
;
187 /* We can't support direct connections with this, as direct connections know no service or unique name
188 * concept, but the Controller field stores exactly that. */
189 if (sd_bus_message_get_bus(message
) != u
->manager
->api_bus
)
190 return sd_bus_error_set(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Sorry, Controller= logic only supported via the bus.");
192 r
= sd_bus_message_read(message
, "s", &controller
);
196 if (!isempty(controller
) && !sd_bus_service_name_is_valid(controller
))
197 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Controller '%s' is not a valid bus name.", controller
);
199 if (!UNIT_WRITE_FLAGS_NOOP(flags
)) {
200 r
= free_and_strdup(&s
->controller
, empty_to_null(controller
));
211 int bus_scope_set_property(
214 sd_bus_message
*message
,
215 UnitWriteFlags flags
,
216 sd_bus_error
*error
) {
225 r
= bus_cgroup_set_property(u
, &s
->cgroup_context
, name
, message
, flags
, error
);
229 if (u
->load_state
== UNIT_STUB
) {
230 /* While we are created we still accept PIDs */
232 r
= bus_scope_set_transient_property(s
, name
, message
, flags
, error
);
236 r
= bus_kill_context_set_transient_property(u
, &s
->kill_context
, name
, message
, flags
, error
);
240 if (streq(name
, "User"))
241 return bus_set_transient_user_relaxed(u
, name
, &s
->user
, message
, flags
, error
);
243 if (streq(name
, "Group"))
244 return bus_set_transient_user_relaxed(u
, name
, &s
->group
, message
, flags
, error
);
250 int bus_scope_commit_properties(Unit
*u
) {
253 (void) unit_realize_cgroup(u
);
258 int bus_scope_send_request_stop(Scope
*s
) {
259 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*m
= NULL
;
260 _cleanup_free_
char *p
= NULL
;
268 p
= unit_dbus_path(UNIT(s
));
272 r
= sd_bus_message_new_signal(
273 UNIT(s
)->manager
->api_bus
,
276 "org.freedesktop.systemd1.Scope",
281 return sd_bus_send_to(UNIT(s
)->manager
->api_bus
, m
, s
->controller
, NULL
);
284 static int on_controller_gone(sd_bus_track
*track
, void *userdata
) {
290 log_unit_debug(UNIT(s
), "Controller %s disappeared from bus.", s
->controller
);
291 unit_add_to_dbus_queue(UNIT(s
));
292 s
->controller
= mfree(s
->controller
);
295 s
->controller_track
= sd_bus_track_unref(s
->controller_track
);
300 int bus_scope_track_controller(Scope
*s
) {
305 if (!s
->controller
|| s
->controller_track
)
308 r
= sd_bus_track_new(UNIT(s
)->manager
->api_bus
, &s
->controller_track
, on_controller_gone
, s
);
312 r
= sd_bus_track_add_name(s
->controller_track
, s
->controller
);
314 s
->controller_track
= sd_bus_track_unref(s
->controller_track
);