]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/nspawn/nspawn-register.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / nspawn / nspawn-register.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2015 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
21 #include "sd-bus.h"
22
23 #include "bus-error.h"
24 #include "bus-unit-util.h"
25 #include "bus-util.h"
26 #include "nspawn-register.h"
27 #include "stat-util.h"
28 #include "strv.h"
29 #include "util.h"
30
31 static int append_machine_properties(
32 sd_bus_message *m,
33 CustomMount *mounts,
34 unsigned n_mounts,
35 int kill_signal,
36 char **properties) {
37
38 unsigned j;
39 int r;
40
41 assert(m);
42
43 r = sd_bus_message_append(m, "(sv)", "DevicePolicy", "s", "closed");
44 if (r < 0)
45 return bus_log_create_error(r);
46
47 /* If you make changes here, also make sure to update systemd-nspawn@.service, to keep the device policies in
48 * sync regardless if we are run with or without the --keep-unit switch. */
49 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 2,
50 /* Allow the container to
51 * access and create the API
52 * device nodes, so that
53 * PrivateDevices= in the
54 * container can work
55 * fine */
56 "/dev/net/tun", "rwm",
57 /* Allow the container
58 * access to ptys. However,
59 * do not permit the
60 * container to ever create
61 * these device nodes. */
62 "char-pts", "rw");
63 if (r < 0)
64 return bus_log_create_error(r);
65
66 for (j = 0; j < n_mounts; j++) {
67 CustomMount *cm = mounts + j;
68
69 if (cm->type != CUSTOM_MOUNT_BIND)
70 continue;
71
72 r = is_device_node(cm->source);
73 if (r == -ENOENT) {
74 /* The bind source might only appear as the image is put together, hence don't complain */
75 log_debug_errno(r, "Bind mount source %s not found, ignoring: %m", cm->source);
76 continue;
77 }
78 if (r < 0)
79 return log_error_errno(r, "Failed to stat %s: %m", cm->source);
80
81 if (r) {
82 r = sd_bus_message_append(m, "(sv)", "DeviceAllow", "a(ss)", 1,
83 cm->source, cm->read_only ? "r" : "rw");
84 if (r < 0)
85 return log_error_errno(r, "Failed to append message arguments: %m");
86 }
87 }
88
89 if (kill_signal != 0) {
90 r = sd_bus_message_append(m, "(sv)", "KillSignal", "i", kill_signal);
91 if (r < 0)
92 return bus_log_create_error(r);
93
94 r = sd_bus_message_append(m, "(sv)", "KillMode", "s", "mixed");
95 if (r < 0)
96 return bus_log_create_error(r);
97 }
98
99 return 0;
100 }
101
102 int register_machine(
103 const char *machine_name,
104 pid_t pid,
105 const char *directory,
106 sd_id128_t uuid,
107 int local_ifindex,
108 const char *slice,
109 CustomMount *mounts,
110 unsigned n_mounts,
111 int kill_signal,
112 char **properties,
113 bool keep_unit,
114 const char *service) {
115
116 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
117 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
118 int r;
119
120 r = sd_bus_default_system(&bus);
121 if (r < 0)
122 return log_error_errno(r, "Failed to open system bus: %m");
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_machine_properties(
178 m,
179 mounts,
180 n_mounts,
181 kill_signal,
182 properties);
183 if (r < 0)
184 return r;
185
186 r = bus_append_unit_property_assignment_many(m, properties);
187 if (r < 0)
188 return r;
189
190 r = sd_bus_message_close_container(m);
191 if (r < 0)
192 return bus_log_create_error(r);
193
194 r = sd_bus_call(bus, m, 0, &error, NULL);
195 }
196
197 if (r < 0) {
198 log_error("Failed to register machine: %s", bus_error_message(&error, r));
199 return r;
200 }
201
202 return 0;
203 }
204
205 int terminate_machine(pid_t pid) {
206 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
207 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
208 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
209 const char *path;
210 int r;
211
212 r = sd_bus_default_system(&bus);
213 if (r < 0)
214 return log_error_errno(r, "Failed to open system bus: %m");
215
216 r = sd_bus_call_method(
217 bus,
218 "org.freedesktop.machine1",
219 "/org/freedesktop/machine1",
220 "org.freedesktop.machine1.Manager",
221 "GetMachineByPID",
222 &error,
223 &reply,
224 "u",
225 (uint32_t) pid);
226 if (r < 0) {
227 /* Note that the machine might already have been
228 * cleaned up automatically, hence don't consider it a
229 * failure if we cannot get the machine object. */
230 log_debug("Failed to get machine: %s", bus_error_message(&error, r));
231 return 0;
232 }
233
234 r = sd_bus_message_read(reply, "o", &path);
235 if (r < 0)
236 return bus_log_parse_error(r);
237
238 r = sd_bus_call_method(
239 bus,
240 "org.freedesktop.machine1",
241 path,
242 "org.freedesktop.machine1.Machine",
243 "Terminate",
244 &error,
245 NULL,
246 NULL);
247 if (r < 0) {
248 log_debug("Failed to terminate machine: %s", bus_error_message(&error, r));
249 return 0;
250 }
251
252 return 0;
253 }
254
255 int allocate_scope(
256 const char *machine_name,
257 pid_t pid,
258 const char *slice,
259 CustomMount *mounts,
260 unsigned n_mounts,
261 int kill_signal,
262 char **properties) {
263
264 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
265 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
266 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
267 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
268 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
269 _cleanup_free_ char *scope = NULL;
270 const char *description, *object;
271 int r;
272
273 r = sd_bus_default_system(&bus);
274 if (r < 0)
275 return log_error_errno(r, "Failed to open system bus: %m");
276
277 r = bus_wait_for_jobs_new(bus, &w);
278 if (r < 0)
279 return log_error_errno(r, "Could not watch job: %m");
280
281 r = unit_name_mangle_with_suffix(machine_name, UNIT_NAME_NOGLOB, ".scope", &scope);
282 if (r < 0)
283 return log_error_errno(r, "Failed to mangle scope name: %m");
284
285 r = sd_bus_message_new_method_call(
286 bus,
287 &m,
288 "org.freedesktop.systemd1",
289 "/org/freedesktop/systemd1",
290 "org.freedesktop.systemd1.Manager",
291 "StartTransientUnit");
292 if (r < 0)
293 return bus_log_create_error(r);
294
295 r = sd_bus_message_append(m, "ss", scope, "fail");
296 if (r < 0)
297 return bus_log_create_error(r);
298
299 /* Properties */
300 r = sd_bus_message_open_container(m, 'a', "(sv)");
301 if (r < 0)
302 return bus_log_create_error(r);
303
304 description = strjoina("Container ", machine_name);
305
306 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
307 "PIDs", "au", 1, pid,
308 "Description", "s", description,
309 "Delegate", "b", 1,
310 "Slice", "s", isempty(slice) ? "machine.slice" : slice);
311 if (r < 0)
312 return bus_log_create_error(r);
313
314 r = append_machine_properties(
315 m,
316 mounts,
317 n_mounts,
318 kill_signal,
319 properties);
320 if (r < 0)
321 return r;
322
323 r = bus_append_unit_property_assignment_many(m, properties);
324 if (r < 0)
325 return r;
326
327 r = sd_bus_message_close_container(m);
328 if (r < 0)
329 return bus_log_create_error(r);
330
331 /* No auxiliary units */
332 r = sd_bus_message_append(
333 m,
334 "a(sa(sv))",
335 0);
336 if (r < 0)
337 return bus_log_create_error(r);
338
339 r = sd_bus_call(bus, m, 0, &error, &reply);
340 if (r < 0) {
341 log_error("Failed to allocate scope: %s", bus_error_message(&error, r));
342 return r;
343 }
344
345 r = sd_bus_message_read(reply, "o", &object);
346 if (r < 0)
347 return bus_log_parse_error(r);
348
349 r = bus_wait_for_jobs_one(w, object, false);
350 if (r < 0)
351 return r;
352
353 return 0;
354 }