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