chiark / gitweb /
machined/machinectl: add logic to show list of available images
[elogind.git] / src / machine / machinectl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2013 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <sys/socket.h>
23 #include <unistd.h>
24 #include <errno.h>
25 #include <string.h>
26 #include <getopt.h>
27 #include <pwd.h>
28 #include <locale.h>
29 #include <fcntl.h>
30 #include <netinet/in.h>
31 #include <arpa/inet.h>
32 #include <net/if.h>
33 #include <sys/mount.h>
34 #include <libgen.h>
35
36 #include "sd-bus.h"
37 #include "log.h"
38 #include "util.h"
39 #include "macro.h"
40 #include "pager.h"
41 #include "bus-util.h"
42 #include "bus-error.h"
43 #include "build.h"
44 #include "strv.h"
45 #include "unit-name.h"
46 #include "cgroup-show.h"
47 #include "cgroup-util.h"
48 #include "ptyfwd.h"
49 #include "event-util.h"
50 #include "path-util.h"
51 #include "mkdir.h"
52 #include "copy.h"
53
54 static char **arg_property = NULL;
55 static bool arg_all = false;
56 static bool arg_full = false;
57 static bool arg_no_pager = false;
58 static bool arg_legend = true;
59 static const char *arg_kill_who = NULL;
60 static int arg_signal = SIGTERM;
61 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
62 static char *arg_host = NULL;
63 static bool arg_read_only = false;
64 static bool arg_mkdir = false;
65
66 static void pager_open_if_enabled(void) {
67
68         /* Cache result before we open the pager */
69         if (arg_no_pager)
70                 return;
71
72         pager_open(false);
73 }
74
75 static int list_machines(sd_bus *bus, char **args, unsigned n) {
76         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
77         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
78         const char *name, *class, *service, *object;
79         unsigned k = 0;
80         int r;
81
82         pager_open_if_enabled();
83
84         r = sd_bus_call_method(
85                                 bus,
86                                 "org.freedesktop.machine1",
87                                 "/org/freedesktop/machine1",
88                                 "org.freedesktop.machine1.Manager",
89                                 "ListMachines",
90                                 &error,
91                                 &reply,
92                                 "");
93         if (r < 0) {
94                 log_error("Could not get machines: %s", bus_error_message(&error, -r));
95                 return r;
96         }
97
98         if (arg_legend)
99                 printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
100
101         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
102         if (r < 0)
103                 return bus_log_parse_error(r);
104
105         while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
106                 printf("%-32s %-9s %-16s\n", name, class, service);
107
108                 k++;
109         }
110         if (r < 0)
111                 return bus_log_parse_error(r);
112
113         r = sd_bus_message_exit_container(reply);
114         if (r < 0)
115                 return bus_log_parse_error(r);
116
117         if (arg_legend)
118                 printf("\n%u machines listed.\n", k);
119
120         return 0;
121 }
122
123 typedef struct ImageInfo {
124         const char *name;
125         const char *type;
126         bool read_only;
127 } ImageInfo;
128
129 static int compare_image_info(const void *a, const void *b) {
130         const ImageInfo *x = a, *y = b;
131
132         return strcmp(x->name, y->name);
133 }
134
135 static int list_images(sd_bus *bus, char **args, unsigned n) {
136
137         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
138         size_t max_name = strlen("NAME"), max_type = strlen("TYPE");
139         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
140         _cleanup_free_ ImageInfo *images = NULL;
141         size_t n_images = 0, n_allocated = 0, j;
142         const char *name, *type, *object;
143         int read_only;
144         int r;
145
146         pager_open_if_enabled();
147
148         r = sd_bus_call_method(
149                                 bus,
150                                 "org.freedesktop.machine1",
151                                 "/org/freedesktop/machine1",
152                                 "org.freedesktop.machine1.Manager",
153                                 "ListImages",
154                                 &error,
155                                 &reply,
156                                 "");
157         if (r < 0) {
158                 log_error("Could not get images: %s", bus_error_message(&error, -r));
159                 return r;
160         }
161
162         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssbo)");
163         if (r < 0)
164                 return bus_log_parse_error(r);
165
166         while ((r = sd_bus_message_read(reply, "(ssbo)", &name, &type, &read_only, &object)) > 0) {
167
168                 if (name[0] == '.' && !arg_all)
169                         continue;
170
171                 if (!GREEDY_REALLOC(images, n_allocated, n_images + 1))
172                         return log_oom();
173
174                 images[n_images].name = name;
175                 images[n_images].type = type;
176                 images[n_images].read_only = read_only;
177
178                 if (strlen(name) > max_name)
179                         max_name = strlen(name);
180
181                 if (strlen(type) > max_type)
182                         max_type = strlen(type);
183
184                 n_images++;
185         }
186         if (r < 0)
187                 return bus_log_parse_error(r);
188
189         r = sd_bus_message_exit_container(reply);
190         if (r < 0)
191                 return bus_log_parse_error(r);
192
193         qsort_safe(images, n_images, sizeof(ImageInfo), compare_image_info);
194
195         if (arg_legend)
196                 printf("%-*s %-*s %-3s\n", (int) max_name, "NAME", (int) max_type, "TYPE", "RO");
197
198         for (j = 0; j < n_images; j++) {
199                 printf("%-*s %-*s %-3s\n",
200                        (int) max_name, images[j].name,
201                        (int) max_type, images[j].type,
202                        yes_no(images[j].read_only));
203         }
204
205         if (r < 0)
206                 return bus_log_parse_error(r);
207
208
209         if (arg_legend)
210                 printf("\n%zu images listed.\n", n_images);
211
212         return 0;
213 }
214
215 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
216         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
217         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
218         _cleanup_free_ char *path = NULL;
219         const char *cgroup;
220         int r, output_flags;
221         unsigned c;
222
223         assert(bus);
224         assert(unit);
225
226         if (arg_transport == BUS_TRANSPORT_REMOTE)
227                 return 0;
228
229         path = unit_dbus_path_from_name(unit);
230         if (!path)
231                 return log_oom();
232
233         r = sd_bus_get_property(
234                         bus,
235                         "org.freedesktop.systemd1",
236                         path,
237                         endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
238                         "ControlGroup",
239                         &error,
240                         &reply,
241                         "s");
242         if (r < 0) {
243                 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
244                 return r;
245         }
246
247         r = sd_bus_message_read(reply, "s", &cgroup);
248         if (r < 0)
249                 return bus_log_parse_error(r);
250
251         if (isempty(cgroup))
252                 return 0;
253
254         if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
255                 return 0;
256
257         output_flags =
258                 arg_all * OUTPUT_SHOW_ALL |
259                 arg_full * OUTPUT_FULL_WIDTH;
260
261         c = columns();
262         if (c > 18)
263                 c -= 18;
264         else
265                 c = 0;
266
267         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, output_flags);
268         return 0;
269 }
270
271 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
272         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
273         int r;
274
275         assert(bus);
276         assert(name);
277         assert(prefix);
278         assert(prefix2);
279
280         r = sd_bus_call_method(bus,
281                                "org.freedesktop.machine1",
282                                "/org/freedesktop/machine1",
283                                "org.freedesktop.machine1.Manager",
284                                "GetMachineAddresses",
285                                NULL,
286                                &reply,
287                                "s", name);
288         if (r < 0)
289                 return r;
290
291         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
292         if (r < 0)
293                 return bus_log_parse_error(r);
294
295         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
296                 int family;
297                 const void *a;
298                 size_t sz;
299                 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
300
301                 r = sd_bus_message_read(reply, "i", &family);
302                 if (r < 0)
303                         return bus_log_parse_error(r);
304
305                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
306                 if (r < 0)
307                         return bus_log_parse_error(r);
308
309                 fputs(prefix, stdout);
310                 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
311                 if (family == AF_INET6 && ifi > 0)
312                         printf("%%%i", ifi);
313                 fputc('\n', stdout);
314
315                 r = sd_bus_message_exit_container(reply);
316                 if (r < 0)
317                         return bus_log_parse_error(r);
318
319                 if (prefix != prefix2)
320                         prefix = prefix2;
321         }
322         if (r < 0)
323                 return bus_log_parse_error(r);
324
325         r = sd_bus_message_exit_container(reply);
326         if (r < 0)
327                 return bus_log_parse_error(r);
328
329         return 0;
330 }
331
332 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
333         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
334         const char *k, *v, *pretty = NULL;
335         int r;
336
337         assert(bus);
338         assert(name);
339         assert(prefix);
340
341         r = sd_bus_call_method(bus,
342                                "org.freedesktop.machine1",
343                                "/org/freedesktop/machine1",
344                                "org.freedesktop.machine1.Manager",
345                                "GetMachineOSRelease",
346                                NULL,
347                                &reply,
348                                "s", name);
349         if (r < 0)
350                 return r;
351
352         r = sd_bus_message_enter_container(reply, 'a', "{ss}");
353         if (r < 0)
354                 return bus_log_parse_error(r);
355
356         while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
357                 if (streq(k, "PRETTY_NAME"))
358                         pretty = v;
359
360         }
361         if (r < 0)
362                 return bus_log_parse_error(r);
363
364         r = sd_bus_message_exit_container(reply);
365         if (r < 0)
366                 return bus_log_parse_error(r);
367
368         if (pretty)
369                 printf("%s%s\n", prefix, pretty);
370
371         return 0;
372 }
373
374 typedef struct MachineStatusInfo {
375         char *name;
376         sd_id128_t id;
377         char *class;
378         char *service;
379         char *unit;
380         char *root_directory;
381         pid_t leader;
382         usec_t timestamp;
383         int *netif;
384         unsigned n_netif;
385 } MachineStatusInfo;
386
387 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
388         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
389         char since2[FORMAT_TIMESTAMP_MAX], *s2;
390         int ifi = -1;
391
392         assert(i);
393
394         fputs(strna(i->name), stdout);
395
396         if (!sd_id128_equal(i->id, SD_ID128_NULL))
397                 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
398         else
399                 putchar('\n');
400
401         s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
402         s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
403
404         if (s1)
405                 printf("\t   Since: %s; %s\n", s2, s1);
406         else if (s2)
407                 printf("\t   Since: %s\n", s2);
408
409         if (i->leader > 0) {
410                 _cleanup_free_ char *t = NULL;
411
412                 printf("\t  Leader: %u", (unsigned) i->leader);
413
414                 get_process_comm(i->leader, &t);
415                 if (t)
416                         printf(" (%s)", t);
417
418                 putchar('\n');
419         }
420
421         if (i->service) {
422                 printf("\t Service: %s", i->service);
423
424                 if (i->class)
425                         printf("; class %s", i->class);
426
427                 putchar('\n');
428         } else if (i->class)
429                 printf("\t   Class: %s\n", i->class);
430
431         if (i->root_directory)
432                 printf("\t    Root: %s\n", i->root_directory);
433
434         if (i->n_netif > 0) {
435                 unsigned c;
436
437                 fputs("\t   Iface:", stdout);
438
439                 for (c = 0; c < i->n_netif; c++) {
440                         char name[IF_NAMESIZE+1] = "";
441
442                         if (if_indextoname(i->netif[c], name)) {
443                                 fputc(' ', stdout);
444                                 fputs(name, stdout);
445
446                                 if (ifi < 0)
447                                         ifi = i->netif[c];
448                                 else
449                                         ifi = 0;
450                         } else
451                                 printf(" %i", i->netif[c]);
452                 }
453
454                 fputc('\n', stdout);
455         }
456
457         print_addresses(bus, i->name, ifi,
458                        "\t Address: ",
459                        "\t          ");
460
461         print_os_release(bus, i->name, "\t      OS: ");
462
463         if (i->unit) {
464                 printf("\t    Unit: %s\n", i->unit);
465                 show_unit_cgroup(bus, i->unit, i->leader);
466         }
467 }
468
469 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
470         MachineStatusInfo *i = userdata;
471         size_t l;
472         const void *v;
473         int r;
474
475         assert_cc(sizeof(int32_t) == sizeof(int));
476         r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
477         if (r < 0)
478                 return r;
479         if (r == 0)
480                 return -EBADMSG;
481
482         i->n_netif = l / sizeof(int32_t);
483         i->netif = memdup(v, l);
484         if (!i->netif)
485                 return -ENOMEM;
486
487         return 0;
488 }
489
490 static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
491
492         static const struct bus_properties_map map[]  = {
493                 { "Name",              "s",  NULL,          offsetof(MachineStatusInfo, name) },
494                 { "Class",             "s",  NULL,          offsetof(MachineStatusInfo, class) },
495                 { "Service",           "s",  NULL,          offsetof(MachineStatusInfo, service) },
496                 { "Unit",              "s",  NULL,          offsetof(MachineStatusInfo, unit) },
497                 { "RootDirectory",     "s",  NULL,          offsetof(MachineStatusInfo, root_directory) },
498                 { "Leader",            "u",  NULL,          offsetof(MachineStatusInfo, leader) },
499                 { "Timestamp",         "t",  NULL,          offsetof(MachineStatusInfo, timestamp) },
500                 { "Id",                "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
501                 { "NetworkInterfaces", "ai", map_netif,     0 },
502                 {}
503         };
504
505         MachineStatusInfo info = {};
506         int r;
507
508         assert(path);
509         assert(new_line);
510
511         r = bus_map_all_properties(bus,
512                                    "org.freedesktop.machine1",
513                                    path,
514                                    map,
515                                    &info);
516         if (r < 0)
517                 return log_error_errno(r, "Could not get properties: %m");
518
519         if (*new_line)
520                 printf("\n");
521         *new_line = true;
522
523         print_machine_status_info(bus, &info);
524
525         free(info.name);
526         free(info.class);
527         free(info.service);
528         free(info.unit);
529         free(info.root_directory);
530         free(info.netif);
531
532         return r;
533 }
534
535 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
536         int r;
537
538         if (*new_line)
539                 printf("\n");
540
541         *new_line = true;
542
543         r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
544         if (r < 0)
545                 log_error_errno(r, "Could not get properties: %m");
546
547         return r;
548 }
549
550 static int show(sd_bus *bus, char **args, unsigned n) {
551         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
552         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
553         int r = 0;
554         unsigned i;
555         bool properties, new_line = false;
556
557         assert(bus);
558         assert(args);
559
560         properties = !strstr(args[0], "status");
561
562         pager_open_if_enabled();
563
564         if (properties && n <= 1) {
565
566                 /* If no argument is specified, inspect the manager
567                  * itself */
568                 r = show_properties(bus, "/org/freedesktop/machine1", &new_line);
569                 if (r < 0)
570                         return r;
571         }
572
573         for (i = 1; i < n; i++) {
574                 const char *path = NULL;
575
576                 r = sd_bus_call_method(
577                                         bus,
578                                         "org.freedesktop.machine1",
579                                         "/org/freedesktop/machine1",
580                                         "org.freedesktop.machine1.Manager",
581                                         "GetMachine",
582                                         &error,
583                                         &reply,
584                                         "s", args[i]);
585                 if (r < 0) {
586                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
587                         return r;
588                 }
589
590                 r = sd_bus_message_read(reply, "o", &path);
591                 if (r < 0)
592                         return bus_log_parse_error(r);
593
594                 if (properties)
595                         r = show_properties(bus, path, &new_line);
596                 else
597                         r = show_info(args[0], bus, path, &new_line);
598         }
599
600         return r;
601 }
602
603 static int kill_machine(sd_bus *bus, char **args, unsigned n) {
604         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
605         unsigned i;
606
607         assert(args);
608
609         if (!arg_kill_who)
610                 arg_kill_who = "all";
611
612         for (i = 1; i < n; i++) {
613                 int r;
614
615                 r = sd_bus_call_method(
616                                         bus,
617                                         "org.freedesktop.machine1",
618                                         "/org/freedesktop/machine1",
619                                         "org.freedesktop.machine1.Manager",
620                                         "KillMachine",
621                                         &error,
622                                         NULL,
623                                         "ssi", args[i], arg_kill_who, arg_signal);
624                 if (r < 0) {
625                         log_error("Could not kill machine: %s", bus_error_message(&error, -r));
626                         return r;
627                 }
628         }
629
630         return 0;
631 }
632
633 static int reboot_machine(sd_bus *bus, char **args, unsigned n) {
634         arg_kill_who = "leader";
635         arg_signal = SIGINT; /* sysvinit + systemd */
636
637         return kill_machine(bus, args, n);
638 }
639
640 static int poweroff_machine(sd_bus *bus, char **args, unsigned n) {
641         arg_kill_who = "leader";
642         arg_signal = SIGRTMIN+4; /* only systemd */
643
644         return kill_machine(bus, args, n);
645 }
646
647 static int terminate_machine(sd_bus *bus, char **args, unsigned n) {
648         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
649         unsigned i;
650
651         assert(args);
652
653         for (i = 1; i < n; i++) {
654                 int r;
655
656                 r = sd_bus_call_method(
657                                 bus,
658                                 "org.freedesktop.machine1",
659                                 "/org/freedesktop/machine1",
660                                 "org.freedesktop.machine1.Manager",
661                                 "TerminateMachine",
662                                 &error,
663                                 NULL,
664                                 "s", args[i]);
665                 if (r < 0) {
666                         log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
667                         return r;
668                 }
669         }
670
671         return 0;
672 }
673
674 static int machine_get_leader(sd_bus *bus, const char *name, pid_t *ret) {
675         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
676         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL;
677         const char *object;
678         uint32_t leader;
679         int r;
680
681         assert(bus);
682         assert(name);
683         assert(ret);
684
685         r = sd_bus_call_method(
686                         bus,
687                         "org.freedesktop.machine1",
688                         "/org/freedesktop/machine1",
689                         "org.freedesktop.machine1.Manager",
690                         "GetMachine",
691                         &error,
692                         &reply,
693                         "s", name);
694         if (r < 0) {
695                 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
696                 return r;
697         }
698
699         r = sd_bus_message_read(reply, "o", &object);
700         if (r < 0)
701                 return bus_log_parse_error(r);
702
703         r = sd_bus_get_property(
704                         bus,
705                         "org.freedesktop.machine1",
706                         object,
707                         "org.freedesktop.machine1.Machine",
708                         "Leader",
709                         &error,
710                         &reply2,
711                         "u");
712         if (r < 0)
713                 return log_error_errno(r, "Failed to retrieve PID of leader: %m");
714
715         r = sd_bus_message_read(reply2, "u", &leader);
716         if (r < 0)
717                 return bus_log_parse_error(r);
718
719         *ret = leader;
720         return 0;
721 }
722
723 static int copy_files(sd_bus *bus, char **args, unsigned n) {
724         char *dest, *host_path, *container_path, *host_dirname, *host_basename, *container_dirname, *container_basename, *t;
725         _cleanup_close_ int hostfd = -1;
726         pid_t child, leader;
727         bool copy_from;
728         siginfo_t si;
729         int r;
730
731         if (n > 4) {
732                 log_error("Too many arguments.");
733                 return -EINVAL;
734         }
735
736         copy_from = streq(args[0], "copy-from");
737         dest = args[3] ?: args[2];
738         host_path = strdupa(copy_from ? dest : args[2]);
739         container_path = strdupa(copy_from ? args[2] : dest);
740
741         if (!path_is_absolute(container_path)) {
742                 log_error("Container path not absolute.");
743                 return -EINVAL;
744         }
745
746         t = strdup(host_path);
747         host_basename = basename(t);
748         host_dirname = dirname(host_path);
749
750         t = strdup(container_path);
751         container_basename = basename(t);
752         container_dirname = dirname(container_path);
753
754         r = machine_get_leader(bus, args[1], &leader);
755         if (r < 0)
756                 return r;
757
758         hostfd = open(host_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
759         if (r < 0)
760                 return log_error_errno(errno, "Failed to open source directory: %m");
761
762         child = fork();
763         if (child < 0)
764                 return log_error_errno(errno, "Failed to fork(): %m");
765
766         if (child == 0) {
767                 int containerfd;
768                 const char *q;
769                 int mntfd;
770
771                 q = procfs_file_alloca(leader, "ns/mnt");
772                 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
773                 if (mntfd < 0) {
774                         log_error_errno(errno, "Failed to open mount namespace of leader: %m");
775                         _exit(EXIT_FAILURE);
776                 }
777
778                 if (setns(mntfd, CLONE_NEWNS) < 0) {
779                         log_error_errno(errno, "Failed to join namespace of leader: %m");
780                         _exit(EXIT_FAILURE);
781                 }
782
783                 containerfd = open(container_dirname, O_CLOEXEC|O_RDONLY|O_NOCTTY|O_DIRECTORY);
784                 if (containerfd < 0) {
785                         log_error_errno(errno, "Failed top open destination directory: %m");
786                         _exit(EXIT_FAILURE);
787                 }
788
789                 if (copy_from)
790                         r = copy_tree_at(containerfd, container_basename, hostfd, host_basename, true);
791                 else
792                         r = copy_tree_at(hostfd, host_basename, containerfd, container_basename, true);
793                 if (r < 0) {
794                         log_error_errno(errno, "Failed to copy tree: %m");
795                         _exit(EXIT_FAILURE);
796                 }
797
798                 _exit(EXIT_SUCCESS);
799         }
800
801         r = wait_for_terminate(child, &si);
802         if (r < 0)
803                 return log_error_errno(r, "Failed to wait for client: %m");
804         if (si.si_code != CLD_EXITED) {
805                 log_error("Client died abnormally.");
806                 return -EIO;
807         }
808         if (si.si_status != EXIT_SUCCESS)
809                 return -EIO;
810
811         return 0;
812 }
813
814 static int bind_mount(sd_bus *bus, char **args, unsigned n) {
815         char mount_slave[] = "/tmp/propagate.XXXXXX", *mount_tmp, *mount_outside, *p;
816         pid_t child, leader;
817         const char *dest;
818         siginfo_t si;
819         bool mount_slave_created = false, mount_slave_mounted = false,
820                 mount_tmp_created = false, mount_tmp_mounted = false,
821                 mount_outside_created = false, mount_outside_mounted = false;
822         int r;
823
824         /* One day, when bind mounting /proc/self/fd/n works across
825          * namespace boundaries we should rework this logic to make
826          * use of it... */
827
828         if (n > 4) {
829                 log_error("Too many arguments.");
830                 return -EINVAL;
831         }
832
833         dest = args[3] ?: args[2];
834         if (!path_is_absolute(dest)) {
835                 log_error("Destination path not absolute.");
836                 return -EINVAL;
837         }
838
839         p = strappenda("/run/systemd/nspawn/propagate/", args[1], "/");
840         if (access(p, F_OK) < 0) {
841                 log_error("Container does not allow propagation of mount points.");
842                 return -ENOTSUP;
843         }
844
845         r = machine_get_leader(bus, args[1], &leader);
846         if (r < 0)
847                 return r;
848
849         /* Our goal is to install a new bind mount into the container,
850            possibly read-only. This is irritatingly complex
851            unfortunately, currently.
852
853            First, we start by creating a private playground in /tmp,
854            that we can mount MS_SLAVE. (Which is necessary, since
855            MS_MOUNT cannot be applied to mounts with MS_SHARED parent
856            mounts.) */
857
858         if (!mkdtemp(mount_slave))
859                 return log_error_errno(errno, "Failed to create playground: %m");
860
861         mount_slave_created = true;
862
863         if (mount(mount_slave, mount_slave, NULL, MS_BIND, NULL) < 0) {
864                 r = log_error_errno(errno, "Failed to make bind mount: %m");
865                 goto finish;
866         }
867
868         mount_slave_mounted = true;
869
870         if (mount(NULL, mount_slave, NULL, MS_SLAVE, NULL) < 0) {
871                 r = log_error_errno(errno, "Failed to remount slave: %m");
872                 goto finish;
873         }
874
875         /* Second, we mount the source directory to a directory inside
876            of our MS_SLAVE playground. */
877         mount_tmp = strappenda(mount_slave, "/mount");
878         if (mkdir(mount_tmp, 0700) < 0) {
879                 r = log_error_errno(errno, "Failed to create temporary mount: %m");
880                 goto finish;
881         }
882
883         mount_tmp_created = true;
884
885         if (mount(args[2], mount_tmp, NULL, MS_BIND, NULL) < 0) {
886                 r = log_error_errno(errno, "Failed to overmount: %m");
887                 goto finish;
888         }
889
890         mount_tmp_mounted = true;
891
892         /* Third, we remount the new bind mount read-only if requested. */
893         if (arg_read_only)
894                 if (mount(NULL, mount_tmp, NULL, MS_BIND|MS_REMOUNT|MS_RDONLY, NULL) < 0) {
895                         r = log_error_errno(errno, "Failed to mark read-only: %m");
896                         goto finish;
897                 }
898
899         /* Fourth, we move the new bind mount into the propagation
900          * directory. This way it will appear there read-only
901          * right-away. */
902
903         mount_outside = strappenda("/run/systemd/nspawn/propagate/", args[1], "/XXXXXX");
904         if (!mkdtemp(mount_outside)) {
905                 r = log_error_errno(errno, "Cannot create propagation directory: %m");
906                 goto finish;
907         }
908
909         mount_outside_created = true;
910
911         if (mount(mount_tmp, mount_outside, NULL, MS_MOVE, NULL) < 0) {
912                 r = log_error_errno(errno, "Failed to move: %m");
913                 goto finish;
914         }
915
916         mount_outside_mounted = true;
917         mount_tmp_mounted = false;
918
919         (void) rmdir(mount_tmp);
920         mount_tmp_created = false;
921
922         (void) umount(mount_slave);
923         mount_slave_mounted = false;
924
925         (void) rmdir(mount_slave);
926         mount_slave_created = false;
927
928         child = fork();
929         if (child < 0) {
930                 r = log_error_errno(errno, "Failed to fork(): %m");
931                 goto finish;
932         }
933
934         if (child == 0) {
935                 const char *mount_inside;
936                 int mntfd;
937                 const char *q;
938
939                 q = procfs_file_alloca(leader, "ns/mnt");
940                 mntfd = open(q, O_RDONLY|O_NOCTTY|O_CLOEXEC);
941                 if (mntfd < 0) {
942                         log_error_errno(errno, "Failed to open mount namespace of leader: %m");
943                         _exit(EXIT_FAILURE);
944                 }
945
946                 if (setns(mntfd, CLONE_NEWNS) < 0) {
947                         log_error_errno(errno, "Failed to join namespace of leader: %m");
948                         _exit(EXIT_FAILURE);
949                 }
950
951                 if (arg_mkdir)
952                         mkdir_p(dest, 0755);
953
954                 /* Fifth, move the mount to the right place inside */
955                 mount_inside = strappenda("/run/systemd/nspawn/incoming/", basename(mount_outside));
956                 if (mount(mount_inside, dest, NULL, MS_MOVE, NULL) < 0) {
957                         log_error_errno(errno, "Failed to mount: %m");
958                         _exit(EXIT_FAILURE);
959                 }
960
961                 _exit(EXIT_SUCCESS);
962         }
963
964         r = wait_for_terminate(child, &si);
965         if (r < 0) {
966                 log_error_errno(r, "Failed to wait for client: %m");
967                 goto finish;
968         }
969         if (si.si_code != CLD_EXITED) {
970                 log_error("Client died abnormally.");
971                 r = -EIO;
972                 goto finish;
973         }
974         if (si.si_status != EXIT_SUCCESS) {
975                 r = -EIO;
976                 goto finish;
977         }
978
979         r = 0;
980
981 finish:
982         if (mount_outside_mounted)
983                 umount(mount_outside);
984         if (mount_outside_created)
985                 rmdir(mount_outside);
986
987         if (mount_tmp_mounted)
988                 umount(mount_tmp);
989         if (mount_tmp_created)
990                 umount(mount_tmp);
991
992         if (mount_slave_mounted)
993                 umount(mount_slave);
994         if (mount_slave_created)
995                 umount(mount_slave);
996
997         return r;
998 }
999
1000 static int openpt_in_namespace(pid_t pid, int flags) {
1001         _cleanup_close_pair_ int pair[2] = { -1, -1 };
1002         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1003         union {
1004                 struct cmsghdr cmsghdr;
1005                 uint8_t buf[CMSG_SPACE(sizeof(int))];
1006         } control = {};
1007         struct msghdr mh = {
1008                 .msg_control = &control,
1009                 .msg_controllen = sizeof(control),
1010         };
1011         struct cmsghdr *cmsg;
1012         int master = -1, r;
1013         pid_t child;
1014         siginfo_t si;
1015
1016         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1017         if (r < 0)
1018                 return r;
1019
1020         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1021                 return -errno;
1022
1023         child = fork();
1024         if (child < 0)
1025                 return -errno;
1026
1027         if (child == 0) {
1028                 pair[0] = safe_close(pair[0]);
1029
1030                 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1031                 if (r < 0)
1032                         _exit(EXIT_FAILURE);
1033
1034                 master = posix_openpt(flags);
1035                 if (master < 0)
1036                         _exit(EXIT_FAILURE);
1037
1038                 cmsg = CMSG_FIRSTHDR(&mh);
1039                 cmsg->cmsg_level = SOL_SOCKET;
1040                 cmsg->cmsg_type = SCM_RIGHTS;
1041                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
1042                 memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
1043
1044                 mh.msg_controllen = cmsg->cmsg_len;
1045
1046                 if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
1047                         _exit(EXIT_FAILURE);
1048
1049                 _exit(EXIT_SUCCESS);
1050         }
1051
1052         pair[1] = safe_close(pair[1]);
1053
1054         r = wait_for_terminate(child, &si);
1055         if (r < 0)
1056                 return r;
1057         if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1058                 return -EIO;
1059
1060         if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
1061                 return -errno;
1062
1063         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
1064                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
1065                         int *fds;
1066                         unsigned n_fds;
1067
1068                         fds = (int*) CMSG_DATA(cmsg);
1069                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
1070
1071                         if (n_fds != 1) {
1072                                 close_many(fds, n_fds);
1073                                 return -EIO;
1074                         }
1075
1076                         master = fds[0];
1077                 }
1078
1079         if (master < 0)
1080                 return -EIO;
1081
1082         return master;
1083 }
1084
1085 static int login_machine(sd_bus *bus, char **args, unsigned n) {
1086         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1087         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1088         _cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
1089         _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
1090         _cleanup_event_unref_ sd_event *event = NULL;
1091         _cleanup_close_ int master = -1;
1092         _cleanup_free_ char *getty = NULL;
1093         const char *pty, *p;
1094         pid_t leader;
1095         sigset_t mask;
1096         int r, ret = 0;
1097
1098         assert(bus);
1099         assert(args);
1100
1101         if (arg_transport != BUS_TRANSPORT_LOCAL) {
1102                 log_error("Login only supported on local machines.");
1103                 return -ENOTSUP;
1104         }
1105
1106         r = sd_event_default(&event);
1107         if (r < 0)
1108                 return log_error_errno(r, "Failed to get event loop: %m");
1109
1110         r = sd_bus_attach_event(bus, event, 0);
1111         if (r < 0)
1112                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1113
1114         r = machine_get_leader(bus, args[1], &leader);
1115         if (r < 0)
1116                 return r;
1117
1118         master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
1119         if (master < 0)
1120                 return log_error_errno(master, "Failed to acquire pseudo tty: %m");
1121
1122         pty = ptsname(master);
1123         if (!pty)
1124                 return log_error_errno(errno, "Failed to get pty name: %m");
1125
1126         p = startswith(pty, "/dev/pts/");
1127         if (!p) {
1128                 log_error("Invalid pty name %s.", pty);
1129                 return -EIO;
1130         }
1131
1132         r = sd_bus_open_system_container(&container_bus, args[1]);
1133         if (r < 0)
1134                 return log_error_errno(r, "Failed to get container bus: %m");
1135
1136         getty = strjoin("container-getty@", p, ".service", NULL);
1137         if (!getty)
1138                 return log_oom();
1139
1140         if (unlockpt(master) < 0)
1141                 return log_error_errno(errno, "Failed to unlock tty: %m");
1142
1143         r = sd_bus_call_method(container_bus,
1144                                "org.freedesktop.systemd1",
1145                                "/org/freedesktop/systemd1",
1146                                "org.freedesktop.systemd1.Manager",
1147                                "StartUnit",
1148                                &error, &reply,
1149                                "ss", getty, "replace");
1150         if (r < 0) {
1151                 log_error("Failed to start getty service: %s", bus_error_message(&error, r));
1152                 return r;
1153         }
1154
1155         container_bus = sd_bus_unref(container_bus);
1156
1157         assert_se(sigemptyset(&mask) == 0);
1158         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
1159         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
1160
1161         log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
1162
1163         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
1164         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
1165
1166         r = pty_forward_new(event, master, &forward);
1167         if (r < 0)
1168                 return log_error_errno(r, "Failed to create PTY forwarder: %m");
1169
1170         r = sd_event_loop(event);
1171         if (r < 0)
1172                 return log_error_errno(r, "Failed to run event loop: %m");
1173
1174         forward = pty_forward_free(forward);
1175
1176         fputc('\n', stdout);
1177
1178         log_info("Connection to container %s terminated.", args[1]);
1179
1180         sd_event_get_exit_code(event, &ret);
1181         return ret;
1182 }
1183
1184 static void help(void) {
1185         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1186                "Send control commands to or query the virtual machine and container\n"
1187                "registration manager.\n\n"
1188                "  -h --help                   Show this help\n"
1189                "     --version                Show package version\n"
1190                "     --no-pager               Do not pipe output into a pager\n"
1191                "     --no-legend              Do not show the headers and footers\n"
1192                "  -H --host=[USER@]HOST       Operate on remote host\n"
1193                "  -M --machine=CONTAINER      Operate on local container\n"
1194                "  -p --property=NAME          Show only properties by this name\n"
1195                "  -a --all                    Show all properties, including empty ones\n"
1196                "  -l --full                   Do not ellipsize output\n"
1197                "     --kill-who=WHO           Who to send signal to\n"
1198                "  -s --signal=SIGNAL          Which signal to send\n"
1199                "     --read-only              Create read-only bind mount\n"
1200                "     --mkdir                  Create directory before bind mounting, if missing\n\n"
1201                "Machine Commands:\n"
1202                "  list                        List running VMs and containers\n"
1203                "  status NAME...              Show VM/container status\n"
1204                "  show NAME...                Show properties of one or more VMs/containers\n"
1205                "  login NAME                  Get a login prompt on a container\n"
1206                "  poweroff NAME...            Power off one or more containers\n"
1207                "  reboot NAME...              Reboot one or more containers\n"
1208                "  kill NAME...                Send signal to processes of a VM/container\n"
1209                "  terminate NAME...           Terminate one or more VMs/containers\n"
1210                "  bind NAME PATH [PATH]       Bind mount a path from the host into a container\n"
1211                "  copy-to NAME PATH [PATH]    Copy files from the host to a container\n"
1212                "  copy-from NAME PATH [PATH]  Copy files from a container to the host\n\n"
1213                "Image commands:\n"
1214                "  list-images                 Show available images\n",
1215                program_invocation_short_name);
1216 }
1217
1218 static int parse_argv(int argc, char *argv[]) {
1219
1220         enum {
1221                 ARG_VERSION = 0x100,
1222                 ARG_NO_PAGER,
1223                 ARG_NO_LEGEND,
1224                 ARG_KILL_WHO,
1225                 ARG_READ_ONLY,
1226                 ARG_MKDIR,
1227         };
1228
1229         static const struct option options[] = {
1230                 { "help",            no_argument,       NULL, 'h'                 },
1231                 { "version",         no_argument,       NULL, ARG_VERSION         },
1232                 { "property",        required_argument, NULL, 'p'                 },
1233                 { "all",             no_argument,       NULL, 'a'                 },
1234                 { "full",            no_argument,       NULL, 'l'                 },
1235                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
1236                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
1237                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
1238                 { "signal",          required_argument, NULL, 's'                 },
1239                 { "host",            required_argument, NULL, 'H'                 },
1240                 { "machine",         required_argument, NULL, 'M'                 },
1241                 { "read-only",       no_argument,       NULL, ARG_READ_ONLY       },
1242                 { "mkdir",           no_argument,       NULL, ARG_MKDIR           },
1243                 {}
1244         };
1245
1246         int c, r;
1247
1248         assert(argc >= 0);
1249         assert(argv);
1250
1251         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
1252
1253                 switch (c) {
1254
1255                 case 'h':
1256                         help();
1257                         return 0;
1258
1259                 case ARG_VERSION:
1260                         puts(PACKAGE_STRING);
1261                         puts(SYSTEMD_FEATURES);
1262                         return 0;
1263
1264                 case 'p':
1265                         r = strv_extend(&arg_property, optarg);
1266                         if (r < 0)
1267                                 return log_oom();
1268
1269                         /* If the user asked for a particular
1270                          * property, show it to him, even if it is
1271                          * empty. */
1272                         arg_all = true;
1273                         break;
1274
1275                 case 'a':
1276                         arg_all = true;
1277                         break;
1278
1279                 case 'l':
1280                         arg_full = true;
1281                         break;
1282
1283                 case ARG_NO_PAGER:
1284                         arg_no_pager = true;
1285                         break;
1286
1287                 case ARG_NO_LEGEND:
1288                         arg_legend = false;
1289                         break;
1290
1291                 case ARG_KILL_WHO:
1292                         arg_kill_who = optarg;
1293                         break;
1294
1295                 case 's':
1296                         arg_signal = signal_from_string_try_harder(optarg);
1297                         if (arg_signal < 0) {
1298                                 log_error("Failed to parse signal string %s.", optarg);
1299                                 return -EINVAL;
1300                         }
1301                         break;
1302
1303                 case 'H':
1304                         arg_transport = BUS_TRANSPORT_REMOTE;
1305                         arg_host = optarg;
1306                         break;
1307
1308                 case 'M':
1309                         arg_transport = BUS_TRANSPORT_CONTAINER;
1310                         arg_host = optarg;
1311                         break;
1312
1313                 case ARG_READ_ONLY:
1314                         arg_read_only = true;
1315                         break;
1316
1317                 case ARG_MKDIR:
1318                         arg_mkdir = true;
1319                         break;
1320
1321                 case '?':
1322                         return -EINVAL;
1323
1324                 default:
1325                         assert_not_reached("Unhandled option");
1326                 }
1327
1328         return 1;
1329 }
1330
1331 static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
1332
1333         static const struct {
1334                 const char* verb;
1335                 const enum {
1336                         MORE,
1337                         LESS,
1338                         EQUAL
1339                 } argc_cmp;
1340                 const int argc;
1341                 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
1342         } verbs[] = {
1343                 { "list",                  LESS,   1, list_machines     },
1344                 { "list-images",           LESS,   1, list_images       },
1345                 { "status",                MORE,   2, show              },
1346                 { "show",                  MORE,   1, show              },
1347                 { "terminate",             MORE,   2, terminate_machine },
1348                 { "reboot",                MORE,   2, reboot_machine    },
1349                 { "poweroff",              MORE,   2, poweroff_machine  },
1350                 { "kill",                  MORE,   2, kill_machine      },
1351                 { "login",                 MORE,   2, login_machine     },
1352                 { "bind",                  MORE,   3, bind_mount        },
1353                 { "copy-to",               MORE,   3, copy_files        },
1354                 { "copy-from",             MORE,   3, copy_files        },
1355         };
1356
1357         int left;
1358         unsigned i;
1359
1360         assert(argc >= 0);
1361         assert(argv);
1362
1363         left = argc - optind;
1364
1365         if (left <= 0)
1366                 /* Special rule: no arguments means "list" */
1367                 i = 0;
1368         else {
1369                 if (streq(argv[optind], "help")) {
1370                         help();
1371                         return 0;
1372                 }
1373
1374                 for (i = 0; i < ELEMENTSOF(verbs); i++)
1375                         if (streq(argv[optind], verbs[i].verb))
1376                                 break;
1377
1378                 if (i >= ELEMENTSOF(verbs)) {
1379                         log_error("Unknown operation %s", argv[optind]);
1380                         return -EINVAL;
1381                 }
1382         }
1383
1384         switch (verbs[i].argc_cmp) {
1385
1386         case EQUAL:
1387                 if (left != verbs[i].argc) {
1388                         log_error("Invalid number of arguments.");
1389                         return -EINVAL;
1390                 }
1391
1392                 break;
1393
1394         case MORE:
1395                 if (left < verbs[i].argc) {
1396                         log_error("Too few arguments.");
1397                         return -EINVAL;
1398                 }
1399
1400                 break;
1401
1402         case LESS:
1403                 if (left > verbs[i].argc) {
1404                         log_error("Too many arguments.");
1405                         return -EINVAL;
1406                 }
1407
1408                 break;
1409
1410         default:
1411                 assert_not_reached("Unknown comparison operator.");
1412         }
1413
1414         return verbs[i].dispatch(bus, argv + optind, left);
1415 }
1416
1417 int main(int argc, char*argv[]) {
1418         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1419         int r;
1420
1421         setlocale(LC_ALL, "");
1422         log_parse_environment();
1423         log_open();
1424
1425         r = parse_argv(argc, argv);
1426         if (r <= 0)
1427                 goto finish;
1428
1429         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1430         if (r < 0) {
1431                 log_error_errno(r, "Failed to create bus connection: %m");
1432                 goto finish;
1433         }
1434
1435         r = machinectl_main(bus, argc, argv);
1436
1437 finish:
1438         pager_close();
1439
1440         strv_free(arg_property);
1441
1442         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1443 }