machinectl.c revision 49cf4170d0b586551527ebf4297f8a3fe6bd71a3
/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <fcntl.h>
#include <getopt.h>
#include <locale.h>
#include <string.h>
#include <unistd.h>
#include "sd-bus.h"
#include "bus-error.h"
#include "bus-util.h"
#include "cgroup-show.h"
#include "cgroup-util.h"
#include "copy.h"
#include "env-util.h"
#include "event-util.h"
#include "fd-util.h"
#include "hostname-util.h"
#include "import-util.h"
#include "log.h"
#include "logs-show.h"
#include "macro.h"
#include "mkdir.h"
#include "pager.h"
#include "parse-util.h"
#include "path-util.h"
#include "process-util.h"
#include "ptyfwd.h"
#include "signal-util.h"
#include "spawn-polkit-agent.h"
#include "strv.h"
#include "terminal-util.h"
#include "unit-name.h"
#include "util.h"
#include "verbs.h"
#include "web-util.h"
static char **arg_property = NULL;
static bool arg_all = false;
static bool arg_full = false;
static bool arg_no_pager = false;
static bool arg_legend = true;
static const char *arg_kill_who = NULL;
static int arg_signal = SIGTERM;
static bool arg_read_only = false;
static bool arg_mkdir = false;
static bool arg_quiet = false;
static bool arg_ask_password = true;
static unsigned arg_lines = 10;
static bool arg_force = false;
static const char* arg_dkr_index_url = NULL;
static const char* arg_format = NULL;
static char **arg_setenv = NULL;
static void pager_open_if_enabled(void) {
if (arg_no_pager)
return;
pager_open(false);
}
static void polkit_agent_open_if_enabled(void) {
/* Open the polkit agent as a child process if necessary */
if (!arg_ask_password)
return;
if (arg_transport != BUS_TRANSPORT_LOCAL)
return;
}
static OutputFlags get_output_flags(void) {
return
on_tty() * OUTPUT_COLOR |
}
typedef struct MachineInfo {
const char *name;
const char *class;
const char *service;
} MachineInfo;
static int compare_machine_info(const void *a, const void *b) {
const MachineInfo *x = a, *y = b;
}
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"ListMachines",
&error,
&reply,
NULL);
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
size_t l;
continue;
return log_oom();
if (l > max_name)
max_name = l;
if (l > max_class)
max_class = l;
if (l > max_service)
max_service = l;
n_machines ++;
}
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
if (arg_legend)
printf("%-*s %-*s %-*s\n",
(int) max_name, "MACHINE",
(int) max_class, "CLASS",
(int) max_service, "SERVICE");
for (j = 0; j < n_machines; j++)
printf("%-*s %-*s %-*s\n",
if (arg_legend)
return 0;
}
typedef struct ImageInfo {
const char *name;
const char *type;
bool read_only;
} ImageInfo;
static int compare_image_info(const void *a, const void *b) {
const ImageInfo *x = a, *y = b;
}
size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
int read_only, r;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"ListImages",
&error,
&reply,
"");
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
size_t l;
continue;
return log_oom();
if (l > max_name)
max_name = l;
if (l > max_type)
max_type = l;
if (crtime != 0) {
if (l > max_crtime)
max_crtime = l;
}
if (mtime != 0) {
if (l > max_mtime)
max_mtime = l;
}
if (l > max_size)
max_size = l;
}
n_images++;
}
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
if (arg_legend)
printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
(int) max_name, "NAME",
(int) max_type, "TYPE",
"RO",
(int) max_size, "USAGE",
(int) max_crtime, "CREATED",
(int) max_mtime, "MODIFIED");
for (j = 0; j < n_images; j++) {
printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_normal() : "",
}
if (arg_legend)
return 0;
}
const char *cgroup;
int r;
unsigned c;
if (arg_transport == BUS_TRANSPORT_REMOTE)
return 0;
if (!path)
return log_oom();
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
"ControlGroup",
&error,
&reply,
"s");
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
return 0;
c = columns();
if (c > 18)
c -= 18;
else
c = 0;
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
return 0;
}
static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
int r;
r = sd_bus_call_method(bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"GetMachineAddresses",
NULL,
&reply,
"s", name);
if (r < 0)
return r;
if (r < 0)
return bus_log_parse_error(r);
int family;
const void *a;
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
}
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
return 0;
}
int r;
r = sd_bus_call_method(bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"GetMachineOSRelease",
NULL,
&reply,
"s", name);
if (r < 0)
return r;
if (r < 0)
return bus_log_parse_error(r);
if (streq(k, "PRETTY_NAME"))
pretty = v;
}
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
if (pretty)
return 0;
}
typedef struct MachineStatusInfo {
char *name;
char *class;
char *service;
char *unit;
char *root_directory;
struct dual_timestamp timestamp;
int *netif;
unsigned n_netif;
if (info) {
}
}
int ifi = -1;
assert(i);
else
putchar('\n');
if (s1)
else if (s2)
if (i->leader > 0) {
_cleanup_free_ char *t = NULL;
get_process_comm(i->leader, &t);
if (t)
printf(" (%s)", t);
putchar('\n');
}
if (i->service) {
if (i->class)
putchar('\n');
} else if (i->class)
if (i->root_directory)
if (i->n_netif > 0) {
unsigned c;
for (c = 0; c < i->n_netif; c++) {
if (ifi < 0)
else
ifi = 0;
} else
}
}
"\t Address: ",
"\t ");
if (i->unit) {
if (arg_transport == BUS_TRANSPORT_LOCAL)
i->unit,
0,
0,
true,
NULL);
}
}
static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
MachineStatusInfo *i = userdata;
size_t l;
const void *v;
int r;
r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
if (r < 0)
return r;
if (r == 0)
return -EBADMSG;
if (!i->netif)
return -ENOMEM;
return 0;
}
static const struct bus_properties_map map[] = {
{}
};
int r;
"org.freedesktop.machine1",
path,
map,
&info);
if (r < 0)
return log_error_errno(r, "Could not get properties: %m");
if (*new_line)
printf("\n");
*new_line = true;
return r;
}
int r;
if (*new_line)
printf("\n");
*new_line = true;
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
bool properties, new_line = false;
int r = 0, i;
/* If no argument is specified, inspect the manager
* itself */
if (r < 0)
return r;
}
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"GetMachine",
&error,
&reply,
"s", argv[i]);
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
if (properties)
else
}
return r;
}
typedef struct ImageStatusInfo {
char *name;
char *path;
char *type;
int read_only;
if (info) {
}
}
assert(i);
if (i->name) {
putchar('\n');
}
if (i->type)
if (i->path)
printf("\t RO: %s%s%s\n",
else if (s2)
else if (s2)
s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
else if (s3)
s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
else if (s3)
}
static const struct bus_properties_map map[] = {
{}
};
int r;
"org.freedesktop.machine1",
path,
map,
&info);
if (r < 0)
return log_error_errno(r, "Could not get properties: %m");
if (*new_line)
printf("\n");
*new_line = true;
return r;
}
typedef struct PoolStatusInfo {
char *path;
if (info) {
}
}
char bs[FORMAT_BYTES_MAX], *s;
if (i->path)
if (s)
printf("\t Usage: %s\n", s);
if (s)
printf("\t Limit: %s\n", s);
}
static const struct bus_properties_map map[] = {
{}
};
};
int r;
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
map,
&info);
if (r < 0)
return log_error_errno(r, "Could not get properties: %m");
return 0;
}
int r;
if (*new_line)
printf("\n");
*new_line = true;
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
bool properties, new_line = false;
int r = 0, i;
if (argc <= 1) {
/* If no argument is specified, inspect the manager
* itself */
if (properties)
else
r = show_pool_info(bus);
if (r < 0)
return r;
}
for (i = 1; i < argc; i++) {
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"GetImage",
&error,
&reply,
"s", argv[i]);
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
if (properties)
else
}
return r;
}
int r, i;
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,
if (r < 0) {
return r;
}
}
return 0;
}
arg_kill_who = "leader";
}
arg_kill_who = "leader";
}
int r, i;
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) {
return r;
}
}
return 0;
}
bool copy_from;
int r;
if (!path_is_absolute(host_path)) {
if (r < 0)
return log_error_errno(r, "Failed to make path absolute: %m");
}
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
&error,
NULL,
"sss",
argv[1],
if (r < 0)
return 0;
}
int r;
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],
if (r < 0) {
return r;
}
return 0;
}
int r;
assert(m);
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 */
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;
log_info("Connected to the local host. Press ^] three times within 1s to exit session.");
else
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");
(flags & PTY_FORWARD_IGNORE_VHANGUP) &&
if (last_char != '\n')
if (machine_died)
log_info("Connection to the local host terminated.");
else
return ret;
}
int master = -1, r;
log_error("--setenv= and --uid= are not supported for 'login'. Use 'shell' instead.");
return -EINVAL;
}
if (arg_transport != BUS_TRANSPORT_LOCAL &&
log_error("Login only supported on local machines.");
return -EOPNOTSUPP;
}
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
"member='MachineRemoved',"
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) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
}
int master = -1, r;
if (arg_transport != BUS_TRANSPORT_LOCAL &&
log_error("Shell only supported on local machines.");
return -EOPNOTSUPP;
}
/* Pass $TERM to shell session, if not explicitly specified. */
const char *t;
if (t) {
if (strv_extend(&arg_setenv, t) < 0)
return log_oom();
}
}
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
if (arg_uid)
else if (machine) {
const char *at;
if (at) {
}
}
machine = ".host";
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
"member='MachineRemoved',"
if (r < 0)
return log_error_errno(r, "Failed to add machine removal match: %m");
bus,
&m,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"OpenMachineShell");
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
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);
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
}
int r, i;
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) {
return r;
}
}
return 0;
}
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"RenameImage",
&error,
NULL,
if (r < 0) {
return r;
}
return 0;
}
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"CloneImage",
&error,
NULL,
if (r < 0) {
return r;
}
return 0;
}
int b = true, r;
if (argc > 2) {
if (b < 0) {
return -EINVAL;
}
}
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"MarkImageReadOnly",
&error,
NULL,
if (r < 0) {
return r;
}
return 0;
}
_cleanup_free_ char *e = NULL;
int r;
if (!machine_name_is_valid(name)) {
return -EINVAL;
}
e = unit_name_escape(name);
if (!e)
return log_oom();
if (r < 0)
return log_error_errno(r, "Failed to build unit name: %m");
return 0;
}
int r, i;
r = bus_wait_for_jobs_new(bus, &w);
if (r < 0)
return log_oom();
for (i = 1; i < argc; i++) {
const char *object;
if (r < 0)
return r;
r = sd_bus_call_method(
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
"StartUnit",
&error,
&reply,
if (r < 0) {
return r;
}
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;
}
int carries_install_info = 0;
int r, i;
bus,
&m,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
method);
if (r < 0)
return bus_log_create_error(r);
if (r < 0)
return bus_log_create_error(r);
for (i = 1; i < argc; i++) {
if (r < 0)
return r;
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);
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);
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
}
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) {
return r;
}
return 0;
}
unsigned priority;
int r;
assert(m);
if (r < 0) {
return 0;
}
return 0;
return 0;
return 0;
}
int r;
assert(m);
if (r < 0) {
return 0;
}
return 0;
return 0;
}
static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
assert(s);
if (!arg_quiet)
log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
return 0;
}
int r;
assert(m);
r = sd_event_default(&event);
if (r < 0)
return log_error_errno(r, "Failed to get event loop: %m");
if (r < 0)
return log_error_errno(r, "Failed to attach bus to event loop: %m");
r = sd_bus_add_match(
bus,
"type='signal',"
"sender='org.freedesktop.import1',"
"interface='org.freedesktop.import1.Manager',"
"member='TransferRemoved',"
"path='/org/freedesktop/import1'",
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
r = sd_bus_add_match(
bus,
"type='signal',"
"sender='org.freedesktop.import1',"
"interface='org.freedesktop.import1.Transfer',"
"member='LogMessage'",
if (r < 0)
return log_error_errno(r, "Failed to install match: %m");
if (r < 0) {
return r;
}
if (r < 0)
return bus_log_parse_error(r);
if (!arg_quiet)
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
return -r;
}
int r;
if (argc >= 2)
if (argc >= 3)
else if (path)
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
if (r < 0)
return log_oom();
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
if (path) {
if (fd < 0)
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportTar");
if (r < 0)
return bus_log_create_error(r);
m,
"hsbb",
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
int r;
if (argc >= 2)
if (argc >= 3)
else if (path)
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
if (r < 0)
return log_oom();
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
if (path) {
if (fd < 0)
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportRaw");
if (r < 0)
return bus_log_create_error(r);
m,
"hsbb",
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";
}
int r;
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
if (argc >= 3)
if (path) {
if (fd < 0)
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportTar");
if (r < 0)
return bus_log_create_error(r);
m,
"shs",
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
int r;
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
if (argc >= 3)
if (path) {
if (fd < 0)
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportRaw");
if (r < 0)
return bus_log_create_error(r);
m,
"shs",
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
int r;
if (!http_url_is_valid(remote)) {
return -EINVAL;
}
if (argc >= 3)
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 (local) {
if (r < 0)
return log_oom();
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullTar");
if (r < 0)
return bus_log_create_error(r);
m,
"sssb",
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
int r;
if (!http_url_is_valid(remote)) {
return -EINVAL;
}
if (argc >= 3)
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 (local) {
if (r < 0)
return log_oom();
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullRaw");
if (r < 0)
return bus_log_create_error(r);
m,
"sssb",
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
int r;
if (arg_verify != IMPORT_VERIFY_NO) {
log_error("Imports from DKR do not support image verification, please pass --verify=no.");
return -EINVAL;
}
if (tag) {
tag++;
}
if (!dkr_name_is_valid(remote)) {
return -EINVAL;
}
return -EINVAL;
}
if (argc >= 3)
else {
if (local)
local++;
else
}
if (local) {
if (!machine_name_is_valid(local)) {
return -EINVAL;
}
}
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullDkr");
if (r < 0)
return bus_log_create_error(r);
m,
"sssssb",
tag,
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
typedef struct TransferInfo {
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;
}
double progress;
int r;
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ListTransfers",
&error,
&reply,
NULL);
if (r < 0) {
return r;
}
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;
return log_oom();
if (l > max_type)
max_type = l;
if (l > max_remote)
max_remote = l;
if (l > max_local)
max_local = l;
n_transfers ++;
}
if (r < 0)
return bus_log_parse_error(r);
if (r < 0)
return bus_log_parse_error(r);
if (arg_legend)
printf("%-*s %-*s %-*s %-*s %-*s\n",
(int) 7, "PERCENT",
(int) max_type, "TYPE",
(int) max_local, "LOCAL",
(int) max_remote, "REMOTE");
for (j = 0; j < n_transfers; j++)
if (arg_legend)
return 0;
}
int r, i;
for (i = 1; i < argc; i++) {
if (r < 0)
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"CancelTransfer",
&error,
NULL,
"u", id);
if (r < 0) {
return r;
}
}
return 0;
}
int r;
else {
if (r < 0)
}
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,
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) {
return r;
}
return 0;
}
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"
" 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"
" 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"
return 0;
}
enum {
ARG_VERSION = 0x100,
};
{}
};
int c, r;
switch (c) {
case 'h':
case ARG_VERSION:
return version();
case 'p':
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':
return -EINVAL;
}
break;
case 'o':
if (arg_output < 0) {
return -EINVAL;
}
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case ARG_KILL_WHO:
break;
case 's':
if (arg_signal < 0) {
return -EINVAL;
}
break;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case 'H':
break;
case 'M':
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:
if (arg_verify < 0) {
return -EINVAL;
}
break;
case ARG_FORCE:
arg_force = true;
break;
case ARG_DKR_INDEX_URL:
if (!http_url_is_valid(optarg)) {
return -EINVAL;
}
break;
case ARG_FORMAT:
return -EINVAL;
}
arg_format = optarg;
break;
case ARG_UID:
break;
case ARG_SETENV:
if (!env_assignment_is_valid(optarg)) {
return -EINVAL;
}
if (r < 0)
return log_oom();
break;
case '?':
return -EINVAL;
default:
assert_not_reached("Unhandled option");
}
return 1;
}
{}
};
}
int r;
log_open();
if (r <= 0)
goto finish;
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
pager_close();
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}