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