chiark / gitweb /
machinectl: minor simplification
[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 typedef struct PullContext {
1737         const char *path;
1738         int result;
1739 } PullContext;
1740
1741 static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1742         PullContext *c = userdata;
1743         const char *line;
1744         unsigned priority;
1745         int r;
1746
1747         assert(bus);
1748         assert(m);
1749
1750         r = sd_bus_message_read(m, "us", &priority, &line);
1751         if (r < 0) {
1752                 bus_log_parse_error(r);
1753                 return 0;
1754         }
1755
1756         if (!streq_ptr(c->path, sd_bus_message_get_path(m)))
1757                 return 0;
1758
1759         if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
1760                 return 0;
1761
1762         log_full(priority, "%s", line);
1763         return 0;
1764 }
1765
1766 static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1767         PullContext *c = userdata;
1768         const char *path, *result;
1769         uint32_t id;
1770         int r;
1771
1772         assert(bus);
1773         assert(m);
1774         assert(c);
1775
1776         r = sd_bus_message_read(m, "uos", &id, &path, &result);
1777         if (r < 0) {
1778                 bus_log_parse_error(r);
1779                 return 0;
1780         }
1781
1782         if (!streq_ptr(c->path, path))
1783                 return 0;
1784
1785         c->result = streq_ptr(result, "done");
1786         return 0;
1787 }
1788
1789 static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
1790         _cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
1791         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1792         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1793         PullContext c = {
1794                 .result = -1,
1795         };
1796         uint32_t id;
1797         int r;
1798
1799         assert(bus);
1800         assert(m);
1801
1802         polkit_agent_open_if_enabled();
1803
1804         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1805         if (r < 0)
1806                 return bus_log_create_error(r);
1807
1808         r = sd_bus_add_match(
1809                         bus,
1810                         &slot_job_removed,
1811                         "type='signal',"
1812                         "sender='org.freedesktop.import1',"
1813                         "interface='org.freedesktop.import1.Manager',"
1814                         "member='TransferRemoved',"
1815                         "path='/org/freedesktop/import1'",
1816                         match_transfer_removed, &c);
1817         if (r < 0)
1818                 return log_error_errno(r, "Failed to install match: %m");
1819
1820         r = sd_bus_add_match(
1821                         bus,
1822                         &slot_log_message,
1823                         "type='signal',"
1824                         "sender='org.freedesktop.import1',"
1825                         "interface='org.freedesktop.import1.Transfer',"
1826                         "member='LogMessage'",
1827                         match_log_message, &c);
1828         if (r < 0)
1829                 return log_error_errno(r, "Failed to install match: %m");
1830
1831         r = sd_bus_call(bus, m, 0, &error, &reply);
1832         if (r < 0) {
1833                 log_error("Failed pull image: %s", bus_error_message(&error, -r));
1834                 return r;
1835         }
1836
1837         r = sd_bus_message_read(reply, "uo", &id, &c.path);
1838         if (r < 0)
1839                 return bus_log_parse_error(r);
1840
1841         for (;;) {
1842                 r = sd_bus_process(bus, NULL);
1843                 if (r < 0)
1844                         return r;
1845
1846                 /* The match sets this to NULL when we are done */
1847                 if (c.result >= 0)
1848                         break;
1849
1850                 r = sd_bus_wait(bus, (uint64_t) -1);
1851                 if (r < 0)
1852                         return r;
1853         }
1854
1855         return c.result ? 0 : -EINVAL;
1856 }
1857
1858 static int pull_tar(int argc, char *argv[], void *userdata) {
1859         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1860         _cleanup_free_ char *l = NULL, *ll = NULL;
1861         const char *local, *remote;
1862         sd_bus *bus = userdata;
1863         int r;
1864
1865         assert(bus);
1866
1867         remote = argv[1];
1868         if (!http_url_is_valid(remote)) {
1869                 log_error("URL '%s' is not valid.", remote);
1870                 return -EINVAL;
1871         }
1872
1873         if (argc >= 3)
1874                 local = argv[2];
1875         else {
1876                 r = import_url_last_component(remote, &l);
1877                 if (r < 0)
1878                         return log_error_errno(r, "Failed to get final component of URL: %m");
1879
1880                 local = l;
1881         }
1882
1883         if (isempty(local) || streq(local, "-"))
1884                 local = NULL;
1885
1886         if (local) {
1887                 r = tar_strip_suffixes(local, &ll);
1888                 if (r < 0)
1889                         return log_error_errno(r, "Failed to strip tar suffixes: %m");
1890
1891                 local = ll;
1892
1893                 if (!machine_name_is_valid(local)) {
1894                         log_error("Local name %s is not a suitable machine name.", local);
1895                         return -EINVAL;
1896                 }
1897         }
1898
1899         r = sd_bus_message_new_method_call(
1900                         bus,
1901                         &m,
1902                         "org.freedesktop.import1",
1903                         "/org/freedesktop/import1",
1904                         "org.freedesktop.import1.Manager",
1905                         "PullTar");
1906         if (r < 0)
1907                 return bus_log_create_error(r);
1908
1909         r = sd_bus_message_append(
1910                         m,
1911                         "sssb",
1912                         remote,
1913                         local,
1914                         import_verify_to_string(arg_verify),
1915                         arg_force);
1916         if (r < 0)
1917                 return bus_log_create_error(r);
1918
1919         return pull_image_common(bus, m);
1920 }
1921
1922 static int pull_raw(int argc, char *argv[], void *userdata) {
1923         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1924         _cleanup_free_ char *l = NULL, *ll = NULL;
1925         const char *local, *remote;
1926         sd_bus *bus = userdata;
1927         int r;
1928
1929         assert(bus);
1930
1931         remote = argv[1];
1932         if (!http_url_is_valid(remote)) {
1933                 log_error("URL '%s' is not valid.", remote);
1934                 return -EINVAL;
1935         }
1936
1937         if (argc >= 3)
1938                 local = argv[2];
1939         else {
1940                 r = import_url_last_component(remote, &l);
1941                 if (r < 0)
1942                         return log_error_errno(r, "Failed to get final component of URL: %m");
1943
1944                 local = l;
1945         }
1946
1947         if (isempty(local) || streq(local, "-"))
1948                 local = NULL;
1949
1950         if (local) {
1951                 r = raw_strip_suffixes(local, &ll);
1952                 if (r < 0)
1953                         return log_error_errno(r, "Failed to strip tar suffixes: %m");
1954
1955                 local = ll;
1956
1957                 if (!machine_name_is_valid(local)) {
1958                         log_error("Local name %s is not a suitable machine name.", local);
1959                         return -EINVAL;
1960                 }
1961         }
1962
1963         r = sd_bus_message_new_method_call(
1964                         bus,
1965                         &m,
1966                         "org.freedesktop.import1",
1967                         "/org/freedesktop/import1",
1968                         "org.freedesktop.import1.Manager",
1969                         "PullRaw");
1970         if (r < 0)
1971                 return bus_log_create_error(r);
1972
1973         r = sd_bus_message_append(
1974                         m,
1975                         "sssb",
1976                         remote,
1977                         local,
1978                         import_verify_to_string(arg_verify),
1979                         arg_force);
1980         if (r < 0)
1981                 return bus_log_create_error(r);
1982
1983         return pull_image_common(bus, m);
1984 }
1985
1986 static int pull_dkr(int argc, char *argv[], void *userdata) {
1987         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1988         _cleanup_free_ char *l = NULL, *ll = NULL;
1989         const char *local, *remote, *tag;
1990         sd_bus *bus = userdata;
1991         int r;
1992
1993         if (!streq_ptr(arg_dkr_index_url, "no")) {
1994                 log_error("Imports from DKR do not support image verification, please pass --verify=no.");
1995                 return -EINVAL;
1996         }
1997
1998         remote = argv[1];
1999         tag = strchr(remote, ':');
2000         if (tag) {
2001                 remote = strndupa(remote, tag - remote);
2002                 tag++;
2003         }
2004
2005         if (!dkr_name_is_valid(remote)) {
2006                 log_error("DKR name '%s' is invalid.", remote);
2007                 return -EINVAL;
2008         }
2009         if (tag && !dkr_tag_is_valid(tag)) {
2010                 log_error("DKR tag '%s' is invalid.", remote);
2011                 return -EINVAL;
2012         }
2013
2014         if (argc >= 3)
2015                 local = argv[2];
2016         else {
2017                 local = strchr(remote, '/');
2018                 if (local)
2019                         local++;
2020                 else
2021                         local = remote;
2022         }
2023
2024         if (isempty(local) || streq(local, "-"))
2025                 local = NULL;
2026
2027         if (local) {
2028                 if (!machine_name_is_valid(local)) {
2029                         log_error("Local name %s is not a suitable machine name.", local);
2030                         return -EINVAL;
2031                 }
2032         }
2033
2034         r = sd_bus_message_new_method_call(
2035                         bus,
2036                         &m,
2037                         "org.freedesktop.import1",
2038                         "/org/freedesktop/import1",
2039                         "org.freedesktop.import1.Manager",
2040                         "PullDkr");
2041         if (r < 0)
2042                 return bus_log_create_error(r);
2043
2044         r = sd_bus_message_append(
2045                         m,
2046                         "sssssb",
2047                         arg_dkr_index_url,
2048                         remote,
2049                         tag,
2050                         local,
2051                         import_verify_to_string(arg_verify),
2052                         arg_force);
2053         if (r < 0)
2054                 return bus_log_create_error(r);
2055
2056         return pull_image_common(bus, m);
2057 }
2058
2059 typedef struct TransferInfo {
2060         uint32_t id;
2061         const char *type;
2062         const char *remote;
2063         const char *local;
2064 } TransferInfo;
2065
2066 static int compare_transfer_info(const void *a, const void *b) {
2067         const TransferInfo *x = a, *y = b;
2068
2069         return strcmp(x->local, y->local);
2070 }
2071
2072 static int list_transfers(int argc, char *argv[], void *userdata) {
2073         size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
2074         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2075         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2076         _cleanup_free_ TransferInfo *transfers = NULL;
2077         size_t n_transfers = 0, n_allocated = 0, j;
2078         const char *type, *remote, *local, *object;
2079         sd_bus *bus = userdata;
2080         uint32_t id, max_id = 0;
2081         int r;
2082
2083         pager_open_if_enabled();
2084
2085         r = sd_bus_call_method(
2086                                 bus,
2087                                 "org.freedesktop.import1",
2088                                 "/org/freedesktop/import1",
2089                                 "org.freedesktop.import1.Manager",
2090                                 "ListTransfers",
2091                                 &error,
2092                                 &reply,
2093                                 NULL);
2094         if (r < 0) {
2095                 log_error("Could not get transfers: %s", bus_error_message(&error, -r));
2096                 return r;
2097         }
2098
2099         r = sd_bus_message_enter_container(reply, 'a', "(ussso)");
2100         if (r < 0)
2101                 return bus_log_parse_error(r);
2102
2103         while ((r = sd_bus_message_read(reply, "(ussso)", &id, &type, &remote, &local, &object)) > 0) {
2104                 size_t l;
2105
2106                 if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
2107                         return log_oom();
2108
2109                 transfers[n_transfers].id = id;
2110                 transfers[n_transfers].type = type;
2111                 transfers[n_transfers].remote = remote;
2112                 transfers[n_transfers].local = local;
2113
2114                 l = strlen(type);
2115                 if (l > max_type)
2116                         max_type = l;
2117
2118                 l = strlen(remote);
2119                 if (l > max_remote)
2120                         max_remote = l;
2121
2122                 l = strlen(local);
2123                 if (l > max_local)
2124                         max_local = l;
2125
2126                 if (id > max_id)
2127                         max_id = id;
2128
2129                 n_transfers ++;
2130         }
2131         if (r < 0)
2132                 return bus_log_parse_error(r);
2133
2134         r = sd_bus_message_exit_container(reply);
2135         if (r < 0)
2136                 return bus_log_parse_error(r);
2137
2138         qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
2139
2140         if (arg_legend)
2141                 printf("%-*s %-*s %-*s %-*s\n",
2142                        (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
2143                        (int) max_type, "TYPE",
2144                        (int) max_local, "LOCAL",
2145                        (int) max_remote, "REMOTE");
2146
2147         for (j = 0; j < n_transfers; j++)
2148                 printf("%*" PRIu32 " %-*s %-*s %-*s\n",
2149                        (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
2150                        (int) max_type, transfers[j].type,
2151                        (int) max_local, transfers[j].local,
2152                        (int) max_remote, transfers[j].remote);
2153
2154         if (arg_legend)
2155                 printf("\n%zu transfers listed.\n", n_transfers);
2156
2157         return 0;
2158 }
2159
2160 static int cancel_transfer(int argc, char *argv[], void *userdata) {
2161         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2162         sd_bus *bus = userdata;
2163         int r, i;
2164
2165         assert(bus);
2166
2167         polkit_agent_open_if_enabled();
2168
2169         for (i = 1; i < argc; i++) {
2170                 uint32_t id;
2171
2172                 r = safe_atou32(argv[i], &id);
2173                 if (r < 0)
2174                         return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
2175
2176                 r = sd_bus_call_method(
2177                                 bus,
2178                                 "org.freedesktop.import1",
2179                                 "/org/freedesktop/import1",
2180                                 "org.freedesktop.import1.Manager",
2181                                 "CancelTransfer",
2182                                 &error,
2183                                 NULL,
2184                                 "u", id);
2185                 if (r < 0) {
2186                         log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
2187                         return r;
2188                 }
2189         }
2190
2191         return 0;
2192 }
2193
2194 static int help(int argc, char *argv[], void *userdata) {
2195
2196         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2197                "Send control commands to or query the virtual machine and container\n"
2198                "registration manager.\n\n"
2199                "  -h --help                   Show this help\n"
2200                "     --version                Show package version\n"
2201                "     --no-pager               Do not pipe output into a pager\n"
2202                "     --no-legend              Do not show the headers and footers\n"
2203                "     --no-ask-password        Do not ask for system passwords\n"
2204                "  -H --host=[USER@]HOST       Operate on remote host\n"
2205                "  -M --machine=CONTAINER      Operate on local container\n"
2206                "  -p --property=NAME          Show only properties by this name\n"
2207                "  -q --quiet                  Suppress output\n"
2208                "  -a --all                    Show all properties, including empty ones\n"
2209                "  -l --full                   Do not ellipsize output\n"
2210                "     --kill-who=WHO           Who to send signal to\n"
2211                "  -s --signal=SIGNAL          Which signal to send\n"
2212                "     --read-only              Create read-only bind mount\n"
2213                "     --mkdir                  Create directory before bind mounting, if missing\n"
2214                "  -n --lines=INTEGER          Number of journal entries to show\n"
2215                "  -o --output=STRING          Change journal output mode (short,\n"
2216                "                              short-monotonic, verbose, export, json,\n"
2217                "                              json-pretty, json-sse, cat)\n"
2218                "      --verify=MODE           Verification mode for downloaded images (no,\n"
2219                "                              checksum, signature)\n"
2220                "      --force                 Download image even if already exists\n"
2221                "      --dkr-index-url=URL     Specify the index URL to use for DKR image\n"
2222                "                              downloads\n\n"
2223                "Machine Commands:\n"
2224                "  list                        List running VMs and containers\n"
2225                "  status NAME...              Show VM/container details\n"
2226                "  show NAME...                Show properties of one or more VMs/containers\n"
2227                "  start NAME...               Start container as a service\n"
2228                "  login NAME                  Get a login prompt on a container\n"
2229                "  enable NAME...              Enable automatic container start at boot\n"
2230                "  disable NAME...             Disable automatic container start at boot\n"
2231                "  poweroff NAME...            Power off one or more containers\n"
2232                "  reboot NAME...              Reboot one or more containers\n"
2233                "  terminate NAME...           Terminate one or more VMs/containers\n"
2234                "  kill NAME...                Send signal to processes of a VM/container\n"
2235                "  copy-to NAME PATH [PATH]    Copy files from the host to a container\n"
2236                "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n"
2237                "  bind NAME PATH [PATH]       Bind mount a path from the host into a container\n\n"
2238                "Image Commands:\n"
2239                "  list-images                 Show available container annd VM images\n"
2240                "  image-status NAME...        Show image details\n"
2241                "  show-image NAME...          Show properties of image\n"
2242                "  clone NAME NAME             Clone an image\n"
2243                "  rename NAME NAME            Rename an image\n"
2244                "  read-only NAME [BOOL]       Mark or unmark image read-only\n"
2245                "  remove NAME...              Remove an image\n\n"
2246                "Image Transfer Commands:\n"
2247                "  pull-tar URL [NAME]         Download a TAR container image\n"
2248                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"
2249                "  pull-dkr REMOTE [NAME]      Download a DKR container image\n"
2250                "  list-transfers              Show list of downloads in progress\n"
2251                "  cancel-transfer             Cancel a download\n"
2252                , program_invocation_short_name);
2253
2254         return 0;
2255 }
2256
2257 static int parse_argv(int argc, char *argv[]) {
2258
2259         enum {
2260                 ARG_VERSION = 0x100,
2261                 ARG_NO_PAGER,
2262                 ARG_NO_LEGEND,
2263                 ARG_KILL_WHO,
2264                 ARG_READ_ONLY,
2265                 ARG_MKDIR,
2266                 ARG_NO_ASK_PASSWORD,
2267                 ARG_VERIFY,
2268                 ARG_FORCE,
2269                 ARG_DKR_INDEX_URL,
2270         };
2271
2272         static const struct option options[] = {
2273                 { "help",            no_argument,       NULL, 'h'                 },
2274                 { "version",         no_argument,       NULL, ARG_VERSION         },
2275                 { "property",        required_argument, NULL, 'p'                 },
2276                 { "all",             no_argument,       NULL, 'a'                 },
2277                 { "full",            no_argument,       NULL, 'l'                 },
2278                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
2279                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
2280                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
2281                 { "signal",          required_argument, NULL, 's'                 },
2282                 { "host",            required_argument, NULL, 'H'                 },
2283                 { "machine",         required_argument, NULL, 'M'                 },
2284                 { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
2285                 { "mkdir",           no_argument,       NULL, ARG_MKDIR           },
2286                 { "quiet",           no_argument,       NULL, 'q'                 },
2287                 { "lines",           required_argument, NULL, 'n'                 },
2288                 { "output",          required_argument, NULL, 'o'                 },
2289                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
2290                 { "verify",          required_argument, NULL, ARG_VERIFY          },
2291                 { "force",           no_argument,       NULL, ARG_FORCE           },
2292                 { "dkr-index-url",   required_argument, NULL, ARG_DKR_INDEX_URL   },
2293                 {}
2294         };
2295
2296         int c, r;
2297
2298         assert(argc >= 0);
2299         assert(argv);
2300
2301         while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
2302
2303                 switch (c) {
2304
2305                 case 'h':
2306                         return help(0, NULL, NULL);
2307
2308                 case ARG_VERSION:
2309                         puts(PACKAGE_STRING);
2310                         puts(SYSTEMD_FEATURES);
2311                         return 0;
2312
2313                 case 'p':
2314                         r = strv_extend(&arg_property, optarg);
2315                         if (r < 0)
2316                                 return log_oom();
2317
2318                         /* If the user asked for a particular
2319                          * property, show it to him, even if it is
2320                          * empty. */
2321                         arg_all = true;
2322                         break;
2323
2324                 case 'a':
2325                         arg_all = true;
2326                         break;
2327
2328                 case 'l':
2329                         arg_full = true;
2330                         break;
2331
2332                 case 'n':
2333                         if (safe_atou(optarg, &arg_lines) < 0) {
2334                                 log_error("Failed to parse lines '%s'", optarg);
2335                                 return -EINVAL;
2336                         }
2337                         break;
2338
2339                 case 'o':
2340                         arg_output = output_mode_from_string(optarg);
2341                         if (arg_output < 0) {
2342                                 log_error("Unknown output '%s'.", optarg);
2343                                 return -EINVAL;
2344                         }
2345                         break;
2346
2347                 case ARG_NO_PAGER:
2348                         arg_no_pager = true;
2349                         break;
2350
2351                 case ARG_NO_LEGEND:
2352                         arg_legend = false;
2353                         break;
2354
2355                 case ARG_KILL_WHO:
2356                         arg_kill_who = optarg;
2357                         break;
2358
2359                 case 's':
2360                         arg_signal = signal_from_string_try_harder(optarg);
2361                         if (arg_signal < 0) {
2362                                 log_error("Failed to parse signal string %s.", optarg);
2363                                 return -EINVAL;
2364                         }
2365                         break;
2366
2367                 case ARG_NO_ASK_PASSWORD:
2368                         arg_ask_password = false;
2369                         break;
2370
2371                 case 'H':
2372                         arg_transport = BUS_TRANSPORT_REMOTE;
2373                         arg_host = optarg;
2374                         break;
2375
2376                 case 'M':
2377                         arg_transport = BUS_TRANSPORT_MACHINE;
2378                         arg_host = optarg;
2379                         break;
2380
2381                 case ARG_READ_ONLY:
2382                         arg_read_only = true;
2383                         break;
2384
2385                 case ARG_MKDIR:
2386                         arg_mkdir = true;
2387                         break;
2388
2389                 case 'q':
2390                         arg_quiet = true;
2391                         break;
2392
2393                 case ARG_VERIFY:
2394                         arg_verify = import_verify_from_string(optarg);
2395                         if (arg_verify < 0) {
2396                                 log_error("Failed to parse --verify= setting: %s", optarg);
2397                                 return -EINVAL;
2398                         }
2399                         break;
2400
2401                 case ARG_FORCE:
2402                         arg_force = true;
2403                         break;
2404
2405                 case ARG_DKR_INDEX_URL:
2406                         if (!http_url_is_valid(optarg)) {
2407                                 log_error("Index URL is invalid: %s", optarg);
2408                                 return -EINVAL;
2409                         }
2410
2411                         arg_dkr_index_url = optarg;
2412                         break;
2413
2414                 case '?':
2415                         return -EINVAL;
2416
2417                 default:
2418                         assert_not_reached("Unhandled option");
2419                 }
2420
2421         return 1;
2422 }
2423
2424 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
2425
2426         static const Verb verbs[] = {
2427                 { "help",            VERB_ANY, VERB_ANY, 0,            help              },
2428                 { "list",            VERB_ANY, 1,        VERB_DEFAULT, list_machines     },
2429                 { "list-images",     VERB_ANY, 1,        0,            list_images       },
2430                 { "status",          2,        VERB_ANY, 0,            show_machine      },
2431                 { "image-status",    2,        VERB_ANY, 0,            show_image        },
2432                 { "show",            VERB_ANY, VERB_ANY, 0,            show_machine      },
2433                 { "show-image",      VERB_ANY, VERB_ANY, 0,            show_image        },
2434                 { "terminate",       2,        VERB_ANY, 0,            terminate_machine },
2435                 { "reboot",          2,        VERB_ANY, 0,            reboot_machine    },
2436                 { "poweroff",        2,        VERB_ANY, 0,            poweroff_machine  },
2437                 { "kill",            2,        VERB_ANY, 0,            kill_machine      },
2438                 { "login",           2,        2,        0,            login_machine     },
2439                 { "bind",            3,        4,        0,            bind_mount        },
2440                 { "copy-to",         3,        4,        0,            copy_files        },
2441                 { "copy-from",       3,        4,        0,            copy_files        },
2442                 { "remove",          2,        VERB_ANY, 0,            remove_image      },
2443                 { "rename",          3,        3,        0,            rename_image      },
2444                 { "clone",           3,        3,        0,            clone_image       },
2445                 { "read-only",       2,        3,        0,            read_only_image   },
2446                 { "start",           2,        VERB_ANY, 0,            start_machine     },
2447                 { "enable",          2,        VERB_ANY, 0,            enable_machine    },
2448                 { "disable",         2,        VERB_ANY, 0,            enable_machine    },
2449                 { "pull-tar",        2,        3,        0,            pull_tar          },
2450                 { "pull-raw",        2,        3,        0,            pull_raw          },
2451                 { "pull-dkr",        2,        3,        0,            pull_dkr          },
2452                 { "list-transfers",  VERB_ANY, 1,        0,            list_transfers    },
2453                 { "cancel-transfer", 2,        VERB_ANY, 0,            cancel_transfer   },
2454                 {}
2455         };
2456
2457         return dispatch_verb(argc, argv, verbs, bus);
2458 }
2459
2460 int main(int argc, char*argv[]) {
2461         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
2462         int r;
2463
2464         setlocale(LC_ALL, "");
2465         log_parse_environment();
2466         log_open();
2467
2468         r = parse_argv(argc, argv);
2469         if (r <= 0)
2470                 goto finish;
2471
2472         r = bus_open_transport(arg_transport, arg_host, false, &bus);
2473         if (r < 0) {
2474                 log_error_errno(r, "Failed to create bus connection: %m");
2475                 goto finish;
2476         }
2477
2478         r = machinectl_main(argc, argv, bus);
2479
2480 finish:
2481         pager_close();
2482         polkit_agent_close();
2483
2484         strv_free(arg_property);
2485
2486         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2487 }