machinectl.c revision a1da85830bfaa77b9eb9c54693e5573559c97e50
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering This file is part of systemd.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Copyright 2013 Lennart Poettering
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is free software; you can redistribute it and/or modify it
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering under the terms of the GNU Lesser General Public License as published by
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering (at your option) any later version.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering systemd is distributed in the hope that it will be useful, but
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering Lesser General Public License for more details.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering You should have received a copy of the GNU Lesser General Public License
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool arg_all = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool arg_full = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool arg_no_pager = false;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic bool arg_ask_password = true;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void pager_open_if_enabled(void) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Cache result before we open the pager */
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int list_machines(sd_bus *bus, char **args, unsigned n) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned k = 0;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1.Manager",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "ListMachines",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not get machines: %s", bus_error_message(&error, -r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("%-32s %-9s %-16s\n", name, class, service);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to parse reply: %s", strerror(-r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int show_scope_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering "org.freedesktop.DBus.Properties",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "ControlGroup");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_read(reply, "v", "s", &cgroup);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to parse reply: %s", strerror(-r));
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, output_flags);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!sd_id128_equal(i->id, SD_ID128_NULL))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("\t Leader: %u", (unsigned) i->leader);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering } else if (i->class)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("\t Root: %s\n", i->root_directory);
9d12709626bccc0cae677a7035f62efe6aabb4abLennart Poettering show_scope_cgroup(bus, i->scope, i->leader);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int status_property_machine(const char *name, sd_bus_message *property, MachineStatusInfo *i) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_peek_type(property, &type, &contents);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not determine type of message: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *s;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen sd_bus_message_read_basic(property, type, &s);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen sd_bus_message_read_basic(property, type, &u);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen sd_bus_message_read_basic(property, type, &u);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (streq(contents, "y") && streq(name, "Id")) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen const void *v;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen sd_bus_message_read_array(property, SD_BUS_TYPE_BYTE, &v, &n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (n == 16)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int print_property(const char *name, sd_bus_message *reply) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (arg_property && !strv_find(arg_property, name))
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen if (bus_generic_print_property(name, reply, arg_all) > 0)
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int show_one(const char *verb, sd_bus *bus, const char *path, bool show_properties, bool *new_line) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.DBus.Properties",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not get properties: %s", bus_error_message(&error, -r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "{sv}");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen while ((r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_DICT_ENTRY, "sv")) > 0) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_read_basic(reply, SD_BUS_TYPE_STRING, &name);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_peek_type(reply, NULL, &contents);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_VARIANT, contents);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen r = status_property_machine(name, reply, &machine_info);
aa1936ea1a89c2bb968ba33e3274898a4eeae771Lennart Poettering print_machine_status_info(bus, &machine_info);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to parse reply: %s", strerror(-r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int show(sd_bus *bus, char **args, unsigned n) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering show_properties = !strstr(args[0], "status");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen /* If no argument is specified inspect the manager
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen return show_one(args[0], bus, "/org/freedesktop/machine1", show_properties, &new_line);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1.Manager",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "GetMachine",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to parse reply: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = show_one(args[0], bus, path, show_properties, &new_line);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int kill_machine(sd_bus *bus, char **args, unsigned n) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1.Manager",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "KillMachine",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not kill machine: %s", bus_error_message(&error, -r));
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int terminate_machine(sd_bus *bus, char **args, unsigned n) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "org.freedesktop.machine1.Manager",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen "TerminateMachine",
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int help(void) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "Send control commands to or query the virtual machine and container registration manager.\n\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -h --help Show this help\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " --version Show package version\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -p --property=NAME Show only properties by this name\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -a --all Show all properties, including empty ones\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " --kill-who=WHO Who to send signal to\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -l --full Do not ellipsize output\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -s --signal=SIGNAL Which signal to send\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " --no-ask-password Don't prompt for password\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " -H --host=[USER@]HOST Show information for remote host\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " --no-pager Do not pipe output into a pager\n\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " list List running VMs and containers\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " status [NAME...] Show VM/container status\n"
19887cd06a3af2f045e763986eda19e208bd3f85Zbigniew Jędrzejewski-Szmek " show [NAME...] Show properties of one or more VMs/containers\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " terminate [NAME...] Terminate one or more VMs/containers\n"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " kill [NAME...] Send signal to processes of a VM/container\n",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int parse_argv(int argc, char *argv[]) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "version", no_argument, NULL, ARG_VERSION },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "property", required_argument, NULL, 'p' },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "signal", required_argument, NULL, 's' },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "host", required_argument, NULL, 'H' },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "privileged", no_argument, NULL, 'P' },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while ((c = getopt_long(argc, argv, "hp:als:H:P", options, NULL)) >= 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If the user asked for a particular
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering * property, show it to him, even if it is
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering arg_signal = signal_from_string_try_harder(optarg);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to parse signal string %s.", optarg);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering parse_user_at_host(optarg, &arg_user, &arg_host);
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersenstatic int machinectl_main(sd_bus *bus, int argc, char *argv[], const int r) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering static const struct {
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering { "terminate", MORE, 2, terminate_machine },
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* Special rule: no arguments means "list-sessions" */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Unknown operation %s", argv[optind]);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Invalid number of arguments.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_not_reached("Unknown comparison operator.");
a1da85830bfaa77b9eb9c54693e5573559c97e50Tom Gundersen log_error("Failed to get D-Bus connection: %s", strerror(-r));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return verbs[i].dispatch(bus, argv + optind, left);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (r == 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_not_reached("Uh, invalid transport...");