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