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