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