2 This file is part of systemd.
4 Copyright 2011 Lennart Poettering
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.
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.
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/>.
22 #include <sys/mount.h>
25 /* When we include libgen.h because we need dirname() we immediately
26 * undefine basename() since libgen.h defines it as a macro to the POSIX
27 * version which is really broken. We prefer GNU basename(). */
31 #include "alloc-util.h"
32 #include "bus-common-errors.h"
33 #include "bus-internal.h"
34 #include "bus-label.h"
40 #include "formats-util.h"
42 #include "in-addr-util.h"
43 #include "local-addresses.h"
44 #include "machine-dbus.h"
47 #include "path-util.h"
48 #include "process-util.h"
49 #include "signal-util.h"
51 #include "terminal-util.h"
52 #include "user-util.h"
54 static int property_get_id(
57 const char *interface
,
59 sd_bus_message
*reply
,
61 sd_bus_error
*error
) {
63 Machine
*m
= userdata
;
69 return sd_bus_message_append_array(reply
, 'y', &m
->id
, 16);
72 static int property_get_state(
75 const char *interface
,
77 sd_bus_message
*reply
,
79 sd_bus_error
*error
) {
81 Machine
*m
= userdata
;
89 state
= machine_state_to_string(machine_get_state(m
));
91 r
= sd_bus_message_append_basic(reply
, 's', state
);
98 static int property_get_netif(
101 const char *interface
,
102 const char *property
,
103 sd_bus_message
*reply
,
105 sd_bus_error
*error
) {
107 Machine
*m
= userdata
;
113 assert_cc(sizeof(int) == sizeof(int32_t));
115 return sd_bus_message_append_array(reply
, 'i', m
->netif
, m
->n_netif
* sizeof(int));
118 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class
, machine_class
, MachineClass
);
120 int bus_machine_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
121 Machine
*m
= userdata
;
127 r
= bus_verify_polkit_async(
130 "org.freedesktop.machine1.manage-machines",
134 &m
->manager
->polkit_registry
,
139 return 1; /* Will call us back */
145 return sd_bus_reply_method_return(message
, NULL
);
148 int bus_machine_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
149 Machine
*m
= userdata
;
158 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
165 who
= kill_who_from_string(swho
);
167 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
170 if (!SIGNAL_VALID(signo
))
171 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
173 r
= bus_verify_polkit_async(
176 "org.freedesktop.machine1.manage-machines",
180 &m
->manager
->polkit_registry
,
185 return 1; /* Will call us back */
187 r
= machine_kill(m
, who
, signo
);
191 return sd_bus_reply_method_return(message
, NULL
);
194 int bus_machine_method_get_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
195 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
196 Machine
*m
= userdata
;
202 r
= sd_bus_message_new_method_return(message
, &reply
);
206 r
= sd_bus_message_open_container(reply
, 'a', "(iay)");
213 _cleanup_free_
struct local_address
*addresses
= NULL
;
214 struct local_address
*a
;
217 n
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
221 for (a
= addresses
, i
= 0; i
< n
; a
++, i
++) {
223 r
= sd_bus_message_open_container(reply
, 'r', "iay");
227 r
= sd_bus_message_append(reply
, "i", addresses
[i
].family
);
231 r
= sd_bus_message_append_array(reply
, 'y', &addresses
[i
].address
, FAMILY_ADDRESS_SIZE(addresses
[i
].family
));
235 r
= sd_bus_message_close_container(reply
);
243 case MACHINE_CONTAINER
: {
244 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
245 _cleanup_free_
char *us
= NULL
, *them
= NULL
;
246 _cleanup_close_
int netns_fd
= -1;
251 r
= readlink_malloc("/proc/self/ns/net", &us
);
255 p
= procfs_file_alloca(m
->leader
, "ns/net");
256 r
= readlink_malloc(p
, &them
);
261 return sd_bus_error_setf(error
, BUS_ERROR_NO_PRIVATE_NETWORKING
, "Machine %s does not use private networking", m
->name
);
263 r
= namespace_open(m
->leader
, NULL
, NULL
, &netns_fd
, NULL
, NULL
);
267 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
272 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
275 _cleanup_free_
struct local_address
*addresses
= NULL
;
276 struct local_address
*a
;
279 pair
[0] = safe_close(pair
[0]);
281 r
= namespace_enter(-1, -1, netns_fd
, -1, -1);
285 n
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
289 for (a
= addresses
, i
= 0; i
< n
; a
++, i
++) {
290 struct iovec iov
[2] = {
291 { .iov_base
= &a
->family
, .iov_len
= sizeof(a
->family
) },
292 { .iov_base
= &a
->address
, .iov_len
= FAMILY_ADDRESS_SIZE(a
->family
) },
295 r
= writev(pair
[1], iov
, 2);
300 pair
[1] = safe_close(pair
[1]);
305 pair
[1] = safe_close(pair
[1]);
310 union in_addr_union in_addr
;
317 iov
[0] = (struct iovec
) { .iov_base
= &family
, .iov_len
= sizeof(family
) };
318 iov
[1] = (struct iovec
) { .iov_base
= &in_addr
, .iov_len
= sizeof(in_addr
) };
320 n
= recvmsg(pair
[0], &mh
, 0);
323 if ((size_t) n
< sizeof(family
))
326 r
= sd_bus_message_open_container(reply
, 'r', "iay");
330 r
= sd_bus_message_append(reply
, "i", family
);
337 if (n
!= sizeof(struct in_addr
) + sizeof(family
))
340 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in
, sizeof(in_addr
.in
));
344 if (n
!= sizeof(struct in6_addr
) + sizeof(family
))
347 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in6
, sizeof(in_addr
.in6
));
353 r
= sd_bus_message_close_container(reply
);
358 r
= wait_for_terminate(child
, &si
);
360 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
361 if (si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
362 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
367 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting IP address data is only supported on container machines.");
370 r
= sd_bus_message_close_container(reply
);
374 return sd_bus_send(NULL
, reply
, NULL
);
377 int bus_machine_method_get_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
378 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
379 _cleanup_strv_free_
char **l
= NULL
;
380 Machine
*m
= userdata
;
390 r
= load_env_file_pairs(NULL
, "/etc/os-release", NULL
, &l
);
396 case MACHINE_CONTAINER
: {
397 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
398 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
399 _cleanup_fclose_
FILE *f
= NULL
;
403 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
407 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
412 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
415 _cleanup_close_
int fd
= -1;
417 pair
[0] = safe_close(pair
[0]);
419 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
423 fd
= open("/etc/os-release", O_RDONLY
|O_CLOEXEC
);
425 fd
= open("/usr/lib/os-release", O_RDONLY
|O_CLOEXEC
);
430 r
= copy_bytes(fd
, pair
[1], (uint64_t) -1, false);
437 pair
[1] = safe_close(pair
[1]);
439 f
= fdopen(pair
[0], "re");
445 r
= load_env_file_pairs(f
, "/etc/os-release", NULL
, &l
);
449 r
= wait_for_terminate(child
, &si
);
451 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
452 if (si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
453 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
459 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting OS release data is only supported on container machines.");
462 r
= sd_bus_message_new_method_return(message
, &reply
);
466 r
= sd_bus_message_open_container(reply
, 'a', "{ss}");
470 STRV_FOREACH_PAIR(k
, v
, l
) {
471 r
= sd_bus_message_append(reply
, "{ss}", *k
, *v
);
476 r
= sd_bus_message_close_container(reply
);
480 return sd_bus_send(NULL
, reply
, NULL
);
483 int bus_machine_method_open_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
484 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
485 _cleanup_free_
char *pty_name
= NULL
;
486 _cleanup_close_
int master
= -1;
487 Machine
*m
= userdata
;
493 r
= bus_verify_polkit_async(
496 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-open-pty" : "org.freedesktop.machine1.open-pty",
500 &m
->manager
->polkit_registry
,
505 return 1; /* Will call us back */
507 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
511 r
= ptsname_namespace(master
, &pty_name
);
515 r
= sd_bus_message_new_method_return(message
, &reply
);
519 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
523 return sd_bus_send(NULL
, reply
, NULL
);
526 static int container_bus_new(Machine
*m
, sd_bus_error
*error
, sd_bus
**ret
) {
538 case MACHINE_CONTAINER
: {
539 _cleanup_(sd_bus_unrefp
) sd_bus
*bus
= NULL
;
542 r
= sd_bus_new(&bus
);
546 if (asprintf(&address
, "x-machine-kernel:pid=%1$" PID_PRI
";x-machine-unix:pid=%1$" PID_PRI
, m
->leader
) < 0)
549 bus
->address
= address
;
550 bus
->bus_client
= true;
551 bus
->trusted
= false;
552 bus
->is_system
= true;
554 r
= sd_bus_start(bus
);
556 return sd_bus_error_set_errnof(error
, r
, "There is no system bus in container %s.", m
->name
);
572 int bus_machine_method_open_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
573 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
574 _cleanup_free_
char *pty_name
= NULL
;
575 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
576 _cleanup_close_
int master
= -1;
577 sd_bus
*container_bus
= NULL
;
578 Machine
*m
= userdata
;
579 const char *p
, *getty
;
585 r
= bus_verify_polkit_async(
588 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-login" : "org.freedesktop.machine1.login",
592 &m
->manager
->polkit_registry
,
597 return 1; /* Will call us back */
599 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
603 r
= ptsname_namespace(master
, &pty_name
);
607 p
= path_startswith(pty_name
, "/dev/pts/");
609 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "PTS name %s is invalid", pty_name
);
611 r
= container_bus_new(m
, error
, &allocated_bus
);
615 container_bus
= allocated_bus
?: m
->manager
->bus
;
617 getty
= strjoina("container-getty@", p
, ".service");
619 r
= sd_bus_call_method(
621 "org.freedesktop.systemd1",
622 "/org/freedesktop/systemd1",
623 "org.freedesktop.systemd1.Manager",
626 "ss", getty
, "replace");
630 r
= sd_bus_message_new_method_return(message
, &reply
);
634 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
638 return sd_bus_send(NULL
, reply
, NULL
);
641 int bus_machine_method_open_shell(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
642 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
, *tm
= NULL
;
643 _cleanup_free_
char *pty_name
= NULL
;
644 _cleanup_(sd_bus_flush_close_unrefp
) sd_bus
*allocated_bus
= NULL
;
645 sd_bus
*container_bus
= NULL
;
646 _cleanup_close_
int master
= -1, slave
= -1;
647 _cleanup_strv_free_
char **env
= NULL
, **args
= NULL
;
648 Machine
*m
= userdata
;
649 const char *p
, *unit
, *user
, *path
, *description
, *utmp_id
;
655 r
= sd_bus_message_read(message
, "ss", &user
, &path
);
658 user
= empty_to_null(user
);
661 if (!path_is_absolute(path
))
662 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Specified path '%s' is not absolute", path
);
664 r
= sd_bus_message_read_strv(message
, &args
);
667 if (strv_isempty(args
)) {
668 args
= strv_free(args
);
670 args
= strv_new(path
, NULL
);
674 args
[0][0] = '-'; /* Tell /bin/sh that this shall be a login shell */
677 r
= sd_bus_message_read_strv(message
, &env
);
680 if (!strv_env_is_valid(env
))
681 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid environment assignments");
683 r
= bus_verify_polkit_async(
686 m
->class == MACHINE_HOST
? "org.freedesktop.machine1.host-shell" : "org.freedesktop.machine1.shell",
690 &m
->manager
->polkit_registry
,
695 return 1; /* Will call us back */
697 master
= machine_openpt(m
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
701 r
= ptsname_namespace(master
, &pty_name
);
705 p
= path_startswith(pty_name
, "/dev/pts/");
708 slave
= machine_open_terminal(m
, pty_name
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
712 utmp_id
= path_startswith(pty_name
, "/dev/");
715 r
= container_bus_new(m
, error
, &allocated_bus
);
719 container_bus
= allocated_bus
?: m
->manager
->bus
;
721 r
= sd_bus_message_new_method_call(
724 "org.freedesktop.systemd1",
725 "/org/freedesktop/systemd1",
726 "org.freedesktop.systemd1.Manager",
727 "StartTransientUnit");
732 unit
= strjoina("container-shell@", p
, ".service");
733 r
= sd_bus_message_append(tm
, "ss", unit
, "fail");
738 r
= sd_bus_message_open_container(tm
, 'a', "(sv)");
742 description
= strjoina("Shell for User ", isempty(user
) ? "root" : user
);
743 r
= sd_bus_message_append(tm
,
744 "(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)(sv)",
745 "Description", "s", description
,
746 "StandardInputFileDescriptor", "h", slave
,
747 "StandardOutputFileDescriptor", "h", slave
,
748 "StandardErrorFileDescriptor", "h", slave
,
749 "SendSIGHUP", "b", true,
750 "IgnoreSIGPIPE", "b", false,
751 "KillMode", "s", "mixed",
752 "TTYReset", "b", true,
753 "UtmpIdentifier", "s", utmp_id
,
754 "UtmpMode", "s", "user",
755 "PAMName", "s", "login",
756 "WorkingDirectory", "s", "-~");
760 r
= sd_bus_message_append(tm
, "(sv)", "User", "s", isempty(user
) ? "root" : user
);
764 if (!strv_isempty(env
)) {
765 r
= sd_bus_message_open_container(tm
, 'r', "sv");
769 r
= sd_bus_message_append(tm
, "s", "Environment");
773 r
= sd_bus_message_open_container(tm
, 'v', "as");
777 r
= sd_bus_message_append_strv(tm
, env
);
781 r
= sd_bus_message_close_container(tm
);
785 r
= sd_bus_message_close_container(tm
);
791 r
= sd_bus_message_open_container(tm
, 'r', "sv");
795 r
= sd_bus_message_append(tm
, "s", "ExecStart");
799 r
= sd_bus_message_open_container(tm
, 'v', "a(sasb)");
803 r
= sd_bus_message_open_container(tm
, 'a', "(sasb)");
807 r
= sd_bus_message_open_container(tm
, 'r', "sasb");
811 r
= sd_bus_message_append(tm
, "s", path
);
815 r
= sd_bus_message_append_strv(tm
, args
);
819 r
= sd_bus_message_append(tm
, "b", true);
823 r
= sd_bus_message_close_container(tm
);
827 r
= sd_bus_message_close_container(tm
);
831 r
= sd_bus_message_close_container(tm
);
835 r
= sd_bus_message_close_container(tm
);
839 r
= sd_bus_message_close_container(tm
);
843 /* Auxiliary units */
844 r
= sd_bus_message_append(tm
, "a(sa(sv))", 0);
848 r
= sd_bus_call(container_bus
, tm
, 0, error
, NULL
);
852 slave
= safe_close(slave
);
854 r
= sd_bus_message_new_method_return(message
, &reply
);
858 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
862 return sd_bus_send(NULL
, reply
, NULL
);
865 int bus_machine_method_bind_mount(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
866 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
867 char mount_slave
[] = "/tmp/propagate.XXXXXX", *mount_tmp
, *mount_outside
, *p
;
868 bool mount_slave_created
= false, mount_slave_mounted
= false,
869 mount_tmp_created
= false, mount_tmp_mounted
= false,
870 mount_outside_created
= false, mount_outside_mounted
= false;
871 const char *dest
, *src
;
872 Machine
*m
= userdata
;
873 int read_only
, make_directory
;
881 if (m
->class != MACHINE_CONTAINER
)
882 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Bind mounting is only supported on container machines.");
884 r
= sd_bus_message_read(message
, "ssbb", &src
, &dest
, &read_only
, &make_directory
);
888 if (!path_is_absolute(src
) || !path_is_safe(src
))
889 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
893 else if (!path_is_absolute(dest
) || !path_is_safe(dest
))
894 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
896 r
= bus_verify_polkit_async(
899 "org.freedesktop.machine1.manage-machines",
903 &m
->manager
->polkit_registry
,
908 return 1; /* Will call us back */
910 /* One day, when bind mounting /proc/self/fd/n works across
911 * namespace boundaries we should rework this logic to make
914 p
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/");
915 if (laccess(p
, F_OK
) < 0)
916 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Container does not allow propagation of mount points.");
918 /* Our goal is to install a new bind mount into the container,
919 possibly read-only. This is irritatingly complex
920 unfortunately, currently.
922 First, we start by creating a private playground in /tmp,
923 that we can mount MS_SLAVE. (Which is necessary, since
924 MS_MOVE cannot be applied to mounts with MS_SHARED parent
927 if (!mkdtemp(mount_slave
))
928 return sd_bus_error_set_errnof(error
, errno
, "Failed to create playground %s: %m", mount_slave
);
930 mount_slave_created
= true;
932 if (mount(mount_slave
, mount_slave
, NULL
, MS_BIND
, NULL
) < 0) {
933 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to make bind mount %s: %m", mount_slave
);
937 mount_slave_mounted
= true;
939 if (mount(NULL
, mount_slave
, NULL
, MS_SLAVE
, NULL
) < 0) {
940 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount slave %s: %m", mount_slave
);
944 /* Second, we mount the source directory to a directory inside
945 of our MS_SLAVE playground. */
946 mount_tmp
= strjoina(mount_slave
, "/mount");
947 if (mkdir(mount_tmp
, 0700) < 0) {
948 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create temporary mount point %s: %m", mount_tmp
);
952 mount_tmp_created
= true;
954 if (mount(src
, mount_tmp
, NULL
, MS_BIND
, NULL
) < 0) {
955 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to overmount %s: %m", mount_tmp
);
959 mount_tmp_mounted
= true;
961 /* Third, we remount the new bind mount read-only if requested. */
963 if (mount(NULL
, mount_tmp
, NULL
, MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
) < 0) {
964 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount read-only %s: %m", mount_tmp
);
968 /* Fourth, we move the new bind mount into the propagation
969 * directory. This way it will appear there read-only
972 mount_outside
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/XXXXXX");
973 if (!mkdtemp(mount_outside
)) {
974 r
= sd_bus_error_set_errnof(error
, errno
, "Cannot create propagation directory %s: %m", mount_outside
);
978 mount_outside_created
= true;
980 if (mount(mount_tmp
, mount_outside
, NULL
, MS_MOVE
, NULL
) < 0) {
981 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to move %s to %s: %m", mount_tmp
, mount_outside
);
985 mount_outside_mounted
= true;
986 mount_tmp_mounted
= false;
988 (void) rmdir(mount_tmp
);
989 mount_tmp_created
= false;
991 (void) umount(mount_slave
);
992 mount_slave_mounted
= false;
994 (void) rmdir(mount_slave
);
995 mount_slave_created
= false;
997 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0) {
998 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1004 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
1009 const char *mount_inside
;
1013 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1015 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1016 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1018 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1022 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1023 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1028 (void) mkdir_p(dest
, 0755);
1030 /* Fifth, move the mount to the right place inside */
1031 mount_inside
= strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside
));
1032 if (mount(mount_inside
, dest
, NULL
, MS_MOVE
, NULL
) < 0) {
1033 r
= log_error_errno(errno
, "Failed to mount: %m");
1037 _exit(EXIT_SUCCESS
);
1040 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1041 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1043 _exit(EXIT_FAILURE
);
1046 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1048 r
= wait_for_terminate(child
, &si
);
1050 r
= sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1053 if (si
.si_code
!= CLD_EXITED
) {
1054 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
1057 if (si
.si_status
!= EXIT_SUCCESS
) {
1059 if (read(errno_pipe_fd
[0], &r
, sizeof(r
)) == sizeof(r
))
1060 r
= sd_bus_error_set_errnof(error
, r
, "Failed to mount: %m");
1062 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child failed.");
1066 r
= sd_bus_reply_method_return(message
, NULL
);
1069 if (mount_outside_mounted
)
1070 umount(mount_outside
);
1071 if (mount_outside_created
)
1072 rmdir(mount_outside
);
1074 if (mount_tmp_mounted
)
1076 if (mount_tmp_created
)
1079 if (mount_slave_mounted
)
1080 umount(mount_slave
);
1081 if (mount_slave_created
)
1087 int bus_machine_method_copy(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1088 const char *src
, *dest
, *host_path
, *container_path
, *host_basename
, *host_dirname
, *container_basename
, *container_dirname
;
1089 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
1090 _cleanup_close_
int hostfd
= -1;
1091 Machine
*m
= userdata
;
1100 if (m
->manager
->n_operations
>= OPERATIONS_MAX
)
1101 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing copies.");
1103 if (m
->class != MACHINE_CONTAINER
)
1104 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Copying files is only supported on container machines.");
1106 r
= sd_bus_message_read(message
, "ss", &src
, &dest
);
1110 if (!path_is_absolute(src
))
1111 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute.");
1115 else if (!path_is_absolute(dest
))
1116 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute.");
1118 r
= bus_verify_polkit_async(
1121 "org.freedesktop.machine1.manage-machines",
1125 &m
->manager
->polkit_registry
,
1130 return 1; /* Will call us back */
1132 copy_from
= strstr(sd_bus_message_get_member(message
), "CopyFrom");
1135 container_path
= src
;
1139 container_path
= dest
;
1142 host_basename
= basename(host_path
);
1143 t
= strdupa(host_path
);
1144 host_dirname
= dirname(t
);
1146 container_basename
= basename(container_path
);
1147 t
= strdupa(container_path
);
1148 container_dirname
= dirname(t
);
1150 hostfd
= open(host_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1152 return sd_bus_error_set_errnof(error
, errno
, "Failed to open host directory %s: %m", host_dirname
);
1154 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
1155 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
1159 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
1166 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
1168 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
1169 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
1171 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
1175 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
1176 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
1180 containerfd
= open(container_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
1181 if (containerfd
< 0) {
1182 r
= log_error_errno(errno
, "Failed top open destination directory: %m");
1187 r
= copy_tree_at(containerfd
, container_basename
, hostfd
, host_basename
, true);
1189 r
= copy_tree_at(hostfd
, host_basename
, containerfd
, container_basename
, true);
1191 hostfd
= safe_close(hostfd
);
1192 containerfd
= safe_close(containerfd
);
1195 r
= log_error_errno(r
, "Failed to copy tree: %m");
1199 _exit(EXIT_SUCCESS
);
1202 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
1203 _exit(EXIT_FAILURE
);
1206 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
1208 /* Copying might take a while, hence install a watch on the child, and return */
1210 r
= operation_new(m
->manager
, m
, child
, message
, errno_pipe_fd
[0], NULL
);
1212 (void) sigkill_wait(child
);
1215 errno_pipe_fd
[0] = -1;
1220 int bus_machine_method_open_root_directory(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
1221 _cleanup_close_
int fd
= -1;
1222 Machine
*m
= userdata
;
1228 r
= bus_verify_polkit_async(
1231 "org.freedesktop.machine1.manage-machines",
1235 &m
->manager
->polkit_registry
,
1240 return 1; /* Will call us back */
1245 fd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1251 case MACHINE_CONTAINER
: {
1252 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
1253 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1257 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, NULL
, &root_fd
);
1261 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1266 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
1269 _cleanup_close_
int dfd
= -1;
1271 pair
[0] = safe_close(pair
[0]);
1273 r
= namespace_enter(-1, mntns_fd
, -1, -1, root_fd
);
1275 _exit(EXIT_FAILURE
);
1277 dfd
= open("/", O_RDONLY
|O_CLOEXEC
|O_DIRECTORY
);
1279 _exit(EXIT_FAILURE
);
1281 r
= send_one_fd(pair
[1], dfd
, 0);
1282 dfd
= safe_close(dfd
);
1284 _exit(EXIT_FAILURE
);
1286 _exit(EXIT_SUCCESS
);
1289 pair
[1] = safe_close(pair
[1]);
1291 r
= wait_for_terminate(child
, &si
);
1293 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for child: %m");
1294 if (si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1295 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Child died abnormally.");
1297 fd
= receive_one_fd(pair
[0], MSG_DONTWAIT
);
1305 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening the root directory is only supported on container machines.");
1308 return sd_bus_reply_method_return(message
, "h", fd
);
1311 const sd_bus_vtable machine_vtable
[] = {
1312 SD_BUS_VTABLE_START(0),
1313 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Machine
, name
), SD_BUS_VTABLE_PROPERTY_CONST
),
1314 SD_BUS_PROPERTY("Id", "ay", property_get_id
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1315 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
1316 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Machine
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
1317 SD_BUS_PROPERTY("Unit", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
),
1318 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
1319 SD_BUS_PROPERTY("Leader", "u", NULL
, offsetof(Machine
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
1320 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Machine
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
1321 SD_BUS_PROPERTY("RootDirectory", "s", NULL
, offsetof(Machine
, root_directory
), SD_BUS_VTABLE_PROPERTY_CONST
),
1322 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
1323 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
1324 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_machine_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
1325 SD_BUS_METHOD("Kill", "si", NULL
, bus_machine_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
1326 SD_BUS_METHOD("GetAddresses", NULL
, "a(iay)", bus_machine_method_get_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
1327 SD_BUS_METHOD("GetOSRelease", NULL
, "a{ss}", bus_machine_method_get_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
1328 SD_BUS_METHOD("OpenPTY", NULL
, "hs", bus_machine_method_open_pty
, SD_BUS_VTABLE_UNPRIVILEGED
),
1329 SD_BUS_METHOD("OpenLogin", NULL
, "hs", bus_machine_method_open_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
1330 SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell
, SD_BUS_VTABLE_UNPRIVILEGED
),
1331 SD_BUS_METHOD("BindMount", "ssbb", NULL
, bus_machine_method_bind_mount
, SD_BUS_VTABLE_UNPRIVILEGED
),
1332 SD_BUS_METHOD("CopyFrom", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1333 SD_BUS_METHOD("CopyTo", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
1334 SD_BUS_METHOD("OpenRootDirectory", NULL
, "h", bus_machine_method_open_root_directory
, SD_BUS_VTABLE_UNPRIVILEGED
),
1338 int machine_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
1339 Manager
*m
= userdata
;
1349 if (streq(path
, "/org/freedesktop/machine1/machine/self")) {
1350 _cleanup_(sd_bus_creds_unrefp
) sd_bus_creds
*creds
= NULL
;
1351 sd_bus_message
*message
;
1354 message
= sd_bus_get_current_message(bus
);
1358 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
1362 r
= sd_bus_creds_get_pid(creds
, &pid
);
1366 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
1370 _cleanup_free_
char *e
= NULL
;
1373 p
= startswith(path
, "/org/freedesktop/machine1/machine/");
1377 e
= bus_label_unescape(p
);
1381 machine
= hashmap_get(m
->machines
, e
);
1390 char *machine_bus_path(Machine
*m
) {
1391 _cleanup_free_
char *e
= NULL
;
1395 e
= bus_label_escape(m
->name
);
1399 return strappend("/org/freedesktop/machine1/machine/", e
);
1402 int machine_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1403 _cleanup_strv_free_
char **l
= NULL
;
1404 Machine
*machine
= NULL
;
1405 Manager
*m
= userdata
;
1413 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1416 p
= machine_bus_path(machine
);
1420 r
= strv_consume(&l
, p
);
1431 int machine_send_signal(Machine
*m
, bool new_machine
) {
1432 _cleanup_free_
char *p
= NULL
;
1436 p
= machine_bus_path(m
);
1440 return sd_bus_emit_signal(
1442 "/org/freedesktop/machine1",
1443 "org.freedesktop.machine1.Manager",
1444 new_machine
? "MachineNew" : "MachineRemoved",
1448 int machine_send_create_reply(Machine
*m
, sd_bus_error
*error
) {
1449 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*c
= NULL
;
1450 _cleanup_free_
char *p
= NULL
;
1454 if (!m
->create_message
)
1457 c
= m
->create_message
;
1458 m
->create_message
= NULL
;
1461 return sd_bus_reply_method_error(c
, error
);
1463 /* Update the machine state file before we notify the client
1464 * about the result. */
1467 p
= machine_bus_path(m
);
1471 return sd_bus_reply_method_return(c
, "o", p
);