]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machine.c
man/systemd-sysext: list ephemeral/ephemeral-import in the list of options
[thirdparty/systemd.git] / src / machine / machine.c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <sched.h>
4 #include <sys/stat.h>
5 #include <unistd.h>
6
7 #include "sd-bus.h"
8 #include "sd-event.h"
9 #include "sd-messages.h"
10
11 #include "alloc-util.h"
12 #include "bus-error.h"
13 #include "bus-internal.h"
14 #include "bus-locator.h"
15 #include "bus-unit-util.h"
16 #include "env-file.h"
17 #include "errno-util.h"
18 #include "escape.h"
19 #include "extract-word.h"
20 #include "fd-util.h"
21 #include "fileio.h"
22 #include "format-util.h"
23 #include "fs-util.h"
24 #include "hashmap.h"
25 #include "log.h"
26 #include "machine.h"
27 #include "machine-dbus.h"
28 #include "machined.h"
29 #include "mkdir-label.h"
30 #include "namespace-util.h"
31 #include "operation.h"
32 #include "parse-util.h"
33 #include "path-util.h"
34 #include "process-util.h"
35 #include "serialize.h"
36 #include "socket-util.h"
37 #include "special.h"
38 #include "stdio-util.h"
39 #include "string-table.h"
40 #include "string-util.h"
41 #include "strv.h"
42 #include "terminal-util.h"
43 #include "tmpfile-util.h"
44 #include "uid-range.h"
45 #include "unit-name.h"
46 #include "user-util.h"
47
48 int machine_new(MachineClass class, const char *name, Machine **ret) {
49 _cleanup_(machine_freep) Machine *m = NULL;
50
51 assert(class < _MACHINE_CLASS_MAX);
52 assert(ret);
53
54 /* Passing class == _MACHINE_CLASS_INVALID here is fine. It
55 * means as much as "we don't know yet", and that we'll figure
56 * it out later when loading the state file. */
57
58 m = new(Machine, 1);
59 if (!m)
60 return -ENOMEM;
61
62 *m = (Machine) {
63 .class = class,
64 .leader = PIDREF_NULL,
65 .vsock_cid = VMADDR_CID_ANY,
66 };
67
68 if (name) {
69 m->name = strdup(name);
70 if (!m->name)
71 return -ENOMEM;
72 }
73
74 *ret = TAKE_PTR(m);
75 return 0;
76 }
77
78 int machine_link(Manager *manager, Machine *machine) {
79 int r;
80
81 assert(manager);
82 assert(machine);
83
84 if (machine->manager)
85 return -EEXIST;
86 if (!machine->name)
87 return -EINVAL;
88
89 if (machine->class != MACHINE_HOST) {
90 char *temp = path_join("/run/systemd/machines", machine->name);
91 if (!temp)
92 return -ENOMEM;
93
94 free_and_replace(machine->state_file, temp);
95 }
96
97 r = hashmap_put(manager->machines, machine->name, machine);
98 if (r < 0)
99 return r;
100
101 machine->manager = manager;
102
103 return 0;
104 }
105
106 Machine* machine_free(Machine *m) {
107 if (!m)
108 return NULL;
109
110 while (m->operations)
111 operation_free(m->operations);
112
113 if (m->in_gc_queue) {
114 assert(m->manager);
115 LIST_REMOVE(gc_queue, m->manager->machine_gc_queue, m);
116 }
117
118 if (m->manager) {
119 machine_release_unit(m);
120
121 (void) hashmap_remove(m->manager->machines, m->name);
122
123 if (m->manager->host_machine == m)
124 m->manager->host_machine = NULL;
125 }
126
127 m->leader_pidfd_event_source = sd_event_source_disable_unref(m->leader_pidfd_event_source);
128 if (pidref_is_set(&m->leader)) {
129 if (m->manager)
130 (void) hashmap_remove_value(m->manager->machines_by_leader, &m->leader, m);
131 pidref_done(&m->leader);
132 }
133
134 sd_bus_message_unref(m->create_message);
135
136 free(m->name);
137 free(m->scope_job);
138 free(m->state_file);
139 free(m->service);
140 free(m->root_directory);
141 free(m->netif);
142 free(m->ssh_address);
143 free(m->ssh_private_key_path);
144 return mfree(m);
145 }
146
147 int machine_save(Machine *m) {
148 int r;
149
150 assert(m);
151
152 if (!m->state_file)
153 return 0;
154
155 if (!m->started)
156 return 0;
157
158 _cleanup_(unlink_and_freep) char *sl = NULL; /* auto-unlink! */
159 if (m->unit) {
160 sl = strjoin("/run/systemd/machines/unit:", m->unit);
161 if (!sl)
162 return log_oom();
163 }
164
165 r = mkdir_safe_label("/run/systemd/machines", 0755, 0, 0, MKDIR_WARN_MODE);
166 if (r < 0)
167 return log_error_errno(r, "Failed to create /run/systemd/machines/: %m");
168
169 _cleanup_(unlink_and_freep) char *temp_path = NULL;
170 _cleanup_fclose_ FILE *f = NULL;
171 r = fopen_tmpfile_linkable(m->state_file, O_WRONLY|O_CLOEXEC, &temp_path, &f);
172 if (r < 0)
173 return log_error_errno(r, "Failed to create state file '%s': %m", m->state_file);
174
175 if (fchmod(fileno(f), 0644) < 0)
176 return log_error_errno(errno, "Failed to set access mode for state file '%s' to 0644: %m", m->state_file);
177
178 fprintf(f,
179 "# This is private data. Do not parse.\n"
180 "NAME=%s\n",
181 m->name);
182
183 /* We continue to call this "SCOPE=" because it is internal only, and we want to stay compatible with old files */
184 env_file_fputs_assignment(f, "SCOPE=", m->unit);
185 env_file_fputs_assignment(f, "SCOPE_JOB=", m->scope_job);
186
187 env_file_fputs_assignment(f, "SERVICE=", m->service);
188 env_file_fputs_assignment(f, "ROOT=", m->root_directory);
189
190 if (!sd_id128_is_null(m->id))
191 fprintf(f, "ID=" SD_ID128_FORMAT_STR "\n", SD_ID128_FORMAT_VAL(m->id));
192
193 if (pidref_is_set(&m->leader)) {
194 fprintf(f, "LEADER="PID_FMT"\n", m->leader.pid);
195 (void) pidref_acquire_pidfd_id(&m->leader);
196 if (m->leader.fd_id != 0)
197 fprintf(f, "LEADER_PIDFDID=%" PRIu64 "\n", m->leader.fd_id);
198 }
199
200 if (m->class != _MACHINE_CLASS_INVALID)
201 fprintf(f, "CLASS=%s\n", machine_class_to_string(m->class));
202
203 if (dual_timestamp_is_set(&m->timestamp))
204 fprintf(f,
205 "REALTIME="USEC_FMT"\n"
206 "MONOTONIC="USEC_FMT"\n",
207 m->timestamp.realtime,
208 m->timestamp.monotonic);
209
210 if (m->n_netif > 0) {
211 fputs("NETIF=\"", f);
212 FOREACH_ARRAY(ifi, m->netif, m->n_netif) {
213 if (*ifi != 0)
214 fputc(' ', f);
215 fprintf(f, "%i", *ifi);
216 }
217 fputs("\"\n", f);
218 }
219
220 if (m->vsock_cid != 0)
221 fprintf(f, "VSOCK_CID=%u\n", m->vsock_cid);
222
223 env_file_fputs_assignment(f, "SSH_ADDRESS=", m->ssh_address);
224 env_file_fputs_assignment(f, "SSH_PRIVATE_KEY_PATH=", m->ssh_private_key_path);
225
226 r = flink_tmpfile(f, temp_path, m->state_file, LINK_TMPFILE_REPLACE);
227 if (r < 0)
228 return log_error_errno(r, "Failed to move '%s' into place: %m", m->state_file);
229
230 temp_path = mfree(temp_path); /* disarm auto-destroy: temporary file does not exist anymore */
231
232 if (sl) {
233 /* Create a symlink from the unit name to the machine name, so that we can quickly find the machine
234 * for each given unit. Ignore error. */
235 (void) symlink(m->name, sl);
236
237 /* disarm auto-removal */
238 sl = mfree(sl);
239 }
240
241 return 0;
242 }
243
244 static void machine_unlink(Machine *m) {
245 assert(m);
246
247 if (m->unit) {
248 const char *sl = strjoina("/run/systemd/machines/unit:", m->unit);
249 (void) unlink(sl);
250 }
251
252 if (m->state_file)
253 (void) unlink(m->state_file);
254 }
255
256 int machine_load(Machine *m) {
257 _cleanup_free_ char *name = NULL, *realtime = NULL, *monotonic = NULL, *id = NULL, *leader = NULL, *leader_pidfdid = NULL,
258 *class = NULL, *netif = NULL, *vsock_cid = NULL;
259 int r;
260
261 assert(m);
262
263 if (!m->state_file)
264 return 0;
265
266 r = parse_env_file(NULL, m->state_file,
267 "NAME", &name,
268 "SCOPE", &m->unit,
269 "SCOPE_JOB", &m->scope_job,
270 "SERVICE", &m->service,
271 "ROOT", &m->root_directory,
272 "ID", &id,
273 "LEADER", &leader,
274 "LEADER_PIDFDID", &leader_pidfdid,
275 "CLASS", &class,
276 "REALTIME", &realtime,
277 "MONOTONIC", &monotonic,
278 "NETIF", &netif,
279 "VSOCK_CID", &vsock_cid,
280 "SSH_ADDRESS", &m->ssh_address,
281 "SSH_PRIVATE_KEY_PATH", &m->ssh_private_key_path);
282 if (r == -ENOENT)
283 return 0;
284 if (r < 0)
285 return log_error_errno(r, "Failed to read %s: %m", m->state_file);
286
287 if (!streq_ptr(name, m->name))
288 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "State file '%s' for machine '%s' reports a different name '%s', refusing", m->state_file, m->name, name);
289
290 if (id)
291 (void) sd_id128_from_string(id, &m->id);
292
293 pidref_done(&m->leader);
294 if (leader) {
295 r = pidref_set_pidstr(&m->leader, leader);
296 if (r < 0)
297 log_debug_errno(r, "Failed to set leader PID to '%s', ignoring: %m", leader);
298 else if (leader_pidfdid) {
299 uint64_t fd_id;
300 r = safe_atou64(leader_pidfdid, &fd_id);
301 if (r < 0)
302 log_warning_errno(r, "Failed to parse leader pidfd ID, ignoring: %s", leader_pidfdid);
303 else {
304 (void) pidref_acquire_pidfd_id(&m->leader);
305
306 if (fd_id != m->leader.fd_id) {
307 log_debug("Leader PID got recycled, ignoring.");
308 pidref_done(&m->leader);
309 }
310 }
311 }
312 }
313
314 if (class) {
315 MachineClass c = machine_class_from_string(class);
316 if (c >= 0)
317 m->class = c;
318 }
319
320 if (realtime)
321 (void) deserialize_usec(realtime, &m->timestamp.realtime);
322 if (monotonic)
323 (void) deserialize_usec(monotonic, &m->timestamp.monotonic);
324
325 m->netif = mfree(m->netif);
326 m->n_netif = 0;
327 if (netif) {
328 _cleanup_free_ int *ni = NULL;
329 size_t nr = 0;
330
331 for (const char *p = netif;;) {
332 _cleanup_free_ char *word = NULL;
333
334 r = extract_first_word(&p, &word, NULL, 0);
335 if (r == 0)
336 break;
337 if (r == -ENOMEM)
338 return log_oom();
339 if (r < 0) {
340 log_warning_errno(r, "Failed to parse NETIF: %s", netif);
341 break;
342 }
343
344 r = parse_ifindex(word);
345 if (r < 0)
346 continue;
347
348 if (!GREEDY_REALLOC(ni, nr + 1))
349 return log_oom();
350
351 ni[nr++] = r;
352 }
353
354 m->netif = TAKE_PTR(ni);
355 m->n_netif = nr;
356 }
357
358 m->vsock_cid = 0;
359 if (vsock_cid) {
360 r = safe_atou(vsock_cid, &m->vsock_cid);
361 if (r < 0)
362 log_warning_errno(r, "Failed to parse AF_VSOCK CID, ignoring: %s", vsock_cid);
363 }
364
365 return r;
366 }
367
368 static int machine_start_scope(
369 Machine *machine,
370 bool allow_pidfd,
371 sd_bus_message *more_properties,
372 sd_bus_error *error) {
373
374 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL;
375 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
376 _cleanup_free_ char *escaped = NULL, *unit = NULL;
377 const char *description;
378 int r;
379
380 assert(machine);
381 assert(pidref_is_set(&machine->leader));
382 assert(!machine->unit);
383
384 escaped = unit_name_escape(machine->name);
385 if (!escaped)
386 return log_oom();
387
388 unit = strjoin("machine-", escaped, ".scope");
389 if (!unit)
390 return log_oom();
391
392 r = bus_message_new_method_call(
393 machine->manager->bus,
394 &m,
395 bus_systemd_mgr,
396 "StartTransientUnit");
397 if (r < 0)
398 return r;
399
400 r = sd_bus_message_append(m, "ss", unit, "fail");
401 if (r < 0)
402 return r;
403
404 r = sd_bus_message_open_container(m, 'a', "(sv)");
405 if (r < 0)
406 return r;
407
408 r = sd_bus_message_append(m, "(sv)", "Slice", "s", SPECIAL_MACHINE_SLICE);
409 if (r < 0)
410 return r;
411
412 description = strjoina(machine->class == MACHINE_VM ? "Virtual Machine " : "Container ", machine->name);
413 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
414 if (r < 0)
415 return r;
416
417 r = bus_append_scope_pidref(m, &machine->leader, allow_pidfd);
418 if (r < 0)
419 return r;
420
421 r = sd_bus_message_append(m, "(sv)(sv)(sv)(sv)",
422 "Delegate", "b", 1,
423 "CollectMode", "s", "inactive-or-failed",
424 "AddRef", "b", 1,
425 "TasksMax", "t", UINT64_C(16384));
426 if (r < 0)
427 return r;
428
429 if (more_properties) {
430 r = sd_bus_message_copy(m, more_properties, true);
431 if (r < 0)
432 return r;
433 }
434
435 r = sd_bus_message_close_container(m);
436 if (r < 0)
437 return r;
438
439 r = sd_bus_message_append(m, "a(sa(sv))", 0);
440 if (r < 0)
441 return r;
442
443 r = sd_bus_call(NULL, m, 0, &e, &reply);
444 if (r < 0) {
445 /* If this failed with a property we couldn't write, this is quite likely because the server
446 * doesn't support PIDFDs yet, let's try without. */
447 if (allow_pidfd &&
448 sd_bus_error_has_names(&e, SD_BUS_ERROR_UNKNOWN_PROPERTY, SD_BUS_ERROR_PROPERTY_READ_ONLY))
449 return machine_start_scope(machine, /* allow_pidfd = */ false, more_properties, error);
450
451 return sd_bus_error_move(error, &e);
452 }
453
454 machine->unit = TAKE_PTR(unit);
455 machine->referenced = true;
456
457 const char *job;
458 r = sd_bus_message_read(reply, "o", &job);
459 if (r < 0)
460 return r;
461
462 return free_and_strdup(&machine->scope_job, job);
463 }
464
465 static int machine_ensure_scope(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
466 int r;
467
468 assert(m);
469 assert(m->class != MACHINE_HOST);
470
471 if (!m->unit) {
472 r = machine_start_scope(m, /* allow_pidfd = */ true, properties, error);
473 if (r < 0)
474 return log_error_errno(r, "Failed to start machine scope: %s", bus_error_message(error, r));
475 }
476
477 assert(m->unit);
478
479 r = hashmap_ensure_put(&m->manager->machines_by_unit, &string_hash_ops, m->unit, m);
480 if (r < 0)
481 return r;
482
483 return 0;
484 }
485
486 static int machine_dispatch_leader_pidfd(sd_event_source *s, int fd, unsigned revents, void *userdata) {
487 Machine *m = ASSERT_PTR(userdata);
488
489 m->leader_pidfd_event_source = sd_event_source_disable_unref(m->leader_pidfd_event_source);
490 machine_add_to_gc_queue(m);
491
492 return 0;
493 }
494
495 static int machine_watch_pidfd(Machine *m) {
496 int r;
497
498 assert(m);
499 assert(m->manager);
500 assert(pidref_is_set(&m->leader));
501 assert(!m->leader_pidfd_event_source);
502
503 if (m->leader.fd < 0)
504 return 0;
505
506 /* If we have a pidfd for the leader, let's also track it for POLLIN, and GC the machine
507 * automatically if it dies */
508
509 r = sd_event_add_io(m->manager->event, &m->leader_pidfd_event_source, m->leader.fd, EPOLLIN, machine_dispatch_leader_pidfd, m);
510 if (r < 0)
511 return r;
512
513 (void) sd_event_source_set_description(m->leader_pidfd_event_source, "machine-pidfd");
514
515 return 0;
516 }
517
518 int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) {
519 int r;
520
521 assert(m);
522
523 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
524 return -EOPNOTSUPP;
525
526 if (m->started)
527 return 0;
528
529 r = hashmap_ensure_put(&m->manager->machines_by_leader, &pidref_hash_ops, &m->leader, m);
530 if (r < 0)
531 return r;
532
533 r = machine_watch_pidfd(m);
534 if (r < 0)
535 return r;
536
537 /* Create cgroup */
538 r = machine_ensure_scope(m, properties, error);
539 if (r < 0)
540 return r;
541
542 log_struct(LOG_INFO,
543 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_START_STR),
544 LOG_ITEM("NAME=%s", m->name),
545 LOG_ITEM("LEADER="PID_FMT, m->leader.pid),
546 LOG_MESSAGE("New machine %s.", m->name));
547
548 if (!dual_timestamp_is_set(&m->timestamp))
549 dual_timestamp_now(&m->timestamp);
550
551 m->started = true;
552
553 /* Save new machine data */
554 machine_save(m);
555
556 machine_send_signal(m, true);
557
558 return 0;
559 }
560
561 int machine_stop(Machine *m) {
562 int r;
563
564 assert(m);
565
566 if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM))
567 return -EOPNOTSUPP;
568
569 if (m->unit) {
570 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
571 char *job = NULL;
572
573 r = manager_stop_unit(m->manager, m->unit, &error, &job);
574 if (r < 0)
575 return log_error_errno(r, "Failed to stop machine unit: %s", bus_error_message(&error, r));
576
577 free_and_replace(m->scope_job, job);
578 }
579
580 m->stopping = true;
581
582 machine_save(m);
583
584 return 0;
585 }
586
587 int machine_finalize(Machine *m) {
588 assert(m);
589
590 if (m->started) {
591 log_struct(LOG_INFO,
592 LOG_MESSAGE_ID(SD_MESSAGE_MACHINE_STOP_STR),
593 LOG_ITEM("NAME=%s", m->name),
594 LOG_ITEM("LEADER="PID_FMT, m->leader.pid),
595 LOG_MESSAGE("Machine %s terminated.", m->name));
596
597 m->stopping = true; /* The machine is supposed to be going away. Don't try to kill it. */
598 }
599
600 machine_unlink(m);
601 machine_add_to_gc_queue(m);
602
603 if (m->started) {
604 machine_send_signal(m, false);
605 m->started = false;
606 }
607
608 return 0;
609 }
610
611 bool machine_may_gc(Machine *m, bool drop_not_started) {
612 int r;
613
614 assert(m);
615
616 if (m->class == MACHINE_HOST)
617 return false;
618
619 if (drop_not_started && !m->started)
620 return true;
621
622 r = pidref_is_alive(&m->leader);
623 if (r == -ESRCH)
624 return true;
625 if (r < 0)
626 log_debug_errno(r, "Unable to determine if leader PID " PID_FMT " is still alive, assuming not: %m", m->leader.pid);
627 if (r > 0)
628 return false;
629
630 if (m->scope_job) {
631 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
632
633 r = manager_job_is_active(m->manager, m->scope_job, &error);
634 if (r < 0)
635 log_debug_errno(r, "Failed to determine whether job '%s' is active, assuming it is: %s", m->scope_job, bus_error_message(&error, r));
636 if (r != 0)
637 return false;
638 }
639
640 if (m->unit) {
641 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
642
643 r = manager_unit_is_active(m->manager, m->unit, &error);
644 if (r < 0)
645 log_debug_errno(r, "Failed to determine whether unit '%s' is active, assuming it is: %s", m->unit, bus_error_message(&error, r));
646 if (r != 0)
647 return false;
648 }
649
650 return true;
651 }
652
653 void machine_add_to_gc_queue(Machine *m) {
654 assert(m);
655
656 if (m->in_gc_queue)
657 return;
658
659 LIST_PREPEND(gc_queue, m->manager->machine_gc_queue, m);
660 m->in_gc_queue = true;
661
662 manager_enqueue_gc(m->manager);
663 }
664
665 MachineState machine_get_state(Machine *s) {
666 assert(s);
667
668 if (s->class == MACHINE_HOST)
669 return MACHINE_RUNNING;
670
671 if (s->stopping)
672 return MACHINE_CLOSING;
673
674 if (s->scope_job)
675 return MACHINE_OPENING;
676
677 return MACHINE_RUNNING;
678 }
679
680 int machine_kill(Machine *m, KillWhom whom, int signo) {
681 assert(m);
682
683 if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER))
684 return -EOPNOTSUPP;
685
686 if (!m->unit)
687 return -ESRCH;
688
689 if (whom == KILL_LEADER) /* If we shall simply kill the leader, do so directly */
690 return pidref_kill(&m->leader, signo);
691
692 /* Otherwise, make PID 1 do it for us, for the entire cgroup */
693 return manager_kill_unit(m->manager, m->unit, signo, NULL);
694 }
695
696 int machine_openpt(Machine *m, int flags, char **ret_peer) {
697 assert(m);
698
699 switch (m->class) {
700
701 case MACHINE_HOST:
702 return openpt_allocate(flags, ret_peer);
703
704 case MACHINE_CONTAINER:
705 if (!pidref_is_set(&m->leader))
706 return -EINVAL;
707
708 return openpt_allocate_in_namespace(&m->leader, flags, ret_peer);
709
710 default:
711 return -EOPNOTSUPP;
712 }
713 }
714
715 static int machine_bus_new(Machine *m, sd_bus_error *error, sd_bus **ret) {
716 int r;
717
718 assert(m);
719 assert(ret);
720
721 switch (m->class) {
722
723 case MACHINE_HOST:
724 *ret = NULL;
725 return 0;
726
727 case MACHINE_CONTAINER: {
728 _cleanup_(sd_bus_close_unrefp) sd_bus *bus = NULL;
729 char *address;
730
731 r = sd_bus_new(&bus);
732 if (r < 0)
733 return log_debug_errno(r, "Failed to allocate new DBus: %m");
734
735 if (asprintf(&address, "x-machine-unix:pid=%" PID_PRI, m->leader.pid) < 0)
736 return -ENOMEM;
737
738 bus->address = address;
739 bus->bus_client = true;
740 bus->trusted = false;
741 bus->runtime_scope = RUNTIME_SCOPE_SYSTEM;
742
743 r = sd_bus_start(bus);
744 if (r == -ENOENT)
745 return sd_bus_error_set_errnof(error, r, "There is no system bus in container %s.", m->name);
746 if (r < 0)
747 return r;
748
749 *ret = TAKE_PTR(bus);
750 return 0;
751 }
752
753 default:
754 return -EOPNOTSUPP;
755 }
756 }
757
758 int machine_start_getty(Machine *m, const char *ptmx_name, sd_bus_error *error) {
759 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
760 sd_bus *container_bus = NULL;
761 const char *p, *getty;
762 int r;
763
764 assert(m);
765 assert(ptmx_name);
766
767 p = path_startswith(ptmx_name, "/dev/pts/");
768 if (!p)
769 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Path of pseudo TTY has unexpected prefix");
770
771 r = machine_bus_new(m, error, &allocated_bus);
772 if (r < 0)
773 return log_debug_errno(r, "Failed to create DBus to machine: %m");
774
775 container_bus = allocated_bus ?: m->manager->bus;
776 getty = strjoina("container-getty@", p, ".service");
777
778 r = bus_call_method(container_bus, bus_systemd_mgr, "StartUnit", error, /* ret_reply = */ NULL, "ss", getty, "replace");
779 if (r < 0)
780 return log_debug_errno(r, "Failed to StartUnit '%s' in container '%s': %m", getty, m->name);
781
782 return 0;
783 }
784
785 int machine_start_shell(
786 Machine *m,
787 int ptmx_fd,
788 const char *ptmx_name,
789 const char *user,
790 const char *path,
791 char **args,
792 char **env,
793 sd_bus_error *error) {
794 _cleanup_close_ int pty_fd = -EBADF;
795 _cleanup_(sd_bus_message_unrefp) sd_bus_message *tm = NULL;
796 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *allocated_bus = NULL;
797 const char *p, *utmp_id, *unit, *description;
798 sd_bus *container_bus = NULL;
799 int r;
800
801 assert(m);
802 assert(ptmx_fd >= 0);
803 assert(ptmx_name);
804
805 if (isempty(user) || isempty(path) || strv_isempty(args))
806 return -EINVAL;
807
808 p = path_startswith(ptmx_name, "/dev/pts/");
809 utmp_id = path_startswith(ptmx_name, "/dev/");
810 if (!p || !utmp_id)
811 return log_debug_errno(SYNTHETIC_ERRNO(EINVAL), "Path of pseudo TTY has unexpected prefix");
812
813 pty_fd = pty_open_peer(ptmx_fd, O_RDWR|O_NOCTTY|O_CLOEXEC);
814 if (pty_fd < 0)
815 return log_debug_errno(pty_fd, "Failed to open terminal: %m");
816
817 r = machine_bus_new(m, error, &allocated_bus);
818 if (r < 0)
819 return log_debug_errno(r, "Failed to create DBus to machine: %m");
820
821 container_bus = allocated_bus ?: m->manager->bus;
822 r = bus_message_new_method_call(container_bus, &tm, bus_systemd_mgr, "StartTransientUnit");
823 if (r < 0)
824 return r;
825
826 /* Name and mode */
827 unit = strjoina("container-shell@", p, ".service");
828 r = sd_bus_message_append(tm, "ss", unit, "fail");
829 if (r < 0)
830 return r;
831
832 /* Properties */
833 r = sd_bus_message_open_container(tm, 'a', "(sv)");
834 if (r < 0)
835 return r;
836
837 description = strjoina("Shell for User ", user);
838 r = sd_bus_message_append(tm,
839 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
840 "Description", "s", description,
841 "StandardInputFileDescriptor", "h", pty_fd,
842 "StandardOutputFileDescriptor", "h", pty_fd,
843 "StandardErrorFileDescriptor", "h", pty_fd,
844 "SendSIGHUP", "b", true,
845 "IgnoreSIGPIPE", "b", false,
846 "KillMode", "s", "mixed",
847 "TTYPath", "s", ptmx_name,
848 "TTYReset", "b", true,
849 "UtmpIdentifier", "s", utmp_id,
850 "UtmpMode", "s", "user",
851 "PAMName", "s", "login",
852 "WorkingDirectory", "s", "-~");
853 if (r < 0)
854 return r;
855
856 r = sd_bus_message_append(tm, "(sv)", "User", "s", user);
857 if (r < 0)
858 return r;
859
860 if (!strv_isempty(env)) {
861 r = sd_bus_message_open_container(tm, 'r', "sv");
862 if (r < 0)
863 return r;
864
865 r = sd_bus_message_append(tm, "s", "Environment");
866 if (r < 0)
867 return r;
868
869 r = sd_bus_message_open_container(tm, 'v', "as");
870 if (r < 0)
871 return r;
872
873 r = sd_bus_message_append_strv(tm, env);
874 if (r < 0)
875 return r;
876
877 r = sd_bus_message_close_container(tm);
878 if (r < 0)
879 return r;
880
881 r = sd_bus_message_close_container(tm);
882 if (r < 0)
883 return r;
884 }
885
886 /* Exec container */
887 r = sd_bus_message_open_container(tm, 'r', "sv");
888 if (r < 0)
889 return r;
890
891 r = sd_bus_message_append(tm, "s", "ExecStart");
892 if (r < 0)
893 return r;
894
895 r = sd_bus_message_open_container(tm, 'v', "a(sasb)");
896 if (r < 0)
897 return r;
898
899 r = sd_bus_message_open_container(tm, 'a', "(sasb)");
900 if (r < 0)
901 return r;
902
903 r = sd_bus_message_open_container(tm, 'r', "sasb");
904 if (r < 0)
905 return r;
906
907 r = sd_bus_message_append(tm, "s", path);
908 if (r < 0)
909 return r;
910
911 r = sd_bus_message_append_strv(tm, args);
912 if (r < 0)
913 return r;
914
915 r = sd_bus_message_append(tm, "b", true);
916 if (r < 0)
917 return r;
918
919 r = sd_bus_message_close_container(tm);
920 if (r < 0)
921 return r;
922
923 r = sd_bus_message_close_container(tm);
924 if (r < 0)
925 return r;
926
927 r = sd_bus_message_close_container(tm);
928 if (r < 0)
929 return r;
930
931 r = sd_bus_message_close_container(tm);
932 if (r < 0)
933 return r;
934
935 r = sd_bus_message_close_container(tm);
936 if (r < 0)
937 return r;
938
939 /* Auxiliary units */
940 r = sd_bus_message_append(tm, "a(sa(sv))", 0);
941 if (r < 0)
942 return r;
943
944 r = sd_bus_call(container_bus, tm, 0, error, NULL);
945 if (r < 0)
946 return r;
947
948 return 0;
949 }
950
951 char** machine_default_shell_args(const char *user) {
952 _cleanup_strv_free_ char **args = NULL;
953 int r;
954
955 assert(user);
956
957 args = new0(char*, 3 + 1);
958 if (!args)
959 return NULL;
960
961 args[0] = strdup("sh");
962 if (!args[0])
963 return NULL;
964
965 args[1] = strdup("-c");
966 if (!args[1])
967 return NULL;
968
969 r = asprintf(&args[2],
970 "shell=$(getent passwd %s 2>/dev/null | { IFS=: read _ _ _ _ _ _ x; echo \"$x\"; })\n"\
971 "exec \"${shell:-/bin/sh}\" -l", /* -l is means --login */
972 user);
973 if (r < 0) {
974 args[2] = NULL;
975 return NULL;
976 }
977
978 return TAKE_PTR(args);
979 }
980
981 int machine_copy_from_to_operation(
982 Manager *manager,
983 Machine *machine,
984 const char *host_path,
985 const char *container_path,
986 bool copy_from_container,
987 CopyFlags copy_flags,
988 Operation **ret) {
989
990 _cleanup_close_ int host_fd = -EBADF, target_mntns_fd = -EBADF, source_mntns_fd = -EBADF;
991 _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
992 _cleanup_free_ char *host_basename = NULL, *container_basename = NULL;
993 _cleanup_(sigkill_waitp) pid_t child = 0;
994 uid_t uid_shift;
995 int r;
996
997 assert(manager);
998 assert(machine);
999 assert(ret);
1000
1001 if (isempty(host_path) || isempty(container_path))
1002 return -EINVAL;
1003
1004 r = path_extract_filename(host_path, &host_basename);
1005 if (r < 0)
1006 return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", host_path);
1007
1008 r = path_extract_filename(container_path, &container_basename);
1009 if (r < 0)
1010 return log_debug_errno(r, "Failed to extract file name of '%s' path: %m", container_path);
1011
1012 host_fd = open_parent(host_path, O_CLOEXEC, 0);
1013 if (host_fd < 0)
1014 return log_debug_errno(host_fd, "Failed to open host directory '%s': %m", host_path);
1015
1016 r = machine_get_uid_shift(machine, &uid_shift);
1017 if (r < 0)
1018 return log_debug_errno(r, "Failed to get UID shift of machine '%s': %m", machine->name);
1019
1020 target_mntns_fd = pidref_namespace_open_by_type(&machine->leader, NAMESPACE_MOUNT);
1021 if (target_mntns_fd < 0)
1022 return log_debug_errno(target_mntns_fd, "Failed to open mount namespace of machine '%s': %m", machine->name);
1023
1024 source_mntns_fd = namespace_open_by_type(NAMESPACE_MOUNT);
1025 if (source_mntns_fd < 0)
1026 return log_debug_errno(source_mntns_fd, "Failed to open our own mount namespace: %m");
1027
1028 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1029 return log_debug_errno(errno, "Failed to create pipe: %m");
1030
1031 r = namespace_fork("(sd-copyns)",
1032 "(sd-copy)",
1033 /* except_fds = */ NULL,
1034 /* n_except_fds = */ 0,
1035 FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
1036 /* pidns_fd = */ -EBADF,
1037 target_mntns_fd,
1038 /* netns_fd = */ -EBADF,
1039 /* userns_fd = */ -EBADF,
1040 /* root_fd = */ -EBADF,
1041 &child);
1042 if (r < 0)
1043 return log_debug_errno(r, "Failed to fork into mount namespace of machine '%s': %m", machine->name);
1044 if (r == 0) {
1045 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1046
1047 _cleanup_close_ int container_fd = -EBADF;
1048 container_fd = open_parent(container_path, O_CLOEXEC, 0);
1049 if (container_fd < 0) {
1050 log_debug_errno(container_fd, "Failed to open container directory: %m");
1051 report_errno_and_exit(errno_pipe_fd[1], container_fd);
1052 }
1053
1054 /* Rejoin the host namespace, so that /proc/self/fd/… works, which copy_tree_at() relies on
1055 * in some cases (by means of fd_reopen()) */
1056 if (setns(source_mntns_fd, CLONE_NEWNS) < 0) {
1057 r = log_debug_errno(errno, "Failed to rejoin namespace of host: %m");
1058 report_errno_and_exit(errno_pipe_fd[1], r);
1059 }
1060
1061 /* Run the actual copy operation. Note that when a UID shift is set we'll either clamp the UID/GID to
1062 * 0 or to the actual UID shift depending on the direction we copy. If no UID shift is set we'll copy
1063 * the UID/GIDs as they are. */
1064 if (copy_from_container)
1065 r = copy_tree_at(
1066 container_fd,
1067 container_basename,
1068 host_fd,
1069 host_basename,
1070 uid_shift == 0 ? UID_INVALID : 0,
1071 uid_shift == 0 ? GID_INVALID : 0,
1072 copy_flags,
1073 /* denylist = */ NULL,
1074 /* subvolumes = */ NULL);
1075 else
1076 r = copy_tree_at(
1077 host_fd,
1078 host_basename,
1079 container_fd,
1080 container_basename,
1081 uid_shift == 0 ? UID_INVALID : uid_shift,
1082 uid_shift == 0 ? GID_INVALID : uid_shift,
1083 copy_flags,
1084 /* denylist = */ NULL,
1085 /* subvolumes = */ NULL);
1086 if (r < 0)
1087 log_debug_errno(r, "Failed to copy tree: %m");
1088
1089 report_errno_and_exit(errno_pipe_fd[1], r);
1090 }
1091
1092 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1093
1094 Operation *operation;
1095 r = operation_new(manager, machine, child, errno_pipe_fd[0], &operation);
1096 if (r < 0)
1097 return r;
1098
1099 TAKE_FD(errno_pipe_fd[0]);
1100 TAKE_PID(child);
1101
1102 *ret = operation;
1103 return 0;
1104 }
1105
1106 void machine_release_unit(Machine *m) {
1107 assert(m);
1108
1109 if (!m->unit)
1110 return;
1111
1112 assert(m->manager);
1113
1114 if (m->referenced) {
1115 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1116 int r;
1117
1118 r = manager_unref_unit(m->manager, m->unit, &error);
1119 if (r < 0)
1120 log_full_errno(ERRNO_IS_DISCONNECT(r) ? LOG_DEBUG : LOG_WARNING, r,
1121 "Failed to drop reference to machine scope, ignoring: %s",
1122 bus_error_message(&error, r));
1123
1124 m->referenced = false;
1125 }
1126
1127 (void) hashmap_remove_value(m->manager->machines_by_unit, m->unit, m);
1128 m->unit = mfree(m->unit);
1129 }
1130
1131 int machine_get_uid_shift(Machine *m, uid_t *ret) {
1132 char p[STRLEN("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1133 uid_t uid_base, uid_shift, uid_range;
1134 gid_t gid_base, gid_shift, gid_range;
1135 _cleanup_fclose_ FILE *f = NULL;
1136 int r;
1137
1138 assert(m);
1139 assert(ret);
1140
1141 /* Return the base UID/GID of the specified machine. Note that this only works for containers with simple
1142 * mappings. In most cases setups should be simple like this, and administrators should only care about the
1143 * basic offset a container has relative to the host. This is what this function exposes.
1144 *
1145 * If we encounter any more complex mappings we politely refuse this with ENXIO. */
1146
1147 if (m->class == MACHINE_HOST) {
1148 *ret = 0;
1149 return 0;
1150 }
1151
1152 if (m->class != MACHINE_CONTAINER)
1153 return -EOPNOTSUPP;
1154
1155 xsprintf(p, "/proc/" PID_FMT "/uid_map", m->leader.pid);
1156 f = fopen(p, "re");
1157 if (!f) {
1158 if (errno == ENOENT) {
1159 /* If the file doesn't exist, user namespacing is off in the kernel, return a zero mapping hence. */
1160 *ret = 0;
1161 return 0;
1162 }
1163
1164 return -errno;
1165 }
1166
1167 /* Read the first line. There's at least one. */
1168 r = uid_map_read_one(f, &uid_base, &uid_shift, &uid_range);
1169 if (r < 0)
1170 return r;
1171
1172 /* Not a mapping starting at 0? Then it's a complex mapping we can't expose here. */
1173 if (uid_base != 0)
1174 return -ENXIO;
1175 /* Insist that at least the nobody user is mapped, everything else is weird, and hence complex, and we don't support it */
1176 if (uid_range < UID_NOBODY)
1177 return -ENXIO;
1178
1179 /* If there's more than one line, then we don't support this mapping. */
1180 r = safe_fgetc(f, NULL);
1181 if (r < 0)
1182 return r;
1183 if (r != 0) /* Insist on EOF */
1184 return -ENXIO;
1185
1186 fclose(f);
1187
1188 xsprintf(p, "/proc/" PID_FMT "/gid_map", m->leader.pid);
1189 f = fopen(p, "re");
1190 if (!f)
1191 return -errno;
1192
1193 /* Read the first line. There's at least one. */
1194 errno = 0;
1195 r = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT "\n", &gid_base, &gid_shift, &gid_range);
1196 if (r == EOF)
1197 return errno_or_else(ENOMSG);
1198 assert(r >= 0);
1199 if (r != 3)
1200 return -EBADMSG;
1201
1202 /* If there's more than one line, then we don't support this file. */
1203 r = safe_fgetc(f, NULL);
1204 if (r < 0)
1205 return r;
1206 if (r != 0) /* Insist on EOF */
1207 return -ENXIO;
1208
1209 /* If the UID and GID mapping doesn't match, we don't support this mapping. */
1210 if (uid_base != (uid_t) gid_base)
1211 return -ENXIO;
1212 if (uid_shift != (uid_t) gid_shift)
1213 return -ENXIO;
1214 if (uid_range != (uid_t) gid_range)
1215 return -ENXIO;
1216
1217 r = pidref_verify(&m->leader);
1218 if (r < 0)
1219 return r;
1220
1221 *ret = uid_shift;
1222 return 0;
1223 }
1224
1225 static int machine_owns_uid_internal(
1226 Machine *machine,
1227 const char *map_file, /* "uid_map" or "gid_map" */
1228 uid_t uid,
1229 uid_t *ret_internal_uid) {
1230
1231 _cleanup_fclose_ FILE *f = NULL;
1232 const char *p;
1233 int r;
1234
1235 /* This is a generic implementation for both uids and gids, under the assumptions they have the same types and semantics. */
1236 assert_cc(sizeof(uid_t) == sizeof(gid_t));
1237
1238 assert(machine);
1239
1240 /* Checks if the specified host UID is owned by the machine, and returns the UID it maps to
1241 * internally in the machine */
1242
1243 if (machine->class != MACHINE_CONTAINER)
1244 goto negative;
1245
1246 p = procfs_file_alloca(machine->leader.pid, map_file);
1247 f = fopen(p, "re");
1248 if (!f) {
1249 log_debug_errno(errno, "Failed to open %s, ignoring.", p);
1250 goto negative;
1251 }
1252
1253 for (;;) {
1254 uid_t uid_base, uid_shift, uid_range, converted;
1255
1256 r = uid_map_read_one(f, &uid_base, &uid_shift, &uid_range);
1257 if (r == -ENOMSG)
1258 break;
1259 if (r < 0)
1260 return r;
1261
1262 /* The private user namespace is disabled, ignoring. */
1263 if (uid_shift == 0)
1264 continue;
1265
1266 if (uid < uid_shift || uid >= uid_shift + uid_range)
1267 continue;
1268
1269 converted = (uid - uid_shift + uid_base);
1270 if (!uid_is_valid(converted))
1271 return -EINVAL;
1272
1273 r = pidref_verify(&machine->leader);
1274 if (r < 0)
1275 return r;
1276
1277 if (ret_internal_uid)
1278 *ret_internal_uid = converted;
1279
1280 return true;
1281 }
1282
1283 negative:
1284 if (ret_internal_uid)
1285 *ret_internal_uid = UID_INVALID;
1286
1287 return false;
1288 }
1289
1290 int machine_owns_uid(Machine *machine, uid_t uid, uid_t *ret_internal_uid) {
1291 return machine_owns_uid_internal(machine, "uid_map", uid, ret_internal_uid);
1292 }
1293
1294 int machine_owns_gid(Machine *machine, gid_t gid, gid_t *ret_internal_gid) {
1295 return machine_owns_uid_internal(machine, "gid_map", (uid_t) gid, (uid_t*) ret_internal_gid);
1296 }
1297
1298 static int machine_translate_uid_internal(
1299 Machine *machine,
1300 const char *map_file, /* "uid_map" or "gid_map" */
1301 uid_t uid,
1302 uid_t *ret_host_uid) {
1303
1304 _cleanup_fclose_ FILE *f = NULL;
1305 const char *p;
1306 int r;
1307
1308 /* This is a generic implementation for both uids and gids, under the assumptions they have the same types and semantics. */
1309 assert_cc(sizeof(uid_t) == sizeof(gid_t));
1310
1311 assert(machine);
1312 assert(uid_is_valid(uid));
1313
1314 if (machine->class != MACHINE_CONTAINER)
1315 return -ESRCH;
1316
1317 /* Translates a machine UID into a host UID */
1318
1319 p = procfs_file_alloca(machine->leader.pid, map_file);
1320 f = fopen(p, "re");
1321 if (!f)
1322 return -errno;
1323
1324 for (;;) {
1325 uid_t uid_base, uid_shift, uid_range, converted;
1326
1327 r = uid_map_read_one(f, &uid_base, &uid_shift, &uid_range);
1328 if (r == -ENOMSG)
1329 break;
1330 if (r < 0)
1331 return r;
1332
1333 if (uid < uid_base || uid >= uid_base + uid_range)
1334 continue;
1335
1336 converted = uid - uid_base + uid_shift;
1337 if (!uid_is_valid(converted))
1338 return -EINVAL;
1339
1340 r = pidref_verify(&machine->leader);
1341 if (r < 0)
1342 return r;
1343
1344 if (ret_host_uid)
1345 *ret_host_uid = converted;
1346
1347 return 0;
1348 }
1349
1350 return -ESRCH;
1351 }
1352
1353 int machine_translate_uid(Machine *machine, gid_t uid, gid_t *ret_host_uid) {
1354 return machine_translate_uid_internal(machine, "uid_map", uid, ret_host_uid);
1355 }
1356
1357 int machine_translate_gid(Machine *machine, gid_t gid, gid_t *ret_host_gid) {
1358 return machine_translate_uid_internal(machine, "gid_map", (uid_t) gid, (uid_t*) ret_host_gid);
1359 }
1360
1361 int machine_open_root_directory(Machine *machine) {
1362 int r;
1363
1364 assert(machine);
1365
1366 switch (machine->class) {
1367 case MACHINE_HOST: {
1368 int fd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1369 if (fd < 0)
1370 return log_debug_errno(errno, "Failed to open host root directory: %m");
1371
1372 return fd;
1373 }
1374
1375 case MACHINE_CONTAINER: {
1376 _cleanup_close_ int mntns_fd = -EBADF, root_fd = -EBADF;
1377 _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR, fd_pass_socket[2] = EBADF_PAIR;
1378 pid_t child;
1379
1380 r = pidref_namespace_open(&machine->leader,
1381 /* ret_pidns_fd = */ NULL,
1382 &mntns_fd,
1383 /* ret_netns_fd = */ NULL,
1384 /* ret_userns_fd = */ NULL,
1385 &root_fd);
1386 if (r < 0)
1387 return log_debug_errno(r, "Failed to open mount namespace of machine '%s': %m", machine->name);
1388
1389 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
1390 return log_debug_errno(errno, "Failed to open pipe: %m");
1391
1392 if (socketpair(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0, fd_pass_socket) < 0)
1393 return log_debug_errno(errno, "Failed to create socket pair: %m");
1394
1395 r = namespace_fork(
1396 "(sd-openrootns)",
1397 "(sd-openroot)",
1398 /* except_fds = */ NULL,
1399 /* n_except_fds = */ 0,
1400 FORK_RESET_SIGNALS|FORK_DEATHSIG_SIGKILL,
1401 /* pidns_fd = */ -EBADF,
1402 mntns_fd,
1403 /* netns_fd = */ -EBADF,
1404 /* userns_fd = */ -EBADF,
1405 root_fd,
1406 &child);
1407 if (r < 0)
1408 return log_debug_errno(r, "Failed to fork into mount namespace of machine '%s': %m", machine->name);
1409 if (r == 0) {
1410 _cleanup_close_ int dfd = -EBADF;
1411
1412 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1413 fd_pass_socket[0] = safe_close(fd_pass_socket[0]);
1414
1415 dfd = open("/", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
1416 if (dfd < 0) {
1417 log_debug_errno(errno, "Failed to open root directory of machine '%s': %m", machine->name);
1418 report_errno_and_exit(errno_pipe_fd[1], -errno);
1419 }
1420
1421 r = send_one_fd(fd_pass_socket[1], dfd, /* flags = */ 0);
1422 dfd = safe_close(dfd);
1423 if (r < 0) {
1424 log_debug_errno(r, "Failed to send FD over socket: %m");
1425 report_errno_and_exit(errno_pipe_fd[1], r);
1426 }
1427
1428 _exit(EXIT_SUCCESS);
1429 }
1430
1431 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
1432 fd_pass_socket[1] = safe_close(fd_pass_socket[1]);
1433
1434 r = wait_for_terminate_and_check("(sd-openrootns)", child, /* flags = */ 0);
1435 if (r < 0)
1436 return log_debug_errno(r, "Failed to wait for child: %m");
1437
1438 r = read_errno(errno_pipe_fd[0]); /* the function does debug reporting */
1439 if (r < 0)
1440 return r;
1441
1442 int fd = receive_one_fd(fd_pass_socket[0], MSG_DONTWAIT);
1443 if (fd < 0)
1444 return log_debug_errno(fd, "Failed to receive FD from child: %m");
1445
1446 return fd;
1447 }
1448
1449 default:
1450 return -EOPNOTSUPP;
1451 }
1452 }
1453
1454 static const char* const machine_class_table[_MACHINE_CLASS_MAX] = {
1455 [MACHINE_CONTAINER] = "container",
1456 [MACHINE_VM] = "vm",
1457 [MACHINE_HOST] = "host",
1458 };
1459
1460 DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass);
1461
1462 static const char* const machine_state_table[_MACHINE_STATE_MAX] = {
1463 [MACHINE_OPENING] = "opening",
1464 [MACHINE_RUNNING] = "running",
1465 [MACHINE_CLOSING] = "closing"
1466 };
1467
1468 DEFINE_STRING_TABLE_LOOKUP(machine_state, MachineState);
1469
1470 static const char* const kill_whom_table[_KILL_WHOM_MAX] = {
1471 [KILL_LEADER] = "leader",
1472 [KILL_ALL] = "all"
1473 };
1474
1475 DEFINE_STRING_TABLE_LOOKUP(kill_whom, KillWhom);
1476
1477 static const char* const acquire_metadata_table[_ACQUIRE_METADATA_MAX] = {
1478 [ACQUIRE_METADATA_NO] = "no",
1479 [ACQUIRE_METADATA_YES] = "yes",
1480 [ACQUIRE_METADATA_GRACEFUL] = "graceful"
1481 };
1482
1483 DEFINE_STRING_TABLE_LOOKUP_WITH_BOOLEAN(acquire_metadata, AcquireMetadata, ACQUIRE_METADATA_YES);