machinectl.c revision 89fec31893bd71292de5ab88cd73816148165b2f
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering/***
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering This file is part of systemd.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering Copyright 2013 Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (at your option) any later version.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering systemd is distributed in the hope that it will be useful, but
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering***/
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <sys/socket.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <unistd.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <errno.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <string.h>
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering#include <getopt.h>
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering#include <locale.h>
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering#include <fcntl.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <netinet/in.h>
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering#include <arpa/inet.h>
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering#include <net/if.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include <sys/mount.h>
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering#include "sd-bus.h"
a09abc4ae0bdc0200324eaa0416f23ff2170ec4eLennart Poettering#include "log.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "util.h"
bb99a35a873c35e80b0b47fe045081022660374dLennart Poettering#include "macro.h"
bb99a35a873c35e80b0b47fe045081022660374dLennart Poettering#include "pager.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "spawn-polkit-agent.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "bus-util.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "bus-error.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "build.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "strv.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "unit-name.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "cgroup-show.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "logs-show.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "cgroup-util.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "ptyfwd.h"
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering#include "event-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "path-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "mkdir.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "copy.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "verbs.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "import-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "process-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "terminal-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "signal-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "env-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering#include "hostname-util.h"
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic char **arg_property = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_all = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_full = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_no_pager = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_legend = true;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic const char *arg_kill_who = NULL;
bb99a35a873c35e80b0b47fe045081022660374dLennart Poetteringstatic int arg_signal = SIGTERM;
bb99a35a873c35e80b0b47fe045081022660374dLennart Poetteringstatic BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic char *arg_host = NULL;
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poetteringstatic bool arg_read_only = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_mkdir = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_quiet = false;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_ask_password = true;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic unsigned arg_lines = 10;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic OutputMode arg_output = OUTPUT_SHORT;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic bool arg_force = false;
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poetteringstatic ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic const char* arg_dkr_index_url = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic const char* arg_format = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic const char *arg_uid = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic char **arg_setenv = NULL;
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic void pager_open_if_enabled(void) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (arg_no_pager)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering pager_open(false);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering}
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek /* Open the polkit agent as a child process if necessary */
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering if (!arg_ask_password)
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen return;
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen if (arg_transport != BUS_TRANSPORT_LOCAL)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return;
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering polkit_agent_open();
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic OutputFlags get_output_flags(void) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering arg_all * OUTPUT_SHOW_ALL |
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering arg_full * OUTPUT_FULL_WIDTH |
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
d0bbc21caa6e68693a47db60c93e99422bf2a858Lennart Poettering on_tty() * OUTPUT_COLOR |
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering !arg_quiet * OUTPUT_WARN_CUTOFF;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
44b601bc79e46722bc0f0862ee0ce34a2284ef11Lennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poetteringtypedef struct MachineInfo {
25d042e81516246b1ebf706a57c47ac19abb0b8aLennart Poettering const char *name;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const char *class;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering const char *service;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering} MachineInfo;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringstatic int compare_machine_info(const void *a, const void *b) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering const MachineInfo *x = a, *y = b;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return strcmp(x->name, y->name);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering}
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringstatic int list_machines(int argc, char *argv[], void *userdata) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
25d042e81516246b1ebf706a57c47ac19abb0b8aLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering _cleanup_free_ MachineInfo *machines = NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const char *name, *class, *service, *object;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering size_t n_machines = 0, n_allocated = 0, j;
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering sd_bus *bus = userdata;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering int r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering assert(bus);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering pager_open_if_enabled();
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_bus_call_method(
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering bus,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "org.freedesktop.machine1",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "/org/freedesktop/machine1",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "org.freedesktop.machine1.Manager",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "ListMachines",
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering &error,
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering &reply,
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering NULL);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (r < 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering log_error("Could not get machines: %s", bus_error_message(&error, -r));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return r;
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering }
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering
72f1d5a2880d103dc1c1746f5c02e192e054705eLennart Poettering r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (r < 0)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return bus_log_parse_error(r);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering size_t l;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (name[0] == '.' && !arg_all)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering continue;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return log_oom();
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering machines[n_machines].name = name;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering machines[n_machines].class = class;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering machines[n_machines].service = service;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering l = strlen(name);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (l > max_name)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering max_name = l;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering l = strlen(class);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (l > max_class)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering max_class = l;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering l = strlen(service);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (l > max_service)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering max_service = l;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering n_machines ++;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering }
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return bus_log_parse_error(r);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_bus_message_exit_container(reply);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (r < 0)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return bus_log_parse_error(r);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (arg_legend)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering printf("%-*s %-*s %-*s\n",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (int) max_name, "MACHINE",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (int) max_class, "CLASS",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (int) max_service, "SERVICE");
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering for (j = 0; j < n_machines; j++)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering printf("%-*s %-*s %-*s\n",
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek (int) max_name, machines[j].name,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (int) max_class, machines[j].class,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering (int) max_service, machines[j].service);
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek if (arg_legend)
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek printf("\n%zu machines listed.\n", n_machines);
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek return 0;
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek}
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmektypedef struct ImageInfo {
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek const char *name;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering const char *type;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering bool read_only;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering usec_t crtime;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering usec_t mtime;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering uint64_t size;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering} ImageInfo;
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poetteringstatic int compare_image_info(const void *a, const void *b) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering const ImageInfo *x = a, *y = b;
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen return strcmp(x->name, y->name);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering}
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poetteringstatic int list_images(int argc, char *argv[], void *userdata) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering _cleanup_free_ ImageInfo *images = NULL;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering size_t n_images = 0, n_allocated = 0, j;
a5344d2c3b0f14e954ce1c0ef905c5b44bc5bf0aLennart Poettering const char *name, *type, *object;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering sd_bus *bus = userdata;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering uint64_t crtime, mtime, size;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering int read_only, r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
29abad107f8610e73b2fc091216040b579c75453Zbigniew Jędrzejewski-Szmek assert(bus);
29abad107f8610e73b2fc091216040b579c75453Zbigniew Jędrzejewski-Szmek
2a0e0692565f0435657c93498e09cbb2d3517152Shawn Landden pager_open_if_enabled();
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_bus_call_method(
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering bus,
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering "org.freedesktop.machine1",
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering "/org/freedesktop/machine1",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "org.freedesktop.machine1.Manager",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "ListImages",
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering &error,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering &reply,
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering "");
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (r < 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering log_error("Could not get images: %s", bus_error_message(&error, -r));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return r;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (r < 0)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return bus_log_parse_error(r);
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering size_t l;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (name[0] == '.' && !arg_all)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering continue;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return log_oom();
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering images[n_images].name = name;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering images[n_images].type = type;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering images[n_images].read_only = read_only;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering images[n_images].crtime = crtime;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering images[n_images].mtime = mtime;
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering images[n_images].size = size;
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering l = strlen(name);
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering if (l > max_name)
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering max_name = l;
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering l = strlen(type);
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering if (l > max_type)
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering max_type = l;
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering if (crtime != 0) {
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering if (l > max_crtime)
ee55db41442ad8055f5a84a339b1e0e22bc037c4Lennart Poettering max_crtime = l;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering if (mtime != 0) {
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering if (l > max_mtime)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering max_mtime = l;
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering }
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering if (size != (uint64_t) -1) {
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering if (l > max_size)
6c045c0b4c49c88a1d3b9360c05efa5084796d2dZbigniew Jędrzejewski-Szmek max_size = l;
6c045c0b4c49c88a1d3b9360c05efa5084796d2dZbigniew Jędrzejewski-Szmek }
6c045c0b4c49c88a1d3b9360c05efa5084796d2dZbigniew Jędrzejewski-Szmek
6c045c0b4c49c88a1d3b9360c05efa5084796d2dZbigniew Jędrzejewski-Szmek n_images++;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering }
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering if (r < 0)
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering return bus_log_parse_error(r);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering r = sd_bus_message_exit_container(reply);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (r < 0)
8e33886ec582336564ae11b80023abe93d7599c0Zbigniew Jędrzejewski-Szmek return bus_log_parse_error(r);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (arg_legend)
73843b52585d42cc1a970a1c664818ece6942e9eLennart Poettering printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering (int) max_name, "NAME",
73843b52585d42cc1a970a1c664818ece6942e9eLennart Poettering (int) max_type, "TYPE",
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering "RO",
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering (int) max_size, "USAGE",
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering (int) max_crtime, "CREATED",
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering (int) max_mtime, "MODIFIED");
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering for (j = 0; j < n_images; j++) {
73843b52585d42cc1a970a1c664818ece6942e9eLennart Poettering char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
87b0284327e34a4b96c22085fa2cdb3219294991Zbigniew Jędrzejewski-Szmek (int) max_name, images[j].name,
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek (int) max_type, images[j].type,
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
73843b52585d42cc1a970a1c664818ece6942e9eLennart Poettering (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering }
73843b52585d42cc1a970a1c664818ece6942e9eLennart Poettering
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering if (arg_legend)
c79e98eadd3056a36a662699fa650db5b1bca0c3Lennart Poettering printf("\n%zu images listed.\n", n_images);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering return 0;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering}
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poetteringstatic int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering _cleanup_free_ char *path = NULL;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering const char *cgroup;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering int r;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering unsigned c;
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering assert(bus);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering assert(unit);
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering
0dad12c190b7493955cd60d2a1625199b1709f69Lennart Poettering if (arg_transport == BUS_TRANSPORT_REMOTE)
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering return 0;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering path = unit_dbus_path_from_name(unit);
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering if (!path)
7f3e62571a63ac90de6ac5eefeeb8d3e9aa6f49eLennart Poettering return log_oom();
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering r = sd_bus_get_property(
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering bus,
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering "org.freedesktop.systemd1",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering path,
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" :
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering endswith(unit, ".slice") ? "org.freedesktop.systemd1.Slice" : "org.freedesktop.systemd1.Service",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "ControlGroup",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering &error,
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering &reply,
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "s");
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (r < 0) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering return r;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering }
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering r = sd_bus_message_read(reply, "s", &cgroup);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (r < 0)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering return bus_log_parse_error(r);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering return 0;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering c = columns();
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (c > 18)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering c -= 18;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering else
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek c = 0;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering return 0;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering}
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poetteringstatic int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering int r;
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering
5c0aa72a4999bdcf03fe93ed5c8213c2b4c681f0Lennart Poettering assert(bus);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering assert(name);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering assert(prefix);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering assert(prefix2);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering r = sd_bus_call_method(bus,
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "org.freedesktop.machine1",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "/org/freedesktop/machine1",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "org.freedesktop.machine1.Manager",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering "GetMachineAddresses",
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering NULL,
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering &reply,
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering "s", name);
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek if (r < 0)
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek return r;
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek
6e5abe1564070a760196b97031eca9cf5e95e8a2Zbigniew Jędrzejewski-Szmek r = sd_bus_message_enter_container(reply, 'a', "(iay)");
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek if (r < 0)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return bus_log_parse_error(r);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering int family;
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen const void *a;
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen size_t sz;
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering r = sd_bus_message_read(reply, "i", &family);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (r < 0)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return bus_log_parse_error(r);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek r = sd_bus_message_read_array(reply, 'y', &a, &sz);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (r < 0)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return bus_log_parse_error(r);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek
86b9b8e70d54e79db3ff4f67bbd5280ecfc82537Lennart Poettering fputs(prefix, stdout);
86b9b8e70d54e79db3ff4f67bbd5280ecfc82537Lennart Poettering fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
bb99a35a873c35e80b0b47fe045081022660374dLennart Poettering if (family == AF_INET6 && ifi > 0)
bb99a35a873c35e80b0b47fe045081022660374dLennart Poettering printf("%%%i", ifi);
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering fputc('\n', stdout);
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering r = sd_bus_message_exit_container(reply);
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering if (r < 0)
8b38f3cc3eb73adf9536cb73d0f319e60d42ea0cLennart Poettering return bus_log_parse_error(r);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering if (prefix != prefix2)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering prefix = prefix2;
a6e87e90ede66815989ba2db92a07102a69906feLennart Poettering }
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (r < 0)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return bus_log_parse_error(r);
4cd9a9d9ecf3a8835e21930f3215a5f5b74144beLennart Poettering
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering r = sd_bus_message_exit_container(reply);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering if (r < 0)
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering return bus_log_parse_error(r);
224f2ee221e77c326d1d7761abb6e812432b2163Lennart Poettering
224f2ee221e77c326d1d7761abb6e812432b2163Lennart Poettering return 0;
224f2ee221e77c326d1d7761abb6e812432b2163Lennart Poettering}
224f2ee221e77c326d1d7761abb6e812432b2163Lennart Poettering
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poetteringstatic int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
553acb7b6b8d4f16a4747b1f978e8b7888fbfb2cZbigniew Jędrzejewski-Szmek _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek const char *k, *v, *pretty = NULL;
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek int r;
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek assert(bus);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek assert(name);
61c024b328d5493a334242a4d01ba923582093faZbigniew Jędrzejewski-Szmek assert(prefix);
fe6521272ba203ec8f0d5a94f0729960b3f90525Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = sd_bus_call_method(bus,
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering "org.freedesktop.machine1",
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering "/org/freedesktop/machine1",
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering "org.freedesktop.machine1.Manager",
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering "GetMachineOSRelease",
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering NULL,
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering &reply,
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering "s", name);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return r;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = sd_bus_message_enter_container(reply, 'a', "{ss}");
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0)
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return bus_log_parse_error(r);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (streq(k, "PRETTY_NAME"))
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen pretty = v;
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen }
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0)
5ffa8c818120e35c89becd938d160235c069dd12Zbigniew Jędrzejewski-Szmek return bus_log_parse_error(r);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering r = sd_bus_message_exit_container(reply);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (r < 0)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return bus_log_parse_error(r);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (pretty)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf("%s%s\n", prefix, pretty);
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering return 0;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering}
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringtypedef struct MachineStatusInfo {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char *name;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering sd_id128_t id;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char *class;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char *service;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char *unit;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char *root_directory;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering pid_t leader;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering struct dual_timestamp timestamp;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering int *netif;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering unsigned n_netif;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering} MachineStatusInfo;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringstatic void machine_status_info_clear(MachineStatusInfo *info) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (info) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->name);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->class);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->service);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->unit);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->root_directory);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering free(info->netif);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering zero(*info);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering }
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering}
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poetteringstatic void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering char since2[FORMAT_TIMESTAMP_MAX], *s2;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering int ifi = -1;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering assert(bus);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering assert(i);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering fputs(strna(i->name), stdout);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (!sd_id128_equal(i->id, SD_ID128_NULL))
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering else
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering putchar('\n');
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (s1)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering printf("\t Since: %s; %s\n", s2, s1);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering else if (s2)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf("\t Since: %s\n", s2);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen if (i->leader > 0) {
1ae464e09376853c52075ec4d8a6bfc4b4036d0cThomas Hindoe Paaboel Andersen _cleanup_free_ char *t = NULL;
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf("\t Leader: %u", (unsigned) i->leader);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering get_process_comm(i->leader, &t);
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering if (t)
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf(" (%s)", t);
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering putchar('\n');
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering }
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering if (i->service) {
b070e7f3c9ed680c821bd89d42506695f2438506Lennart Poettering printf("\t Service: %s", i->service);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (i->class)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering printf("; class %s", i->class);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering putchar('\n');
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering } else if (i->class)
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering printf("\t Class: %s\n", i->class);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (i->root_directory)
3ed08c446cfaaae2b234fdfeb0c34ab6b4748c3eLennart Poettering printf("\t Root: %s\n", i->root_directory);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering if (i->n_netif > 0) {
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering unsigned c;
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering fputs("\t Iface:", stdout);
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering
18c7ed186be28800a2eeb37ad31c9c44480d3d9cLennart Poettering for (c = 0; c < i->n_netif; c++) {
char name[IF_NAMESIZE+1] = "";
if (if_indextoname(i->netif[c], name)) {
fputc(' ', stdout);
fputs(name, stdout);
if (ifi < 0)
ifi = i->netif[c];
else
ifi = 0;
} else
printf(" %i", i->netif[c]);
}
fputc('\n', stdout);
}
print_addresses(bus, i->name, ifi,
"\t Address: ",
"\t ");
print_os_release(bus, i->name, "\t OS: ");
if (i->unit) {
printf("\t Unit: %s\n", i->unit);
show_unit_cgroup(bus, i->unit, i->leader);
if (arg_transport == BUS_TRANSPORT_LOCAL) {
show_journal_by_unit(
stdout,
i->unit,
arg_output,
0,
i->timestamp.monotonic,
arg_lines,
0,
get_output_flags() | OUTPUT_BEGIN_NEWLINE,
SD_JOURNAL_LOCAL_ONLY,
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;
assert_cc(sizeof(int32_t) == sizeof(int));
r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
if (r < 0)
return r;
if (r == 0)
return -EBADMSG;
i->n_netif = l / sizeof(int32_t);
i->netif = memdup(v, l);
if (!i->netif)
return -ENOMEM;
return 0;
}
static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
{ "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
{ "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
{ "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
{ "NetworkInterfaces", "ai", map_netif, 0 },
{}
};
_cleanup_(machine_status_info_clear) MachineStatusInfo info = {};
int r;
assert(verb);
assert(bus);
assert(path);
assert(new_line);
r = bus_map_all_properties(bus,
"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;
print_machine_status_info(bus, &info);
return r;
}
static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
assert(bus);
assert(path);
assert(new_line);
if (*new_line)
printf("\n");
*new_line = true;
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
static int show_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
bool properties, new_line = false;
sd_bus *bus = userdata;
int r = 0, i;
assert(bus);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (properties && argc <= 1) {
/* If no argument is specified, inspect the manager
* itself */
r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
if (r < 0)
return r;
}
for (i = 1; i < argc; i++) {
const char *path = NULL;
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) {
log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_machine_properties(bus, path, &new_line);
else
r = show_machine_info(argv[0], bus, path, &new_line);
}
return r;
}
typedef struct ImageStatusInfo {
char *name;
char *path;
char *type;
int read_only;
usec_t crtime;
usec_t mtime;
uint64_t usage;
uint64_t limit;
uint64_t usage_exclusive;
uint64_t limit_exclusive;
} ImageStatusInfo;
static void image_status_info_clear(ImageStatusInfo *info) {
if (info) {
free(info->name);
free(info->path);
free(info->type);
zero(*info);
}
}
static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
char bs[FORMAT_BYTES_MAX], *s3;
char bs_exclusive[FORMAT_BYTES_MAX], *s4;
assert(bus);
assert(i);
if (i->name) {
fputs(i->name, stdout);
putchar('\n');
}
if (i->type)
printf("\t Type: %s\n", i->type);
if (i->path)
printf("\t Path: %s\n", i->path);
printf("\t RO: %s%s%s\n",
i->read_only ? ansi_highlight_red() : "",
i->read_only ? "read-only" : "writable",
i->read_only ? ansi_highlight_off() : "");
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
if (s1 && s2)
printf("\t Created: %s; %s\n", s2, s1);
else if (s2)
printf("\t Created: %s\n", s2);
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
if (s1 && s2)
printf("\tModified: %s; %s\n", s2, s1);
else if (s2)
printf("\tModified: %s\n", s2);
s3 = format_bytes(bs, sizeof(bs), i->usage);
s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
if (s3 && s4)
printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
else if (s3)
printf("\t Usage: %s\n", s3);
s3 = format_bytes(bs, sizeof(bs), i->limit);
s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
if (s3 && s4)
printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
else if (s3)
printf("\t Limit: %s\n", s3);
}
static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
{ "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
{ "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
{ "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
{ "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
{ "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
{ "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
{ "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
{ "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
{ "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
{}
};
_cleanup_(image_status_info_clear) ImageStatusInfo info = {};
int r;
assert(bus);
assert(path);
assert(new_line);
r = bus_map_all_properties(bus,
"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;
print_image_status_info(bus, &info);
return r;
}
typedef struct PoolStatusInfo {
char *path;
uint64_t usage;
uint64_t limit;
} PoolStatusInfo;
static void pool_status_info_clear(PoolStatusInfo *info) {
if (info) {
free(info->path);
zero(*info);
info->usage = -1;
info->limit = -1;
}
}
static void print_pool_status_info(sd_bus *bus, PoolStatusInfo *i) {
char bs[FORMAT_BYTES_MAX], *s;
if (i->path)
printf("\t Path: %s\n", i->path);
s = format_bytes(bs, sizeof(bs), i->usage);
if (s)
printf("\t Usage: %s\n", s);
s = format_bytes(bs, sizeof(bs), i->limit);
if (s)
printf("\t Limit: %s\n", s);
}
static int show_pool_info(sd_bus *bus) {
static const struct bus_properties_map map[] = {
{ "PoolPath", "s", NULL, offsetof(PoolStatusInfo, path) },
{ "PoolUsage", "t", NULL, offsetof(PoolStatusInfo, usage) },
{ "PoolLimit", "t", NULL, offsetof(PoolStatusInfo, limit) },
{}
};
_cleanup_(pool_status_info_clear) PoolStatusInfo info = {
.usage = (uint64_t) -1,
.limit = (uint64_t) -1,
};
int r;
assert(bus);
r = bus_map_all_properties(bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
map,
&info);
if (r < 0)
return log_error_errno(r, "Could not get properties: %m");
print_pool_status_info(bus, &info);
return 0;
}
static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
assert(bus);
assert(path);
assert(new_line);
if (*new_line)
printf("\n");
*new_line = true;
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
static int show_image(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
bool properties, new_line = false;
sd_bus *bus = userdata;
int r = 0, i;
assert(bus);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (argc <= 1) {
/* If no argument is specified, inspect the manager
* itself */
if (properties)
r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
else
r = show_pool_info(bus);
if (r < 0)
return r;
}
for (i = 1; i < argc; i++) {
const char *path = NULL;
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) {
log_error("Could not get path to image: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_image_properties(bus, path, &new_line);
else
r = show_image_info(bus, path, &new_line);
}
return r;
}
static int kill_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();
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, bool ignore_vhangup, 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, ignore_vhangup, false, 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 =
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, true, 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, false, 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 (streq(argv[argc-1], "-"))
limit = (uint64_t) -1;
else {
off_t off;
r = parse_size(argv[argc-1], 1024, &off);
if (r < 0)
return log_error("Failed to parse size: %s", argv[argc-1]);
limit = (uint64_t) off;
}
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:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
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_open_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;
}