diff options
author | Lennart Poettering <lennart@poettering.net> | 2015-08-24 21:05:09 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2015-08-24 22:46:45 +0200 |
commit | fbe550738d03b178bb004a1390e74115e904118a (patch) | |
tree | a4a281a5c7d7fb95ad409ba424eb2a430f1cc664 /src/machine | |
parent | b9a8d250810d4803bc9bf6b36932b528cb991d1e (diff) | |
download | systemd-fbe550738d03b178bb004a1390e74115e904118a.tar.gz systemd-fbe550738d03b178bb004a1390e74115e904118a.tar.bz2 systemd-fbe550738d03b178bb004a1390e74115e904118a.zip |
machined: introduce pseudo-machine ".host" refererring to the host system
Some of the operations machined/machinectl implement are also very
useful when applied to the host system (such as machinectl login,
machinectl shell or machinectl status), hence introduce a pseudo-machine
by the name of ".host" in machined that refers to the host system, and
may be used top execute operations on the host system with.
This copies the pseudo-image ".host" machined already implements for
image related commands.
(This commit also adds a PK privilege for opening a PTY in a container,
which was previously not accessible for non-root.)
Diffstat (limited to 'src/machine')
-rw-r--r-- | src/machine/machine-dbus.c | 416 | ||||
-rw-r--r-- | src/machine/machine.c | 67 | ||||
-rw-r--r-- | src/machine/machine.h | 5 | ||||
-rw-r--r-- | src/machine/machinectl.c | 6 | ||||
-rw-r--r-- | src/machine/machined-dbus.c | 2 | ||||
-rw-r--r-- | src/machine/machined.c | 47 | ||||
-rw-r--r-- | src/machine/machined.h | 2 | ||||
-rw-r--r-- | src/machine/org.freedesktop.machine1.policy.in | 10 |
8 files changed, 367 insertions, 188 deletions
diff --git a/src/machine/machine-dbus.c b/src/machine/machine-dbus.c index ad3dd8facf..b89bb2cba1 100644 --- a/src/machine/machine-dbus.c +++ b/src/machine/machine-dbus.c @@ -186,141 +186,179 @@ int bus_machine_method_kill(sd_bus_message *message, void *userdata, sd_bus_erro int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_close_pair_ int pair[2] = { -1, -1 }; - _cleanup_free_ char *us = NULL, *them = NULL; - _cleanup_close_ int netns_fd = -1; Machine *m = userdata; - const char *p; - siginfo_t si; - pid_t child; int r; assert(message); assert(m); - if (m->class != MACHINE_CONTAINER) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines."); - - r = readlink_malloc("/proc/self/ns/net", &us); - if (r < 0) - return r; - - p = procfs_file_alloca(m->leader, "ns/net"); - r = readlink_malloc(p, &them); + r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; - if (streq(us, them)) - return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name); - - r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL); + r = sd_bus_message_open_container(reply, 'a', "(iay)"); if (r < 0) return r; - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) - return -errno; - - child = fork(); - if (child < 0) - return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + switch (m->class) { - if (child == 0) { + case MACHINE_HOST: { _cleanup_free_ struct local_address *addresses = NULL; struct local_address *a; - int i, n; - - pair[0] = safe_close(pair[0]); - - r = namespace_enter(-1, -1, netns_fd, -1, -1); - if (r < 0) - _exit(EXIT_FAILURE); + int n, i; n = local_addresses(NULL, 0, AF_UNSPEC, &addresses); if (n < 0) - _exit(EXIT_FAILURE); + return n; for (a = addresses, i = 0; i < n; a++, i++) { - struct iovec iov[2] = { - { .iov_base = &a->family, .iov_len = sizeof(a->family) }, - { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) }, - }; - r = writev(pair[1], iov, 2); + r = sd_bus_message_open_container(reply, 'r', "iay"); if (r < 0) - _exit(EXIT_FAILURE); - } - - pair[1] = safe_close(pair[1]); + return r; - _exit(EXIT_SUCCESS); - } - - pair[1] = safe_close(pair[1]); + r = sd_bus_message_append(reply, "i", addresses[i].family); + if (r < 0) + return r; - r = sd_bus_message_new_method_return(message, &reply); - if (r < 0) - return r; + r = sd_bus_message_append_array(reply, 'y', &addresses[i].address, FAMILY_ADDRESS_SIZE(addresses[i].family)); + if (r < 0) + return r; - r = sd_bus_message_open_container(reply, 'a', "(iay)"); - if (r < 0) - return r; + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } - for (;;) { - int family; - ssize_t n; - union in_addr_union in_addr; - struct iovec iov[2]; - struct msghdr mh = { - .msg_iov = iov, - .msg_iovlen = 2, - }; + break; + } - iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) }; - iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) }; + case MACHINE_CONTAINER: { + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + _cleanup_free_ char *us = NULL, *them = NULL; + _cleanup_close_ int netns_fd = -1; + const char *p; + siginfo_t si; + pid_t child; - n = recvmsg(pair[0], &mh, 0); - if (n < 0) - return -errno; - if ((size_t) n < sizeof(family)) - break; + r = readlink_malloc("/proc/self/ns/net", &us); + if (r < 0) + return r; - r = sd_bus_message_open_container(reply, 'r', "iay"); + p = procfs_file_alloca(m->leader, "ns/net"); + r = readlink_malloc(p, &them); if (r < 0) return r; - r = sd_bus_message_append(reply, "i", family); + if (streq(us, them)) + return sd_bus_error_setf(error, BUS_ERROR_NO_PRIVATE_NETWORKING, "Machine %s does not use private networking", m->name); + + r = namespace_open(m->leader, NULL, NULL, &netns_fd, NULL, NULL); if (r < 0) return r; - switch (family) { + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) + return -errno; + + child = fork(); + if (child < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + + if (child == 0) { + _cleanup_free_ struct local_address *addresses = NULL; + struct local_address *a; + int i, n; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(-1, -1, netns_fd, -1, -1); + if (r < 0) + _exit(EXIT_FAILURE); - case AF_INET: - if (n != sizeof(struct in_addr) + sizeof(family)) - return -EIO; + n = local_addresses(NULL, 0, AF_UNSPEC, &addresses); + if (n < 0) + _exit(EXIT_FAILURE); - r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in)); - break; + for (a = addresses, i = 0; i < n; a++, i++) { + struct iovec iov[2] = { + { .iov_base = &a->family, .iov_len = sizeof(a->family) }, + { .iov_base = &a->address, .iov_len = FAMILY_ADDRESS_SIZE(a->family) }, + }; - case AF_INET6: - if (n != sizeof(struct in6_addr) + sizeof(family)) - return -EIO; + r = writev(pair[1], iov, 2); + if (r < 0) + _exit(EXIT_FAILURE); + } - r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6)); - break; + pair[1] = safe_close(pair[1]); + + _exit(EXIT_SUCCESS); } - if (r < 0) - return r; - r = sd_bus_message_close_container(reply); + pair[1] = safe_close(pair[1]); + + for (;;) { + int family; + ssize_t n; + union in_addr_union in_addr; + struct iovec iov[2]; + struct msghdr mh = { + .msg_iov = iov, + .msg_iovlen = 2, + }; + + iov[0] = (struct iovec) { .iov_base = &family, .iov_len = sizeof(family) }; + iov[1] = (struct iovec) { .iov_base = &in_addr, .iov_len = sizeof(in_addr) }; + + n = recvmsg(pair[0], &mh, 0); + if (n < 0) + return -errno; + if ((size_t) n < sizeof(family)) + break; + + r = sd_bus_message_open_container(reply, 'r', "iay"); + if (r < 0) + return r; + + r = sd_bus_message_append(reply, "i", family); + if (r < 0) + return r; + + switch (family) { + + case AF_INET: + if (n != sizeof(struct in_addr) + sizeof(family)) + return -EIO; + + r = sd_bus_message_append_array(reply, 'y', &in_addr.in, sizeof(in_addr.in)); + break; + + case AF_INET6: + if (n != sizeof(struct in6_addr) + sizeof(family)) + return -EIO; + + r = sd_bus_message_append_array(reply, 'y', &in_addr.in6, sizeof(in_addr.in6)); + break; + } + if (r < 0) + return r; + + r = sd_bus_message_close_container(reply); + if (r < 0) + return r; + } + + r = wait_for_terminate(child, &si); if (r < 0) - return r; + return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m"); + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally."); + break; } - r = wait_for_terminate(child, &si); - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m"); - if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) - return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally."); + default: + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting IP address data is only supported on container machines."); + } r = sd_bus_message_close_container(reply); if (r < 0) @@ -331,73 +369,88 @@ int bus_machine_method_get_addresses(sd_bus_message *message, void *userdata, sd int bus_machine_method_get_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; - _cleanup_close_ int mntns_fd = -1, root_fd = -1; - _cleanup_close_pair_ int pair[2] = { -1, -1 }; _cleanup_strv_free_ char **l = NULL; - _cleanup_fclose_ FILE *f = NULL; Machine *m = userdata; char **k, **v; - siginfo_t si; - pid_t child; int r; assert(message); assert(m); - if (m->class != MACHINE_CONTAINER) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines."); + switch (m->class) { - r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd); - if (r < 0) - return r; + case MACHINE_HOST: + r = load_env_file_pairs(NULL, "/etc/os-release", NULL, &l); + if (r < 0) + return r; - if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) - return -errno; + break; - child = fork(); - if (child < 0) - return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + case MACHINE_CONTAINER: { + _cleanup_close_ int mntns_fd = -1, root_fd = -1; + _cleanup_close_pair_ int pair[2] = { -1, -1 }; + _cleanup_fclose_ FILE *f = NULL; + siginfo_t si; + pid_t child; - if (child == 0) { - _cleanup_close_ int fd = -1; + r = namespace_open(m->leader, NULL, &mntns_fd, NULL, NULL, &root_fd); + if (r < 0) + return r; - pair[0] = safe_close(pair[0]); + if (socketpair(AF_UNIX, SOCK_SEQPACKET, 0, pair) < 0) + return -errno; - r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); - if (r < 0) - _exit(EXIT_FAILURE); + child = fork(); + if (child < 0) + return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m"); + + if (child == 0) { + _cleanup_close_ int fd = -1; + + pair[0] = safe_close(pair[0]); + + r = namespace_enter(-1, mntns_fd, -1, -1, root_fd); + if (r < 0) + _exit(EXIT_FAILURE); + + fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC); + if (fd < 0) { + fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC); + if (fd < 0) + _exit(EXIT_FAILURE); + } - fd = open("/etc/os-release", O_RDONLY|O_CLOEXEC); - if (fd < 0) { - fd = open("/usr/lib/os-release", O_RDONLY|O_CLOEXEC); - if (fd < 0) + r = copy_bytes(fd, pair[1], (off_t) -1, false); + if (r < 0) _exit(EXIT_FAILURE); + + _exit(EXIT_SUCCESS); } - r = copy_bytes(fd, pair[1], (off_t) -1, false); - if (r < 0) - _exit(EXIT_FAILURE); + pair[1] = safe_close(pair[1]); - _exit(EXIT_SUCCESS); - } + f = fdopen(pair[0], "re"); + if (!f) + return -errno; - pair[1] = safe_close(pair[1]); + pair[0] = -1; - f = fdopen(pair[0], "re"); - if (!f) - return -errno; + r = load_env_file_pairs(f, "/etc/os-release", NULL, &l); + if (r < 0) + return r; - pair[0] = -1; + r = wait_for_terminate(child, &si); + if (r < 0) + return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m"); + if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) + return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally."); - r = load_env_file_pairs(f, "/etc/os-release", NULL, &l); - if (r < 0) - return r; + break; + } - r = wait_for_terminate(child, &si); - if (r < 0) - return sd_bus_error_set_errnof(error, r, "Failed to wait for client: %m"); - if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS) - return sd_bus_error_setf(error, SD_BUS_ERROR_FAILED, "Client died abnormally."); + default: + return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Requesting OS release data is only supported on container machines."); + } r = sd_bus_message_new_method_return(message, &reply); if (r < 0) @@ -430,10 +483,20 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_ assert(message); assert(m); - if (m->class != MACHINE_CONTAINER) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening pseudo TTYs is only supported on container machines."); + r = bus_verify_polkit_async( + message, + CAP_SYS_ADMIN, + "org.freedesktop.machine1.open-pty", + false, + UID_INVALID, + &m->manager->polkit_registry, + error); + if (r < 0) + return r; + if (r == 0) + return 1; /* Will call us back */ - master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC); + master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC); if (master < 0) return master; @@ -453,31 +516,45 @@ int bus_machine_method_open_pty(sd_bus_message *message, void *userdata, sd_bus_ } static int container_bus_new(Machine *m, sd_bus **ret) { - _cleanup_bus_unref_ sd_bus *bus = NULL; - char *address; int r; assert(m); assert(ret); - r = sd_bus_new(&bus); - if (r < 0) - return r; + switch (m->class) { - if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0) - return -ENOMEM; + case MACHINE_HOST: + *ret = NULL; + break; - bus->address = address; - bus->bus_client = true; - bus->trusted = false; - bus->is_system = true; + case MACHINE_CONTAINER: { + _cleanup_bus_unref_ sd_bus *bus = NULL; + char *address; - r = sd_bus_start(bus); - if (r < 0) - return r; + r = sd_bus_new(&bus); + if (r < 0) + return r; - *ret = bus; - bus = NULL; + if (asprintf(&address, "x-machine-kernel:pid=%1$" PID_PRI ";x-machine-unix:pid=%1$" PID_PRI, m->leader) < 0) + return -ENOMEM; + + bus->address = address; + bus->bus_client = true; + bus->trusted = false; + bus->is_system = true; + + r = sd_bus_start(bus); + if (r < 0) + return r; + + *ret = bus; + bus = NULL; + break; + } + + default: + return -EOPNOTSUPP; + } return 0; } @@ -485,8 +562,9 @@ static int container_bus_new(Machine *m, sd_bus **ret) { int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL; _cleanup_free_ char *pty_name = NULL; - _cleanup_bus_unref_ sd_bus *container_bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; _cleanup_close_ int master = -1; + sd_bus *container_bus = NULL; Machine *m = userdata; const char *p, *getty; int r; @@ -494,9 +572,6 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu assert(message); assert(m); - if (m->class != MACHINE_CONTAINER) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening logins is only supported on container machines."); - r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, @@ -510,7 +585,7 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu if (r == 0) return 1; /* Will call us back */ - master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC); + master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC); if (master < 0) return master; @@ -525,10 +600,12 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu if (unlockpt(master) < 0) return -errno; - r = container_bus_new(m, &container_bus); + r = container_bus_new(m, &allocated_bus); if (r < 0) return r; + container_bus = allocated_bus ?: m->manager->bus; + getty = strjoina("container-getty@", p, ".service"); r = sd_bus_call_method( @@ -542,8 +619,6 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - container_bus = sd_bus_unref(container_bus); - r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; @@ -558,7 +633,8 @@ int bus_machine_method_open_login(sd_bus_message *message, void *userdata, sd_bu int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) { _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *tm = NULL; _cleanup_free_ char *pty_name = NULL; - _cleanup_bus_unref_ sd_bus *container_bus = NULL; + _cleanup_bus_flush_close_unref_ sd_bus *allocated_bus = NULL; + sd_bus *container_bus = NULL; _cleanup_close_ int master = -1; _cleanup_strv_free_ char **env = NULL, **args = NULL; Machine *m = userdata; @@ -597,9 +673,6 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (!strv_env_is_valid(env)) return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid environment assignments"); - if (m->class != MACHINE_CONTAINER) - return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Opening shells is only supported on container machines."); - r = bus_verify_polkit_async( message, CAP_SYS_ADMIN, @@ -613,7 +686,7 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r == 0) return 1; /* Will call us back */ - master = openpt_in_namespace(m->leader, O_RDWR|O_NOCTTY|O_CLOEXEC); + master = machine_openpt(m, O_RDWR|O_NOCTTY|O_CLOEXEC); if (master < 0) return master; @@ -631,10 +704,12 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (unlockpt(master) < 0) return -errno; - r = container_bus_new(m, &container_bus); + r = container_bus_new(m, &allocated_bus); if (r < 0) return r; + container_bus = allocated_bus ?: m->manager->bus; + r = sd_bus_message_new_method_call( container_bus, &tm, @@ -645,9 +720,8 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - unit = strjoina("container-shell@", p, ".service", NULL); - /* Name and mode */ + unit = strjoina("container-shell@", p, ".service", NULL); r = sd_bus_message_append(tm, "ss", unit, "fail"); if (r < 0) return r; @@ -768,8 +842,6 @@ int bus_machine_method_open_shell(sd_bus_message *message, void *userdata, sd_bu if (r < 0) return r; - container_bus = sd_bus_unref(container_bus); - r = sd_bus_message_new_method_return(message, &reply); if (r < 0) return r; @@ -1207,7 +1279,7 @@ const sd_bus_vtable machine_vtable[] = { SD_BUS_METHOD("Kill", "si", NULL, bus_machine_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), 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), - SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, 0), + SD_BUS_METHOD("OpenPTY", NULL, "hs", bus_machine_method_open_pty, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenLogin", NULL, "hs", bus_machine_method_open_login, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("OpenShell", "ssasas", "hs", bus_machine_method_open_shell, SD_BUS_VTABLE_UNPRIVILEGED), SD_BUS_METHOD("BindMount", "ssbb", NULL, bus_machine_method_bind_mount, SD_BUS_VTABLE_UNPRIVILEGED), diff --git a/src/machine/machine.c b/src/machine/machine.c index f045159d41..0d1b119dc1 100644 --- a/src/machine/machine.c +++ b/src/machine/machine.c @@ -37,12 +37,17 @@ #include "machine-dbus.h" #include "formats-util.h" -Machine* machine_new(Manager *manager, const char *name) { +Machine* machine_new(Manager *manager, MachineClass class, const char *name) { Machine *m; assert(manager); + assert(class < _MACHINE_CLASS_MAX); assert(name); + /* Passing class == _MACHINE_CLASS_INVALID here is fine. It + * means as much as "we don't know yet", and that we'll figure + * it out later when loading the state file. */ + m = new0(Machine, 1); if (!m) return NULL; @@ -51,14 +56,17 @@ Machine* machine_new(Manager *manager, const char *name) { if (!m->name) goto fail; - m->state_file = strappend("/run/systemd/machines/", m->name); - if (!m->state_file) - goto fail; + if (class != MACHINE_HOST) { + m->state_file = strappend("/run/systemd/machines/", m->name); + if (!m->state_file) + goto fail; + } + + m->class = class; if (hashmap_put(manager->machines, m->name, m) < 0) goto fail; - m->class = _MACHINE_CLASS_INVALID; m->manager = manager; return m; @@ -86,6 +94,9 @@ void machine_free(Machine *m) { (void) hashmap_remove(m->manager->machines, m->name); + if (m->manager->host_machine == m) + m->manager->host_machine = NULL; + if (m->leader > 0) (void) hashmap_remove_value(m->manager->machine_leaders, UINT_TO_PTR(m->leader), m); @@ -105,7 +116,9 @@ int machine_save(Machine *m) { int r; assert(m); - assert(m->state_file); + + if (!m->state_file) + return 0; if (!m->started) return 0; @@ -244,6 +257,9 @@ int machine_load(Machine *m) { assert(m); + if (!m->state_file) + return 0; + r = parse_env_file(m->state_file, NEWLINE, "SCOPE", &m->unit, "SCOPE_JOB", &m->scope_job, @@ -325,6 +341,7 @@ static int machine_start_scope(Machine *m, sd_bus_message *properties, sd_bus_er int r = 0; assert(m); + assert(m->class != MACHINE_HOST); if (!m->unit) { _cleanup_free_ char *escaped = NULL; @@ -364,6 +381,9 @@ int machine_start(Machine *m, sd_bus_message *properties, sd_bus_error *error) { assert(m); + if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM)) + return -EOPNOTSUPP; + if (m->started) return 0; @@ -402,6 +422,7 @@ static int machine_stop_scope(Machine *m) { int r; assert(m); + assert(m->class != MACHINE_HOST); if (!m->unit) return 0; @@ -422,6 +443,9 @@ int machine_stop(Machine *m) { int r; assert(m); + if (!IN_SET(m->class, MACHINE_CONTAINER, MACHINE_VM)) + return -EOPNOTSUPP; + r = machine_stop_scope(m); m->stopping = true; @@ -456,6 +480,9 @@ int machine_finalize(Machine *m) { bool machine_check_gc(Machine *m, bool drop_not_started) { assert(m); + if (m->class == MACHINE_HOST) + return true; + if (drop_not_started && !m->started) return false; @@ -481,6 +508,9 @@ void machine_add_to_gc_queue(Machine *m) { MachineState machine_get_state(Machine *s) { assert(s); + if (s->class == MACHINE_HOST) + return MACHINE_RUNNING; + if (s->stopping) return MACHINE_CLOSING; @@ -493,6 +523,9 @@ MachineState machine_get_state(Machine *s) { int machine_kill(Machine *m, KillWho who, int signo) { assert(m); + if (!IN_SET(m->class, MACHINE_VM, MACHINE_CONTAINER)) + return -EOPNOTSUPP; + if (!m->unit) return -ESRCH; @@ -509,6 +542,25 @@ int machine_kill(Machine *m, KillWho who, int signo) { return manager_kill_unit(m->manager, m->unit, signo, NULL); } +int machine_openpt(Machine *m, int flags) { + assert(m); + + switch (m->class) { + + case MACHINE_HOST: + return posix_openpt(flags); + + case MACHINE_CONTAINER: + if (m->leader <= 0) + return -EINVAL; + + return openpt_in_namespace(m->leader, flags); + + default: + return -EOPNOTSUPP; + } +} + MachineOperation *machine_operation_unref(MachineOperation *o) { if (!o) return NULL; @@ -544,7 +596,8 @@ void machine_release_unit(Machine *m) { static const char* const machine_class_table[_MACHINE_CLASS_MAX] = { [MACHINE_CONTAINER] = "container", - [MACHINE_VM] = "vm" + [MACHINE_VM] = "vm", + [MACHINE_HOST] = "host", }; DEFINE_STRING_TABLE_LOOKUP(machine_class, MachineClass); diff --git a/src/machine/machine.h b/src/machine/machine.h index 0132b65a97..5f978289f2 100644 --- a/src/machine/machine.h +++ b/src/machine/machine.h @@ -39,6 +39,7 @@ typedef enum MachineState { typedef enum MachineClass { MACHINE_CONTAINER, MACHINE_VM, + MACHINE_HOST, _MACHINE_CLASS_MAX, _MACHINE_CLASS_INVALID = -1 } MachineClass; @@ -95,7 +96,7 @@ struct Machine { unsigned n_operations; }; -Machine* machine_new(Manager *manager, const char *name); +Machine* machine_new(Manager *manager, MachineClass class, const char *name); void machine_free(Machine *m); bool machine_check_gc(Machine *m, bool drop_not_started); void machine_add_to_gc_queue(Machine *m); @@ -120,3 +121,5 @@ MachineState machine_state_from_string(const char *s) _pure_; const char *kill_who_to_string(KillWho k) _const_; KillWho kill_who_from_string(const char *s) _pure_; + +int machine_openpt(Machine *m, int flags); diff --git a/src/machine/machinectl.c b/src/machine/machinectl.c index 72b9a619d2..c84deba1c0 100644 --- a/src/machine/machinectl.c +++ b/src/machine/machinectl.c @@ -358,7 +358,8 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { bus, "org.freedesktop.systemd1", path, - endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service", + endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : + endswith(unit, ".slice") ? "org.freedesktop.systemd1.Slice" : "org.freedesktop.systemd1.Service", "ControlGroup", &error, &reply, @@ -372,9 +373,6 @@ static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) { if (r < 0) return bus_log_parse_error(r); - if (isempty(cgroup)) - return 0; - if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0) return 0; diff --git a/src/machine/machined-dbus.c b/src/machine/machined-dbus.c index 03625ba4cd..29649899ed 100644 --- a/src/machine/machined-dbus.c +++ b/src/machine/machined-dbus.c @@ -1508,7 +1508,7 @@ int manager_add_machine(Manager *m, const char *name, Machine **_machine) { machine = hashmap_get(m->machines, name); if (!machine) { - machine = machine_new(m, name); + machine = machine_new(m, _MACHINE_CLASS_INVALID, name); if (!machine) return -ENOMEM; } diff --git a/src/machine/machined.c b/src/machine/machined.c index 9b9a334838..df3cc9972a 100644 --- a/src/machine/machined.c +++ b/src/machine/machined.c @@ -90,6 +90,45 @@ void manager_free(Manager *m) { free(m); } +static int manager_add_host_machine(Manager *m) { + _cleanup_free_ char *rd = NULL, *unit = NULL; + sd_id128_t mid; + Machine *t; + int r; + + if (m->host_machine) + return 0; + + r = sd_id128_get_machine(&mid); + if (r < 0) + return log_error_errno(r, "Failed to get machine ID: %m"); + + rd = strdup("/"); + if (!rd) + return log_oom(); + + unit = strdup("-.slice"); + if (!unit) + return log_oom(); + + t = machine_new(m, MACHINE_HOST, ".host"); + if (!t) + return log_oom(); + + t->leader = 1; + t->id = mid; + + t->root_directory = rd; + t->unit = unit; + rd = unit = NULL; + + dual_timestamp_from_boottime_or_monotonic(&t->timestamp, 0); + + m->host_machine = t; + + return 0; +} + int manager_enumerate_machines(Manager *m) { _cleanup_closedir_ DIR *d = NULL; struct dirent *de; @@ -97,6 +136,10 @@ int manager_enumerate_machines(Manager *m) { assert(m); + r = manager_add_host_machine(m); + if (r < 0) + return r; + /* Read in machine data stored on disk */ d = opendir("/run/systemd/machines"); if (!d) { @@ -123,9 +166,7 @@ int manager_enumerate_machines(Manager *m) { k = manager_add_machine(m, de->d_name, &machine); if (k < 0) { - log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name); - - r = k; + r = log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name); continue; } diff --git a/src/machine/machined.h b/src/machine/machined.h index 61dbefb5f1..b3e59bf998 100644 --- a/src/machine/machined.h +++ b/src/machine/machined.h @@ -48,6 +48,8 @@ struct Manager { sd_event_source *image_cache_defer_event; LIST_HEAD(Machine, machine_gc_queue); + + Machine *host_machine; }; Manager *manager_new(void); diff --git a/src/machine/org.freedesktop.machine1.policy.in b/src/machine/org.freedesktop.machine1.policy.in index b3b2fa29c1..f1557806d1 100644 --- a/src/machine/org.freedesktop.machine1.policy.in +++ b/src/machine/org.freedesktop.machine1.policy.in @@ -26,6 +26,16 @@ </defaults> </action> + <action id="org.freedesktop.machine1.open-pty"> + <_description>Acquire a pseudo TTY in a local container</_description> + <_message>Authentication is acquire a pseudo TTY in a local container.</_message> + <defaults> + <allow_any>auth_admin</allow_any> + <allow_inactive>auth_admin</allow_inactive> + <allow_active>auth_admin_keep</allow_active> + </defaults> + </action> + <action id="org.freedesktop.machine1.shell"> <_description>Acquire a shell in a local container</_description> <_message>Authentication is required to acquire a shell in a local container.</_message> |