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>
29 #include <netinet/in.h>
30 #include <arpa/inet.h>
32 #include <sys/mount.h>
39 #include "spawn-polkit-agent.h"
41 #include "bus-error.h"
44 #include "unit-name.h"
45 #include "cgroup-show.h"
46 #include "logs-show.h"
47 #include "cgroup-util.h"
49 #include "event-util.h"
50 #include "path-util.h"
54 #include "import-util.h"
56 static char **arg_property = NULL;
57 static bool arg_all = false;
58 static bool arg_full = false;
59 static bool arg_no_pager = false;
60 static bool arg_legend = true;
61 static const char *arg_kill_who = NULL;
62 static int arg_signal = SIGTERM;
63 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
64 static char *arg_host = NULL;
65 static bool arg_read_only = false;
66 static bool arg_mkdir = false;
67 static bool arg_quiet = false;
68 static bool arg_ask_password = true;
69 static unsigned arg_lines = 10;
70 static OutputMode arg_output = OUTPUT_SHORT;
71 static bool arg_force = false;
72 static ImportVerify arg_verify = IMPORT_VERIFY_SIGNATURE;
73 static const char* arg_dkr_index_url = NULL;
75 static void pager_open_if_enabled(void) {
83 static void polkit_agent_open_if_enabled(void) {
85 /* Open the polkit agent as a child process if necessary */
87 if (!arg_ask_password)
90 if (arg_transport != BUS_TRANSPORT_LOCAL)
96 static OutputFlags get_output_flags(void) {
98 arg_all * OUTPUT_SHOW_ALL |
99 arg_full * OUTPUT_FULL_WIDTH |
100 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
101 on_tty() * OUTPUT_COLOR |
102 !arg_quiet * OUTPUT_WARN_CUTOFF;
105 typedef struct MachineInfo {
111 static int compare_machine_info(const void *a, const void *b) {
112 const MachineInfo *x = a, *y = b;
114 return strcmp(x->name, y->name);
117 static int list_machines(int argc, char *argv[], void *userdata) {
119 size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
120 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
121 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
122 _cleanup_free_ MachineInfo *machines = NULL;
123 const char *name, *class, *service, *object;
124 size_t n_machines = 0, n_allocated = 0, j;
125 sd_bus *bus = userdata;
130 pager_open_if_enabled();
132 r = sd_bus_call_method(
134 "org.freedesktop.machine1",
135 "/org/freedesktop/machine1",
136 "org.freedesktop.machine1.Manager",
142 log_error("Could not get machines: %s", bus_error_message(&error, -r));
146 r = sd_bus_message_enter_container(reply, 'a', "(ssso)");
148 return bus_log_parse_error(r);
150 while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
153 if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
156 machines[n_machines].name = name;
157 machines[n_machines].class = class;
158 machines[n_machines].service = service;
175 return bus_log_parse_error(r);
177 r = sd_bus_message_exit_container(reply);
179 return bus_log_parse_error(r);
181 qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
184 printf("%-*s %-*s %-*s\n",
185 (int) max_name, "MACHINE",
186 (int) max_class, "CLASS",
187 (int) max_service, "SERVICE");
189 for (j = 0; j < n_machines; j++)
190 printf("%-*s %-*s %-*s\n",
191 (int) max_name, machines[j].name,
192 (int) max_class, machines[j].class,
193 (int) max_service, machines[j].service);
196 printf("\n%zu machines listed.\n", n_machines);
201 typedef struct ImageInfo {
210 static int compare_image_info(const void *a, const void *b) {
211 const ImageInfo *x = a, *y = b;
213 return strcmp(x->name, y->name);
216 static int list_images(int argc, char *argv[], void *userdata) {
218 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
219 size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("USAGE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
220 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
221 _cleanup_free_ ImageInfo *images = NULL;
222 size_t n_images = 0, n_allocated = 0, j;
223 const char *name, *type, *object;
224 sd_bus *bus = userdata;
225 uint64_t crtime, mtime, size;
230 pager_open_if_enabled();
232 r = sd_bus_call_method(
234 "org.freedesktop.machine1",
235 "/org/freedesktop/machine1",
236 "org.freedesktop.machine1.Manager",
242 log_error("Could not get images: %s", bus_error_message(&error, -r));
246 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
248 return bus_log_parse_error(r);
250 while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
251 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
254 if (name[0] == '.' && !arg_all)
257 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
260 images[n_images].name = name;
261 images[n_images].type = type;
262 images[n_images].read_only = read_only;
263 images[n_images].crtime = crtime;
264 images[n_images].mtime = mtime;
265 images[n_images].size = size;
276 l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
282 l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
287 if (size != (uint64_t) -1) {
288 l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
296 return bus_log_parse_error(r);
298 r = sd_bus_message_exit_container(reply);
300 return bus_log_parse_error(r);
302 qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
305 printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
306 (int) max_name, "NAME",
307 (int) max_type, "TYPE",
309 (int) max_size, "USAGE",
310 (int) max_crtime, "CREATED",
311 (int) max_mtime, "MODIFIED");
313 for (j = 0; j < n_images; j++) {
314 char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
316 printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
317 (int) max_name, images[j].name,
318 (int) max_type, images[j].type,
319 images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
320 (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
321 (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
322 (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
326 printf("\n%zu images listed.\n", n_images);
331 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
332 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
333 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
334 _cleanup_free_ char *path = NULL;
342 if (arg_transport == BUS_TRANSPORT_REMOTE)
345 path = unit_dbus_path_from_name(unit);
349 r = sd_bus_get_property(
351 "org.freedesktop.systemd1",
353 endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
359 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
363 r = sd_bus_message_read(reply, "s", &cgroup);
365 return bus_log_parse_error(r);
370 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
379 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
383 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
384 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
392 r = sd_bus_call_method(bus,
393 "org.freedesktop.machine1",
394 "/org/freedesktop/machine1",
395 "org.freedesktop.machine1.Manager",
396 "GetMachineAddresses",
403 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
405 return bus_log_parse_error(r);
407 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
411 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
413 r = sd_bus_message_read(reply, "i", &family);
415 return bus_log_parse_error(r);
417 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
419 return bus_log_parse_error(r);
421 fputs(prefix, stdout);
422 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
423 if (family == AF_INET6 && ifi > 0)
427 r = sd_bus_message_exit_container(reply);
429 return bus_log_parse_error(r);
431 if (prefix != prefix2)
435 return bus_log_parse_error(r);
437 r = sd_bus_message_exit_container(reply);
439 return bus_log_parse_error(r);
444 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
445 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
446 const char *k, *v, *pretty = NULL;
453 r = sd_bus_call_method(bus,
454 "org.freedesktop.machine1",
455 "/org/freedesktop/machine1",
456 "org.freedesktop.machine1.Manager",
457 "GetMachineOSRelease",
464 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
466 return bus_log_parse_error(r);
468 while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
469 if (streq(k, "PRETTY_NAME"))
474 return bus_log_parse_error(r);
476 r = sd_bus_message_exit_container(reply);
478 return bus_log_parse_error(r);
481 printf("%s%s\n", prefix, pretty);
486 typedef struct MachineStatusInfo {
492 char *root_directory;
494 struct dual_timestamp timestamp;
499 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
500 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
501 char since2[FORMAT_TIMESTAMP_MAX], *s2;
507 fputs(strna(i->name), stdout);
509 if (!sd_id128_equal(i->id, SD_ID128_NULL))
510 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
514 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
515 s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
518 printf("\t Since: %s; %s\n", s2, s1);
520 printf("\t Since: %s\n", s2);
523 _cleanup_free_ char *t = NULL;
525 printf("\t Leader: %u", (unsigned) i->leader);
527 get_process_comm(i->leader, &t);
535 printf("\t Service: %s", i->service);
538 printf("; class %s", i->class);
542 printf("\t Class: %s\n", i->class);
544 if (i->root_directory)
545 printf("\t Root: %s\n", i->root_directory);
547 if (i->n_netif > 0) {
550 fputs("\t Iface:", stdout);
552 for (c = 0; c < i->n_netif; c++) {
553 char name[IF_NAMESIZE+1] = "";
555 if (if_indextoname(i->netif[c], name)) {
564 printf(" %i", i->netif[c]);
570 print_addresses(bus, i->name, ifi,
574 print_os_release(bus, i->name, "\t OS: ");
577 printf("\t Unit: %s\n", i->unit);
578 show_unit_cgroup(bus, i->unit, i->leader);
580 if (arg_transport == BUS_TRANSPORT_LOCAL) {
582 show_journal_by_unit(
587 i->timestamp.monotonic,
590 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
591 SD_JOURNAL_LOCAL_ONLY,
598 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
599 MachineStatusInfo *i = userdata;
604 assert_cc(sizeof(int32_t) == sizeof(int));
605 r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
611 i->n_netif = l / sizeof(int32_t);
612 i->netif = memdup(v, l);
619 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
621 static const struct bus_properties_map map[] = {
622 { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
623 { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
624 { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
625 { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
626 { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
627 { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
628 { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
629 { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
630 { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
631 { "NetworkInterfaces", "ai", map_netif, 0 },
635 MachineStatusInfo info = {};
643 r = bus_map_all_properties(bus,
644 "org.freedesktop.machine1",
649 return log_error_errno(r, "Could not get properties: %m");
655 print_machine_status_info(bus, &info);
661 free(info.root_directory);
667 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
679 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
681 log_error_errno(r, "Could not get properties: %m");
686 static int show_machine(int argc, char *argv[], void *userdata) {
688 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
689 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
690 bool properties, new_line = false;
691 sd_bus *bus = userdata;
696 properties = !strstr(argv[0], "status");
698 pager_open_if_enabled();
700 if (properties && argc <= 1) {
702 /* If no argument is specified, inspect the manager
704 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
709 for (i = 1; i < argc; i++) {
710 const char *path = NULL;
712 r = sd_bus_call_method(
714 "org.freedesktop.machine1",
715 "/org/freedesktop/machine1",
716 "org.freedesktop.machine1.Manager",
722 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
726 r = sd_bus_message_read(reply, "o", &path);
728 return bus_log_parse_error(r);
731 r = show_machine_properties(bus, path, &new_line);
733 r = show_machine_info(argv[0], bus, path, &new_line);
739 typedef struct ImageStatusInfo {
748 uint64_t usage_exclusive;
749 uint64_t limit_exclusive;
752 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
753 char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
754 char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
755 char bs[FORMAT_BYTES_MAX], *s3;
756 char bs_exclusive[FORMAT_BYTES_MAX], *s4;
762 fputs(i->name, stdout);
767 printf("\t Type: %s\n", i->type);
770 printf("\t Path: %s\n", i->path);
772 printf("\t RO: %s%s%s\n",
773 i->read_only ? ansi_highlight_red() : "",
774 i->read_only ? "read-only" : "writable",
775 i->read_only ? ansi_highlight_off() : "");
777 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
778 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
780 printf("\t Created: %s; %s\n", s2, s1);
782 printf("\t Created: %s\n", s2);
784 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
785 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
787 printf("\tModified: %s; %s\n", s2, s1);
789 printf("\tModified: %s\n", s2);
791 s3 = format_bytes(bs, sizeof(bs), i->usage);
792 s4 = i->usage_exclusive != i->usage ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->usage_exclusive) : NULL;
794 printf("\t Usage: %s (exclusive: %s)\n", s3, s4);
796 printf("\t Usage: %s\n", s3);
798 s3 = format_bytes(bs, sizeof(bs), i->limit);
799 s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
801 printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
803 printf("\t Limit: %s\n", s3);
806 static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
808 static const struct bus_properties_map map[] = {
809 { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
810 { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
811 { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
812 { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
813 { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
814 { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
815 { "Usage", "t", NULL, offsetof(ImageStatusInfo, usage) },
816 { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
817 { "UsageExclusive", "t", NULL, offsetof(ImageStatusInfo, usage_exclusive) },
818 { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
822 ImageStatusInfo info = {};
830 r = bus_map_all_properties(bus,
831 "org.freedesktop.machine1",
836 return log_error_errno(r, "Could not get properties: %m");
842 print_image_status_info(bus, &info);
851 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
863 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
865 log_error_errno(r, "Could not get properties: %m");
870 static int show_image(int argc, char *argv[], void *userdata) {
872 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
873 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
874 bool properties, new_line = false;
875 sd_bus *bus = userdata;
880 properties = !strstr(argv[0], "status");
882 pager_open_if_enabled();
884 if (properties && argc <= 1) {
886 /* If no argument is specified, inspect the manager
888 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
893 for (i = 1; i < argc; i++) {
894 const char *path = NULL;
896 r = sd_bus_call_method(
898 "org.freedesktop.machine1",
899 "/org/freedesktop/machine1",
900 "org.freedesktop.machine1.Manager",
906 log_error("Could not get path to image: %s", bus_error_message(&error, -r));
910 r = sd_bus_message_read(reply, "o", &path);
912 return bus_log_parse_error(r);
915 r = show_image_properties(bus, path, &new_line);
917 r = show_image_info(argv[0], bus, path, &new_line);
923 static int kill_machine(int argc, char *argv[], void *userdata) {
924 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
925 sd_bus *bus = userdata;
930 polkit_agent_open_if_enabled();
933 arg_kill_who = "all";
935 for (i = 1; i < argc; i++) {
936 r = sd_bus_call_method(
938 "org.freedesktop.machine1",
939 "/org/freedesktop/machine1",
940 "org.freedesktop.machine1.Manager",
944 "ssi", argv[i], arg_kill_who, arg_signal);
946 log_error("Could not kill machine: %s", bus_error_message(&error, -r));
954 static int reboot_machine(int argc, char *argv[], void *userdata) {
955 arg_kill_who = "leader";
956 arg_signal = SIGINT; /* sysvinit + systemd */
958 return kill_machine(argc, argv, userdata);
961 static int poweroff_machine(int argc, char *argv[], void *userdata) {
962 arg_kill_who = "leader";
963 arg_signal = SIGRTMIN+4; /* only systemd */
965 return kill_machine(argc, argv, userdata);
968 static int terminate_machine(int argc, char *argv[], void *userdata) {
969 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
970 sd_bus *bus = userdata;
975 polkit_agent_open_if_enabled();
977 for (i = 1; i < argc; i++) {
978 r = sd_bus_call_method(
980 "org.freedesktop.machine1",
981 "/org/freedesktop/machine1",
982 "org.freedesktop.machine1.Manager",
988 log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
996 static int copy_files(int argc, char *argv[], void *userdata) {
997 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
998 sd_bus *bus = userdata;
1004 polkit_agent_open_if_enabled();
1006 copy_from = streq(argv[0], "copy-from");
1008 r = sd_bus_call_method(
1010 "org.freedesktop.machine1",
1011 "/org/freedesktop/machine1",
1012 "org.freedesktop.machine1.Manager",
1013 copy_from ? "CopyFromMachine" : "CopyToMachine",
1021 log_error("Failed to copy: %s", bus_error_message(&error, -r));
1028 static int bind_mount(int argc, char *argv[], void *userdata) {
1029 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1030 sd_bus *bus = userdata;
1035 polkit_agent_open_if_enabled();
1037 r = sd_bus_call_method(
1039 "org.freedesktop.machine1",
1040 "/org/freedesktop/machine1",
1041 "org.freedesktop.machine1.Manager",
1052 log_error("Failed to bind mount: %s", bus_error_message(&error, -r));
1059 static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
1060 PTYForward ** forward = (PTYForward**) userdata;
1068 /* If the forwarder is already initialized, tell it to
1069 * exit on the next vhangup(), so that we still flush
1070 * out what might be queued and exit then. */
1072 r = pty_forward_set_ignore_vhangup(*forward, false);
1076 log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
1079 /* On error, or when the forwarder is not initialized yet, quit immediately */
1080 sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
1084 static int login_machine(int argc, char *argv[], void *userdata) {
1085 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1086 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1087 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
1088 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1089 _cleanup_event_unref_ sd_event *event = NULL;
1090 int master = -1, r, ret = 0;
1091 sd_bus *bus = userdata;
1092 const char *pty, *match;
1098 if (arg_transport != BUS_TRANSPORT_LOCAL &&
1099 arg_transport != BUS_TRANSPORT_MACHINE) {
1100 log_error("Login only supported on local machines.");
1104 polkit_agent_open_if_enabled();
1106 r = sd_event_default(&event);
1108 return log_error_errno(r, "Failed to get event loop: %m");
1110 r = sd_bus_attach_event(bus, event, 0);
1112 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1114 match = strjoina("type='signal',"
1115 "sender='org.freedesktop.machine1',"
1116 "path='/org/freedesktop/machine1',",
1117 "interface='org.freedesktop.machine1.Manager',"
1118 "member='MachineRemoved',"
1123 r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
1125 return log_error_errno(r, "Failed to add machine removal match: %m");
1127 r = sd_bus_call_method(
1129 "org.freedesktop.machine1",
1130 "/org/freedesktop/machine1",
1131 "org.freedesktop.machine1.Manager",
1137 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1141 r = sd_bus_message_read(reply, "hs", &master, &pty);
1143 return bus_log_parse_error(r);
1145 sigprocmask_many(SIG_BLOCK, SIGWINCH, SIGTERM, SIGINT, -1);
1147 log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
1149 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1150 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1152 r = pty_forward_new(event, master, true, false, &forward);
1154 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1156 r = sd_event_loop(event);
1158 return log_error_errno(r, "Failed to run event loop: %m");
1160 pty_forward_get_last_char(forward, &last_char);
1161 machine_died = pty_forward_get_ignore_vhangup(forward) == 0;
1163 forward = pty_forward_free(forward);
1165 if (last_char != '\n')
1166 fputc('\n', stdout);
1169 log_info("Machine %s terminated.", argv[1]);
1171 log_info("Connection to machine %s terminated.", argv[1]);
1173 sd_event_get_exit_code(event, &ret);
1177 static int remove_image(int argc, char *argv[], void *userdata) {
1178 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1179 sd_bus *bus = userdata;
1184 polkit_agent_open_if_enabled();
1186 for (i = 1; i < argc; i++) {
1187 r = sd_bus_call_method(
1189 "org.freedesktop.machine1",
1190 "/org/freedesktop/machine1",
1191 "org.freedesktop.machine1.Manager",
1197 log_error("Could not remove image: %s", bus_error_message(&error, -r));
1205 static int rename_image(int argc, char *argv[], void *userdata) {
1206 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1207 sd_bus *bus = userdata;
1210 polkit_agent_open_if_enabled();
1212 r = sd_bus_call_method(
1214 "org.freedesktop.machine1",
1215 "/org/freedesktop/machine1",
1216 "org.freedesktop.machine1.Manager",
1220 "ss", argv[1], argv[2]);
1222 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1229 static int clone_image(int argc, char *argv[], void *userdata) {
1230 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1231 sd_bus *bus = userdata;
1234 polkit_agent_open_if_enabled();
1236 r = sd_bus_call_method(
1238 "org.freedesktop.machine1",
1239 "/org/freedesktop/machine1",
1240 "org.freedesktop.machine1.Manager",
1244 "ssb", argv[1], argv[2], arg_read_only);
1246 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1253 static int read_only_image(int argc, char *argv[], void *userdata) {
1254 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1255 sd_bus *bus = userdata;
1259 b = parse_boolean(argv[2]);
1261 log_error("Failed to parse boolean argument: %s", argv[2]);
1266 polkit_agent_open_if_enabled();
1268 r = sd_bus_call_method(
1270 "org.freedesktop.machine1",
1271 "/org/freedesktop/machine1",
1272 "org.freedesktop.machine1.Manager",
1273 "MarkImageReadOnly",
1278 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1285 static int start_machine(int argc, char *argv[], void *userdata) {
1286 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1287 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1288 sd_bus *bus = userdata;
1293 polkit_agent_open_if_enabled();
1295 r = bus_wait_for_jobs_new(bus, &w);
1299 for (i = 1; i < argc; i++) {
1300 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1301 _cleanup_free_ char *e = NULL, *unit = NULL;
1304 if (!machine_name_is_valid(argv[i])) {
1305 log_error("Invalid machine name %s.", argv[i]);
1309 e = unit_name_escape(argv[i]);
1313 unit = unit_name_build("systemd-nspawn", e, ".service");
1317 r = sd_bus_call_method(
1319 "org.freedesktop.systemd1",
1320 "/org/freedesktop/systemd1",
1321 "org.freedesktop.systemd1.Manager",
1325 "ss", unit, "fail");
1327 log_error("Failed to start unit: %s", bus_error_message(&error, -r));
1331 r = sd_bus_message_read(reply, "o", &object);
1333 return bus_log_parse_error(r);
1335 r = bus_wait_for_jobs_add(w, object);
1340 r = bus_wait_for_jobs(w, arg_quiet);
1347 static int enable_machine(int argc, char *argv[], void *userdata) {
1348 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1349 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1350 int carries_install_info = 0;
1351 const char *method = NULL;
1352 sd_bus *bus = userdata;
1357 polkit_agent_open_if_enabled();
1359 method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
1361 r = sd_bus_message_new_method_call(
1364 "org.freedesktop.systemd1",
1365 "/org/freedesktop/systemd1",
1366 "org.freedesktop.systemd1.Manager",
1369 return bus_log_create_error(r);
1371 r = sd_bus_message_open_container(m, 'a', "s");
1373 return bus_log_create_error(r);
1375 for (i = 1; i < argc; i++) {
1376 _cleanup_free_ char *e = NULL, *unit = NULL;
1378 if (!machine_name_is_valid(argv[i])) {
1379 log_error("Invalid machine name %s.", argv[i]);
1383 e = unit_name_escape(argv[i]);
1387 unit = unit_name_build("systemd-nspawn", e, ".service");
1391 r = sd_bus_message_append(m, "s", unit);
1393 return bus_log_create_error(r);
1396 r = sd_bus_message_close_container(m);
1398 return bus_log_create_error(r);
1400 if (streq(argv[0], "enable"))
1401 r = sd_bus_message_append(m, "bb", false, false);
1403 r = sd_bus_message_append(m, "b", false);
1405 return bus_log_create_error(r);
1407 r = sd_bus_call(bus, m, 0, &error, &reply);
1409 log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
1413 if (streq(argv[0], "enable")) {
1414 r = sd_bus_message_read(reply, "b", carries_install_info);
1416 return bus_log_parse_error(r);
1419 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1423 r = sd_bus_call_method(
1425 "org.freedesktop.systemd1",
1426 "/org/freedesktop/systemd1",
1427 "org.freedesktop.systemd1.Manager",
1433 log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
1440 static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1441 const char **our_path = userdata, *line;
1449 r = sd_bus_message_read(m, "us", &priority, &line);
1451 bus_log_parse_error(r);
1455 if (!streq_ptr(*our_path, sd_bus_message_get_path(m)))
1458 if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
1461 log_full(priority, "%s", line);
1465 static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1466 const char **our_path = userdata, *path, *result;
1474 r = sd_bus_message_read(m, "uos", &id, &path, &result);
1476 bus_log_parse_error(r);
1480 if (!streq_ptr(*our_path, path))
1483 sd_event_exit(sd_bus_get_event(bus), !streq_ptr(result, "done"));
1487 static int transfer_signal_handler(sd_event_source *s, const struct signalfd_siginfo *si, void *userdata) {
1492 log_info("Continuing download in the background. Use \"machinectl cancel-transfer %" PRIu32 "\" to abort transfer.", PTR_TO_UINT32(userdata));
1494 sd_event_exit(sd_event_source_get_event(s), EINTR);
1498 static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
1499 _cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
1500 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1501 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1502 _cleanup_event_unref_ sd_event* event = NULL;
1503 const char *path = NULL;
1510 polkit_agent_open_if_enabled();
1512 r = sd_event_default(&event);
1514 return log_error_errno(r, "Failed to get event loop: %m");
1516 r = sd_bus_attach_event(bus, event, 0);
1518 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1520 r = sd_bus_add_match(
1524 "sender='org.freedesktop.import1',"
1525 "interface='org.freedesktop.import1.Manager',"
1526 "member='TransferRemoved',"
1527 "path='/org/freedesktop/import1'",
1528 match_transfer_removed, &path);
1530 return log_error_errno(r, "Failed to install match: %m");
1532 r = sd_bus_add_match(
1536 "sender='org.freedesktop.import1',"
1537 "interface='org.freedesktop.import1.Transfer',"
1538 "member='LogMessage'",
1539 match_log_message, &path);
1541 return log_error_errno(r, "Failed to install match: %m");
1543 r = sd_bus_call(bus, m, 0, &error, &reply);
1545 log_error("Failed pull image: %s", bus_error_message(&error, -r));
1549 r = sd_bus_message_read(reply, "uo", &id, &path);
1551 return bus_log_parse_error(r);
1553 sigprocmask_many(SIG_BLOCK, SIGTERM, SIGINT, -1);
1556 log_info("Enqueued transfer job %u. Press C-c to continue download in background.", id);
1558 sd_event_add_signal(event, NULL, SIGINT, transfer_signal_handler, UINT32_TO_PTR(id));
1559 sd_event_add_signal(event, NULL, SIGTERM, transfer_signal_handler, UINT32_TO_PTR(id));
1561 r = sd_event_loop(event);
1563 return log_error_errno(r, "Failed to run event loop: %m");
1568 static int pull_tar(int argc, char *argv[], void *userdata) {
1569 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1570 _cleanup_free_ char *l = NULL, *ll = NULL;
1571 const char *local, *remote;
1572 sd_bus *bus = userdata;
1578 if (!http_url_is_valid(remote)) {
1579 log_error("URL '%s' is not valid.", remote);
1586 r = import_url_last_component(remote, &l);
1588 return log_error_errno(r, "Failed to get final component of URL: %m");
1593 if (isempty(local) || streq(local, "-"))
1597 r = tar_strip_suffixes(local, &ll);
1599 return log_error_errno(r, "Failed to strip tar suffixes: %m");
1603 if (!machine_name_is_valid(local)) {
1604 log_error("Local name %s is not a suitable machine name.", local);
1609 r = sd_bus_message_new_method_call(
1612 "org.freedesktop.import1",
1613 "/org/freedesktop/import1",
1614 "org.freedesktop.import1.Manager",
1617 return bus_log_create_error(r);
1619 r = sd_bus_message_append(
1624 import_verify_to_string(arg_verify),
1627 return bus_log_create_error(r);
1629 return pull_image_common(bus, m);
1632 static int pull_raw(int argc, char *argv[], void *userdata) {
1633 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1634 _cleanup_free_ char *l = NULL, *ll = NULL;
1635 const char *local, *remote;
1636 sd_bus *bus = userdata;
1642 if (!http_url_is_valid(remote)) {
1643 log_error("URL '%s' is not valid.", remote);
1650 r = import_url_last_component(remote, &l);
1652 return log_error_errno(r, "Failed to get final component of URL: %m");
1657 if (isempty(local) || streq(local, "-"))
1661 r = raw_strip_suffixes(local, &ll);
1663 return log_error_errno(r, "Failed to strip tar suffixes: %m");
1667 if (!machine_name_is_valid(local)) {
1668 log_error("Local name %s is not a suitable machine name.", local);
1673 r = sd_bus_message_new_method_call(
1676 "org.freedesktop.import1",
1677 "/org/freedesktop/import1",
1678 "org.freedesktop.import1.Manager",
1681 return bus_log_create_error(r);
1683 r = sd_bus_message_append(
1688 import_verify_to_string(arg_verify),
1691 return bus_log_create_error(r);
1693 return pull_image_common(bus, m);
1696 static int pull_dkr(int argc, char *argv[], void *userdata) {
1697 _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1698 const char *local, *remote, *tag;
1699 sd_bus *bus = userdata;
1702 if (arg_verify != IMPORT_VERIFY_NO) {
1703 log_error("Imports from DKR do not support image verification, please pass --verify=no.");
1708 tag = strchr(remote, ':');
1710 remote = strndupa(remote, tag - remote);
1714 if (!dkr_name_is_valid(remote)) {
1715 log_error("DKR name '%s' is invalid.", remote);
1718 if (tag && !dkr_tag_is_valid(tag)) {
1719 log_error("DKR tag '%s' is invalid.", remote);
1726 local = strchr(remote, '/');
1733 if (isempty(local) || streq(local, "-"))
1737 if (!machine_name_is_valid(local)) {
1738 log_error("Local name %s is not a suitable machine name.", local);
1743 r = sd_bus_message_new_method_call(
1746 "org.freedesktop.import1",
1747 "/org/freedesktop/import1",
1748 "org.freedesktop.import1.Manager",
1751 return bus_log_create_error(r);
1753 r = sd_bus_message_append(
1760 import_verify_to_string(arg_verify),
1763 return bus_log_create_error(r);
1765 return pull_image_common(bus, m);
1768 typedef struct TransferInfo {
1776 static int compare_transfer_info(const void *a, const void *b) {
1777 const TransferInfo *x = a, *y = b;
1779 return strcmp(x->local, y->local);
1782 static int list_transfers(int argc, char *argv[], void *userdata) {
1783 size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
1784 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1785 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1786 _cleanup_free_ TransferInfo *transfers = NULL;
1787 size_t n_transfers = 0, n_allocated = 0, j;
1788 const char *type, *remote, *local, *object;
1789 sd_bus *bus = userdata;
1790 uint32_t id, max_id = 0;
1794 pager_open_if_enabled();
1796 r = sd_bus_call_method(
1798 "org.freedesktop.import1",
1799 "/org/freedesktop/import1",
1800 "org.freedesktop.import1.Manager",
1806 log_error("Could not get transfers: %s", bus_error_message(&error, -r));
1810 r = sd_bus_message_enter_container(reply, 'a', "(usssdo)");
1812 return bus_log_parse_error(r);
1814 while ((r = sd_bus_message_read(reply, "(usssdo)", &id, &type, &remote, &local, &progress, &object)) > 0) {
1817 if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
1820 transfers[n_transfers].id = id;
1821 transfers[n_transfers].type = type;
1822 transfers[n_transfers].remote = remote;
1823 transfers[n_transfers].local = local;
1824 transfers[n_transfers].progress = progress;
1844 return bus_log_parse_error(r);
1846 r = sd_bus_message_exit_container(reply);
1848 return bus_log_parse_error(r);
1850 qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
1853 printf("%-*s %-*s %-*s %-*s %-*s\n",
1854 (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
1856 (int) max_type, "TYPE",
1857 (int) max_local, "LOCAL",
1858 (int) max_remote, "REMOTE");
1860 for (j = 0; j < n_transfers; j++)
1861 printf("%*" PRIu32 " %*u%% %-*s %-*s %-*s\n",
1862 (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
1863 (int) 6, (unsigned) (transfers[j].progress * 100),
1864 (int) max_type, transfers[j].type,
1865 (int) max_local, transfers[j].local,
1866 (int) max_remote, transfers[j].remote);
1869 printf("\n%zu transfers listed.\n", n_transfers);
1874 static int cancel_transfer(int argc, char *argv[], void *userdata) {
1875 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1876 sd_bus *bus = userdata;
1881 polkit_agent_open_if_enabled();
1883 for (i = 1; i < argc; i++) {
1886 r = safe_atou32(argv[i], &id);
1888 return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
1890 r = sd_bus_call_method(
1892 "org.freedesktop.import1",
1893 "/org/freedesktop/import1",
1894 "org.freedesktop.import1.Manager",
1900 log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
1908 static int help(int argc, char *argv[], void *userdata) {
1910 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1911 "Send control commands to or query the virtual machine and container\n"
1912 "registration manager.\n\n"
1913 " -h --help Show this help\n"
1914 " --version Show package version\n"
1915 " --no-pager Do not pipe output into a pager\n"
1916 " --no-legend Do not show the headers and footers\n"
1917 " --no-ask-password Do not ask for system passwords\n"
1918 " -H --host=[USER@]HOST Operate on remote host\n"
1919 " -M --machine=CONTAINER Operate on local container\n"
1920 " -p --property=NAME Show only properties by this name\n"
1921 " -q --quiet Suppress output\n"
1922 " -a --all Show all properties, including empty ones\n"
1923 " -l --full Do not ellipsize output\n"
1924 " --kill-who=WHO Who to send signal to\n"
1925 " -s --signal=SIGNAL Which signal to send\n"
1926 " --read-only Create read-only bind mount\n"
1927 " --mkdir Create directory before bind mounting, if missing\n"
1928 " -n --lines=INTEGER Number of journal entries to show\n"
1929 " -o --output=STRING Change journal output mode (short,\n"
1930 " short-monotonic, verbose, export, json,\n"
1931 " json-pretty, json-sse, cat)\n"
1932 " --verify=MODE Verification mode for downloaded images (no,\n"
1933 " checksum, signature)\n"
1934 " --force Download image even if already exists\n"
1935 " --dkr-index-url=URL Specify the index URL to use for DKR image\n"
1937 "Machine Commands:\n"
1938 " list List running VMs and containers\n"
1939 " status NAME... Show VM/container details\n"
1940 " show NAME... Show properties of one or more VMs/containers\n"
1941 " start NAME... Start container as a service\n"
1942 " login NAME Get a login prompt on a container\n"
1943 " enable NAME... Enable automatic container start at boot\n"
1944 " disable NAME... Disable automatic container start at boot\n"
1945 " poweroff NAME... Power off one or more containers\n"
1946 " reboot NAME... Reboot one or more containers\n"
1947 " terminate NAME... Terminate one or more VMs/containers\n"
1948 " kill NAME... Send signal to processes of a VM/container\n"
1949 " copy-to NAME PATH [PATH] Copy files from the host to a container\n"
1950 " copy-from NAME PATH [PATH] Copy files from a container to the host\n"
1951 " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
1953 " list-images Show available container and VM images\n"
1954 " image-status NAME... Show image details\n"
1955 " show-image NAME... Show properties of image\n"
1956 " clone NAME NAME Clone an image\n"
1957 " rename NAME NAME Rename an image\n"
1958 " read-only NAME [BOOL] Mark or unmark image read-only\n"
1959 " remove NAME... Remove an image\n\n"
1960 "Image Transfer Commands:\n"
1961 " pull-tar URL [NAME] Download a TAR container image\n"
1962 " pull-raw URL [NAME] Download a RAW container or VM image\n"
1963 " pull-dkr REMOTE [NAME] Download a DKR container image\n"
1964 " list-transfers Show list of downloads in progress\n"
1965 " cancel-transfer Cancel a download\n"
1966 , program_invocation_short_name);
1971 static int parse_argv(int argc, char *argv[]) {
1974 ARG_VERSION = 0x100,
1980 ARG_NO_ASK_PASSWORD,
1986 static const struct option options[] = {
1987 { "help", no_argument, NULL, 'h' },
1988 { "version", no_argument, NULL, ARG_VERSION },
1989 { "property", required_argument, NULL, 'p' },
1990 { "all", no_argument, NULL, 'a' },
1991 { "full", no_argument, NULL, 'l' },
1992 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1993 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1994 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1995 { "signal", required_argument, NULL, 's' },
1996 { "host", required_argument, NULL, 'H' },
1997 { "machine", required_argument, NULL, 'M' },
1998 { "read-only", no_argument, NULL, ARG_READ_ONLY },
1999 { "mkdir", no_argument, NULL, ARG_MKDIR },
2000 { "quiet", no_argument, NULL, 'q' },
2001 { "lines", required_argument, NULL, 'n' },
2002 { "output", required_argument, NULL, 'o' },
2003 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
2004 { "verify", required_argument, NULL, ARG_VERIFY },
2005 { "force", no_argument, NULL, ARG_FORCE },
2006 { "dkr-index-url", required_argument, NULL, ARG_DKR_INDEX_URL },
2015 while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
2020 return help(0, NULL, NULL);
2023 puts(PACKAGE_STRING);
2024 puts(SYSTEMD_FEATURES);
2028 r = strv_extend(&arg_property, optarg);
2032 /* If the user asked for a particular
2033 * property, show it to him, even if it is
2047 if (safe_atou(optarg, &arg_lines) < 0) {
2048 log_error("Failed to parse lines '%s'", optarg);
2054 arg_output = output_mode_from_string(optarg);
2055 if (arg_output < 0) {
2056 log_error("Unknown output '%s'.", optarg);
2062 arg_no_pager = true;
2070 arg_kill_who = optarg;
2074 arg_signal = signal_from_string_try_harder(optarg);
2075 if (arg_signal < 0) {
2076 log_error("Failed to parse signal string %s.", optarg);
2081 case ARG_NO_ASK_PASSWORD:
2082 arg_ask_password = false;
2086 arg_transport = BUS_TRANSPORT_REMOTE;
2091 arg_transport = BUS_TRANSPORT_MACHINE;
2096 arg_read_only = true;
2108 arg_verify = import_verify_from_string(optarg);
2109 if (arg_verify < 0) {
2110 log_error("Failed to parse --verify= setting: %s", optarg);
2119 case ARG_DKR_INDEX_URL:
2120 if (!http_url_is_valid(optarg)) {
2121 log_error("Index URL is invalid: %s", optarg);
2125 arg_dkr_index_url = optarg;
2132 assert_not_reached("Unhandled option");
2138 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
2140 static const Verb verbs[] = {
2141 { "help", VERB_ANY, VERB_ANY, 0, help },
2142 { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
2143 { "list-images", VERB_ANY, 1, 0, list_images },
2144 { "status", 2, VERB_ANY, 0, show_machine },
2145 { "image-status", 2, VERB_ANY, 0, show_image },
2146 { "show", VERB_ANY, VERB_ANY, 0, show_machine },
2147 { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
2148 { "terminate", 2, VERB_ANY, 0, terminate_machine },
2149 { "reboot", 2, VERB_ANY, 0, reboot_machine },
2150 { "poweroff", 2, VERB_ANY, 0, poweroff_machine },
2151 { "kill", 2, VERB_ANY, 0, kill_machine },
2152 { "login", 2, 2, 0, login_machine },
2153 { "bind", 3, 4, 0, bind_mount },
2154 { "copy-to", 3, 4, 0, copy_files },
2155 { "copy-from", 3, 4, 0, copy_files },
2156 { "remove", 2, VERB_ANY, 0, remove_image },
2157 { "rename", 3, 3, 0, rename_image },
2158 { "clone", 3, 3, 0, clone_image },
2159 { "read-only", 2, 3, 0, read_only_image },
2160 { "start", 2, VERB_ANY, 0, start_machine },
2161 { "enable", 2, VERB_ANY, 0, enable_machine },
2162 { "disable", 2, VERB_ANY, 0, enable_machine },
2163 { "pull-tar", 2, 3, 0, pull_tar },
2164 { "pull-raw", 2, 3, 0, pull_raw },
2165 { "pull-dkr", 2, 3, 0, pull_dkr },
2166 { "list-transfers", VERB_ANY, 1, 0, list_transfers },
2167 { "cancel-transfer", 2, VERB_ANY, 0, cancel_transfer },
2171 return dispatch_verb(argc, argv, verbs, bus);
2174 int main(int argc, char*argv[]) {
2175 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
2178 setlocale(LC_ALL, "");
2179 log_parse_environment();
2182 r = parse_argv(argc, argv);
2186 r = bus_open_transport(arg_transport, arg_host, false, &bus);
2188 log_error_errno(r, "Failed to create bus connection: %m");
2192 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
2194 r = machinectl_main(argc, argv, bus);
2198 polkit_agent_close();
2200 strv_free(arg_property);
2202 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;