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 XDG
28 * version which is really broken. */
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"
46 static int property_get_id(
49 const char *interface,
51 sd_bus_message *reply,
53 sd_bus_error *error) {
55 Machine *m = userdata;
62 r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
69 static int property_get_state(
72 const char *interface,
74 sd_bus_message *reply,
76 sd_bus_error *error) {
78 Machine *m = userdata;
86 state = machine_state_to_string(machine_get_state(m));
88 r = sd_bus_message_append_basic(reply, 's', state);
95 static int property_get_netif(
98 const char *interface,
100 sd_bus_message *reply,
102 sd_bus_error *error) {
104 Machine *m = userdata;
111 assert_cc(sizeof(int) == sizeof(int32_t));
113 r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
120 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
122 int bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
123 Machine *m = userdata;
130 r = bus_verify_polkit_async(
133 "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",
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 *bus, 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;
211 if (m->class != MACHINE_CONTAINER)
212 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
214 r = readlink_malloc("/proc/self/ns/net", &us);
218 p = procfs_file_alloca(m->leader, "ns/net");
219 r = readlink_malloc(p, &them);
224 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
226 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
230 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
235 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
238 _cleanup_free_ struct local_address *addresses = NULL;
239 struct local_address *a;
242 pair[0] = safe_close(pair[0]);
244 r = namespace_enter(-1, -1, netns_fd, -1);
248 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
252 for (a = addresses, i = 0; i < n; a++, i++) {
253 struct iovec iov[2] = {
254 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
255 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
258 r = writev(pair[1], iov, 2);
263 pair[1] = safe_close(pair[1]);
268 pair[1] = safe_close(pair[1]);
270 r = sd_bus_message_new_method_return(message, &reply);
274 r = sd_bus_message_open_container(reply, 'a', "(iay)");
281 union in_addr_union in_addr;
288 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
289 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
291 n = recvmsg(pair[0], &mh, 0);
294 if ((size_t) n < sizeof(family))
297 r = sd_bus_message_open_container(reply, 'r', "iay");
301 r = sd_bus_message_append(reply, "i", family);
308 if (n != sizeof(struct in_addr) + sizeof(family))
311 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
315 if (n != sizeof(struct in6_addr) + sizeof(family))
318 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
324 r = sd_bus_message_close_container(reply);
329 r = wait_for_terminate(child, &si);
331 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
332 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
333 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
335 r = sd_bus_message_close_container(reply);
339 return sd_bus_send(bus, reply, NULL);
342 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
343 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
344 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
345 _cleanup_close_pair_ int pair[2] = { -1, -1 };
346 _cleanup_strv_free_ char **l = NULL;
347 _cleanup_fclose_ FILE *f = NULL;
348 Machine *m = userdata;
358 if (m->class != MACHINE_CONTAINER)
359 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
361 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
365 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
370 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
373 _cleanup_close_ int fd = -1;
375 pair[0] = safe_close(pair[0]);
377 r = namespace_enter(-1, mntns_fd, -1, root_fd);
381 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
383 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
388 r = copy_bytes(fd, pair[1], (off_t) -1, false);
395 pair[1] = safe_close(pair[1]);
397 f = fdopen(pair[0], "re");
403 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
407 r = wait_for_terminate(child, &si);
409 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
410 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
411 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
413 r = sd_bus_message_new_method_return(message, &reply);
417 r = sd_bus_message_open_container(reply, 'a', "{ss}");
421 STRV_FOREACH_PAIR(k, v, l) {
422 r = sd_bus_message_append(reply, "{ss}", *k, *v);
427 r = sd_bus_message_close_container(reply);
431 return sd_bus_send(bus, reply, NULL);
434 int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
435 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
436 _cleanup_free_ char *pty_name = NULL;
437 _cleanup_close_ int master = -1;
438 Machine *m = userdata;
445 if (m->class != MACHINE_CONTAINER)
446 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
448 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
452 r = ptsname_malloc(master, &pty_name);
456 r = sd_bus_message_new_method_return(message, &reply);
460 r = sd_bus_message_append(reply, "hs", master, pty_name);
464 return sd_bus_send(bus, reply, NULL);
467 int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
469 _cleanup_free_ char *pty_name = NULL, *getty = NULL;
470 _cleanup_bus_unref_ sd_bus *container_bus = NULL;
471 _cleanup_close_ int master = -1;
472 Machine *m = userdata;
476 if (m->class != MACHINE_CONTAINER)
477 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
479 r = bus_verify_polkit_async(
482 "org.freedesktop.machine1.login",
485 &m->manager->polkit_registry,
490 return 1; /* Will call us back */
492 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
496 r = ptsname_malloc(master, &pty_name);
500 p = path_startswith(pty_name, "/dev/pts/");
502 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
504 if (unlockpt(master) < 0)
507 r = sd_bus_new(&container_bus);
512 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
514 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader);
516 if (!container_bus->address)
519 container_bus->bus_client = true;
520 container_bus->trusted = false;
521 container_bus->is_system = true;
523 r = sd_bus_start(container_bus);
527 getty = strjoin("container-getty@", p, ".service", NULL);
531 r = sd_bus_call_method(
533 "org.freedesktop.systemd1",
534 "/org/freedesktop/systemd1",
535 "org.freedesktop.systemd1.Manager",
538 "ss", getty, "replace");
542 container_bus = sd_bus_unref(container_bus);
544 r = sd_bus_message_new_method_return(message, &reply);
548 r = sd_bus_message_append(reply, "hs", master, pty_name);
552 return sd_bus_send(bus, reply, NULL);
555 int bus_machine_method_bind_mount(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
556 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
557 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
558 bool mount_slave_created = false, mount_slave_mounted = false,
559 mount_tmp_created = false, mount_tmp_mounted = false,
560 mount_outside_created = false, mount_outside_mounted = false;
561 const char *dest, *src;
562 Machine *m = userdata;
563 int read_only, make_directory;
568 if (m->class != MACHINE_CONTAINER)
569 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
571 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
575 if (!path_is_absolute(src) || !path_is_safe(src))
576 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
580 else if (!path_is_absolute(dest) || !path_is_safe(dest))
581 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
583 r = bus_verify_polkit_async(
586 "org.freedesktop.machine1.manage-machines",
589 &m->manager->polkit_registry,
594 return 1; /* Will call us back */
596 /* One day, when bind mounting /proc/self/fd/n works across
597 * namespace boundaries we should rework this logic to make
600 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
601 if (laccess(p, F_OK) < 0)
602 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
604 /* Our goal is to install a new bind mount into the container,
605 possibly read-only. This is irritatingly complex
606 unfortunately, currently.
608 First, we start by creating a private playground in /tmp,
609 that we can mount MS_SLAVE. (Which is necessary, since
610 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
613 if (!mkdtemp(mount_slave))
614 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
616 mount_slave_created = true;
618 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
619 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
623 mount_slave_mounted = true;
625 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
626 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
630 /* Second, we mount the source directory to a directory inside
631 of our MS_SLAVE playground. */
632 mount_tmp = strjoina(mount_slave, "/mount");
633 if (mkdir(mount_tmp, 0700) < 0) {
634 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
638 mount_tmp_created = true;
640 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
641 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
645 mount_tmp_mounted = true;
647 /* Third, we remount the new bind mount read-only if requested. */
649 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
650 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
654 /* Fourth, we move the new bind mount into the propagation
655 * directory. This way it will appear there read-only
658 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
659 if (!mkdtemp(mount_outside)) {
660 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
664 mount_outside_created = true;
666 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
667 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
671 mount_outside_mounted = true;
672 mount_tmp_mounted = false;
674 (void) rmdir(mount_tmp);
675 mount_tmp_created = false;
677 (void) umount(mount_slave);
678 mount_slave_mounted = false;
680 (void) rmdir(mount_slave);
681 mount_slave_created = false;
683 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
684 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
690 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
695 const char *mount_inside;
699 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
701 q = procfs_file_alloca(m->leader, "ns/mnt");
702 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
704 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
708 if (setns(mntfd, CLONE_NEWNS) < 0) {
709 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
714 (void) mkdir_p(dest, 0755);
716 /* Fifth, move the mount to the right place inside */
717 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
718 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
719 r = log_error_errno(errno, "Failed to mount: %m");
726 (void) write(errno_pipe_fd[1], &r, sizeof(r));
727 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
732 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
734 r = wait_for_terminate(child, &si);
736 r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
739 if (si.si_code != CLD_EXITED) {
740 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
743 if (si.si_status != EXIT_SUCCESS) {
745 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
746 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
748 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
752 r = sd_bus_reply_method_return(message, NULL);
755 if (mount_outside_mounted)
756 umount(mount_outside);
757 if (mount_outside_created)
758 rmdir(mount_outside);
760 if (mount_tmp_mounted)
762 if (mount_tmp_created)
765 if (mount_slave_mounted)
767 if (mount_slave_created)
773 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
774 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
775 MachineOperation *o = userdata;
783 if (si->si_code != CLD_EXITED) {
784 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
788 if (si->si_status != EXIT_SUCCESS) {
789 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
790 r = sd_bus_error_set_errnof(&error, r, "%m");
792 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
797 r = sd_bus_reply_method_return(o->message, NULL);
799 log_error_errno(r, "Failed to reply to message: %m");
801 machine_operation_unref(o);
805 r = sd_bus_reply_method_error(o->message, &error);
807 log_error_errno(r, "Failed to reply to message: %m");
809 machine_operation_unref(o);
813 int bus_machine_method_copy(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
814 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
815 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
816 _cleanup_close_ int hostfd = -1;
817 Machine *m = userdata;
824 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
825 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
827 if (m->class != MACHINE_CONTAINER)
828 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
830 r = sd_bus_message_read(message, "ss", &src, &dest);
834 if (!path_is_absolute(src) || !path_is_safe(src))
835 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
839 else if (!path_is_absolute(dest) || !path_is_safe(dest))
840 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
842 r = bus_verify_polkit_async(
845 "org.freedesktop.machine1.manage-machines",
848 &m->manager->polkit_registry,
853 return 1; /* Will call us back */
855 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
858 container_path = src;
862 container_path = dest;
865 host_basename = basename(host_path);
866 t = strdupa(host_path);
867 host_dirname = dirname(t);
869 container_basename = basename(container_path);
870 t = strdupa(container_path);
871 container_dirname = dirname(t);
873 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
875 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
877 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
878 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
882 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
889 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
891 q = procfs_file_alloca(m->leader, "ns/mnt");
892 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
894 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
898 if (setns(mntfd, CLONE_NEWNS) < 0) {
899 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
903 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
904 if (containerfd < 0) {
905 r = log_error_errno(errno, "Failed top open destination directory: %m");
910 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
912 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
914 hostfd = safe_close(hostfd);
915 containerfd = safe_close(containerfd);
918 r = log_error_errno(r, "Failed to copy tree: %m");
925 (void) write(errno_pipe_fd[1], &r, sizeof(r));
926 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
931 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
933 /* Copying might take a while, hence install a watch the
934 * child, and return */
936 o = new0(MachineOperation, 1);
941 o->message = sd_bus_message_ref(message);
942 o->errno_fd = errno_pipe_fd[0];
943 errno_pipe_fd[0] = -1;
945 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
947 machine_operation_unref(o);
951 LIST_PREPEND(operations, m->operations, o);
958 const sd_bus_vtable machine_vtable[] = {
959 SD_BUS_VTABLE_START(0),
960 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
961 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
962 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
963 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
964 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
965 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
966 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
967 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
968 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
969 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
970 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
971 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
972 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
973 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
974 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
975 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
976 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
977 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
978 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
979 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
983 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
984 Manager *m = userdata;
994 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
995 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
996 sd_bus_message *message;
999 message = sd_bus_get_current_message(bus);
1003 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1007 r = sd_bus_creds_get_pid(creds, &pid);
1011 r = manager_get_machine_by_pid(m, pid, &machine);
1015 _cleanup_free_ char *e = NULL;
1018 p = startswith(path, "/org/freedesktop/machine1/machine/");
1022 e = bus_label_unescape(p);
1026 machine = hashmap_get(m->machines, e);
1035 char *machine_bus_path(Machine *m) {
1036 _cleanup_free_ char *e = NULL;
1040 e = bus_label_escape(m->name);
1044 return strappend("/org/freedesktop/machine1/machine/", e);
1047 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1048 _cleanup_strv_free_ char **l = NULL;
1049 Machine *machine = NULL;
1050 Manager *m = userdata;
1058 HASHMAP_FOREACH(machine, m->machines, i) {
1061 p = machine_bus_path(machine);
1065 r = strv_consume(&l, p);
1076 int machine_send_signal(Machine *m, bool new_machine) {
1077 _cleanup_free_ char *p = NULL;
1081 p = machine_bus_path(m);
1085 return sd_bus_emit_signal(
1087 "/org/freedesktop/machine1",
1088 "org.freedesktop.machine1.Manager",
1089 new_machine ? "MachineNew" : "MachineRemoved",
1093 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1094 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1095 _cleanup_free_ char *p = NULL;
1099 if (!m->create_message)
1102 c = m->create_message;
1103 m->create_message = NULL;
1106 return sd_bus_reply_method_error(c, error);
1108 /* Update the machine state file before we notify the client
1109 * about the result. */
1112 p = machine_bus_path(m);
1116 return sd_bus_reply_method_return(c, "o", p);