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