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;
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(bus, reply, NULL);
557 int bus_machine_method_bind_mount(sd_bus *bus, 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;
570 if (m->class != MACHINE_CONTAINER)
571 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
573 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
577 if (!path_is_absolute(src) || !path_is_safe(src))
578 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
582 else if (!path_is_absolute(dest) || !path_is_safe(dest))
583 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
585 r = bus_verify_polkit_async(
588 "org.freedesktop.machine1.manage-machines",
591 &m->manager->polkit_registry,
596 return 1; /* Will call us back */
598 /* One day, when bind mounting /proc/self/fd/n works across
599 * namespace boundaries we should rework this logic to make
602 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
603 if (laccess(p, F_OK) < 0)
604 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
606 /* Our goal is to install a new bind mount into the container,
607 possibly read-only. This is irritatingly complex
608 unfortunately, currently.
610 First, we start by creating a private playground in /tmp,
611 that we can mount MS_SLAVE. (Which is necessary, since
612 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
615 if (!mkdtemp(mount_slave))
616 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
618 mount_slave_created = true;
620 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
621 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
625 mount_slave_mounted = true;
627 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
628 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
632 /* Second, we mount the source directory to a directory inside
633 of our MS_SLAVE playground. */
634 mount_tmp = strjoina(mount_slave, "/mount");
635 if (mkdir(mount_tmp, 0700) < 0) {
636 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
640 mount_tmp_created = true;
642 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
643 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
647 mount_tmp_mounted = true;
649 /* Third, we remount the new bind mount read-only if requested. */
651 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
652 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
656 /* Fourth, we move the new bind mount into the propagation
657 * directory. This way it will appear there read-only
660 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
661 if (!mkdtemp(mount_outside)) {
662 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
666 mount_outside_created = true;
668 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
669 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
673 mount_outside_mounted = true;
674 mount_tmp_mounted = false;
676 (void) rmdir(mount_tmp);
677 mount_tmp_created = false;
679 (void) umount(mount_slave);
680 mount_slave_mounted = false;
682 (void) rmdir(mount_slave);
683 mount_slave_created = false;
685 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
686 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
692 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
697 const char *mount_inside;
701 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
703 q = procfs_file_alloca(m->leader, "ns/mnt");
704 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
706 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
710 if (setns(mntfd, CLONE_NEWNS) < 0) {
711 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
716 (void) mkdir_p(dest, 0755);
718 /* Fifth, move the mount to the right place inside */
719 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
720 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
721 r = log_error_errno(errno, "Failed to mount: %m");
728 (void) write(errno_pipe_fd[1], &r, sizeof(r));
729 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
734 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
736 r = wait_for_terminate(child, &si);
738 r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
741 if (si.si_code != CLD_EXITED) {
742 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
745 if (si.si_status != EXIT_SUCCESS) {
747 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
748 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
750 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
754 r = sd_bus_reply_method_return(message, NULL);
757 if (mount_outside_mounted)
758 umount(mount_outside);
759 if (mount_outside_created)
760 rmdir(mount_outside);
762 if (mount_tmp_mounted)
764 if (mount_tmp_created)
767 if (mount_slave_mounted)
769 if (mount_slave_created)
775 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
776 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
777 MachineOperation *o = userdata;
785 if (si->si_code != CLD_EXITED) {
786 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
790 if (si->si_status != EXIT_SUCCESS) {
791 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
792 r = sd_bus_error_set_errnof(&error, r, "%m");
794 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
799 r = sd_bus_reply_method_return(o->message, NULL);
801 log_error_errno(r, "Failed to reply to message: %m");
803 machine_operation_unref(o);
807 r = sd_bus_reply_method_error(o->message, &error);
809 log_error_errno(r, "Failed to reply to message: %m");
811 machine_operation_unref(o);
815 int bus_machine_method_copy(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
816 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
817 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
818 _cleanup_close_ int hostfd = -1;
819 Machine *m = userdata;
826 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
827 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
829 if (m->class != MACHINE_CONTAINER)
830 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
832 r = sd_bus_message_read(message, "ss", &src, &dest);
836 if (!path_is_absolute(src) || !path_is_safe(src))
837 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
841 else if (!path_is_absolute(dest) || !path_is_safe(dest))
842 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
844 r = bus_verify_polkit_async(
847 "org.freedesktop.machine1.manage-machines",
850 &m->manager->polkit_registry,
855 return 1; /* Will call us back */
857 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
860 container_path = src;
864 container_path = dest;
867 host_basename = basename(host_path);
868 t = strdupa(host_path);
869 host_dirname = dirname(t);
871 container_basename = basename(container_path);
872 t = strdupa(container_path);
873 container_dirname = dirname(t);
875 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
877 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
879 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
880 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
884 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
891 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
893 q = procfs_file_alloca(m->leader, "ns/mnt");
894 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
896 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
900 if (setns(mntfd, CLONE_NEWNS) < 0) {
901 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
905 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
906 if (containerfd < 0) {
907 r = log_error_errno(errno, "Failed top open destination directory: %m");
912 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
914 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
916 hostfd = safe_close(hostfd);
917 containerfd = safe_close(containerfd);
920 r = log_error_errno(r, "Failed to copy tree: %m");
927 (void) write(errno_pipe_fd[1], &r, sizeof(r));
928 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
933 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
935 /* Copying might take a while, hence install a watch the
936 * child, and return */
938 o = new0(MachineOperation, 1);
943 o->message = sd_bus_message_ref(message);
944 o->errno_fd = errno_pipe_fd[0];
945 errno_pipe_fd[0] = -1;
947 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
949 machine_operation_unref(o);
953 LIST_PREPEND(operations, m->operations, o);
960 const sd_bus_vtable machine_vtable[] = {
961 SD_BUS_VTABLE_START(0),
962 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
963 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
964 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
965 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
966 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
967 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
968 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
969 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
970 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
971 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
972 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
973 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_UNPRIVILEGED),
974 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED),
975 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
976 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
977 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
978 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
979 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED),
980 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
981 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, SD_BUS_VTABLE_UNPRIVILEGED),
985 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
986 Manager *m = userdata;
996 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
997 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
998 sd_bus_message *message;
1001 message = sd_bus_get_current_message(bus);
1005 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
1009 r = sd_bus_creds_get_pid(creds, &pid);
1013 r = manager_get_machine_by_pid(m, pid, &machine);
1017 _cleanup_free_ char *e = NULL;
1020 p = startswith(path, "/org/freedesktop/machine1/machine/");
1024 e = bus_label_unescape(p);
1028 machine = hashmap_get(m->machines, e);
1037 char *machine_bus_path(Machine *m) {
1038 _cleanup_free_ char *e = NULL;
1042 e = bus_label_escape(m->name);
1046 return strappend("/org/freedesktop/machine1/machine/", e);
1049 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1050 _cleanup_strv_free_ char **l = NULL;
1051 Machine *machine = NULL;
1052 Manager *m = userdata;
1060 HASHMAP_FOREACH(machine, m->machines, i) {
1063 p = machine_bus_path(machine);
1067 r = strv_consume(&l, p);
1078 int machine_send_signal(Machine *m, bool new_machine) {
1079 _cleanup_free_ char *p = NULL;
1083 p = machine_bus_path(m);
1087 return sd_bus_emit_signal(
1089 "/org/freedesktop/machine1",
1090 "org.freedesktop.machine1.Manager",
1091 new_machine ? "MachineNew" : "MachineRemoved",
1095 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1096 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1097 _cleanup_free_ char *p = NULL;
1101 if (!m->create_message)
1104 c = m->create_message;
1105 m->create_message = NULL;
1108 return sd_bus_reply_method_error(c, error);
1110 /* Update the machine state file before we notify the client
1111 * about the result. */
1114 p = machine_bus_path(m);
1118 return sd_bus_reply_method_return(c, "o", p);