]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-register.c
Merge pull request #12048 from jengelh/master
[thirdparty/systemd.git] / src / nspawn / nspawn-register.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include "sd-bus.h"
4
5 #include "bus-error.h"
6 #include "bus-unit-util.h"
7 #include "bus-util.h"
8 #include "bus-wait-for-jobs.h"
9 #include "nspawn-register.h"
10 #include "special.h"
11 #include "stat-util.h"
12 #include "strv.h"
13 #include "util.h"
14
15 static int append_machine_properties(
16 sd_bus_message *m,
17 CustomMount *mounts,
18 unsigned n_mounts,
19 int kill_signal) {
20
21 unsigned j;
22 int r;
23
24 assert(m);
25
26 r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed");
27 if (r < 0)
28 return bus_log_create_error(r);
29
30 /* If you make changes here, also make sure to update systemd-nspawn@.service, to keep the device policies in
31 * sync regardless if we are run with or without the --keep-unit switch. */
32 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2,
33 /* Allow the container to
34 * access and create the API
35 * device nodes, so that
36 * PrivateDevices= in the
37 * container can work
38 * fine */
39 "/dev/net/tun", "rwm",
40 /* Allow the container
41 * access to ptys. However,
42 * do not permit the
43 * container to ever create
44 * these device nodes. */
45 "char-pts", "rw");
46 if (r < 0)
47 return bus_log_create_error(r);
48
49 for (j = 0; j < n_mounts; j++) {
50 CustomMount *cm = mounts + j;
51
52 if (cm->type != CUSTOM_MOUNT_BIND)
53 continue;
54
55 r = is_device_node(cm->source);
56 if (r == -ENOENT) {
57 /* The bind source might only appear as the image is put together, hence don't complain */
58 log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source);
59 continue;
60 }
61 if (r < 0)
62 return log_error_errno(r, "Failed to stat %s: %m", cm->source);
63
64 if (r) {
65 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1,
66 cm->source, cm->read_only ? "r" : "rw");
67 if (r < 0)
68 return log_error_errno(r, "Failed to append message arguments: %m");
69 }
70 }
71
72 if (kill_signal != 0) {
73 r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal);
74 if (r < 0)
75 return bus_log_create_error(r);
76
77 r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed");
78 if (r < 0)
79 return bus_log_create_error(r);
80 }
81
82 return 0;
83 }
84
85 static int append_controller_property(sd_bus *bus, sd_bus_message *m) {
86 const char *unique;
87 int r;
88
89 assert(bus);
90 assert(m);
91
92 r = sd_bus_get_unique_name(bus, &unique);
93 if (r < 0)
94 return log_error_errno(r, "Failed to get unique name: %m");
95
96 r = sd_bus_message_append(m, "(sv)", "Controller", "s", unique);
97 if (r < 0)
98 return bus_log_create_error(r);
99
100 return 0;
101 }
102
103 int register_machine(
104 sd_bus *bus,
105 const char *machine_name,
106 pid_t pid,
107 const char *directory,
108 sd_id128_t uuid,
109 int local_ifindex,
110 const char *slice,
111 CustomMount *mounts,
112 unsigned n_mounts,
113 int kill_signal,
114 char **properties,
115 sd_bus_message *properties_message,
116 bool keep_unit,
117 const char *service) {
118
119 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
120 int r;
121
122 assert(bus);
123
124 if (keep_unit) {
125 r = sd_bus_call_method(
126 bus,
127 "org.freedesktop.machine1",
128 "/org/freedesktop/machine1",
129 "org.freedesktop.machine1.Manager",
130 "RegisterMachineWithNetwork",
131 &error,
132 NULL,
133 "sayssusai",
134 machine_name,
135 SD_BUS_MESSAGE_APPEND_ID128(uuid),
136 service,
137 "container",
138 (uint32_t) pid,
139 strempty(directory),
140 local_ifindex > 0 ? 1 : 0, local_ifindex);
141 } else {
142 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
143
144 r = sd_bus_message_new_method_call(
145 bus,
146 &m,
147 "org.freedesktop.machine1",
148 "/org/freedesktop/machine1",
149 "org.freedesktop.machine1.Manager",
150 "CreateMachineWithNetwork");
151 if (r < 0)
152 return bus_log_create_error(r);
153
154 r = sd_bus_message_append(
155 m,
156 "sayssusai",
157 machine_name,
158 SD_BUS_MESSAGE_APPEND_ID128(uuid),
159 service,
160 "container",
161 (uint32_t) pid,
162 strempty(directory),
163 local_ifindex > 0 ? 1 : 0, local_ifindex);
164 if (r < 0)
165 return bus_log_create_error(r);
166
167 r = sd_bus_message_open_container(m, 'a', "(sv)");
168 if (r < 0)
169 return bus_log_create_error(r);
170
171 if (!isempty(slice)) {
172 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
173 if (r < 0)
174 return bus_log_create_error(r);
175 }
176
177 r = append_controller_property(bus, m);
178 if (r < 0)
179 return r;
180
181 r = append_machine_properties(
182 m,
183 mounts,
184 n_mounts,
185 kill_signal);
186 if (r < 0)
187 return r;
188
189 if (properties_message) {
190 r = sd_bus_message_copy(m, properties_message, true);
191 if (r < 0)
192 return bus_log_create_error(r);
193 }
194
195 r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
196 if (r < 0)
197 return r;
198
199 r = sd_bus_message_close_container(m);
200 if (r < 0)
201 return bus_log_create_error(r);
202
203 r = sd_bus_call(bus, m, 0, &error, NULL);
204 }
205
206 if (r < 0)
207 return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
208
209 return 0;
210 }
211
212 int terminate_machine(
213 sd_bus *bus,
214 const char *machine_name) {
215
216 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
217 int r;
218
219 assert(bus);
220
221 r = sd_bus_call_method(
222 bus,
223 "org.freedesktop.machine1",
224 "/org/freedesktop/machine1",
225 "org.freedesktop.machine1.Manager",
226 "TerminateMachine",
227 &error,
228 NULL,
229 "s",
230 machine_name);
231 if (r < 0)
232 log_debug("Failed to terminate machine: %s", bus_error_message(&error, r));
233
234 return 0;
235 }
236
237 int allocate_scope(
238 sd_bus *bus,
239 const char *machine_name,
240 pid_t pid,
241 const char *slice,
242 CustomMount *mounts,
243 unsigned n_mounts,
244 int kill_signal,
245 char **properties,
246 sd_bus_message *properties_message) {
247
248 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
249 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
250 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
251 _cleanup_free_ char *scope = NULL;
252 const char *description, *object;
253 int r;
254
255 assert(bus);
256
257 r = bus_wait_for_jobs_new(bus, &w);
258 if (r < 0)
259 return log_error_errno(r, "Could not watch job: %m");
260
261 r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
262 if (r < 0)
263 return log_error_errno(r, "Failed to mangle scope name: %m");
264
265 r = sd_bus_message_new_method_call(
266 bus,
267 &m,
268 "org.freedesktop.systemd1",
269 "/org/freedesktop/systemd1",
270 "org.freedesktop.systemd1.Manager",
271 "StartTransientUnit");
272 if (r < 0)
273 return bus_log_create_error(r);
274
275 r = sd_bus_message_append(m, "ss", scope, "fail");
276 if (r < 0)
277 return bus_log_create_error(r);
278
279 /* Properties */
280 r = sd_bus_message_open_container(m, 'a', "(sv)");
281 if (r < 0)
282 return bus_log_create_error(r);
283
284 description = strjoina("Container ", machine_name);
285
286 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)(sv)",
287 "PIDs", "au", 1, pid,
288 "Description", "s", description,
289 "Delegate", "b", 1,
290 "CollectMode", "s", "inactive-or-failed",
291 "AddRef", "b", 1,
292 "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice);
293 if (r < 0)
294 return bus_log_create_error(r);
295
296 r = append_controller_property(bus, m);
297 if (r < 0)
298 return r;
299
300 if (properties_message) {
301 r = sd_bus_message_copy(m, properties_message, true);
302 if (r < 0)
303 return bus_log_create_error(r);
304 }
305
306 r = append_machine_properties(
307 m,
308 mounts,
309 n_mounts,
310 kill_signal);
311 if (r < 0)
312 return r;
313
314 r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties);
315 if (r < 0)
316 return r;
317
318 r = sd_bus_message_close_container(m);
319 if (r < 0)
320 return bus_log_create_error(r);
321
322 /* No auxiliary units */
323 r = sd_bus_message_append(
324 m,
325 "a(sa(sv))",
326 0);
327 if (r < 0)
328 return bus_log_create_error(r);
329
330 r = sd_bus_call(bus, m, 0, &error, &reply);
331 if (r < 0)
332 return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r));
333
334 r = sd_bus_message_read(reply, "o", &object);
335 if (r < 0)
336 return bus_log_parse_error(r);
337
338 r = bus_wait_for_jobs_one(w, object, false);
339 if (r < 0)
340 return r;
341
342 return 0;
343 }
344
345 int terminate_scope(
346 sd_bus *bus,
347 const char *machine_name) {
348
349 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
350 _cleanup_free_ char *scope = NULL;
351 int r;
352
353 r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
354 if (r < 0)
355 return log_error_errno(r, "Failed to mangle scope name: %m");
356
357 r = sd_bus_call_method(
358 bus,
359 "org.freedesktop.systemd1",
360 "/org/freedesktop/systemd1",
361 "org.freedesktop.systemd1.Manager",
362 "AbandonScope",
363 &error,
364 NULL,
365 "s",
366 scope);
367 if (r < 0) {
368 log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
369 sd_bus_error_free(&error);
370 }
371
372 r = sd_bus_call_method(
373 bus,
374 "org.freedesktop.systemd1",
375 "/org/freedesktop/systemd1",
376 "org.freedesktop.systemd1.Manager",
377 "KillUnit",
378 &error,
379 NULL,
380 "ssi",
381 scope,
382 "all",
383 (int32_t) SIGKILL);
384 if (r < 0) {
385 log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
386 sd_bus_error_free(&error);
387 }
388
389 r = sd_bus_call_method(
390 bus,
391 "org.freedesktop.systemd1",
392 "/org/freedesktop/systemd1",
393 "org.freedesktop.systemd1.Manager",
394 "UnrefUnit",
395 &error,
396 NULL,
397 "s",
398 scope);
399 if (r < 0)
400 log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
401
402 return 0;
403 }