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