machinectl.c revision 1ee306e1248866617c96ed9f4263f375588ad838
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 */
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int list_machines(DBusConnection *bus, char **args, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering unsigned k = 0;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1.Manager",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "ListMachines",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_STRUCT) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *name, *class, *service, *object;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRUCT) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &class, true) < 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &service, true) < 0 ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_OBJECT_PATH, &object, false) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("%-32s %-9s %-16s\n", name, class, service);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic void print_machine_status_info(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);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering printf("\t CGroup: %s\n", i->default_control_group);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering show_cgroup_and_extra_by_spec(i->default_control_group,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int status_property_machine(const char *name, DBusMessageIter *iter, MachineStatusInfo *i) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering switch (dbus_message_iter_get_arg_type(iter)) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering const char *s;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (streq(name, "DefaultControlGroup"))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) == DBUS_TYPE_BYTE && streq(name, "Id")) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dbus_message_iter_get_fixed_array(&sub, &v, &n);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (n == 16)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int print_property(const char *name, DBusMessageIter *iter) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (arg_property && !strv_find(arg_property, name))
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (generic_print_property(name, iter, arg_all) > 0)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int show_one(const char *verb, DBusConnection *bus, const char *path, bool show_properties, bool *new_line) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.DBus.Properties",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!dbus_message_iter_init(reply, &iter) ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY ||
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering dbus_message_iter_get_element_type(&iter) != DBUS_TYPE_DICT_ENTRY) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering while (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_INVALID) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_DICT_ENTRY) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (bus_iter_get_basic_and_next(&sub2, DBUS_TYPE_STRING, &name, true) < 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (dbus_message_iter_get_arg_type(&sub2) != DBUS_TYPE_VARIANT) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = status_property_machine(name, &sub3, &machine_info);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering print_machine_status_info(&machine_info);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int show(DBusConnection *bus, char **args, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering _cleanup_dbus_message_unref_ DBusMessage *reply = NULL;
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering show_properties = !strstr(args[0], "status");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering /* If not argument is specified inspect the manager
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering ret = show_one(args[0], bus, "/org/freedesktop/machine1", show_properties, &new_line);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1.Manager",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering if (!dbus_message_get_args(reply, &error,
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to parse reply: %s", bus_error_message(&error));
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering r = show_one(args[0], bus, path, show_properties, &new_line);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int kill_machine(DBusConnection *bus, char **args, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1.Manager",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "KillMachine",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int terminate_machine(DBusConnection *bus, char **args, unsigned n) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering for (i = 1; i < n; i++) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "org.freedesktop.machine1.Manager",
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering "TerminateMachine",
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 " -P --privileged Acquire privileges before execution\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"
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering " 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);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poetteringstatic int machinectl_main(DBusConnection *bus, int argc, char *argv[], DBusError *error) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering static const struct {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering int (* const dispatch)(DBusConnection *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.");
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering log_error("Failed to get D-Bus connection: %s", error->message);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering return verbs[i].dispatch(bus, argv + optind, left);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (r == 0) {
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering else if (arg_transport == TRANSPORT_POLKIT)
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering bus_connect_system_ssh(NULL, arg_host, &bus, &error);
1ee306e1248866617c96ed9f4263f375588ad838Lennart Poettering assert_not_reached("Uh, invalid transport...");