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;
135 return sd_bus_reply_method_return(message, NULL);
138 int bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
139 Machine *m = userdata;
149 r = sd_bus_message_read(message, "si", &swho, &signo);
156 who = kill_who_from_string(swho);
158 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
161 if (signo <= 0 || signo >= _NSIG)
162 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
164 r = machine_kill(m, who, signo);
168 return sd_bus_reply_method_return(message, NULL);
171 int bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
172 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
173 _cleanup_close_pair_ int pair[2] = { -1, -1 };
174 _cleanup_free_ char *us = NULL, *them = NULL;
175 _cleanup_close_ int netns_fd = -1;
176 Machine *m = userdata;
186 if (m->class != MACHINE_CONTAINER)
187 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
189 r = readlink_malloc("/proc/self/ns/net", &us);
193 p = procfs_file_alloca(m->leader, "ns/net");
194 r = readlink_malloc(p, &them);
199 return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
201 r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
205 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
210 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
213 _cleanup_free_ struct local_address *addresses = NULL;
214 struct local_address *a;
217 pair[0] = safe_close(pair[0]);
219 r = namespace_enter(-1, -1, netns_fd, -1);
223 n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
227 for (a = addresses, i = 0; i < n; a++, i++) {
228 struct iovec iov[2] = {
229 { .iov_base = &a->family, .iov_len = sizeof(a->family) },
230 { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
233 r = writev(pair[1], iov, 2);
238 pair[1] = safe_close(pair[1]);
243 pair[1] = safe_close(pair[1]);
245 r = sd_bus_message_new_method_return(message, &reply);
249 r = sd_bus_message_open_container(reply, 'a', "(iay)");
256 union in_addr_union in_addr;
263 iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
264 iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
266 n = recvmsg(pair[0], &mh, 0);
269 if ((size_t) n < sizeof(family))
272 r = sd_bus_message_open_container(reply, 'r', "iay");
276 r = sd_bus_message_append(reply, "i", family);
283 if (n != sizeof(struct in_addr) + sizeof(family))
286 r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
290 if (n != sizeof(struct in6_addr) + sizeof(family))
293 r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
299 r = sd_bus_message_close_container(reply);
304 r = wait_for_terminate(child, &si);
306 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
307 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
308 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
310 r = sd_bus_message_close_container(reply);
314 return sd_bus_send(bus, reply, NULL);
317 int bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
318 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
319 _cleanup_close_ int mntns_fd = -1, root_fd = -1;
320 _cleanup_close_pair_ int pair[2] = { -1, -1 };
321 _cleanup_strv_free_ char **l = NULL;
322 _cleanup_fclose_ FILE *f = NULL;
323 Machine *m = userdata;
333 if (m->class != MACHINE_CONTAINER)
334 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
336 r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
340 if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
345 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
348 _cleanup_close_ int fd = -1;
350 pair[0] = safe_close(pair[0]);
352 r = namespace_enter(-1, mntns_fd, -1, root_fd);
356 fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
358 fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
363 r = copy_bytes(fd, pair[1], (off_t) -1, false);
370 pair[1] = safe_close(pair[1]);
372 f = fdopen(pair[0], "re");
378 r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
382 r = wait_for_terminate(child, &si);
384 return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
385 if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
386 return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
388 r = sd_bus_message_new_method_return(message, &reply);
392 r = sd_bus_message_open_container(reply, 'a', "{ss}");
396 STRV_FOREACH_PAIR(k, v, l) {
397 r = sd_bus_message_append(reply, "{ss}", *k, *v);
402 r = sd_bus_message_close_container(reply);
406 return sd_bus_send(bus, reply, NULL);
409 int bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
410 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
411 _cleanup_free_ char *pty_name = NULL;
412 _cleanup_close_ int master = -1;
413 Machine *m = userdata;
420 if (m->class != MACHINE_CONTAINER)
421 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
423 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
427 r = ptsname_malloc(master, &pty_name);
431 r = sd_bus_message_new_method_return(message, &reply);
435 r = sd_bus_message_append(reply, "hs", master, pty_name);
439 return sd_bus_send(bus, reply, NULL);
442 int bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
443 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
444 _cleanup_free_ char *pty_name = NULL, *getty = NULL;
445 _cleanup_bus_unref_ sd_bus *container_bus = NULL;
446 _cleanup_close_ int master = -1;
447 Machine *m = userdata;
451 if (m->class != MACHINE_CONTAINER)
452 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
454 r = bus_verify_polkit_async(
457 "org.freedesktop.machine1.login",
459 &m->manager->polkit_registry,
464 return 1; /* Will call us back */
466 master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
470 r = ptsname_malloc(master, &pty_name);
474 p = path_startswith(pty_name, "/dev/pts/");
476 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "PTS name %s is invalid", pty_name);
478 if (unlockpt(master) < 0)
481 r = sd_bus_new(&container_bus);
486 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
488 asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT, m->leader);
490 if (!container_bus->address)
493 container_bus->bus_client = true;
494 container_bus->trusted = false;
495 container_bus->is_system = true;
497 r = sd_bus_start(container_bus);
501 getty = strjoin("container-getty@", p, ".service", NULL);
505 r = sd_bus_call_method(
507 "org.freedesktop.systemd1",
508 "/org/freedesktop/systemd1",
509 "org.freedesktop.systemd1.Manager",
512 "ss", getty, "replace");
516 container_bus = sd_bus_unref(container_bus);
518 r = sd_bus_message_new_method_return(message, &reply);
522 r = sd_bus_message_append(reply, "hs", master, pty_name);
526 return sd_bus_send(bus, reply, NULL);
529 int bus_machine_method_bind_mount(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
530 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
531 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
532 bool mount_slave_created = false, mount_slave_mounted = false,
533 mount_tmp_created = false, mount_tmp_mounted = false,
534 mount_outside_created = false, mount_outside_mounted = false;
535 const char *dest, *src;
536 Machine *m = userdata;
537 int read_only, make_directory;
542 if (m->class != MACHINE_CONTAINER)
543 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
545 r = sd_bus_message_read(message, "ssbb", &src, &dest, &read_only, &make_directory);
549 if (!path_is_absolute(src) || !path_is_safe(src))
550 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
554 else if (!path_is_absolute(dest) || !path_is_safe(dest))
555 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
557 /* One day, when bind mounting /proc/self/fd/n works across
558 * namespace boundaries we should rework this logic to make
561 p = strjoina("/run/systemd/nspawn/propagate/", m->name, "/");
562 if (laccess(p, F_OK) < 0)
563 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
565 /* Our goal is to install a new bind mount into the container,
566 possibly read-only. This is irritatingly complex
567 unfortunately, currently.
569 First, we start by creating a private playground in /tmp,
570 that we can mount MS_SLAVE. (Which is necessary, since
571 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
574 if (!mkdtemp(mount_slave))
575 return sd_bus_error_set_errnof(error, errno, "Failed to create playground %s: %m", mount_slave);
577 mount_slave_created = true;
579 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
580 r = sd_bus_error_set_errnof(error, errno, "Failed to make bind mount %s: %m", mount_slave);
584 mount_slave_mounted = true;
586 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
587 r = sd_bus_error_set_errnof(error, errno, "Failed to remount slave %s: %m", mount_slave);
591 /* Second, we mount the source directory to a directory inside
592 of our MS_SLAVE playground. */
593 mount_tmp = strjoina(mount_slave, "/mount");
594 if (mkdir(mount_tmp, 0700) < 0) {
595 r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
599 mount_tmp_created = true;
601 if (mount(src, mount_tmp, NULL, MS_BIND, NULL) < 0) {
602 r = sd_bus_error_set_errnof(error, errno, "Failed to overmount %s: %m", mount_tmp);
606 mount_tmp_mounted = true;
608 /* Third, we remount the new bind mount read-only if requested. */
610 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
611 r = sd_bus_error_set_errnof(error, errno, "Failed to remount read-only %s: %m", mount_tmp);
615 /* Fourth, we move the new bind mount into the propagation
616 * directory. This way it will appear there read-only
619 mount_outside = strjoina("/run/systemd/nspawn/propagate/", m->name, "/XXXXXX");
620 if (!mkdtemp(mount_outside)) {
621 r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
625 mount_outside_created = true;
627 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
628 r = sd_bus_error_set_errnof(error, errno, "Failed to move %s to %s: %m", mount_tmp, mount_outside);
632 mount_outside_mounted = true;
633 mount_tmp_mounted = false;
635 (void) rmdir(mount_tmp);
636 mount_tmp_created = false;
638 (void) umount(mount_slave);
639 mount_slave_mounted = false;
641 (void) rmdir(mount_slave);
642 mount_slave_created = false;
644 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0) {
645 r = sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
651 r = sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
656 const char *mount_inside;
660 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
662 q = procfs_file_alloca(m->leader, "ns/mnt");
663 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
665 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
669 if (setns(mntfd, CLONE_NEWNS) < 0) {
670 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
675 (void) mkdir_p(dest, 0755);
677 /* Fifth, move the mount to the right place inside */
678 mount_inside = strjoina("/run/systemd/nspawn/incoming/", basename(mount_outside));
679 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
680 r = log_error_errno(errno, "Failed to mount: %m");
687 (void) write(errno_pipe_fd[1], &r, sizeof(r));
688 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
693 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
695 r = wait_for_terminate(child, &si);
697 r = sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
700 if (si.si_code != CLD_EXITED) {
701 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
704 if (si.si_status != EXIT_SUCCESS) {
706 if (read(errno_pipe_fd[0], &r, sizeof(r)) == sizeof(r))
707 r = sd_bus_error_set_errnof(error, r, "Failed to mount: %m");
709 r = sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client failed.");
713 r = sd_bus_reply_method_return(message, NULL);
716 if (mount_outside_mounted)
717 umount(mount_outside);
718 if (mount_outside_created)
719 rmdir(mount_outside);
721 if (mount_tmp_mounted)
723 if (mount_tmp_created)
726 if (mount_slave_mounted)
728 if (mount_slave_created)
734 static int machine_operation_done(sd_event_source *s, const siginfo_t *si, void *userdata) {
735 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
736 MachineOperation *o = userdata;
744 if (si->si_code != CLD_EXITED) {
745 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
749 if (si->si_status != EXIT_SUCCESS) {
750 if (read(o->errno_fd, &r, sizeof(r)) == sizeof(r))
751 r = sd_bus_error_set_errnof(&error, r, "%m");
753 r = sd_bus_error_setf(&error, SD_BUS_ERROR_FAILED, "Client failed.");
758 r = sd_bus_reply_method_return(o->message, NULL);
760 log_error_errno(r, "Failed to reply to message: %m");
762 machine_operation_unref(o);
766 r = sd_bus_reply_method_error(o->message, &error);
768 log_error_errno(r, "Failed to reply to message: %m");
770 machine_operation_unref(o);
774 int bus_machine_method_copy(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
775 const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
776 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
777 _cleanup_close_ int hostfd = -1;
778 Machine *m = userdata;
785 if (m->n_operations >= MACHINE_OPERATIONS_MAX)
786 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing copies.");
788 if (m->class != MACHINE_CONTAINER)
789 return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
791 r = sd_bus_message_read(message, "ss", &src, &dest);
795 if (!path_is_absolute(src) || !path_is_safe(src))
796 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
800 else if (!path_is_absolute(dest) || !path_is_safe(dest))
801 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
803 copy_from = strstr(sd_bus_message_get_member(message), "CopyFrom");
806 container_path = src;
810 container_path = dest;
813 host_basename = basename(host_path);
814 t = strdupa(host_path);
815 host_dirname = dirname(t);
817 container_basename = basename(container_path);
818 t = strdupa(container_path);
819 container_dirname = dirname(t);
821 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
823 return sd_bus_error_set_errnof(error, errno, "Failed to open host directory %s: %m", host_dirname);
825 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
826 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
830 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
837 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
839 q = procfs_file_alloca(m->leader, "ns/mnt");
840 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
842 r = log_error_errno(errno, "Failed to open mount namespace of leader: %m");
846 if (setns(mntfd, CLONE_NEWNS) < 0) {
847 r = log_error_errno(errno, "Failed to join namespace of leader: %m");
851 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
852 if (containerfd < 0) {
853 r = log_error_errno(errno, "Failed top open destination directory: %m");
858 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
860 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
862 hostfd = safe_close(hostfd);
863 containerfd = safe_close(containerfd);
866 r = log_error_errno(r, "Failed to copy tree: %m");
873 (void) write(errno_pipe_fd[1], &r, sizeof(r));
874 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
879 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
881 /* Copying might take a while, hence install a watch the
882 * child, and return */
884 o = new0(MachineOperation, 1);
889 o->message = sd_bus_message_ref(message);
890 o->errno_fd = errno_pipe_fd[0];
891 errno_pipe_fd[0] = -1;
893 r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
895 machine_operation_unref(o);
899 LIST_PREPEND(operations, m->operations, o);
906 const sd_bus_vtable machine_vtable[] = {
907 SD_BUS_VTABLE_START(0),
908 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Machine, name), SD_BUS_VTABLE_PROPERTY_CONST),
909 SD_BUS_PROPERTY("Id", "ay", property_get_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
910 BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
911 SD_BUS_PROPERTY("Service", "s", NULL, offsetof(Machine, service), SD_BUS_VTABLE_PROPERTY_CONST),
912 SD_BUS_PROPERTY("Unit", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST),
913 SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
914 SD_BUS_PROPERTY("Leader", "u", NULL, offsetof(Machine, leader), SD_BUS_VTABLE_PROPERTY_CONST),
915 SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
916 SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
917 SD_BUS_PROPERTY("NetworkInterfaces", "ai", property_get_netif, 0, SD_BUS_VTABLE_PROPERTY_CONST),
918 SD_BUS_PROPERTY("State", "s", property_get_state, 0, 0),
919 SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
920 SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
921 SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
922 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
923 SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0),
924 SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED),
925 SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, 0),
926 SD_BUS_METHOD("CopyFrom", "ss", NULL, bus_machine_method_copy, 0),
927 SD_BUS_METHOD("CopyTo", "ss", NULL, bus_machine_method_copy, 0),
931 int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
932 Manager *m = userdata;
942 if (streq(path, "/org/freedesktop/machine1/machine/self")) {
943 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
944 sd_bus_message *message;
947 message = sd_bus_get_current_message(bus);
951 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
955 r = sd_bus_creds_get_pid(creds, &pid);
959 r = manager_get_machine_by_pid(m, pid, &machine);
963 _cleanup_free_ char *e = NULL;
966 p = startswith(path, "/org/freedesktop/machine1/machine/");
970 e = bus_label_unescape(p);
974 machine = hashmap_get(m->machines, e);
983 char *machine_bus_path(Machine *m) {
984 _cleanup_free_ char *e = NULL;
988 e = bus_label_escape(m->name);
992 return strappend("/org/freedesktop/machine1/machine/", e);
995 int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
996 _cleanup_strv_free_ char **l = NULL;
997 Machine *machine = NULL;
998 Manager *m = userdata;
1006 HASHMAP_FOREACH(machine, m->machines, i) {
1009 p = machine_bus_path(machine);
1013 r = strv_consume(&l, p);
1024 int machine_send_signal(Machine *m, bool new_machine) {
1025 _cleanup_free_ char *p = NULL;
1029 p = machine_bus_path(m);
1033 return sd_bus_emit_signal(
1035 "/org/freedesktop/machine1",
1036 "org.freedesktop.machine1.Manager",
1037 new_machine ? "MachineNew" : "MachineRemoved",
1041 int machine_send_create_reply(Machine *m, sd_bus_error *error) {
1042 _cleanup_bus_message_unref_ sd_bus_message *c = NULL;
1043 _cleanup_free_ char *p = NULL;
1047 if (!m->create_message)
1050 c = m->create_message;
1051 m->create_message = NULL;
1054 return sd_bus_reply_method_error(c, error);
1056 /* Update the machine state file before we notify the client
1057 * about the result. */
1060 p = machine_bus_path(m);
1064 return sd_bus_reply_method_return(c, "o", p);