]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-register.c
Merge pull request #11988 from keszybz/test-binaries-installation
[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 bool keep_unit,
116 const char *service) {
117
118 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
119 int r;
120
121 assert(bus);
122
123 if (keep_unit) {
124 r = sd_bus_call_method(
125 bus,
126 "org.freedesktop.machine1",
127 "/org/freedesktop/machine1",
128 "org.freedesktop.machine1.Manager",
129 "RegisterMachineWithNetwork",
130 &error,
131 NULL,
132 "sayssusai",
133 machine_name,
134 SD_BUS_MESSAGE_APPEND_ID128(uuid),
135 service,
136 "container",
137 (uint32_t) pid,
138 strempty(directory),
139 local_ifindex > 0 ? 1 : 0, local_ifindex);
140 } else {
141 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
142
143 r = sd_bus_message_new_method_call(
144 bus,
145 &m,
146 "org.freedesktop.machine1",
147 "/org/freedesktop/machine1",
148 "org.freedesktop.machine1.Manager",
149 "CreateMachineWithNetwork");
150 if (r < 0)
151 return bus_log_create_error(r);
152
153 r = sd_bus_message_append(
154 m,
155 "sayssusai",
156 machine_name,
157 SD_BUS_MESSAGE_APPEND_ID128(uuid),
158 service,
159 "container",
160 (uint32_t) pid,
161 strempty(directory),
162 local_ifindex > 0 ? 1 : 0, local_ifindex);
163 if (r < 0)
164 return bus_log_create_error(r);
165
166 r = sd_bus_message_open_container(m, 'a', "(sv)");
167 if (r < 0)
168 return bus_log_create_error(r);
169
170 if (!isempty(slice)) {
171 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
172 if (r < 0)
173 return bus_log_create_error(r);
174 }
175
176 r = append_controller_property(bus, m);
177 if (r < 0)
178 return r;
179
180 r = append_machine_properties(
181 m,
182 mounts,
183 n_mounts,
184 kill_signal);
185 if (r < 0)
186 return r;
187
188 r = bus_append_unit_property_assignment_many(m, UNIT_SERVICE, properties);
189 if (r < 0)
190 return r;
191
192 r = sd_bus_message_close_container(m);
193 if (r < 0)
194 return bus_log_create_error(r);
195
196 r = sd_bus_call(bus, m, 0, &error, NULL);
197 }
198
199 if (r < 0)
200 return log_error_errno(r, "Failed to register machine: %s", bus_error_message(&error, r));
201
202 return 0;
203 }
204
205 int terminate_machine(
206 sd_bus *bus,
207 const char *machine_name) {
208
209 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
210 int r;
211
212 assert(bus);
213
214 r = sd_bus_call_method(
215 bus,
216 "org.freedesktop.machine1",
217 "/org/freedesktop/machine1",
218 "org.freedesktop.machine1.Manager",
219 "TerminateMachine",
220 &error,
221 NULL,
222 "s",
223 machine_name);
224 if (r < 0)
225 log_debug("Failed to terminate machine: %s", bus_error_message(&error, r));
226
227 return 0;
228 }
229
230 int allocate_scope(
231 sd_bus *bus,
232 const char *machine_name,
233 pid_t pid,
234 const char *slice,
235 CustomMount *mounts,
236 unsigned n_mounts,
237 int kill_signal,
238 char **properties) {
239
240 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
241 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
242 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
243 _cleanup_free_ char *scope = NULL;
244 const char *description, *object;
245 int r;
246
247 assert(bus);
248
249 r = bus_wait_for_jobs_new(bus, &w);
250 if (r < 0)
251 return log_error_errno(r, "Could not watch job: %m");
252
253 r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
254 if (r < 0)
255 return log_error_errno(r, "Failed to mangle scope name: %m");
256
257 r = sd_bus_message_new_method_call(
258 bus,
259 &m,
260 "org.freedesktop.systemd1",
261 "/org/freedesktop/systemd1",
262 "org.freedesktop.systemd1.Manager",
263 "StartTransientUnit");
264 if (r < 0)
265 return bus_log_create_error(r);
266
267 r = sd_bus_message_append(m, "ss", scope, "fail");
268 if (r < 0)
269 return bus_log_create_error(r);
270
271 /* Properties */
272 r = sd_bus_message_open_container(m, 'a', "(sv)");
273 if (r < 0)
274 return bus_log_create_error(r);
275
276 description = strjoina("Container ", machine_name);
277
278 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)(sv)(sv)",
279 "PIDs", "au", 1, pid,
280 "Description", "s", description,
281 "Delegate", "b", 1,
282 "CollectMode", "s", "inactive-or-failed",
283 "AddRef", "b", 1,
284 "Slice", "s", isempty(slice) ? SPECIAL_MACHINE_SLICE : slice);
285 if (r < 0)
286 return bus_log_create_error(r);
287
288 r = append_controller_property(bus, m);
289 if (r < 0)
290 return r;
291
292 r = append_machine_properties(
293 m,
294 mounts,
295 n_mounts,
296 kill_signal);
297 if (r < 0)
298 return r;
299
300 r = bus_append_unit_property_assignment_many(m, UNIT_SCOPE, properties);
301 if (r < 0)
302 return r;
303
304 r = sd_bus_message_close_container(m);
305 if (r < 0)
306 return bus_log_create_error(r);
307
308 /* No auxiliary units */
309 r = sd_bus_message_append(
310 m,
311 "a(sa(sv))",
312 0);
313 if (r < 0)
314 return bus_log_create_error(r);
315
316 r = sd_bus_call(bus, m, 0, &error, &reply);
317 if (r < 0)
318 return log_error_errno(r, "Failed to allocate scope: %s", bus_error_message(&error, r));
319
320 r = sd_bus_message_read(reply, "o", &object);
321 if (r < 0)
322 return bus_log_parse_error(r);
323
324 r = bus_wait_for_jobs_one(w, object, false);
325 if (r < 0)
326 return r;
327
328 return 0;
329 }
330
331 int terminate_scope(
332 sd_bus *bus,
333 const char *machine_name) {
334
335 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
336 _cleanup_free_ char *scope = NULL;
337 int r;
338
339 r = unit_name_mangle_with_suffix(machine_name, 0, ".scope", &scope);
340 if (r < 0)
341 return log_error_errno(r, "Failed to mangle scope name: %m");
342
343 r = sd_bus_call_method(
344 bus,
345 "org.freedesktop.systemd1",
346 "/org/freedesktop/systemd1",
347 "org.freedesktop.systemd1.Manager",
348 "AbandonScope",
349 &error,
350 NULL,
351 "s",
352 scope);
353 if (r < 0) {
354 log_debug_errno(r, "Failed to abandon scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
355 sd_bus_error_free(&error);
356 }
357
358 r = sd_bus_call_method(
359 bus,
360 "org.freedesktop.systemd1",
361 "/org/freedesktop/systemd1",
362 "org.freedesktop.systemd1.Manager",
363 "KillUnit",
364 &error,
365 NULL,
366 "ssi",
367 scope,
368 "all",
369 (int32_t) SIGKILL);
370 if (r < 0) {
371 log_debug_errno(r, "Failed to SIGKILL scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
372 sd_bus_error_free(&error);
373 }
374
375 r = sd_bus_call_method(
376 bus,
377 "org.freedesktop.systemd1",
378 "/org/freedesktop/systemd1",
379 "org.freedesktop.systemd1.Manager",
380 "UnrefUnit",
381 &error,
382 NULL,
383 "s",
384 scope);
385 if (r < 0)
386 log_debug_errno(r, "Failed to drop reference to scope '%s', ignoring: %s", scope, bus_error_message(&error, r));
387
388 return 0;
389 }