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