]> git.ipfire.org Git - thirdparty/systemd.git/blame_incremental - src/core/dbus-scope.c
analyze: fix typo
[thirdparty/systemd.git] / src / core / dbus-scope.c
... / ...
CommitLineData
1/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3#include "alloc-util.h"
4#include "bus-common-errors.h"
5#include "bus-get-properties.h"
6#include "bus-util.h"
7#include "dbus-cgroup.h"
8#include "dbus-kill.h"
9#include "dbus-manager.h"
10#include "dbus-scope.h"
11#include "dbus-util.h"
12#include "manager.h"
13#include "pidref.h"
14#include "scope.h"
15#include "selinux-access.h"
16#include "string-util.h"
17#include "unit.h"
18
19int bus_scope_method_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
20 Scope *s = ASSERT_PTR(userdata);
21 int r;
22
23 assert(message);
24
25 r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
26 if (r < 0)
27 return r;
28
29 r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
30 if (r < 0)
31 return r;
32 if (r == 0)
33 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
34
35 r = scope_abandon(s);
36 if (r == -ESTALE)
37 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
38 if (r < 0)
39 return r;
40
41 return sd_bus_reply_method_return(message, NULL);
42}
43
44static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
45static BUS_DEFINE_SET_TRANSIENT_PARSE(oom_policy, OOMPolicy, oom_policy_from_string);
46
47const 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),
57 SD_BUS_VTABLE_END
58};
59
60static int bus_scope_set_transient_property(
61 Scope *s,
62 const char *name,
63 sd_bus_message *message,
64 UnitWriteFlags flags,
65 sd_bus_error *error) {
66
67 Unit *u = UNIT(s);
68 int r;
69
70 assert(s);
71 assert(name);
72 assert(message);
73
74 flags |= UNIT_PRIVATE;
75
76 if (streq(name, "TimeoutStopUSec"))
77 return bus_set_transient_usec(u, name, &s->timeout_stop_usec, message, flags, error);
78
79 if (streq(name, "RuntimeMaxUSec"))
80 return bus_set_transient_usec(u, name, &s->runtime_max_usec, message, flags, error);
81
82 if (streq(name, "RuntimeRandomizedExtraUSec"))
83 return bus_set_transient_usec(u, name, &s->runtime_rand_extra_usec, message, flags, error);
84
85 if (streq(name, "OOMPolicy"))
86 return bus_set_transient_oom_policy(u, name, &s->oom_policy, message, flags, error);
87
88 if (streq(name, "PIDs")) {
89 _cleanup_(pidref_done) PidRef sender_pidref = PIDREF_NULL;
90 unsigned n = 0;
91
92 r = sd_bus_message_enter_container(message, 'a', "u");
93 if (r < 0)
94 return r;
95
96 for (;;) {
97 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
98 uint32_t upid;
99 PidRef *p;
100
101 r = sd_bus_message_read(message, "u", &upid);
102 if (r < 0)
103 return r;
104 if (r == 0)
105 break;
106
107 if (upid == 0) {
108 if (!pidref_is_set(&sender_pidref)) {
109 r = bus_query_sender_pidref(message, &sender_pidref);
110 if (r < 0)
111 return r;
112 }
113
114 p = &sender_pidref;
115 } else {
116 r = pidref_set_pid(&pidref, upid);
117 if (r < 0)
118 return r;
119
120 p = &pidref;
121 }
122
123 r = unit_pid_attachable(u, p, error);
124 if (r < 0)
125 return r;
126
127 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
128 r = unit_watch_pidref(u, p, /* exclusive= */ false);
129 if (r < 0)
130 return r;
131 }
132
133 n++;
134 }
135
136 r = sd_bus_message_exit_container(message);
137 if (r < 0)
138 return r;
139
140 return n <= 0 ? -EINVAL : 1;
141 }
142
143 if (streq(name, "PIDFDs")) {
144 unsigned n = 0;
145
146 r = sd_bus_message_enter_container(message, 'a', "h");
147 if (r < 0)
148 return r;
149
150 for (;;) {
151 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
152 int fd;
153
154 r = sd_bus_message_read(message, "h", &fd);
155 if (r < 0)
156 return r;
157 if (r == 0)
158 break;
159
160 r = pidref_set_pidfd(&pidref, fd);
161 if (r < 0)
162 return r;
163
164 r = unit_pid_attachable(u, &pidref, error);
165 if (r < 0)
166 return r;
167
168 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
169 r = unit_watch_pidref(u, &pidref, /* exclusive= */ false);
170 if (r < 0)
171 return r;
172 }
173
174 n++;
175 }
176
177 r = sd_bus_message_exit_container(message);
178 if (r < 0)
179 return r;
180
181 return n <= 0 ? -EINVAL : 1;
182 }
183
184 if (streq(name, "Controller")) {
185 const char *controller;
186
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.");
191
192 r = sd_bus_message_read(message, "s", &controller);
193 if (r < 0)
194 return r;
195
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);
198
199 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
200 r = free_and_strdup(&s->controller, empty_to_null(controller));
201 if (r < 0)
202 return r;
203 }
204
205 return 1;
206 }
207
208 return 0;
209}
210
211int bus_scope_set_property(
212 Unit *u,
213 const char *name,
214 sd_bus_message *message,
215 UnitWriteFlags flags,
216 sd_bus_error *error) {
217
218 Scope *s = SCOPE(u);
219 int r;
220
221 assert(s);
222 assert(name);
223 assert(message);
224
225 r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
226 if (r != 0)
227 return r;
228
229 if (u->load_state == UNIT_STUB) {
230 /* While we are created we still accept PIDs */
231
232 r = bus_scope_set_transient_property(s, name, message, flags, error);
233 if (r != 0)
234 return r;
235
236 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
237 if (r != 0)
238 return r;
239
240 if (streq(name, "User"))
241 return bus_set_transient_user_relaxed(u, name, &s->user, message, flags, error);
242
243 if (streq(name, "Group"))
244 return bus_set_transient_user_relaxed(u, name, &s->group, message, flags, error);
245 }
246
247 return 0;
248}
249
250int bus_scope_commit_properties(Unit *u) {
251 assert(u);
252
253 (void) unit_realize_cgroup(u);
254
255 return 0;
256}
257
258int bus_scope_send_request_stop(Scope *s) {
259 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
260 _cleanup_free_ char *p = NULL;
261 int r;
262
263 assert(s);
264
265 if (!s->controller)
266 return 0;
267
268 p = unit_dbus_path(UNIT(s));
269 if (!p)
270 return -ENOMEM;
271
272 r = sd_bus_message_new_signal(
273 UNIT(s)->manager->api_bus,
274 &m,
275 p,
276 "org.freedesktop.systemd1.Scope",
277 "RequestStop");
278 if (r < 0)
279 return r;
280
281 return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
282}
283
284static int on_controller_gone(sd_bus_track *track, void *userdata) {
285 Scope *s = userdata;
286
287 assert(track);
288
289 if (s->controller) {
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);
293 }
294
295 s->controller_track = sd_bus_track_unref(s->controller_track);
296
297 return 0;
298}
299
300int bus_scope_track_controller(Scope *s) {
301 int r;
302
303 assert(s);
304
305 if (!s->controller || s->controller_track)
306 return 0;
307
308 r = sd_bus_track_new(UNIT(s)->manager->api_bus, &s->controller_track, on_controller_gone, s);
309 if (r < 0)
310 return r;
311
312 r = sd_bus_track_add_name(s->controller_track, s->controller);
313 if (r < 0) {
314 s->controller_track = sd_bus_track_unref(s->controller_track);
315 return r;
316 }
317
318 return 0;
319}