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