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