machinectl.c revision 7705a4053d83b5da22c9354a44be26ffc8e24f5a
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock/***
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock This file is part of systemd.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock Copyright 2013 Lennart Poettering
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock systemd is free software; you can redistribute it and/or modify it
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock under the terms of the GNU Lesser General Public License as published by
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock the Free Software Foundation; either version 2.1 of the License, or
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (at your option) any later version.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock systemd is distributed in the hope that it will be useful, but
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock WITHOUT ANY WARRANTY; without even the implied warranty of
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock Lesser General Public License for more details.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock You should have received a copy of the GNU Lesser General Public License
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock along with systemd; If not, see <http://www.gnu.org/licenses/>.
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock***/
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <arpa/inet.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <errno.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <fcntl.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <getopt.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <locale.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <net/if.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <netinet/in.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <string.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <sys/mount.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <sys/socket.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include <unistd.h>
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "sd-bus.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "bus-error.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "bus-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "cgroup-show.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "cgroup-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "copy.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "env-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "event-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "hostname-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "import-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "log.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "logs-show.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "macro.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "mkdir.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "pager.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "path-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "process-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "ptyfwd.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "signal-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "spawn-polkit-agent.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "strv.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "terminal-util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "unit-name.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "util.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock#include "verbs.h"
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic char **arg_property = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_all = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_full = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_no_pager = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_legend = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const char *arg_kill_who = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int arg_signal = SIGTERM;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic char *arg_host = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_read_only = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_mkdir = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_quiet = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_ask_password = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic unsigned arg_lines = 10;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic OutputMode arg_output = OUTPUT_SHORT;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic bool arg_force = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const char* arg_dkr_index_url = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const char* arg_format = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic const char *arg_uid = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic char **arg_setenv = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void pager_open_if_enabled(void) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_no_pager)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pager_open(false);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void polkit_agent_open_if_enabled(void) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /* Open the polkit agent as a child process if necessary */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!arg_ask_password)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_transport != BUS_TRANSPORT_LOCAL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock polkit_agent_open();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic OutputFlags get_output_flags(void) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock arg_all * OUTPUT_SHOW_ALL |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock arg_full * OUTPUT_FULL_WIDTH |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock on_tty() * OUTPUT_COLOR |
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock !arg_quiet * OUTPUT_WARN_CUTOFF;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocktypedef struct MachineInfo {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *class;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *service;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock} MachineInfo;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int compare_machine_info(const void *a, const void *b) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const MachineInfo *x = a, *y = b;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return strcmp(x->name, y->name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int list_machines(int argc, char *argv[], void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_free_ MachineInfo *machines = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *name, *class, *service, *object;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t n_machines = 0, n_allocated = 0, j;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_bus *bus = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pager_open_if_enabled();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
9af3851a3a831b4de34b42482c22351e14f33f16eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
9af3851a3a831b4de34b42482c22351e14f33f16eschrock "ListMachines",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &error,
9af3851a3a831b4de34b42482c22351e14f33f16eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock NULL);
9af3851a3a831b4de34b42482c22351e14f33f16eschrock if (r < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error("Could not get machines: %s", bus_error_message(&error, -r));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (name[0] == '.' && !arg_all)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_oom();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock machines[n_machines].name = name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock machines[n_machines].class = class;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock machines[n_machines].service = service;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_name)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_name = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(class);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_class)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_class = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(service);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_service)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_service = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock n_machines ++;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_exit_container(reply);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_legend)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%-*s %-*s %-*s\n",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_name, "MACHINE",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_class, "CLASS",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_service, "SERVICE");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (j = 0; j < n_machines; j++)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%-*s %-*s %-*s\n",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_name, machines[j].name,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_class, machines[j].class,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_service, machines[j].service);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_legend)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n%zu machines listed.\n", n_machines);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocktypedef struct ImageInfo {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *type;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bool read_only;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock usec_t crtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock usec_t mtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t size;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock} ImageInfo;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int compare_image_info(const void *a, const void *b) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const ImageInfo *x = a, *y = b;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return strcmp(x->name, y->name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int list_images(int argc, char *argv[], void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_free_ ImageInfo *images = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t n_images = 0, n_allocated = 0, j;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *name, *type, *object;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_bus *bus = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t crtime, mtime, size;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int read_only, r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pager_open_if_enabled();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "ListImages",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &error,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error("Could not get images: %s", bus_error_message(&error, -r));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (name[0] == '.' && !arg_all)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock continue;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_oom();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].name = name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].type = type;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].read_only = read_only;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].crtime = crtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].mtime = mtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[n_images].size = size;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_name)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_name = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(type);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_type)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_type = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (crtime != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_crtime)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_crtime = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (mtime != 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_mtime)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_mtime = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (size != (uint64_t) -1) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (l > max_size)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock max_size = l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock n_images++;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_exit_container(reply);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_legend)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_name, "NAME",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_type, "TYPE",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "RO",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_size, "USAGE",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_crtime, "CREATED",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_mtime, "MODIFIED");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (j = 0; j < n_images; j++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_name, images[j].name,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_type, images[j].type,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_normal() : "",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_legend)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n%zu images listed.\n", n_images);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_free_ char *path = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *cgroup;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock unsigned c;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(unit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_transport == BUS_TRANSPORT_REMOTE)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock path = unit_dbus_path_from_name(unit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!path)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_oom();
9af3851a3a831b4de34b42482c22351e14f33f16eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_get_property(
9af3851a3a831b4de34b42482c22351e14f33f16eschrock bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.systemd1",
9af3851a3a831b4de34b42482c22351e14f33f16eschrock path,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock unit_dbus_interface_from_name(unit),
9af3851a3a831b4de34b42482c22351e14f33f16eschrock "ControlGroup",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &error,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "s");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read(reply, "s", &cgroup);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup) != 0 && leader <= 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
9af3851a3a831b4de34b42482c22351e14f33f16eschrock c = columns();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (c > 18)
9af3851a3a831b4de34b42482c22351e14f33f16eschrock c -= 18;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock c = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(prefix);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(prefix2);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "GetMachineAddresses",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock NULL,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "s", name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_enter_container(reply, 'a', "(iay)");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int family;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const void *a;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t sz;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read(reply, "i", &family);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read_array(reply, 'y', &a, &sz);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs(prefix, stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (family == AF_INET6 && ifi > 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%%%i", ifi);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputc('\n', stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_exit_container(reply);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (prefix != prefix2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock prefix = prefix2;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_exit_container(reply);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *k, *v, *pretty = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(prefix);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "GetMachineOSRelease",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock NULL,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "s", name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_enter_container(reply, 'a', "{ss}");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (streq(k, "PRETTY_NAME"))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pretty = v;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_exit_container(reply);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (pretty)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("%s%s\n", prefix, pretty);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocktypedef struct MachineStatusInfo {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_id128_t id;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *class;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *service;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *unit;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *root_directory;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pid_t leader;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock struct dual_timestamp timestamp;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int *netif;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock unsigned n_netif;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock} MachineStatusInfo;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void machine_status_info_clear(MachineStatusInfo *info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->class);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->service);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->unit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->root_directory);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->netif);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock zero(*info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char since2[FORMAT_TIMESTAMP_MAX], *s2;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int ifi = -1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(i);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs(strna(i->name), stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!sd_id128_equal(i->id, SD_ID128_NULL))
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock putchar('\n');
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s1)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Since: %s; %s\n", s2, s1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else if (s2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Since: %s\n", s2);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->leader > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_free_ char *t = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Leader: %u", (unsigned) i->leader);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock get_process_comm(i->leader, &t);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (t)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf(" (%s)", t);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock putchar('\n');
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->service) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Service: %s", i->service);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->class)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("; class %s", i->class);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock putchar('\n');
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock } else if (i->class)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Class: %s\n", i->class);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->root_directory)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Root: %s\n", i->root_directory);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->n_netif > 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock unsigned c;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs("\t Iface:", stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (c = 0; c < i->n_netif; c++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char name[IF_NAMESIZE+1] = "";
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (if_indextoname(i->netif[c], name)) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputc(' ', stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs(name, stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (ifi < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ifi = i->netif[c];
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock ifi = 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock } else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf(" %i", i->netif[c]);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputc('\n', stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock print_addresses(bus, i->name, ifi,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "\t Address: ",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "\t ");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock print_os_release(bus, i->name, "\t OS: ");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->unit) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Unit: %s\n", i->unit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock show_unit_cgroup(bus, i->unit, i->leader);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (arg_transport == BUS_TRANSPORT_LOCAL)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock show_journal_by_unit(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock stdout,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->unit,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock arg_output,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock 0,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->timestamp.monotonic,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock arg_lines,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock 0,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock get_output_flags() | OUTPUT_BEGIN_NEWLINE,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock SD_JOURNAL_LOCAL_ONLY,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock true,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock NULL);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock MachineStatusInfo *i = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock size_t l;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const void *v;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert_cc(sizeof(int32_t) == sizeof(int));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r == 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return -EBADMSG;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->n_netif = l / sizeof(int32_t);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->netif = memdup(v, l);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (!i->netif)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return -ENOMEM;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock static const struct bus_properties_map map[] = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "NetworkInterfaces", "ai", map_netif, 0 },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock {}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock };
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(verb);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = bus_map_all_properties(bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock path,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock map,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_error_errno(r, "Could not get properties: %m");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (*new_line)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *new_line = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock print_machine_status_info(bus, &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (*new_line)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *new_line = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error_errno(r, "Could not get properties: %m");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_machine(int argc, char *argv[], void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bool properties, new_line = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_bus *bus = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r = 0, i;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock properties = !strstr(argv[0], "status");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pager_open_if_enabled();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (properties && argc <= 1) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /* If no argument is specified, inspect the manager
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * itself */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (i = 1; i < argc; i++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *path = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "GetMachine",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &error,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "s", argv[i]);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read(reply, "o", &path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (properties)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_machine_properties(bus, path, &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_machine_info(argv[0], bus, path, &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocktypedef struct ImageStatusInfo {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *name;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *path;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *type;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int read_only;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock usec_t crtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock usec_t mtime;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t usage;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t limit;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t usage_exclusive;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t limit_exclusive;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock} ImageStatusInfo;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void image_status_info_clear(ImageStatusInfo *info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->name);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->type);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock zero(*info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char bs[FORMAT_BYTES_MAX], *s3;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char bs_exclusive[FORMAT_BYTES_MAX], *s4;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(i);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->name) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock fputs(i->name, stdout);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock putchar('\n');
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->type)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Type: %s\n", i->type);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->path)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Path: %s\n", i->path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t RO: %s%s%s\n",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->read_only ? ansi_highlight_red() : "",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->read_only ? "read-only" : "writable",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock i->read_only ? ansi_normal() : "");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s1 && s2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Created: %s; %s\n", s2, s1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else if (s2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Created: %s\n", s2);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s1 && s2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\tModified: %s; %s\n", s2, s1);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else if (s2)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\tModified: %s\n", s2);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s3 = format_bytes(bs, sizeof(bs), i->usage);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s3 && s4)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else if (s3)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Usage: %s\n", s3);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s3 = format_bytes(bs, sizeof(bs), i->limit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s3 && s4)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else if (s3)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Limit: %s\n", s3);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock static const struct bus_properties_map map[] = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock {}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock };
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_(image_status_info_clear) ImageStatusInfo info = {};
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = bus_map_all_properties(bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock path,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock map,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_error_errno(r, "Could not get properties: %m");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (*new_line)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *new_line = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock print_image_status_info(bus, &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrocktypedef struct PoolStatusInfo {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char *path;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t usage;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock uint64_t limit;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock} PoolStatusInfo;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void pool_status_info_clear(PoolStatusInfo *info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (info) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock free(info->path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock zero(*info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock info->usage = -1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock info->limit = -1;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock char bs[FORMAT_BYTES_MAX], *s;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (i->path)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Path: %s\n", i->path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s = format_bytes(bs, sizeof(bs), i->usage);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Usage: %s\n", s);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock s = format_bytes(bs, sizeof(bs), i->limit);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (s)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\t Limit: %s\n", s);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_pool_info(sd_bus *bus) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock static const struct bus_properties_map map[] = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock { "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) },
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock {}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock };
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_(pool_status_info_clear) PoolStatusInfo info = {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .usage = (uint64_t) -1,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock .limit = (uint64_t) -1,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock };
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = bus_map_all_properties(bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock map,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return log_error_errno(r, "Could not get properties: %m");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock print_pool_status_info(bus, &info);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return 0;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (*new_line)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock printf("\n");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock *new_line = true;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error_errno(r, "Could not get properties: %m");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int show_image(int argc, char *argv[], void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bool properties, new_line = false;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_bus *bus = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r = 0, i;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock assert(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock properties = !strstr(argv[0], "status");
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock pager_open_if_enabled();
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (argc <= 1) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock /* If no argument is specified, inspect the manager
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock * itself */
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (properties)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_pool_info(bus);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock for (i = 1; i < argc; i++) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock const char *path = NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_call_method(
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock bus,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "/org/freedesktop/machine1",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "org.freedesktop.machine1.Manager",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "GetImage",
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &error,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock &reply,
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock "s", argv[i]);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock log_error("Could not get path to image: %s", bus_error_message(&error, -r));
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = sd_bus_message_read(reply, "o", &path);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (r < 0)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return bus_log_parse_error(r);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock if (properties)
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_image_properties(bus, path, &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock else
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock r = show_image_info(bus, path, &new_line);
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock }
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock return r;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock}
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrockstatic int kill_machine(int argc, char *argv[], void *userdata) {
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock sd_bus *bus = userdata;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock int r, i;
275c9da86e89f8abf71135cf63d9fc23671b2e60eschrock
assert(bus);
polkit_agent_open_if_enabled();
if (!arg_kill_who)
arg_kill_who = "all";
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"KillMachine",
&error,
NULL,
"ssi", argv[i], arg_kill_who, arg_signal);
if (r < 0) {
log_error("Could not kill machine: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int reboot_machine(int argc, char *argv[], void *userdata) {
arg_kill_who = "leader";
arg_signal = SIGINT; /* sysvinit + systemd */
return kill_machine(argc, argv, userdata);
}
static int poweroff_machine(int argc, char *argv[], void *userdata) {
arg_kill_who = "leader";
arg_signal = SIGRTMIN+4; /* only systemd */
return kill_machine(argc, argv, userdata);
}
static int terminate_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"TerminateMachine",
&error,
NULL,
"s", argv[i]);
if (r < 0) {
log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int copy_files(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ char *abs_host_path = NULL;
char *dest, *host_path, *container_path;
sd_bus *bus = userdata;
bool copy_from;
int r;
assert(bus);
polkit_agent_open_if_enabled();
copy_from = streq(argv[0], "copy-from");
dest = argv[3] ?: argv[2];
host_path = copy_from ? dest : argv[2];
container_path = copy_from ? argv[2] : dest;
if (!path_is_absolute(host_path)) {
abs_host_path = path_make_absolute_cwd(host_path);
if (!abs_host_path)
return log_oom();
host_path = abs_host_path;
}
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
copy_from ? "CopyFromMachine" : "CopyToMachine",
&error,
NULL,
"sss",
argv[1],
copy_from ? container_path : host_path,
copy_from ? host_path : container_path);
if (r < 0) {
log_error("Failed to copy: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int bind_mount(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"BindMountMachine",
&error,
NULL,
"sssbb",
argv[1],
argv[2],
argv[3],
arg_read_only,
arg_mkdir);
if (r < 0) {
log_error("Failed to bind mount: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int on_machine_removed(sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
PTYForward ** forward = (PTYForward**) userdata;
int r;
assert(m);
assert(forward);
if (*forward) {
/* If the forwarder is already initialized, tell it to
* exit on the next vhangup(), so that we still flush
* out what might be queued and exit then. */
r = pty_forward_set_ignore_vhangup(*forward, false);
if (r >= 0)
return 0;
log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
}
/* On error, or when the forwarder is not initialized yet, quit immediately */
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), EXIT_FAILURE);
return 0;
}
static int process_forward(sd_event *event, PTYForward **forward, int master, PTYForwardFlags flags, const char *name) {
char last_char = 0;
bool machine_died;
int ret = 0, r;
assert(event);
assert(master >= 0);
assert(name);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGWINCH, SIGTERM, SIGINT, -1) >= 0);
if (streq(name, ".host"))
log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
else
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", name);
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
r = pty_forward_new(event, master, flags, forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
pty_forward_get_last_char(*forward, &last_char);
machine_died =
(flags & PTY_FORWARD_IGNORE_VHANGUP) &&
pty_forward_get_ignore_vhangup(*forward) == 0;
*forward = pty_forward_free(*forward);
if (last_char != '\n')
fputc('\n', stdout);
if (machine_died)
log_info("Machine %s terminated.", name);
else if (streq(name, ".host"))
log_info("Connection to the local host terminated.");
else
log_info("Connection to machine %s terminated.", name);
sd_event_get_exit_code(event, &ret);
return ret;
}
static int login_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
int master = -1, r;
sd_bus *bus = userdata;
const char *pty, *match, *machine;
assert(bus);
if (!strv_isempty(arg_setenv) || arg_uid) {
log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
return -EINVAL;
}
if (arg_transport != BUS_TRANSPORT_LOCAL &&
arg_transport != BUS_TRANSPORT_MACHINE) {
log_error("Login only supported on local machines.");
return -EOPNOTSUPP;
}
polkit_agent_open_if_enabled();
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
machine = argc < 2 || isempty(argv[1]) ? ".host" : argv[1];
match = strjoina("type='signal',"
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
"member='MachineRemoved',"
"arg0='", machine, "'");
r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
if (r < 0)
return log_error_errno(r, "Failed to add machine removal match: %m");
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"OpenMachineLogin",
&error,
&reply,
"s", machine);
if (r < 0) {
log_error("Failed to get login PTY: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "hs", &master, &pty);
if (r < 0)
return bus_log_parse_error(r);
return process_forward(event, &forward, master, PTY_FORWARD_IGNORE_VHANGUP, machine);
}
static int shell_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *m = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
int master = -1, r;
sd_bus *bus = userdata;
const char *pty, *match, *machine, *path, *uid = NULL;
assert(bus);
if (arg_transport != BUS_TRANSPORT_LOCAL &&
arg_transport != BUS_TRANSPORT_MACHINE) {
log_error("Shell only supported on local machines.");
return -EOPNOTSUPP;
}
/* Pass $TERM to shell session, if not explicitly specified. */
if (!strv_find_prefix(arg_setenv, "TERM=")) {
const char *t;
t = strv_find_prefix(environ, "TERM=");
if (t) {
if (strv_extend(&arg_setenv, t) < 0)
return log_oom();
}
}
polkit_agent_open_if_enabled();
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
machine = argc < 2 || isempty(argv[1]) ? NULL : argv[1];
if (arg_uid)
uid = arg_uid;
else if (machine) {
const char *at;
at = strchr(machine, '@');
if (at) {
uid = strndupa(machine, at - machine);
machine = at + 1;
}
}
if (isempty(machine))
machine = ".host";
match = strjoina("type='signal',"
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
"member='MachineRemoved',"
"arg0='", machine, "'");
r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
if (r < 0)
return log_error_errno(r, "Failed to add machine removal match: %m");
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"OpenMachineShell");
if (r < 0)
return bus_log_create_error(r);
path = argc < 3 || isempty(argv[2]) ? NULL : argv[2];
r = sd_bus_message_append(m, "sss", machine, uid, path);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, strv_length(argv) <= 3 ? NULL : argv + 2);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append_strv(m, arg_setenv);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to get shell PTY: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "hs", &master, &pty);
if (r < 0)
return bus_log_parse_error(r);
return process_forward(event, &forward, master, 0, machine);
}
static int remove_image(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"RemoveImage",
&error,
NULL,
"s", argv[i]);
if (r < 0) {
log_error("Could not remove image: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int rename_image(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r;
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"RenameImage",
&error,
NULL,
"ss", argv[1], argv[2]);
if (r < 0) {
log_error("Could not rename image: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int clone_image(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r;
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"CloneImage",
&error,
NULL,
"ssb", argv[1], argv[2], arg_read_only);
if (r < 0) {
log_error("Could not clone image: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int read_only_image(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int b = true, r;
if (argc > 2) {
b = parse_boolean(argv[2]);
if (b < 0) {
log_error("Failed to parse boolean argument: %s", argv[2]);
return -EINVAL;
}
}
polkit_agent_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"MarkImageReadOnly",
&error,
NULL,
"sb", argv[1], b);
if (r < 0) {
log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int make_service_name(const char *name, char **ret) {
_cleanup_free_ char *e = NULL;
int r;
assert(name);
assert(ret);
if (!machine_name_is_valid(name)) {
log_error("Invalid machine name %s.", name);
return -EINVAL;
}
e = unit_name_escape(name);
if (!e)
return log_oom();
r = unit_name_build("systemd-nspawn", e, ".service", ret);
if (r < 0)
return log_error_errno(r, "Failed to build unit name: %m");
return 0;
}
static int start_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
r = bus_wait_for_jobs_new(bus, &w);
if (r < 0)
return log_oom();
for (i = 1; i < argc; i++) {
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_free_ char *unit = NULL;
const char *object;
r = make_service_name(argv[i], &unit);
if (r < 0)
return r;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartUnit",
&error,
&reply,
"ss", unit, "fail");
if (r < 0) {
log_error("Failed to start unit: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "o", &object);
if (r < 0)
return bus_log_parse_error(r);
r = bus_wait_for_jobs_add(w, object);
if (r < 0)
return log_oom();
}
r = bus_wait_for_jobs(w, arg_quiet);
if (r < 0)
return r;
return 0;
}
static int enable_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
int carries_install_info = 0;
const char *method = NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
method);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_open_container(m, 'a', "s");
if (r < 0)
return bus_log_create_error(r);
for (i = 1; i < argc; i++) {
_cleanup_free_ char *unit = NULL;
r = make_service_name(argv[i], &unit);
if (r < 0)
return r;
r = sd_bus_message_append(m, "s", unit);
if (r < 0)
return bus_log_create_error(r);
}
r = sd_bus_message_close_container(m);
if (r < 0)
return bus_log_create_error(r);
if (streq(argv[0], "enable"))
r = sd_bus_message_append(m, "bb", false, false);
else
r = sd_bus_message_append(m, "b", false);
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
return r;
}
if (streq(argv[0], "enable")) {
r = sd_bus_message_read(reply, "b", carries_install_info);
if (r < 0)
return bus_log_parse_error(r);
}
r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet, NULL, NULL);
if (r < 0)
return r;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"Reload",
&error,
NULL,
NULL);
if (r < 0) {
log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int match_log_message(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *line;
unsigned priority;
int r;
assert(m);
assert(our_path);
r = sd_bus_message_read(m, "us", &priority, &line);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
return 0;
if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
return 0;
log_full(priority, "%s", line);
return 0;
}
static int match_transfer_removed(sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *path, *result;
uint32_t id;
int r;
assert(m);
assert(our_path);
r = sd_bus_message_read(m, "uos", &id, &path, &result);
if (r < 0) {
bus_log_parse_error(r);
return 0;
}
if (!streq_ptr(*our_path, path))
return 0;
sd_event_exit(sd_bus_get_event(sd_bus_message_get_bus(m)), !streq_ptr(result, "done"));
return 0;
}
static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
assert(si);
if (!arg_quiet)
log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
sd_event_exit(sd_event_source_get_event(s), EINTR);
return 0;
}
static int transfer_image_common(sd_bus *bus, sd_bus_message *m) {
_cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_event_unref_ sd_event* event = NULL;
const char *path = NULL;
uint32_t id;
int r;
assert(bus);
assert(m);
polkit_agent_open_if_enabled();
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
r = sd_bus_attach_event(bus, event, 0);
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = sd_bus_add_match(
bus,
&slot_job_removed,
"type='signal',"
"sender='org.freedesktop.import1',"
"interface='org.freedesktop.import1.Manager',"
"member='TransferRemoved',"
"path='/org/freedesktop/import1'",
match_transfer_removed, &path);
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
r = sd_bus_add_match(
bus,
&slot_log_message,
"type='signal',"
"sender='org.freedesktop.import1',"
"interface='org.freedesktop.import1.Transfer',"
"member='LogMessage'",
match_log_message, &path);
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
r = sd_bus_call(bus, m, 0, &error, &reply);
if (r < 0) {
log_error("Failed transfer image: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "uo", &id, &path);
if (r < 0)
return bus_log_parse_error(r);
assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGTERM, SIGINT, -1) >= 0);
if (!arg_quiet)
log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
return -r;
}
static int import_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *ll = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
if (argc >= 2)
path = argv[1];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (argc >= 3)
local = argv[2];
else if (path)
local = basename(path);
if (isempty(local) || streq(local, "-"))
local = NULL;
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
r = tar_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
if (path) {
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"hsbb",
fd >= 0 ? fd : STDIN_FILENO,
local,
arg_force,
arg_read_only);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int import_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *ll = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
if (argc >= 2)
path = argv[1];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (argc >= 3)
local = argv[2];
else if (path)
local = basename(path);
if (isempty(local) || streq(local, "-"))
local = NULL;
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
r = raw_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
if (path) {
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"hsbb",
fd >= 0 ? fd : STDIN_FILENO,
local,
arg_force,
arg_read_only);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static void determine_compression_from_filename(const char *p) {
if (arg_format)
return;
if (!p)
return;
if (endswith(p, ".xz"))
arg_format = "xz";
else if (endswith(p, ".gz"))
arg_format = "gzip";
else if (endswith(p, ".bz2"))
arg_format = "bzip2";
}
static int export_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
local = argv[1];
if (!machine_name_is_valid(local)) {
log_error("Machine name %s is not valid.", local);
return -EINVAL;
}
if (argc >= 3)
path = argv[2];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (path) {
determine_compression_from_filename(path);
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"shs",
local,
fd >= 0 ? fd : STDOUT_FILENO,
arg_format);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int export_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
local = argv[1];
if (!machine_name_is_valid(local)) {
log_error("Machine name %s is not valid.", local);
return -EINVAL;
}
if (argc >= 3)
path = argv[2];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (path) {
determine_compression_from_filename(path);
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"shs",
local,
fd >= 0 ? fd : STDOUT_FILENO,
arg_format);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *l = NULL, *ll = NULL;
const char *local, *remote;
sd_bus *bus = userdata;
int r;
assert(bus);
remote = argv[1];
if (!http_url_is_valid(remote)) {
log_error("URL '%s' is not valid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
r = import_url_last_component(remote, &l);
if (r < 0)
return log_error_errno(r, "Failed to get final component of URL: %m");
local = l;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
r = tar_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssb",
remote,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *l = NULL, *ll = NULL;
const char *local, *remote;
sd_bus *bus = userdata;
int r;
assert(bus);
remote = argv[1];
if (!http_url_is_valid(remote)) {
log_error("URL '%s' is not valid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
r = import_url_last_component(remote, &l);
if (r < 0)
return log_error_errno(r, "Failed to get final component of URL: %m");
local = l;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
r = raw_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssb",
remote,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_dkr(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *local, *remote, *tag;
sd_bus *bus = userdata;
int r;
if (arg_verify != IMPORT_VERIFY_NO) {
log_error("Imports from DKR do not support image verification, please pass --verify=no.");
return -EINVAL;
}
remote = argv[1];
tag = strchr(remote, ':');
if (tag) {
remote = strndupa(remote, tag - remote);
tag++;
}
if (!dkr_name_is_valid(remote)) {
log_error("DKR name '%s' is invalid.", remote);
return -EINVAL;
}
if (tag && !dkr_tag_is_valid(tag)) {
log_error("DKR tag '%s' is invalid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
local = strchr(remote, '/');
if (local)
local++;
else
local = remote;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullDkr");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssssb",
arg_dkr_index_url,
remote,
tag,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
typedef struct TransferInfo {
uint32_t id;
const char *type;
const char *remote;
const char *local;
double progress;
} TransferInfo;
static int compare_transfer_info(const void *a, const void *b) {
const TransferInfo *x = a, *y = b;
return strcmp(x->local, y->local);
}
static int list_transfers(int argc, char *argv[], void *userdata) {
size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ TransferInfo *transfers = NULL;
size_t n_transfers = 0, n_allocated = 0, j;
const char *type, *remote, *local, *object;
sd_bus *bus = userdata;
uint32_t id, max_id = 0;
double progress;
int r;
pager_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ListTransfers",
&error,
&reply,
NULL);
if (r < 0) {
log_error("Could not get transfers: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
size_t l;
if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
return log_oom();
transfers[n_transfers].id = id;
transfers[n_transfers].type = type;
transfers[n_transfers].remote = remote;
transfers[n_transfers].local = local;
transfers[n_transfers].progress = progress;
l = strlen(type);
if (l > max_type)
max_type = l;
l = strlen(remote);
if (l > max_remote)
max_remote = l;
l = strlen(local);
if (l > max_local)
max_local = l;
if (id > max_id)
max_id = id;
n_transfers ++;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
if (arg_legend)
printf("%-*s %-*s %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
(int) 7, "PERCENT",
(int) max_type, "TYPE",
(int) max_local, "LOCAL",
(int) max_remote, "REMOTE");
for (j = 0; j < n_transfers; j++)
printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
(int) 6, (unsigned) (transfers[j].progress * 100),
(int) max_type, transfers[j].type,
(int) max_local, transfers[j].local,
(int) max_remote, transfers[j].remote);
if (arg_legend)
printf("\n%zu transfers listed.\n", n_transfers);
return 0;
}
static int cancel_transfer(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
uint32_t id;
r = safe_atou32(argv[i], &id);
if (r < 0)
return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"CancelTransfer",
&error,
NULL,
"u", id);
if (r < 0) {
log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int set_limit(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
uint64_t limit;
int r;
if (STR_IN_SET(argv[argc-1], "-", "none", "infinity"))
limit = (uint64_t) -1;
else {
r = parse_size(argv[argc-1], 1024, &limit);
if (r < 0)
return log_error("Failed to parse size: %s", argv[argc-1]);
}
if (argc > 2)
/* With two arguments changes the quota limit of the
* specified image */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetImageLimit",
&error,
NULL,
"st", argv[1], limit);
else
/* With one argument changes the pool quota limit */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetPoolLimit",
&error,
NULL,
"t", limit);
if (r < 0) {
log_error("Could not set limit: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Send control commands to or query the virtual machine and container\n"
"registration manager.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --no-ask-password Do not ask for system passwords\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" -p --property=NAME Show only properties by this name\n"
" -q --quiet Suppress output\n"
" -a --all Show all properties, including empty ones\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" --uid=USER Specify user ID to invoke shell as\n"
" --setenv=VAR=VALUE Add an environment variable for shell\n"
" --read-only Create read-only bind mount\n"
" --mkdir Create directory before bind mounting, if missing\n"
" -n --lines=INTEGER Number of journal entries to show\n"
" -o --output=STRING Change journal output mode (short,\n"
" short-monotonic, verbose, export, json,\n"
" json-pretty, json-sse, cat)\n"
" --verify=MODE Verification mode for downloaded images (no,\n"
" checksum, signature)\n"
" --force Download image even if already exists\n"
" --dkr-index-url=URL Specify the index URL to use for DKR image\n"
" downloads\n\n"
"Machine Commands:\n"
" list List running VMs and containers\n"
" status NAME... Show VM/container details\n"
" show [NAME...] Show properties of one or more VMs/containers\n"
" start NAME... Start container as a service\n"
" login [NAME] Get a login prompt in a container or on the\n"
" local host\n"
" shell [[USER@]NAME [COMMAND...]]\n"
" Invoke a shell (or other command) in a container\n"
" or on the local host\n"
" enable NAME... Enable automatic container start at boot\n"
" disable NAME... Disable automatic container start at boot\n"
" poweroff NAME... Power off one or more containers\n"
" reboot NAME... Reboot one or more containers\n"
" terminate NAME... Terminate one or more VMs/containers\n"
" kill NAME... Send signal to processes of a VM/container\n"
" copy-to NAME PATH [PATH] Copy files from the host to a container\n"
" copy-from NAME PATH [PATH] Copy files from a container to the host\n"
" bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
"Image Commands:\n"
" list-images Show available container and VM images\n"
" image-status [NAME...] Show image details\n"
" show-image [NAME...] Show properties of image\n"
" clone NAME NAME Clone an image\n"
" rename NAME NAME Rename an image\n"
" read-only NAME [BOOL] Mark or unmark image read-only\n"
" remove NAME... Remove an image\n"
" set-limit [NAME] BYTES Set image or pool size limit (disk quota)\n\n"
"Image Transfer Commands:\n"
" pull-tar URL [NAME] Download a TAR container image\n"
" pull-raw URL [NAME] Download a RAW container or VM image\n"
" pull-dkr REMOTE [NAME] Download a DKR container image\n"
" import-tar FILE [NAME] Import a local TAR container image\n"
" import-raw FILE [NAME] Import a local RAW container or VM image\n"
" export-tar NAME [FILE] Export a TAR container image locally\n"
" export-raw NAME [FILE] Export a RAW container or VM image locally\n"
" list-transfers Show list of downloads in progress\n"
" cancel-transfer Cancel a download\n"
, program_invocation_short_name);
return 0;
}
static int parse_argv(int argc, char *argv[]) {
enum {
ARG_VERSION = 0x100,
ARG_NO_PAGER,
ARG_NO_LEGEND,
ARG_KILL_WHO,
ARG_READ_ONLY,
ARG_MKDIR,
ARG_NO_ASK_PASSWORD,
ARG_VERIFY,
ARG_FORCE,
ARG_DKR_INDEX_URL,
ARG_FORMAT,
ARG_UID,
ARG_SETENV,
};
static const struct option options[] = {
{ "help", no_argument, NULL, 'h' },
{ "version", no_argument, NULL, ARG_VERSION },
{ "property", required_argument, NULL, 'p' },
{ "all", no_argument, NULL, 'a' },
{ "full", no_argument, NULL, 'l' },
{ "no-pager", no_argument, NULL, ARG_NO_PAGER },
{ "no-legend", no_argument, NULL, ARG_NO_LEGEND },
{ "kill-who", required_argument, NULL, ARG_KILL_WHO },
{ "signal", required_argument, NULL, 's' },
{ "host", required_argument, NULL, 'H' },
{ "machine", required_argument, NULL, 'M' },
{ "read-only", no_argument, NULL, ARG_READ_ONLY },
{ "mkdir", no_argument, NULL, ARG_MKDIR },
{ "quiet", no_argument, NULL, 'q' },
{ "lines", required_argument, NULL, 'n' },
{ "output", required_argument, NULL, 'o' },
{ "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
{ "verify", required_argument, NULL, ARG_VERIFY },
{ "force", no_argument, NULL, ARG_FORCE },
{ "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
{ "format", required_argument, NULL, ARG_FORMAT },
{ "uid", required_argument, NULL, ARG_UID },
{ "setenv", required_argument, NULL, ARG_SETENV },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
switch (c) {
case 'h':
return help(0, NULL, NULL);
case ARG_VERSION:
return version();
case 'p':
r = strv_extend(&arg_property, optarg);
if (r < 0)
return log_oom();
/* If the user asked for a particular
* property, show it to him, even if it is
* empty. */
arg_all = true;
break;
case 'a':
arg_all = true;
break;
case 'l':
arg_full = true;
break;
case 'n':
if (safe_atou(optarg, &arg_lines) < 0) {
log_error("Failed to parse lines '%s'", optarg);
return -EINVAL;
}
break;
case 'o':
arg_output = output_mode_from_string(optarg);
if (arg_output < 0) {
log_error("Unknown output '%s'.", optarg);
return -EINVAL;
}
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case ARG_KILL_WHO:
arg_kill_who = optarg;
break;
case 's':
arg_signal = signal_from_string_try_harder(optarg);
if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
break;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
arg_transport = BUS_TRANSPORT_MACHINE;
arg_host = optarg;
break;
case ARG_READ_ONLY:
arg_read_only = true;
break;
case ARG_MKDIR:
arg_mkdir = true;
break;
case 'q':
arg_quiet = true;
break;
case ARG_VERIFY:
arg_verify = import_verify_from_string(optarg);
if (arg_verify < 0) {
log_error("Failed to parse --verify= setting: %s", optarg);
return -EINVAL;
}
break;
case ARG_FORCE:
arg_force = true;
break;
case ARG_DKR_INDEX_URL:
if (!http_url_is_valid(optarg)) {
log_error("Index URL is invalid: %s", optarg);
return -EINVAL;
}
arg_dkr_index_url = optarg;
break;
case ARG_FORMAT:
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) {
log_error("Unknown format: %s", optarg);
return -EINVAL;
}
arg_format = optarg;
break;
case ARG_UID:
arg_uid = optarg;
break;
case ARG_SETENV:
if (!env_assignment_is_valid(optarg)) {
log_error("Environment assignment invalid: %s", optarg);
return -EINVAL;
}
r = strv_extend(&arg_setenv, optarg);
if (r < 0)
return log_oom();
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
return 1;
}
static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
static const Verb verbs[] = {
{ "help", VERB_ANY, VERB_ANY, 0, help },
{ "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
{ "list-images", VERB_ANY, 1, 0, list_images },
{ "status", 2, VERB_ANY, 0, show_machine },
{ "image-status", VERB_ANY, VERB_ANY, 0, show_image },
{ "show", VERB_ANY, VERB_ANY, 0, show_machine },
{ "show-image", VERB_ANY, VERB_ANY, 0, show_image },
{ "terminate", 2, VERB_ANY, 0, terminate_machine },
{ "reboot", 2, VERB_ANY, 0, reboot_machine },
{ "poweroff", 2, VERB_ANY, 0, poweroff_machine },
{ "kill", 2, VERB_ANY, 0, kill_machine },
{ "login", VERB_ANY, 2, 0, login_machine },
{ "shell", VERB_ANY, VERB_ANY, 0, shell_machine },
{ "bind", 3, 4, 0, bind_mount },
{ "copy-to", 3, 4, 0, copy_files },
{ "copy-from", 3, 4, 0, copy_files },
{ "remove", 2, VERB_ANY, 0, remove_image },
{ "rename", 3, 3, 0, rename_image },
{ "clone", 3, 3, 0, clone_image },
{ "read-only", 2, 3, 0, read_only_image },
{ "start", 2, VERB_ANY, 0, start_machine },
{ "enable", 2, VERB_ANY, 0, enable_machine },
{ "disable", 2, VERB_ANY, 0, enable_machine },
{ "import-tar", 2, 3, 0, import_tar },
{ "import-raw", 2, 3, 0, import_raw },
{ "export-tar", 2, 3, 0, export_tar },
{ "export-raw", 2, 3, 0, export_raw },
{ "pull-tar", 2, 3, 0, pull_tar },
{ "pull-raw", 2, 3, 0, pull_raw },
{ "pull-dkr", 2, 3, 0, pull_dkr },
{ "list-transfers", VERB_ANY, 1, 0, list_transfers },
{ "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
{ "set-limit", 2, 3, 0, set_limit },
{}
};
return dispatch_verb(argc, argv, verbs, bus);
}
int main(int argc, char*argv[]) {
_cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = bus_connect_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
r = machinectl_main(argc, argv, bus);
finish:
pager_close();
polkit_agent_close();
strv_free(arg_property);
strv_free(arg_setenv);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}