chiark / gitweb /
17fbe51f9f8486aae5375fb5487cae609c0b62c0
[elogind.git] / src / machine / machinectl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <getopt.h>
27 #include <pwd.h>
28 #include <locale.h>
29 #include <fcntl.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <net/if.h>
33 #include <sys/mount.h>
34 #include <libgen.h>
35
36 #include "sd-bus.h"
37 #include "log.h"
38 #include "util.h"
39 #include "macro.h"
40 #include "pager.h"
41 #include "bus-util.h"
42 #include "bus-error.h"
43 #include "build.h"
44 #include "strv.h"
45 #include "unit-name.h"
46 #include "cgroup-show.h"
47 #include "cgroup-util.h"
48 #include "ptyfwd.h"
49 #include "event-util.h"
50 #include "path-util.h"
51 #include "mkdir.h"
52 #include "copy.h"
53 #include "verbs.h"
54
55 static char **arg_property = NULL;
56 static bool arg_all = false;
57 static bool arg_full = false;
58 static bool arg_no_pager = false;
59 static bool arg_legend = true;
60 static const char *arg_kill_who = NULL;
61 static int arg_signal = SIGTERM;
62 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
63 static char *arg_host = NULL;
64 static bool arg_read_only = false;
65 static bool arg_mkdir = false;
66
67 static void pager_open_if_enabled(void) {
68
69         /* Cache result before we open the pager */
70         if (arg_no_pager)
71                 return;
72
73         pager_open(false);
74 }
75
76 static int list_machines(int argc, char *argv[], void *userdata) {
77
78         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
79         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
80         const char *name, *class, *service, *object;
81         sd_bus *bus = userdata;
82         unsigned k = 0;
83         int r;
84
85         assert(bus);
86
87         pager_open_if_enabled();
88
89         r = sd_bus_call_method(
90                                 bus,
91                                 "org.freedesktop.machine1",
92                                 "/org/freedesktop/machine1",
93                                 "org.freedesktop.machine1.Manager",
94                                 "ListMachines",
95                                 &error,
96                                 &reply,
97                                 "");
98         if (r < 0) {
99                 log_error("Could not get machines: %s", bus_error_message(&error, -r));
100                 return r;
101         }
102
103         if (arg_legend)
104                 printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
105
106         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
107         if (r < 0)
108                 return bus_log_parse_error(r);
109
110         while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
111                 printf("%-32s %-9s %-16s\n", name, class, service);
112
113                 k++;
114         }
115         if (r < 0)
116                 return bus_log_parse_error(r);
117
118         r = sd_bus_message_exit_container(reply);
119         if (r < 0)
120                 return bus_log_parse_error(r);
121
122         if (arg_legend)
123                 printf("\n%u machines listed.\n", k);
124
125         return 0;
126 }
127
128 typedef struct ImageInfo {
129         const char *name;
130         const char *type;
131         bool read_only;
132         usec_t crtime;
133         usec_t mtime;
134         uint64_t size;
135 } ImageInfo;
136
137 static int compare_image_info(const void *a, const void *b) {
138         const ImageInfo *x = a, *y = b;
139
140         return strcmp(x->name, y->name);
141 }
142
143 static int list_images(int argc, char *argv[], void *userdata) {
144
145         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
146         size_t max_name = strlen("NAME"), max_type = strlen("TYPE"), max_size = strlen("SIZE"), max_crtime = strlen("CREATED"), max_mtime = strlen("MODIFIED");
147         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
148         _cleanup_free_ ImageInfo *images = NULL;
149         size_t n_images = 0, n_allocated = 0, j;
150         const char *name, *type, *object;
151         sd_bus *bus = userdata;
152         uint64_t crtime, mtime, size;
153         int read_only, r;
154
155         assert(bus);
156
157         pager_open_if_enabled();
158
159         r = sd_bus_call_method(
160                                 bus,
161                                 "org.freedesktop.machine1",
162                                 "/org/freedesktop/machine1",
163                                 "org.freedesktop.machine1.Manager",
164                                 "ListImages",
165                                 &error,
166                                 &reply,
167                                 "");
168         if (r < 0) {
169                 log_error("Could not get images: %s", bus_error_message(&error, -r));
170                 return r;
171         }
172
173         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbttto)");
174         if (r < 0)
175                 return bus_log_parse_error(r);
176
177         while ((r = sd_bus_message_read(reply, "(ssbttto)", &name, &type, &read_only, &crtime, &mtime, &size, &object)) > 0) {
178                 char buf[MAX(FORMAT_TIMESTAMP_MAX, FORMAT_BYTES_MAX)];
179                 size_t l;
180
181                 if (name[0] == '.' && !arg_all)
182                         continue;
183
184                 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
185                         return log_oom();
186
187                 images[n_images].name = name;
188                 images[n_images].type = type;
189                 images[n_images].read_only = read_only;
190                 images[n_images].crtime = crtime;
191                 images[n_images].mtime = mtime;
192                 images[n_images].size = size;
193
194                 l = strlen(name);
195                 if (l > max_name)
196                         max_name = l;
197
198                 l = strlen(type);
199                 if (l > max_type)
200                         max_type = l;
201
202                 if (crtime != 0) {
203                         l = strlen(strna(format_timestamp(buf, sizeof(buf), crtime)));
204                         if (l > max_crtime)
205                                 max_crtime = l;
206                 }
207
208                 if (mtime != 0) {
209                         l = strlen(strna(format_timestamp(buf, sizeof(buf), mtime)));
210                         if (l > max_mtime)
211                                 max_mtime = l;
212                 }
213
214                 if (size != (uint64_t) -1) {
215                         l = strlen(strna(format_bytes(buf, sizeof(buf), size)));
216                         if (l > max_size)
217                                 max_size = l;
218                 }
219
220                 n_images++;
221         }
222         if (r < 0)
223                 return bus_log_parse_error(r);
224
225         r = sd_bus_message_exit_container(reply);
226         if (r < 0)
227                 return bus_log_parse_error(r);
228
229         qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
230
231         if (arg_legend)
232                 printf("%-*s %-*s %-3s %-*s %-*s %-*s\n",
233                        (int) max_name, "NAME",
234                        (int) max_type, "TYPE",
235                        "RO",
236                        (int) max_size, "SIZE",
237                        (int) max_crtime, "CREATED",
238                        (int) max_mtime, "MODIFIED");
239
240         for (j = 0; j < n_images; j++) {
241                 char crtime_buf[FORMAT_TIMESTAMP_MAX], mtime_buf[FORMAT_TIMESTAMP_MAX], size_buf[FORMAT_BYTES_MAX];
242
243                 printf("%-*s %-*s %s%-3s%s %-*s %-*s %-*s\n",
244                        (int) max_name, images[j].name,
245                        (int) max_type, images[j].type,
246                        images[j].read_only ? ansi_highlight_red() : "", yes_no(images[j].read_only), images[j].read_only ? ansi_highlight_off() : "",
247                        (int) max_size, strna(format_bytes(size_buf, sizeof(size_buf), images[j].size)),
248                        (int) max_crtime, strna(format_timestamp(crtime_buf, sizeof(crtime_buf), images[j].crtime)),
249                        (int) max_mtime, strna(format_timestamp(mtime_buf, sizeof(mtime_buf), images[j].mtime)));
250         }
251
252         if (r < 0)
253                 return bus_log_parse_error(r);
254
255
256         if (arg_legend)
257                 printf("\n%zu images listed.\n", n_images);
258
259         return 0;
260 }
261
262 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
263         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
264         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
265         _cleanup_free_ char *path = NULL;
266         const char *cgroup;
267         int r, output_flags;
268         unsigned c;
269
270         assert(bus);
271         assert(unit);
272
273         if (arg_transport == BUS_TRANSPORT_REMOTE)
274                 return 0;
275
276         path = unit_dbus_path_from_name(unit);
277         if (!path)
278                 return log_oom();
279
280         r = sd_bus_get_property(
281                         bus,
282                         "org.freedesktop.systemd1",
283                         path,
284                         endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
285                         "ControlGroup",
286                         &error,
287                         &reply,
288                         "s");
289         if (r < 0) {
290                 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
291                 return r;
292         }
293
294         r = sd_bus_message_read(reply, "s", &cgroup);
295         if (r < 0)
296                 return bus_log_parse_error(r);
297
298         if (isempty(cgroup))
299                 return 0;
300
301         if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
302                 return 0;
303
304         output_flags =
305                 arg_all * OUTPUT_SHOW_ALL |
306                 arg_full * OUTPUT_FULL_WIDTH;
307
308         c = columns();
309         if (c > 18)
310                 c -= 18;
311         else
312                 c = 0;
313
314         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, output_flags);
315         return 0;
316 }
317
318 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
319         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
320         int r;
321
322         assert(bus);
323         assert(name);
324         assert(prefix);
325         assert(prefix2);
326
327         r = sd_bus_call_method(bus,
328                                "org.freedesktop.machine1",
329                                "/org/freedesktop/machine1",
330                                "org.freedesktop.machine1.Manager",
331                                "GetMachineAddresses",
332                                NULL,
333                                &reply,
334                                "s", name);
335         if (r < 0)
336                 return r;
337
338         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
339         if (r < 0)
340                 return bus_log_parse_error(r);
341
342         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
343                 int family;
344                 const void *a;
345                 size_t sz;
346                 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
347
348                 r = sd_bus_message_read(reply, "i", &family);
349                 if (r < 0)
350                         return bus_log_parse_error(r);
351
352                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
353                 if (r < 0)
354                         return bus_log_parse_error(r);
355
356                 fputs(prefix, stdout);
357                 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
358                 if (family == AF_INET6 && ifi > 0)
359                         printf("%%%i", ifi);
360                 fputc('\n', stdout);
361
362                 r = sd_bus_message_exit_container(reply);
363                 if (r < 0)
364                         return bus_log_parse_error(r);
365
366                 if (prefix != prefix2)
367                         prefix = prefix2;
368         }
369         if (r < 0)
370                 return bus_log_parse_error(r);
371
372         r = sd_bus_message_exit_container(reply);
373         if (r < 0)
374                 return bus_log_parse_error(r);
375
376         return 0;
377 }
378
379 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
380         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
381         const char *k, *v, *pretty = NULL;
382         int r;
383
384         assert(bus);
385         assert(name);
386         assert(prefix);
387
388         r = sd_bus_call_method(bus,
389                                "org.freedesktop.machine1",
390                                "/org/freedesktop/machine1",
391                                "org.freedesktop.machine1.Manager",
392                                "GetMachineOSRelease",
393                                NULL,
394                                &reply,
395                                "s", name);
396         if (r < 0)
397                 return r;
398
399         r = sd_bus_message_enter_container(reply, 'a', "{ss}");
400         if (r < 0)
401                 return bus_log_parse_error(r);
402
403         while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
404                 if (streq(k, "PRETTY_NAME"))
405                         pretty = v;
406
407         }
408         if (r < 0)
409                 return bus_log_parse_error(r);
410
411         r = sd_bus_message_exit_container(reply);
412         if (r < 0)
413                 return bus_log_parse_error(r);
414
415         if (pretty)
416                 printf("%s%s\n", prefix, pretty);
417
418         return 0;
419 }
420
421 typedef struct MachineStatusInfo {
422         char *name;
423         sd_id128_t id;
424         char *class;
425         char *service;
426         char *unit;
427         char *root_directory;
428         pid_t leader;
429         usec_t timestamp;
430         int *netif;
431         unsigned n_netif;
432 } MachineStatusInfo;
433
434 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
435         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
436         char since2[FORMAT_TIMESTAMP_MAX], *s2;
437         int ifi = -1;
438
439         assert(bus);
440         assert(i);
441
442         fputs(strna(i->name), stdout);
443
444         if (!sd_id128_equal(i->id, SD_ID128_NULL))
445                 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
446         else
447                 putchar('\n');
448
449         s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
450         s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
451
452         if (s1)
453                 printf("\t   Since: %s; %s\n", s2, s1);
454         else if (s2)
455                 printf("\t   Since: %s\n", s2);
456
457         if (i->leader > 0) {
458                 _cleanup_free_ char *t = NULL;
459
460                 printf("\t  Leader: %u", (unsigned) i->leader);
461
462                 get_process_comm(i->leader, &t);
463                 if (t)
464                         printf(" (%s)", t);
465
466                 putchar('\n');
467         }
468
469         if (i->service) {
470                 printf("\t Service: %s", i->service);
471
472                 if (i->class)
473                         printf("; class %s", i->class);
474
475                 putchar('\n');
476         } else if (i->class)
477                 printf("\t   Class: %s\n", i->class);
478
479         if (i->root_directory)
480                 printf("\t    Root: %s\n", i->root_directory);
481
482         if (i->n_netif > 0) {
483                 unsigned c;
484
485                 fputs("\t   Iface:", stdout);
486
487                 for (c = 0; c < i->n_netif; c++) {
488                         char name[IF_NAMESIZE+1] = "";
489
490                         if (if_indextoname(i->netif[c], name)) {
491                                 fputc(' ', stdout);
492                                 fputs(name, stdout);
493
494                                 if (ifi < 0)
495                                         ifi = i->netif[c];
496                                 else
497                                         ifi = 0;
498                         } else
499                                 printf(" %i", i->netif[c]);
500                 }
501
502                 fputc('\n', stdout);
503         }
504
505         print_addresses(bus, i->name, ifi,
506                        "\t Address: ",
507                        "\t          ");
508
509         print_os_release(bus, i->name, "\t      OS: ");
510
511         if (i->unit) {
512                 printf("\t    Unit: %s\n", i->unit);
513                 show_unit_cgroup(bus, i->unit, i->leader);
514         }
515 }
516
517 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
518         MachineStatusInfo *i = userdata;
519         size_t l;
520         const void *v;
521         int r;
522
523         assert_cc(sizeof(int32_t) == sizeof(int));
524         r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
525         if (r < 0)
526                 return r;
527         if (r == 0)
528                 return -EBADMSG;
529
530         i->n_netif = l / sizeof(int32_t);
531         i->netif = memdup(v, l);
532         if (!i->netif)
533                 return -ENOMEM;
534
535         return 0;
536 }
537
538 static int show_machine_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
539
540         static const struct bus_properties_map map[]  = {
541                 { "Name",              "s",  NULL,          offsetof(MachineStatusInfo, name) },
542                 { "Class",             "s",  NULL,          offsetof(MachineStatusInfo, class) },
543                 { "Service",           "s",  NULL,          offsetof(MachineStatusInfo, service) },
544                 { "Unit",              "s",  NULL,          offsetof(MachineStatusInfo, unit) },
545                 { "RootDirectory",     "s",  NULL,          offsetof(MachineStatusInfo, root_directory) },
546                 { "Leader",            "u",  NULL,          offsetof(MachineStatusInfo, leader) },
547                 { "Timestamp",         "t",  NULL,          offsetof(MachineStatusInfo, timestamp) },
548                 { "Id",                "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
549                 { "NetworkInterfaces", "ai", map_netif,     0 },
550                 {}
551         };
552
553         MachineStatusInfo info = {};
554         int r;
555
556         assert(verb);
557         assert(bus);
558         assert(path);
559         assert(new_line);
560
561         r = bus_map_all_properties(bus,
562                                    "org.freedesktop.machine1",
563                                    path,
564                                    map,
565                                    &info);
566         if (r < 0)
567                 return log_error_errno(r, "Could not get properties: %m");
568
569         if (*new_line)
570                 printf("\n");
571         *new_line = true;
572
573         print_machine_status_info(bus, &info);
574
575         free(info.name);
576         free(info.class);
577         free(info.service);
578         free(info.unit);
579         free(info.root_directory);
580         free(info.netif);
581
582         return r;
583 }
584
585 static int show_machine_properties(sd_bus *bus, const char *path, bool *new_line) {
586         int r;
587
588         assert(bus);
589         assert(path);
590         assert(new_line);
591
592         if (*new_line)
593                 printf("\n");
594
595         *new_line = true;
596
597         r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
598         if (r < 0)
599                 log_error_errno(r, "Could not get properties: %m");
600
601         return r;
602 }
603
604 static int show_machine(int argc, char *argv[], void *userdata) {
605
606         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
607         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
608         bool properties, new_line = false;
609         sd_bus *bus = userdata;
610         int r = 0, i;
611
612         assert(bus);
613
614         properties = !strstr(argv[0], "status");
615
616         pager_open_if_enabled();
617
618         if (properties && argc <= 1) {
619
620                 /* If no argument is specified, inspect the manager
621                  * itself */
622                 r = show_machine_properties(bus, "/org/freedesktop/machine1", &new_line);
623                 if (r < 0)
624                         return r;
625         }
626
627         for (i = 1; i < argc; i++) {
628                 const char *path = NULL;
629
630                 r = sd_bus_call_method(
631                                         bus,
632                                         "org.freedesktop.machine1",
633                                         "/org/freedesktop/machine1",
634                                         "org.freedesktop.machine1.Manager",
635                                         "GetMachine",
636                                         &error,
637                                         &reply,
638                                         "s", argv[i]);
639                 if (r < 0) {
640                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
641                         return r;
642                 }
643
644                 r = sd_bus_message_read(reply, "o", &path);
645                 if (r < 0)
646                         return bus_log_parse_error(r);
647
648                 if (properties)
649                         r = show_machine_properties(bus, path, &new_line);
650                 else
651                         r = show_machine_info(argv[0], bus, path, &new_line);
652         }
653
654         return r;
655 }
656
657 typedef struct ImageStatusInfo {
658         char *name;
659         char *path;
660         char *type;
661         int read_only;
662         usec_t crtime;
663         usec_t mtime;
664         uint64_t size;
665         uint64_t limit;
666         uint64_t size_exclusive;
667         uint64_t limit_exclusive;
668 } ImageStatusInfo;
669
670 static void print_image_status_info(sd_bus *bus, ImageStatusInfo *i) {
671         char ts_relative[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
672         char ts_absolute[FORMAT_TIMESTAMP_MAX], *s2;
673         char bs[FORMAT_BYTES_MAX], *s3;
674         char bs_exclusive[FORMAT_BYTES_MAX], *s4;
675
676         assert(bus);
677         assert(i);
678
679         if (i->name) {
680                 fputs(i->name, stdout);
681                 putchar('\n');
682         }
683
684         if (i->path)
685                 printf("\t    Type: %s\n", i->type);
686
687         if (i->path)
688                 printf("\t    Path: %s\n", i->path);
689
690         printf("\t      RO: %s%s%s\n",
691                i->read_only ? ansi_highlight_red() : "",
692                i->read_only ? "read-only" : "writable",
693                i->read_only ? ansi_highlight_off() : "");
694
695         s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->crtime);
696         s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->crtime);
697         if (s1 && s2)
698                 printf("\t Created: %s; %s\n", s2, s1);
699         else if (s2)
700                 printf("\t Created: %s\n", s2);
701
702         s1 = format_timestamp_relative(ts_relative, sizeof(ts_relative), i->mtime);
703         s2 = format_timestamp(ts_absolute, sizeof(ts_absolute), i->mtime);
704         if (s1 && s2)
705                 printf("\tModified: %s; %s\n", s2, s1);
706         else if (s2)
707                 printf("\tModified: %s\n", s2);
708
709         s3 = format_bytes(bs, sizeof(bs), i->size);
710         s4 = i->size_exclusive != i->size ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->size_exclusive) : NULL;
711         if (s3 && s4)
712                 printf("\t    Size: %s (exclusive: %s)\n", s3, s4);
713         else if (s3)
714                 printf("\t    Size: %s\n", s3);
715
716         s3 = format_bytes(bs, sizeof(bs), i->limit);
717         s4 = i->limit_exclusive != i->limit ? format_bytes(bs_exclusive, sizeof(bs_exclusive), i->limit_exclusive) : NULL;
718         if (s3 && s4)
719                 printf("\t   Limit: %s (exclusive: %s)\n", s3, s4);
720         else if (s3)
721                 printf("\t   Limit: %s\n", s3);
722 }
723
724 static int show_image_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
725
726         static const struct bus_properties_map map[]  = {
727                 { "Name",                  "s",  NULL, offsetof(ImageStatusInfo, name)            },
728                 { "Path",                  "s",  NULL, offsetof(ImageStatusInfo, path)            },
729                 { "Type",                  "s",  NULL, offsetof(ImageStatusInfo, type)            },
730                 { "ReadOnly",              "b",  NULL, offsetof(ImageStatusInfo, read_only)       },
731                 { "CreationTimestamp",     "t",  NULL, offsetof(ImageStatusInfo, crtime)          },
732                 { "ModificationTimestamp", "t",  NULL, offsetof(ImageStatusInfo, mtime)           },
733                 { "Size",                  "t",  NULL, offsetof(ImageStatusInfo, size)            },
734                 { "Limit",                 "t",  NULL, offsetof(ImageStatusInfo, limit)           },
735                 { "SizeExclusive",         "t",  NULL, offsetof(ImageStatusInfo, size_exclusive)  },
736                 { "LimitExclusive",        "t",  NULL, offsetof(ImageStatusInfo, limit_exclusive) },
737                 {}
738         };
739
740         ImageStatusInfo info = {};
741         int r;
742
743         assert(verb);
744         assert(bus);
745         assert(path);
746         assert(new_line);
747
748         r = bus_map_all_properties(bus,
749                                    "org.freedesktop.machine1",
750                                    path,
751                                    map,
752                                    &info);
753         if (r < 0)
754                 return log_error_errno(r, "Could not get properties: %m");
755
756         if (*new_line)
757                 printf("\n");
758         *new_line = true;
759
760         print_image_status_info(bus, &info);
761
762         free(info.name);
763         free(info.path);
764         free(info.type);
765
766         return r;
767 }
768
769 static int show_image_properties(sd_bus *bus, const char *path, bool *new_line) {
770         int r;
771
772         assert(bus);
773         assert(path);
774         assert(new_line);
775
776         if (*new_line)
777                 printf("\n");
778
779         *new_line = true;
780
781         r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
782         if (r < 0)
783                 log_error_errno(r, "Could not get properties: %m");
784
785         return r;
786 }
787
788 static int show_image(int argc, char *argv[], void *userdata) {
789
790         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
791         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
792         bool properties, new_line = false;
793         sd_bus *bus = userdata;
794         int r = 0, i;
795
796         assert(bus);
797
798         properties = !strstr(argv[0], "status");
799
800         pager_open_if_enabled();
801
802         if (properties && argc <= 1) {
803
804                 /* If no argument is specified, inspect the manager
805                  * itself */
806                 r = show_image_properties(bus, "/org/freedesktop/machine1", &new_line);
807                 if (r < 0)
808                         return r;
809         }
810
811         for (i = 1; i < argc; i++) {
812                 const char *path = NULL;
813
814                 r = sd_bus_call_method(
815                                         bus,
816                                         "org.freedesktop.machine1",
817                                         "/org/freedesktop/machine1",
818                                         "org.freedesktop.machine1.Manager",
819                                         "GetImage",
820                                         &error,
821                                         &reply,
822                                         "s", argv[i]);
823                 if (r < 0) {
824                         log_error("Could not get path to image: %s", bus_error_message(&error, -r));
825                         return r;
826                 }
827
828                 r = sd_bus_message_read(reply, "o", &path);
829                 if (r < 0)
830                         return bus_log_parse_error(r);
831
832                 if (properties)
833                         r = show_image_properties(bus, path, &new_line);
834                 else
835                         r = show_image_info(argv[0], bus, path, &new_line);
836         }
837
838         return r;
839 }
840
841 static int kill_machine(int argc, char *argv[], void *userdata) {
842         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
843         sd_bus *bus = userdata;
844         int i;
845
846         assert(bus);
847
848         if (!arg_kill_who)
849                 arg_kill_who = "all";
850
851         for (i = 1; i < argc; i++) {
852                 int r;
853
854                 r = sd_bus_call_method(
855                                 bus,
856                                 "org.freedesktop.machine1",
857                                 "/org/freedesktop/machine1",
858                                 "org.freedesktop.machine1.Manager",
859                                 "KillMachine",
860                                 &error,
861                                 NULL,
862                                 "ssi", argv[i], arg_kill_who, arg_signal);
863                 if (r < 0) {
864                         log_error("Could not kill machine: %s", bus_error_message(&error, -r));
865                         return r;
866                 }
867         }
868
869         return 0;
870 }
871
872 static int reboot_machine(int argc, char *argv[], void *userdata) {
873         arg_kill_who = "leader";
874         arg_signal = SIGINT; /* sysvinit + systemd */
875
876         return kill_machine(argc, argv, userdata);
877 }
878
879 static int poweroff_machine(int argc, char *argv[], void *userdata) {
880         arg_kill_who = "leader";
881         arg_signal = SIGRTMIN+4; /* only systemd */
882
883         return kill_machine(argc, argv, userdata);
884 }
885
886 static int terminate_machine(int argc, char *argv[], void *userdata) {
887         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
888         sd_bus *bus = userdata;
889         int i;
890
891         assert(bus);
892
893         for (i = 1; i < argc; i++) {
894                 int r;
895
896                 r = sd_bus_call_method(
897                                 bus,
898                                 "org.freedesktop.machine1",
899                                 "/org/freedesktop/machine1",
900                                 "org.freedesktop.machine1.Manager",
901                                 "TerminateMachine",
902                                 &error,
903                                 NULL,
904                                 "s", argv[i]);
905                 if (r < 0) {
906                         log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
907                         return r;
908                 }
909         }
910
911         return 0;
912 }
913
914 static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
915         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
916         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL;
917         const char *object;
918         uint32_t leader;
919         int r;
920
921         assert(bus);
922         assert(name);
923         assert(ret);
924
925         r = sd_bus_call_method(
926                         bus,
927                         "org.freedesktop.machine1",
928                         "/org/freedesktop/machine1",
929                         "org.freedesktop.machine1.Manager",
930                         "GetMachine",
931                         &error,
932                         &reply,
933                         "s", name);
934         if (r < 0) {
935                 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
936                 return r;
937         }
938
939         r = sd_bus_message_read(reply, "o", &object);
940         if (r < 0)
941                 return bus_log_parse_error(r);
942
943         r = sd_bus_get_property(
944                         bus,
945                         "org.freedesktop.machine1",
946                         object,
947                         "org.freedesktop.machine1.Machine",
948                         "Leader",
949                         &error,
950                         &reply2,
951                         "u");
952         if (r < 0)
953                 return log_error_errno(r, "Failed to retrieve PID of leader: %m");
954
955         r = sd_bus_message_read(reply2, "u", &leader);
956         if (r < 0)
957                 return bus_log_parse_error(r);
958
959         *ret = leader;
960         return 0;
961 }
962
963 static int copy_files(int argc, char *argv[], void *userdata) {
964         char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
965         _cleanup_close_ int hostfd = -1;
966         sd_bus *bus = userdata;
967         pid_t child, leader;
968         bool copy_from;
969         siginfo_t si;
970         int r;
971
972         assert(bus);
973
974         copy_from = streq(argv[0], "copy-from");
975         dest = argv[3] ?: argv[2];
976         host_path = strdupa(copy_from ? dest : argv[2]);
977         container_path = strdupa(copy_from ? argv[2] : dest);
978
979         if (!path_is_absolute(container_path)) {
980                 log_error("Container path not absolute.");
981                 return -EINVAL;
982         }
983
984         t = strdup(host_path);
985         host_basename = basename(t);
986         host_dirname = dirname(host_path);
987
988         t = strdup(container_path);
989         container_basename = basename(t);
990         container_dirname = dirname(container_path);
991
992         r = machine_get_leader(bus, argv[1], &leader);
993         if (r < 0)
994                 return r;
995
996         hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
997         if (r < 0)
998                 return log_error_errno(errno, "Failed to open source directory: %m");
999
1000         child = fork();
1001         if (child < 0)
1002                 return log_error_errno(errno, "Failed to fork(): %m");
1003
1004         if (child == 0) {
1005                 int containerfd;
1006                 const char *q;
1007                 int mntfd;
1008
1009                 q = procfs_file_alloca(leader, "ns/mnt");
1010                 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1011                 if (mntfd < 0) {
1012                         log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1013                         _exit(EXIT_FAILURE);
1014                 }
1015
1016                 if (setns(mntfd, CLONE_NEWNS) < 0) {
1017                         log_error_errno(errno, "Failed to join namespace of leader: %m");
1018                         _exit(EXIT_FAILURE);
1019                 }
1020
1021                 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
1022                 if (containerfd < 0) {
1023                         log_error_errno(errno, "Failed top open destination directory: %m");
1024                         _exit(EXIT_FAILURE);
1025                 }
1026
1027                 if (copy_from)
1028                         r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
1029                 else
1030                         r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
1031                 if (r < 0) {
1032                         log_error_errno(errno, "Failed to copy tree: %m");
1033                         _exit(EXIT_FAILURE);
1034                 }
1035
1036                 _exit(EXIT_SUCCESS);
1037         }
1038
1039         r = wait_for_terminate(child, &si);
1040         if (r < 0)
1041                 return log_error_errno(r, "Failed to wait for client: %m");
1042         if (si.si_code != CLD_EXITED) {
1043                 log_error("Client died abnormally.");
1044                 return -EIO;
1045         }
1046         if (si.si_status != EXIT_SUCCESS)
1047                 return -EIO;
1048
1049         return 0;
1050 }
1051
1052 static int bind_mount(int argc, char *argv[], void *userdata) {
1053         char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
1054         sd_bus *bus = userdata;
1055         pid_t child, leader;
1056         const char *dest;
1057         siginfo_t si;
1058         bool mount_slave_created = false, mount_slave_mounted = false,
1059                 mount_tmp_created = false, mount_tmp_mounted = false,
1060                 mount_outside_created = false, mount_outside_mounted = false;
1061         int r;
1062
1063         assert(bus);
1064
1065         /* One day, when bind mounting /proc/self/fd/n works across
1066          * namespace boundaries we should rework this logic to make
1067          * use of it... */
1068
1069         dest = argv[3] ?: argv[2];
1070         if (!path_is_absolute(dest)) {
1071                 log_error("Destination path not absolute.");
1072                 return -EINVAL;
1073         }
1074
1075         p = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/");
1076         if (access(p, F_OK) < 0) {
1077                 log_error("Container does not allow propagation of mount points.");
1078                 return -ENOTSUP;
1079         }
1080
1081         r = machine_get_leader(bus, argv[1], &leader);
1082         if (r < 0)
1083                 return r;
1084
1085         /* Our goal is to install a new bind mount into the container,
1086            possibly read-only. This is irritatingly complex
1087            unfortunately, currently.
1088
1089            First, we start by creating a private playground in /tmp,
1090            that we can mount MS_SLAVE. (Which is necessary, since
1091            MS_MOUNT cannot be applied to mounts with MS_SHARED parent
1092            mounts.) */
1093
1094         if (!mkdtemp(mount_slave))
1095                 return log_error_errno(errno, "Failed to create playground: %m");
1096
1097         mount_slave_created = true;
1098
1099         if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
1100                 r = log_error_errno(errno, "Failed to make bind mount: %m");
1101                 goto finish;
1102         }
1103
1104         mount_slave_mounted = true;
1105
1106         if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
1107                 r = log_error_errno(errno, "Failed to remount slave: %m");
1108                 goto finish;
1109         }
1110
1111         /* Second, we mount the source directory to a directory inside
1112            of our MS_SLAVE playground. */
1113         mount_tmp = strappenda(mount_slave, "/mount");
1114         if (mkdir(mount_tmp, 0700) < 0) {
1115                 r = log_error_errno(errno, "Failed to create temporary mount: %m");
1116                 goto finish;
1117         }
1118
1119         mount_tmp_created = true;
1120
1121         if (mount(argv[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
1122                 r = log_error_errno(errno, "Failed to overmount: %m");
1123                 goto finish;
1124         }
1125
1126         mount_tmp_mounted = true;
1127
1128         /* Third, we remount the new bind mount read-only if requested. */
1129         if (arg_read_only)
1130                 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
1131                         r = log_error_errno(errno, "Failed to mark read-only: %m");
1132                         goto finish;
1133                 }
1134
1135         /* Fourth, we move the new bind mount into the propagation
1136          * directory. This way it will appear there read-only
1137          * right-away. */
1138
1139         mount_outside = strappenda("/run/systemd/nspawn/propagate/", argv[1], "/XXXXXX");
1140         if (!mkdtemp(mount_outside)) {
1141                 r = log_error_errno(errno, "Cannot create propagation directory: %m");
1142                 goto finish;
1143         }
1144
1145         mount_outside_created = true;
1146
1147         if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
1148                 r = log_error_errno(errno, "Failed to move: %m");
1149                 goto finish;
1150         }
1151
1152         mount_outside_mounted = true;
1153         mount_tmp_mounted = false;
1154
1155         (void) rmdir(mount_tmp);
1156         mount_tmp_created = false;
1157
1158         (void) umount(mount_slave);
1159         mount_slave_mounted = false;
1160
1161         (void) rmdir(mount_slave);
1162         mount_slave_created = false;
1163
1164         child = fork();
1165         if (child < 0) {
1166                 r = log_error_errno(errno, "Failed to fork(): %m");
1167                 goto finish;
1168         }
1169
1170         if (child == 0) {
1171                 const char *mount_inside;
1172                 int mntfd;
1173                 const char *q;
1174
1175                 q = procfs_file_alloca(leader, "ns/mnt");
1176                 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
1177                 if (mntfd < 0) {
1178                         log_error_errno(errno, "Failed to open mount namespace of leader: %m");
1179                         _exit(EXIT_FAILURE);
1180                 }
1181
1182                 if (setns(mntfd, CLONE_NEWNS) < 0) {
1183                         log_error_errno(errno, "Failed to join namespace of leader: %m");
1184                         _exit(EXIT_FAILURE);
1185                 }
1186
1187                 if (arg_mkdir)
1188                         mkdir_p(dest, 0755);
1189
1190                 /* Fifth, move the mount to the right place inside */
1191                 mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside));
1192                 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
1193                         log_error_errno(errno, "Failed to mount: %m");
1194                         _exit(EXIT_FAILURE);
1195                 }
1196
1197                 _exit(EXIT_SUCCESS);
1198         }
1199
1200         r = wait_for_terminate(child, &si);
1201         if (r < 0) {
1202                 log_error_errno(r, "Failed to wait for client: %m");
1203                 goto finish;
1204         }
1205         if (si.si_code != CLD_EXITED) {
1206                 log_error("Client died abnormally.");
1207                 r = -EIO;
1208                 goto finish;
1209         }
1210         if (si.si_status != EXIT_SUCCESS) {
1211                 r = -EIO;
1212                 goto finish;
1213         }
1214
1215         r = 0;
1216
1217 finish:
1218         if (mount_outside_mounted)
1219                 umount(mount_outside);
1220         if (mount_outside_created)
1221                 rmdir(mount_outside);
1222
1223         if (mount_tmp_mounted)
1224                 umount(mount_tmp);
1225         if (mount_tmp_created)
1226                 umount(mount_tmp);
1227
1228         if (mount_slave_mounted)
1229                 umount(mount_slave);
1230         if (mount_slave_created)
1231                 umount(mount_slave);
1232
1233         return r;
1234 }
1235
1236 static int login_machine(int argc, char *argv[], void *userdata) {
1237         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1238         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1239         _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1240         _cleanup_event_unref_ sd_event *event = NULL;
1241         int master = -1, r, ret = 0;
1242         sd_bus *bus = userdata;
1243         const char *pty;
1244         sigset_t mask;
1245         char last_char = 0;
1246
1247         assert(bus);
1248
1249         if (arg_transport != BUS_TRANSPORT_LOCAL &&
1250             arg_transport != BUS_TRANSPORT_MACHINE) {
1251                 log_error("Login only supported on local machines.");
1252                 return -ENOTSUP;
1253         }
1254
1255         r = sd_event_default(&event);
1256         if (r < 0)
1257                 return log_error_errno(r, "Failed to get event loop: %m");
1258
1259         r = sd_bus_attach_event(bus, event, 0);
1260         if (r < 0)
1261                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1262
1263         r = sd_bus_message_new_method_call(bus,
1264                                            &m,
1265                                            "org.freedesktop.machine1",
1266                                            "/org/freedesktop/machine1",
1267                                            "org.freedesktop.machine1.Manager",
1268                                            "OpenMachineLogin");
1269         if (r < 0)
1270                 return bus_log_create_error(r);
1271
1272         r = sd_bus_message_set_allow_interactive_authorization(m, true);
1273         if (r < 0)
1274                 return bus_log_create_error(r);
1275
1276         r = sd_bus_message_append(m, "s", argv[1]);
1277         if (r < 0)
1278                 return bus_log_create_error(r);
1279
1280         r = sd_bus_call(bus, m, 0, &error, &reply);
1281         if (r < 0) {
1282                 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1283                 return r;
1284         }
1285
1286         r = sd_bus_message_read(reply, "hs", &master, &pty);
1287         if (r < 0)
1288                 return bus_log_parse_error(r);
1289
1290         assert_se(sigemptyset(&mask) == 0);
1291         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
1292         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
1293
1294         log_info("Connected to container %s. Press ^] three times within 1s to exit session.", argv[1]);
1295
1296         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1297         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1298
1299         r = pty_forward_new(event, master, true, &forward);
1300         if (r < 0)
1301                 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1302
1303         r = sd_event_loop(event);
1304         if (r < 0)
1305                 return log_error_errno(r, "Failed to run event loop: %m");
1306
1307         pty_forward_last_char(forward, &last_char);
1308
1309         forward = pty_forward_free(forward);
1310
1311         if (last_char != '\n')
1312                 fputc('\n', stdout);
1313
1314         log_info("Connection to container %s terminated.", argv[1]);
1315
1316         sd_event_get_exit_code(event, &ret);
1317         return ret;
1318 }
1319
1320 static int remove_image(int argc, char *argv[], void *userdata) {
1321         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1322         sd_bus *bus = userdata;
1323         int r, i;
1324
1325         assert(bus);
1326
1327         for (i = 1; i < argc; i++) {
1328                 r = sd_bus_call_method(
1329                                 bus,
1330                                 "org.freedesktop.machine1",
1331                                 "/org/freedesktop/machine1",
1332                                 "org.freedesktop.machine1.Manager",
1333                                 "RemoveImage",
1334                                 &error,
1335                                 NULL,
1336                                 "s", argv[i]);
1337                 if (r < 0) {
1338                         log_error("Could not remove image: %s", bus_error_message(&error, -r));
1339                         return r;
1340                 }
1341         }
1342
1343         return 0;
1344 }
1345
1346 static int rename_image(int argc, char *argv[], void *userdata) {
1347         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1348         sd_bus *bus = userdata;
1349         int r;
1350
1351         r = sd_bus_call_method(
1352                         bus,
1353                         "org.freedesktop.machine1",
1354                         "/org/freedesktop/machine1",
1355                         "org.freedesktop.machine1.Manager",
1356                         "RenameImage",
1357                         &error,
1358                         NULL,
1359                         "ss", argv[1], argv[2]);
1360         if (r < 0) {
1361                 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1362                 return r;
1363         }
1364
1365         return 0;
1366 }
1367
1368 static int clone_image(int argc, char *argv[], void *userdata) {
1369         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1370         sd_bus *bus = userdata;
1371         int r;
1372
1373         r = sd_bus_call_method(
1374                         bus,
1375                         "org.freedesktop.machine1",
1376                         "/org/freedesktop/machine1",
1377                         "org.freedesktop.machine1.Manager",
1378                         "CloneImage",
1379                         &error,
1380                         NULL,
1381                         "ssb", argv[1], argv[2], arg_read_only);
1382         if (r < 0) {
1383                 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1384                 return r;
1385         }
1386
1387         return 0;
1388 }
1389
1390 static int read_only_image(int argc, char *argv[], void *userdata) {
1391         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1392         sd_bus *bus = userdata;
1393         int b = true, r;
1394
1395         if (argc > 2) {
1396                 b = parse_boolean(argv[2]);
1397                 if (b < 0) {
1398                         log_error("Failed to parse boolean argument: %s", argv[2]);
1399                         return -EINVAL;
1400                 }
1401         }
1402
1403         r = sd_bus_call_method(
1404                         bus,
1405                         "org.freedesktop.machine1",
1406                         "/org/freedesktop/machine1",
1407                         "org.freedesktop.machine1.Manager",
1408                         "MarkImageReadOnly",
1409                         &error,
1410                         NULL,
1411                         "sb", argv[1], b);
1412         if (r < 0) {
1413                 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1414                 return r;
1415         }
1416
1417         return 0;
1418 }
1419
1420 static int help(int argc, char *argv[], void *userdata) {
1421
1422         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1423                "Send control commands to or query the virtual machine and container\n"
1424                "registration manager.\n\n"
1425                "  -h --help                   Show this help\n"
1426                "     --version                Show package version\n"
1427                "     --no-pager               Do not pipe output into a pager\n"
1428                "     --no-legend              Do not show the headers and footers\n"
1429                "  -H --host=[USER@]HOST       Operate on remote host\n"
1430                "  -M --machine=CONTAINER      Operate on local container\n"
1431                "  -p --property=NAME          Show only properties by this name\n"
1432                "  -a --all                    Show all properties, including empty ones\n"
1433                "  -l --full                   Do not ellipsize output\n"
1434                "     --kill-who=WHO           Who to send signal to\n"
1435                "  -s --signal=SIGNAL          Which signal to send\n"
1436                "     --read-only              Create read-only bind mount\n"
1437                "     --mkdir                  Create directory before bind mounting, if missing\n\n"
1438                "Machine Commands:\n"
1439                "  list                        List running VMs and containers\n"
1440                "  status NAME...              Show VM/container details\n"
1441                "  show NAME...                Show properties of one or more VMs/containers\n"
1442                "  login NAME                  Get a login prompt on a container\n"
1443                "  poweroff NAME...            Power off one or more containers\n"
1444                "  reboot NAME...              Reboot one or more containers\n"
1445                "  terminate NAME...           Terminate one or more VMs/containers\n"
1446                "  kill NAME...                Send signal to processes of a VM/container\n"
1447                "  copy-to NAME PATH [PATH]    Copy files from the host to a container\n"
1448                "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n"
1449                "  bind NAME PATH [PATH]       Bind mount a path from the host into a container\n\n"
1450                "Image Commands:\n"
1451                "  list-images                 Show available images\n"
1452                "  image-status NAME...        Show image details\n"
1453                "  show-image NAME...          Show properties of image\n"
1454                "  clone NAME NAME             Clone an image\n"
1455                "  rename NAME NAME            Rename an image\n"
1456                "  read-only NAME [BOOL]       Mark or unmark image read-only\n"
1457                "  remove NAME...              Remove an image\n",
1458                program_invocation_short_name);
1459
1460         return 0;
1461 }
1462
1463 static int parse_argv(int argc, char *argv[]) {
1464
1465         enum {
1466                 ARG_VERSION = 0x100,
1467                 ARG_NO_PAGER,
1468                 ARG_NO_LEGEND,
1469                 ARG_KILL_WHO,
1470                 ARG_READ_ONLY,
1471                 ARG_MKDIR,
1472         };
1473
1474         static const struct option options[] = {
1475                 { "help",            no_argument,       NULL, 'h'                 },
1476                 { "version",         no_argument,       NULL, ARG_VERSION         },
1477                 { "property",        required_argument, NULL, 'p'                 },
1478                 { "all",             no_argument,       NULL, 'a'                 },
1479                 { "full",            no_argument,       NULL, 'l'                 },
1480                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
1481                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
1482                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
1483                 { "signal",          required_argument, NULL, 's'                 },
1484                 { "host",            required_argument, NULL, 'H'                 },
1485                 { "machine",         required_argument, NULL, 'M'                 },
1486                 { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
1487                 { "mkdir",           no_argument,       NULL, ARG_MKDIR           },
1488                 {}
1489         };
1490
1491         int c, r;
1492
1493         assert(argc >= 0);
1494         assert(argv);
1495
1496         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
1497
1498                 switch (c) {
1499
1500                 case 'h':
1501                         return help(0, NULL, NULL);
1502
1503                 case ARG_VERSION:
1504                         puts(PACKAGE_STRING);
1505                         puts(SYSTEMD_FEATURES);
1506                         return 0;
1507
1508                 case 'p':
1509                         r = strv_extend(&arg_property, optarg);
1510                         if (r < 0)
1511                                 return log_oom();
1512
1513                         /* If the user asked for a particular
1514                          * property, show it to him, even if it is
1515                          * empty. */
1516                         arg_all = true;
1517                         break;
1518
1519                 case 'a':
1520                         arg_all = true;
1521                         break;
1522
1523                 case 'l':
1524                         arg_full = true;
1525                         break;
1526
1527                 case ARG_NO_PAGER:
1528                         arg_no_pager = true;
1529                         break;
1530
1531                 case ARG_NO_LEGEND:
1532                         arg_legend = false;
1533                         break;
1534
1535                 case ARG_KILL_WHO:
1536                         arg_kill_who = optarg;
1537                         break;
1538
1539                 case 's':
1540                         arg_signal = signal_from_string_try_harder(optarg);
1541                         if (arg_signal < 0) {
1542                                 log_error("Failed to parse signal string %s.", optarg);
1543                                 return -EINVAL;
1544                         }
1545                         break;
1546
1547                 case 'H':
1548                         arg_transport = BUS_TRANSPORT_REMOTE;
1549                         arg_host = optarg;
1550                         break;
1551
1552                 case 'M':
1553                         arg_transport = BUS_TRANSPORT_MACHINE;
1554                         arg_host = optarg;
1555                         break;
1556
1557                 case ARG_READ_ONLY:
1558                         arg_read_only = true;
1559                         break;
1560
1561                 case ARG_MKDIR:
1562                         arg_mkdir = true;
1563                         break;
1564
1565                 case '?':
1566                         return -EINVAL;
1567
1568                 default:
1569                         assert_not_reached("Unhandled option");
1570                 }
1571
1572         return 1;
1573 }
1574
1575 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
1576
1577         static const Verb verbs[] = {
1578                 { "help",        VERB_ANY, VERB_ANY, 0,            help              },
1579                 { "list",        VERB_ANY, 1,        VERB_DEFAULT, list_machines     },
1580                 { "list-images", VERB_ANY, 1,        0,            list_images       },
1581                 { "status",      2,        VERB_ANY, 0,            show_machine      },
1582                 { "image-status",2,        VERB_ANY, 0,            show_image        },
1583                 { "show",        VERB_ANY, VERB_ANY, 0,            show_machine      },
1584                 { "show-image",  VERB_ANY, VERB_ANY, 0,            show_image        },
1585                 { "terminate",   2,        VERB_ANY, 0,            terminate_machine },
1586                 { "reboot",      2,        VERB_ANY, 0,            reboot_machine    },
1587                 { "poweroff",    2,        VERB_ANY, 0,            poweroff_machine  },
1588                 { "kill",        2,        VERB_ANY, 0,            kill_machine      },
1589                 { "login",       2,        2,        0,            login_machine     },
1590                 { "bind",        3,        4,        0,            bind_mount        },
1591                 { "copy-to",     3,        4,        0,            copy_files        },
1592                 { "copy-from",   3,        4,        0,            copy_files        },
1593                 { "remove",      2,        VERB_ANY, 0,            remove_image      },
1594                 { "rename",      3,        3,        0,            rename_image      },
1595                 { "clone",       3,        3,        0,            clone_image       },
1596                 { "read-only",   2,        3,        0,            read_only_image   },
1597                 {}
1598         };
1599
1600         return dispatch_verb(argc, argv, verbs, bus);
1601 }
1602
1603 int main(int argc, char*argv[]) {
1604         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1605         int r;
1606
1607         setlocale(LC_ALL, "");
1608         log_parse_environment();
1609         log_open();
1610
1611         r = parse_argv(argc, argv);
1612         if (r <= 0)
1613                 goto finish;
1614
1615         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1616         if (r < 0) {
1617                 log_error_errno(r, "Failed to create bus connection: %m");
1618                 goto finish;
1619         }
1620
1621         r = machinectl_main(argc, argv, bus);
1622
1623 finish:
1624         pager_close();
1625
1626         strv_free(arg_property);
1627
1628         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1629 }