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