1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
24 #include <sys/mount.h>
26 /* When we include libgen.h because we need dirname() we immediately
27 * undefine basename() since libgen.h defines it as a macro to the POSIX
28 * version which is really broken. We prefer GNU basename(). */
33 #include "bus-label.h"
35 #include "bus-common-errors.h"
38 #include "in-addr-util.h"
39 #include "local-addresses.h"
40 #include "path-util.h"
42 #include "bus-internal.h"
44 #include "machine-dbus.h"
45 #include "formats-util.h"
46 #include "process-util.h"
48 static int property_get_id(
51 const char *interface
,
53 sd_bus_message
*reply
,
55 sd_bus_error
*error
) {
57 Machine
*m
= userdata
;
64 r
= sd_bus_message_append_array(reply
, 'y', &m
->id
, 16);
71 static int property_get_state(
74 const char *interface
,
76 sd_bus_message
*reply
,
78 sd_bus_error
*error
) {
80 Machine
*m
= userdata
;
88 state
= machine_state_to_string(machine_get_state(m
));
90 r
= sd_bus_message_append_basic(reply
, 's', state
);
97 static int property_get_netif(
100 const char *interface
,
101 const char *property
,
102 sd_bus_message
*reply
,
104 sd_bus_error
*error
) {
106 Machine
*m
= userdata
;
113 assert_cc(sizeof(int) == sizeof(int32_t));
115 r
= sd_bus_message_append_array(reply
, 'i', m
->netif
, m
->n_netif
* sizeof(int));
122 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class
, machine_class
, MachineClass
);
124 int bus_machine_method_terminate(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
125 Machine
*m
= userdata
;
131 r
= bus_verify_polkit_async(
134 "org.freedesktop.machine1.manage-machines",
137 &m
->manager
->polkit_registry
,
142 return 1; /* Will call us back */
148 return sd_bus_reply_method_return(message
, NULL
);
151 int bus_machine_method_kill(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
152 Machine
*m
= userdata
;
161 r
= sd_bus_message_read(message
, "si", &swho
, &signo
);
168 who
= kill_who_from_string(swho
);
170 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid kill parameter '%s'", swho
);
173 if (signo
<= 0 || signo
>= _NSIG
)
174 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Invalid signal %i", signo
);
176 r
= bus_verify_polkit_async(
179 "org.freedesktop.machine1.manage-machines",
182 &m
->manager
->polkit_registry
,
187 return 1; /* Will call us back */
189 r
= machine_kill(m
, who
, signo
);
193 return sd_bus_reply_method_return(message
, NULL
);
196 int bus_machine_method_get_addresses(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
197 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
198 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
199 _cleanup_free_
char *us
= NULL
, *them
= NULL
;
200 _cleanup_close_
int netns_fd
= -1;
201 Machine
*m
= userdata
;
210 if (m
->class != MACHINE_CONTAINER
)
211 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting IP address data is only supported on container machines.");
213 r
= readlink_malloc("/proc/self/ns/net", &us
);
217 p
= procfs_file_alloca(m
->leader
, "ns/net");
218 r
= readlink_malloc(p
, &them
);
223 return sd_bus_error_setf(error
, BUS_ERROR_NO_PRIVATE_NETWORKING
, "Machine %s does not use private networking", m
->name
);
225 r
= namespace_open(m
->leader
, NULL
, NULL
, &netns_fd
, NULL
);
229 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
234 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
237 _cleanup_free_
struct local_address
*addresses
= NULL
;
238 struct local_address
*a
;
241 pair
[0] = safe_close(pair
[0]);
243 r
= namespace_enter(-1, -1, netns_fd
, -1);
247 n
= local_addresses(NULL
, 0, AF_UNSPEC
, &addresses
);
251 for (a
= addresses
, i
= 0; i
< n
; a
++, i
++) {
252 struct iovec iov
[2] = {
253 { .iov_base
= &a
->family
, .iov_len
= sizeof(a
->family
) },
254 { .iov_base
= &a
->address
, .iov_len
= FAMILY_ADDRESS_SIZE(a
->family
) },
257 r
= writev(pair
[1], iov
, 2);
262 pair
[1] = safe_close(pair
[1]);
267 pair
[1] = safe_close(pair
[1]);
269 r
= sd_bus_message_new_method_return(message
, &reply
);
273 r
= sd_bus_message_open_container(reply
, 'a', "(iay)");
280 union in_addr_union in_addr
;
287 iov
[0] = (struct iovec
) { .iov_base
= &family
, .iov_len
= sizeof(family
) };
288 iov
[1] = (struct iovec
) { .iov_base
= &in_addr
, .iov_len
= sizeof(in_addr
) };
290 n
= recvmsg(pair
[0], &mh
, 0);
293 if ((size_t) n
< sizeof(family
))
296 r
= sd_bus_message_open_container(reply
, 'r', "iay");
300 r
= sd_bus_message_append(reply
, "i", family
);
307 if (n
!= sizeof(struct in_addr
) + sizeof(family
))
310 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in
, sizeof(in_addr
.in
));
314 if (n
!= sizeof(struct in6_addr
) + sizeof(family
))
317 r
= sd_bus_message_append_array(reply
, 'y', &in_addr
.in6
, sizeof(in_addr
.in6
));
323 r
= sd_bus_message_close_container(reply
);
328 r
= wait_for_terminate(child
, &si
);
330 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for client: %m");
331 if (si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
332 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Client died abnormally.");
334 r
= sd_bus_message_close_container(reply
);
338 return sd_bus_send(NULL
, reply
, NULL
);
341 int bus_machine_method_get_os_release(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
342 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
343 _cleanup_close_
int mntns_fd
= -1, root_fd
= -1;
344 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
345 _cleanup_strv_free_
char **l
= NULL
;
346 _cleanup_fclose_
FILE *f
= NULL
;
347 Machine
*m
= userdata
;
356 if (m
->class != MACHINE_CONTAINER
)
357 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Requesting OS release data is only supported on container machines.");
359 r
= namespace_open(m
->leader
, NULL
, &mntns_fd
, NULL
, &root_fd
);
363 if (socketpair(AF_UNIX
, SOCK_SEQPACKET
, 0, pair
) < 0)
368 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
371 _cleanup_close_
int fd
= -1;
373 pair
[0] = safe_close(pair
[0]);
375 r
= namespace_enter(-1, mntns_fd
, -1, root_fd
);
379 fd
= open("/etc/os-release", O_RDONLY
|O_CLOEXEC
);
381 fd
= open("/usr/lib/os-release", O_RDONLY
|O_CLOEXEC
);
386 r
= copy_bytes(fd
, pair
[1], (off_t
) -1, false);
393 pair
[1] = safe_close(pair
[1]);
395 f
= fdopen(pair
[0], "re");
401 r
= load_env_file_pairs(f
, "/etc/os-release", NULL
, &l
);
405 r
= wait_for_terminate(child
, &si
);
407 return sd_bus_error_set_errnof(error
, r
, "Failed to wait for client: %m");
408 if (si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
409 return sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Client died abnormally.");
411 r
= sd_bus_message_new_method_return(message
, &reply
);
415 r
= sd_bus_message_open_container(reply
, 'a', "{ss}");
419 STRV_FOREACH_PAIR(k
, v
, l
) {
420 r
= sd_bus_message_append(reply
, "{ss}", *k
, *v
);
425 r
= sd_bus_message_close_container(reply
);
429 return sd_bus_send(NULL
, reply
, NULL
);
432 int bus_machine_method_open_pty(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
433 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
434 _cleanup_free_
char *pty_name
= NULL
;
435 _cleanup_close_
int master
= -1;
436 Machine
*m
= userdata
;
442 if (m
->class != MACHINE_CONTAINER
)
443 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening pseudo TTYs is only supported on container machines.");
445 master
= openpt_in_namespace(m
->leader
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
449 r
= ptsname_malloc(master
, &pty_name
);
453 r
= sd_bus_message_new_method_return(message
, &reply
);
457 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
461 return sd_bus_send(NULL
, reply
, NULL
);
464 int bus_machine_method_open_login(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
465 _cleanup_bus_message_unref_ sd_bus_message
*reply
= NULL
;
466 _cleanup_free_
char *pty_name
= NULL
, *getty
= NULL
;
467 _cleanup_bus_unref_ sd_bus
*container_bus
= NULL
;
468 _cleanup_close_
int master
= -1;
469 Machine
*m
= userdata
;
477 if (m
->class != MACHINE_CONTAINER
)
478 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Opening logins is only supported on container machines.");
480 r
= bus_verify_polkit_async(
483 "org.freedesktop.machine1.login",
486 &m
->manager
->polkit_registry
,
491 return 1; /* Will call us back */
493 master
= openpt_in_namespace(m
->leader
, O_RDWR
|O_NOCTTY
|O_CLOEXEC
);
497 r
= ptsname_malloc(master
, &pty_name
);
501 p
= path_startswith(pty_name
, "/dev/pts/");
503 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "PTS name %s is invalid", pty_name
);
505 if (unlockpt(master
) < 0)
508 r
= sd_bus_new(&container_bus
);
513 # define ADDRESS_FMT "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI
515 # define ADDRESS_FMT "x-machine-unix:pid=%1$" PID_PRI
517 if (asprintf(&address
, ADDRESS_FMT
, m
->leader
) < 0)
520 container_bus
->address
= address
;
521 container_bus
->bus_client
= true;
522 container_bus
->trusted
= false;
523 container_bus
->is_system
= true;
525 r
= sd_bus_start(container_bus
);
529 getty
= strjoin("container-getty@", p
, ".service", NULL
);
533 r
= sd_bus_call_method(
535 "org.freedesktop.systemd1",
536 "/org/freedesktop/systemd1",
537 "org.freedesktop.systemd1.Manager",
540 "ss", getty
, "replace");
544 container_bus
= sd_bus_unref(container_bus
);
546 r
= sd_bus_message_new_method_return(message
, &reply
);
550 r
= sd_bus_message_append(reply
, "hs", master
, pty_name
);
554 return sd_bus_send(NULL
, reply
, NULL
);
557 int bus_machine_method_bind_mount(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
558 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
559 char mount_slave
[] = "/tmp/propagate.XXXXXX", *mount_tmp
, *mount_outside
, *p
;
560 bool mount_slave_created
= false, mount_slave_mounted
= false,
561 mount_tmp_created
= false, mount_tmp_mounted
= false,
562 mount_outside_created
= false, mount_outside_mounted
= false;
563 const char *dest
, *src
;
564 Machine
*m
= userdata
;
565 int read_only
, make_directory
;
573 if (m
->class != MACHINE_CONTAINER
)
574 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Bind mounting is only supported on container machines.");
576 r
= sd_bus_message_read(message
, "ssbb", &src
, &dest
, &read_only
, &make_directory
);
580 if (!path_is_absolute(src
) || !path_is_safe(src
))
581 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
585 else if (!path_is_absolute(dest
) || !path_is_safe(dest
))
586 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
588 r
= bus_verify_polkit_async(
591 "org.freedesktop.machine1.manage-machines",
594 &m
->manager
->polkit_registry
,
599 return 1; /* Will call us back */
601 /* One day, when bind mounting /proc/self/fd/n works across
602 * namespace boundaries we should rework this logic to make
605 p
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/");
606 if (laccess(p
, F_OK
) < 0)
607 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Container does not allow propagation of mount points.");
609 /* Our goal is to install a new bind mount into the container,
610 possibly read-only. This is irritatingly complex
611 unfortunately, currently.
613 First, we start by creating a private playground in /tmp,
614 that we can mount MS_SLAVE. (Which is necessary, since
615 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
618 if (!mkdtemp(mount_slave
))
619 return sd_bus_error_set_errnof(error
, errno
, "Failed to create playground %s: %m", mount_slave
);
621 mount_slave_created
= true;
623 if (mount(mount_slave
, mount_slave
, NULL
, MS_BIND
, NULL
) < 0) {
624 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to make bind mount %s: %m", mount_slave
);
628 mount_slave_mounted
= true;
630 if (mount(NULL
, mount_slave
, NULL
, MS_SLAVE
, NULL
) < 0) {
631 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount slave %s: %m", mount_slave
);
635 /* Second, we mount the source directory to a directory inside
636 of our MS_SLAVE playground. */
637 mount_tmp
= strjoina(mount_slave
, "/mount");
638 if (mkdir(mount_tmp
, 0700) < 0) {
639 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create temporary mount point %s: %m", mount_tmp
);
643 mount_tmp_created
= true;
645 if (mount(src
, mount_tmp
, NULL
, MS_BIND
, NULL
) < 0) {
646 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to overmount %s: %m", mount_tmp
);
650 mount_tmp_mounted
= true;
652 /* Third, we remount the new bind mount read-only if requested. */
654 if (mount(NULL
, mount_tmp
, NULL
, MS_BIND
|MS_REMOUNT
|MS_RDONLY
, NULL
) < 0) {
655 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to remount read-only %s: %m", mount_tmp
);
659 /* Fourth, we move the new bind mount into the propagation
660 * directory. This way it will appear there read-only
663 mount_outside
= strjoina("/run/systemd/nspawn/propagate/", m
->name
, "/XXXXXX");
664 if (!mkdtemp(mount_outside
)) {
665 r
= sd_bus_error_set_errnof(error
, errno
, "Cannot create propagation directory %s: %m", mount_outside
);
669 mount_outside_created
= true;
671 if (mount(mount_tmp
, mount_outside
, NULL
, MS_MOVE
, NULL
) < 0) {
672 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to move %s to %s: %m", mount_tmp
, mount_outside
);
676 mount_outside_mounted
= true;
677 mount_tmp_mounted
= false;
679 (void) rmdir(mount_tmp
);
680 mount_tmp_created
= false;
682 (void) umount(mount_slave
);
683 mount_slave_mounted
= false;
685 (void) rmdir(mount_slave
);
686 mount_slave_created
= false;
688 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0) {
689 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
695 r
= sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
700 const char *mount_inside
;
704 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
706 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
707 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
709 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
713 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
714 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
719 (void) mkdir_p(dest
, 0755);
721 /* Fifth, move the mount to the right place inside */
722 mount_inside
= strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside
));
723 if (mount(mount_inside
, dest
, NULL
, MS_MOVE
, NULL
) < 0) {
724 r
= log_error_errno(errno
, "Failed to mount: %m");
731 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
732 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
737 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
739 r
= wait_for_terminate(child
, &si
);
741 r
= sd_bus_error_set_errnof(error
, r
, "Failed to wait for client: %m");
744 if (si
.si_code
!= CLD_EXITED
) {
745 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Client died abnormally.");
748 if (si
.si_status
!= EXIT_SUCCESS
) {
750 if (read(errno_pipe_fd
[0], &r
, sizeof(r
)) == sizeof(r
))
751 r
= sd_bus_error_set_errnof(error
, r
, "Failed to mount: %m");
753 r
= sd_bus_error_setf(error
, SD_BUS_ERROR_FAILED
, "Client failed.");
757 r
= sd_bus_reply_method_return(message
, NULL
);
760 if (mount_outside_mounted
)
761 umount(mount_outside
);
762 if (mount_outside_created
)
763 rmdir(mount_outside
);
765 if (mount_tmp_mounted
)
767 if (mount_tmp_created
)
770 if (mount_slave_mounted
)
772 if (mount_slave_created
)
778 static int machine_operation_done(sd_event_source
*s
, const siginfo_t
*si
, void *userdata
) {
779 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
780 MachineOperation
*o
= userdata
;
788 if (si
->si_code
!= CLD_EXITED
) {
789 r
= sd_bus_error_setf(&error
, SD_BUS_ERROR_FAILED
, "Client died abnormally.");
793 if (si
->si_status
!= EXIT_SUCCESS
) {
794 if (read(o
->errno_fd
, &r
, sizeof(r
)) == sizeof(r
))
795 r
= sd_bus_error_set_errnof(&error
, r
, "%m");
797 r
= sd_bus_error_setf(&error
, SD_BUS_ERROR_FAILED
, "Client failed.");
802 r
= sd_bus_reply_method_return(o
->message
, NULL
);
804 log_error_errno(r
, "Failed to reply to message: %m");
806 machine_operation_unref(o
);
810 r
= sd_bus_reply_method_error(o
->message
, &error
);
812 log_error_errno(r
, "Failed to reply to message: %m");
814 machine_operation_unref(o
);
818 int bus_machine_method_copy(sd_bus_message
*message
, void *userdata
, sd_bus_error
*error
) {
819 const char *src
, *dest
, *host_path
, *container_path
, *host_basename
, *host_dirname
, *container_basename
, *container_dirname
;
820 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
821 _cleanup_close_
int hostfd
= -1;
822 Machine
*m
= userdata
;
832 if (m
->n_operations
>= MACHINE_OPERATIONS_MAX
)
833 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing copies.");
835 if (m
->class != MACHINE_CONTAINER
)
836 return sd_bus_error_setf(error
, SD_BUS_ERROR_NOT_SUPPORTED
, "Copying files is only supported on container machines.");
838 r
= sd_bus_message_read(message
, "ss", &src
, &dest
);
842 if (!path_is_absolute(src
) || !path_is_safe(src
))
843 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Source path must be absolute and not contain ../.");
847 else if (!path_is_absolute(dest
) || !path_is_safe(dest
))
848 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Destination path must be absolute and not contain ../.");
850 r
= bus_verify_polkit_async(
853 "org.freedesktop.machine1.manage-machines",
856 &m
->manager
->polkit_registry
,
861 return 1; /* Will call us back */
863 copy_from
= strstr(sd_bus_message_get_member(message
), "CopyFrom");
866 container_path
= src
;
870 container_path
= dest
;
873 host_basename
= basename(host_path
);
874 t
= strdupa(host_path
);
875 host_dirname
= dirname(t
);
877 container_basename
= basename(container_path
);
878 t
= strdupa(container_path
);
879 container_dirname
= dirname(t
);
881 hostfd
= open(host_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
883 return sd_bus_error_set_errnof(error
, errno
, "Failed to open host directory %s: %m", host_dirname
);
885 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
886 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
890 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
897 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
899 q
= procfs_file_alloca(m
->leader
, "ns/mnt");
900 mntfd
= open(q
, O_RDONLY
|O_NOCTTY
|O_CLOEXEC
);
902 r
= log_error_errno(errno
, "Failed to open mount namespace of leader: %m");
906 if (setns(mntfd
, CLONE_NEWNS
) < 0) {
907 r
= log_error_errno(errno
, "Failed to join namespace of leader: %m");
911 containerfd
= open(container_dirname
, O_CLOEXEC
|O_RDONLY
|O_NOCTTY
|O_DIRECTORY
);
912 if (containerfd
< 0) {
913 r
= log_error_errno(errno
, "Failed top open destination directory: %m");
918 r
= copy_tree_at(containerfd
, container_basename
, hostfd
, host_basename
, true);
920 r
= copy_tree_at(hostfd
, host_basename
, containerfd
, container_basename
, true);
922 hostfd
= safe_close(hostfd
);
923 containerfd
= safe_close(containerfd
);
926 r
= log_error_errno(r
, "Failed to copy tree: %m");
933 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
934 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
939 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
941 /* Copying might take a while, hence install a watch the
942 * child, and return */
944 o
= new0(MachineOperation
, 1);
949 o
->message
= sd_bus_message_ref(message
);
950 o
->errno_fd
= errno_pipe_fd
[0];
951 errno_pipe_fd
[0] = -1;
953 r
= sd_event_add_child(m
->manager
->event
, &o
->event_source
, child
, WEXITED
, machine_operation_done
, o
);
955 machine_operation_unref(o
);
959 LIST_PREPEND(operations
, m
->operations
, o
);
966 const sd_bus_vtable machine_vtable
[] = {
967 SD_BUS_VTABLE_START(0),
968 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Machine
, name
), SD_BUS_VTABLE_PROPERTY_CONST
),
969 SD_BUS_PROPERTY("Id", "ay", property_get_id
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
970 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine
, timestamp
), SD_BUS_VTABLE_PROPERTY_CONST
),
971 SD_BUS_PROPERTY("Service", "s", NULL
, offsetof(Machine
, service
), SD_BUS_VTABLE_PROPERTY_CONST
),
972 SD_BUS_PROPERTY("Unit", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
),
973 SD_BUS_PROPERTY("Scope", "s", NULL
, offsetof(Machine
, unit
), SD_BUS_VTABLE_PROPERTY_CONST
|SD_BUS_VTABLE_HIDDEN
),
974 SD_BUS_PROPERTY("Leader", "u", NULL
, offsetof(Machine
, leader
), SD_BUS_VTABLE_PROPERTY_CONST
),
975 SD_BUS_PROPERTY("Class", "s", property_get_class
, offsetof(Machine
, class), SD_BUS_VTABLE_PROPERTY_CONST
),
976 SD_BUS_PROPERTY("RootDirectory", "s", NULL
, offsetof(Machine
, root_directory
), SD_BUS_VTABLE_PROPERTY_CONST
),
977 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif
, 0, SD_BUS_VTABLE_PROPERTY_CONST
),
978 SD_BUS_PROPERTY("State", "s", property_get_state
, 0, 0),
979 SD_BUS_METHOD("Terminate", NULL
, NULL
, bus_machine_method_terminate
, SD_BUS_VTABLE_UNPRIVILEGED
),
980 SD_BUS_METHOD("Kill", "si", NULL
, bus_machine_method_kill
, SD_BUS_VTABLE_UNPRIVILEGED
),
981 SD_BUS_METHOD("GetAddresses", NULL
, "a(iay)", bus_machine_method_get_addresses
, SD_BUS_VTABLE_UNPRIVILEGED
),
982 SD_BUS_METHOD("GetOSRelease", NULL
, "a{ss}", bus_machine_method_get_os_release
, SD_BUS_VTABLE_UNPRIVILEGED
),
983 SD_BUS_METHOD("OpenPTY", NULL
, "hs", bus_machine_method_open_pty
, 0),
984 SD_BUS_METHOD("OpenLogin", NULL
, "hs", bus_machine_method_open_login
, SD_BUS_VTABLE_UNPRIVILEGED
),
985 SD_BUS_METHOD("BindMount", "ssbb", NULL
, bus_machine_method_bind_mount
, SD_BUS_VTABLE_UNPRIVILEGED
),
986 SD_BUS_METHOD("CopyFrom", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
987 SD_BUS_METHOD("CopyTo", "ss", NULL
, bus_machine_method_copy
, SD_BUS_VTABLE_UNPRIVILEGED
),
991 int machine_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
992 Manager
*m
= userdata
;
1002 if (streq(path
, "/org/freedesktop/machine1/machine/self")) {
1003 _cleanup_bus_creds_unref_ sd_bus_creds
*creds
= NULL
;
1004 sd_bus_message
*message
;
1007 message
= sd_bus_get_current_message(bus
);
1011 r
= sd_bus_query_sender_creds(message
, SD_BUS_CREDS_PID
, &creds
);
1015 r
= sd_bus_creds_get_pid(creds
, &pid
);
1019 r
= manager_get_machine_by_pid(m
, pid
, &machine
);
1023 _cleanup_free_
char *e
= NULL
;
1026 p
= startswith(path
, "/org/freedesktop/machine1/machine/");
1030 e
= bus_label_unescape(p
);
1034 machine
= hashmap_get(m
->machines
, e
);
1043 char *machine_bus_path(Machine
*m
) {
1044 _cleanup_free_
char *e
= NULL
;
1048 e
= bus_label_escape(m
->name
);
1052 return strappend("/org/freedesktop/machine1/machine/", e
);
1055 int machine_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
1056 _cleanup_strv_free_
char **l
= NULL
;
1057 Machine
*machine
= NULL
;
1058 Manager
*m
= userdata
;
1066 HASHMAP_FOREACH(machine
, m
->machines
, i
) {
1069 p
= machine_bus_path(machine
);
1073 r
= strv_consume(&l
, p
);
1084 int machine_send_signal(Machine
*m
, bool new_machine
) {
1085 _cleanup_free_
char *p
= NULL
;
1089 p
= machine_bus_path(m
);
1093 return sd_bus_emit_signal(
1095 "/org/freedesktop/machine1",
1096 "org.freedesktop.machine1.Manager",
1097 new_machine
? "MachineNew" : "MachineRemoved",
1101 int machine_send_create_reply(Machine
*m
, sd_bus_error
*error
) {
1102 _cleanup_bus_message_unref_ sd_bus_message
*c
= NULL
;
1103 _cleanup_free_
char *p
= NULL
;
1107 if (!m
->create_message
)
1110 c
= m
->create_message
;
1111 m
->create_message
= NULL
;
1114 return sd_bus_reply_method_error(c
, error
);
1116 /* Update the machine state file before we notify the client
1117 * about the result. */
1120 p
= machine_bus_path(m
);
1124 return sd_bus_reply_method_return(c
, "o", p
);