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