chiark / gitweb /
ec403e8f33482df5404d2dde1a6af6ead2e10cef
[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         sigset_t mask;
1359         char last_char = 0;
1360         bool machine_died;
1361
1362         assert(bus);
1363
1364         if (arg_transport != BUS_TRANSPORT_LOCAL &&
1365             arg_transport != BUS_TRANSPORT_MACHINE) {
1366                 log_error("Login only supported on local machines.");
1367                 return -ENOTSUP;
1368         }
1369
1370         polkit_agent_open_if_enabled();
1371
1372         r = sd_event_default(&event);
1373         if (r < 0)
1374                 return log_error_errno(r, "Failed to get event loop: %m");
1375
1376         r = sd_bus_attach_event(bus, event, 0);
1377         if (r < 0)
1378                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1379
1380         match = strappenda("type='signal',"
1381                            "sender='org.freedesktop.machine1',"
1382                            "path='/org/freedesktop/machine1',",
1383                            "interface='org.freedesktop.machine1.Manager',"
1384                            "member='MachineRemoved',"
1385                            "arg0='",
1386                            argv[1],
1387                            "'");
1388
1389         r = sd_bus_add_match(bus, &slot, match, on_machine_removed, &forward);
1390         if (r < 0)
1391                 return log_error_errno(r, "Failed to add machine removal match: %m");
1392
1393         r = sd_bus_message_new_method_call(bus,
1394                                            &m,
1395                                            "org.freedesktop.machine1",
1396                                            "/org/freedesktop/machine1",
1397                                            "org.freedesktop.machine1.Manager",
1398                                            "OpenMachineLogin");
1399         if (r < 0)
1400                 return bus_log_create_error(r);
1401
1402         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1403         if (r < 0)
1404                 return bus_log_create_error(r);
1405
1406         r = sd_bus_message_append(m, "s", argv[1]);
1407         if (r < 0)
1408                 return bus_log_create_error(r);
1409
1410         r = sd_bus_call(bus, m, 0, &error, &reply);
1411         if (r < 0) {
1412                 log_error("Failed to get machine PTY: %s", bus_error_message(&error, -r));
1413                 return r;
1414         }
1415
1416         r = sd_bus_message_read(reply, "hs", &master, &pty);
1417         if (r < 0)
1418                 return bus_log_parse_error(r);
1419
1420         assert_se(sigemptyset(&mask) == 0);
1421         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
1422         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
1423
1424         log_info("Connected to machine %s. Press ^] three times within 1s to exit session.", argv[1]);
1425
1426         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1427         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1428
1429         r = pty_forward_new(event, master, true, &forward);
1430         if (r < 0)
1431                 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1432
1433         r = sd_event_loop(event);
1434         if (r < 0)
1435                 return log_error_errno(r, "Failed to run event loop: %m");
1436
1437         pty_forward_get_last_char(forward, &last_char);
1438         machine_died = pty_forward_get_ignore_vhangup(forward) == 0;
1439
1440         forward = pty_forward_free(forward);
1441
1442         if (last_char != '\n')
1443                 fputc('\n', stdout);
1444
1445         if (machine_died)
1446                 log_info("Machine %s terminated.", argv[1]);
1447         else
1448                 log_info("Connection to machine %s terminated.", argv[1]);
1449
1450         sd_event_get_exit_code(event, &ret);
1451         return ret;
1452 }
1453
1454 static int remove_image(int argc, char *argv[], void *userdata) {
1455         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1456         sd_bus *bus = userdata;
1457         int r, i;
1458
1459         assert(bus);
1460
1461         polkit_agent_open_if_enabled();
1462
1463         for (i = 1; i < argc; i++) {
1464                 r = sd_bus_call_method(
1465                                 bus,
1466                                 "org.freedesktop.machine1",
1467                                 "/org/freedesktop/machine1",
1468                                 "org.freedesktop.machine1.Manager",
1469                                 "RemoveImage",
1470                                 &error,
1471                                 NULL,
1472                                 "s", argv[i]);
1473                 if (r < 0) {
1474                         log_error("Could not remove image: %s", bus_error_message(&error, -r));
1475                         return r;
1476                 }
1477         }
1478
1479         return 0;
1480 }
1481
1482 static int rename_image(int argc, char *argv[], void *userdata) {
1483         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1484         sd_bus *bus = userdata;
1485         int r;
1486
1487         polkit_agent_open_if_enabled();
1488
1489         r = sd_bus_call_method(
1490                         bus,
1491                         "org.freedesktop.machine1",
1492                         "/org/freedesktop/machine1",
1493                         "org.freedesktop.machine1.Manager",
1494                         "RenameImage",
1495                         &error,
1496                         NULL,
1497                         "ss", argv[1], argv[2]);
1498         if (r < 0) {
1499                 log_error("Could not rename image: %s", bus_error_message(&error, -r));
1500                 return r;
1501         }
1502
1503         return 0;
1504 }
1505
1506 static int clone_image(int argc, char *argv[], void *userdata) {
1507         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1508         sd_bus *bus = userdata;
1509         int r;
1510
1511         polkit_agent_open_if_enabled();
1512
1513         r = sd_bus_call_method(
1514                         bus,
1515                         "org.freedesktop.machine1",
1516                         "/org/freedesktop/machine1",
1517                         "org.freedesktop.machine1.Manager",
1518                         "CloneImage",
1519                         &error,
1520                         NULL,
1521                         "ssb", argv[1], argv[2], arg_read_only);
1522         if (r < 0) {
1523                 log_error("Could not clone image: %s", bus_error_message(&error, -r));
1524                 return r;
1525         }
1526
1527         return 0;
1528 }
1529
1530 static int read_only_image(int argc, char *argv[], void *userdata) {
1531         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1532         sd_bus *bus = userdata;
1533         int b = true, r;
1534
1535         if (argc > 2) {
1536                 b = parse_boolean(argv[2]);
1537                 if (b < 0) {
1538                         log_error("Failed to parse boolean argument: %s", argv[2]);
1539                         return -EINVAL;
1540                 }
1541         }
1542
1543         polkit_agent_open_if_enabled();
1544
1545         r = sd_bus_call_method(
1546                         bus,
1547                         "org.freedesktop.machine1",
1548                         "/org/freedesktop/machine1",
1549                         "org.freedesktop.machine1.Manager",
1550                         "MarkImageReadOnly",
1551                         &error,
1552                         NULL,
1553                         "sb", argv[1], b);
1554         if (r < 0) {
1555                 log_error("Could not mark image read-only: %s", bus_error_message(&error, -r));
1556                 return r;
1557         }
1558
1559         return 0;
1560 }
1561
1562 static int start_machine(int argc, char *argv[], void *userdata) {
1563         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1564         _cleanup_(bus_wait_for_jobs_freep) BusWaitForJobs *w = NULL;
1565         sd_bus *bus = userdata;
1566         int r, i;
1567
1568         assert(bus);
1569
1570         polkit_agent_open_if_enabled();
1571
1572         r = bus_wait_for_jobs_new(bus, &w);
1573         if (r < 0)
1574                 return log_oom();
1575
1576         for (i = 1; i < argc; i++) {
1577                 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1578                 _cleanup_free_ char *e = NULL, *unit = NULL;
1579                 const char *object;
1580
1581                 if (!machine_name_is_valid(argv[i])) {
1582                         log_error("Invalid machine name %s.", argv[i]);
1583                         return -EINVAL;
1584                 }
1585
1586                 e = unit_name_escape(argv[i]);
1587                 if (!e)
1588                         return log_oom();
1589
1590                 unit = unit_name_build("systemd-nspawn", e, ".service");
1591                 if (!unit)
1592                         return log_oom();
1593
1594                 r = sd_bus_message_new_method_call(
1595                                 bus,
1596                                 &m,
1597                                 "org.freedesktop.systemd1",
1598                                 "/org/freedesktop/systemd1",
1599                                 "org.freedesktop.systemd1.Manager",
1600                                 "StartUnit");
1601                 if (r < 0)
1602                         return bus_log_create_error(r);
1603
1604                 r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1605                 if (r < 0)
1606                         return bus_log_create_error(r);
1607
1608                 r = sd_bus_message_append(m, "ss", unit, "fail");
1609                 if (r < 0)
1610                         return bus_log_create_error(r);
1611
1612                 r = sd_bus_call(bus, m, 0, &error, &reply);
1613                 if (r < 0) {
1614                         log_error("Failed to start unit: %s", bus_error_message(&error, -r));
1615                         return r;
1616                 }
1617
1618                 r = sd_bus_message_read(reply, "o", &object);
1619                 if (r < 0)
1620                         return bus_log_parse_error(r);
1621
1622                 r = bus_wait_for_jobs_add(w, object);
1623                 if (r < 0)
1624                         return log_oom();
1625         }
1626
1627         r = bus_wait_for_jobs(w, arg_quiet);
1628         if (r < 0)
1629                 return r;
1630
1631         return 0;
1632 }
1633
1634 static int enable_machine(int argc, char *argv[], void *userdata) {
1635         _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1636         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1637         int carries_install_info = 0;
1638         const char *method = NULL;
1639         sd_bus *bus = userdata;
1640         int r, i;
1641
1642         assert(bus);
1643
1644         polkit_agent_open_if_enabled();
1645
1646         method = streq(argv[0], "enable") ? "EnableUnitFiles" : "DisableUnitFiles";
1647
1648         r = sd_bus_message_new_method_call(
1649                         bus,
1650                         &m,
1651                         "org.freedesktop.systemd1",
1652                         "/org/freedesktop/systemd1",
1653                         "org.freedesktop.systemd1.Manager",
1654                         method);
1655         if (r < 0)
1656                 return bus_log_create_error(r);
1657
1658         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1659         if (r < 0)
1660                 return bus_log_create_error(r);
1661
1662         r = sd_bus_message_open_container(m, 'a', "s");
1663         if (r < 0)
1664                 return bus_log_create_error(r);
1665
1666         for (i = 1; i < argc; i++) {
1667                 _cleanup_free_ char *e = NULL, *unit = NULL;
1668
1669                 if (!machine_name_is_valid(argv[i])) {
1670                         log_error("Invalid machine name %s.", argv[i]);
1671                         return -EINVAL;
1672                 }
1673
1674                 e = unit_name_escape(argv[i]);
1675                 if (!e)
1676                         return log_oom();
1677
1678                 unit = unit_name_build("systemd-nspawn", e, ".service");
1679                 if (!unit)
1680                         return log_oom();
1681
1682                 r = sd_bus_message_append(m, "s", unit);
1683                 if (r < 0)
1684                         return bus_log_create_error(r);
1685         }
1686
1687         r = sd_bus_message_close_container(m);
1688         if (r < 0)
1689                 return bus_log_create_error(r);
1690
1691         if (streq(argv[0], "enable"))
1692                 r = sd_bus_message_append(m, "bb", false, false);
1693         else
1694                 r = sd_bus_message_append(m, "b", false);
1695         if (r < 0)
1696                 return bus_log_create_error(r);
1697
1698         r = sd_bus_call(bus, m, 0, &error, &reply);
1699         if (r < 0) {
1700                 log_error("Failed to enable or disable unit: %s", bus_error_message(&error, -r));
1701                 return r;
1702         }
1703
1704         if (streq(argv[0], "enable")) {
1705                 r = sd_bus_message_read(reply, "b", carries_install_info);
1706                 if (r < 0)
1707                         return bus_log_parse_error(r);
1708         }
1709
1710         r = bus_deserialize_and_dump_unit_file_changes(reply, arg_quiet);
1711         if (r < 0)
1712                 return r;
1713
1714         m = sd_bus_message_unref(m);
1715
1716         r = sd_bus_message_new_method_call(
1717                         bus,
1718                         &m,
1719                         "org.freedesktop.systemd1",
1720                         "/org/freedesktop/systemd1",
1721                         "org.freedesktop.systemd1.Manager",
1722                         "Reload");
1723         if (r < 0)
1724                 return bus_log_create_error(r);
1725
1726         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1727         if (r < 0)
1728                 return bus_log_create_error(r);
1729
1730         r = sd_bus_call(bus, m, 0, &error, NULL);
1731         if (r < 0) {
1732                 log_error("Failed to reload daemon: %s", bus_error_message(&error, -r));
1733                 return r;
1734         }
1735
1736         return 0;
1737 }
1738
1739 typedef struct PullContext {
1740         const char *path;
1741         int result;
1742 } PullContext;
1743
1744 static int match_log_message(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1745         PullContext *c = userdata;
1746         const char *line;
1747         unsigned priority;
1748         int r;
1749
1750         assert(bus);
1751         assert(m);
1752
1753         r = sd_bus_message_read(m, "us", &priority, &line);
1754         if (r < 0) {
1755                 bus_log_parse_error(r);
1756                 return 0;
1757         }
1758
1759         if (!streq_ptr(c->path, sd_bus_message_get_path(m)))
1760                 return 0;
1761
1762         if (arg_quiet && LOG_PRI(priority) >= LOG_INFO)
1763                 return 0;
1764
1765         log_full(priority, "%s", line);
1766         return 0;
1767 }
1768
1769 static int match_transfer_removed(sd_bus *bus, sd_bus_message *m, void *userdata, sd_bus_error *error) {
1770         PullContext *c = userdata;
1771         const char *path, *result;
1772         uint32_t id;
1773         int r;
1774
1775         assert(bus);
1776         assert(m);
1777         assert(c);
1778
1779         r = sd_bus_message_read(m, "uos", &id, &path, &result);
1780         if (r < 0) {
1781                 bus_log_parse_error(r);
1782                 return 0;
1783         }
1784
1785         if (!streq_ptr(c->path, path))
1786                 return 0;
1787
1788         c->result = streq_ptr(result, "done");
1789         return 0;
1790 }
1791
1792 static int pull_image_common(sd_bus *bus, sd_bus_message *m) {
1793         _cleanup_bus_slot_unref_ sd_bus_slot *slot_job_removed = NULL, *slot_log_message = NULL;
1794         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1795         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1796         PullContext c = {
1797                 .result = -1,
1798         };
1799         uint32_t id;
1800         int r;
1801
1802         assert(bus);
1803         assert(m);
1804
1805         polkit_agent_open_if_enabled();
1806
1807         r = sd_bus_message_set_allow_interactive_authorization(m, arg_ask_password);
1808         if (r < 0)
1809                 return bus_log_create_error(r);
1810
1811         r = sd_bus_add_match(
1812                         bus,
1813                         &slot_job_removed,
1814                         "type='signal',"
1815                         "sender='org.freedesktop.import1',"
1816                         "interface='org.freedesktop.import1.Manager',"
1817                         "member='TransferRemoved',"
1818                         "path='/org/freedesktop/import1'",
1819                         match_transfer_removed, &c);
1820         if (r < 0)
1821                 return log_error_errno(r, "Failed to install match: %m");
1822
1823         r = sd_bus_add_match(
1824                         bus,
1825                         &slot_log_message,
1826                         "type='signal',"
1827                         "sender='org.freedesktop.import1',"
1828                         "interface='org.freedesktop.import1.Transfer',"
1829                         "member='LogMessage'",
1830                         match_log_message, &c);
1831         if (r < 0)
1832                 return log_error_errno(r, "Failed to install match: %m");
1833
1834         r = sd_bus_call(bus, m, 0, &error, &reply);
1835         if (r < 0) {
1836                 log_error("Failed pull image: %s", bus_error_message(&error, -r));
1837                 return r;
1838         }
1839
1840         r = sd_bus_message_read(reply, "uo", &id, &c.path);
1841         if (r < 0)
1842                 return bus_log_parse_error(r);
1843
1844         for (;;) {
1845                 r = sd_bus_process(bus, NULL);
1846                 if (r < 0)
1847                         return r;
1848
1849                 /* The match sets this to NULL when we are done */
1850                 if (c.result >= 0)
1851                         break;
1852
1853                 r = sd_bus_wait(bus, (uint64_t) -1);
1854                 if (r < 0)
1855                         return r;
1856         }
1857
1858         return c.result ? 0 : -EINVAL;
1859 }
1860
1861 static int pull_tar(int argc, char *argv[], void *userdata) {
1862         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1863         _cleanup_free_ char *l = NULL, *ll = NULL;
1864         const char *local, *remote;
1865         sd_bus *bus = userdata;
1866         int r;
1867
1868         assert(bus);
1869
1870         remote = argv[1];
1871         if (!http_url_is_valid(remote)) {
1872                 log_error("URL '%s' is not valid.", remote);
1873                 return -EINVAL;
1874         }
1875
1876         if (argc >= 3)
1877                 local = argv[2];
1878         else {
1879                 r = import_url_last_component(remote, &l);
1880                 if (r < 0)
1881                         return log_error_errno(r, "Failed to get final component of URL: %m");
1882
1883                 local = l;
1884         }
1885
1886         if (isempty(local) || streq(local, "-"))
1887                 local = NULL;
1888
1889         if (local) {
1890                 r = tar_strip_suffixes(local, &ll);
1891                 if (r < 0)
1892                         return log_error_errno(r, "Failed to strip tar suffixes: %m");
1893
1894                 local = ll;
1895
1896                 if (!machine_name_is_valid(local)) {
1897                         log_error("Local name %s is not a suitable machine name.", local);
1898                         return -EINVAL;
1899                 }
1900         }
1901
1902         r = sd_bus_message_new_method_call(
1903                         bus,
1904                         &m,
1905                         "org.freedesktop.import1",
1906                         "/org/freedesktop/import1",
1907                         "org.freedesktop.import1.Manager",
1908                         "PullTar");
1909         if (r < 0)
1910                 return bus_log_create_error(r);
1911
1912         r = sd_bus_message_append(
1913                         m,
1914                         "sssb",
1915                         remote,
1916                         local,
1917                         import_verify_to_string(arg_verify),
1918                         arg_force);
1919         if (r < 0)
1920                 return bus_log_create_error(r);
1921
1922         return pull_image_common(bus, m);
1923 }
1924
1925 static int pull_raw(int argc, char *argv[], void *userdata) {
1926         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1927         _cleanup_free_ char *l = NULL, *ll = NULL;
1928         const char *local, *remote;
1929         sd_bus *bus = userdata;
1930         int r;
1931
1932         assert(bus);
1933
1934         remote = argv[1];
1935         if (!http_url_is_valid(remote)) {
1936                 log_error("URL '%s' is not valid.", remote);
1937                 return -EINVAL;
1938         }
1939
1940         if (argc >= 3)
1941                 local = argv[2];
1942         else {
1943                 r = import_url_last_component(remote, &l);
1944                 if (r < 0)
1945                         return log_error_errno(r, "Failed to get final component of URL: %m");
1946
1947                 local = l;
1948         }
1949
1950         if (isempty(local) || streq(local, "-"))
1951                 local = NULL;
1952
1953         if (local) {
1954                 r = raw_strip_suffixes(local, &ll);
1955                 if (r < 0)
1956                         return log_error_errno(r, "Failed to strip tar suffixes: %m");
1957
1958                 local = ll;
1959
1960                 if (!machine_name_is_valid(local)) {
1961                         log_error("Local name %s is not a suitable machine name.", local);
1962                         return -EINVAL;
1963                 }
1964         }
1965
1966         r = sd_bus_message_new_method_call(
1967                         bus,
1968                         &m,
1969                         "org.freedesktop.import1",
1970                         "/org/freedesktop/import1",
1971                         "org.freedesktop.import1.Manager",
1972                         "PullRaw");
1973         if (r < 0)
1974                 return bus_log_create_error(r);
1975
1976         r = sd_bus_message_append(
1977                         m,
1978                         "sssb",
1979                         remote,
1980                         local,
1981                         import_verify_to_string(arg_verify),
1982                         arg_force);
1983         if (r < 0)
1984                 return bus_log_create_error(r);
1985
1986         return pull_image_common(bus, m);
1987 }
1988
1989 static int pull_dkr(int argc, char *argv[], void *userdata) {
1990         _cleanup_bus_message_unref_ sd_bus_message *m = NULL;
1991         _cleanup_free_ char *l = NULL, *ll = NULL;
1992         const char *local, *remote, *tag;
1993         sd_bus *bus = userdata;
1994         int r;
1995
1996         if (!streq_ptr(arg_dkr_index_url, "no")) {
1997                 log_error("Imports from DKR do not support image verification, please pass --verify=no.");
1998                 return -EINVAL;
1999         }
2000
2001         remote = argv[1];
2002         tag = strchr(remote, ':');
2003         if (tag) {
2004                 remote = strndupa(remote, tag - remote);
2005                 tag++;
2006         }
2007
2008         if (!dkr_name_is_valid(remote)) {
2009                 log_error("DKR name '%s' is invalid.", remote);
2010                 return -EINVAL;
2011         }
2012         if (tag && !dkr_tag_is_valid(tag)) {
2013                 log_error("DKR tag '%s' is invalid.", remote);
2014                 return -EINVAL;
2015         }
2016
2017         if (argc >= 3)
2018                 local = argv[2];
2019         else {
2020                 local = strchr(remote, '/');
2021                 if (local)
2022                         local++;
2023                 else
2024                         local = remote;
2025         }
2026
2027         if (isempty(local) || streq(local, "-"))
2028                 local = NULL;
2029
2030         if (local) {
2031                 if (!machine_name_is_valid(local)) {
2032                         log_error("Local name %s is not a suitable machine name.", local);
2033                         return -EINVAL;
2034                 }
2035         }
2036
2037         r = sd_bus_message_new_method_call(
2038                         bus,
2039                         &m,
2040                         "org.freedesktop.import1",
2041                         "/org/freedesktop/import1",
2042                         "org.freedesktop.import1.Manager",
2043                         "PullDkr");
2044         if (r < 0)
2045                 return bus_log_create_error(r);
2046
2047         r = sd_bus_message_append(
2048                         m,
2049                         "sssssb",
2050                         arg_dkr_index_url,
2051                         remote,
2052                         tag,
2053                         local,
2054                         import_verify_to_string(arg_verify),
2055                         arg_force);
2056         if (r < 0)
2057                 return bus_log_create_error(r);
2058
2059         return pull_image_common(bus, m);
2060 }
2061
2062 typedef struct TransferInfo {
2063         uint32_t id;
2064         const char *type;
2065         const char *remote;
2066         const char *local;
2067 } TransferInfo;
2068
2069 static int compare_transfer_info(const void *a, const void *b) {
2070         const TransferInfo *x = a, *y = b;
2071
2072         return strcmp(x->local, y->local);
2073 }
2074
2075 static int list_transfers(int argc, char *argv[], void *userdata) {
2076         size_t max_type = strlen("TYPE"), max_local = strlen("LOCAL"), max_remote = strlen("REMOTE");
2077         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
2078         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2079         _cleanup_free_ TransferInfo *transfers = NULL;
2080         size_t n_transfers = 0, n_allocated = 0, j;
2081         const char *type, *remote, *local, *object;
2082         sd_bus *bus = userdata;
2083         uint32_t id, max_id = 0;
2084         int r;
2085
2086         pager_open_if_enabled();
2087
2088         r = sd_bus_call_method(
2089                                 bus,
2090                                 "org.freedesktop.import1",
2091                                 "/org/freedesktop/import1",
2092                                 "org.freedesktop.import1.Manager",
2093                                 "ListTransfers",
2094                                 &error,
2095                                 &reply,
2096                                 NULL);
2097         if (r < 0) {
2098                 log_error("Could not get transfers: %s", bus_error_message(&error, -r));
2099                 return r;
2100         }
2101
2102         r = sd_bus_message_enter_container(reply, 'a', "(ussso)");
2103         if (r < 0)
2104                 return bus_log_parse_error(r);
2105
2106         while ((r = sd_bus_message_read(reply, "(ussso)", &id, &type, &remote, &local, &object)) > 0) {
2107                 size_t l;
2108
2109                 if (!GREEDY_REALLOC(transfers, n_allocated, n_transfers + 1))
2110                         return log_oom();
2111
2112                 transfers[n_transfers].id = id;
2113                 transfers[n_transfers].type = type;
2114                 transfers[n_transfers].remote = remote;
2115                 transfers[n_transfers].local = local;
2116
2117                 l = strlen(type);
2118                 if (l > max_type)
2119                         max_type = l;
2120
2121                 l = strlen(remote);
2122                 if (l > max_remote)
2123                         max_remote = l;
2124
2125                 l = strlen(local);
2126                 if (l > max_local)
2127                         max_local = l;
2128
2129                 if (id > max_id)
2130                         max_id = id;
2131
2132                 n_transfers ++;
2133         }
2134         if (r < 0)
2135                 return bus_log_parse_error(r);
2136
2137         r = sd_bus_message_exit_container(reply);
2138         if (r < 0)
2139                 return bus_log_parse_error(r);
2140
2141         qsort_safe(transfers, n_transfers, sizeof(TransferInfo), compare_transfer_info);
2142
2143         if (arg_legend)
2144                 printf("%-*s %-*s %-*s %-*s\n",
2145                        (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), "ID",
2146                        (int) max_type, "TYPE",
2147                        (int) max_local, "LOCAL",
2148                        (int) max_remote, "REMOTE");
2149
2150         for (j = 0; j < n_transfers; j++)
2151                 printf("%*" PRIu32 " %-*s %-*s %-*s\n",
2152                        (int) MAX(2U, DECIMAL_STR_WIDTH(max_id)), transfers[j].id,
2153                        (int) max_type, transfers[j].type,
2154                        (int) max_local, transfers[j].local,
2155                        (int) max_remote, transfers[j].remote);
2156
2157         if (arg_legend)
2158                 printf("\n%zu transfers listed.\n", n_transfers);
2159
2160         return 0;
2161 }
2162
2163 static int cancel_transfer(int argc, char *argv[], void *userdata) {
2164         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
2165         sd_bus *bus = userdata;
2166         int r, i;
2167
2168         assert(bus);
2169
2170         polkit_agent_open_if_enabled();
2171
2172         for (i = 1; i < argc; i++) {
2173                 uint32_t id;
2174
2175                 r = safe_atou32(argv[i], &id);
2176                 if (r < 0)
2177                         return log_error_errno(r, "Failed to parse transfer id: %s", argv[i]);
2178
2179                 r = sd_bus_call_method(
2180                                 bus,
2181                                 "org.freedesktop.import1",
2182                                 "/org/freedesktop/import1",
2183                                 "org.freedesktop.import1.Manager",
2184                                 "CancelTransfer",
2185                                 &error,
2186                                 NULL,
2187                                 "u", id);
2188                 if (r < 0) {
2189                         log_error("Could not cancel transfer: %s", bus_error_message(&error, -r));
2190                         return r;
2191                 }
2192         }
2193
2194         return 0;
2195 }
2196
2197 static int help(int argc, char *argv[], void *userdata) {
2198
2199         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
2200                "Send control commands to or query the virtual machine and container\n"
2201                "registration manager.\n\n"
2202                "  -h --help                   Show this help\n"
2203                "     --version                Show package version\n"
2204                "     --no-pager               Do not pipe output into a pager\n"
2205                "     --no-legend              Do not show the headers and footers\n"
2206                "     --no-ask-password        Do not ask for system passwords\n"
2207                "  -H --host=[USER@]HOST       Operate on remote host\n"
2208                "  -M --machine=CONTAINER      Operate on local container\n"
2209                "  -p --property=NAME          Show only properties by this name\n"
2210                "  -q --quiet                  Suppress output\n"
2211                "  -a --all                    Show all properties, including empty ones\n"
2212                "  -l --full                   Do not ellipsize output\n"
2213                "     --kill-who=WHO           Who to send signal to\n"
2214                "  -s --signal=SIGNAL          Which signal to send\n"
2215                "     --read-only              Create read-only bind mount\n"
2216                "     --mkdir                  Create directory before bind mounting, if missing\n"
2217                "  -n --lines=INTEGER          Number of journal entries to show\n"
2218                "  -o --output=STRING          Change journal output mode (short,\n"
2219                "                              short-monotonic, verbose, export, json,\n"
2220                "                              json-pretty, json-sse, cat)\n"
2221                "      --verify=MODE           Verification mode for downloaded images (no,\n"
2222                "                              checksum, signature)\n"
2223                "      --force                 Download image even if already exists\n"
2224                "      --dkr-index-url=URL     Specify the index URL to use for DKR image\n"
2225                "                              downloads\n\n"
2226                "Machine Commands:\n"
2227                "  list                        List running VMs and containers\n"
2228                "  status NAME...              Show VM/container details\n"
2229                "  show NAME...                Show properties of one or more VMs/containers\n"
2230                "  start NAME...               Start container as a service\n"
2231                "  login NAME                  Get a login prompt on a container\n"
2232                "  enable NAME...              Enable automatic container start at boot\n"
2233                "  disable NAME...             Disable automatic container start at boot\n"
2234                "  poweroff NAME...            Power off one or more containers\n"
2235                "  reboot NAME...              Reboot one or more containers\n"
2236                "  terminate NAME...           Terminate one or more VMs/containers\n"
2237                "  kill NAME...                Send signal to processes of a VM/container\n"
2238                "  copy-to NAME PATH [PATH]    Copy files from the host to a container\n"
2239                "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n"
2240                "  bind NAME PATH [PATH]       Bind mount a path from the host into a container\n\n"
2241                "Image Commands:\n"
2242                "  list-images                 Show available container annd VM images\n"
2243                "  image-status NAME...        Show image details\n"
2244                "  show-image NAME...          Show properties of image\n"
2245                "  clone NAME NAME             Clone an image\n"
2246                "  rename NAME NAME            Rename an image\n"
2247                "  read-only NAME [BOOL]       Mark or unmark image read-only\n"
2248                "  remove NAME...              Remove an image\n\n"
2249                "Image Transfer Commands:\n"
2250                "  pull-tar URL [NAME]         Download a TAR container image\n"
2251                "  pull-raw URL [NAME]         Download a RAW container or VM image\n"
2252                "  pull-dkr REMOTE [NAME]      Download a DKR container image\n"
2253                "  list-transfers              Show list of downloads in progress\n"
2254                "  cancel-transfer             Cancel a download\n"
2255                , program_invocation_short_name);
2256
2257         return 0;
2258 }
2259
2260 static int parse_argv(int argc, char *argv[]) {
2261
2262         enum {
2263                 ARG_VERSION = 0x100,
2264                 ARG_NO_PAGER,
2265                 ARG_NO_LEGEND,
2266                 ARG_KILL_WHO,
2267                 ARG_READ_ONLY,
2268                 ARG_MKDIR,
2269                 ARG_NO_ASK_PASSWORD,
2270                 ARG_VERIFY,
2271                 ARG_FORCE,
2272                 ARG_DKR_INDEX_URL,
2273         };
2274
2275         static const struct option options[] = {
2276                 { "help",            no_argument,       NULL, 'h'                 },
2277                 { "version",         no_argument,       NULL, ARG_VERSION         },
2278                 { "property",        required_argument, NULL, 'p'                 },
2279                 { "all",             no_argument,       NULL, 'a'                 },
2280                 { "full",            no_argument,       NULL, 'l'                 },
2281                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
2282                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
2283                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
2284                 { "signal",          required_argument, NULL, 's'                 },
2285                 { "host",            required_argument, NULL, 'H'                 },
2286                 { "machine",         required_argument, NULL, 'M'                 },
2287                 { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
2288                 { "mkdir",           no_argument,       NULL, ARG_MKDIR           },
2289                 { "quiet",           no_argument,       NULL, 'q'                 },
2290                 { "lines",           required_argument, NULL, 'n'                 },
2291                 { "output",          required_argument, NULL, 'o'                 },
2292                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
2293                 { "verify",          required_argument, NULL, ARG_VERIFY          },
2294                 { "force",           no_argument,       NULL, ARG_FORCE           },
2295                 { "dkr-index-url",   required_argument, NULL, ARG_DKR_INDEX_URL   },
2296                 {}
2297         };
2298
2299         int c, r;
2300
2301         assert(argc >= 0);
2302         assert(argv);
2303
2304         while ((c = getopt_long(argc, argv, "hp:als:H:M:qn:o:", options, NULL)) >= 0)
2305
2306                 switch (c) {
2307
2308                 case 'h':
2309                         return help(0, NULL, NULL);
2310
2311                 case ARG_VERSION:
2312                         puts(PACKAGE_STRING);
2313                         puts(SYSTEMD_FEATURES);
2314                         return 0;
2315
2316                 case 'p':
2317                         r = strv_extend(&arg_property, optarg);
2318                         if (r < 0)
2319                                 return log_oom();
2320
2321                         /* If the user asked for a particular
2322                          * property, show it to him, even if it is
2323                          * empty. */
2324                         arg_all = true;
2325                         break;
2326
2327                 case 'a':
2328                         arg_all = true;
2329                         break;
2330
2331                 case 'l':
2332                         arg_full = true;
2333                         break;
2334
2335                 case 'n':
2336                         if (safe_atou(optarg, &arg_lines) < 0) {
2337                                 log_error("Failed to parse lines '%s'", optarg);
2338                                 return -EINVAL;
2339                         }
2340                         break;
2341
2342                 case 'o':
2343                         arg_output = output_mode_from_string(optarg);
2344                         if (arg_output < 0) {
2345                                 log_error("Unknown output '%s'.", optarg);
2346                                 return -EINVAL;
2347                         }
2348                         break;
2349
2350                 case ARG_NO_PAGER:
2351                         arg_no_pager = true;
2352                         break;
2353
2354                 case ARG_NO_LEGEND:
2355                         arg_legend = false;
2356                         break;
2357
2358                 case ARG_KILL_WHO:
2359                         arg_kill_who = optarg;
2360                         break;
2361
2362                 case 's':
2363                         arg_signal = signal_from_string_try_harder(optarg);
2364                         if (arg_signal < 0) {
2365                                 log_error("Failed to parse signal string %s.", optarg);
2366                                 return -EINVAL;
2367                         }
2368                         break;
2369
2370                 case ARG_NO_ASK_PASSWORD:
2371                         arg_ask_password = false;
2372                         break;
2373
2374                 case 'H':
2375                         arg_transport = BUS_TRANSPORT_REMOTE;
2376                         arg_host = optarg;
2377                         break;
2378
2379                 case 'M':
2380                         arg_transport = BUS_TRANSPORT_MACHINE;
2381                         arg_host = optarg;
2382                         break;
2383
2384                 case ARG_READ_ONLY:
2385                         arg_read_only = true;
2386                         break;
2387
2388                 case ARG_MKDIR:
2389                         arg_mkdir = true;
2390                         break;
2391
2392                 case 'q':
2393                         arg_quiet = true;
2394                         break;
2395
2396                 case ARG_VERIFY:
2397                         arg_verify = import_verify_from_string(optarg);
2398                         if (arg_verify < 0) {
2399                                 log_error("Failed to parse --verify= setting: %s", optarg);
2400                                 return -EINVAL;
2401                         }
2402                         break;
2403
2404                 case ARG_FORCE:
2405                         arg_force = true;
2406                         break;
2407
2408                 case ARG_DKR_INDEX_URL:
2409                         if (!http_url_is_valid(optarg)) {
2410                                 log_error("Index URL is invalid: %s", optarg);
2411                                 return -EINVAL;
2412                         }
2413
2414                         arg_dkr_index_url = optarg;
2415                         break;
2416
2417                 case '?':
2418                         return -EINVAL;
2419
2420                 default:
2421                         assert_not_reached("Unhandled option");
2422                 }
2423
2424         return 1;
2425 }
2426
2427 static int machinectl_main(int argc, char *argv[], sd_bus *bus) {
2428
2429         static const Verb verbs[] = {
2430                 { "help",            VERB_ANY, VERB_ANY, 0,            help              },
2431                 { "list",            VERB_ANY, 1,        VERB_DEFAULT, list_machines     },
2432                 { "list-images",     VERB_ANY, 1,        0,            list_images       },
2433                 { "status",          2,        VERB_ANY, 0,            show_machine      },
2434                 { "image-status",    2,        VERB_ANY, 0,            show_image        },
2435                 { "show",            VERB_ANY, VERB_ANY, 0,            show_machine      },
2436                 { "show-image",      VERB_ANY, VERB_ANY, 0,            show_image        },
2437                 { "terminate",       2,        VERB_ANY, 0,            terminate_machine },
2438                 { "reboot",          2,        VERB_ANY, 0,            reboot_machine    },
2439                 { "poweroff",        2,        VERB_ANY, 0,            poweroff_machine  },
2440                 { "kill",            2,        VERB_ANY, 0,            kill_machine      },
2441                 { "login",           2,        2,        0,            login_machine     },
2442                 { "bind",            3,        4,        0,            bind_mount        },
2443                 { "copy-to",         3,        4,        0,            copy_files        },
2444                 { "copy-from",       3,        4,        0,            copy_files        },
2445                 { "remove",          2,        VERB_ANY, 0,            remove_image      },
2446                 { "rename",          3,        3,        0,            rename_image      },
2447                 { "clone",           3,        3,        0,            clone_image       },
2448                 { "read-only",       2,        3,        0,            read_only_image   },
2449                 { "start",           2,        VERB_ANY, 0,            start_machine     },
2450                 { "enable",          2,        VERB_ANY, 0,            enable_machine    },
2451                 { "disable",         2,        VERB_ANY, 0,            enable_machine    },
2452                 { "pull-tar",        2,        3,        0,            pull_tar          },
2453                 { "pull-raw",        2,        3,        0,            pull_raw          },
2454                 { "pull-dkr",        2,        3,        0,            pull_dkr          },
2455                 { "list-transfers",  VERB_ANY, 1,        0,            list_transfers    },
2456                 { "cancel-transfer", 2,        VERB_ANY, 0,            cancel_transfer   },
2457                 {}
2458         };
2459
2460         return dispatch_verb(argc, argv, verbs, bus);
2461 }
2462
2463 int main(int argc, char*argv[]) {
2464         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
2465         int r;
2466
2467         setlocale(LC_ALL, "");
2468         log_parse_environment();
2469         log_open();
2470
2471         r = parse_argv(argc, argv);
2472         if (r <= 0)
2473                 goto finish;
2474
2475         r = bus_open_transport(arg_transport, arg_host, false, &bus);
2476         if (r < 0) {
2477                 log_error_errno(r, "Failed to create bus connection: %m");
2478                 goto finish;
2479         }
2480
2481         r = machinectl_main(argc, argv, bus);
2482
2483 finish:
2484         pager_close();
2485         polkit_agent_close();
2486
2487         strv_free(arg_property);
2488
2489         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
2490 }