]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/core/dbus-scope.c
core: add new new bus call for migrating foreign processes to scope/service units
[thirdparty/systemd.git] / src / core / dbus-scope.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
6c12b52e
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2013 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
b5efdb8a 21#include "alloc-util.h"
96aad8d1 22#include "bus-common-errors.h"
b5efdb8a
LP
23#include "bus-internal.h"
24#include "bus-util.h"
1d22e906
LP
25#include "dbus-cgroup.h"
26#include "dbus-kill.h"
27#include "dbus-scope.h"
b5efdb8a 28#include "dbus-unit.h"
0fb0fffa 29#include "dbus-util.h"
b5efdb8a
LP
30#include "dbus.h"
31#include "scope.h"
32#include "selinux-access.h"
33#include "unit.h"
6c12b52e 34
19070062 35static int bus_scope_abandon(sd_bus_message *message, void *userdata, sd_bus_error *error) {
a911bb9a 36 Scope *s = userdata;
4e2f8d27 37 int r;
a911bb9a 38
a911bb9a
LP
39 assert(message);
40 assert(s);
41
1d22e906
LP
42 r = mac_selinux_unit_access_check(UNIT(s), message, "stop", error);
43 if (r < 0)
44 return r;
45
46 r = bus_verify_manage_units_async(UNIT(s)->manager, message, error);
283868e1
SW
47 if (r < 0)
48 return r;
49 if (r == 0)
50 return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */
51
4e2f8d27 52 r = scope_abandon(s);
4e2f8d27
LP
53 if (r == -ESTALE)
54 return sd_bus_error_setf(error, BUS_ERROR_SCOPE_NOT_RUNNING, "Scope %s is not running, cannot abandon.", UNIT(s)->id);
1d22e906
LP
55 if (r < 0)
56 return r;
4e2f8d27
LP
57
58 return sd_bus_reply_method_return(message, NULL);
a911bb9a
LP
59}
60
718db961 61static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_result, scope_result, ScopeResult);
6c12b52e 62
718db961
LP
63const sd_bus_vtable bus_scope_vtable[] = {
64 SD_BUS_VTABLE_START(0),
371c0b79 65 SD_BUS_PROPERTY("Controller", "s", NULL, offsetof(Scope, controller), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
556089dc 66 SD_BUS_PROPERTY("TimeoutStopUSec", "t", bus_property_get_usec, offsetof(Scope, timeout_stop_usec), SD_BUS_VTABLE_PROPERTY_CONST),
718db961 67 SD_BUS_PROPERTY("Result", "s", property_get_result, offsetof(Scope, result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
2d4a39e7 68 SD_BUS_SIGNAL("RequestStop", NULL, 0),
1d22e906 69 SD_BUS_METHOD("Abandon", NULL, NULL, bus_scope_abandon, SD_BUS_VTABLE_UNPRIVILEGED),
718db961
LP
70 SD_BUS_VTABLE_END
71};
6c12b52e 72
9f2e86af 73static int bus_scope_set_transient_property(
6c12b52e
LP
74 Scope *s,
75 const char *name,
718db961 76 sd_bus_message *message,
2e59b241 77 UnitWriteFlags flags,
718db961 78 sd_bus_error *error) {
6c12b52e
LP
79
80 int r;
81
6c12b52e 82 assert(s);
718db961
LP
83 assert(name);
84 assert(message);
6c12b52e 85
2e59b241
LP
86 flags |= UNIT_PRIVATE;
87
0fb0fffa
YW
88 if (streq(name, "TimeoutStopUSec"))
89 return bus_set_transient_usec(UNIT(s), name, &s->timeout_stop_usec, message, flags, error);
90
6c12b52e 91 if (streq(name, "PIDs")) {
6592b975 92 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
294a90cc 93 unsigned n = 0;
6c12b52e 94
718db961
LP
95 r = sd_bus_message_enter_container(message, 'a', "u");
96 if (r < 0)
97 return r;
6c12b52e 98
6592b975
LP
99 for (;;) {
100 uint32_t upid;
101 pid_t pid;
102
103 r = sd_bus_message_read(message, "u", &upid);
104 if (r < 0)
105 return r;
106 if (r == 0)
107 break;
108
109 if (upid == 0) {
110 if (!creds) {
111 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
112 if (r < 0)
113 return r;
114 }
115
116 r = sd_bus_creds_get_pid(creds, &pid);
117 if (r < 0)
118 return r;
119 } else
120 pid = (uid_t) upid;
6c12b52e 121
6592b975
LP
122 r = unit_pid_attachable(UNIT(s), pid, error);
123 if (r < 0)
124 return r;
6c12b52e 125
2e59b241 126 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
a911bb9a 127 r = unit_watch_pid(UNIT(s), pid);
adb3a45d
LP
128 if (r < 0 && r != -EEXIST)
129 return r;
130 }
6c12b52e 131
adb3a45d 132 n++;
6c12b52e 133 }
718db961
LP
134
135 r = sd_bus_message_exit_container(message);
136 if (r < 0)
137 return r;
6c12b52e 138
adb3a45d 139 if (n <= 0)
6c12b52e
LP
140 return -EINVAL;
141
142 return 1;
cc23f9f1 143
2d4a39e7
LP
144 } else if (streq(name, "Controller")) {
145 const char *controller;
2d4a39e7 146
f2c49c86
LP
147 /* We can't support direct connections with this, as direct connections know no service or unique name
148 * concept, but the Controller field stores exactly that. */
149 if (sd_bus_message_get_bus(message) != UNIT(s)->manager->api_bus)
150 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Sorry, Controller= logic only supported via the bus.");
151
2d4a39e7
LP
152 r = sd_bus_message_read(message, "s", &controller);
153 if (r < 0)
154 return r;
155
156 if (!isempty(controller) && !service_name_is_valid(controller))
157 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Controller '%s' is not a valid bus name.", controller);
158
2e59b241
LP
159 if (!UNIT_WRITE_FLAGS_NOOP(flags)) {
160 r = free_and_strdup(&s->controller, empty_to_null(controller));
161 if (r < 0)
162 return r;
2d4a39e7
LP
163 }
164
cc23f9f1 165 return 1;
6c12b52e
LP
166 }
167
168 return 0;
169}
170
171int bus_scope_set_property(
172 Unit *u,
173 const char *name,
718db961 174 sd_bus_message *message,
2e59b241 175 UnitWriteFlags flags,
718db961 176 sd_bus_error *error) {
6c12b52e
LP
177
178 Scope *s = SCOPE(u);
179 int r;
180
718db961 181 assert(s);
6c12b52e 182 assert(name);
718db961 183 assert(message);
6c12b52e 184
2e59b241 185 r = bus_cgroup_set_property(u, &s->cgroup_context, name, message, flags, error);
6c12b52e
LP
186 if (r != 0)
187 return r;
188
189 if (u->load_state == UNIT_STUB) {
190 /* While we are created we still accept PIDs */
191
2e59b241 192 r = bus_scope_set_transient_property(s, name, message, flags, error);
6c12b52e
LP
193 if (r != 0)
194 return r;
a6c0353b 195
2e59b241 196 r = bus_kill_context_set_transient_property(u, &s->kill_context, name, message, flags, error);
a6c0353b
LP
197 if (r != 0)
198 return r;
6c12b52e
LP
199 }
200
201 return 0;
202}
203
204int bus_scope_commit_properties(Unit *u) {
205 assert(u);
206
bc432dc7 207 unit_update_cgroup_members_masks(u);
6c12b52e 208 unit_realize_cgroup(u);
bc432dc7 209
6c12b52e
LP
210 return 0;
211}
2d4a39e7
LP
212
213int bus_scope_send_request_stop(Scope *s) {
4afd3348 214 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2d4a39e7
LP
215 _cleanup_free_ char *p = NULL;
216 int r;
217
218 assert(s);
219
220 if (!s->controller)
221 return 0;
222
223 p = unit_dbus_path(UNIT(s));
224 if (!p)
225 return -ENOMEM;
226
227 r = sd_bus_message_new_signal(
228 UNIT(s)->manager->api_bus,
151b9b96 229 &m,
2d4a39e7
LP
230 p,
231 "org.freedesktop.systemd1.Scope",
151b9b96 232 "RequestStop");
2d4a39e7
LP
233 if (r < 0)
234 return r;
235
f4b0fb23 236 return sd_bus_send_to(UNIT(s)->manager->api_bus, m, s->controller, NULL);
2d4a39e7 237}
371c0b79
LP
238
239static int on_controller_gone(sd_bus_track *track, void *userdata) {
240 Scope *s = userdata;
241
242 assert(track);
243
244 if (s->controller) {
245 log_unit_debug(UNIT(s), "Controller %s disappeared from bus.", s->controller);
246 unit_add_to_dbus_queue(UNIT(s));
247 s->controller = mfree(s->controller);
248 }
249
250 s->controller_track = sd_bus_track_unref(s->controller_track);
251
252 return 0;
253}
254
255int bus_scope_track_controller(Scope *s) {
256 int r;
257
258 assert(s);
259
260 if (!s->controller || s->controller_track)
261 return 0;
262
263 r = sd_bus_track_new(UNIT(s)->manager->api_bus, &s->controller_track, on_controller_gone, s);
264 if (r < 0)
265 return r;
266
267 r = sd_bus_track_add_name(s->controller_track, s->controller);
268 if (r < 0) {
269 s->controller_track = sd_bus_track_unref(s->controller_track);
270 return r;
271 }
272
273 return 0;
274}