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