machinectl.c revision 0b452006de98294d1690f045f6ea2f7f6630ec3b
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
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/socket.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <unistd.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <errno.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <string.h>
b5efdb8af40ea759a1ea584c1bc44ecc81dd00ceLennart Poettering#include <getopt.h>
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering#include <locale.h>
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include <fcntl.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <netinet/in.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <arpa/inet.h>
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include <net/if.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include <sys/mount.h>
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "sd-bus.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "log.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "macro.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "pager.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "spawn-polkit-agent.h"
d5099efc47d4e6ac60816b5381a5f607ab03f06eMichal Schmidt#include "bus-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "bus-error.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "build.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "strv.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "unit-name.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "cgroup-show.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "logs-show.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "cgroup-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "ptyfwd.h"
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering#include "event-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "path-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "mkdir.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "copy.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "verbs.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "import-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering#include "process-util.h"
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic char **arg_property = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_all = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_full = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart 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;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic char *arg_host = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_read_only = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_mkdir = false;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poetteringstatic bool arg_quiet = false;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poetteringstatic bool arg_ask_password = true;
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poetteringstatic unsigned arg_lines = 10;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic OutputMode arg_output = OUTPUT_SHORT;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic bool arg_force = false;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic const char* arg_dkr_index_url = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic const char* arg_format = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic void pager_open_if_enabled(void) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (arg_no_pager)
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack return;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering pager_open(false);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic void polkit_agent_open_if_enabled(void) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering /* Open the polkit agent as a child process if necessary */
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!arg_ask_password)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen if (arg_transport != BUS_TRANSPORT_LOCAL)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering polkit_agent_open();
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poetteringstatic OutputFlags get_output_flags(void) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering arg_all * OUTPUT_SHOW_ALL |
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering arg_full * OUTPUT_FULL_WIDTH |
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
db97a66aa69925f7403ba3c433e86320d136567dLennart Poettering on_tty() * OUTPUT_COLOR |
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering !arg_quiet * OUTPUT_WARN_CUTOFF;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidttypedef struct MachineInfo {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering const char *name;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering const char *class;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering const char *service;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering} MachineInfo;
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poetteringstatic int compare_machine_info(const void *a, const void *b) {
90ab504273a7f186ebb76e6acfb778b4e0d7c91bLennart Poettering const MachineInfo *x = a, *y = b;
db97a66aa69925f7403ba3c433e86320d136567dLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return strcmp(x->name, y->name);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidtstatic int list_machines(int argc, char *argv[], void *userdata) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack _cleanup_free_ MachineInfo *machines = NULL;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack const char *name, *class, *service, *object;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack size_t n_machines = 0, n_allocated = 0, j;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack sd_bus *bus = userdata;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack int r;
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack assert(bus);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack pager_open_if_enabled();
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack r = sd_bus_call_method(
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack bus,
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack "org.freedesktop.machine1",
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack "/org/freedesktop/machine1",
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack "org.freedesktop.machine1.Manager",
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack "ListMachines",
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack &error,
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack &reply,
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack NULL);
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack if (r < 0) {
b4f1862df2e45aba90386887d685b8bf3c840e10Daniel Mack log_error("Could not get machines: %s", bus_error_message(&error, -r));
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return bus_log_parse_error(r);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering size_t l;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return log_oom();
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering machines[n_machines].name = name;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering machines[n_machines].class = class;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering machines[n_machines].service = service;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering l = strlen(name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (l > max_name)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering max_name = l;
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l = strlen(class);
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen if (l > max_class)
cc7844e78751916acb639443c119763cafe2c684Lennart Poettering max_class = l;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering l = strlen(service);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (l > max_service)
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering max_service = l;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering n_machines ++;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return bus_log_parse_error(r);
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen r = sd_bus_message_exit_container(reply);
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen if (r < 0)
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen return bus_log_parse_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen if (arg_legend)
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering printf("%-*s %-*s %-*s\n",
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering (int) max_name, "MACHINE",
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering (int) max_class, "CLASS",
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering (int) max_service, "SERVICE");
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering for (j = 0; j < n_machines; j++)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf("%-*s %-*s %-*s\n",
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering (int) max_name, machines[j].name,
5cb36f41f01cf4b1f4395abfffd1b33116591e58Lennart Poettering (int) max_class, machines[j].class,
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen (int) max_service, machines[j].service);
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering if (arg_legend)
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen printf("\n%zu machines listed.\n", n_machines);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen return 0;
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen}
6f4dedb250f2d607eceefaa491f338becbeee7c0Tom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringtypedef struct ImageInfo {
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering const char *name;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *type;
0b58db658b5c3f586ac3a837427f1f7fec2abb2eLennart Poettering bool read_only;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering usec_t crtime;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering usec_t mtime;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering uint64_t size;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering} ImageInfo;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int compare_image_info(const void *a, const void *b) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const ImageInfo *x = a, *y = b;
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return strcmp(x->name, y->name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
4b95f1798f22c1bb75295f448188560cb6ec9eceLennart Poetteringstatic int list_images(int argc, char *argv[], void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering _cleanup_free_ ImageInfo *images = NULL;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering size_t n_images = 0, n_allocated = 0, j;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering const char *name, *type, *object;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering sd_bus *bus = userdata;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering uint64_t crtime, mtime, size;
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen int read_only, r;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering assert(bus);
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering pager_open_if_enabled();
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering r = sd_bus_call_method(
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering bus,
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "org.freedesktop.machine1",
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "/org/freedesktop/machine1",
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "org.freedesktop.machine1.Manager",
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "ListImages",
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering &error,
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering &reply,
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "");
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering if (r < 0) {
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering log_error("Could not get images: %s", bus_error_message(&error, -r));
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering return r;
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering }
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering if (r < 0)
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering return bus_log_parse_error(r);
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering size_t l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (name[0] == '.' && !arg_all)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering continue;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering return log_oom();
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering images[n_images].name = name;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering images[n_images].type = type;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering images[n_images].read_only = read_only;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering images[n_images].crtime = crtime;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering images[n_images].mtime = mtime;
1ade96e980d3c0855a04140f4728b3ffd429bbeaLennart Poettering images[n_images].size = size;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering l = strlen(name);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l > max_name)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering max_name = l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering l = strlen(type);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l > max_type)
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen max_type = l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (crtime != 0) {
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l > max_crtime)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering max_crtime = l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering }
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (mtime != 0) {
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l > max_mtime)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering max_mtime = l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering }
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (size != (uint64_t) -1) {
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (l > max_size)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering max_size = l;
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering }
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen n_images++;
bda2c408f8a739c19161818bcc842107f60652a2Tom Gundersen }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering return bus_log_parse_error(r);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_exit_container(reply);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
6073b6f26ab9fc6bf335faa7073ec443eef093fdTom Gundersen return bus_log_parse_error(r);
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering if (arg_legend)
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering (int) max_name, "NAME",
a51c10485af349eb15faa4d1a63b9818bcf3e589Lennart Poettering (int) max_type, "TYPE",
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering "RO",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) max_size, "USAGE",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) max_crtime, "CREATED",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) max_mtime, "MODIFIED");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
0dd25fb9f005d8ab7ac4bc10a609d00569f8c56aLennart Poettering for (j = 0; j < n_images; j++) {
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) max_name, images[j].name,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering (int) max_type, images[j].type,
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (arg_legend)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf("\n%zu images listed.\n", n_images);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
d6731e4c7964ee2860d4f5abdb0b52acd7a66960Tom Gundersen}
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering _cleanup_free_ char *path = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *cgroup;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering unsigned c;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(bus);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(unit);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (arg_transport == BUS_TRANSPORT_REMOTE)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering path = unit_dbus_path_from_name(unit);
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering if (!path)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return log_oom();
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_get_property(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering bus,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "org.freedesktop.systemd1",
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering path,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering "ControlGroup",
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering &error,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering &reply,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering "s");
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0) {
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return r;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering }
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering r = sd_bus_message_read(reply, "s", &cgroup);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering return bus_log_parse_error(r);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering if (isempty(cgroup))
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering return 0;
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering
2c27fbca2d88214bd305272308a370a962818f1eLennart Poettering if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering c = columns();
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (c > 18)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering c -= 18;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering else
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering c = 0;
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return 0;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(bus);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(name);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert(prefix);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering assert(prefix2);
0eac462399c8e87bcce252cf058eba9f2678f2bdLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering r = sd_bus_call_method(bus,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "org.freedesktop.machine1",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "/org/freedesktop/machine1",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering "org.freedesktop.machine1.Manager",
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering "GetMachineAddresses",
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering &reply,
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering "s", name);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_enter_container(reply, 'a', "(iay)");
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return bus_log_parse_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int family;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *a;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t sz;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read(reply, "i", &family);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return bus_log_parse_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_read_array(reply, 'y', &a, &sz);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (r < 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering return bus_log_parse_error(r);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fputs(prefix, stdout);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (family == AF_INET6 && ifi > 0)
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf("%%%i", ifi);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fputc('\n', stdout);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering r = sd_bus_message_exit_container(reply);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return bus_log_parse_error(r);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (prefix != prefix2)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering prefix = prefix2;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering }
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return bus_log_parse_error(r);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_bus_message_exit_container(reply);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (r < 0)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return bus_log_parse_error(r);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering return 0;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const char *k, *v, *pretty = NULL;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering assert(bus);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(name);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering assert(prefix);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering r = sd_bus_call_method(bus,
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering "org.freedesktop.machine1",
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering "/org/freedesktop/machine1",
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering "org.freedesktop.machine1.Manager",
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering "GetMachineOSRelease",
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering NULL,
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering &reply,
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering "s", name);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering if (r < 0)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering return r;
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering r = sd_bus_message_enter_container(reply, 'a', "{ss}");
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return bus_log_parse_error(r);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (streq(k, "PRETTY_NAME"))
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering pretty = v;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return bus_log_parse_error(r);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering r = sd_bus_message_exit_container(reply);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (r < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering return bus_log_parse_error(r);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (pretty)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering printf("%s%s\n", prefix, pretty);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering return 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering}
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poetteringtypedef struct MachineStatusInfo {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering char *name;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering sd_id128_t id;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering char *class;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering char *service;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering char *unit;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt char *root_directory;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering pid_t leader;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering struct dual_timestamp timestamp;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering int *netif;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt unsigned n_netif;
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering} MachineStatusInfo;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poetteringstatic void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering char since2[FORMAT_TIMESTAMP_MAX], *s2;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering int ifi = -1;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(bus);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering assert(i);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering fputs(strna(i->name), stdout);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (!sd_id128_equal(i->id, SD_ID128_NULL))
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering else
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering putchar('\n');
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering
19b50b5ba7ee8c1bfb330377309e4bab7a7531d8Lennart Poettering if (s1)
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering printf("\t Since: %s; %s\n", s2, s1);
4e945a6f7971fd7d1f6b2c62ee3afdaff3c95ce4Lennart Poettering else if (s2)
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering printf("\t Since: %s\n", s2);
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering if (i->leader > 0) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering _cleanup_free_ char *t = NULL;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf("\t Leader: %u", (unsigned) i->leader);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering get_process_comm(i->leader, &t);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (t)
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering printf(" (%s)", t);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering putchar('\n');
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (i->service) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf("\t Service: %s", i->service);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering if (i->class)
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering printf("; class %s", i->class);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
78c6a153c47f8d597c827bdcaf8c4e42ac87f738Lennart Poettering putchar('\n');
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering } else if (i->class)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf("\t Class: %s\n", i->class);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (i->root_directory)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf("\t Root: %s\n", i->root_directory);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (i->n_netif > 0) {
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering unsigned c;
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fputs("\t Iface:", stdout);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering for (c = 0; c < i->n_netif; c++) {
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt char name[IF_NAMESIZE+1] = "";
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (if_indextoname(i->netif[c], name)) {
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering fputc(' ', stdout);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering fputs(name, stdout);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering if (ifi < 0)
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering ifi = i->netif[c];
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering else
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering ifi = 0;
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering } else
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering printf(" %i", i->netif[c]);
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering }
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering fputc('\n', stdout);
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering }
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering print_addresses(bus, i->name, ifi,
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering "\t Address: ",
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt "\t ");
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering print_os_release(bus, i->name, "\t OS: ");
1c4baffc1895809bae9ac36b670af90a4cb9cd7dTom Gundersen
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (i->unit) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering printf("\t Unit: %s\n", i->unit);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering show_unit_cgroup(bus, i->unit, i->leader);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering if (arg_transport == BUS_TRANSPORT_LOCAL) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering show_journal_by_unit(
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering stdout,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering i->unit,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering arg_output,
1716f6dcf54d4c181c2e2558e3d5414f54c8d9caLennart Poettering 0,
ec2c5e4398f9d65e5dfe61530f2556224733d1e6Lennart Poettering i->timestamp.monotonic,
623a4c97b9175f95c4b1c6fc34e36c56f1e4ddbfLennart Poettering arg_lines,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering 0,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering get_output_flags() | OUTPUT_BEGIN_NEWLINE,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering SD_JOURNAL_LOCAL_ONLY,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering true,
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering NULL);
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering }
7b85d72f824cdf34554b349712b6b8e39095dbd4Lennart Poettering }
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering}
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poetteringstatic int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering MachineStatusInfo *i = userdata;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering size_t l;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering const void *v;
74b2466e14a1961bf3ac0e8a60cfaceec705bd59Lennart Poettering int r;
assert_cc(sizeof(int32_t) == sizeof(int));
r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
if (r < 0)
return r;
if (r == 0)
return -EBADMSG;
i->n_netif = l / sizeof(int32_t);
i->netif = memdup(v, l);
if (!i->netif)
return -ENOMEM;
return 0;
}
static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
{ "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
{ "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
{ "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
{ "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
{ "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
{ "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
{ "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
{ "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
{ "NetworkInterfaces", "ai", map_netif, 0 },
{}
};
MachineStatusInfo info = {};
int r;
assert(verb);
assert(bus);
assert(path);
assert(new_line);
r = bus_map_all_properties(bus,
"org.freedesktop.machine1",
path,
map,
&info);
if (r < 0)
return log_error_errno(r, "Could not get properties: %m");
if (*new_line)
printf("\n");
*new_line = true;
print_machine_status_info(bus, &info);
free(info.name);
free(info.class);
free(info.service);
free(info.unit);
free(info.root_directory);
free(info.netif);
return r;
}
static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
int r;
assert(bus);
assert(path);
assert(new_line);
if (*new_line)
printf("\n");
*new_line = true;
r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
if (r < 0)
log_error_errno(r, "Could not get properties: %m");
return r;
}
static int show_machine(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
bool properties, new_line = false;
sd_bus *bus = userdata;
int r = 0, i;
assert(bus);
properties = !strstr(argv[0], "status");
pager_open_if_enabled();
if (properties && argc <= 1) {
/* If no argument is specified, inspect the manager
* itself */
r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
if (r < 0)
return r;
}
for (i = 1; i < argc; i++) {
const char *path = NULL;
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"GetMachine",
&error,
&reply,
"s", argv[i]);
if (r < 0) {
log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_read(reply, "o", &path);
if (r < 0)
return bus_log_parse_error(r);
if (properties)
r = show_machine_properties(bus, path, &new_line);
else
r = show_machine_info(argv[0], bus, path, &new_line);
}
return r;
}
typedef struct ImageStatusInfo {
char *name;
char *path;
char *type;
int read_only;
usec_t crtime;
usec_t mtime;
uint64_t usage;
uint64_t limit;
uint64_t usage_exclusive;
uint64_t limit_exclusive;
} ImageStatusInfo;
static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
char bs[FORMAT_BYTES_MAX], *s3;
char bs_exclusive[FORMAT_BYTES_MAX], *s4;
assert(bus);
assert(i);
if (i->name) {
fputs(i->name, stdout);
putchar('\n');
}
if (i->type)
printf("\t Type: %s\n", i->type);
if (i->path)
printf("\t Path: %s\n", i->path);
printf("\t RO: %s%s%s\n",
i->read_only ? ansi_highlight_red() : "",
i->read_only ? "read-only" : "writable",
i->read_only ? ansi_highlight_off() : "");
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
if (s1 && s2)
printf("\t Created: %s; %s\n", s2, s1);
else if (s2)
printf("\t Created: %s\n", s2);
s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
if (s1 && s2)
printf("\tModified: %s; %s\n", s2, s1);
else if (s2)
printf("\tModified: %s\n", s2);
s3 = format_bytes(bs, sizeof(bs), i->usage);
s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
if (s3 && s4)
printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
else if (s3)
printf("\t Usage: %s\n", s3);
s3 = format_bytes(bs, sizeof(bs), i->limit);
s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
if (s3 && s4)
printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
else if (s3)
printf("\t Limit: %s\n", s3);
}
static int show_image_info(sd_bus *bus, const char *path, bool *new_line) {
static const struct bus_properties_map map[] = {
{ "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
{ "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
{ "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
{ "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
{ "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
{ "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
{ "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
{ "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
{ "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
{ "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
{}
};
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);
free(info.name);
free(info.path);
free(info.type);
return r;
}
typedef struct PoolStatusInfo {
char *path;
uint64_t usage;
uint64_t limit;
} PoolStatusInfo;
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) },
{}
};
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);
free(info.path);
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;
sd_bus *bus = userdata;
bool copy_from;
int r;
assert(bus);
polkit_agent_open_if_enabled();
copy_from = streq(argv[0], "copy-from");
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],
argv[2],
argv[3]);
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 *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
PTYForward ** forward = (PTYForward**) userdata;
int r;
assert(bus);
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(bus), EXIT_FAILURE);
return 0;
}
static int login_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;
_cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
_cleanup_(pty_forward_freep) PTYForward *forward = NULL;
_cleanup_event_unref_ sd_event *event = NULL;
int master = -1, r, ret = 0;
sd_bus *bus = userdata;
const char *pty, *match;
char last_char = 0;
bool machine_died;
assert(bus);
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");
match = strjoina("type='signal',"
"sender='org.freedesktop.machine1',"
"path='/org/freedesktop/machine1',",
"interface='org.freedesktop.machine1.Manager',"
"member='MachineRemoved',"
"arg0='",
argv[1],
"'");
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", argv[1]);
if (r < 0) {
log_error("Failed to get machine 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);
sigprocmask_many(SIG_BLOCK, SIGWINCH, SIGTERM, SIGINT, -1);
log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
r = pty_forward_new(event, master, true, false, &forward);
if (r < 0)
return log_error_errno(r, "Failed to create PTY forwarder: %m");
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
pty_forward_get_last_char(forward, &last_char);
machine_died = 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.", argv[1]);
else
log_info("Connection to machine %s terminated.", argv[1]);
sd_event_get_exit_code(event, &ret);
return ret;
}
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 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 *e = NULL, *unit = NULL;
const char *object;
if (!machine_name_is_valid(argv[i])) {
log_error("Invalid machine name %s.", argv[i]);
return -EINVAL;
}
e = unit_name_escape(argv[i]);
if (!e)
return log_oom();
unit = unit_name_build("systemd-nspawn", e, ".service");
if (!unit)
return log_oom();
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 *e = NULL, *unit = NULL;
if (!machine_name_is_valid(argv[i])) {
log_error("Invalid machine name %s.", argv[i]);
return -EINVAL;
}
e = unit_name_escape(argv[i]);
if (!e)
return log_oom();
unit = unit_name_build("systemd-nspawn", e, ".service");
if (!unit)
return log_oom();
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);
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 *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *line;
unsigned priority;
int r;
assert(bus);
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 *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
const char **our_path = userdata, *path, *result;
uint32_t id;
int r;
assert(bus);
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(bus), !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);
sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
if (!arg_quiet)
log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
r = sd_event_loop(event);
if (r < 0)
return log_error_errno(r, "Failed to run event loop: %m");
return -r;
}
static int import_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *ll = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
if (argc >= 2)
path = argv[1];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (argc >= 3)
local = argv[2];
else if (path)
local = basename(path);
if (isempty(local) || streq(local, "-"))
local = NULL;
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
r = tar_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
if (path) {
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"hsbb",
fd >= 0 ? fd : STDIN_FILENO,
local,
arg_force,
arg_read_only);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int import_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *ll = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
if (argc >= 2)
path = argv[1];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (argc >= 3)
local = argv[2];
else if (path)
local = basename(path);
if (isempty(local) || streq(local, "-"))
local = NULL;
if (!local) {
log_error("Need either path or local name.");
return -EINVAL;
}
r = raw_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
if (path) {
fd = open(path, O_RDONLY|O_CLOEXEC|O_NOCTTY);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ImportRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"hsbb",
fd >= 0 ? fd : STDIN_FILENO,
local,
arg_force,
arg_read_only);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static void determine_compression_from_filename(const char *p) {
if (arg_format)
return;
if (!p)
return;
if (endswith(p, ".xz"))
arg_format = "xz";
else if (endswith(p, ".gz"))
arg_format = "gzip";
else if (endswith(p, ".bz2"))
arg_format = "bzip2";
}
static int export_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
local = argv[1];
if (!machine_name_is_valid(local)) {
log_error("Machine name %s is not valid.", local);
return -EINVAL;
}
if (argc >= 3)
path = argv[2];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (path) {
determine_compression_from_filename(path);
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"shs",
local,
fd >= 0 ? fd : STDOUT_FILENO,
arg_format);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int export_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_close_ int fd = -1;
const char *local = NULL, *path = NULL;
sd_bus *bus = userdata;
int r;
assert(bus);
local = argv[1];
if (!machine_name_is_valid(local)) {
log_error("Machine name %s is not valid.", local);
return -EINVAL;
}
if (argc >= 3)
path = argv[2];
if (isempty(path) || streq(path, "-"))
path = NULL;
if (path) {
determine_compression_from_filename(path);
fd = open(path, O_WRONLY|O_CREAT|O_TRUNC|O_CLOEXEC|O_NOCTTY, 0666);
if (fd < 0)
return log_error_errno(errno, "Failed to open %s: %m", path);
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ExportRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"shs",
local,
fd >= 0 ? fd : STDOUT_FILENO,
arg_format);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_tar(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *l = NULL, *ll = NULL;
const char *local, *remote;
sd_bus *bus = userdata;
int r;
assert(bus);
remote = argv[1];
if (!http_url_is_valid(remote)) {
log_error("URL '%s' is not valid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
r = import_url_last_component(remote, &l);
if (r < 0)
return log_error_errno(r, "Failed to get final component of URL: %m");
local = l;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
r = tar_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullTar");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssb",
remote,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_raw(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
_cleanup_free_ char *l = NULL, *ll = NULL;
const char *local, *remote;
sd_bus *bus = userdata;
int r;
assert(bus);
remote = argv[1];
if (!http_url_is_valid(remote)) {
log_error("URL '%s' is not valid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
r = import_url_last_component(remote, &l);
if (r < 0)
return log_error_errno(r, "Failed to get final component of URL: %m");
local = l;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
r = raw_strip_suffixes(local, &ll);
if (r < 0)
return log_oom();
local = ll;
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullRaw");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssb",
remote,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
static int pull_dkr(int argc, char *argv[], void *userdata) {
_cleanup_bus_message_unref_ sd_bus_message *m = NULL;
const char *local, *remote, *tag;
sd_bus *bus = userdata;
int r;
if (arg_verify != IMPORT_VERIFY_NO) {
log_error("Imports from DKR do not support image verification, please pass --verify=no.");
return -EINVAL;
}
remote = argv[1];
tag = strchr(remote, ':');
if (tag) {
remote = strndupa(remote, tag - remote);
tag++;
}
if (!dkr_name_is_valid(remote)) {
log_error("DKR name '%s' is invalid.", remote);
return -EINVAL;
}
if (tag && !dkr_tag_is_valid(tag)) {
log_error("DKR tag '%s' is invalid.", remote);
return -EINVAL;
}
if (argc >= 3)
local = argv[2];
else {
local = strchr(remote, '/');
if (local)
local++;
else
local = remote;
}
if (isempty(local) || streq(local, "-"))
local = NULL;
if (local) {
if (!machine_name_is_valid(local)) {
log_error("Local name %s is not a suitable machine name.", local);
return -EINVAL;
}
}
r = sd_bus_message_new_method_call(
bus,
&m,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"PullDkr");
if (r < 0)
return bus_log_create_error(r);
r = sd_bus_message_append(
m,
"sssssb",
arg_dkr_index_url,
remote,
tag,
local,
import_verify_to_string(arg_verify),
arg_force);
if (r < 0)
return bus_log_create_error(r);
return transfer_image_common(bus, m);
}
typedef struct TransferInfo {
uint32_t id;
const char *type;
const char *remote;
const char *local;
double progress;
} TransferInfo;
static int compare_transfer_info(const void *a, const void *b) {
const TransferInfo *x = a, *y = b;
return strcmp(x->local, y->local);
}
static int list_transfers(int argc, char *argv[], void *userdata) {
size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
_cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
_cleanup_free_ TransferInfo *transfers = NULL;
size_t n_transfers = 0, n_allocated = 0, j;
const char *type, *remote, *local, *object;
sd_bus *bus = userdata;
uint32_t id, max_id = 0;
double progress;
int r;
pager_open_if_enabled();
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"ListTransfers",
&error,
&reply,
NULL);
if (r < 0) {
log_error("Could not get transfers: %s", bus_error_message(&error, -r));
return r;
}
r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
if (r < 0)
return bus_log_parse_error(r);
while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
size_t l;
if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
return log_oom();
transfers[n_transfers].id = id;
transfers[n_transfers].type = type;
transfers[n_transfers].remote = remote;
transfers[n_transfers].local = local;
transfers[n_transfers].progress = progress;
l = strlen(type);
if (l > max_type)
max_type = l;
l = strlen(remote);
if (l > max_remote)
max_remote = l;
l = strlen(local);
if (l > max_local)
max_local = l;
if (id > max_id)
max_id = id;
n_transfers ++;
}
if (r < 0)
return bus_log_parse_error(r);
r = sd_bus_message_exit_container(reply);
if (r < 0)
return bus_log_parse_error(r);
qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
if (arg_legend)
printf("%-*s %-*s %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
(int) 7, "PERCENT",
(int) max_type, "TYPE",
(int) max_local, "LOCAL",
(int) max_remote, "REMOTE");
for (j = 0; j < n_transfers; j++)
printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
(int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
(int) 6, (unsigned) (transfers[j].progress * 100),
(int) max_type, transfers[j].type,
(int) max_local, transfers[j].local,
(int) max_remote, transfers[j].remote);
if (arg_legend)
printf("\n%zu transfers listed.\n", n_transfers);
return 0;
}
static int cancel_transfer(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
int r, i;
assert(bus);
polkit_agent_open_if_enabled();
for (i = 1; i < argc; i++) {
uint32_t id;
r = safe_atou32(argv[i], &id);
if (r < 0)
return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
r = sd_bus_call_method(
bus,
"org.freedesktop.import1",
"/org/freedesktop/import1",
"org.freedesktop.import1.Manager",
"CancelTransfer",
&error,
NULL,
"u", id);
if (r < 0) {
log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
return r;
}
}
return 0;
}
static int set_limit(int argc, char *argv[], void *userdata) {
_cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
sd_bus *bus = userdata;
uint64_t limit;
int r;
if (streq(argv[argc-1], "-"))
limit = (uint64_t) -1;
else {
off_t off;
r = parse_size(argv[argc-1], 1024, &off);
if (r < 0)
return log_error("Failed to parse size: %s", argv[argc-1]);
limit = (uint64_t) off;
}
if (argc > 2)
/* With two arguments changes the quota limit of the
* specified image */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetImageLimit",
&error,
NULL,
"st", argv[1], limit);
else
/* With one argument changes the pool quota limit */
r = sd_bus_call_method(
bus,
"org.freedesktop.machine1",
"/org/freedesktop/machine1",
"org.freedesktop.machine1.Manager",
"SetPoolLimit",
&error,
NULL,
"t", limit);
if (r < 0) {
log_error("Could not set limit: %s", bus_error_message(&error, -r));
return r;
}
return 0;
}
static int help(int argc, char *argv[], void *userdata) {
printf("%s [OPTIONS...] {COMMAND} ...\n\n"
"Send control commands to or query the virtual machine and container\n"
"registration manager.\n\n"
" -h --help Show this help\n"
" --version Show package version\n"
" --no-pager Do not pipe output into a pager\n"
" --no-legend Do not show the headers and footers\n"
" --no-ask-password Do not ask for system passwords\n"
" -H --host=[USER@]HOST Operate on remote host\n"
" -M --machine=CONTAINER Operate on local container\n"
" -p --property=NAME Show only properties by this name\n"
" -q --quiet Suppress output\n"
" -a --all Show all properties, including empty ones\n"
" -l --full Do not ellipsize output\n"
" --kill-who=WHO Who to send signal to\n"
" -s --signal=SIGNAL Which signal to send\n"
" --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 on a container\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,
};
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 },
{}
};
int c, r;
assert(argc >= 0);
assert(argv);
while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
switch (c) {
case 'h':
return help(0, NULL, NULL);
case ARG_VERSION:
puts(PACKAGE_STRING);
puts(SYSTEMD_FEATURES);
return 0;
case 'p':
r = strv_extend(&arg_property, optarg);
if (r < 0)
return log_oom();
/* If the user asked for a particular
* property, show it to him, even if it is
* empty. */
arg_all = true;
break;
case 'a':
arg_all = true;
break;
case 'l':
arg_full = true;
break;
case 'n':
if (safe_atou(optarg, &arg_lines) < 0) {
log_error("Failed to parse lines '%s'", optarg);
return -EINVAL;
}
break;
case 'o':
arg_output = output_mode_from_string(optarg);
if (arg_output < 0) {
log_error("Unknown output '%s'.", optarg);
return -EINVAL;
}
break;
case ARG_NO_PAGER:
arg_no_pager = true;
break;
case ARG_NO_LEGEND:
arg_legend = false;
break;
case ARG_KILL_WHO:
arg_kill_who = optarg;
break;
case 's':
arg_signal = signal_from_string_try_harder(optarg);
if (arg_signal < 0) {
log_error("Failed to parse signal string %s.", optarg);
return -EINVAL;
}
break;
case ARG_NO_ASK_PASSWORD:
arg_ask_password = false;
break;
case 'H':
arg_transport = BUS_TRANSPORT_REMOTE;
arg_host = optarg;
break;
case 'M':
arg_transport = BUS_TRANSPORT_MACHINE;
arg_host = optarg;
break;
case ARG_READ_ONLY:
arg_read_only = true;
break;
case ARG_MKDIR:
arg_mkdir = true;
break;
case 'q':
arg_quiet = true;
break;
case ARG_VERIFY:
arg_verify = import_verify_from_string(optarg);
if (arg_verify < 0) {
log_error("Failed to parse --verify= setting: %s", optarg);
return -EINVAL;
}
break;
case ARG_FORCE:
arg_force = true;
break;
case ARG_DKR_INDEX_URL:
if (!http_url_is_valid(optarg)) {
log_error("Index URL is invalid: %s", optarg);
return -EINVAL;
}
arg_dkr_index_url = optarg;
break;
case ARG_FORMAT:
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2")) {
log_error("Unknown format: %s", optarg);
return -EINVAL;
}
arg_format = optarg;
break;
case '?':
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", 2, 2, 0, login_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_close_unref_ sd_bus *bus = NULL;
int r;
setlocale(LC_ALL, "");
log_parse_environment();
log_open();
r = parse_argv(argc, argv);
if (r <= 0)
goto finish;
r = bus_open_transport(arg_transport, arg_host, false, &bus);
if (r < 0) {
log_error_errno(r, "Failed to create bus connection: %m");
goto finish;
}
sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
r = machinectl_main(argc, argv, bus);
finish:
pager_close();
polkit_agent_close();
strv_free(arg_property);
return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
}