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) {
75 /* Cache result before we open the pager */
82 static void polkit_agent_open_if_enabled(void) {
84 /* Open the polkit agent as a child process if necessary */
86 if (!arg_ask_password)
89 if (arg_transport != BUS_TRANSPORT_LOCAL)
95 static OutputFlags get_output_flags(void) {
97 arg_all * OUTPUT_SHOW_ALL |
98 arg_full * OUTPUT_FULL_WIDTH |
99 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
100 on_tty() * OUTPUT_COLOR |
101 !arg_quiet * OUTPUT_WARN_CUTOFF;
104 typedef struct MachineInfo {
110 static int compare_machine_info(const void *a, const void *b) {
111 const MachineInfo *x = a, *y = b;
113 return strcmp(x->name, y->name);
116 static int list_machines(int argc, char *argv[], void *userdata) {
118 size_t max_name = strlen("MACHINE"), max_class = strlen("CLASS"), max_service = strlen("SERVICE");
119 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
120 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
121 _cleanup_free_ MachineInfo *machines = NULL;
122 const char *name, *class, *service, *object;
123 size_t n_machines = 0, n_allocated = 0, j;
124 sd_bus *bus = userdata;
129 pager_open_if_enabled();
131 r = sd_bus_call_method(
133 "org.freedesktop.machine1",
134 "/org/freedesktop/machine1",
135 "org.freedesktop.machine1.Manager",
141 log_error("Could not get machines: %s", bus_error_message(&error, -r));
145 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
147 return bus_log_parse_error(r);
149 while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
152 if (!GREEDY_REALLOC(machines, n_allocated, n_machines + 1))
155 machines[n_machines].name = name;
156 machines[n_machines].class = class;
157 machines[n_machines].service = service;
174 return bus_log_parse_error(r);
176 r = sd_bus_message_exit_container(reply);
178 return bus_log_parse_error(r);
180 qsort_safe(machines, n_machines, sizeof(MachineInfo), compare_machine_info);
183 printf("%-*s %-*s %-*s\n",
184 (int) max_name, "MACHINE",
185 (int) max_class, "CLASS",
186 (int) max_service, "SERVICE");
188 for (j = 0; j < n_machines; j++)
189 printf("%-*s %-*s %-*s\n",
190 (int) max_name, machines[j].name,
191 (int) max_class, machines[j].class,
192 (int) max_service, machines[j].service);
195 printf("\n%zu machines listed.\n", n_machines);
200 typedef struct ImageInfo {
209 static int compare_image_info(const void *a, const void *b) {
210 const ImageInfo *x = a, *y = b;
212 return strcmp(x->name, y->name);
215 static int list_images(int argc, char *argv[], void *userdata) {
217 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
218 size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("SIZE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
219 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
220 _cleanup_free_ ImageInfo *images = NULL;
221 size_t n_images = 0, n_allocated = 0, j;
222 const char *name, *type, *object;
223 sd_bus *bus = userdata;
224 uint64_t crtime, mtime, size;
229 pager_open_if_enabled();
231 r = sd_bus_call_method(
233 "org.freedesktop.machine1",
234 "/org/freedesktop/machine1",
235 "org.freedesktop.machine1.Manager",
241 log_error("Could not get images: %s", bus_error_message(&error, -r));
245 r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
247 return bus_log_parse_error(r);
249 while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
250 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
253 if (name[0] == '.' && !arg_all)
256 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
259 images[n_images].name = name;
260 images[n_images].type = type;
261 images[n_images].read_only = read_only;
262 images[n_images].crtime = crtime;
263 images[n_images].mtime = mtime;
264 images[n_images].size = size;
275 l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
281 l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
286 if (size != (uint64_t) -1) {
287 l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
295 return bus_log_parse_error(r);
297 r = sd_bus_message_exit_container(reply);
299 return bus_log_parse_error(r);
301 qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
304 printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
305 (int) max_name, "NAME",
306 (int) max_type, "TYPE",
308 (int) max_size, "SIZE",
309 (int) max_crtime, "CREATED",
310 (int) max_mtime, "MODIFIED");
312 for (j = 0; j < n_images; j++) {
313 char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
315 printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
316 (int) max_name, images[j].name,
317 (int) max_type, images[j].type,
318 images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
319 (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
320 (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
321 (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
325 printf("\n%zu images listed.\n", n_images);
330 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
331 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
332 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
333 _cleanup_free_ char *path = NULL;
341 if (arg_transport == BUS_TRANSPORT_REMOTE)
344 path = unit_dbus_path_from_name(unit);
348 r = sd_bus_get_property(
350 "org.freedesktop.systemd1",
352 endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
358 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
362 r = sd_bus_message_read(reply, "s", &cgroup);
364 return bus_log_parse_error(r);
369 if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
378 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t ", c, false, &leader, leader > 0, get_output_flags());
382 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
383 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
391 r = sd_bus_call_method(bus,
392 "org.freedesktop.machine1",
393 "/org/freedesktop/machine1",
394 "org.freedesktop.machine1.Manager",
395 "GetMachineAddresses",
402 r = sd_bus_message_enter_container(reply, 'a', "(iay)");
404 return bus_log_parse_error(r);
406 while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
410 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
412 r = sd_bus_message_read(reply, "i", &family);
414 return bus_log_parse_error(r);
416 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
418 return bus_log_parse_error(r);
420 fputs(prefix, stdout);
421 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
422 if (family == AF_INET6 && ifi > 0)
426 r = sd_bus_message_exit_container(reply);
428 return bus_log_parse_error(r);
430 if (prefix != prefix2)
434 return bus_log_parse_error(r);
436 r = sd_bus_message_exit_container(reply);
438 return bus_log_parse_error(r);
443 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
444 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
445 const char *k, *v, *pretty = NULL;
452 r = sd_bus_call_method(bus,
453 "org.freedesktop.machine1",
454 "/org/freedesktop/machine1",
455 "org.freedesktop.machine1.Manager",
456 "GetMachineOSRelease",
463 r = sd_bus_message_enter_container(reply, 'a', "{ss}");
465 return bus_log_parse_error(r);
467 while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
468 if (streq(k, "PRETTY_NAME"))
473 return bus_log_parse_error(r);
475 r = sd_bus_message_exit_container(reply);
477 return bus_log_parse_error(r);
480 printf("%s%s\n", prefix, pretty);
485 typedef struct MachineStatusInfo {
491 char *root_directory;
493 struct dual_timestamp timestamp;
498 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
499 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
500 char since2[FORMAT_TIMESTAMP_MAX], *s2;
506 fputs(strna(i->name), stdout);
508 if (!sd_id128_equal(i->id, SD_ID128_NULL))
509 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
513 s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp.realtime);
514 s2 = format_timestamp(since2, sizeof(since2), i->timestamp.realtime);
517 printf("\t Since: %s; %s\n", s2, s1);
519 printf("\t Since: %s\n", s2);
522 _cleanup_free_ char *t = NULL;
524 printf("\t Leader: %u", (unsigned) i->leader);
526 get_process_comm(i->leader, &t);
534 printf("\t Service: %s", i->service);
537 printf("; class %s", i->class);
541 printf("\t Class: %s\n", i->class);
543 if (i->root_directory)
544 printf("\t Root: %s\n", i->root_directory);
546 if (i->n_netif > 0) {
549 fputs("\t Iface:", stdout);
551 for (c = 0; c < i->n_netif; c++) {
552 char name[IF_NAMESIZE+1] = "";
554 if (if_indextoname(i->netif[c], name)) {
563 printf(" %i", i->netif[c]);
569 print_addresses(bus, i->name, ifi,
573 print_os_release(bus, i->name, "\t OS: ");
576 printf("\t Unit: %s\n", i->unit);
577 show_unit_cgroup(bus, i->unit, i->leader);
579 if (arg_transport == BUS_TRANSPORT_LOCAL) {
581 show_journal_by_unit(
586 i->timestamp.monotonic,
589 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
590 SD_JOURNAL_LOCAL_ONLY,
597 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
598 MachineStatusInfo *i = userdata;
603 assert_cc(sizeof(int32_t) == sizeof(int));
604 r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
610 i->n_netif = l / sizeof(int32_t);
611 i->netif = memdup(v, l);
618 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
620 static const struct bus_properties_map map[] = {
621 { "Name", "s", NULL, offsetof(MachineStatusInfo, name) },
622 { "Class", "s", NULL, offsetof(MachineStatusInfo, class) },
623 { "Service", "s", NULL, offsetof(MachineStatusInfo, service) },
624 { "Unit", "s", NULL, offsetof(MachineStatusInfo, unit) },
625 { "RootDirectory", "s", NULL, offsetof(MachineStatusInfo, root_directory) },
626 { "Leader", "u", NULL, offsetof(MachineStatusInfo, leader) },
627 { "Timestamp", "t", NULL, offsetof(MachineStatusInfo, timestamp.realtime) },
628 { "TimestampMonotonic", "t", NULL, offsetof(MachineStatusInfo, timestamp.monotonic) },
629 { "Id", "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
630 { "NetworkInterfaces", "ai", map_netif, 0 },
634 MachineStatusInfo info = {};
642 r = bus_map_all_properties(bus,
643 "org.freedesktop.machine1",
648 return log_error_errno(r, "Could not get properties: %m");
654 print_machine_status_info(bus, &info);
660 free(info.root_directory);
666 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
678 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
680 log_error_errno(r, "Could not get properties: %m");
685 static int show_machine(int argc, char *argv[], void *userdata) {
687 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
688 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
689 bool properties, new_line = false;
690 sd_bus *bus = userdata;
695 properties = !strstr(argv[0], "status");
697 pager_open_if_enabled();
699 if (properties && argc <= 1) {
701 /* If no argument is specified, inspect the manager
703 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
708 for (i = 1; i < argc; i++) {
709 const char *path = NULL;
711 r = sd_bus_call_method(
713 "org.freedesktop.machine1",
714 "/org/freedesktop/machine1",
715 "org.freedesktop.machine1.Manager",
721 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
725 r = sd_bus_message_read(reply, "o", &path);
727 return bus_log_parse_error(r);
730 r = show_machine_properties(bus, path, &new_line);
732 r = show_machine_info(argv[0], bus, path, &new_line);
738 typedef struct ImageStatusInfo {
747 uint64_t size_exclusive;
748 uint64_t limit_exclusive;
751 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
752 char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
753 char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
754 char bs[FORMAT_BYTES_MAX], *s3;
755 char bs_exclusive[FORMAT_BYTES_MAX], *s4;
761 fputs(i->name, stdout);
766 printf("\t Type: %s\n", i->type);
769 printf("\t Path: %s\n", i->path);
771 printf("\t RO: %s%s%s\n",
772 i->read_only ? ansi_highlight_red() : "",
773 i->read_only ? "read-only" : "writable",
774 i->read_only ? ansi_highlight_off() : "");
776 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
777 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
779 printf("\t Created: %s; %s\n", s2, s1);
781 printf("\t Created: %s\n", s2);
783 s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
784 s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
786 printf("\tModified: %s; %s\n", s2, s1);
788 printf("\tModified: %s\n", s2);
790 s3 = format_bytes(bs, sizeof(bs), i->size);
791 s4 = i->size_exclusive != i->size ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->size_exclusive) : NULL;
793 printf("\t Size: %s (exclusive: %s)\n", s3, s4);
795 printf("\t Size: %s\n", s3);
797 s3 = format_bytes(bs, sizeof(bs), i->limit);
798 s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
800 printf("\t Limit: %s (exclusive: %s)\n", s3, s4);
802 printf("\t Limit: %s\n", s3);
805 static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
807 static const struct bus_properties_map map[] = {
808 { "Name", "s", NULL, offsetof(ImageStatusInfo, name) },
809 { "Path", "s", NULL, offsetof(ImageStatusInfo, path) },
810 { "Type", "s", NULL, offsetof(ImageStatusInfo, type) },
811 { "ReadOnly", "b", NULL, offsetof(ImageStatusInfo, read_only) },
812 { "CreationTimestamp", "t", NULL, offsetof(ImageStatusInfo, crtime) },
813 { "ModificationTimestamp", "t", NULL, offsetof(ImageStatusInfo, mtime) },
814 { "Size", "t", NULL, offsetof(ImageStatusInfo, size) },
815 { "Limit", "t", NULL, offsetof(ImageStatusInfo, limit) },
816 { "SizeExclusive", "t", NULL, offsetof(ImageStatusInfo, size_exclusive) },
817 { "LimitExclusive", "t", NULL, offsetof(ImageStatusInfo, limit_exclusive) },
821 ImageStatusInfo info = {};
829 r = bus_map_all_properties(bus,
830 "org.freedesktop.machine1",
835 return log_error_errno(r, "Could not get properties: %m");
841 print_image_status_info(bus, &info);
850 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
862 r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
864 log_error_errno(r, "Could not get properties: %m");
869 static int show_image(int argc, char *argv[], void *userdata) {
871 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
872 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
873 bool properties, new_line = false;
874 sd_bus *bus = userdata;
879 properties = !strstr(argv[0], "status");
881 pager_open_if_enabled();
883 if (properties && argc <= 1) {
885 /* If no argument is specified, inspect the manager
887 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
892 for (i = 1; i < argc; i++) {
893 const char *path = NULL;
895 r = sd_bus_call_method(
897 "org.freedesktop.machine1",
898 "/org/freedesktop/machine1",
899 "org.freedesktop.machine1.Manager",
905 log_error("Could not get path to image: %s", bus_error_message(&error, -r));
909 r = sd_bus_message_read(reply, "o", &path);
911 return bus_log_parse_error(r);
914 r = show_image_properties(bus, path, &new_line);
916 r = show_image_info(argv[0], bus, path, &new_line);
922 static int kill_machine(int argc, char *argv[], void *userdata) {
923 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
924 sd_bus *bus = userdata;
929 polkit_agent_open_if_enabled();
932 arg_kill_who = "all";
934 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++) {
981 r = sd_bus_call_method(
983 "org.freedesktop.machine1",
984 "/org/freedesktop/machine1",
985 "org.freedesktop.machine1.Manager",
991 log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
999 static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
1000 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1001 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL;
1010 r = sd_bus_call_method(
1012 "org.freedesktop.machine1",
1013 "/org/freedesktop/machine1",
1014 "org.freedesktop.machine1.Manager",
1020 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
1024 r = sd_bus_message_read(reply, "o", &object);
1026 return bus_log_parse_error(r);
1028 r = sd_bus_get_property(
1030 "org.freedesktop.machine1",
1032 "org.freedesktop.machine1.Machine",
1038 return log_error_errno(r, "Failed to retrieve PID of leader: %m");
1040 r = sd_bus_message_read(reply2, "u", &leader);
1042 return bus_log_parse_error(r);
1048 static int copy_files(int argc, char *argv[], void *userdata) {
1049 char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
1050 _cleanup_close_ int hostfd = -1;
1051 sd_bus *bus = userdata;
1052 pid_t child, leader;
1059 copy_from = streq(argv[0], "copy-from");
1060 dest = argv[3] ?: argv[2];
1061 host_path = strdupa(copy_from ? dest : argv[2]);
1062 container_path = strdupa(copy_from ? argv[2] : dest);
1064 if (!path_is_absolute(container_path)) {
1065 log_error("Container path not absolute.");
1069 t = strdup(host_path);
1070 host_basename = basename(t);
1071 host_dirname = dirname(host_path);
1073 t = strdup(container_path);
1074 container_basename = basename(t);
1075 container_dirname = dirname(container_path);
1077 r = machine_get_leader(bus, argv[1], &leader);
1081 hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1083 return log_error_errno(errno, "Failed to open source directory: %m");
1087 return log_error_errno(errno, "Failed to fork(): %m");
1094 q = procfs_file_alloca(leader, "ns/mnt");
1095 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1097 log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1098 _exit(EXIT_FAILURE);
1101 if (setns(mntfd, CLONE_NEWNS) < 0) {
1102 log_error_errno(errno, "Failed to join namespace of leader: %m");
1103 _exit(EXIT_FAILURE);
1106 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1107 if (containerfd < 0) {
1108 log_error_errno(errno, "Failed top open destination directory: %m");
1109 _exit(EXIT_FAILURE);
1113 r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1115 r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1117 log_error_errno(errno, "Failed to copy tree: %m");
1118 _exit(EXIT_FAILURE);
1121 _exit(EXIT_SUCCESS);
1124 r = wait_for_terminate(child, &si);
1126 return log_error_errno(r, "Failed to wait for client: %m");
1127 if (si.si_code != CLD_EXITED) {
1128 log_error("Client died abnormally.");
1131 if (si.si_status != EXIT_SUCCESS)
1137 static int bind_mount(int argc, char *argv[], void *userdata) {
1138 char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
1139 sd_bus *bus = userdata;
1140 pid_t child, leader;
1143 bool mount_slave_created = false, mount_slave_mounted = false,
1144 mount_tmp_created = false, mount_tmp_mounted = false,
1145 mount_outside_created = false, mount_outside_mounted = false;
1150 /* One day, when bind mounting /proc/self/fd/n works across
1151 * namespace boundaries we should rework this logic to make
1154 dest = argv[3] ?: argv[2];
1155 if (!path_is_absolute(dest)) {
1156 log_error("Destination path not absolute.");
1160 p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/");
1161 if (access(p, F_OK) < 0) {
1162 log_error("Container does not allow propagation of mount points.");
1166 r = machine_get_leader(bus, argv[1], &leader);
1170 /* Our goal is to install a new bind mount into the container,
1171 possibly read-only. This is irritatingly complex
1172 unfortunately, currently.
1174 First, we start by creating a private playground in /tmp,
1175 that we can mount MS_SLAVE. (Which is necessary, since
1176 MS_MOUNT cannot be applied to mounts with MS_SHARED parent
1179 if (!mkdtemp(mount_slave))
1180 return log_error_errno(errno, "Failed to create playground: %m");
1182 mount_slave_created = true;
1184 if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
1185 r = log_error_errno(errno, "Failed to make bind mount: %m");
1189 mount_slave_mounted = true;
1191 if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
1192 r = log_error_errno(errno, "Failed to remount slave: %m");
1196 /* Second, we mount the source directory to a directory inside
1197 of our MS_SLAVE playground. */
1198 mount_tmp = strappenda(mount_slave, "/mount");
1199 if (mkdir(mount_tmp, 0700) < 0) {
1200 r = log_error_errno(errno, "Failed to create temporary mount: %m");
1204 mount_tmp_created = true;
1206 if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
1207 r = log_error_errno(errno, "Failed to overmount: %m");
1211 mount_tmp_mounted = true;
1213 /* Third, we remount the new bind mount read-only if requested. */
1215 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
1216 r = log_error_errno(errno, "Failed to mark read-only: %m");
1220 /* Fourth, we move the new bind mount into the propagation
1221 * directory. This way it will appear there read-only
1224 mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
1225 if (!mkdtemp(mount_outside)) {
1226 r = log_error_errno(errno, "Cannot create propagation directory: %m");
1230 mount_outside_created = true;
1232 if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
1233 r = log_error_errno(errno, "Failed to move: %m");
1237 mount_outside_mounted = true;
1238 mount_tmp_mounted = false;
1240 (void) rmdir(mount_tmp);
1241 mount_tmp_created = false;
1243 (void) umount(mount_slave);
1244 mount_slave_mounted = false;
1246 (void) rmdir(mount_slave);
1247 mount_slave_created = false;
1251 r = log_error_errno(errno, "Failed to fork(): %m");
1256 const char *mount_inside;
1260 q = procfs_file_alloca(leader, "ns/mnt");
1261 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1263 log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1264 _exit(EXIT_FAILURE);
1267 if (setns(mntfd, CLONE_NEWNS) < 0) {
1268 log_error_errno(errno, "Failed to join namespace of leader: %m");
1269 _exit(EXIT_FAILURE);
1273 mkdir_p(dest, 0755);
1275 /* Fifth, move the mount to the right place inside */
1276 mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside));
1277 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1278 log_error_errno(errno, "Failed to mount: %m");
1279 _exit(EXIT_FAILURE);
1282 _exit(EXIT_SUCCESS);
1285 r = wait_for_terminate(child, &si);
1287 log_error_errno(r, "Failed to wait for client: %m");
1290 if (si.si_code != CLD_EXITED) {
1291 log_error("Client died abnormally.");
1295 if (si.si_status != EXIT_SUCCESS) {
1303 if (mount_outside_mounted)
1304 umount(mount_outside);
1305 if (mount_outside_created)
1306 rmdir(mount_outside);
1308 if (mount_tmp_mounted)
1310 if (mount_tmp_created)
1313 if (mount_slave_mounted)
1314 umount(mount_slave);
1315 if (mount_slave_created)
1316 umount(mount_slave);
1321 static int on_machine_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *ret_error) {
1322 PTYForward ** forward = (PTYForward**) userdata;
1330 /* If the forwarder is already initialized, tell it to
1331 * exit on the next vhangup(), so that we still flush
1332 * out what might be queued and exit then. */
1334 r = pty_forward_set_ignore_vhangup(*forward, false);
1338 log_error_errno(r, "Failed to set ignore_vhangup flag: %m");
1341 /* On error, or when the forwarder is not initialized yet, quit immediately */
1342 sd_event_exit(sd_bus_get_event(bus), EXIT_FAILURE);
1346 static int login_machine(int argc, char *argv[], void *userdata) {
1347 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1348 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1349 _cleanup_bus_slot_unref_ sd_bus_slot *slot = NULL;
1350 _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1351 _cleanup_event_unref_ sd_event *event = NULL;
1352 int master = -1, r, ret = 0;
1353 sd_bus *bus = userdata;
1354 const char *pty, *match;
1361 if (arg_transport != BUS_TRANSPORT_LOCAL &&
1362 arg_transport != BUS_TRANSPORT_MACHINE) {
1363 log_error("Login only supported on local machines.");
1367 polkit_agent_open_if_enabled();
1369 r = sd_event_default(&event);
1371 return log_error_errno(r, "Failed to get event loop: %m");
1373 r = sd_bus_attach_event(bus, event, 0);
1375 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1377 match = strappenda("type='signal',"
1378 "sender='org.freedesktop.machine1',"
1379 "path='/org/freedesktop/machine1',",
1380 "interface='org.freedesktop.machine1.Manager',"
1381 "member='MachineRemoved',"
1386 r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
1388 return log_error_errno(r, "Failed to add machine removal match: %m");
1390 r = sd_bus_message_new_method_call(bus,
1392 "org.freedesktop.machine1",
1393 "/org/freedesktop/machine1",
1394 "org.freedesktop.machine1.Manager",
1395 "OpenMachineLogin");
1397 return bus_log_create_error(r);
1399 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1401 return bus_log_create_error(r);
1403 r = sd_bus_message_append(m, "s", argv[1]);
1405 return bus_log_create_error(r);
1407 r = sd_bus_call(bus, m, 0, &error, &reply);
1409 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1413 r = sd_bus_message_read(reply, "hs", &master, &pty);
1415 return bus_log_parse_error(r);
1417 assert_se(sigemptyset(&mask) == 0);
1418 sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
1419 assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
1421 log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
1423 sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1424 sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1426 r = pty_forward_new(event, master, true, &forward);
1428 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1430 r = sd_event_loop(event);
1432 return log_error_errno(r, "Failed to run event loop: %m");
1434 pty_forward_get_last_char(forward, &last_char);
1435 machine_died = pty_forward_get_ignore_vhangup(forward) == 0;
1437 forward = pty_forward_free(forward);
1439 if (last_char != '\n')
1440 fputc('\n', stdout);
1443 log_info("Machine %s terminated.", argv[1]);
1445 log_info("Connection to machine %s terminated.", argv[1]);
1447 sd_event_get_exit_code(event, &ret);
1451 static int remove_image(int argc, char *argv[], void *userdata) {
1452 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1453 sd_bus *bus = userdata;
1458 polkit_agent_open_if_enabled();
1460 for (i = 1; i < argc; i++) {
1461 r = sd_bus_call_method(
1463 "org.freedesktop.machine1",
1464 "/org/freedesktop/machine1",
1465 "org.freedesktop.machine1.Manager",
1471 log_error("Could not remove image: %s", bus_error_message(&error, -r));
1479 static int rename_image(int argc, char *argv[], void *userdata) {
1480 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1481 sd_bus *bus = userdata;
1484 polkit_agent_open_if_enabled();
1486 r = sd_bus_call_method(
1488 "org.freedesktop.machine1",
1489 "/org/freedesktop/machine1",
1490 "org.freedesktop.machine1.Manager",
1494 "ss", argv[1], argv[2]);
1496 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1503 static int clone_image(int argc, char *argv[], void *userdata) {
1504 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1505 sd_bus *bus = userdata;
1508 polkit_agent_open_if_enabled();
1510 r = sd_bus_call_method(
1512 "org.freedesktop.machine1",
1513 "/org/freedesktop/machine1",
1514 "org.freedesktop.machine1.Manager",
1518 "ssb", argv[1], argv[2], arg_read_only);
1520 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1527 static int read_only_image(int argc, char *argv[], void *userdata) {
1528 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1529 sd_bus *bus = userdata;
1533 b = parse_boolean(argv[2]);
1535 log_error("Failed to parse boolean argument: %s", argv[2]);
1540 polkit_agent_open_if_enabled();
1542 r = sd_bus_call_method(
1544 "org.freedesktop.machine1",
1545 "/org/freedesktop/machine1",
1546 "org.freedesktop.machine1.Manager",
1547 "MarkImageReadOnly",
1552 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1559 static int start_machine(int argc, char *argv[], void *userdata) {
1560 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1561 _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1562 sd_bus *bus = userdata;
1567 polkit_agent_open_if_enabled();
1569 r = bus_wait_for_jobs_new(bus, &w);
1573 for (i = 1; i < argc; i++) {
1574 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1575 _cleanup_free_ char *e = NULL, *unit = NULL;
1578 if (!machine_name_is_valid(argv[i])) {
1579 log_error("Invalid machine name %s.", argv[i]);
1583 e = unit_name_escape(argv[i]);
1587 unit = unit_name_build("systemd-nspawn", e, ".service");
1591 r = sd_bus_message_new_method_call(
1594 "org.freedesktop.systemd1",
1595 "/org/freedesktop/systemd1",
1596 "org.freedesktop.systemd1.Manager",
1599 return bus_log_create_error(r);
1601 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1603 return bus_log_create_error(r);
1605 r = sd_bus_message_append(m, "ss", unit, "fail");
1607 return bus_log_create_error(r);
1609 r = sd_bus_call(bus, m, 0, &error, &reply);
1611 log_error("Failed to start unit: %s", bus_error_message(&error, -r));
1615 r = sd_bus_message_read(reply, "o", &object);
1617 return bus_log_parse_error(r);
1619 r = bus_wait_for_jobs_add(w, object);
1624 r = bus_wait_for_jobs(w, arg_quiet);
1631 static int enable_machine(int argc, char *argv[], void *userdata) {
1632 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1633 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1634 int carries_install_info = 0;
1635 const char *method = NULL;
1636 sd_bus *bus = userdata;
1641 polkit_agent_open_if_enabled();
1643 method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
1645 r = sd_bus_message_new_method_call(
1648 "org.freedesktop.systemd1",
1649 "/org/freedesktop/systemd1",
1650 "org.freedesktop.systemd1.Manager",
1653 return bus_log_create_error(r);
1655 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1657 return bus_log_create_error(r);
1659 r = sd_bus_message_open_container(m, 'a', "s");
1661 return bus_log_create_error(r);
1663 for (i = 1; i < argc; i++) {
1664 _cleanup_free_ char *e = NULL, *unit = NULL;
1666 if (!machine_name_is_valid(argv[i])) {
1667 log_error("Invalid machine name %s.", argv[i]);
1671 e = unit_name_escape(argv[i]);
1675 unit = unit_name_build("systemd-nspawn", e, ".service");
1679 r = sd_bus_message_append(m, "s", unit);
1681 return bus_log_create_error(r);
1684 r = sd_bus_message_close_container(m);
1686 return bus_log_create_error(r);
1688 if (streq(argv[0], "enable"))
1689 r = sd_bus_message_append(m, "bb", false, false);
1691 r = sd_bus_message_append(m, "b", false);
1693 return bus_log_create_error(r);
1695 r = sd_bus_call(bus, m, 0, &error, &reply);
1697 log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
1701 if (streq(argv[0], "enable")) {
1702 r = sd_bus_message_read(reply, "b", carries_install_info);
1704 return bus_log_parse_error(r);
1707 r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1711 m = sd_bus_message_unref(m);
1713 r = sd_bus_message_new_method_call(
1716 "org.freedesktop.systemd1",
1717 "/org/freedesktop/systemd1",
1718 "org.freedesktop.systemd1.Manager",
1721 return bus_log_create_error(r);
1723 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1725 return bus_log_create_error(r);
1727 r = sd_bus_call(bus, m, 0, &error, NULL);
1729 log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
1736 static int help(int argc, char *argv[], void *userdata) {
1738 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1739 "Send control commands to or query the virtual machine and container\n"
1740 "registration manager.\n\n"
1741 " -h --help Show this help\n"
1742 " --version Show package version\n"
1743 " --no-pager Do not pipe output into a pager\n"
1744 " --no-legend Do not show the headers and footers\n"
1745 " --no-ask-password Do not ask for system passwords\n"
1746 " -H --host=[USER@]HOST Operate on remote host\n"
1747 " -M --machine=CONTAINER Operate on local container\n"
1748 " -p --property=NAME Show only properties by this name\n"
1749 " -q --quiet Suppress output\n"
1750 " -a --all Show all properties, including empty ones\n"
1751 " -l --full Do not ellipsize output\n"
1752 " --kill-who=WHO Who to send signal to\n"
1753 " -s --signal=SIGNAL Which signal to send\n"
1754 " --read-only Create read-only bind mount\n"
1755 " --mkdir Create directory before bind mounting, if missing\n"
1756 " -n --lines=INTEGER Number of journal entries to show\n"
1757 " -o --output=STRING Change journal output mode (short,\n"
1758 " short-monotonic, verbose, export, json,\n"
1759 " json-pretty, json-sse, cat)\n\n"
1760 "Machine Commands:\n"
1761 " list List running VMs and containers\n"
1762 " status NAME... Show VM/container details\n"
1763 " show NAME... Show properties of one or more VMs/containers\n"
1764 " login NAME Get a login prompt on a container\n"
1765 " start NAME... Start container as a service\n"
1766 " enable NAME... Enable automatic container start at boot\n"
1767 " disable NAME... Disable automatic container start at boot\n"
1768 " poweroff NAME... Power off one or more containers\n"
1769 " reboot NAME... Reboot one or more containers\n"
1770 " terminate NAME... Terminate one or more VMs/containers\n"
1771 " kill NAME... Send signal to processes of a VM/container\n"
1772 " copy-to NAME PATH [PATH] Copy files from the host to a container\n"
1773 " copy-from NAME PATH [PATH] Copy files from a container to the host\n"
1774 " bind NAME PATH [PATH] Bind mount a path from the host into a container\n\n"
1776 " list-images Show available images\n"
1777 " image-status NAME... Show image details\n"
1778 " show-image NAME... Show properties of image\n"
1779 " clone NAME NAME Clone an image\n"
1780 " rename NAME NAME Rename an image\n"
1781 " read-only NAME [BOOL] Mark or unmark image read-only\n"
1782 " remove NAME... Remove an image\n",
1783 program_invocation_short_name);
1788 static int parse_argv(int argc, char *argv[]) {
1791 ARG_VERSION = 0x100,
1797 ARG_NO_ASK_PASSWORD,
1800 static const struct option options[] = {
1801 { "help", no_argument, NULL, 'h' },
1802 { "version", no_argument, NULL, ARG_VERSION },
1803 { "property", required_argument, NULL, 'p' },
1804 { "all", no_argument, NULL, 'a' },
1805 { "full", no_argument, NULL, 'l' },
1806 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1807 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1808 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1809 { "signal", required_argument, NULL, 's' },
1810 { "host", required_argument, NULL, 'H' },
1811 { "machine", required_argument, NULL, 'M' },
1812 { "read-only", no_argument, NULL, ARG_READ_ONLY },
1813 { "mkdir", no_argument, NULL, ARG_MKDIR },
1814 { "quiet", no_argument, NULL, 'q' },
1815 { "lines", required_argument, NULL, 'n' },
1816 { "output", required_argument, NULL, 'o' },
1817 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1826 while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
1831 return help(0, NULL, NULL);
1834 puts(PACKAGE_STRING);
1835 puts(SYSTEMD_FEATURES);
1839 r = strv_extend(&arg_property, optarg);
1843 /* If the user asked for a particular
1844 * property, show it to him, even if it is
1858 if (safe_atou(optarg, &arg_lines) < 0) {
1859 log_error("Failed to parse lines '%s'", optarg);
1865 arg_output = output_mode_from_string(optarg);
1866 if (arg_output < 0) {
1867 log_error("Unknown output '%s'.", optarg);
1873 arg_no_pager = true;
1881 arg_kill_who = optarg;
1885 arg_signal = signal_from_string_try_harder(optarg);
1886 if (arg_signal < 0) {
1887 log_error("Failed to parse signal string %s.", optarg);
1892 case ARG_NO_ASK_PASSWORD:
1893 arg_ask_password = false;
1897 arg_transport = BUS_TRANSPORT_REMOTE;
1902 arg_transport = BUS_TRANSPORT_MACHINE;
1907 arg_read_only = true;
1922 assert_not_reached("Unhandled option");
1928 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
1930 static const Verb verbs[] = {
1931 { "help", VERB_ANY, VERB_ANY, 0, help },
1932 { "list", VERB_ANY, 1, VERB_DEFAULT, list_machines },
1933 { "list-images", VERB_ANY, 1, 0, list_images },
1934 { "status", 2, VERB_ANY, 0, show_machine },
1935 { "image-status",2, VERB_ANY, 0, show_image },
1936 { "show", VERB_ANY, VERB_ANY, 0, show_machine },
1937 { "show-image", VERB_ANY, VERB_ANY, 0, show_image },
1938 { "terminate", 2, VERB_ANY, 0, terminate_machine },
1939 { "reboot", 2, VERB_ANY, 0, reboot_machine },
1940 { "poweroff", 2, VERB_ANY, 0, poweroff_machine },
1941 { "kill", 2, VERB_ANY, 0, kill_machine },
1942 { "login", 2, 2, 0, login_machine },
1943 { "bind", 3, 4, 0, bind_mount },
1944 { "copy-to", 3, 4, 0, copy_files },
1945 { "copy-from", 3, 4, 0, copy_files },
1946 { "remove", 2, VERB_ANY, 0, remove_image },
1947 { "rename", 3, 3, 0, rename_image },
1948 { "clone", 3, 3, 0, clone_image },
1949 { "read-only", 2, 3, 0, read_only_image },
1950 { "start", 2, VERB_ANY, 0, start_machine },
1951 { "enable", 2, VERB_ANY, 0, enable_machine },
1952 { "disable", 2, VERB_ANY, 0, enable_machine },
1956 return dispatch_verb(argc, argv, verbs, bus);
1959 int main(int argc, char*argv[]) {
1960 _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1963 setlocale(LC_ALL, "");
1964 log_parse_environment();
1967 r = parse_argv(argc, argv);
1971 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1973 log_error_errno(r, "Failed to create bus connection: %m");
1977 r = machinectl_main(argc, argv, bus);
1981 polkit_agent_close();
1983 strv_free(arg_property);
1985 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;