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