chiark / gitweb /
6db9e5c91bfab956beee7f3e9645e443ecdc9436
[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
34 #include "sd-bus.h"
35 #include "log.h"
36 #include "util.h"
37 #include "macro.h"
38 #include "pager.h"
39 #include "bus-util.h"
40 #include "bus-error.h"
41 #include "build.h"
42 #include "strv.h"
43 #include "unit-name.h"
44 #include "cgroup-show.h"
45 #include "cgroup-util.h"
46 #include "ptyfwd.h"
47 #include "event-util.h"
48
49 static char **arg_property = NULL;
50 static bool arg_all = false;
51 static bool arg_full = false;
52 static bool arg_no_pager = false;
53 static bool arg_legend = true;
54 static const char *arg_kill_who = NULL;
55 static int arg_signal = SIGTERM;
56 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
57 static char *arg_host = NULL;
58
59 static void pager_open_if_enabled(void) {
60
61         /* Cache result before we open the pager */
62         if (arg_no_pager)
63                 return;
64
65         pager_open(false);
66 }
67
68 static int list_machines(sd_bus *bus, char **args, unsigned n) {
69         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
70         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
71         const char *name, *class, *service, *object;
72         unsigned k = 0;
73         int r;
74
75         pager_open_if_enabled();
76
77         r = sd_bus_call_method(
78                                 bus,
79                                 "org.freedesktop.machine1",
80                                 "/org/freedesktop/machine1",
81                                 "org.freedesktop.machine1.Manager",
82                                 "ListMachines",
83                                 &error,
84                                 &reply,
85                                 "");
86         if (r < 0) {
87                 log_error("Could not get machines: %s", bus_error_message(&error, -r));
88                 return r;
89         }
90
91         if (arg_legend)
92                 printf("%-32s %-9s %-16s\n", "MACHINE", "CONTAINER", "SERVICE");
93
94         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssso)");
95         if (r < 0)
96                 return bus_log_parse_error(r);
97
98         while ((r = sd_bus_message_read(reply, "(ssso)", &name, &class, &service, &object)) > 0) {
99                 printf("%-32s %-9s %-16s\n", name, class, service);
100
101                 k++;
102         }
103         if (r < 0)
104                 return bus_log_parse_error(r);
105
106         r = sd_bus_message_exit_container(reply);
107         if (r < 0)
108                 return bus_log_parse_error(r);
109
110         if (arg_legend)
111                 printf("\n%u machines listed.\n", k);
112
113         return 0;
114 }
115
116 static int show_unit_cgroup(sd_bus *bus, const char *unit, pid_t leader) {
117         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
118         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
119         _cleanup_free_ char *path = NULL;
120         const char *cgroup;
121         int r, output_flags;
122         unsigned c;
123
124         assert(bus);
125         assert(unit);
126
127         if (arg_transport == BUS_TRANSPORT_REMOTE)
128                 return 0;
129
130         path = unit_dbus_path_from_name(unit);
131         if (!path)
132                 return log_oom();
133
134         r = sd_bus_get_property(
135                         bus,
136                         "org.freedesktop.systemd1",
137                         path,
138                         endswith(unit, ".scope") ? "org.freedesktop.systemd1.Scope" : "org.freedesktop.systemd1.Service",
139                         "ControlGroup",
140                         &error,
141                         &reply,
142                         "s");
143         if (r < 0) {
144                 log_error("Failed to query ControlGroup: %s", bus_error_message(&error, -r));
145                 return r;
146         }
147
148         r = sd_bus_message_read(reply, "s", &cgroup);
149         if (r < 0)
150                 return bus_log_parse_error(r);
151
152         if (isempty(cgroup))
153                 return 0;
154
155         if (cg_is_empty_recursive(SYSTEMD_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
156                 return 0;
157
158         output_flags =
159                 arg_all * OUTPUT_SHOW_ALL |
160                 arg_full * OUTPUT_FULL_WIDTH;
161
162         c = columns();
163         if (c > 18)
164                 c -= 18;
165         else
166                 c = 0;
167
168         show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, output_flags);
169         return 0;
170 }
171
172 static int print_addresses(sd_bus *bus, const char *name, int ifi, const char *prefix, const char *prefix2) {
173         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
174         int r;
175
176         assert(bus);
177         assert(name);
178         assert(prefix);
179         assert(prefix2);
180
181         r = sd_bus_call_method(bus,
182                                "org.freedesktop.machine1",
183                                "/org/freedesktop/machine1",
184                                "org.freedesktop.machine1.Manager",
185                                "GetMachineAddresses",
186                                NULL,
187                                &reply,
188                                "s", name);
189         if (r < 0)
190                 return r;
191
192         r = sd_bus_message_enter_container(reply, 'a', "(iay)");
193         if (r < 0)
194                 return bus_log_parse_error(r);
195
196         while ((r = sd_bus_message_enter_container(reply, 'r', "iay")) > 0) {
197                 int family;
198                 const void *a;
199                 size_t sz;
200                 char buffer[MAX(INET6_ADDRSTRLEN, INET_ADDRSTRLEN)];
201
202                 r = sd_bus_message_read(reply, "i", &family);
203                 if (r < 0)
204                         return bus_log_parse_error(r);
205
206                 r = sd_bus_message_read_array(reply, 'y', &a, &sz);
207                 if (r < 0)
208                         return bus_log_parse_error(r);
209
210                 fputs(prefix, stdout);
211                 fputs(inet_ntop(family, a, buffer, sizeof(buffer)), stdout);
212                 if (family == AF_INET6 && ifi > 0)
213                         printf("%%%i", ifi);
214                 fputc('\n', stdout);
215
216                 r = sd_bus_message_exit_container(reply);
217                 if (r < 0)
218                         return bus_log_parse_error(r);
219
220                 if (prefix != prefix2)
221                         prefix = prefix2;
222         }
223         if (r < 0)
224                 return bus_log_parse_error(r);
225
226         r = sd_bus_message_exit_container(reply);
227         if (r < 0)
228                 return bus_log_parse_error(r);
229
230         return 0;
231 }
232
233 static int print_os_release(sd_bus *bus, const char *name, const char *prefix) {
234         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
235         const char *k, *v, *pretty = NULL;
236         int r;
237
238         assert(bus);
239         assert(name);
240         assert(prefix);
241
242         r = sd_bus_call_method(bus,
243                                "org.freedesktop.machine1",
244                                "/org/freedesktop/machine1",
245                                "org.freedesktop.machine1.Manager",
246                                "GetMachineOSRelease",
247                                NULL,
248                                &reply,
249                                "s", name);
250         if (r < 0)
251                 return r;
252
253         r = sd_bus_message_enter_container(reply, 'a', "{ss}");
254         if (r < 0)
255                 return bus_log_parse_error(r);
256
257         while ((r = sd_bus_message_read(reply, "{ss}", &k, &v)) > 0) {
258                 if (streq(k, "PRETTY_NAME"))
259                         pretty = v;
260
261         }
262         if (r < 0)
263                 return bus_log_parse_error(r);
264
265         r = sd_bus_message_exit_container(reply);
266         if (r < 0)
267                 return bus_log_parse_error(r);
268
269         if (pretty)
270                 printf("%s%s\n", prefix, pretty);
271
272         return 0;
273 }
274
275 typedef struct MachineStatusInfo {
276         char *name;
277         sd_id128_t id;
278         char *class;
279         char *service;
280         char *unit;
281         char *root_directory;
282         pid_t leader;
283         usec_t timestamp;
284         int *netif;
285         unsigned n_netif;
286 } MachineStatusInfo;
287
288 static void print_machine_status_info(sd_bus *bus, MachineStatusInfo *i) {
289         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
290         char since2[FORMAT_TIMESTAMP_MAX], *s2;
291         int ifi = -1;
292
293         assert(i);
294
295         fputs(strna(i->name), stdout);
296
297         if (!sd_id128_equal(i->id, SD_ID128_NULL))
298                 printf("(" SD_ID128_FORMAT_STR ")\n", SD_ID128_FORMAT_VAL(i->id));
299         else
300                 putchar('\n');
301
302         s1 = format_timestamp_relative(since1, sizeof(since1), i->timestamp);
303         s2 = format_timestamp(since2, sizeof(since2), i->timestamp);
304
305         if (s1)
306                 printf("\t   Since: %s; %s\n", s2, s1);
307         else if (s2)
308                 printf("\t   Since: %s\n", s2);
309
310         if (i->leader > 0) {
311                 _cleanup_free_ char *t = NULL;
312
313                 printf("\t  Leader: %u", (unsigned) i->leader);
314
315                 get_process_comm(i->leader, &t);
316                 if (t)
317                         printf(" (%s)", t);
318
319                 putchar('\n');
320         }
321
322         if (i->service) {
323                 printf("\t Service: %s", i->service);
324
325                 if (i->class)
326                         printf("; class %s", i->class);
327
328                 putchar('\n');
329         } else if (i->class)
330                 printf("\t   Class: %s\n", i->class);
331
332         if (i->root_directory)
333                 printf("\t    Root: %s\n", i->root_directory);
334
335         if (i->n_netif > 0) {
336                 unsigned c;
337
338                 fputs("\t   Iface:", stdout);
339
340                 for (c = 0; c < i->n_netif; c++) {
341                         char name[IF_NAMESIZE+1] = "";
342
343                         if (if_indextoname(i->netif[c], name)) {
344                                 fputc(' ', stdout);
345                                 fputs(name, stdout);
346
347                                 if (ifi < 0)
348                                         ifi = i->netif[c];
349                                 else
350                                         ifi = 0;
351                         } else
352                                 printf(" %i", i->netif[c]);
353                 }
354
355                 fputc('\n', stdout);
356         }
357
358         print_addresses(bus, i->name, ifi,
359                        "\t Address: ",
360                        "\t          ");
361
362         print_os_release(bus, i->name, "\t      OS: ");
363
364         if (i->unit) {
365                 printf("\t    Unit: %s\n", i->unit);
366                 show_unit_cgroup(bus, i->unit, i->leader);
367         }
368 }
369
370 static int map_netif(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
371         MachineStatusInfo *i = userdata;
372         size_t l;
373         const void *v;
374         int r;
375
376         assert_cc(sizeof(int32_t) == sizeof(int));
377         r = sd_bus_message_read_array(m, SD_BUS_TYPE_INT32, &v, &l);
378         if (r < 0)
379                 return r;
380         if (r == 0)
381                 return -EBADMSG;
382
383         i->n_netif = l / sizeof(int32_t);
384         i->netif = memdup(v, l);
385         if (!i->netif)
386                 return -ENOMEM;
387
388         return 0;
389 }
390
391 static int show_info(const char *verb, sd_bus *bus, const char *path, bool *new_line) {
392
393         static const struct bus_properties_map map[]  = {
394                 { "Name",              "s",  NULL,          offsetof(MachineStatusInfo, name) },
395                 { "Class",             "s",  NULL,          offsetof(MachineStatusInfo, class) },
396                 { "Service",           "s",  NULL,          offsetof(MachineStatusInfo, service) },
397                 { "Unit",              "s",  NULL,          offsetof(MachineStatusInfo, unit) },
398                 { "RootDirectory",     "s",  NULL,          offsetof(MachineStatusInfo, root_directory) },
399                 { "Leader",            "u",  NULL,          offsetof(MachineStatusInfo, leader) },
400                 { "Timestamp",         "t",  NULL,          offsetof(MachineStatusInfo, timestamp) },
401                 { "Id",                "ay", bus_map_id128, offsetof(MachineStatusInfo, id) },
402                 { "NetworkInterfaces", "ai", map_netif,     0 },
403                 {}
404         };
405
406         MachineStatusInfo info = {};
407         int r;
408
409         assert(path);
410         assert(new_line);
411
412         r = bus_map_all_properties(bus,
413                                    "org.freedesktop.machine1",
414                                    path,
415                                    map,
416                                    &info);
417         if (r < 0)
418                 return log_error_errno(r, "Could not get properties: %m");
419
420         if (*new_line)
421                 printf("\n");
422         *new_line = true;
423
424         print_machine_status_info(bus, &info);
425
426         free(info.name);
427         free(info.class);
428         free(info.service);
429         free(info.unit);
430         free(info.root_directory);
431         free(info.netif);
432
433         return r;
434 }
435
436 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
437         int r;
438
439         if (*new_line)
440                 printf("\n");
441
442         *new_line = true;
443
444         r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
445         if (r < 0)
446                 log_error_errno(r, "Could not get properties: %m");
447
448         return r;
449 }
450
451 static int show(sd_bus *bus, char **args, unsigned n) {
452         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
453         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
454         int r = 0;
455         unsigned i;
456         bool properties, new_line = false;
457
458         assert(bus);
459         assert(args);
460
461         properties = !strstr(args[0], "status");
462
463         pager_open_if_enabled();
464
465         if (properties && n <= 1) {
466
467                 /* If no argument is specified, inspect the manager
468                  * itself */
469                 r = show_properties(bus, "/org/freedesktop/machine1", &new_line);
470                 if (r < 0)
471                         return r;
472         }
473
474         for (i = 1; i < n; i++) {
475                 const char *path = NULL;
476
477                 r = sd_bus_call_method(
478                                         bus,
479                                         "org.freedesktop.machine1",
480                                         "/org/freedesktop/machine1",
481                                         "org.freedesktop.machine1.Manager",
482                                         "GetMachine",
483                                         &error,
484                                         &reply,
485                                         "s", args[i]);
486                 if (r < 0) {
487                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
488                         return r;
489                 }
490
491                 r = sd_bus_message_read(reply, "o", &path);
492                 if (r < 0)
493                         return bus_log_parse_error(r);
494
495                 if (properties)
496                         r = show_properties(bus, path, &new_line);
497                 else
498                         r = show_info(args[0], bus, path, &new_line);
499         }
500
501         return r;
502 }
503
504 static int kill_machine(sd_bus *bus, char **args, unsigned n) {
505         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
506         unsigned i;
507
508         assert(args);
509
510         if (!arg_kill_who)
511                 arg_kill_who = "all";
512
513         for (i = 1; i < n; i++) {
514                 int r;
515
516                 r = sd_bus_call_method(
517                                         bus,
518                                         "org.freedesktop.machine1",
519                                         "/org/freedesktop/machine1",
520                                         "org.freedesktop.machine1.Manager",
521                                         "KillMachine",
522                                         &error,
523                                         NULL,
524                                         "ssi", args[i], arg_kill_who, arg_signal);
525                 if (r < 0) {
526                         log_error("Could not kill machine: %s", bus_error_message(&error, -r));
527                         return r;
528                 }
529         }
530
531         return 0;
532 }
533
534 static int reboot_machine(sd_bus *bus, char **args, unsigned n) {
535         arg_kill_who = "leader";
536         arg_signal = SIGINT; /* sysvinit + systemd */
537
538         return kill_machine(bus, args, n);
539 }
540
541 static int poweroff_machine(sd_bus *bus, char **args, unsigned n) {
542         arg_kill_who = "leader";
543         arg_signal = SIGRTMIN+4; /* only systemd */
544
545         return kill_machine(bus, args, n);
546 }
547
548 static int terminate_machine(sd_bus *bus, char **args, unsigned n) {
549         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
550         unsigned i;
551
552         assert(args);
553
554         for (i = 1; i < n; i++) {
555                 int r;
556
557                 r = sd_bus_call_method(
558                                 bus,
559                                 "org.freedesktop.machine1",
560                                 "/org/freedesktop/machine1",
561                                 "org.freedesktop.machine1.Manager",
562                                 "TerminateMachine",
563                                 &error,
564                                 NULL,
565                                 "s", args[i]);
566                 if (r < 0) {
567                         log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
568                         return r;
569                 }
570         }
571
572         return 0;
573 }
574
575 static int openpt_in_namespace(pid_t pid, int flags) {
576         _cleanup_close_pair_ int pair[2] = { -1, -1 };
577         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
578         union {
579                 struct cmsghdr cmsghdr;
580                 uint8_t buf[CMSG_SPACE(sizeof(int))];
581         } control = {};
582         struct msghdr mh = {
583                 .msg_control = &control,
584                 .msg_controllen = sizeof(control),
585         };
586         struct cmsghdr *cmsg;
587         int master = -1, r;
588         pid_t child;
589         siginfo_t si;
590
591         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
592         if (r < 0)
593                 return r;
594
595         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
596                 return -errno;
597
598         child = fork();
599         if (child < 0)
600                 return -errno;
601
602         if (child == 0) {
603                 pair[0] = safe_close(pair[0]);
604
605                 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
606                 if (r < 0)
607                         _exit(EXIT_FAILURE);
608
609                 master = posix_openpt(flags);
610                 if (master < 0)
611                         _exit(EXIT_FAILURE);
612
613                 cmsg = CMSG_FIRSTHDR(&mh);
614                 cmsg->cmsg_level = SOL_SOCKET;
615                 cmsg->cmsg_type = SCM_RIGHTS;
616                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
617                 memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
618
619                 mh.msg_controllen = cmsg->cmsg_len;
620
621                 if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
622                         _exit(EXIT_FAILURE);
623
624                 _exit(EXIT_SUCCESS);
625         }
626
627         pair[1] = safe_close(pair[1]);
628
629         r = wait_for_terminate(child, &si);
630         if (r < 0)
631                 return r;
632         if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
633                 return -EIO;
634
635         if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
636                 return -errno;
637
638         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
639                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
640                         int *fds;
641                         unsigned n_fds;
642
643                         fds = (int*) CMSG_DATA(cmsg);
644                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
645
646                         if (n_fds != 1) {
647                                 close_many(fds, n_fds);
648                                 return -EIO;
649                         }
650
651                         master = fds[0];
652                 }
653
654         if (master < 0)
655                 return -EIO;
656
657         return master;
658 }
659
660 static int login_machine(sd_bus *bus, char **args, unsigned n) {
661         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL, *reply3 = NULL;
662         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
663         _cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
664         _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
665         _cleanup_event_unref_ sd_event *event = NULL;
666         _cleanup_close_ int master = -1;
667         _cleanup_free_ char *getty = NULL;
668         const char *path, *pty, *p;
669         uint32_t leader;
670         sigset_t mask;
671         int r, ret = 0;
672
673         assert(bus);
674         assert(args);
675
676         if (arg_transport != BUS_TRANSPORT_LOCAL) {
677                 log_error("Login only supported on local machines.");
678                 return -ENOTSUP;
679         }
680
681         r = sd_event_default(&event);
682         if (r < 0)
683                 return log_error_errno(r, "Failed to get event loop: %m");
684
685         r = sd_bus_attach_event(bus, event, 0);
686         if (r < 0)
687                 return log_error_errno(r, "Failed to attach bus to event loop: %m");
688
689         r = sd_bus_call_method(
690                         bus,
691                         "org.freedesktop.machine1",
692                         "/org/freedesktop/machine1",
693                         "org.freedesktop.machine1.Manager",
694                         "GetMachine",
695                         &error,
696                         &reply,
697                         "s", args[1]);
698         if (r < 0) {
699                 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
700                 return r;
701         }
702
703         r = sd_bus_message_read(reply, "o", &path);
704         if (r < 0)
705                 return bus_log_parse_error(r);
706
707         r = sd_bus_get_property(
708                         bus,
709                         "org.freedesktop.machine1",
710                         path,
711                         "org.freedesktop.machine1.Machine",
712                         "Leader",
713                         &error,
714                         &reply2,
715                         "u");
716         if (r < 0)
717                 return log_error_errno(r, "Failed to retrieve PID of leader: %m");
718
719         r = sd_bus_message_read(reply2, "u", &leader);
720         if (r < 0)
721                 return bus_log_parse_error(r);
722
723         master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
724         if (master < 0)
725                 return log_error_errno(master, "Failed to acquire pseudo tty: %m");
726
727         pty = ptsname(master);
728         if (!pty) {
729                 log_error("Failed to get pty name: %m");
730                 return -errno;
731         }
732
733         p = startswith(pty, "/dev/pts/");
734         if (!p) {
735                 log_error("Invalid pty name %s.", pty);
736                 return -EIO;
737         }
738
739         r = sd_bus_open_system_container(&container_bus, args[1]);
740         if (r < 0)
741                 return log_error_errno(r, "Failed to get container bus: %m");
742
743         getty = strjoin("container-getty@", p, ".service", NULL);
744         if (!getty)
745                 return log_oom();
746
747         if (unlockpt(master) < 0) {
748                 log_error("Failed to unlock tty: %m");
749                 return -errno;
750         }
751
752         r = sd_bus_call_method(container_bus,
753                                "org.freedesktop.systemd1",
754                                "/org/freedesktop/systemd1",
755                                "org.freedesktop.systemd1.Manager",
756                                "StartUnit",
757                                &error, &reply3,
758                                "ss", getty, "replace");
759         if (r < 0) {
760                 log_error("Failed to start getty service: %s", bus_error_message(&error, r));
761                 return r;
762         }
763
764         container_bus = sd_bus_unref(container_bus);
765
766         assert_se(sigemptyset(&mask) == 0);
767         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
768         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
769
770         log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
771
772         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
773         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
774
775         r = pty_forward_new(event, master, &forward);
776         if (r < 0)
777                 return log_error_errno(r, "Failed to create PTY forwarder: %m");
778
779         r = sd_event_loop(event);
780         if (r < 0)
781                 return log_error_errno(r, "Failed to run event loop: %m");
782
783         forward = pty_forward_free(forward);
784
785         fputc('\n', stdout);
786
787         log_info("Connection to container %s terminated.", args[1]);
788
789         sd_event_get_exit_code(event, &ret);
790         return ret;
791 }
792
793 static void help(void) {
794         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
795                "Send control commands to or query the virtual machine and container registration manager.\n\n"
796                "  -h --help              Show this help\n"
797                "     --version           Show package version\n"
798                "     --no-pager          Do not pipe output into a pager\n"
799                "     --no-legend         Do not show the headers and footers\n"
800                "  -H --host=[USER@]HOST  Operate on remote host\n"
801                "  -M --machine=CONTAINER Operate on local container\n"
802                "  -p --property=NAME     Show only properties by this name\n"
803                "  -a --all               Show all properties, including empty ones\n"
804                "  -l --full              Do not ellipsize output\n"
805                "     --kill-who=WHO      Who to send signal to\n"
806                "  -s --signal=SIGNAL     Which signal to send\n\n"
807                "Commands:\n"
808                "  list                   List running VMs and containers\n"
809                "  status NAME...         Show VM/container status\n"
810                "  show NAME...           Show properties of one or more VMs/containers\n"
811                "  login NAME             Get a login prompt on a container\n"
812                "  poweroff NAME...       Power off one or more containers\n"
813                "  reboot NAME...         Reboot one or more containers\n"
814                "  kill NAME...           Send signal to processes of a VM/container\n"
815                "  terminate NAME...      Terminate one or more VMs/containers\n",
816                program_invocation_short_name);
817 }
818
819 static int parse_argv(int argc, char *argv[]) {
820
821         enum {
822                 ARG_VERSION = 0x100,
823                 ARG_NO_PAGER,
824                 ARG_NO_LEGEND,
825                 ARG_KILL_WHO,
826         };
827
828         static const struct option options[] = {
829                 { "help",            no_argument,       NULL, 'h'                 },
830                 { "version",         no_argument,       NULL, ARG_VERSION         },
831                 { "property",        required_argument, NULL, 'p'                 },
832                 { "all",             no_argument,       NULL, 'a'                 },
833                 { "full",            no_argument,       NULL, 'l'                 },
834                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
835                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
836                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
837                 { "signal",          required_argument, NULL, 's'                 },
838                 { "host",            required_argument, NULL, 'H'                 },
839                 { "machine",         required_argument, NULL, 'M'                 },
840                 {}
841         };
842
843         int c, r;
844
845         assert(argc >= 0);
846         assert(argv);
847
848         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
849
850                 switch (c) {
851
852                 case 'h':
853                         help();
854                         return 0;
855
856                 case ARG_VERSION:
857                         puts(PACKAGE_STRING);
858                         puts(SYSTEMD_FEATURES);
859                         return 0;
860
861                 case 'p':
862                         r = strv_extend(&arg_property, optarg);
863                         if (r < 0)
864                                 return log_oom();
865
866                         /* If the user asked for a particular
867                          * property, show it to him, even if it is
868                          * empty. */
869                         arg_all = true;
870                         break;
871
872                 case 'a':
873                         arg_all = true;
874                         break;
875
876                 case 'l':
877                         arg_full = true;
878                         break;
879
880                 case ARG_NO_PAGER:
881                         arg_no_pager = true;
882                         break;
883
884                 case ARG_NO_LEGEND:
885                         arg_legend = false;
886                         break;
887
888                 case ARG_KILL_WHO:
889                         arg_kill_who = optarg;
890                         break;
891
892                 case 's':
893                         arg_signal = signal_from_string_try_harder(optarg);
894                         if (arg_signal < 0) {
895                                 log_error("Failed to parse signal string %s.", optarg);
896                                 return -EINVAL;
897                         }
898                         break;
899
900                 case 'H':
901                         arg_transport = BUS_TRANSPORT_REMOTE;
902                         arg_host = optarg;
903                         break;
904
905                 case 'M':
906                         arg_transport = BUS_TRANSPORT_CONTAINER;
907                         arg_host = optarg;
908                         break;
909
910                 case '?':
911                         return -EINVAL;
912
913                 default:
914                         assert_not_reached("Unhandled option");
915                 }
916
917         return 1;
918 }
919
920 static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
921
922         static const struct {
923                 const char* verb;
924                 const enum {
925                         MORE,
926                         LESS,
927                         EQUAL
928                 } argc_cmp;
929                 const int argc;
930                 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
931         } verbs[] = {
932                 { "list",                  LESS,   1, list_machines     },
933                 { "status",                MORE,   2, show              },
934                 { "show",                  MORE,   1, show              },
935                 { "terminate",             MORE,   2, terminate_machine },
936                 { "reboot",                MORE,   2, reboot_machine    },
937                 { "poweroff",              MORE,   2, poweroff_machine  },
938                 { "kill",                  MORE,   2, kill_machine      },
939                 { "login",                 MORE,   2, login_machine     },
940         };
941
942         int left;
943         unsigned i;
944
945         assert(argc >= 0);
946         assert(argv);
947
948         left = argc - optind;
949
950         if (left <= 0)
951                 /* Special rule: no arguments means "list" */
952                 i = 0;
953         else {
954                 if (streq(argv[optind], "help")) {
955                         help();
956                         return 0;
957                 }
958
959                 for (i = 0; i < ELEMENTSOF(verbs); i++)
960                         if (streq(argv[optind], verbs[i].verb))
961                                 break;
962
963                 if (i >= ELEMENTSOF(verbs)) {
964                         log_error("Unknown operation %s", argv[optind]);
965                         return -EINVAL;
966                 }
967         }
968
969         switch (verbs[i].argc_cmp) {
970
971         case EQUAL:
972                 if (left != verbs[i].argc) {
973                         log_error("Invalid number of arguments.");
974                         return -EINVAL;
975                 }
976
977                 break;
978
979         case MORE:
980                 if (left < verbs[i].argc) {
981                         log_error("Too few arguments.");
982                         return -EINVAL;
983                 }
984
985                 break;
986
987         case LESS:
988                 if (left > verbs[i].argc) {
989                         log_error("Too many arguments.");
990                         return -EINVAL;
991                 }
992
993                 break;
994
995         default:
996                 assert_not_reached("Unknown comparison operator.");
997         }
998
999         return verbs[i].dispatch(bus, argv + optind, left);
1000 }
1001
1002 int main(int argc, char*argv[]) {
1003         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1004         int r;
1005
1006         setlocale(LC_ALL, "");
1007         log_parse_environment();
1008         log_open();
1009
1010         r = parse_argv(argc, argv);
1011         if (r <= 0)
1012                 goto finish;
1013
1014         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1015         if (r < 0) {
1016                 log_error_errno(r, "Failed to create bus connection: %m");
1017                 goto finish;
1018         }
1019
1020         r = machinectl_main(bus, argc, argv);
1021
1022 finish:
1023         pager_close();
1024
1025         strv_free(arg_property);
1026
1027         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1028 }