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>
41 #include "spawn-polkit-agent.h"
43 #include "bus-error.h"
46 #include "unit-name.h"
47 #include "cgroup-show.h"
48 #include "logs-show.h"
49 #include "cgroup-util.h"
51 #include "event-util.h"
52 #include "path-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;
73 static void pager_open_if_enabled(void) {
81 static void polkit_agent_open_if_enabled(void) {
83 /* Open the polkit agent as a child process if necessary */
85 if (!arg_ask_password)
88 if (arg_transport != BUS_TRANSPORT_LOCAL)
94 static OutputFlags get_output_flags(void) {
96 arg_all * OUTPUT_SHOW_ALL |
97 arg_full * OUTPUT_FULL_WIDTH |
98 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
99 on_tty() * OUTPUT_COLOR |
100 !arg_quiet * OUTPUT_WARN_CUTOFF;
103 typedef struct MachineInfo {
109 static int compare_machine_info(const void *a, const void *b) {
110 const MachineInfo *x = a, *y = b;
112 return strcmp(x->name, y->name);
115 static int list_machines(int argc, char *argv[], void *userdata) {
117 size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
118 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
119 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
120 _cleanup_free_ MachineInfo *machines = NULL;
121 const char *name, *class, *service, *object;
122 size_t n_machines = 0, n_allocated = 0, j;
123 sd_bus *bus = userdata;
128 pager_open_if_enabled();
130 r = sd_bus_call_method(
132 "org.freedesktop.machine1",
133 "/org/freedesktop/machine1",
134 "org.freedesktop.machine1.Manager",
140 log_error("Could not get machines: %s", bus_error_message(&error, -r));
144 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
146 return bus_log_parse_error(r);
148 while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
151 if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
154 machines[n_machines].name = name;
155 machines[n_machines].class = class;
156 machines[n_machines].service = service;
173 return bus_log_parse_error(r);
175 r = sd_bus_message_exit_container(reply);
177 return bus_log_parse_error(r);
179 qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
182 printf("%-*s %-*s %-*s\n",
183 (int) max_name, "MACHINE",
184 (int) max_class, "CLASS",
185 (int) max_service, "SERVICE");
187 for (j = 0; j < n_machines; j++)
188 printf("%-*s %-*s %-*s\n",
189 (int) max_name, machines[j].name,
190 (int) max_class, machines[j].class,
191 (int) max_service, machines[j].service);
194 printf("\n%zu machines listed.\n", n_machines);
199 typedef struct ImageInfo {
208 static int compare_image_info(const void *a, const void *b) {
209 const ImageInfo *x = a, *y = b;
211 return strcmp(x->name, y->name);
214 static int list_images(int argc, char *argv[], void *userdata) {
216 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
217 size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("SIZE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
218 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
219 _cleanup_free_ ImageInfo *images = NULL;
220 size_t n_images = 0, n_allocated = 0, j;
221 const char *name, *type, *object;
222 sd_bus *bus = userdata;
223 uint64_t crtime, mtime, size;
228 pager_open_if_enabled();
230 r = sd_bus_call_method(
232 "org.freedesktop.machine1",
233 "/org/freedesktop/machine1",
234 "org.freedesktop.machine1.Manager",
240 log_error("Could not get images: %s", bus_error_message(&error, -r));
244 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
246 return bus_log_parse_error(r);
248 while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
249 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
252 if (name[0] == '.' && !arg_all)
255 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
258 images[n_images].name = name;
259 images[n_images].type = type;
260 images[n_images].read_only = read_only;
261 images[n_images].crtime = crtime;
262 images[n_images].mtime = mtime;
263 images[n_images].size = size;
274 l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
280 l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
285 if (size != (uint64_t) -1) {
286 l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
294 return bus_log_parse_error(r);
296 r = sd_bus_message_exit_container(reply);
298 return bus_log_parse_error(r);
300 qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
303 printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
304 (int) max_name, "NAME",
305 (int) max_type, "TYPE",
307 (int) max_size, "SIZE",
308 (int) max_crtime, "CREATED",
309 (int) max_mtime, "MODIFIED");
311 for (j = 0; j < n_images; j++) {
312 char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
314 printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
315 (int) max_name, images[j].name,
316 (int) max_type, images[j].type,
317 images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
318 (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
319 (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
320 (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
324 printf("\n%zu images listed.\n", n_images);
329 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
330 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
331 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
332 _cleanup_free_ char *path = NULL;
340 if (arg_transport == BUS_TRANSPORT_REMOTE)
343 path = unit_dbus_path_from_name(unit);
347 r = sd_bus_get_property(
349 "org.freedesktop.systemd1",
351 endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
357 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
361 r = sd_bus_message_read(reply, "s", &cgroup);
363 return bus_log_parse_error(r);
368 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
377 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
381 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
382 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
390 r = sd_bus_call_method(bus,
391 "org.freedesktop.machine1",
392 "/org/freedesktop/machine1",
393 "org.freedesktop.machine1.Manager",
394 "GetMachineAddresses",
401 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
403 return bus_log_parse_error(r);
405 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
409 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
411 r = sd_bus_message_read(reply, "i", &family);
413 return bus_log_parse_error(r);
415 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
417 return bus_log_parse_error(r);
419 fputs(prefix, stdout);
420 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
421 if (family == AF_INET6 && ifi > 0)
425 r = sd_bus_message_exit_container(reply);
427 return bus_log_parse_error(r);
429 if (prefix != prefix2)
433 return bus_log_parse_error(r);
435 r = sd_bus_message_exit_container(reply);
437 return bus_log_parse_error(r);
442 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
443 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
444 const char *k, *v, *pretty = NULL;
451 r = sd_bus_call_method(bus,
452 "org.freedesktop.machine1",
453 "/org/freedesktop/machine1",
454 "org.freedesktop.machine1.Manager",
455 "GetMachineOSRelease",
462 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
464 return bus_log_parse_error(r);
466 while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
467 if (streq(k, "PRETTY_NAME"))
472 return bus_log_parse_error(r);
474 r = sd_bus_message_exit_container(reply);
476 return bus_log_parse_error(r);
479 printf("%s%s\n", prefix, pretty);
484 typedef struct MachineStatusInfo {
490 char *root_directory;
492 struct dual_timestamp timestamp;
497 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
498 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
499 char since2[FORMAT_TIMESTAMP_MAX], *s2;
505 fputs(strna(i->name), stdout);
507 if (!sd_id128_equal(i->id, SD_ID128_NULL))
508 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
512 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
513 s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
516 printf("\t Since: %s; %s\n", s2, s1);
518 printf("\t Since: %s\n", s2);
521 _cleanup_free_ char *t = NULL;
523 printf("\t Leader: %u", (unsigned) i->leader);
525 get_process_comm(i->leader, &t);
533 printf("\t Service: %s", i->service);
536 printf("; class %s", i->class);
540 printf("\t Class: %s\n", i->class);
542 if (i->root_directory)
543 printf("\t Root: %s\n", i->root_directory);
545 if (i->n_netif > 0) {
548 fputs("\t Iface:", stdout);
550 for (c = 0; c < i->n_netif; c++) {
551 char name[IF_NAMESIZE+1] = "";
553 if (if_indextoname(i->netif[c], name)) {
562 printf(" %i", i->netif[c]);
568 print_addresses(bus, i->name, ifi,
572 print_os_release(bus, i->name, "\t OS: ");
575 printf("\t Unit: %s\n", i->unit);
576 show_unit_cgroup(bus, i->unit, i->leader);
578 if (arg_transport == BUS_TRANSPORT_LOCAL) {
580 show_journal_by_unit(
585 i->timestamp.monotonic,
588 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
589 SD_JOURNAL_LOCAL_ONLY,
596 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
597 MachineStatusInfo *i = userdata;
602 assert_cc(sizeof(int32_t) == sizeof(int));
603 r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
609 i->n_netif = l / sizeof(int32_t);
610 i->netif = memdup(v, l);
617 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
619 static const struct bus_properties_map map[] = {
620 { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
621 { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
622 { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
623 { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
624 { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
625 { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
626 { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
627 { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
628 { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
629 { "NetworkInterfaces", "ai", map_netif, 0 },
633 MachineStatusInfo info = {};
641 r = bus_map_all_properties(bus,
642 "org.freedesktop.machine1",
647 return log_error_errno(r, "Could not get properties: %m");
653 print_machine_status_info(bus, &info);
659 free(info.root_directory);
665 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
677 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
679 log_error_errno(r, "Could not get properties: %m");
684 static int show_machine(int argc, char *argv[], void *userdata) {
686 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
687 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
688 bool properties, new_line = false;
689 sd_bus *bus = userdata;
694 properties = !strstr(argv[0], "status");
696 pager_open_if_enabled();
698 if (properties && argc <= 1) {
700 /* If no argument is specified, inspect the manager
702 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
707 for (i = 1; i < argc; i++) {
708 const char *path = NULL;
710 r = sd_bus_call_method(
712 "org.freedesktop.machine1",
713 "/org/freedesktop/machine1",
714 "org.freedesktop.machine1.Manager",
720 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
724 r = sd_bus_message_read(reply, "o", &path);
726 return bus_log_parse_error(r);
729 r = show_machine_properties(bus, path, &new_line);
731 r = show_machine_info(argv[0], bus, path, &new_line);
737 typedef struct ImageStatusInfo {
746 uint64_t size_exclusive;
747 uint64_t limit_exclusive;
750 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
751 char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
752 char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
753 char bs[FORMAT_BYTES_MAX], *s3;
754 char bs_exclusive[FORMAT_BYTES_MAX], *s4;
760 fputs(i->name, stdout);
765 printf("\t Type: %s\n", i->type);
768 printf("\t Path: %s\n", i->path);
770 printf("\t RO: %s%s%s\n",
771 i->read_only ? ansi_highlight_red() : "",
772 i->read_only ? "read-only" : "writable",
773 i->read_only ? ansi_highlight_off() : "");
775 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
776 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
778 printf("\t Created: %s; %s\n", s2, s1);
780 printf("\t Created: %s\n", s2);
782 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
783 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
785 printf("\tModified: %s; %s\n", s2, s1);
787 printf("\tModified: %s\n", s2);
789 s3 = format_bytes(bs, sizeof(bs), i->size);
790 s4 = i->size_exclusive != i->size ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->size_exclusive) : NULL;
792 printf("\t Size: %s (exclusive: %s)\n", s3, s4);
794 printf("\t Size: %s\n", s3);
796 s3 = format_bytes(bs, sizeof(bs), i->limit);
797 s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
799 printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
801 printf("\t Limit: %s\n", s3);
804 static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
806 static const struct bus_properties_map map[] = {
807 { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
808 { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
809 { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
810 { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
811 { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
812 { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
813 { "Size", "t", NULL, offsetof(ImageStatusInfo, size) },
814 { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
815 { "SizeExclusive", "t", NULL, offsetof(ImageStatusInfo, size_exclusive) },
816 { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
820 ImageStatusInfo info = {};
828 r = bus_map_all_properties(bus,
829 "org.freedesktop.machine1",
834 return log_error_errno(r, "Could not get properties: %m");
840 print_image_status_info(bus, &info);
849 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
861 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
863 log_error_errno(r, "Could not get properties: %m");
868 static int show_image(int argc, char *argv[], void *userdata) {
870 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
871 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
872 bool properties, new_line = false;
873 sd_bus *bus = userdata;
878 properties = !strstr(argv[0], "status");
880 pager_open_if_enabled();
882 if (properties && argc <= 1) {
884 /* If no argument is specified, inspect the manager
886 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
891 for (i = 1; i < argc; i++) {
892 const char *path = NULL;
894 r = sd_bus_call_method(
896 "org.freedesktop.machine1",
897 "/org/freedesktop/machine1",
898 "org.freedesktop.machine1.Manager",
904 log_error("Could not get path to image: %s", bus_error_message(&error, -r));
908 r = sd_bus_message_read(reply, "o", &path);
910 return bus_log_parse_error(r);
913 r = show_image_properties(bus, path, &new_line);
915 r = show_image_info(argv[0], bus, path, &new_line);
921 static int kill_machine(int argc, char *argv[], void *userdata) {
922 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
923 sd_bus *bus = userdata;
928 polkit_agent_open_if_enabled();
931 arg_kill_who = "all";
933 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++) {
980 r = sd_bus_call_method(
982 "org.freedesktop.machine1",
983 "/org/freedesktop/machine1",
984 "org.freedesktop.machine1.Manager",
990 log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
998 static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
999 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1000 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL;
1009 r = sd_bus_call_method(
1011 "org.freedesktop.machine1",
1012 "/org/freedesktop/machine1",
1013 "org.freedesktop.machine1.Manager",
1019 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
1023 r = sd_bus_message_read(reply, "o", &object);
1025 return bus_log_parse_error(r);
1027 r = sd_bus_get_property(
1029 "org.freedesktop.machine1",
1031 "org.freedesktop.machine1.Machine",
1037 return log_error_errno(r, "Failed to retrieve PID of leader: %m");
1039 r = sd_bus_message_read(reply2, "u", &leader);
1041 return bus_log_parse_error(r);
1047 static int copy_files(int argc, char *argv[], void *userdata) {
1048 char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
1049 _cleanup_close_ int hostfd = -1;
1050 sd_bus *bus = userdata;
1051 pid_t child, leader;
1058 copy_from = streq(argv[0], "copy-from");
1059 dest = argv[3] ?: argv[2];
1060 host_path = strdupa(copy_from ? dest : argv[2]);
1061 container_path = strdupa(copy_from ? argv[2] : dest);
1063 if (!path_is_absolute(container_path)) {
1064 log_error("Container path not absolute.");
1068 t = strdupa(host_path);
1069 host_basename = basename(t);
1070 host_dirname = dirname(host_path);
1072 t = strdupa(container_path);
1073 container_basename = basename(t);
1074 container_dirname = dirname(container_path);
1076 r = machine_get_leader(bus, argv[1], &leader);
1080 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1082 return log_error_errno(errno, "Failed to open source directory: %m");
1086 return log_error_errno(errno, "Failed to fork(): %m");
1093 q = procfs_file_alloca(leader, "ns/mnt");
1094 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1096 log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1097 _exit(EXIT_FAILURE);
1100 if (setns(mntfd, CLONE_NEWNS) < 0) {
1101 log_error_errno(errno, "Failed to join namespace of leader: %m");
1102 _exit(EXIT_FAILURE);
1105 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1106 if (containerfd < 0) {
1107 log_error_errno(errno, "Failed top open destination directory: %m");
1108 _exit(EXIT_FAILURE);
1112 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1114 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1116 log_error_errno(errno, "Failed to copy tree: %m");
1117 _exit(EXIT_FAILURE);
1120 _exit(EXIT_SUCCESS);
1123 r = wait_for_terminate(child, &si);
1125 return log_error_errno(r, "Failed to wait for client: %m");
1126 if (si.si_code != CLD_EXITED) {
1127 log_error("Client died abnormally.");
1130 if (si.si_status != EXIT_SUCCESS)
1136 static int bind_mount(int argc, char *argv[], void *userdata) {
1137 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
1138 sd_bus *bus = userdata;
1139 pid_t child, leader;
1142 bool mount_slave_created = false, mount_slave_mounted = false,
1143 mount_tmp_created = false, mount_tmp_mounted = false,
1144 mount_outside_created = false, mount_outside_mounted = false;
1149 /* One day, when bind mounting /proc/self/fd/n works across
1150 * namespace boundaries we should rework this logic to make
1153 dest = argv[3] ?: argv[2];
1154 if (!path_is_absolute(dest)) {
1155 log_error("Destination path not absolute.");
1159 p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/");
1160 if (access(p, F_OK) < 0) {
1161 log_error("Container does not allow propagation of mount points.");
1165 r = machine_get_leader(bus, argv[1], &leader);
1169 /* Our goal is to install a new bind mount into the container,
1170 possibly read-only. This is irritatingly complex
1171 unfortunately, currently.
1173 First, we start by creating a private playground in /tmp,
1174 that we can mount MS_SLAVE. (Which is necessary, since
1175 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
1178 if (!mkdtemp(mount_slave))
1179 return log_error_errno(errno, "Failed to create playground: %m");
1181 mount_slave_created = true;
1183 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
1184 r = log_error_errno(errno, "Failed to make bind mount: %m");
1188 mount_slave_mounted = true;
1190 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
1191 r = log_error_errno(errno, "Failed to remount slave: %m");
1195 /* Second, we mount the source directory to a directory inside
1196 of our MS_SLAVE playground. */
1197 mount_tmp = strappenda(mount_slave, "/mount");
1198 if (mkdir(mount_tmp, 0700) < 0) {
1199 r = log_error_errno(errno, "Failed to create temporary mount: %m");
1203 mount_tmp_created = true;
1205 if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
1206 r = log_error_errno(errno, "Failed to overmount: %m");
1210 mount_tmp_mounted = true;
1212 /* Third, we remount the new bind mount read-only if requested. */
1214 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
1215 r = log_error_errno(errno, "Failed to mark read-only: %m");
1219 /* Fourth, we move the new bind mount into the propagation
1220 * directory. This way it will appear there read-only
1223 mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
1224 if (!mkdtemp(mount_outside)) {
1225 r = log_error_errno(errno, "Cannot create propagation directory: %m");
1229 mount_outside_created = true;
1231 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
1232 r = log_error_errno(errno, "Failed to move: %m");
1236 mount_outside_mounted = true;
1237 mount_tmp_mounted = false;
1239 (void) rmdir(mount_tmp);
1240 mount_tmp_created = false;
1242 (void) umount(mount_slave);
1243 mount_slave_mounted = false;
1245 (void) rmdir(mount_slave);
1246 mount_slave_created = false;
1250 r = log_error_errno(errno, "Failed to fork(): %m");
1255 const char *mount_inside;
1259 q = procfs_file_alloca(leader, "ns/mnt");
1260 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1262 log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1263 _exit(EXIT_FAILURE);
1266 if (setns(mntfd, CLONE_NEWNS) < 0) {
1267 log_error_errno(errno, "Failed to join namespace of leader: %m");
1268 _exit(EXIT_FAILURE);
1272 mkdir_p(dest, 0755);
1274 /* Fifth, move the mount to the right place inside */
1275 mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside));
1276 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1277 log_error_errno(errno, "Failed to mount: %m");
1278 _exit(EXIT_FAILURE);
1281 _exit(EXIT_SUCCESS);
1284 r = wait_for_terminate(child, &si);
1286 log_error_errno(r, "Failed to wait for client: %m");
1289 if (si.si_code != CLD_EXITED) {
1290 log_error("Client died abnormally.");
1294 if (si.si_status != EXIT_SUCCESS) {
1302 if (mount_outside_mounted)
1303 umount(mount_outside);
1304 if (mount_outside_created)
1305 rmdir(mount_outside);
1307 if (mount_tmp_mounted)
1309 if (mount_tmp_created)
1312 if (mount_slave_mounted)
1313 umount(mount_slave);
1314 if (mount_slave_created)
1315 umount(mount_slave);
1320 static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
1321 PTYForward ** forward = (PTYForward**) userdata;
1329 /* If the forwarder is already initialized, tell it to
1330 * exit on the next vhangup(), so that we still flush
1331 * out what might be queued and exit then. */
1333 r = pty_forward_set_ignore_vhangup(*forward, false);
1337 log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
1340 /* On error, or when the forwarder is not initialized yet, quit immediately */
1341 sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
1345 static int login_machine(int argc, char *argv[], void *userdata) {
1346 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1347 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1348 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
1349 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1350 _cleanup_event_unref_ sd_event *event = NULL;
1351 int master = -1, r, ret = 0;
1352 sd_bus *bus = userdata;
1353 const char *pty, *match;
1360 if (arg_transport != BUS_TRANSPORT_LOCAL &&
1361 arg_transport != BUS_TRANSPORT_MACHINE) {
1362 log_error("Login only supported on local machines.");
1366 polkit_agent_open_if_enabled();
1368 r = sd_event_default(&event);
1370 return log_error_errno(r, "Failed to get event loop: %m");
1372 r = sd_bus_attach_event(bus, event, 0);
1374 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1376 match = strappenda("type='signal',"
1377 "sender='org.freedesktop.machine1',"
1378 "path='/org/freedesktop/machine1',",
1379 "interface='org.freedesktop.machine1.Manager',"
1380 "member='MachineRemoved',"
1385 r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
1387 return log_error_errno(r, "Failed to add machine removal match: %m");
1389 r = sd_bus_message_new_method_call(bus,
1391 "org.freedesktop.machine1",
1392 "/org/freedesktop/machine1",
1393 "org.freedesktop.machine1.Manager",
1394 "OpenMachineLogin");
1396 return bus_log_create_error(r);
1398 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1400 return bus_log_create_error(r);
1402 r = sd_bus_message_append(m, "s", argv[1]);
1404 return bus_log_create_error(r);
1406 r = sd_bus_call(bus, m, 0, &error, &reply);
1408 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1412 r = sd_bus_message_read(reply, "hs", &master, &pty);
1414 return bus_log_parse_error(r);
1416 assert_se(sigemptyset(&mask) == 0);
1417 sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
1418 assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
1420 log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
1422 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1423 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1425 r = pty_forward_new(event, master, true, &forward);
1427 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1429 r = sd_event_loop(event);
1431 return log_error_errno(r, "Failed to run event loop: %m");
1433 pty_forward_get_last_char(forward, &last_char);
1434 machine_died = pty_forward_get_ignore_vhangup(forward) == 0;
1436 forward = pty_forward_free(forward);
1438 if (last_char != '\n')
1439 fputc('\n', stdout);
1442 log_info("Machine %s terminated.", argv[1]);
1444 log_info("Connection to machine %s terminated.", argv[1]);
1446 sd_event_get_exit_code(event, &ret);
1450 static int remove_image(int argc, char *argv[], void *userdata) {
1451 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1452 sd_bus *bus = userdata;
1457 polkit_agent_open_if_enabled();
1459 for (i = 1; i < argc; i++) {
1460 r = sd_bus_call_method(
1462 "org.freedesktop.machine1",
1463 "/org/freedesktop/machine1",
1464 "org.freedesktop.machine1.Manager",
1470 log_error("Could not remove image: %s", bus_error_message(&error, -r));
1478 static int rename_image(int argc, char *argv[], void *userdata) {
1479 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1480 sd_bus *bus = userdata;
1483 polkit_agent_open_if_enabled();
1485 r = sd_bus_call_method(
1487 "org.freedesktop.machine1",
1488 "/org/freedesktop/machine1",
1489 "org.freedesktop.machine1.Manager",
1493 "ss", argv[1], argv[2]);
1495 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1502 static int clone_image(int argc, char *argv[], void *userdata) {
1503 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1504 sd_bus *bus = userdata;
1507 polkit_agent_open_if_enabled();
1509 r = sd_bus_call_method(
1511 "org.freedesktop.machine1",
1512 "/org/freedesktop/machine1",
1513 "org.freedesktop.machine1.Manager",
1517 "ssb", argv[1], argv[2], arg_read_only);
1519 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1526 static int read_only_image(int argc, char *argv[], void *userdata) {
1527 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1528 sd_bus *bus = userdata;
1532 b = parse_boolean(argv[2]);
1534 log_error("Failed to parse boolean argument: %s", argv[2]);
1539 polkit_agent_open_if_enabled();
1541 r = sd_bus_call_method(
1543 "org.freedesktop.machine1",
1544 "/org/freedesktop/machine1",
1545 "org.freedesktop.machine1.Manager",
1546 "MarkImageReadOnly",
1551 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1558 static int start_machine(int argc, char *argv[], void *userdata) {
1559 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1560 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1561 sd_bus *bus = userdata;
1566 polkit_agent_open_if_enabled();
1568 r = bus_wait_for_jobs_new(bus, &w);
1572 for (i = 1; i < argc; i++) {
1573 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1574 _cleanup_free_ char *e = NULL, *unit = NULL;
1577 if (!machine_name_is_valid(argv[i])) {
1578 log_error("Invalid machine name %s.", argv[i]);
1582 e = unit_name_escape(argv[i]);
1586 unit = unit_name_build("systemd-nspawn", e, ".service");
1590 r = sd_bus_message_new_method_call(
1593 "org.freedesktop.systemd1",
1594 "/org/freedesktop/systemd1",
1595 "org.freedesktop.systemd1.Manager",
1598 return bus_log_create_error(r);
1600 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1602 return bus_log_create_error(r);
1604 r = sd_bus_message_append(m, "ss", unit, "fail");
1606 return bus_log_create_error(r);
1608 r = sd_bus_call(bus, m, 0, &error, &reply);
1610 log_error("Failed to start unit: %s", bus_error_message(&error, -r));
1614 r = sd_bus_message_read(reply, "o", &object);
1616 return bus_log_parse_error(r);
1618 r = bus_wait_for_jobs_add(w, object);
1623 r = bus_wait_for_jobs(w, arg_quiet);
1630 static int enable_machine(int argc, char *argv[], void *userdata) {
1631 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1632 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1633 int carries_install_info = 0;
1634 const char *method = NULL;
1635 sd_bus *bus = userdata;
1640 polkit_agent_open_if_enabled();
1642 method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
1644 r = sd_bus_message_new_method_call(
1647 "org.freedesktop.systemd1",
1648 "/org/freedesktop/systemd1",
1649 "org.freedesktop.systemd1.Manager",
1652 return bus_log_create_error(r);
1654 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1656 return bus_log_create_error(r);
1658 r = sd_bus_message_open_container(m, 'a', "s");
1660 return bus_log_create_error(r);
1662 for (i = 1; i < argc; i++) {
1663 _cleanup_free_ char *e = NULL, *unit = NULL;
1665 if (!machine_name_is_valid(argv[i])) {
1666 log_error("Invalid machine name %s.", argv[i]);
1670 e = unit_name_escape(argv[i]);
1674 unit = unit_name_build("systemd-nspawn", e, ".service");
1678 r = sd_bus_message_append(m, "s", unit);
1680 return bus_log_create_error(r);
1683 r = sd_bus_message_close_container(m);
1685 return bus_log_create_error(r);
1687 if (streq(argv[0], "enable"))
1688 r = sd_bus_message_append(m, "bb", false, false);
1690 r = sd_bus_message_append(m, "b", false);
1692 return bus_log_create_error(r);
1694 r = sd_bus_call(bus, m, 0, &error, &reply);
1696 log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
1700 if (streq(argv[0], "enable")) {
1701 r = sd_bus_message_read(reply, "b", carries_install_info);
1703 return bus_log_parse_error(r);
1706 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1710 m = sd_bus_message_unref(m);
1712 r = sd_bus_message_new_method_call(
1715 "org.freedesktop.systemd1",
1716 "/org/freedesktop/systemd1",
1717 "org.freedesktop.systemd1.Manager",
1720 return bus_log_create_error(r);
1722 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1724 return bus_log_create_error(r);
1726 r = sd_bus_call(bus, m, 0, &error, NULL);
1728 log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
1735 static int help(int argc, char *argv[], void *userdata) {
1737 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1738 "Send control commands to or query the virtual machine and container\n"
1739 "registration manager.\n\n"
1740 " -h --help Show this help\n"
1741 " --version Show package version\n"
1742 " --no-pager Do not pipe output into a pager\n"
1743 " --no-legend Do not show the headers and footers\n"
1744 " --no-ask-password Do not ask for system passwords\n"
1745 " -H --host=[USER@]HOST Operate on remote host\n"
1746 " -M --machine=CONTAINER Operate on local container\n"
1747 " -p --property=NAME Show only properties by this name\n"
1748 " -q --quiet Suppress output\n"
1749 " -a --all Show all properties, including empty ones\n"
1750 " -l --full Do not ellipsize output\n"
1751 " --kill-who=WHO Who to send signal to\n"
1752 " -s --signal=SIGNAL Which signal to send\n"
1753 " --read-only Create read-only bind mount\n"
1754 " --mkdir Create directory before bind mounting, if missing\n"
1755 " -n --lines=INTEGER Number of journal entries to show\n"
1756 " -o --output=STRING Change journal output mode (short,\n"
1757 " short-monotonic, verbose, export, json,\n"
1758 " json-pretty, json-sse, cat)\n\n"
1759 "Machine Commands:\n"
1760 " list List running VMs and containers\n"
1761 " status NAME... Show VM/container details\n"
1762 " show NAME... Show properties of one or more VMs/containers\n"
1763 " start NAME... Start container as a service\n"
1764 " login NAME Get a login prompt on a container\n"
1765 " enable NAME... Enable automatic container start at boot\n"
1766 " disable NAME... Disable automatic container start at boot\n"
1767 " poweroff NAME... Power off one or more containers\n"
1768 " reboot NAME... Reboot one or more containers\n"
1769 " terminate NAME... Terminate one or more VMs/containers\n"
1770 " kill NAME... Send signal to processes of a VM/container\n"
1771 " copy-to NAME PATH [PATH] Copy files from the host to a container\n"
1772 " copy-from NAME PATH [PATH] Copy files from a container to the host\n"
1773 " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
1775 " list-images Show available images\n"
1776 " image-status NAME... Show image details\n"
1777 " show-image NAME... Show properties of image\n"
1778 " clone NAME NAME Clone an image\n"
1779 " rename NAME NAME Rename an image\n"
1780 " read-only NAME [BOOL] Mark or unmark image read-only\n"
1781 " remove NAME... Remove an image\n"
1782 , program_invocation_short_name);
1787 static int parse_argv(int argc, char *argv[]) {
1790 ARG_VERSION = 0x100,
1796 ARG_NO_ASK_PASSWORD,
1799 static const struct option options[] = {
1800 { "help", no_argument, NULL, 'h' },
1801 { "version", no_argument, NULL, ARG_VERSION },
1802 { "property", required_argument, NULL, 'p' },
1803 { "all", no_argument, NULL, 'a' },
1804 { "full", no_argument, NULL, 'l' },
1805 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1806 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1807 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1808 { "signal", required_argument, NULL, 's' },
1809 { "host", required_argument, NULL, 'H' },
1810 { "machine", required_argument, NULL, 'M' },
1811 { "read-only", no_argument, NULL, ARG_READ_ONLY },
1812 { "mkdir", no_argument, NULL, ARG_MKDIR },
1813 { "quiet", no_argument, NULL, 'q' },
1814 { "lines", required_argument, NULL, 'n' },
1815 { "output", required_argument, NULL, 'o' },
1816 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1825 while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
1830 return help(0, NULL, NULL);
1833 puts(PACKAGE_STRING);
1834 puts(SYSTEMD_FEATURES);
1838 r = strv_extend(&arg_property, optarg);
1842 /* If the user asked for a particular
1843 * property, show it to him, even if it is
1857 if (safe_atou(optarg, &arg_lines) < 0) {
1858 log_error("Failed to parse lines '%s'", optarg);
1864 arg_output = output_mode_from_string(optarg);
1865 if (arg_output < 0) {
1866 log_error("Unknown output '%s'.", optarg);
1872 arg_no_pager = true;
1880 arg_kill_who = optarg;
1884 arg_signal = signal_from_string_try_harder(optarg);
1885 if (arg_signal < 0) {
1886 log_error("Failed to parse signal string %s.", optarg);
1891 case ARG_NO_ASK_PASSWORD:
1892 arg_ask_password = false;
1896 arg_transport = BUS_TRANSPORT_REMOTE;
1901 arg_transport = BUS_TRANSPORT_MACHINE;
1906 arg_read_only = true;
1921 assert_not_reached("Unhandled option");
1927 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
1929 static const Verb verbs[] = {
1930 { "help", VERB_ANY, VERB_ANY, 0, help },
1931 { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
1932 { "list-images", VERB_ANY, 1, 0, list_images },
1933 { "status", 2, VERB_ANY, 0, show_machine },
1934 { "image-status",2, VERB_ANY, 0, show_image },
1935 { "show", VERB_ANY, VERB_ANY, 0, show_machine },
1936 { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
1937 { "terminate", 2, VERB_ANY, 0, terminate_machine },
1938 { "reboot", 2, VERB_ANY, 0, reboot_machine },
1939 { "poweroff", 2, VERB_ANY, 0, poweroff_machine },
1940 { "kill", 2, VERB_ANY, 0, kill_machine },
1941 { "login", 2, 2, 0, login_machine },
1942 { "bind", 3, 4, 0, bind_mount },
1943 { "copy-to", 3, 4, 0, copy_files },
1944 { "copy-from", 3, 4, 0, copy_files },
1945 { "remove", 2, VERB_ANY, 0, remove_image },
1946 { "rename", 3, 3, 0, rename_image },
1947 { "clone", 3, 3, 0, clone_image },
1948 { "read-only", 2, 3, 0, read_only_image },
1949 { "start", 2, VERB_ANY, 0, start_machine },
1950 { "enable", 2, VERB_ANY, 0, enable_machine },
1951 { "disable", 2, VERB_ANY, 0, enable_machine },
1955 return dispatch_verb(argc, argv, verbs, bus);
1958 int main(int argc, char*argv[]) {
1959 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1962 setlocale(LC_ALL, "");
1963 log_parse_environment();
1966 r = parse_argv(argc, argv);
1970 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1972 log_error_errno(r, "Failed to create bus connection: %m");
1976 r = machinectl_main(argc, argv, bus);
1980 polkit_agent_close();
1982 strv_free(arg_property);
1984 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;