machine-dbus.c revision 0370612e0522191f929e3feb7d4937fff3d421e2
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering This file is part of systemd.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Copyright 2011 Lennart Poettering
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is free software; you can redistribute it and/or modify it
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering under the terms of the GNU Lesser General Public License as published by
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering (at your option) any later version.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering systemd is distributed in the hope that it will be useful, but
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering Lesser General Public License for more details.
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering You should have received a copy of the GNU Lesser General Public License
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering/* When we include libgen.h because we need dirname() we immediately
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering * undefine basename() since libgen.h defines it as a macro to the XDG
afc5dbf37fd2399d37976388d9dd9ab470ecf446Lennart Poettering * version which is really broken. */
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &m->id, 16);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering state = machine_state_to_string(machine_get_state(m));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append_basic(reply, 's', state);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering assert_cc(sizeof(int) == sizeof(int32_t));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append_array(reply, 'i', m->netif, m->n_netif * sizeof(int));
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringstatic BUS_DEFINE_PROPERTY_GET_ENUM(property_get_class, machine_class, MachineClass);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringint bus_machine_method_terminate(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return sd_bus_reply_method_return(message, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringint bus_machine_method_kill(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_read(message, "si", &swho, &signo);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_reply_method_return(message, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringint bus_machine_method_get_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_close_pair_ int pair[2] = { -1, -1 };
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ char *us = NULL, *them = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering const char *p;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = readlink_malloc("/proc/self/ns/net", &us);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering p = procfs_file_alloca(m->leader, "ns/net");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_free_ struct local_address *addresses = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = namespace_enter(-1, -1, netns_fd, -1);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering n = local_addresses(NULL, 0, AF_UNSPEC, &addresses);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering for (a = addresses, i = 0; i < n; a++, i++) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering { .iov_base = &a->family, .iov_len = sizeof(a->family) },
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) },
e88baee88fad8bc59d33b55a7a2d640ef9e16cd6Zbigniew Jędrzejewski-Szmek r = sd_bus_message_new_method_return(message, &reply);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "(iay)");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) };
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) };
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_open_container(reply, 'r', "iay");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_append(reply, "i", family);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (n != sizeof(struct in_addr) + sizeof(family))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (n != sizeof(struct in6_addr) + sizeof(family))
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6));
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_close_container(reply);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering r = sd_bus_message_close_container(reply);
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poetteringint bus_machine_method_get_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_close_ int mntns_fd = -1, root_fd = -1;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_close_pair_ int pair[2] = { -1, -1 };
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering char **k, **v;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = namespace_open(m->leader, NULL, &mntns_fd, NULL, &root_fd);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0)
5809560d858f45351856d6fe786a8117306dd0f2Lennart Poettering return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = namespace_enter(-1, mntns_fd, -1, root_fd);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC);
d054f0a4d451120c26494263fc4dc175bfd405b1Daniel Mack fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC);
8457f8d6ac7adc6c6ef31378e6e7761cce522141Lennart Poettering r = copy_bytes(fd, pair[1], (off_t) -1, false);
63c372cb9df3bee01e3bf8cd7f96f336bddda846Lennart Poettering r = load_env_file_pairs(f, "/etc/os-release", NULL, &l);
968f319679d9069af037240d0c3bcd126181cdacZbigniew Jędrzejewski-Szmek r = wait_for_terminate(child, &si);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
3b3154df7e2773332bb814e167187367a0ccae4aLennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_new_method_return(message, &reply);
46b131574fdd7d77c15a0919ca9010cad7aa6ac7Lennart Poettering r = sd_bus_message_open_container(reply, 'a', "{ss}");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append(reply, "{ss}", *k, *v);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_close_container(reply);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poetteringint bus_machine_method_open_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines.");
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC);
48cef29504b1ffc0df9929f2d8b2af2ad74d2b4aVito Caputo r = sd_bus_message_new_method_return(message, &reply);
35e2e347d38cc2f8bd7c38a0d8a5129f5fbb0ab9Lennart Poettering r = sd_bus_message_append(reply, "hs", master, pty_name);
178cc7700c23ac088cd7190d7854282075028d91Lennart Poetteringint bus_machine_method_open_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering _cleanup_free_ char *pty_name = NULL, *getty = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering _cleanup_bus_unref_ sd_bus *container_bus = NULL;
178cc7700c23ac088cd7190d7854282075028d91Lennart Poettering const char *p;
8a03c9ef744e13dc700a7e7ca6cae8afdcf0d71cZbigniew Jędrzejewski-Szmek if (m->class != MACHINE_CONTAINER)
8a03c9ef744e13dc700a7e7ca6cae8afdcf0d71cZbigniew Jędrzejewski-Szmek return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines.");
error);
if (master < 0)
return master;
return -errno;
#ifdef ENABLE_KDBUS
asprintf(&container_bus->address, "x-machine-kernel:pid=" PID_FMT ";x-machine-unix:pid=" PID_FMT, m->leader, m->leader);
return log_oom();
if (!getty)
return log_oom();
r = sd_bus_call_method(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
int bus_machine_method_bind_mount(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Bind mounting is only supported on container machines.");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Container does not allow propagation of mount points.");
mount_slave_created = true;
goto finish;
mount_slave_mounted = true;
goto finish;
r = sd_bus_error_set_errnof(error, errno, "Failed to create temporary mount point %s: %m", mount_tmp);
goto finish;
mount_tmp_created = true;
goto finish;
mount_tmp_mounted = true;
if (read_only)
goto finish;
r = sd_bus_error_set_errnof(error, errno, "Cannot create propagation directory %s: %m", mount_outside);
goto finish;
mount_outside_created = true;
goto finish;
mount_outside_mounted = true;
mount_tmp_mounted = false;
mount_tmp_created = false;
mount_slave_mounted = false;
mount_slave_created = false;
goto finish;
if (child < 0) {
goto finish;
if (child == 0) {
const char *mount_inside;
int mntfd;
if (mntfd < 0) {
goto child_fail;
goto child_fail;
if (make_directory)
goto child_fail;
goto finish;
goto finish;
goto finish;
if (mount_tmp_mounted)
if (mount_tmp_created)
if (mount_slave_mounted)
if (mount_slave_created)
assert(o);
o->pid = 0;
goto fail;
goto fail;
fail:
int bus_machine_method_copy(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
const char *src, *dest, *host_path, *container_path, *host_basename, *host_dirname, *container_basename, *container_dirname;
MachineOperation *o;
bool copy_from;
return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Copying files is only supported on container machines.");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Source path must be absolute and not contain ../.");
return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Destination path must be absolute and not contain ../.");
if (copy_from) {
if (child < 0)
if (child == 0) {
int containerfd;
int mntfd;
if (mntfd < 0) {
goto child_fail;
goto child_fail;
if (containerfd < 0) {
goto child_fail;
if (copy_from)
goto child_fail;
return log_oom();
r = sd_event_add_child(m->manager->event, &o->event_source, child, WEXITED, machine_operation_done, o);
return log_oom();
m->n_operations++;
o->machine = m;
BUS_PROPERTY_DUAL_TIMESTAMP("Timestamp", offsetof(Machine, timestamp), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("Scope", "s", NULL, offsetof(Machine, unit), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN),
SD_BUS_PROPERTY("Class", "s", property_get_class, offsetof(Machine, class), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_PROPERTY("RootDirectory", "s", NULL, offsetof(Machine, root_directory), SD_BUS_VTABLE_PROPERTY_CONST),
SD_BUS_METHOD("Terminate", NULL, NULL, bus_machine_method_terminate, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
SD_BUS_METHOD("GetAddresses", NULL, "a(iay)", bus_machine_method_get_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_machine_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
int machine_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
assert(m);
if (!message)
e = bus_label_unescape(p);
return -ENOMEM;
if (!machine)
assert(m);
return NULL;
int machine_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
Iterator i;
return -ENOMEM;
r = strv_consume(&l, p);
*nodes = l;
l = NULL;
assert(m);
p = machine_bus_path(m);
return -ENOMEM;
return sd_bus_emit_signal(
"/org/freedesktop/machine1",
assert(m);
if (!m->create_message)
c = m->create_message;
if (error)
machine_save(m);
p = machine_bus_path(m);
return -ENOMEM;