chiark / gitweb /
treewide: no need to negate errno for log_*_errno()
[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                 log_error_errno(r, "Could not get properties: %m");
419                 return r;
420         }
421
422         if (*new_line)
423                 printf("\n");
424         *new_line = true;
425
426         print_machine_status_info(bus, &info);
427
428         free(info.name);
429         free(info.class);
430         free(info.service);
431         free(info.unit);
432         free(info.root_directory);
433         free(info.netif);
434
435         return r;
436 }
437
438 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
439         int r;
440
441         if (*new_line)
442                 printf("\n");
443
444         *new_line = true;
445
446         r = bus_print_all_properties(bus, "org.freedesktop.machine1", path, arg_property, arg_all);
447         if (r < 0)
448                 log_error_errno(r, "Could not get properties: %m");
449
450         return r;
451 }
452
453 static int show(sd_bus *bus, char **args, unsigned n) {
454         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
455         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
456         int r = 0;
457         unsigned i;
458         bool properties, new_line = false;
459
460         assert(bus);
461         assert(args);
462
463         properties = !strstr(args[0], "status");
464
465         pager_open_if_enabled();
466
467         if (properties && n <= 1) {
468
469                 /* If no argument is specified, inspect the manager
470                  * itself */
471                 r = show_properties(bus, "/org/freedesktop/machine1", &new_line);
472                 if (r < 0)
473                         return r;
474         }
475
476         for (i = 1; i < n; i++) {
477                 const char *path = NULL;
478
479                 r = sd_bus_call_method(
480                                         bus,
481                                         "org.freedesktop.machine1",
482                                         "/org/freedesktop/machine1",
483                                         "org.freedesktop.machine1.Manager",
484                                         "GetMachine",
485                                         &error,
486                                         &reply,
487                                         "s", args[i]);
488                 if (r < 0) {
489                         log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
490                         return r;
491                 }
492
493                 r = sd_bus_message_read(reply, "o", &path);
494                 if (r < 0)
495                         return bus_log_parse_error(r);
496
497                 if (properties)
498                         r = show_properties(bus, path, &new_line);
499                 else
500                         r = show_info(args[0], bus, path, &new_line);
501         }
502
503         return r;
504 }
505
506 static int kill_machine(sd_bus *bus, char **args, unsigned n) {
507         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
508         unsigned i;
509
510         assert(args);
511
512         if (!arg_kill_who)
513                 arg_kill_who = "all";
514
515         for (i = 1; i < n; i++) {
516                 int r;
517
518                 r = sd_bus_call_method(
519                                         bus,
520                                         "org.freedesktop.machine1",
521                                         "/org/freedesktop/machine1",
522                                         "org.freedesktop.machine1.Manager",
523                                         "KillMachine",
524                                         &error,
525                                         NULL,
526                                         "ssi", args[i], arg_kill_who, arg_signal);
527                 if (r < 0) {
528                         log_error("Could not kill machine: %s", bus_error_message(&error, -r));
529                         return r;
530                 }
531         }
532
533         return 0;
534 }
535
536 static int reboot_machine(sd_bus *bus, char **args, unsigned n) {
537         arg_kill_who = "leader";
538         arg_signal = SIGINT; /* sysvinit + systemd */
539
540         return kill_machine(bus, args, n);
541 }
542
543 static int poweroff_machine(sd_bus *bus, char **args, unsigned n) {
544         arg_kill_who = "leader";
545         arg_signal = SIGRTMIN+4; /* only systemd */
546
547         return kill_machine(bus, args, n);
548 }
549
550 static int terminate_machine(sd_bus *bus, char **args, unsigned n) {
551         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
552         unsigned i;
553
554         assert(args);
555
556         for (i = 1; i < n; i++) {
557                 int r;
558
559                 r = sd_bus_call_method(
560                                 bus,
561                                 "org.freedesktop.machine1",
562                                 "/org/freedesktop/machine1",
563                                 "org.freedesktop.machine1.Manager",
564                                 "TerminateMachine",
565                                 &error,
566                                 NULL,
567                                 "s", args[i]);
568                 if (r < 0) {
569                         log_error("Could not terminate machine: %s", bus_error_message(&error, -r));
570                         return r;
571                 }
572         }
573
574         return 0;
575 }
576
577 static int openpt_in_namespace(pid_t pid, int flags) {
578         _cleanup_close_pair_ int pair[2] = { -1, -1 };
579         _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
580         union {
581                 struct cmsghdr cmsghdr;
582                 uint8_t buf[CMSG_SPACE(sizeof(int))];
583         } control = {};
584         struct msghdr mh = {
585                 .msg_control = &control,
586                 .msg_controllen = sizeof(control),
587         };
588         struct cmsghdr *cmsg;
589         int master = -1, r;
590         pid_t child;
591         siginfo_t si;
592
593         r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
594         if (r < 0)
595                 return r;
596
597         if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
598                 return -errno;
599
600         child = fork();
601         if (child < 0)
602                 return -errno;
603
604         if (child == 0) {
605                 pair[0] = safe_close(pair[0]);
606
607                 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
608                 if (r < 0)
609                         _exit(EXIT_FAILURE);
610
611                 master = posix_openpt(flags);
612                 if (master < 0)
613                         _exit(EXIT_FAILURE);
614
615                 cmsg = CMSG_FIRSTHDR(&mh);
616                 cmsg->cmsg_level = SOL_SOCKET;
617                 cmsg->cmsg_type = SCM_RIGHTS;
618                 cmsg->cmsg_len = CMSG_LEN(sizeof(int));
619                 memcpy(CMSG_DATA(cmsg), &master, sizeof(int));
620
621                 mh.msg_controllen = cmsg->cmsg_len;
622
623                 if (sendmsg(pair[1], &mh, MSG_NOSIGNAL) < 0)
624                         _exit(EXIT_FAILURE);
625
626                 _exit(EXIT_SUCCESS);
627         }
628
629         pair[1] = safe_close(pair[1]);
630
631         r = wait_for_terminate(child, &si);
632         if (r < 0)
633                 return r;
634         if (si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
635                 return -EIO;
636
637         if (recvmsg(pair[0], &mh, MSG_NOSIGNAL|MSG_CMSG_CLOEXEC) < 0)
638                 return -errno;
639
640         for (cmsg = CMSG_FIRSTHDR(&mh); cmsg; cmsg = CMSG_NXTHDR(&mh, cmsg))
641                 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) {
642                         int *fds;
643                         unsigned n_fds;
644
645                         fds = (int*) CMSG_DATA(cmsg);
646                         n_fds = (cmsg->cmsg_len - CMSG_LEN(0)) / sizeof(int);
647
648                         if (n_fds != 1) {
649                                 close_many(fds, n_fds);
650                                 return -EIO;
651                         }
652
653                         master = fds[0];
654                 }
655
656         if (master < 0)
657                 return -EIO;
658
659         return master;
660 }
661
662 static int login_machine(sd_bus *bus, char **args, unsigned n) {
663         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL, *reply2 = NULL, *reply3 = NULL;
664         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
665         _cleanup_bus_close_unref_ sd_bus *container_bus = NULL;
666         _cleanup_(pty_forward_freep) PTYForward *forward = NULL;
667         _cleanup_event_unref_ sd_event *event = NULL;
668         _cleanup_close_ int master = -1;
669         _cleanup_free_ char *getty = NULL;
670         const char *path, *pty, *p;
671         uint32_t leader;
672         sigset_t mask;
673         int r, ret = 0;
674
675         assert(bus);
676         assert(args);
677
678         if (arg_transport != BUS_TRANSPORT_LOCAL) {
679                 log_error("Login only supported on local machines.");
680                 return -ENOTSUP;
681         }
682
683         r = sd_event_default(&event);
684         if (r < 0) {
685                 log_error_errno(r, "Failed to get event loop: %m");
686                 return r;
687         }
688
689         r = sd_bus_attach_event(bus, event, 0);
690         if (r < 0) {
691                 log_error_errno(r, "Failed to attach bus to event loop: %m");
692                 return r;
693         }
694
695         r = sd_bus_call_method(
696                         bus,
697                         "org.freedesktop.machine1",
698                         "/org/freedesktop/machine1",
699                         "org.freedesktop.machine1.Manager",
700                         "GetMachine",
701                         &error,
702                         &reply,
703                         "s", args[1]);
704         if (r < 0) {
705                 log_error("Could not get path to machine: %s", bus_error_message(&error, -r));
706                 return r;
707         }
708
709         r = sd_bus_message_read(reply, "o", &path);
710         if (r < 0)
711                 return bus_log_parse_error(r);
712
713         r = sd_bus_get_property(
714                         bus,
715                         "org.freedesktop.machine1",
716                         path,
717                         "org.freedesktop.machine1.Machine",
718                         "Leader",
719                         &error,
720                         &reply2,
721                         "u");
722         if (r < 0) {
723                 log_error_errno(r, "Failed to retrieve PID of leader: %m");
724                 return r;
725         }
726
727         r = sd_bus_message_read(reply2, "u", &leader);
728         if (r < 0)
729                 return bus_log_parse_error(r);
730
731         master = openpt_in_namespace(leader, O_RDWR|O_NOCTTY|O_CLOEXEC|O_NDELAY);
732         if (master < 0) {
733                 log_error_errno(master, "Failed to acquire pseudo tty: %m");
734                 return master;
735         }
736
737         pty = ptsname(master);
738         if (!pty) {
739                 log_error("Failed to get pty name: %m");
740                 return -errno;
741         }
742
743         p = startswith(pty, "/dev/pts/");
744         if (!p) {
745                 log_error("Invalid pty name %s.", pty);
746                 return -EIO;
747         }
748
749         r = sd_bus_open_system_container(&container_bus, args[1]);
750         if (r < 0) {
751                 log_error_errno(r, "Failed to get container bus: %m");
752                 return r;
753         }
754
755         getty = strjoin("container-getty@", p, ".service", NULL);
756         if (!getty)
757                 return log_oom();
758
759         if (unlockpt(master) < 0) {
760                 log_error("Failed to unlock tty: %m");
761                 return -errno;
762         }
763
764         r = sd_bus_call_method(container_bus,
765                                "org.freedesktop.systemd1",
766                                "/org/freedesktop/systemd1",
767                                "org.freedesktop.systemd1.Manager",
768                                "StartUnit",
769                                &error, &reply3,
770                                "ss", getty, "replace");
771         if (r < 0) {
772                 log_error("Failed to start getty service: %s", bus_error_message(&error, r));
773                 return r;
774         }
775
776         container_bus = sd_bus_unref(container_bus);
777
778         assert_se(sigemptyset(&mask) == 0);
779         sigset_add_many(&mask, SIGWINCH, SIGTERM, SIGINT, -1);
780         assert_se(sigprocmask(SIG_BLOCK, &mask, NULL) == 0);
781
782         log_info("Connected to container %s. Press ^] three times within 1s to exit session.", args[1]);
783
784         sd_event_add_signal(event, NULL, SIGINT, NULL, NULL);
785         sd_event_add_signal(event, NULL, SIGTERM, NULL, NULL);
786
787         r = pty_forward_new(event, master, &forward);
788         if (r < 0) {
789                 log_error_errno(r, "Failed to create PTY forwarder: %m");
790                 return r;
791         }
792
793         r = sd_event_loop(event);
794         if (r < 0) {
795                 log_error_errno(r, "Failed to run event loop: %m");
796                 return r;
797         }
798
799         forward = pty_forward_free(forward);
800
801         fputc('\n', stdout);
802
803         log_info("Connection to container %s terminated.", args[1]);
804
805         sd_event_get_exit_code(event, &ret);
806         return ret;
807 }
808
809 static void help(void) {
810         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
811                "Send control commands to or query the virtual machine and container registration manager.\n\n"
812                "  -h --help              Show this help\n"
813                "     --version           Show package version\n"
814                "     --no-pager          Do not pipe output into a pager\n"
815                "     --no-legend         Do not show the headers and footers\n"
816                "  -H --host=[USER@]HOST  Operate on remote host\n"
817                "  -M --machine=CONTAINER Operate on local container\n"
818                "  -p --property=NAME     Show only properties by this name\n"
819                "  -a --all               Show all properties, including empty ones\n"
820                "  -l --full              Do not ellipsize output\n"
821                "     --kill-who=WHO      Who to send signal to\n"
822                "  -s --signal=SIGNAL     Which signal to send\n\n"
823                "Commands:\n"
824                "  list                   List running VMs and containers\n"
825                "  status NAME...         Show VM/container status\n"
826                "  show NAME...           Show properties of one or more VMs/containers\n"
827                "  login NAME             Get a login prompt on a container\n"
828                "  poweroff NAME...       Power off one or more containers\n"
829                "  reboot NAME...         Reboot one or more containers\n"
830                "  kill NAME...           Send signal to processes of a VM/container\n"
831                "  terminate NAME...      Terminate one or more VMs/containers\n",
832                program_invocation_short_name);
833 }
834
835 static int parse_argv(int argc, char *argv[]) {
836
837         enum {
838                 ARG_VERSION = 0x100,
839                 ARG_NO_PAGER,
840                 ARG_NO_LEGEND,
841                 ARG_KILL_WHO,
842         };
843
844         static const struct option options[] = {
845                 { "help",            no_argument,       NULL, 'h'                 },
846                 { "version",         no_argument,       NULL, ARG_VERSION         },
847                 { "property",        required_argument, NULL, 'p'                 },
848                 { "all",             no_argument,       NULL, 'a'                 },
849                 { "full",            no_argument,       NULL, 'l'                 },
850                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
851                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
852                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
853                 { "signal",          required_argument, NULL, 's'                 },
854                 { "host",            required_argument, NULL, 'H'                 },
855                 { "machine",         required_argument, NULL, 'M'                 },
856                 {}
857         };
858
859         int c, r;
860
861         assert(argc >= 0);
862         assert(argv);
863
864         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
865
866                 switch (c) {
867
868                 case 'h':
869                         help();
870                         return 0;
871
872                 case ARG_VERSION:
873                         puts(PACKAGE_STRING);
874                         puts(SYSTEMD_FEATURES);
875                         return 0;
876
877                 case 'p':
878                         r = strv_extend(&arg_property, optarg);
879                         if (r < 0)
880                                 return log_oom();
881
882                         /* If the user asked for a particular
883                          * property, show it to him, even if it is
884                          * empty. */
885                         arg_all = true;
886                         break;
887
888                 case 'a':
889                         arg_all = true;
890                         break;
891
892                 case 'l':
893                         arg_full = true;
894                         break;
895
896                 case ARG_NO_PAGER:
897                         arg_no_pager = true;
898                         break;
899
900                 case ARG_NO_LEGEND:
901                         arg_legend = false;
902                         break;
903
904                 case ARG_KILL_WHO:
905                         arg_kill_who = optarg;
906                         break;
907
908                 case 's':
909                         arg_signal = signal_from_string_try_harder(optarg);
910                         if (arg_signal < 0) {
911                                 log_error("Failed to parse signal string %s.", optarg);
912                                 return -EINVAL;
913                         }
914                         break;
915
916                 case 'H':
917                         arg_transport = BUS_TRANSPORT_REMOTE;
918                         arg_host = optarg;
919                         break;
920
921                 case 'M':
922                         arg_transport = BUS_TRANSPORT_CONTAINER;
923                         arg_host = optarg;
924                         break;
925
926                 case '?':
927                         return -EINVAL;
928
929                 default:
930                         assert_not_reached("Unhandled option");
931                 }
932
933         return 1;
934 }
935
936 static int machinectl_main(sd_bus *bus, int argc, char *argv[]) {
937
938         static const struct {
939                 const char* verb;
940                 const enum {
941                         MORE,
942                         LESS,
943                         EQUAL
944                 } argc_cmp;
945                 const int argc;
946                 int (* const dispatch)(sd_bus *bus, char **args, unsigned n);
947         } verbs[] = {
948                 { "list",                  LESS,   1, list_machines     },
949                 { "status",                MORE,   2, show              },
950                 { "show",                  MORE,   1, show              },
951                 { "terminate",             MORE,   2, terminate_machine },
952                 { "reboot",                MORE,   2, reboot_machine    },
953                 { "poweroff",              MORE,   2, poweroff_machine  },
954                 { "kill",                  MORE,   2, kill_machine      },
955                 { "login",                 MORE,   2, login_machine     },
956         };
957
958         int left;
959         unsigned i;
960
961         assert(argc >= 0);
962         assert(argv);
963
964         left = argc - optind;
965
966         if (left <= 0)
967                 /* Special rule: no arguments means "list" */
968                 i = 0;
969         else {
970                 if (streq(argv[optind], "help")) {
971                         help();
972                         return 0;
973                 }
974
975                 for (i = 0; i < ELEMENTSOF(verbs); i++)
976                         if (streq(argv[optind], verbs[i].verb))
977                                 break;
978
979                 if (i >= ELEMENTSOF(verbs)) {
980                         log_error("Unknown operation %s", argv[optind]);
981                         return -EINVAL;
982                 }
983         }
984
985         switch (verbs[i].argc_cmp) {
986
987         case EQUAL:
988                 if (left != verbs[i].argc) {
989                         log_error("Invalid number of arguments.");
990                         return -EINVAL;
991                 }
992
993                 break;
994
995         case MORE:
996                 if (left < verbs[i].argc) {
997                         log_error("Too few arguments.");
998                         return -EINVAL;
999                 }
1000
1001                 break;
1002
1003         case LESS:
1004                 if (left > verbs[i].argc) {
1005                         log_error("Too many arguments.");
1006                         return -EINVAL;
1007                 }
1008
1009                 break;
1010
1011         default:
1012                 assert_not_reached("Unknown comparison operator.");
1013         }
1014
1015         return verbs[i].dispatch(bus, argv + optind, left);
1016 }
1017
1018 int main(int argc, char*argv[]) {
1019         _cleanup_bus_close_unref_ sd_bus *bus = NULL;
1020         int r;
1021
1022         setlocale(LC_ALL, "");
1023         log_parse_environment();
1024         log_open();
1025
1026         r = parse_argv(argc, argv);
1027         if (r <= 0)
1028                 goto finish;
1029
1030         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1031         if (r < 0) {
1032                 log_error_errno(r, "Failed to create bus connection: %m");
1033                 goto finish;
1034         }
1035
1036         r = machinectl_main(bus, argc, argv);
1037
1038 finish:
1039         pager_close();
1040
1041         strv_free(arg_property);
1042
1043         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1044 }