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