machinectl.c revision 9f6eb1cd58f2ddf2eb6ba0e4de056e13d938af75
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering This file is part of systemd.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Copyright 2013 Lennart Poettering
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is free software; you can redistribute it and/or modify it
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering under the terms of the GNU Lesser General Public License as published by
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering (at your option) any later version.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering systemd is distributed in the hope that it will be useful, but
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering Lesser General Public License for more details.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering You should have received a copy of the GNU Lesser General Public License
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_all = false;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_full = false;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_no_pager = false;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic bool arg_ask_password = true;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void pager_open_if_enabled(void) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* Cache result before we open the pager */
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int list_machines(sd_bus *bus, char **args, unsigned n) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering const char *name, *class, *service, *object;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering unsigned k = 0;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1.Manager",
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering "ListMachines",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Could not get machines: %s", bus_error_message(&error, -r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
6ad623a3f77e087e308f334525fd4046811f2a9aLennart Poettering printf("%-32s %-9s %-16s\n", name, class, service);
6ad623a3f77e087e308f334525fd4046811f2a9aLennart Poettering r = sd_bus_message_exit_container(reply);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to parse reply: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (arg_transport == BUS_TRANSPORT_REMOTE)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "ControlGroup",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = sd_bus_message_read(reply, "s", &cgroup);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to parse reply: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (!sd_id128_equal(i->id, SD_ID128_NULL))
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering printf("\t Leader: %u", (unsigned) i->leader);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering } else if (i->class)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering printf("\t Root: %s\n", i->root_directory);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering show_scope_cgroup(bus, i->scope, i->leader);
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburgerstatic int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger static const struct bus_properties_map map[] = {
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Scope", "s", NULL, offsetof(MachineStatusInfo, scope) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger "org.freedesktop.machine1",
28cb17ef0281efc3a46e5d0e702b0b0ddeaafaa4Filipe Brandenburger log_error("Could not get properties: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int show_properties(sd_bus *bus, const char *path, bool *new_line) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = bus_print_all_properties(bus, path, arg_property, arg_all);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Could not get properties: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int show(sd_bus *bus, char **args, unsigned n) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering /* If no argument is specified, inspect the manager
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = show_properties(bus, "/org/freedesktop/machine1", &new_line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering log_error("Failed to query properties: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering for (i = 1; i < n; i++) {
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering "org.freedesktop.machine1",
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering "org.freedesktop.machine1.Manager",
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering r = sd_bus_message_read(reply, "o", &path);
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering log_error("Failed to parse reply: %s", strerror(-r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = show_properties(bus, path, &new_line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = show_info(args[0], bus, path, &new_line);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int kill_machine(sd_bus *bus, char **args, unsigned n) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering for (i = 1; i < n; i++) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1.Manager",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "KillMachine",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "ssi", args[i], arg_kill_who, arg_signal);
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering log_error("Could not kill machine: %s", bus_error_message(&error, -r));
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poetteringstatic int terminate_machine(sd_bus *bus, char **args, unsigned n) {
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering for (i = 1; i < n; i++) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "org.freedesktop.machine1.Manager",
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering "TerminateMachine",
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poetteringstatic int openpt_in_namespace(pid_t pid, int flags) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_close_ int nsfd = -1, rootfd = -1;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_free_ char *ns = NULL, *root = NULL;
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering _cleanup_close_pipe_ int sock[2] = { -1, -1 };
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering r = asprintf(&ns, "/proc/%lu/ns/mnt", (unsigned long) pid);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering nsfd = open(ns, O_RDONLY|O_NOCTTY|O_CLOEXEC);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering r = asprintf(&root, "/proc/%lu/root", (unsigned long) pid);
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering rootfd = open(root, O_RDONLY|O_NOCTTY|O_CLOEXEC|O_DIRECTORY);
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sock) < 0)
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering if (recvmsg(sock[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
2d49a208f8ad9d1c4e79fa4302451e35d06de707Lennart Poettering if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS || master < 0) {
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev return r < 0 ? r : -EIO;
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venevstatic int login_machine(sd_bus *bus, char **args, unsigned n) {
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL, *reply3 = NULL;
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev _cleanup_bus_unref_ sd_bus *container_bus = NULL;
436dd70f5331ec541ebdd84e106abaa63203f6f1Hristo Venev log_error("Login only support on local machines.");
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
&reply,
r = sd_bus_get_property(
bus,
path,
&error,
&reply2,
if (master < 0) {
return master;
if (!pty) {
return -errno;
return -EIO;
if (!getty)
return log_oom();
return -errno;
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
static int help(void) {
" show [NAME...] Show properties of one or more VMs/containers\n"
" terminate [NAME...] Terminate one or more VMs/containers\n"
help();
case ARG_VERSION:
return log_oom();
arg_all = true;
arg_all = true;
arg_full = true;
case ARG_NO_PAGER:
arg_no_pager = true;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
case ARG_KILL_WHO:
if (arg_signal < 0) {
return -EINVAL;
return -EINVAL;
return -EINVAL;
const char* verb;
MORE,
LESS,
} argc_cmp;
const int argc;
} verbs[] = {
int left;
if (left <= 0)
help();
return -EINVAL;
case EQUAL:
return -EINVAL;
case MORE:
return -EINVAL;
case LESS:
return -EINVAL;
log_open();
goto finish;
goto finish;
goto finish;
pager_close();
return ret;