1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
22 #include <sys/socket.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
33 #include <sys/mount.h>
40 #include "spawn-polkit-agent.h"
42 #include "bus-error.h"
45 #include "unit-name.h"
46 #include "cgroup-show.h"
47 #include "logs-show.h"
48 #include "cgroup-util.h"
50 #include "event-util.h"
51 #include "path-util.h"
55 #include "import-util.h"
57 static char **arg_property = NULL;
58 static bool arg_all = false;
59 static bool arg_full = false;
60 static bool arg_no_pager = false;
61 static bool arg_legend = true;
62 static const char *arg_kill_who = NULL;
63 static int arg_signal = SIGTERM;
64 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
65 static char *arg_host = NULL;
66 static bool arg_read_only = false;
67 static bool arg_mkdir = false;
68 static bool arg_quiet = false;
69 static bool arg_ask_password = true;
70 static unsigned arg_lines = 10;
71 static OutputMode arg_output = OUTPUT_SHORT;
72 static bool arg_force = false;
73 static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
74 static const char* arg_dkr_index_url = NULL;
76 static void pager_open_if_enabled(void) {
84 static void polkit_agent_open_if_enabled(void) {
86 /* Open the polkit agent as a child process if necessary */
88 if (!arg_ask_password)
91 if (arg_transport != BUS_TRANSPORT_LOCAL)
97 static OutputFlags get_output_flags(void) {
99 arg_all * OUTPUT_SHOW_ALL |
100 arg_full * OUTPUT_FULL_WIDTH |
101 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
102 on_tty() * OUTPUT_COLOR |
103 !arg_quiet * OUTPUT_WARN_CUTOFF;
106 typedef struct MachineInfo {
112 static int compare_machine_info(const void *a, const void *b) {
113 const MachineInfo *x = a, *y = b;
115 return strcmp(x->name, y->name);
118 static int list_machines(int argc, char *argv[], void *userdata) {
120 size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
121 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
122 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
123 _cleanup_free_ MachineInfo *machines = NULL;
124 const char *name, *class, *service, *object;
125 size_t n_machines = 0, n_allocated = 0, j;
126 sd_bus *bus = userdata;
131 pager_open_if_enabled();
133 r = sd_bus_call_method(
135 "org.freedesktop.machine1",
136 "/org/freedesktop/machine1",
137 "org.freedesktop.machine1.Manager",
143 log_error("Could not get machines: %s", bus_error_message(&error, -r));
147 r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
149 return bus_log_parse_error(r);
151 while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
154 if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
157 machines[n_machines].name = name;
158 machines[n_machines].class = class;
159 machines[n_machines].service = service;
176 return bus_log_parse_error(r);
178 r = sd_bus_message_exit_container(reply);
180 return bus_log_parse_error(r);
182 qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
185 printf("%-*s %-*s %-*s\n",
186 (int) max_name, "MACHINE",
187 (int) max_class, "CLASS",
188 (int) max_service, "SERVICE");
190 for (j = 0; j < n_machines; j++)
191 printf("%-*s %-*s %-*s\n",
192 (int) max_name, machines[j].name,
193 (int) max_class, machines[j].class,
194 (int) max_service, machines[j].service);
197 printf("\n%zu machines listed.\n", n_machines);
202 typedef struct ImageInfo {
211 static int compare_image_info(const void *a, const void *b) {
212 const ImageInfo *x = a, *y = b;
214 return strcmp(x->name, y->name);
217 static int list_images(int argc, char *argv[], void *userdata) {
219 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
220 size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
221 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
222 _cleanup_free_ ImageInfo *images = NULL;
223 size_t n_images = 0, n_allocated = 0, j;
224 const char *name, *type, *object;
225 sd_bus *bus = userdata;
226 uint64_t crtime, mtime, size;
231 pager_open_if_enabled();
233 r = sd_bus_call_method(
235 "org.freedesktop.machine1",
236 "/org/freedesktop/machine1",
237 "org.freedesktop.machine1.Manager",
243 log_error("Could not get images: %s", bus_error_message(&error, -r));
247 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
249 return bus_log_parse_error(r);
251 while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
252 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
255 if (name[0] == '.' && !arg_all)
258 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
261 images[n_images].name = name;
262 images[n_images].type = type;
263 images[n_images].read_only = read_only;
264 images[n_images].crtime = crtime;
265 images[n_images].mtime = mtime;
266 images[n_images].size = size;
277 l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
283 l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
288 if (size != (uint64_t) -1) {
289 l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
297 return bus_log_parse_error(r);
299 r = sd_bus_message_exit_container(reply);
301 return bus_log_parse_error(r);
303 qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
306 printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
307 (int) max_name, "NAME",
308 (int) max_type, "TYPE",
310 (int) max_size, "USAGE",
311 (int) max_crtime, "CREATED",
312 (int) max_mtime, "MODIFIED");
314 for (j = 0; j < n_images; j++) {
315 char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
317 printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
318 (int) max_name, images[j].name,
319 (int) max_type, images[j].type,
320 images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
321 (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
322 (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
323 (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
327 printf("\n%zu images listed.\n", n_images);
332 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
333 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
334 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
335 _cleanup_free_ char *path = NULL;
343 if (arg_transport == BUS_TRANSPORT_REMOTE)
346 path = unit_dbus_path_from_name(unit);
350 r = sd_bus_get_property(
352 "org.freedesktop.systemd1",
354 endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
360 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
364 r = sd_bus_message_read(reply, "s", &cgroup);
366 return bus_log_parse_error(r);
371 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
380 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
384 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
385 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
393 r = sd_bus_call_method(bus,
394 "org.freedesktop.machine1",
395 "/org/freedesktop/machine1",
396 "org.freedesktop.machine1.Manager",
397 "GetMachineAddresses",
404 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
406 return bus_log_parse_error(r);
408 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
412 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
414 r = sd_bus_message_read(reply, "i", &family);
416 return bus_log_parse_error(r);
418 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
420 return bus_log_parse_error(r);
422 fputs(prefix, stdout);
423 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
424 if (family == AF_INET6 && ifi > 0)
428 r = sd_bus_message_exit_container(reply);
430 return bus_log_parse_error(r);
432 if (prefix != prefix2)
436 return bus_log_parse_error(r);
438 r = sd_bus_message_exit_container(reply);
440 return bus_log_parse_error(r);
445 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
446 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
447 const char *k, *v, *pretty = NULL;
454 r = sd_bus_call_method(bus,
455 "org.freedesktop.machine1",
456 "/org/freedesktop/machine1",
457 "org.freedesktop.machine1.Manager",
458 "GetMachineOSRelease",
465 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
467 return bus_log_parse_error(r);
469 while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
470 if (streq(k, "PRETTY_NAME"))
475 return bus_log_parse_error(r);
477 r = sd_bus_message_exit_container(reply);
479 return bus_log_parse_error(r);
482 printf("%s%s\n", prefix, pretty);
487 typedef struct MachineStatusInfo {
493 char *root_directory;
495 struct dual_timestamp timestamp;
500 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
501 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
502 char since2[FORMAT_TIMESTAMP_MAX], *s2;
508 fputs(strna(i->name), stdout);
510 if (!sd_id128_equal(i->id, SD_ID128_NULL))
511 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
515 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
516 s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
519 printf("\t Since: %s; %s\n", s2, s1);
521 printf("\t Since: %s\n", s2);
524 _cleanup_free_ char *t = NULL;
526 printf("\t Leader: %u", (unsigned) i->leader);
528 get_process_comm(i->leader, &t);
536 printf("\t Service: %s", i->service);
539 printf("; class %s", i->class);
543 printf("\t Class: %s\n", i->class);
545 if (i->root_directory)
546 printf("\t Root: %s\n", i->root_directory);
548 if (i->n_netif > 0) {
551 fputs("\t Iface:", stdout);
553 for (c = 0; c < i->n_netif; c++) {
554 char name[IF_NAMESIZE+1] = "";
556 if (if_indextoname(i->netif[c], name)) {
565 printf(" %i", i->netif[c]);
571 print_addresses(bus, i->name, ifi,
575 print_os_release(bus, i->name, "\t OS: ");
578 printf("\t Unit: %s\n", i->unit);
579 show_unit_cgroup(bus, i->unit, i->leader);
581 if (arg_transport == BUS_TRANSPORT_LOCAL) {
583 show_journal_by_unit(
588 i->timestamp.monotonic,
591 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
592 SD_JOURNAL_LOCAL_ONLY,
599 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
600 MachineStatusInfo *i = userdata;
605 assert_cc(sizeof(int32_t) == sizeof(int));
606 r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
612 i->n_netif = l / sizeof(int32_t);
613 i->netif = memdup(v, l);
620 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
622 static const struct bus_properties_map map[] = {
623 { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
624 { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
625 { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
626 { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
627 { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
628 { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
629 { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
630 { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
631 { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
632 { "NetworkInterfaces", "ai", map_netif, 0 },
636 MachineStatusInfo info = {};
644 r = bus_map_all_properties(bus,
645 "org.freedesktop.machine1",
650 return log_error_errno(r, "Could not get properties: %m");
656 print_machine_status_info(bus, &info);
662 free(info.root_directory);
668 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
680 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
682 log_error_errno(r, "Could not get properties: %m");
687 static int show_machine(int argc, char *argv[], void *userdata) {
689 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
690 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
691 bool properties, new_line = false;
692 sd_bus *bus = userdata;
697 properties = !strstr(argv[0], "status");
699 pager_open_if_enabled();
701 if (properties && argc <= 1) {
703 /* If no argument is specified, inspect the manager
705 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
710 for (i = 1; i < argc; i++) {
711 const char *path = NULL;
713 r = sd_bus_call_method(
715 "org.freedesktop.machine1",
716 "/org/freedesktop/machine1",
717 "org.freedesktop.machine1.Manager",
723 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
727 r = sd_bus_message_read(reply, "o", &path);
729 return bus_log_parse_error(r);
732 r = show_machine_properties(bus, path, &new_line);
734 r = show_machine_info(argv[0], bus, path, &new_line);
740 typedef struct ImageStatusInfo {
749 uint64_t usage_exclusive;
750 uint64_t limit_exclusive;
753 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
754 char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
755 char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
756 char bs[FORMAT_BYTES_MAX], *s3;
757 char bs_exclusive[FORMAT_BYTES_MAX], *s4;
763 fputs(i->name, stdout);
768 printf("\t Type: %s\n", i->type);
771 printf("\t Path: %s\n", i->path);
773 printf("\t RO: %s%s%s\n",
774 i->read_only ? ansi_highlight_red() : "",
775 i->read_only ? "read-only" : "writable",
776 i->read_only ? ansi_highlight_off() : "");
778 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
779 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
781 printf("\t Created: %s; %s\n", s2, s1);
783 printf("\t Created: %s\n", s2);
785 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
786 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
788 printf("\tModified: %s; %s\n", s2, s1);
790 printf("\tModified: %s\n", s2);
792 s3 = format_bytes(bs, sizeof(bs), i->usage);
793 s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
795 printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
797 printf("\t Usage: %s\n", s3);
799 s3 = format_bytes(bs, sizeof(bs), i->limit);
800 s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
802 printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
804 printf("\t Limit: %s\n", s3);
807 static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
809 static const struct bus_properties_map map[] = {
810 { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
811 { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
812 { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
813 { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
814 { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
815 { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
816 { "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
817 { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
818 { "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
819 { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
823 ImageStatusInfo info = {};
831 r = bus_map_all_properties(bus,
832 "org.freedesktop.machine1",
837 return log_error_errno(r, "Could not get properties: %m");
843 print_image_status_info(bus, &info);
852 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
864 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
866 log_error_errno(r, "Could not get properties: %m");
871 static int show_image(int argc, char *argv[], void *userdata) {
873 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
874 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
875 bool properties, new_line = false;
876 sd_bus *bus = userdata;
881 properties = !strstr(argv[0], "status");
883 pager_open_if_enabled();
885 if (properties && argc <= 1) {
887 /* If no argument is specified, inspect the manager
889 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
894 for (i = 1; i < argc; i++) {
895 const char *path = NULL;
897 r = sd_bus_call_method(
899 "org.freedesktop.machine1",
900 "/org/freedesktop/machine1",
901 "org.freedesktop.machine1.Manager",
907 log_error("Could not get path to image: %s", bus_error_message(&error, -r));
911 r = sd_bus_message_read(reply, "o", &path);
913 return bus_log_parse_error(r);
916 r = show_image_properties(bus, path, &new_line);
918 r = show_image_info(argv[0], bus, path, &new_line);
924 static int kill_machine(int argc, char *argv[], void *userdata) {
925 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
926 sd_bus *bus = userdata;
931 polkit_agent_open_if_enabled();
934 arg_kill_who = "all";
936 for (i = 1; i < argc; i++) {
937 r = sd_bus_call_method(
939 "org.freedesktop.machine1",
940 "/org/freedesktop/machine1",
941 "org.freedesktop.machine1.Manager",
945 "ssi", argv[i], arg_kill_who, arg_signal);
947 log_error("Could not kill machine: %s", bus_error_message(&error, -r));
955 static int reboot_machine(int argc, char *argv[], void *userdata) {
956 arg_kill_who = "leader";
957 arg_signal = SIGINT; /* sysvinit + systemd */
959 return kill_machine(argc, argv, userdata);
962 static int poweroff_machine(int argc, char *argv[], void *userdata) {
963 arg_kill_who = "leader";
964 arg_signal = SIGRTMIN+4; /* only systemd */
966 return kill_machine(argc, argv, userdata);
969 static int terminate_machine(int argc, char *argv[], void *userdata) {
970 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
971 sd_bus *bus = userdata;
976 polkit_agent_open_if_enabled();
978 for (i = 1; i < argc; i++) {
979 r = sd_bus_call_method(
981 "org.freedesktop.machine1",
982 "/org/freedesktop/machine1",
983 "org.freedesktop.machine1.Manager",
989 log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
997 static int copy_files(int argc, char *argv[], void *userdata) {
998 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
999 sd_bus *bus = userdata;
1005 polkit_agent_open_if_enabled();
1007 copy_from = streq(argv[0], "copy-from");
1009 r = sd_bus_call_method(
1011 "org.freedesktop.machine1",
1012 "/org/freedesktop/machine1",
1013 "org.freedesktop.machine1.Manager",
1014 copy_from ? "CopyFromMachine" : "CopyToMachine",
1022 log_error("Failed to copy: %s", bus_error_message(&error, -r));
1029 static int bind_mount(int argc, char *argv[], void *userdata) {
1030 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1031 sd_bus *bus = userdata;
1036 polkit_agent_open_if_enabled();
1038 r = sd_bus_call_method(
1040 "org.freedesktop.machine1",
1041 "/org/freedesktop/machine1",
1042 "org.freedesktop.machine1.Manager",
1053 log_error("Failed to bind mount: %s", bus_error_message(&error, -r));
1060 static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
1061 PTYForward ** forward = (PTYForward**) userdata;
1069 /* If the forwarder is already initialized, tell it to
1070 * exit on the next vhangup(), so that we still flush
1071 * out what might be queued and exit then. */
1073 r = pty_forward_set_ignore_vhangup(*forward, false);
1077 log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
1080 /* On error, or when the forwarder is not initialized yet, quit immediately */
1081 sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
1085 static int login_machine(int argc, char *argv[], void *userdata) {
1086 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1087 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1088 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
1089 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1090 _cleanup_event_unref_ sd_event *event = NULL;
1091 int master = -1, r, ret = 0;
1092 sd_bus *bus = userdata;
1093 const char *pty, *match;
1099 if (arg_transport != BUS_TRANSPORT_LOCAL &&
1100 arg_transport != BUS_TRANSPORT_MACHINE) {
1101 log_error("Login only supported on local machines.");
1105 polkit_agent_open_if_enabled();
1107 r = sd_event_default(&event);
1109 return log_error_errno(r, "Failed to get event loop: %m");
1111 r = sd_bus_attach_event(bus, event, 0);
1113 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1115 match = strjoina("type='signal',"
1116 "sender='org.freedesktop.machine1',"
1117 "path='/org/freedesktop/machine1',",
1118 "interface='org.freedesktop.machine1.Manager',"
1119 "member='MachineRemoved',"
1124 r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
1126 return log_error_errno(r, "Failed to add machine removal match: %m");
1128 r = sd_bus_call_method(
1130 "org.freedesktop.machine1",
1131 "/org/freedesktop/machine1",
1132 "org.freedesktop.machine1.Manager",
1138 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1142 r = sd_bus_message_read(reply, "hs", &master, &pty);
1144 return bus_log_parse_error(r);
1146 sigprocmask_many(SIG_BLOCK, SIGWINCH, SIGTERM, SIGINT, -1);
1148 log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
1150 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1151 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1153 r = pty_forward_new(event, master, true, false, &forward);
1155 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1157 r = sd_event_loop(event);
1159 return log_error_errno(r, "Failed to run event loop: %m");
1161 pty_forward_get_last_char(forward, &last_char);
1162 machine_died = pty_forward_get_ignore_vhangup(forward) == 0;
1164 forward = pty_forward_free(forward);
1166 if (last_char != '\n')
1167 fputc('\n', stdout);
1170 log_info("Machine %s terminated.", argv[1]);
1172 log_info("Connection to machine %s terminated.", argv[1]);
1174 sd_event_get_exit_code(event, &ret);
1178 static int remove_image(int argc, char *argv[], void *userdata) {
1179 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1180 sd_bus *bus = userdata;
1185 polkit_agent_open_if_enabled();
1187 for (i = 1; i < argc; i++) {
1188 r = sd_bus_call_method(
1190 "org.freedesktop.machine1",
1191 "/org/freedesktop/machine1",
1192 "org.freedesktop.machine1.Manager",
1198 log_error("Could not remove image: %s", bus_error_message(&error, -r));
1206 static int rename_image(int argc, char *argv[], void *userdata) {
1207 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1208 sd_bus *bus = userdata;
1211 polkit_agent_open_if_enabled();
1213 r = sd_bus_call_method(
1215 "org.freedesktop.machine1",
1216 "/org/freedesktop/machine1",
1217 "org.freedesktop.machine1.Manager",
1221 "ss", argv[1], argv[2]);
1223 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1230 static int clone_image(int argc, char *argv[], void *userdata) {
1231 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1232 sd_bus *bus = userdata;
1235 polkit_agent_open_if_enabled();
1237 r = sd_bus_call_method(
1239 "org.freedesktop.machine1",
1240 "/org/freedesktop/machine1",
1241 "org.freedesktop.machine1.Manager",
1245 "ssb", argv[1], argv[2], arg_read_only);
1247 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1254 static int read_only_image(int argc, char *argv[], void *userdata) {
1255 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1256 sd_bus *bus = userdata;
1260 b = parse_boolean(argv[2]);
1262 log_error("Failed to parse boolean argument: %s", argv[2]);
1267 polkit_agent_open_if_enabled();
1269 r = sd_bus_call_method(
1271 "org.freedesktop.machine1",
1272 "/org/freedesktop/machine1",
1273 "org.freedesktop.machine1.Manager",
1274 "MarkImageReadOnly",
1279 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1286 static int start_machine(int argc, char *argv[], void *userdata) {
1287 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1288 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1289 sd_bus *bus = userdata;
1294 polkit_agent_open_if_enabled();
1296 r = bus_wait_for_jobs_new(bus, &w);
1300 for (i = 1; i < argc; i++) {
1301 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1302 _cleanup_free_ char *e = NULL, *unit = NULL;
1305 if (!machine_name_is_valid(argv[i])) {
1306 log_error("Invalid machine name %s.", argv[i]);
1310 e = unit_name_escape(argv[i]);
1314 unit = unit_name_build("systemd-nspawn", e, ".service");
1318 r = sd_bus_call_method(
1320 "org.freedesktop.systemd1",
1321 "/org/freedesktop/systemd1",
1322 "org.freedesktop.systemd1.Manager",
1326 "ss", unit, "fail");
1328 log_error("Failed to start unit: %s", bus_error_message(&error, -r));
1332 r = sd_bus_message_read(reply, "o", &object);
1334 return bus_log_parse_error(r);
1336 r = bus_wait_for_jobs_add(w, object);
1341 r = bus_wait_for_jobs(w, arg_quiet);
1348 static int enable_machine(int argc, char *argv[], void *userdata) {
1349 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1350 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1351 int carries_install_info = 0;
1352 const char *method = NULL;
1353 sd_bus *bus = userdata;
1358 polkit_agent_open_if_enabled();
1360 method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
1362 r = sd_bus_message_new_method_call(
1365 "org.freedesktop.systemd1",
1366 "/org/freedesktop/systemd1",
1367 "org.freedesktop.systemd1.Manager",
1370 return bus_log_create_error(r);
1372 r = sd_bus_message_open_container(m, 'a', "s");
1374 return bus_log_create_error(r);
1376 for (i = 1; i < argc; i++) {
1377 _cleanup_free_ char *e = NULL, *unit = NULL;
1379 if (!machine_name_is_valid(argv[i])) {
1380 log_error("Invalid machine name %s.", argv[i]);
1384 e = unit_name_escape(argv[i]);
1388 unit = unit_name_build("systemd-nspawn", e, ".service");
1392 r = sd_bus_message_append(m, "s", unit);
1394 return bus_log_create_error(r);
1397 r = sd_bus_message_close_container(m);
1399 return bus_log_create_error(r);
1401 if (streq(argv[0], "enable"))
1402 r = sd_bus_message_append(m, "bb", false, false);
1404 r = sd_bus_message_append(m, "b", false);
1406 return bus_log_create_error(r);
1408 r = sd_bus_call(bus, m, 0, &error, &reply);
1410 log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
1414 if (streq(argv[0], "enable")) {
1415 r = sd_bus_message_read(reply, "b", carries_install_info);
1417 return bus_log_parse_error(r);
1420 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1424 r = sd_bus_call_method(
1426 "org.freedesktop.systemd1",
1427 "/org/freedesktop/systemd1",
1428 "org.freedesktop.systemd1.Manager",
1434 log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
1441 static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1442 const char **our_path = userdata, *line;
1450 r = sd_bus_message_read(m, "us", &priority, &line);
1452 bus_log_parse_error(r);
1456 if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
1459 if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
1462 log_full(priority, "%s", line);
1466 static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1467 const char **our_path = userdata, *path, *result;
1475 r = sd_bus_message_read(m, "uos", &id, &path, &result);
1477 bus_log_parse_error(r);
1481 if (!streq_ptr(*our_path, path))
1484 sd_event_exit(sd_bus_get_event(bus), !streq_ptr(result, "done"));
1488 static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
1493 log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
1495 sd_event_exit(sd_event_source_get_event(s), EINTR);
1499 static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
1500 _cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
1501 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1502 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1503 _cleanup_event_unref_ sd_event* event = NULL;
1504 const char *path = NULL;
1511 polkit_agent_open_if_enabled();
1513 r = sd_event_default(&event);
1515 return log_error_errno(r, "Failed to get event loop: %m");
1517 r = sd_bus_attach_event(bus, event, 0);
1519 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1521 r = sd_bus_add_match(
1525 "sender='org.freedesktop.import1',"
1526 "interface='org.freedesktop.import1.Manager',"
1527 "member='TransferRemoved',"
1528 "path='/org/freedesktop/import1'",
1529 match_transfer_removed, &path);
1531 return log_error_errno(r, "Failed to install match: %m");
1533 r = sd_bus_add_match(
1537 "sender='org.freedesktop.import1',"
1538 "interface='org.freedesktop.import1.Transfer',"
1539 "member='LogMessage'",
1540 match_log_message, &path);
1542 return log_error_errno(r, "Failed to install match: %m");
1544 r = sd_bus_call(bus, m, 0, &error, &reply);
1546 log_error("Failed pull image: %s", bus_error_message(&error, -r));
1550 r = sd_bus_message_read(reply, "uo", &id, &path);
1552 return bus_log_parse_error(r);
1554 sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
1557 log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
1559 sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
1560 sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
1562 r = sd_event_loop(event);
1564 return log_error_errno(r, "Failed to run event loop: %m");
1569 static int pull_tar(int argc, char *argv[], void *userdata) {
1570 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1571 _cleanup_free_ char *l = NULL, *ll = NULL;
1572 const char *local, *remote;
1573 sd_bus *bus = userdata;
1579 if (!http_url_is_valid(remote)) {
1580 log_error("URL '%s' is not valid.", remote);
1587 r = import_url_last_component(remote, &l);
1589 return log_error_errno(r, "Failed to get final component of URL: %m");
1594 if (isempty(local) || streq(local, "-"))
1598 r = tar_strip_suffixes(local, &ll);
1600 return log_error_errno(r, "Failed to strip tar suffixes: %m");
1604 if (!machine_name_is_valid(local)) {
1605 log_error("Local name %s is not a suitable machine name.", local);
1610 r = sd_bus_message_new_method_call(
1613 "org.freedesktop.import1",
1614 "/org/freedesktop/import1",
1615 "org.freedesktop.import1.Manager",
1618 return bus_log_create_error(r);
1620 r = sd_bus_message_append(
1625 import_verify_to_string(arg_verify),
1628 return bus_log_create_error(r);
1630 return pull_image_common(bus, m);
1633 static int pull_raw(int argc, char *argv[], void *userdata) {
1634 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1635 _cleanup_free_ char *l = NULL, *ll = NULL;
1636 const char *local, *remote;
1637 sd_bus *bus = userdata;
1643 if (!http_url_is_valid(remote)) {
1644 log_error("URL '%s' is not valid.", remote);
1651 r = import_url_last_component(remote, &l);
1653 return log_error_errno(r, "Failed to get final component of URL: %m");
1658 if (isempty(local) || streq(local, "-"))
1662 r = raw_strip_suffixes(local, &ll);
1664 return log_error_errno(r, "Failed to strip tar suffixes: %m");
1668 if (!machine_name_is_valid(local)) {
1669 log_error("Local name %s is not a suitable machine name.", local);
1674 r = sd_bus_message_new_method_call(
1677 "org.freedesktop.import1",
1678 "/org/freedesktop/import1",
1679 "org.freedesktop.import1.Manager",
1682 return bus_log_create_error(r);
1684 r = sd_bus_message_append(
1689 import_verify_to_string(arg_verify),
1692 return bus_log_create_error(r);
1694 return pull_image_common(bus, m);
1697 static int pull_dkr(int argc, char *argv[], void *userdata) {
1698 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1699 const char *local, *remote, *tag;
1700 sd_bus *bus = userdata;
1703 if (arg_verify != IMPORT_VERIFY_NO) {
1704 log_error("Imports from DKR do not support image verification, please pass --verify=no.");
1709 tag = strchr(remote, ':');
1711 remote = strndupa(remote, tag - remote);
1715 if (!dkr_name_is_valid(remote)) {
1716 log_error("DKR name '%s' is invalid.", remote);
1719 if (tag && !dkr_tag_is_valid(tag)) {
1720 log_error("DKR tag '%s' is invalid.", remote);
1727 local = strchr(remote, '/');
1734 if (isempty(local) || streq(local, "-"))
1738 if (!machine_name_is_valid(local)) {
1739 log_error("Local name %s is not a suitable machine name.", local);
1744 r = sd_bus_message_new_method_call(
1747 "org.freedesktop.import1",
1748 "/org/freedesktop/import1",
1749 "org.freedesktop.import1.Manager",
1752 return bus_log_create_error(r);
1754 r = sd_bus_message_append(
1761 import_verify_to_string(arg_verify),
1764 return bus_log_create_error(r);
1766 return pull_image_common(bus, m);
1769 typedef struct TransferInfo {
1777 static int compare_transfer_info(const void *a, const void *b) {
1778 const TransferInfo *x = a, *y = b;
1780 return strcmp(x->local, y->local);
1783 static int list_transfers(int argc, char *argv[], void *userdata) {
1784 size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
1785 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1786 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1787 _cleanup_free_ TransferInfo *transfers = NULL;
1788 size_t n_transfers = 0, n_allocated = 0, j;
1789 const char *type, *remote, *local, *object;
1790 sd_bus *bus = userdata;
1791 uint32_t id, max_id = 0;
1795 pager_open_if_enabled();
1797 r = sd_bus_call_method(
1799 "org.freedesktop.import1",
1800 "/org/freedesktop/import1",
1801 "org.freedesktop.import1.Manager",
1807 log_error("Could not get transfers: %s", bus_error_message(&error, -r));
1811 r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
1813 return bus_log_parse_error(r);
1815 while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
1818 if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
1821 transfers[n_transfers].id = id;
1822 transfers[n_transfers].type = type;
1823 transfers[n_transfers].remote = remote;
1824 transfers[n_transfers].local = local;
1825 transfers[n_transfers].progress = progress;
1845 return bus_log_parse_error(r);
1847 r = sd_bus_message_exit_container(reply);
1849 return bus_log_parse_error(r);
1851 qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
1854 printf("%-*s %-*s %-*s %-*s %-*s\n",
1855 (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
1857 (int) max_type, "TYPE",
1858 (int) max_local, "LOCAL",
1859 (int) max_remote, "REMOTE");
1861 for (j = 0; j < n_transfers; j++)
1862 printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
1863 (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
1864 (int) 6, (unsigned) (transfers[j].progress * 100),
1865 (int) max_type, transfers[j].type,
1866 (int) max_local, transfers[j].local,
1867 (int) max_remote, transfers[j].remote);
1870 printf("\n%zu transfers listed.\n", n_transfers);
1875 static int cancel_transfer(int argc, char *argv[], void *userdata) {
1876 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1877 sd_bus *bus = userdata;
1882 polkit_agent_open_if_enabled();
1884 for (i = 1; i < argc; i++) {
1887 r = safe_atou32(argv[i], &id);
1889 return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
1891 r = sd_bus_call_method(
1893 "org.freedesktop.import1",
1894 "/org/freedesktop/import1",
1895 "org.freedesktop.import1.Manager",
1901 log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
1909 static int help(int argc, char *argv[], void *userdata) {
1911 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1912 "Send control commands to or query the virtual machine and container\n"
1913 "registration manager.\n\n"
1914 " -h --help Show this help\n"
1915 " --version Show package version\n"
1916 " --no-pager Do not pipe output into a pager\n"
1917 " --no-legend Do not show the headers and footers\n"
1918 " --no-ask-password Do not ask for system passwords\n"
1919 " -H --host=[USER@]HOST Operate on remote host\n"
1920 " -M --machine=CONTAINER Operate on local container\n"
1921 " -p --property=NAME Show only properties by this name\n"
1922 " -q --quiet Suppress output\n"
1923 " -a --all Show all properties, including empty ones\n"
1924 " -l --full Do not ellipsize output\n"
1925 " --kill-who=WHO Who to send signal to\n"
1926 " -s --signal=SIGNAL Which signal to send\n"
1927 " --read-only Create read-only bind mount\n"
1928 " --mkdir Create directory before bind mounting, if missing\n"
1929 " -n --lines=INTEGER Number of journal entries to show\n"
1930 " -o --output=STRING Change journal output mode (short,\n"
1931 " short-monotonic, verbose, export, json,\n"
1932 " json-pretty, json-sse, cat)\n"
1933 " --verify=MODE Verification mode for downloaded images (no,\n"
1934 " checksum, signature)\n"
1935 " --force Download image even if already exists\n"
1936 " --dkr-index-url=URL Specify the index URL to use for DKR image\n"
1938 "Machine Commands:\n"
1939 " list List running VMs and containers\n"
1940 " status NAME... Show VM/container details\n"
1941 " show NAME... Show properties of one or more VMs/containers\n"
1942 " start NAME... Start container as a service\n"
1943 " login NAME Get a login prompt on a container\n"
1944 " enable NAME... Enable automatic container start at boot\n"
1945 " disable NAME... Disable automatic container start at boot\n"
1946 " poweroff NAME... Power off one or more containers\n"
1947 " reboot NAME... Reboot one or more containers\n"
1948 " terminate NAME... Terminate one or more VMs/containers\n"
1949 " kill NAME... Send signal to processes of a VM/container\n"
1950 " copy-to NAME PATH [PATH] Copy files from the host to a container\n"
1951 " copy-from NAME PATH [PATH] Copy files from a container to the host\n"
1952 " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
1954 " list-images Show available container and VM images\n"
1955 " image-status NAME... Show image details\n"
1956 " show-image NAME... Show properties of image\n"
1957 " clone NAME NAME Clone an image\n"
1958 " rename NAME NAME Rename an image\n"
1959 " read-only NAME [BOOL] Mark or unmark image read-only\n"
1960 " remove NAME... Remove an image\n\n"
1961 "Image Transfer Commands:\n"
1962 " pull-tar URL [NAME] Download a TAR container image\n"
1963 " pull-raw URL [NAME] Download a RAW container or VM image\n"
1964 " pull-dkr REMOTE [NAME] Download a DKR container image\n"
1965 " list-transfers Show list of downloads in progress\n"
1966 " cancel-transfer Cancel a download\n"
1967 , program_invocation_short_name);
1972 static int parse_argv(int argc, char *argv[]) {
1975 ARG_VERSION = 0x100,
1981 ARG_NO_ASK_PASSWORD,
1987 static const struct option options[] = {
1988 { "help", no_argument, NULL, 'h' },
1989 { "version", no_argument, NULL, ARG_VERSION },
1990 { "property", required_argument, NULL, 'p' },
1991 { "all", no_argument, NULL, 'a' },
1992 { "full", no_argument, NULL, 'l' },
1993 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1994 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1995 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1996 { "signal", required_argument, NULL, 's' },
1997 { "host", required_argument, NULL, 'H' },
1998 { "machine", required_argument, NULL, 'M' },
1999 { "read-only", no_argument, NULL, ARG_READ_ONLY },
2000 { "mkdir", no_argument, NULL, ARG_MKDIR },
2001 { "quiet", no_argument, NULL, 'q' },
2002 { "lines", required_argument, NULL, 'n' },
2003 { "output", required_argument, NULL, 'o' },
2004 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
2005 { "verify", required_argument, NULL, ARG_VERIFY },
2006 { "force", no_argument, NULL, ARG_FORCE },
2007 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
2016 while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
2021 return help(0, NULL, NULL);
2024 puts(PACKAGE_STRING);
2025 puts(SYSTEMD_FEATURES);
2029 r = strv_extend(&arg_property, optarg);
2033 /* If the user asked for a particular
2034 * property, show it to him, even if it is
2048 if (safe_atou(optarg, &arg_lines) < 0) {
2049 log_error("Failed to parse lines '%s'", optarg);
2055 arg_output = output_mode_from_string(optarg);
2056 if (arg_output < 0) {
2057 log_error("Unknown output '%s'.", optarg);
2063 arg_no_pager = true;
2071 arg_kill_who = optarg;
2075 arg_signal = signal_from_string_try_harder(optarg);
2076 if (arg_signal < 0) {
2077 log_error("Failed to parse signal string %s.", optarg);
2082 case ARG_NO_ASK_PASSWORD:
2083 arg_ask_password = false;
2087 arg_transport = BUS_TRANSPORT_REMOTE;
2092 arg_transport = BUS_TRANSPORT_MACHINE;
2097 arg_read_only = true;
2109 arg_verify = import_verify_from_string(optarg);
2110 if (arg_verify < 0) {
2111 log_error("Failed to parse --verify= setting: %s", optarg);
2120 case ARG_DKR_INDEX_URL:
2121 if (!http_url_is_valid(optarg)) {
2122 log_error("Index URL is invalid: %s", optarg);
2126 arg_dkr_index_url = optarg;
2133 assert_not_reached("Unhandled option");
2139 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
2141 static const Verb verbs[] = {
2142 { "help", VERB_ANY, VERB_ANY, 0, help },
2143 { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
2144 { "list-images", VERB_ANY, 1, 0, list_images },
2145 { "status", 2, VERB_ANY, 0, show_machine },
2146 { "image-status", 2, VERB_ANY, 0, show_image },
2147 { "show", VERB_ANY, VERB_ANY, 0, show_machine },
2148 { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
2149 { "terminate", 2, VERB_ANY, 0, terminate_machine },
2150 { "reboot", 2, VERB_ANY, 0, reboot_machine },
2151 { "poweroff", 2, VERB_ANY, 0, poweroff_machine },
2152 { "kill", 2, VERB_ANY, 0, kill_machine },
2153 { "login", 2, 2, 0, login_machine },
2154 { "bind", 3, 4, 0, bind_mount },
2155 { "copy-to", 3, 4, 0, copy_files },
2156 { "copy-from", 3, 4, 0, copy_files },
2157 { "remove", 2, VERB_ANY, 0, remove_image },
2158 { "rename", 3, 3, 0, rename_image },
2159 { "clone", 3, 3, 0, clone_image },
2160 { "read-only", 2, 3, 0, read_only_image },
2161 { "start", 2, VERB_ANY, 0, start_machine },
2162 { "enable", 2, VERB_ANY, 0, enable_machine },
2163 { "disable", 2, VERB_ANY, 0, enable_machine },
2164 { "pull-tar", 2, 3, 0, pull_tar },
2165 { "pull-raw", 2, 3, 0, pull_raw },
2166 { "pull-dkr", 2, 3, 0, pull_dkr },
2167 { "list-transfers", VERB_ANY, 1, 0, list_transfers },
2168 { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
2172 return dispatch_verb(argc, argv, verbs, bus);
2175 int main(int argc, char*argv[]) {
2176 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
2179 setlocale(LC_ALL, "");
2180 log_parse_environment();
2183 r = parse_argv(argc, argv);
2187 r = bus_open_transport(arg_transport, arg_host, false, &bus);
2189 log_error_errno(r, "Failed to create bus connection: %m");
2193 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
2195 r = machinectl_main(argc, argv, bus);
2199 polkit_agent_close();
2201 strv_free(arg_property);
2203 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;