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