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 <arpa/inet.h>
25 #include <sys/mount.h>
27 /* When we include libgen.h because we need dirname() we immediately
28 * undefine basename() since libgen.h defines it as a macro to the XDG
29 * version which is really broken. */
34 #include "bus-label.h"
36 #include "bus-common-errors.h"
39 #include "in-addr-util.h"
40 #include "local-addresses.h"
41 #include "path-util.h"
43 #include "bus-internal.h"
45 #include "machine-dbus.h"
47 static int property_get_id(
50 const char *interface,
52 sd_bus_message *reply,
54 sd_bus_error *error) {
56 Machine *m = userdata;
63 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
70 static int property_get_state(
73 const char *interface,
75 sd_bus_message *reply,
77 sd_bus_error *error) {
79 Machine *m = userdata;
87 state = machine_state_to_string(machine_get_state(m));
89 r = sd_bus_message_append_basic(reply, 's', state);
96 static int property_get_netif(
99 const char *interface,
100 const char *property,
101 sd_bus_message *reply,
103 sd_bus_error *error) {
105 Machine *m = userdata;
112 assert_cc(sizeof(int) == sizeof(int32_t));
114 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
121 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
123 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
124 Machine *m = userdata;
131 r = bus_verify_polkit_async(
134 "org.freedesktop.machine1.manage-machines",
136 &m->manager->polkit_registry,
141 return 1; /* Will call us back */
147 return sd_bus_reply_method_return(message, NULL);
150 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
151 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",
181 &m->manager->polkit_registry,
186 return 1; /* Will call us back */
188 r = machine_kill(m, who, signo);
192 return sd_bus_reply_method_return(message, NULL);
195 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
196 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
197 _cleanup_close_pair_ int pair[2] = { -1, -1 };
198 _cleanup_free_ char *us = NULL, *them = NULL;
199 _cleanup_close_ int netns_fd = -1;
200 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(bus, reply, NULL);
341 int bus_machine_method_get_os_release(sd_bus *bus, 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;
357 if (m->class != MACHINE_CONTAINER)
358 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
360 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
364 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
369 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
372 _cleanup_close_ int fd = -1;
374 pair[0] = safe_close(pair[0]);
376 r = namespace_enter(-1, mntns_fd, -1, root_fd);
380 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
382 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
387 r = copy_bytes(fd, pair[1], (off_t) -1, false);
394 pair[1] = safe_close(pair[1]);
396 f = fdopen(pair[0], "re");
402 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
406 r = wait_for_terminate(child, &si);
408 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
409 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
410 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
412 r = sd_bus_message_new_method_return(message, &reply);
416 r = sd_bus_message_open_container(reply, 'a', "{ss}");
420 STRV_FOREACH_PAIR(k, v, l) {
421 r = sd_bus_message_append(reply, "{ss}", *k, *v);
426 r = sd_bus_message_close_container(reply);
430 return sd_bus_send(bus, reply, NULL);
433 int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
434 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
435 _cleanup_free_ char *pty_name = NULL;
436 _cleanup_close_ int master = -1;
437 Machine *m = userdata;
444 if (m->class != MACHINE_CONTAINER)
445 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
447 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
451 r = ptsname_malloc(master, &pty_name);
455 r = sd_bus_message_new_method_return(message, &reply);
459 r = sd_bus_message_append(reply, "hs", master, pty_name);
463 return sd_bus_send(bus, reply, NULL);
466 int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
467 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
468 _cleanup_free_ char *pty_name = NULL, *getty = NULL;
469 _cleanup_bus_unref_ sd_bus *container_bus = NULL;
470 _cleanup_close_ int master = -1;
471 Machine *m = userdata;
475 if (m->class != MACHINE_CONTAINER)
476 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
478 r = bus_verify_polkit_async(
481 "org.freedesktop.machine1.login",
483 &m->manager->polkit_registry,
488 return 1; /* Will call us back */
490 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
494 r = ptsname_malloc(master, &pty_name);
498 p = path_startswith(pty_name, "/dev/pts/");
500 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
502 if (unlockpt(master) < 0)
505 r = sd_bus_new(&container_bus);
510 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
512 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader);
514 if (!container_bus->address)
517 container_bus->bus_client = true;
518 container_bus->trusted = false;
519 container_bus->is_system = true;
521 r = sd_bus_start(container_bus);
525 getty = strjoin("container-getty@", p, ".service", NULL);
529 r = sd_bus_call_method(
531 "org.freedesktop.systemd1",
532 "/org/freedesktop/systemd1",
533 "org.freedesktop.systemd1.Manager",
536 "ss", getty, "replace");
540 container_bus = sd_bus_unref(container_bus);
542 r = sd_bus_message_new_method_return(message, &reply);
546 r = sd_bus_message_append(reply, "hs", master, pty_name);
550 return sd_bus_send(bus, reply, NULL);
553 int bus_machine_method_bind_mount(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
554 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
555 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
556 bool mount_slave_created = false, mount_slave_mounted = false,
557 mount_tmp_created = false, mount_tmp_mounted = false,
558 mount_outside_created = false, mount_outside_mounted = false;
559 const char *dest, *src;
560 Machine *m = userdata;
561 int read_only, make_directory;
566 if (m->class != MACHINE_CONTAINER)
567 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
569 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
573 if (!path_is_absolute(src) || !path_is_safe(src))
574 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
578 else if (!path_is_absolute(dest) || !path_is_safe(dest))
579 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
581 r = bus_verify_polkit_async(
584 "org.freedesktop.machine1.manage-machines",
586 &m->manager->polkit_registry,
591 return 1; /* Will call us back */
593 /* One day, when bind mounting /proc/self/fd/n works across
594 * namespace boundaries we should rework this logic to make
597 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
598 if (laccess(p, F_OK) < 0)
599 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
601 /* Our goal is to install a new bind mount into the container,
602 possibly read-only. This is irritatingly complex
603 unfortunately, currently.
605 First, we start by creating a private playground in /tmp,
606 that we can mount MS_SLAVE. (Which is necessary, since
607 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
610 if (!mkdtemp(mount_slave))
611 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
613 mount_slave_created = true;
615 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
616 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
620 mount_slave_mounted = true;
622 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
623 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
627 /* Second, we mount the source directory to a directory inside
628 of our MS_SLAVE playground. */
629 mount_tmp = strjoina(mount_slave, "/mount");
630 if (mkdir(mount_tmp, 0700) < 0) {
631 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
635 mount_tmp_created = true;
637 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
638 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
642 mount_tmp_mounted = true;
644 /* Third, we remount the new bind mount read-only if requested. */
646 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
647 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
651 /* Fourth, we move the new bind mount into the propagation
652 * directory. This way it will appear there read-only
655 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
656 if (!mkdtemp(mount_outside)) {
657 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
661 mount_outside_created = true;
663 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
664 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
668 mount_outside_mounted = true;
669 mount_tmp_mounted = false;
671 (void) rmdir(mount_tmp);
672 mount_tmp_created = false;
674 (void) umount(mount_slave);
675 mount_slave_mounted = false;
677 (void) rmdir(mount_slave);
678 mount_slave_created = false;
680 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
681 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
687 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
692 const char *mount_inside;
696 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
698 q = procfs_file_alloca(m->leader, "ns/mnt");
699 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
701 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
705 if (setns(mntfd, CLONE_NEWNS) < 0) {
706 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
711 (void) mkdir_p(dest, 0755);
713 /* Fifth, move the mount to the right place inside */
714 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
715 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
716 r = log_error_errno(errno, "Failed to mount: %m");
723 (void) write(errno_pipe_fd[1], &r, sizeof(r));
724 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
729 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
731 r = wait_for_terminate(child, &si);
733 r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
736 if (si.si_code != CLD_EXITED) {
737 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
740 if (si.si_status != EXIT_SUCCESS) {
742 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
743 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
745 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
749 r = sd_bus_reply_method_return(message, NULL);
752 if (mount_outside_mounted)
753 umount(mount_outside);
754 if (mount_outside_created)
755 rmdir(mount_outside);
757 if (mount_tmp_mounted)
759 if (mount_tmp_created)
762 if (mount_slave_mounted)
764 if (mount_slave_created)
770 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
771 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
772 MachineOperation *o = userdata;
780 if (si->si_code != CLD_EXITED) {
781 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
785 if (si->si_status != EXIT_SUCCESS) {
786 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
787 r = sd_bus_error_set_errnof(&error, r, "%m");
789 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
794 r = sd_bus_reply_method_return(o->message, NULL);
796 log_error_errno(r, "Failed to reply to message: %m");
798 machine_operation_unref(o);
802 r = sd_bus_reply_method_error(o->message, &error);
804 log_error_errno(r, "Failed to reply to message: %m");
806 machine_operation_unref(o);
810 int bus_machine_method_copy(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
811 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
812 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
813 _cleanup_close_ int hostfd = -1;
814 Machine *m = userdata;
821 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
822 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
824 if (m->class != MACHINE_CONTAINER)
825 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
827 r = sd_bus_message_read(message, "ss", &src, &dest);
831 if (!path_is_absolute(src) || !path_is_safe(src))
832 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
836 else if (!path_is_absolute(dest) || !path_is_safe(dest))
837 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
839 r = bus_verify_polkit_async(
842 "org.freedesktop.machine1.manage-machines",
844 &m->manager->polkit_registry,
849 return 1; /* Will call us back */
851 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
854 container_path = src;
858 container_path = dest;
861 host_basename = basename(host_path);
862 t = strdupa(host_path);
863 host_dirname = dirname(t);
865 container_basename = basename(container_path);
866 t = strdupa(container_path);
867 container_dirname = dirname(t);
869 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
871 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
873 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
874 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
878 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
885 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
887 q = procfs_file_alloca(m->leader, "ns/mnt");
888 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
890 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
894 if (setns(mntfd, CLONE_NEWNS) < 0) {
895 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
899 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
900 if (containerfd < 0) {
901 r = log_error_errno(errno, "Failed top open destination directory: %m");
906 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
908 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
910 hostfd = safe_close(hostfd);
911 containerfd = safe_close(containerfd);
914 r = log_error_errno(r, "Failed to copy tree: %m");
921 (void) write(errno_pipe_fd[1], &r, sizeof(r));
922 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
927 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
929 /* Copying might take a while, hence install a watch the
930 * child, and return */
932 o = new0(MachineOperation, 1);
937 o->message = sd_bus_message_ref(message);
938 o->errno_fd = errno_pipe_fd[0];
939 errno_pipe_fd[0] = -1;
941 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
943 machine_operation_unref(o);
947 LIST_PREPEND(operations, m->operations, o);
954 const sd_bus_vtable machine_vtable[] = {
955 SD_BUS_VTABLE_START(0),
956 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
957 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
958 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
959 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
960 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
961 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
962 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
963 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
964 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
965 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
966 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
967 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
968 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
969 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
970 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
971 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
972 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
973 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
974 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
975 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
979 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
980 Manager *m = userdata;
990 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
991 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
992 sd_bus_message *message;
995 message = sd_bus_get_current_message(bus);
999 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1003 r = sd_bus_creds_get_pid(creds, &pid);
1007 r = manager_get_machine_by_pid(m, pid, &machine);
1011 _cleanup_free_ char *e = NULL;
1014 p = startswith(path, "/org/freedesktop/machine1/machine/");
1018 e = bus_label_unescape(p);
1022 machine = hashmap_get(m->machines, e);
1031 char *machine_bus_path(Machine *m) {
1032 _cleanup_free_ char *e = NULL;
1036 e = bus_label_escape(m->name);
1040 return strappend("/org/freedesktop/machine1/machine/", e);
1043 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1044 _cleanup_strv_free_ char **l = NULL;
1045 Machine *machine = NULL;
1046 Manager *m = userdata;
1054 HASHMAP_FOREACH(machine, m->machines, i) {
1057 p = machine_bus_path(machine);
1061 r = strv_consume(&l, p);
1072 int machine_send_signal(Machine *m, bool new_machine) {
1073 _cleanup_free_ char *p = NULL;
1077 p = machine_bus_path(m);
1081 return sd_bus_emit_signal(
1083 "/org/freedesktop/machine1",
1084 "org.freedesktop.machine1.Manager",
1085 new_machine ? "MachineNew" : "MachineRemoved",
1089 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1090 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1091 _cleanup_free_ char *p = NULL;
1095 if (!m->create_message)
1098 c = m->create_message;
1099 m->create_message = NULL;
1102 return sd_bus_reply_method_error(c, error);
1104 /* Update the machine state file before we notify the client
1105 * about the result. */
1108 p = machine_bus_path(m);
1112 return sd_bus_reply_method_return(c, "o", p);