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