machinectl.c revision 7079cfeffb6d520f20ddff53fd78467e72e6cc94
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen This file is part of systemd.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Copyright 2013 Lennart Poettering
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is free software; you can redistribute it and/or modify it
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen under the terms of the GNU Lesser General Public License as published by
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen the Free Software Foundation; either version 2.1 of the License, or
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen (at your option) any later version.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen systemd is distributed in the hope that it will be useful, but
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen WITHOUT ANY WARRANTY; without even the implied warranty of
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen Lesser General Public License for more details.
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen You should have received a copy of the GNU Lesser General Public License
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen along with systemd; If not, see <http://www.gnu.org/licenses/>.
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_all = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_full = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_no_pager = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_legend = true;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_read_only = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_mkdir = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_quiet = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_ask_password = true;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic bool arg_force = false;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void pager_open_if_enabled(void) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic void polkit_agent_open_if_enabled(void) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen /* Open the polkit agent as a child process if necessary */
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersentypedef struct MachineInfo {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int compare_machine_info(const void *a, const void *b) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen const MachineInfo *x = a, *y = b;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersenstatic int list_machines(int argc, char *argv[], void *userdata) {
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "org.freedesktop.machine1",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "org.freedesktop.machine1.Manager",
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen "ListMachines",
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen log_error("Could not get machines: %s", bus_error_message(&error, -r));
7a695d8e1fda59857c4c23bcb50cd1e0aaf4a854Tom Gundersen r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
3b015d40c19d9338b66bf916d84dec601019c811Tom Gundersen for (j = 0; j < n_machines; j++)
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen printf("\n%zu machines listed.\n", n_machines);
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersentypedef struct ImageInfo {
962b0647298b601548b049893931d2477f06ab57Tom Gundersenstatic int compare_image_info(const void *a, const void *b) {
962b0647298b601548b049893931d2477f06ab57Tom Gundersen const ImageInfo *x = a, *y = b;
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersenstatic int list_images(int argc, char *argv[], void *userdata) {
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "org.freedesktop.machine1",
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "org.freedesktop.machine1.Manager",
a13c50e7a33e2b8e0481f725c6272142e6f71751Tom Gundersen "ListImages",
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen log_error("Could not get images: %s", bus_error_message(&error, -r));
9d96e6c3efbe5ef52b2855612d51db52c469beb2Tom Gundersen r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
size_t l;
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++;
return bus_log_parse_error(r);
return bus_log_parse_error(r);
if (arg_legend)
for (j = 0; j < n_images; j++) {
images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
if (arg_legend)
const char *cgroup;
if (!path)
return log_oom();
r = sd_bus_get_property(
bus,
"org.freedesktop.systemd1",
path,
&error,
&reply,
return bus_log_parse_error(r);
c = columns();
show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
"/org/freedesktop/machine1",
NULL,
&reply,
return bus_log_parse_error(r);
int family;
return bus_log_parse_error(r);
return bus_log_parse_error(r);
return bus_log_parse_error(r);
return bus_log_parse_error(r);
return bus_log_parse_error(r);
"/org/freedesktop/machine1",
NULL,
&reply,
return bus_log_parse_error(r);
pretty = v;
return bus_log_parse_error(r);
return bus_log_parse_error(r);
if (pretty)
typedef struct MachineStatusInfo {
char *name;
char *class;
char *service;
char *unit;
char *root_directory;
int *netif;
unsigned n_netif;
assert(i);
if (s1)
else if (s2)
if (i->leader > 0) {
if (i->service) {
if (i->class)
} else if (i->class)
if (i->root_directory)
if (i->n_netif > 0) {
for (c = 0; c < i->n_netif; c++) {
if (ifi < 0)
ifi = 0;
if (i->unit) {
i->unit,
NULL);
static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
size_t l;
return -EBADMSG;
if (!i->netif)
return -ENOMEM;
path,
map,
&info);
if (*new_line)
*new_line = true;
if (*new_line)
*new_line = true;
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
&reply,
return bus_log_parse_error(r);
if (properties)
typedef struct ImageStatusInfo {
char *name;
char *path;
char *type;
int read_only;
assert(i);
if (i->name) {
if (i->type)
if (i->path)
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)
path,
map,
&info);
if (*new_line)
*new_line = true;
if (*new_line)
*new_line = true;
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
&reply,
return bus_log_parse_error(r);
if (properties)
if (!arg_kill_who)
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
const char *object;
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
&reply,
return bus_log_parse_error(r);
r = sd_bus_get_property(
bus,
&error,
&reply2,
return bus_log_parse_error(r);
char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
bool copy_from;
return -EINVAL;
if (child < 0)
if (child == 0) {
int containerfd;
int mntfd;
if (mntfd < 0) {
if (containerfd < 0) {
if (copy_from)
return -EIO;
return -EIO;
const char *dest;
return -EINVAL;
return -ENOTSUP;
mount_slave_created = true;
goto finish;
mount_slave_mounted = true;
goto finish;
goto finish;
mount_tmp_created = true;
goto finish;
mount_tmp_mounted = true;
if (arg_read_only)
goto finish;
goto finish;
mount_outside_created = true;
goto finish;
mount_outside_mounted = true;
mount_tmp_mounted = false;
mount_tmp_created = false;
mount_slave_mounted = false;
mount_slave_created = false;
if (child < 0) {
goto finish;
if (child == 0) {
const char *mount_inside;
int mntfd;
if (mntfd < 0) {
if (arg_mkdir)
goto finish;
r = -EIO;
goto finish;
r = -EIO;
goto finish;
if (mount_tmp_mounted)
if (mount_tmp_created)
if (mount_slave_mounted)
if (mount_slave_created)
static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
assert(m);
if (*forward) {
char last_char = 0;
bool machine_died;
return -ENOTSUP;
"path='/org/freedesktop/machine1',",
"/org/freedesktop/machine1",
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_parse_error(r);
if (machine_died)
return ret;
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
return -EINVAL;
r = sd_bus_call_method(
bus,
"/org/freedesktop/machine1",
&error,
NULL,
return log_oom();
const char *object;
return -EINVAL;
return log_oom();
if (!unit)
return log_oom();
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_parse_error(r);
return log_oom();
int carries_install_info = 0;
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
method);
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_create_error(r);
return -EINVAL;
return log_oom();
if (!unit)
return log_oom();
return bus_log_create_error(r);
r = sd_bus_message_close_container(m);
return bus_log_create_error(r);
return bus_log_create_error(r);
return bus_log_parse_error(r);
m = sd_bus_message_unref(m);
bus,
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
"org.freedesktop.systemd1.Manager",
return bus_log_create_error(r);
return bus_log_create_error(r);
unsigned priority;
assert(m);
static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
assert(m);
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 arbort transfer.", PTR_TO_UINT32(userdata));
assert(m);
return bus_log_create_error(r);
r = sd_bus_add_match(
bus,
"path='/org/freedesktop/import1'",
r = sd_bus_add_match(
bus,
return bus_log_parse_error(r);
if (!arg_quiet)
return -EINVAL;
local = l;
if (local) {
return -EINVAL;
bus,
"/org/freedesktop/import1",
return bus_log_create_error(r);
return bus_log_create_error(r);
return -EINVAL;
local = l;
if (local) {
return -EINVAL;
bus,
"/org/freedesktop/import1",
return bus_log_create_error(r);
return bus_log_create_error(r);
return -EINVAL;
if (tag) {
tag++;
return -EINVAL;
return -EINVAL;
if (local)
local++;
if (local) {
return -EINVAL;
bus,
"/org/freedesktop/import1",
return bus_log_create_error(r);
tag,
return bus_log_create_error(r);
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;
r = sd_bus_call_method(
bus,
"/org/freedesktop/import1",
&error,
&reply,
NULL);
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 ++;
return bus_log_parse_error(r);
return bus_log_parse_error(r);
if (arg_legend)
for (j = 0; j < n_transfers; j++)
if (arg_legend)
r = sd_bus_call_method(
bus,
"/org/freedesktop/import1",
&error,
NULL,
" show NAME... Show properties of one or more VMs/containers\n"
" terminate NAME... Terminate one or more VMs/containers\n"
case ARG_VERSION:
return log_oom();
arg_all = true;
arg_all = true;
arg_full = true;
return -EINVAL;
if (arg_output < 0) {
return -EINVAL;
case ARG_NO_PAGER:
arg_no_pager = true;
case ARG_NO_LEGEND:
arg_legend = false;
case ARG_KILL_WHO:
if (arg_signal < 0) {
return -EINVAL;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
case ARG_READ_ONLY:
arg_read_only = true;
case ARG_MKDIR:
arg_mkdir = true;
arg_quiet = true;
case ARG_VERIFY:
if (arg_verify < 0) {
return -EINVAL;
case ARG_FORCE:
arg_force = true;
case ARG_DKR_INDEX_URL:
return -EINVAL;
return -EINVAL;
log_open();
goto finish;
goto finish;
pager_close();