chiark / gitweb /
rtnl: when querying local addresses and gateways, take address family into account
[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                 return log_error_errno(errno, "Failed to get pty name: %m");
730
731         p = startswith(pty, "/dev/pts/");
732         if (!p) {
733                 log_error("Invalid pty name %s.", pty);
734                 return -EIO;
735         }
736
737         r = sd_bus_open_system_container(&container_bus, args[1]);
738         if (r < 0)
739                 return log_error_errno(r, "Failed to get container bus: %m");
740
741         getty = strjoin("container-getty@", p, ".service", NULL);
742         if (!getty)
743                 return log_oom();
744
745         if (unlockpt(master) < 0)
746                 return log_error_errno(errno, "Failed to unlock tty: %m");
747
748         r = sd_bus_call_method(container_bus,
749                                "org.freedesktop.systemd1",
750                                "/org/freedesktop/systemd1",
751                                "org.freedesktop.systemd1.Manager",
752                                "StartUnit",
753                                &error, &reply3,
754                                "ss", getty, "replace");
755         if (r < 0) {
756                 log_error("Failed to start getty service: %s", bus_error_message(&error, r));
757                 return r;
758         }
759
760         container_bus = sd_bus_unref(container_bus);
761
762         assert_se(sigemptyset(&mask) == 0);
763         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
764         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
765
766         log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
767
768         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
769         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
770
771         r = pty_forward_new(event, master, &forward);
772         if (r < 0)
773                 return log_error_errno(r, "Failed to create PTY forwarder: %m");
774
775         r = sd_event_loop(event);
776         if (r < 0)
777                 return log_error_errno(r, "Failed to run event loop: %m");
778
779         forward = pty_forward_free(forward);
780
781         fputc('\n', stdout);
782
783         log_info("Connection to container %s terminated.", args[1]);
784
785         sd_event_get_exit_code(event, &ret);
786         return ret;
787 }
788
789 static void help(void) {
790         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
791                "Send control commands to or query the virtual machine and container registration manager.\n\n"
792                "  -h --help              Show this help\n"
793                "     --version           Show package version\n"
794                "     --no-pager          Do not pipe output into a pager\n"
795                "     --no-legend         Do not show the headers and footers\n"
796                "  -H --host=[USER@]HOST  Operate on remote host\n"
797                "  -M --machine=CONTAINER Operate on local container\n"
798                "  -p --property=NAME     Show only properties by this name\n"
799                "  -a --all               Show all properties, including empty ones\n"
800                "  -l --full              Do not ellipsize output\n"
801                "     --kill-who=WHO      Who to send signal to\n"
802                "  -s --signal=SIGNAL     Which signal to send\n\n"
803                "Commands:\n"
804                "  list                   List running VMs and containers\n"
805                "  status NAME...         Show VM/container status\n"
806                "  show NAME...           Show properties of one or more VMs/containers\n"
807                "  login NAME             Get a login prompt on a container\n"
808                "  poweroff NAME...       Power off one or more containers\n"
809                "  reboot NAME...         Reboot one or more containers\n"
810                "  kill NAME...           Send signal to processes of a VM/container\n"
811                "  terminate NAME...      Terminate one or more VMs/containers\n",
812                program_invocation_short_name);
813 }
814
815 static int parse_argv(int argc, char *argv[]) {
816
817         enum {
818                 ARG_VERSION = 0x100,
819                 ARG_NO_PAGER,
820                 ARG_NO_LEGEND,
821                 ARG_KILL_WHO,
822         };
823
824         static const struct option options[] = {
825                 { "help",            no_argument,       NULL, 'h'                 },
826                 { "version",         no_argument,       NULL, ARG_VERSION         },
827                 { "property",        required_argument, NULL, 'p'                 },
828                 { "all",             no_argument,       NULL, 'a'                 },
829                 { "full",            no_argument,       NULL, 'l'                 },
830                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
831                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
832                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
833                 { "signal",          required_argument, NULL, 's'                 },
834                 { "host",            required_argument, NULL, 'H'                 },
835                 { "machine",         required_argument, NULL, 'M'                 },
836                 {}
837         };
838
839         int c, r;
840
841         assert(argc >= 0);
842         assert(argv);
843
844         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
845
846                 switch (c) {
847
848                 case 'h':
849                         help();
850                         return 0;
851
852                 case ARG_VERSION:
853                         puts(PACKAGE_STRING);
854                         puts(SYSTEMD_FEATURES);
855                         return 0;
856
857                 case 'p':
858                         r = strv_extend(&arg_property, optarg);
859                         if (r < 0)
860                                 return log_oom();
861
862                         /* If the user asked for a particular
863                          * property, show it to him, even if it is
864                          * empty. */
865                         arg_all = true;
866                         break;
867
868                 case 'a':
869                         arg_all = true;
870                         break;
871
872                 case 'l':
873                         arg_full = true;
874                         break;
875
876                 case ARG_NO_PAGER:
877                         arg_no_pager = true;
878                         break;
879
880                 case ARG_NO_LEGEND:
881                         arg_legend = false;
882                         break;
883
884                 case ARG_KILL_WHO:
885                         arg_kill_who = optarg;
886                         break;
887
888                 case 's':
889                         arg_signal = signal_from_string_try_harder(optarg);
890                         if (arg_signal < 0) {
891                                 log_error("Failed to parse signal string %s.", optarg);
892                                 return -EINVAL;
893                         }
894                         break;
895
896                 case 'H':
897                         arg_transport = BUS_TRANSPORT_REMOTE;
898                         arg_host = optarg;
899                         break;
900
901                 case 'M':
902                         arg_transport = BUS_TRANSPORT_CONTAINER;
903                         arg_host = optarg;
904                         break;
905
906                 case '?':
907                         return -EINVAL;
908
909                 default:
910                         assert_not_reached("Unhandled option");
911                 }
912
913         return 1;
914 }
915
916 static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
917
918         static const struct {
919                 const char* verb;
920                 const enum {
921                         MORE,
922                         LESS,
923                         EQUAL
924                 } argc_cmp;
925                 const int argc;
926                 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
927         } verbs[] = {
928                 { "list",                  LESS,   1, list_machines     },
929                 { "status",                MORE,   2, show              },
930                 { "show",                  MORE,   1, show              },
931                 { "terminate",             MORE,   2, terminate_machine },
932                 { "reboot",                MORE,   2, reboot_machine    },
933                 { "poweroff",              MORE,   2, poweroff_machine  },
934                 { "kill",                  MORE,   2, kill_machine      },
935                 { "login",                 MORE,   2, login_machine     },
936         };
937
938         int left;
939         unsigned i;
940
941         assert(argc >= 0);
942         assert(argv);
943
944         left = argc - optind;
945
946         if (left <= 0)
947                 /* Special rule: no arguments means "list" */
948                 i = 0;
949         else {
950                 if (streq(argv[optind], "help")) {
951                         help();
952                         return 0;
953                 }
954
955                 for (i = 0; i < ELEMENTSOF(verbs); i++)
956                         if (streq(argv[optind], verbs[i].verb))
957                                 break;
958
959                 if (i >= ELEMENTSOF(verbs)) {
960                         log_error("Unknown operation %s", argv[optind]);
961                         return -EINVAL;
962                 }
963         }
964
965         switch (verbs[i].argc_cmp) {
966
967         case EQUAL:
968                 if (left != verbs[i].argc) {
969                         log_error("Invalid number of arguments.");
970                         return -EINVAL;
971                 }
972
973                 break;
974
975         case MORE:
976                 if (left < verbs[i].argc) {
977                         log_error("Too few arguments.");
978                         return -EINVAL;
979                 }
980
981                 break;
982
983         case LESS:
984                 if (left > verbs[i].argc) {
985                         log_error("Too many arguments.");
986                         return -EINVAL;
987                 }
988
989                 break;
990
991         default:
992                 assert_not_reached("Unknown comparison operator.");
993         }
994
995         return verbs[i].dispatch(bus, argv + optind, left);
996 }
997
998 int main(int argc, char*argv[]) {
999         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1000         int r;
1001
1002         setlocale(LC_ALL, "");
1003         log_parse_environment();
1004         log_open();
1005
1006         r = parse_argv(argc, argv);
1007         if (r <= 0)
1008                 goto finish;
1009
1010         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1011         if (r < 0) {
1012                 log_error_errno(r, "Failed to create bus connection: %m");
1013                 goto finish;
1014         }
1015
1016         r = machinectl_main(bus, argc, argv);
1017
1018 finish:
1019         pager_close();
1020
1021         strv_free(arg_property);
1022
1023         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1024 }