chiark / gitweb /
util: make malloc0 ask calloc for one block of size n
[elogind.git] / src / login / loginctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2010 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 <unistd.h>
23 #include <errno.h>
24 #include <string.h>
25 #include <getopt.h>
26 #include <locale.h>
27
28 #include "sd-bus.h"
29 #include "sd-login.h"
30 #include "bus-util.h"
31 #include "bus-error.h"
32 #include "log.h"
33 #include "util.h"
34 #include "macro.h"
35 #include "pager.h"
36 #include "build.h"
37 #include "strv.h"
38 #include "unit-name.h"
39 #include "sysfs-show.h"
40 // #include "logs-show.h"
41 #include "cgroup-show.h"
42 #include "cgroup-util.h"
43 #include "spawn-polkit-agent.h"
44 #include "verbs.h"
45 #include "process-util.h"
46 #include "terminal-util.h"
47 #include "signal-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 static bool arg_ask_password = true;
59 #if 0
60 static unsigned arg_lines = 10;
61 static OutputMode arg_output = OUTPUT_SHORT;
62 #endif // 0
63
64 static void pager_open_if_enabled(void) {
65
66         if (arg_no_pager)
67                 return;
68
69         pager_open(false);
70 }
71
72 static void polkit_agent_open_if_enabled(void) {
73
74         /* Open the polkit agent as a child process if necessary */
75
76         if (!arg_ask_password)
77                 return;
78
79         if (arg_transport != BUS_TRANSPORT_LOCAL)
80                 return;
81
82         polkit_agent_open();
83 }
84
85 static OutputFlags get_output_flags(void) {
86
87         return
88                 arg_all * OUTPUT_SHOW_ALL |
89                 arg_full * OUTPUT_FULL_WIDTH |
90                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
91                 on_tty() * OUTPUT_COLOR;
92 }
93
94 static int list_sessions(int argc, char *argv[], void *userdata) {
95         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
96         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
97         const char *id, *user, *seat, *object;
98         sd_bus *bus = userdata;
99         unsigned k = 0;
100         uint32_t uid;
101         int r;
102
103         assert(bus);
104         assert(argv);
105
106         pager_open_if_enabled();
107
108         r = sd_bus_call_method(
109                         bus,
110                         "org.freedesktop.login1",
111                         "/org/freedesktop/login1",
112                         "org.freedesktop.login1.Manager",
113                         "ListSessions",
114                         &error, &reply,
115                         "");
116         if (r < 0) {
117                 log_error("Failed to list sessions: %s", bus_error_message(&error, r));
118                 return r;
119         }
120
121         r = sd_bus_message_enter_container(reply, 'a', "(susso)");
122         if (r < 0)
123                 return bus_log_parse_error(r);
124
125         if (arg_legend)
126                 printf("%10s %10s %-16s %-16s\n", "SESSION", "UID", "USER", "SEAT");
127
128         while ((r = sd_bus_message_read(reply, "(susso)", &id, &uid, &user, &seat, &object)) > 0) {
129                 printf("%10s %10u %-16s %-16s\n", id, (unsigned) uid, user, seat);
130                 k++;
131         }
132         if (r < 0)
133                 return bus_log_parse_error(r);
134
135         if (arg_legend)
136                 printf("\n%u sessions listed.\n", k);
137
138         return 0;
139 }
140
141 static int list_users(int argc, char *argv[], void *userdata) {
142         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
143         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
144         const char *user, *object;
145         sd_bus *bus = userdata;
146         unsigned k = 0;
147         uint32_t uid;
148         int r;
149
150         assert(bus);
151         assert(argv);
152
153         pager_open_if_enabled();
154
155         r = sd_bus_call_method(
156                         bus,
157                         "org.freedesktop.login1",
158                         "/org/freedesktop/login1",
159                         "org.freedesktop.login1.Manager",
160                         "ListUsers",
161                         &error, &reply,
162                         "");
163         if (r < 0) {
164                 log_error("Failed to list users: %s", bus_error_message(&error, r));
165                 return r;
166         }
167
168         r = sd_bus_message_enter_container(reply, 'a', "(uso)");
169         if (r < 0)
170                 return bus_log_parse_error(r);
171
172         if (arg_legend)
173                 printf("%10s %-16s\n", "UID", "USER");
174
175         while ((r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object)) > 0) {
176                 printf("%10u %-16s\n", (unsigned) uid, user);
177                 k++;
178         }
179         if (r < 0)
180                 return bus_log_parse_error(r);
181
182         if (arg_legend)
183                 printf("\n%u users listed.\n", k);
184
185         return 0;
186 }
187
188 static int list_seats(int argc, char *argv[], void *userdata) {
189         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
190         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
191         const char *seat, *object;
192         sd_bus *bus = userdata;
193         unsigned k = 0;
194         int r;
195
196         assert(bus);
197         assert(argv);
198
199         pager_open_if_enabled();
200
201         r = sd_bus_call_method(
202                         bus,
203                         "org.freedesktop.login1",
204                         "/org/freedesktop/login1",
205                         "org.freedesktop.login1.Manager",
206                         "ListSeats",
207                         &error, &reply,
208                         "");
209         if (r < 0) {
210                 log_error("Failed to list seats: %s", bus_error_message(&error, r));
211                 return r;
212         }
213
214         r = sd_bus_message_enter_container(reply, 'a', "(so)");
215         if (r < 0)
216                 return bus_log_parse_error(r);
217
218         if (arg_legend)
219                 printf("%-16s\n", "SEAT");
220
221         while ((r = sd_bus_message_read(reply, "(so)", &seat, &object)) > 0) {
222                 printf("%-16s\n", seat);
223                 k++;
224         }
225         if (r < 0)
226                 return bus_log_parse_error(r);
227
228         if (arg_legend)
229                 printf("\n%u seats listed.\n", k);
230
231         return 0;
232 }
233
234 static int show_unit_cgroup(sd_bus *bus, const char *interface, const char *unit, pid_t leader) {
235         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
236         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
237         _cleanup_free_ char *path = NULL;
238         const char *cgroup;
239         int r;
240         unsigned c;
241
242         assert(bus);
243         assert(unit);
244
245         if (arg_transport != BUS_TRANSPORT_LOCAL)
246                 return 0;
247
248         path = unit_dbus_path_from_name(unit);
249         if (!path)
250                 return -ENOMEM;
251
252         r = sd_bus_get_property(
253                         bus,
254                         "org.freedesktop.systemd1",
255                         path,
256                         interface,
257                         "ControlGroup",
258                         &error, &reply, "s");
259         if (r < 0)
260                 return r;
261
262         r = sd_bus_message_read(reply, "s", &cgroup);
263         if (r < 0)
264                 return r;
265
266         if (isempty(cgroup))
267                 return 0;
268
269         if (cg_is_empty_recursive(ELOGIND_CGROUP_CONTROLLER, cgroup, false) != 0 && leader <= 0)
270                 return 0;
271
272         c = columns();
273         if (c > 18)
274                 c -= 18;
275         else
276                 c = 0;
277
278         show_cgroup_and_extra(ELOGIND_CGROUP_CONTROLLER, cgroup, "\t\t  ", c, false, &leader, leader > 0, get_output_flags());
279         return 0;
280 }
281
282 typedef struct SessionStatusInfo {
283         char *id;
284         uid_t uid;
285         char *name;
286         struct dual_timestamp timestamp;
287         unsigned int vtnr;
288         char *seat;
289         char *tty;
290         char *display;
291         bool remote;
292         char *remote_host;
293         char *remote_user;
294         char *service;
295         pid_t leader;
296         char *type;
297         char *class;
298         char *state;
299         char *scope;
300         char *desktop;
301 } SessionStatusInfo;
302
303 typedef struct UserStatusInfo {
304         uid_t uid;
305         char *name;
306         struct dual_timestamp timestamp;
307         char *state;
308         char **sessions;
309         char *display;
310         char *slice;
311 } UserStatusInfo;
312
313 typedef struct SeatStatusInfo {
314         char *id;
315         char *active_session;
316         char **sessions;
317 } SeatStatusInfo;
318
319 static void session_status_info_clear(SessionStatusInfo *info) {
320         if (info) {
321                 free(info->id);
322                 free(info->name);
323                 free(info->seat);
324                 free(info->tty);
325                 free(info->display);
326                 free(info->remote_host);
327                 free(info->remote_user);
328                 free(info->service);
329                 free(info->type);
330                 free(info->class);
331                 free(info->state);
332                 free(info->scope);
333                 free(info->desktop);
334                 zero(*info);
335         }
336 }
337
338 static void user_status_info_clear(UserStatusInfo *info) {
339         if (info) {
340                 free(info->name);
341                 free(info->state);
342                 strv_free(info->sessions);
343                 free(info->display);
344                 free(info->slice);
345                 zero(*info);
346         }
347 }
348
349 static void seat_status_info_clear(SeatStatusInfo *info) {
350         if (info) {
351                 free(info->id);
352                 free(info->active_session);
353                 strv_free(info->sessions);
354                 zero(*info);
355         }
356 }
357
358 static int prop_map_first_of_struct(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
359         const char *contents;
360         int r;
361
362         r = sd_bus_message_peek_type(m, NULL, &contents);
363         if (r < 0)
364                 return r;
365
366         r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, contents);
367         if (r < 0)
368                 return r;
369
370         if (contents[0] == 's' || contents[0] == 'o') {
371                 const char *s;
372                 char **p = (char **) userdata;
373
374                 r = sd_bus_message_read_basic(m, contents[0], &s);
375                 if (r < 0)
376                         return r;
377
378                 r = free_and_strdup(p, s);
379                 if (r < 0)
380                         return r;
381         } else {
382                 r = sd_bus_message_read_basic(m, contents[0], userdata);
383                 if (r < 0)
384                         return r;
385         }
386
387         r = sd_bus_message_skip(m, contents+1);
388         if (r < 0)
389                 return r;
390
391         r = sd_bus_message_exit_container(m);
392         if (r < 0)
393                 return r;
394
395         return 0;
396 }
397
398 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
399         const char *name;
400         int r;
401
402         assert(bus);
403         assert(m);
404
405         r = sd_bus_message_enter_container(m, 'a', "(so)");
406         if (r < 0)
407                 return r;
408
409         while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
410                 r = strv_extend(userdata, name);
411                 if (r < 0)
412                         return r;
413         }
414         if (r < 0)
415                 return r;
416
417         return sd_bus_message_exit_container(m);
418 }
419
420 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
421
422         static const struct bus_properties_map map[]  = {
423                 { "Id",                  "s",    NULL,                     offsetof(SessionStatusInfo, id)                  },
424                 { "Name",                "s",    NULL,                     offsetof(SessionStatusInfo, name)                },
425                 { "TTY",                 "s",    NULL,                     offsetof(SessionStatusInfo, tty)                 },
426                 { "Display",             "s",    NULL,                     offsetof(SessionStatusInfo, display)             },
427                 { "RemoteHost",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_host)         },
428                 { "RemoteUser",          "s",    NULL,                     offsetof(SessionStatusInfo, remote_user)         },
429                 { "Service",             "s",    NULL,                     offsetof(SessionStatusInfo, service)             },
430                 { "Desktop",             "s",    NULL,                     offsetof(SessionStatusInfo, desktop)             },
431                 { "Type",                "s",    NULL,                     offsetof(SessionStatusInfo, type)                },
432                 { "Class",               "s",    NULL,                     offsetof(SessionStatusInfo, class)               },
433                 { "Scope",               "s",    NULL,                     offsetof(SessionStatusInfo, scope)               },
434                 { "State",               "s",    NULL,                     offsetof(SessionStatusInfo, state)               },
435                 { "VTNr",                "u",    NULL,                     offsetof(SessionStatusInfo, vtnr)                },
436                 { "Leader",              "u",    NULL,                     offsetof(SessionStatusInfo, leader)              },
437                 { "Remote",              "b",    NULL,                     offsetof(SessionStatusInfo, remote)              },
438                 { "Timestamp",           "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.realtime)  },
439                 { "TimestampMonotonic",  "t",    NULL,                     offsetof(SessionStatusInfo, timestamp.monotonic) },
440                 { "User",                "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid)                 },
441                 { "Seat",                "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat)                },
442                 {}
443         };
444
445         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
446         char since2[FORMAT_TIMESTAMP_MAX], *s2;
447         _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
448         int r;
449
450         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
451         if (r < 0)
452                 return log_error_errno(r, "Could not get properties: %m");
453
454         if (*new_line)
455                 printf("\n");
456
457         *new_line = true;
458
459         printf("%s - ", strna(i.id));
460
461         if (i.name)
462                 printf("%s (%u)\n", i.name, (unsigned) i.uid);
463         else
464                 printf("%u\n", (unsigned) i.uid);
465
466         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
467         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
468
469         if (s1)
470                 printf("\t   Since: %s; %s\n", s2, s1);
471         else if (s2)
472                 printf("\t   Since: %s\n", s2);
473
474         if (i.leader > 0) {
475                 _cleanup_free_ char *t = NULL;
476
477                 printf("\t  Leader: %u", (unsigned) i.leader);
478
479                 get_process_comm(i.leader, &t);
480                 if (t)
481                         printf(" (%s)", t);
482
483                 printf("\n");
484         }
485
486         if (!isempty(i.seat)) {
487                 printf("\t    Seat: %s", i.seat);
488
489                 if (i.vtnr > 0)
490                         printf("; vc%u", i.vtnr);
491
492                 printf("\n");
493         }
494
495         if (i.tty)
496                 printf("\t     TTY: %s\n", i.tty);
497         else if (i.display)
498                 printf("\t Display: %s\n", i.display);
499
500         if (i.remote_host && i.remote_user)
501                 printf("\t  Remote: %s@%s\n", i.remote_user, i.remote_host);
502         else if (i.remote_host)
503                 printf("\t  Remote: %s\n", i.remote_host);
504         else if (i.remote_user)
505                 printf("\t  Remote: user %s\n", i.remote_user);
506         else if (i.remote)
507                 printf("\t  Remote: Yes\n");
508
509         if (i.service) {
510                 printf("\t Service: %s", i.service);
511
512                 if (i.type)
513                         printf("; type %s", i.type);
514
515                 if (i.class)
516                         printf("; class %s", i.class);
517
518                 printf("\n");
519         } else if (i.type) {
520                 printf("\t    Type: %s", i.type);
521
522                 if (i.class)
523                         printf("; class %s", i.class);
524
525                 printf("\n");
526         } else if (i.class)
527                 printf("\t   Class: %s\n", i.class);
528
529         if (!isempty(i.desktop))
530                 printf("\t Desktop: %s\n", i.desktop);
531
532         if (i.state)
533                 printf("\t   State: %s\n", i.state);
534
535         if (i.scope) {
536                 printf("\t    Unit: %s\n", i.scope);
537                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
538 #if 0
539                 if (arg_transport == BUS_TRANSPORT_LOCAL) {
540
541                         show_journal_by_unit(
542                                         stdout,
543                                         i.scope,
544                                         arg_output,
545                                         0,
546                                         i.timestamp.monotonic,
547                                         arg_lines,
548                                         0,
549                                         get_output_flags() | OUTPUT_BEGIN_NEWLINE,
550                                         SD_JOURNAL_LOCAL_ONLY,
551                                         true,
552                                         NULL);
553                 }
554
555 #endif // 0
556         }
557
558         return 0;
559 }
560
561 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
562
563         static const struct bus_properties_map map[]  = {
564                 { "Name",               "s",     NULL,                     offsetof(UserStatusInfo, name)                },
565                 { "Slice",              "s",     NULL,                     offsetof(UserStatusInfo, slice)               },
566                 { "State",              "s",     NULL,                     offsetof(UserStatusInfo, state)               },
567                 { "UID",                "u",     NULL,                     offsetof(UserStatusInfo, uid)                 },
568                 { "Timestamp",          "t",     NULL,                     offsetof(UserStatusInfo, timestamp.realtime)  },
569                 { "TimestampMonotonic", "t",     NULL,                     offsetof(UserStatusInfo, timestamp.monotonic) },
570                 { "Display",            "(so)",  prop_map_first_of_struct, offsetof(UserStatusInfo, display)             },
571                 { "Sessions",           "a(so)", prop_map_sessions_strv,   offsetof(UserStatusInfo, sessions)            },
572                 {}
573         };
574
575         char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
576         char since2[FORMAT_TIMESTAMP_MAX], *s2;
577         _cleanup_(user_status_info_clear) UserStatusInfo i = {};
578         int r;
579
580         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
581         if (r < 0)
582                 return log_error_errno(r, "Could not get properties: %m");
583
584         if (*new_line)
585                 printf("\n");
586
587         *new_line = true;
588
589         if (i.name)
590                 printf("%s (%u)\n", i.name, (unsigned) i.uid);
591         else
592                 printf("%u\n", (unsigned) i.uid);
593
594         s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
595         s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
596
597         if (s1)
598                 printf("\t   Since: %s; %s\n", s2, s1);
599         else if (s2)
600                 printf("\t   Since: %s\n", s2);
601
602         if (!isempty(i.state))
603                 printf("\t   State: %s\n", i.state);
604
605         if (!strv_isempty(i.sessions)) {
606                 char **l;
607                 printf("\tSessions:");
608
609                 STRV_FOREACH(l, i.sessions) {
610                         if (streq_ptr(*l, i.display))
611                                 printf(" *%s", *l);
612                         else
613                                 printf(" %s", *l);
614                 }
615
616                 printf("\n");
617         }
618
619         if (i.slice) {
620                 printf("\t    Unit: %s\n", i.slice);
621                 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
622 #if 0
623                 show_journal_by_unit(
624                                 stdout,
625                                 i.slice,
626                                 arg_output,
627                                 0,
628                                 i.timestamp.monotonic,
629                                 arg_lines,
630                                 0,
631                                 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
632                                 SD_JOURNAL_LOCAL_ONLY,
633                                 true,
634                                 NULL);
635
636 #endif // 0
637         }
638
639         return 0;
640 }
641
642 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
643
644         static const struct bus_properties_map map[]  = {
645                 { "Id",            "s",     NULL, offsetof(SeatStatusInfo, id) },
646                 { "ActiveSession", "(so)",  prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
647                 { "Sessions",      "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
648                 {}
649         };
650
651         _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
652         int r;
653
654         r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
655         if (r < 0)
656                 return log_error_errno(r, "Could not get properties: %m");
657
658         if (*new_line)
659                 printf("\n");
660
661         *new_line = true;
662
663         printf("%s\n", strna(i.id));
664
665         if (!strv_isempty(i.sessions)) {
666                 char **l;
667                 printf("\tSessions:");
668
669                 STRV_FOREACH(l, i.sessions) {
670                         if (streq_ptr(*l, i.active_session))
671                                 printf(" *%s", *l);
672                         else
673                                 printf(" %s", *l);
674                 }
675
676                 printf("\n");
677         }
678
679         if (arg_transport == BUS_TRANSPORT_LOCAL) {
680                 unsigned c;
681
682                 c = columns();
683                 if (c > 21)
684                         c -= 21;
685                 else
686                         c = 0;
687
688                 printf("\t Devices:\n");
689
690                 show_sysfs(i.id, "\t\t  ", c);
691         }
692
693         return 0;
694 }
695
696 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
697         int r;
698
699         if (*new_line)
700                 printf("\n");
701
702         *new_line = true;
703
704         r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
705         if (r < 0)
706                 log_error_errno(r, "Could not get properties: %m");
707
708         return r;
709 }
710
711 static int show_session(int argc, char *argv[], void *userdata) {
712         bool properties, new_line = false;
713         sd_bus *bus = userdata;
714         int r, i;
715
716         assert(bus);
717         assert(argv);
718
719         properties = !strstr(argv[0], "status");
720
721         pager_open_if_enabled();
722
723         if (argc <= 1) {
724                 /* If not argument is specified inspect the manager
725                  * itself */
726                 if (properties)
727                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
728
729                 /* And in the pretty case, show data of the calling session */
730                 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
731         }
732
733         for (i = 1; i < argc; i++) {
734                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
735                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
736                 const char *path = NULL;
737
738                 r = sd_bus_call_method(
739                                 bus,
740                                 "org.freedesktop.login1",
741                                 "/org/freedesktop/login1",
742                                 "org.freedesktop.login1.Manager",
743                                 "GetSession",
744                                 &error, &reply,
745                                 "s", argv[i]);
746                 if (r < 0) {
747                         log_error("Failed to get session: %s", bus_error_message(&error, r));
748                         return r;
749                 }
750
751                 r = sd_bus_message_read(reply, "o", &path);
752                 if (r < 0)
753                         return bus_log_parse_error(r);
754
755                 if (properties)
756                         r = show_properties(bus, path, &new_line);
757                 else
758                         r = print_session_status_info(bus, path, &new_line);
759
760                 if (r < 0)
761                         return r;
762         }
763
764         return 0;
765 }
766
767 static int show_user(int argc, char *argv[], void *userdata) {
768         bool properties, new_line = false;
769         sd_bus *bus = userdata;
770         int r, i;
771
772         assert(bus);
773         assert(argv);
774
775         properties = !strstr(argv[0], "status");
776
777         pager_open_if_enabled();
778
779         if (argc <= 1) {
780                 /* If not argument is specified inspect the manager
781                  * itself */
782                 if (properties)
783                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
784
785                 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
786         }
787
788         for (i = 1; i < argc; i++) {
789                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
790                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
791                 const char *path = NULL;
792                 uid_t uid;
793
794                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
795                 if (r < 0)
796                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
797
798                 r = sd_bus_call_method(
799                                 bus,
800                                 "org.freedesktop.login1",
801                                 "/org/freedesktop/login1",
802                                 "org.freedesktop.login1.Manager",
803                                 "GetUser",
804                                 &error, &reply,
805                                 "u", (uint32_t) uid);
806                 if (r < 0) {
807                         log_error("Failed to get user: %s", bus_error_message(&error, r));
808                         return r;
809                 }
810
811                 r = sd_bus_message_read(reply, "o", &path);
812                 if (r < 0)
813                         return bus_log_parse_error(r);
814
815                 if (properties)
816                         r = show_properties(bus, path, &new_line);
817                 else
818                         r = print_user_status_info(bus, path, &new_line);
819
820                 if (r < 0)
821                         return r;
822         }
823
824         return 0;
825 }
826
827 static int show_seat(int argc, char *argv[], void *userdata) {
828         bool properties, new_line = false;
829         sd_bus *bus = userdata;
830         int r, i;
831
832         assert(bus);
833         assert(argv);
834
835         properties = !strstr(argv[0], "status");
836
837         pager_open_if_enabled();
838
839         if (argc <= 1) {
840                 /* If not argument is specified inspect the manager
841                  * itself */
842                 if (properties)
843                         return show_properties(bus, "/org/freedesktop/login1", &new_line);
844
845                 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
846         }
847
848         for (i = 1; i < argc; i++) {
849                 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
850                 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
851                 const char *path = NULL;
852
853                 r = sd_bus_call_method(
854                                 bus,
855                                 "org.freedesktop.login1",
856                                 "/org/freedesktop/login1",
857                                 "org.freedesktop.login1.Manager",
858                                 "GetSeat",
859                                 &error, &reply,
860                                 "s", argv[i]);
861                 if (r < 0) {
862                         log_error("Failed to get seat: %s", bus_error_message(&error, r));
863                         return r;
864                 }
865
866                 r = sd_bus_message_read(reply, "o", &path);
867                 if (r < 0)
868                         return bus_log_parse_error(r);
869
870                 if (properties)
871                         r = show_properties(bus, path, &new_line);
872                 else
873                         r = print_seat_status_info(bus, path, &new_line);
874
875                 if (r < 0)
876                         return r;
877         }
878
879         return 0;
880 }
881
882 static int activate(int argc, char *argv[], void *userdata) {
883         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
884         sd_bus *bus = userdata;
885         char *short_argv[3];
886         int r, i;
887
888         assert(bus);
889         assert(argv);
890
891         polkit_agent_open_if_enabled();
892
893         if (argc < 2) {
894                 /* No argument? Let's convert this into the empty
895                  * session name, which the calls will then resolve to
896                  * the caller's session. */
897
898                 short_argv[0] = argv[0];
899                 short_argv[1] = (char*) "";
900                 short_argv[2] = NULL;
901
902                 argv = short_argv;
903                 argc = 2;
904         }
905
906         for (i = 1; i < argc; i++) {
907
908                 r = sd_bus_call_method(
909                                 bus,
910                                 "org.freedesktop.login1",
911                                 "/org/freedesktop/login1",
912                                 "org.freedesktop.login1.Manager",
913                                 streq(argv[0], "lock-session")      ? "LockSession" :
914                                 streq(argv[0], "unlock-session")    ? "UnlockSession" :
915                                 streq(argv[0], "terminate-session") ? "TerminateSession" :
916                                                                       "ActivateSession",
917                                 &error, NULL,
918                                 "s", argv[i]);
919                 if (r < 0) {
920                         log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
921                         return r;
922                 }
923         }
924
925         return 0;
926 }
927
928 static int kill_session(int argc, char *argv[], void *userdata) {
929         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
930         sd_bus *bus = userdata;
931         int r, i;
932
933         assert(bus);
934         assert(argv);
935
936         polkit_agent_open_if_enabled();
937
938         if (!arg_kill_who)
939                 arg_kill_who = "all";
940
941         for (i = 1; i < argc; i++) {
942
943                 r = sd_bus_call_method(
944                         bus,
945                         "org.freedesktop.login1",
946                         "/org/freedesktop/login1",
947                         "org.freedesktop.login1.Manager",
948                         "KillSession",
949                         &error, NULL,
950                         "ssi", argv[i], arg_kill_who, arg_signal);
951                 if (r < 0) {
952                         log_error("Could not kill session: %s", bus_error_message(&error, -r));
953                         return r;
954                 }
955         }
956
957         return 0;
958 }
959
960 static int enable_linger(int argc, char *argv[], void *userdata) {
961         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
962         sd_bus *bus = userdata;
963         char* short_argv[3];
964         bool b;
965         int r, i;
966
967         assert(bus);
968         assert(argv);
969
970         polkit_agent_open_if_enabled();
971
972         b = streq(argv[0], "enable-linger");
973
974         if (argc < 2) {
975                 short_argv[0] = argv[0];
976                 short_argv[1] = (char*) "";
977                 short_argv[2] = NULL;
978                 argv = short_argv;
979                 argc = 2;
980         }
981
982         for (i = 1; i < argc; i++) {
983                 uid_t uid;
984
985                 if (isempty(argv[i]))
986                         uid = UID_INVALID;
987                 else {
988                         r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
989                         if (r < 0)
990                                 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
991                 }
992
993                 r = sd_bus_call_method(
994                         bus,
995                         "org.freedesktop.login1",
996                         "/org/freedesktop/login1",
997                         "org.freedesktop.login1.Manager",
998                         "SetUserLinger",
999                         &error, NULL,
1000                         "ubb", (uint32_t) uid, b, true);
1001                 if (r < 0) {
1002                         log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1003                         return r;
1004                 }
1005         }
1006
1007         return 0;
1008 }
1009
1010 static int terminate_user(int argc, char *argv[], void *userdata) {
1011         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1012         sd_bus *bus = userdata;
1013         int r, i;
1014
1015         assert(bus);
1016         assert(argv);
1017
1018         polkit_agent_open_if_enabled();
1019
1020         for (i = 1; i < argc; i++) {
1021                 uid_t uid;
1022
1023                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1024                 if (r < 0)
1025                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1026
1027                 r = sd_bus_call_method(
1028                         bus,
1029                         "org.freedesktop.login1",
1030                         "/org/freedesktop/login1",
1031                         "org.freedesktop.login1.Manager",
1032                         "TerminateUser",
1033                         &error, NULL,
1034                         "u", (uint32_t) uid);
1035                 if (r < 0) {
1036                         log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1037                         return r;
1038                 }
1039         }
1040
1041         return 0;
1042 }
1043
1044 static int kill_user(int argc, char *argv[], void *userdata) {
1045         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1046         sd_bus *bus = userdata;
1047         int r, i;
1048
1049         assert(bus);
1050         assert(argv);
1051
1052         polkit_agent_open_if_enabled();
1053
1054         if (!arg_kill_who)
1055                 arg_kill_who = "all";
1056
1057         for (i = 1; i < argc; i++) {
1058                 uid_t uid;
1059
1060                 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1061                 if (r < 0)
1062                         return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1063
1064                 r = sd_bus_call_method(
1065                         bus,
1066                         "org.freedesktop.login1",
1067                         "/org/freedesktop/login1",
1068                         "org.freedesktop.login1.Manager",
1069                         "KillUser",
1070                         &error, NULL,
1071                         "ui", (uint32_t) uid, arg_signal);
1072                 if (r < 0) {
1073                         log_error("Could not kill user: %s", bus_error_message(&error, -r));
1074                         return r;
1075                 }
1076         }
1077
1078         return 0;
1079 }
1080
1081 static int attach(int argc, char *argv[], void *userdata) {
1082         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1083         sd_bus *bus = userdata;
1084         int r, i;
1085
1086         assert(bus);
1087         assert(argv);
1088
1089         polkit_agent_open_if_enabled();
1090
1091         for (i = 2; i < argc; i++) {
1092
1093                 r = sd_bus_call_method(
1094                         bus,
1095                         "org.freedesktop.login1",
1096                         "/org/freedesktop/login1",
1097                         "org.freedesktop.login1.Manager",
1098                         "AttachDevice",
1099                         &error, NULL,
1100                         "ssb", argv[1], argv[i], true);
1101
1102                 if (r < 0) {
1103                         log_error("Could not attach device: %s", bus_error_message(&error, -r));
1104                         return r;
1105                 }
1106         }
1107
1108         return 0;
1109 }
1110
1111 static int flush_devices(int argc, char *argv[], void *userdata) {
1112         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1113         sd_bus *bus = userdata;
1114         int r;
1115
1116         assert(bus);
1117         assert(argv);
1118
1119         polkit_agent_open_if_enabled();
1120
1121         r = sd_bus_call_method(
1122                         bus,
1123                         "org.freedesktop.login1",
1124                         "/org/freedesktop/login1",
1125                         "org.freedesktop.login1.Manager",
1126                         "FlushDevices",
1127                         &error, NULL,
1128                         "b", true);
1129         if (r < 0)
1130                 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1131
1132         return r;
1133 }
1134
1135 static int lock_sessions(int argc, char *argv[], void *userdata) {
1136         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1137         sd_bus *bus = userdata;
1138         int r;
1139
1140         assert(bus);
1141         assert(argv);
1142
1143         polkit_agent_open_if_enabled();
1144
1145         r = sd_bus_call_method(
1146                         bus,
1147                         "org.freedesktop.login1",
1148                         "/org/freedesktop/login1",
1149                         "org.freedesktop.login1.Manager",
1150                         streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1151                         &error, NULL,
1152                         NULL);
1153         if (r < 0)
1154                 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1155
1156         return r;
1157 }
1158
1159 static int terminate_seat(int argc, char *argv[], void *userdata) {
1160         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1161         sd_bus *bus = userdata;
1162         int r, i;
1163
1164         assert(bus);
1165         assert(argv);
1166
1167         polkit_agent_open_if_enabled();
1168
1169         for (i = 1; i < argc; i++) {
1170
1171                 r = sd_bus_call_method(
1172                         bus,
1173                         "org.freedesktop.login1",
1174                         "/org/freedesktop/login1",
1175                         "org.freedesktop.login1.Manager",
1176                         "TerminateSeat",
1177                         &error, NULL,
1178                         "s", argv[i]);
1179                 if (r < 0) {
1180                         log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1181                         return r;
1182                 }
1183         }
1184
1185         return 0;
1186 }
1187
1188 static int check_inhibitors(sd_bus *bus, const char *verb, const char *inhibit_what) {
1189         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1190         _cleanup_strv_free_ char **sessions = NULL;
1191         const char *what, *who, *why, *mode;
1192         uint32_t uid, pid;
1193         unsigned c = 0;
1194         char **s;
1195         int r;
1196
1197         assert(bus);
1198
1199         if (geteuid() == 0)
1200                 return 0;
1201
1202         if (!on_tty())
1203                 return 0;
1204
1205         r = sd_bus_call_method(
1206                         bus,
1207                         "org.freedesktop.login1",
1208                         "/org/freedesktop/login1",
1209                         "org.freedesktop.login1.Manager",
1210                         "ListInhibitors",
1211                         NULL,
1212                         &reply,
1213                         NULL);
1214         if (r < 0)
1215                 /* If logind is not around, then there are no inhibitors... */
1216                 return 0;
1217
1218         r = sd_bus_message_enter_container(reply, SD_BUS_TYPE_ARRAY, "(ssssuu)");
1219         if (r < 0)
1220                 return bus_log_parse_error(r);
1221
1222         while ((r = sd_bus_message_read(reply, "(ssssuu)", &what, &who, &why, &mode, &uid, &pid)) > 0) {
1223                 _cleanup_free_ char *comm = NULL, *user = NULL;
1224                 _cleanup_strv_free_ char **sv = NULL;
1225
1226                 if (!streq(mode, "block"))
1227                         continue;
1228
1229                 sv = strv_split(what, ":");
1230                 if (!sv)
1231                         return log_oom();
1232
1233                 if (!strv_contains(sv, inhibit_what))
1234                         continue;
1235
1236                 get_process_comm(pid, &comm);
1237                 user = uid_to_name(uid);
1238
1239                 log_warning("Operation inhibited by \"%s\" (PID "PID_FMT" \"%s\", user %s), reason is \"%s\".",
1240                             who, pid, strna(comm), strna(user), why);
1241
1242                 c++;
1243         }
1244         if (r < 0)
1245                 return bus_log_parse_error(r);
1246
1247         r = sd_bus_message_exit_container(reply);
1248         if (r < 0)
1249                 return bus_log_parse_error(r);
1250
1251         /* Check for current sessions */
1252         sd_get_sessions(&sessions);
1253         STRV_FOREACH(s, sessions) {
1254                 _cleanup_free_ char *type = NULL, *tty = NULL, *seat = NULL, *user = NULL, *service = NULL, *class = NULL;
1255
1256                 if (sd_session_get_uid(*s, &uid) < 0 || uid == getuid())
1257                         continue;
1258
1259                 if (sd_session_get_class(*s, &class) < 0 || !streq(class, "user"))
1260                         continue;
1261
1262                 if (sd_session_get_type(*s, &type) < 0 || (!streq(type, "x11") && !streq(type, "tty")))
1263                         continue;
1264
1265                 sd_session_get_tty(*s, &tty);
1266                 sd_session_get_seat(*s, &seat);
1267                 sd_session_get_service(*s, &service);
1268                 user = uid_to_name(uid);
1269
1270                 log_warning("User %s is logged in on %s.", strna(user), isempty(tty) ? (isempty(seat) ? strna(service) : seat) : tty);
1271                 c++;
1272         }
1273
1274         if (c <= 0)
1275                 return 0;
1276
1277         log_error("Please retry operation after closing inhibitors and logging out other users.\nAlternatively, ignore inhibitors and users with 'loginctl %s -i'.", verb);
1278
1279         return -EPERM;
1280 }
1281
1282 static int poweroff(int argc, char *argv[], void *userdata) {
1283         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1284         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1285         sd_bus *bus = userdata;
1286         int r;
1287
1288         assert(bus);
1289
1290         r = check_inhibitors(bus, "poweroff", "shutdown");
1291         if (r < 0)
1292                 return r;
1293
1294         polkit_agent_open_if_enabled();
1295
1296         r = sd_bus_call_method(
1297                         bus,
1298                         "org.freedesktop.login1",
1299                         "/org/freedesktop/login1",
1300                         "org.freedesktop.login1.Manager",
1301                         "PowerOff",
1302                         &error,
1303                         NULL,
1304                         "b", arg_ask_password);
1305         if (r < 0)
1306                 log_error("Failed to power off: %s", bus_error_message(&error, r));
1307
1308         return r;
1309 }
1310
1311 static int reboot(int argc, char *argv[], void *userdata) {
1312         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1313         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1314         sd_bus *bus = userdata;
1315         int r;
1316
1317         assert(bus);
1318
1319         r = check_inhibitors(bus, "reboot", "shutdown");
1320         if (r < 0)
1321                 return r;
1322
1323         polkit_agent_open_if_enabled();
1324
1325         r = sd_bus_call_method(
1326                         bus,
1327                         "org.freedesktop.login1",
1328                         "/org/freedesktop/login1",
1329                         "org.freedesktop.login1.Manager",
1330                         "Reboot",
1331                         &error,
1332                         NULL,
1333                         "b", arg_ask_password);
1334         if (r < 0)
1335                 log_error("Failed to reboot: %s", bus_error_message(&error, r));
1336
1337         return r;
1338 }
1339
1340 static int suspend(int argc, char *argv[], void *userdata) {
1341         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1342         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1343         sd_bus *bus = userdata;
1344         int r;
1345
1346         assert(bus);
1347
1348         r = check_inhibitors(bus, "suspend", "sleep");
1349         if (r < 0)
1350                 return r;
1351
1352         polkit_agent_open_if_enabled();
1353
1354         r = sd_bus_call_method(
1355                         bus,
1356                         "org.freedesktop.login1",
1357                         "/org/freedesktop/login1",
1358                         "org.freedesktop.login1.Manager",
1359                         "Suspend",
1360                         &error,
1361                         NULL,
1362                         "b", arg_ask_password);
1363         if (r < 0)
1364                 log_error("Failed to suspend: %s", bus_error_message(&error, r));
1365
1366         return r;
1367 }
1368
1369 static int hibernate(int argc, char *argv[], void *userdata) {
1370         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1371         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1372         sd_bus *bus = userdata;
1373         int r;
1374
1375         assert(bus);
1376
1377         r = check_inhibitors(bus, "hibernate", "sleep");
1378         if (r < 0)
1379                 return r;
1380
1381         polkit_agent_open_if_enabled();
1382
1383         r = sd_bus_call_method(
1384                         bus,
1385                         "org.freedesktop.login1",
1386                         "/org/freedesktop/login1",
1387                         "org.freedesktop.login1.Manager",
1388                         "Hibernate",
1389                         &error,
1390                         NULL,
1391                         "b", arg_ask_password);
1392         if (r < 0)
1393                 log_error("Failed to hibernate: %s", bus_error_message(&error, r));
1394
1395         return r;
1396 }
1397
1398 static int hybrid_sleep(int argc, char *argv[], void *userdata) {
1399         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1400         _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1401         sd_bus *bus = userdata;
1402         int r;
1403
1404         assert(bus);
1405
1406         r = check_inhibitors(bus, "hybrid-sleep", "sleep");
1407         if (r < 0)
1408                 return r;
1409
1410         polkit_agent_open_if_enabled();
1411
1412         r = sd_bus_call_method(
1413                         bus,
1414                         "org.freedesktop.login1",
1415                         "/org/freedesktop/login1",
1416                         "org.freedesktop.login1.Manager",
1417                         "HybridSleep",
1418                         &error,
1419                         NULL,
1420                         "b", arg_ask_password);
1421         if (r < 0)
1422                 log_error("Failed to hybrid sleep: %s", bus_error_message(&error, r));
1423
1424         return r;
1425 }
1426
1427 static int help(int argc, char *argv[], void *userdata) {
1428
1429         printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1430                "Send control commands to or query the login manager.\n\n"
1431                "  -h --help                Show this help\n"
1432                "     --version             Show package version\n"
1433                "     --no-pager            Do not pipe output into a pager\n"
1434                "     --no-legend           Do not show the headers and footers\n"
1435                "     --no-ask-password     Don't prompt for password\n"
1436                "  -H --host=[USER@]HOST    Operate on remote host\n"
1437                "  -M --machine=CONTAINER   Operate on local container\n"
1438                "  -p --property=NAME       Show only properties by this name\n"
1439                "  -a --all                 Show all properties, including empty ones\n"
1440                "  -l --full                Do not ellipsize output\n"
1441                "     --kill-who=WHO        Who to send signal to\n"
1442                "  -s --signal=SIGNAL       Which signal to send\n"
1443 #if 0
1444                "  -n --lines=INTEGER       Number of journal entries to show\n"
1445                "  -o --output=STRING       Change journal output mode (short, short-monotonic,\n"
1446                "                           verbose, export, json, json-pretty, json-sse, cat)\n\n"
1447 #endif // 0
1448                "Session Commands:\n"
1449                "  list-sessions            List sessions\n"
1450                "  session-status [ID...]   Show session status\n"
1451                "  show-session [ID...]     Show properties of sessions or the manager\n"
1452                "  activate [ID]            Activate a session\n"
1453                "  lock-session [ID...]     Screen lock one or more sessions\n"
1454                "  unlock-session [ID...]   Screen unlock one or more sessions\n"
1455                "  lock-sessions            Screen lock all current sessions\n"
1456                "  unlock-sessions          Screen unlock all current sessions\n"
1457                "  terminate-session ID...  Terminate one or more sessions\n"
1458                "  kill-session ID...       Send signal to processes of a session\n\n"
1459                "User Commands:\n"
1460                "  list-users               List users\n"
1461                "  user-status [USER...]    Show user status\n"
1462                "  show-user [USER...]      Show properties of users or the manager\n"
1463                "  enable-linger [USER...]  Enable linger state of one or more users\n"
1464                "  disable-linger [USER...] Disable linger state of one or more users\n"
1465                "  terminate-user USER...   Terminate all sessions of one or more users\n"
1466                "  kill-user USER...        Send signal to processes of a user\n\n"
1467                "Seat Commands:\n"
1468                "  list-seats               List seats\n"
1469                "  seat-status [NAME...]    Show seat status\n"
1470                "  show-seat [NAME...]      Show properties of seats or the manager\n"
1471                "  attach NAME DEVICE...    Attach one or more devices to a seat\n"
1472                "  flush-devices            Flush all device associations\n"
1473                "  terminate-seat NAME...   Terminate all sessions on one or more seats\n"
1474                "System Commands:\n"
1475                "  poweroff                 Turn off the machine\n"
1476                "  reboot                   Reboot the machine\n"
1477                "  suspend                  Suspend the machine to memory\n"
1478                "  hibernate                Suspend the machine to disk\n"
1479                "  hybrid-sleep             Suspend the machine to memory and disk\n"
1480                , program_invocation_short_name);
1481
1482         return 0;
1483 }
1484
1485 static int parse_argv(int argc, char *argv[]) {
1486
1487         enum {
1488                 ARG_VERSION = 0x100,
1489                 ARG_NO_PAGER,
1490                 ARG_NO_LEGEND,
1491                 ARG_KILL_WHO,
1492                 ARG_NO_ASK_PASSWORD,
1493         };
1494
1495         static const struct option options[] = {
1496                 { "help",            no_argument,       NULL, 'h'                 },
1497                 { "version",         no_argument,       NULL, ARG_VERSION         },
1498                 { "property",        required_argument, NULL, 'p'                 },
1499                 { "all",             no_argument,       NULL, 'a'                 },
1500                 { "full",            no_argument,       NULL, 'l'                 },
1501                 { "no-pager",        no_argument,       NULL, ARG_NO_PAGER        },
1502                 { "no-legend",       no_argument,       NULL, ARG_NO_LEGEND       },
1503                 { "kill-who",        required_argument, NULL, ARG_KILL_WHO        },
1504                 { "signal",          required_argument, NULL, 's'                 },
1505                 { "host",            required_argument, NULL, 'H'                 },
1506                 { "machine",         required_argument, NULL, 'M'                 },
1507                 { "no-ask-password", no_argument,       NULL, ARG_NO_ASK_PASSWORD },
1508 #if 0
1509                 { "lines",           required_argument, NULL, 'n'                 },
1510                 { "output",          required_argument, NULL, 'o'                 },
1511 #endif //
1512                 {}
1513         };
1514
1515         int c, r;
1516
1517         assert(argc >= 0);
1518         assert(argv);
1519
1520         while ((c = getopt_long(argc, argv, "hp:als:H:M:", options, NULL)) >= 0)
1521
1522                 switch (c) {
1523
1524                 case 'h':
1525                         help(0, NULL, NULL);
1526                         return 0;
1527
1528                 case ARG_VERSION:
1529                         puts(PACKAGE_STRING);
1530                         puts(SYSTEMD_FEATURES);
1531                         return 0;
1532
1533                 case 'p': {
1534                         r = strv_extend(&arg_property, optarg);
1535                         if (r < 0)
1536                                 return log_oom();
1537
1538                         /* If the user asked for a particular
1539                          * property, show it to him, even if it is
1540                          * empty. */
1541                         arg_all = true;
1542                         break;
1543                 }
1544
1545                 case 'a':
1546                         arg_all = true;
1547                         break;
1548
1549                 case 'l':
1550                         arg_full = true;
1551                         break;
1552 #if 0
1553                 case 'n':
1554                         if (safe_atou(optarg, &arg_lines) < 0) {
1555                                 log_error("Failed to parse lines '%s'", optarg);
1556                                 return -EINVAL;
1557                         }
1558                         break;
1559
1560                 case 'o':
1561                         arg_output = output_mode_from_string(optarg);
1562                         if (arg_output < 0) {
1563                                 log_error("Unknown output '%s'.", optarg);
1564                                 return -EINVAL;
1565                         }
1566                         break;
1567 #endif // 0
1568                 case ARG_NO_PAGER:
1569                         arg_no_pager = true;
1570                         break;
1571
1572                 case ARG_NO_LEGEND:
1573                         arg_legend = false;
1574                         break;
1575
1576                 case ARG_NO_ASK_PASSWORD:
1577                         arg_ask_password = false;
1578                         break;
1579
1580                 case ARG_KILL_WHO:
1581                         arg_kill_who = optarg;
1582                         break;
1583
1584                 case 's':
1585                         arg_signal = signal_from_string_try_harder(optarg);
1586                         if (arg_signal < 0) {
1587                                 log_error("Failed to parse signal string %s.", optarg);
1588                                 return -EINVAL;
1589                         }
1590                         break;
1591
1592                 case 'H':
1593                         arg_transport = BUS_TRANSPORT_REMOTE;
1594                         arg_host = optarg;
1595                         break;
1596
1597                 case 'M':
1598                         arg_transport = BUS_TRANSPORT_MACHINE;
1599                         arg_host = optarg;
1600                         break;
1601
1602                 case '?':
1603                         return -EINVAL;
1604
1605                 default:
1606                         assert_not_reached("Unhandled option");
1607                 }
1608
1609         return 1;
1610 }
1611
1612 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1613
1614         static const Verb verbs[] = {
1615                 { "help",              VERB_ANY, VERB_ANY, 0,            help              },
1616                 { "list-sessions",     VERB_ANY, 1,        VERB_DEFAULT, list_sessions     },
1617                 { "session-status",    VERB_ANY, VERB_ANY, 0,            show_session      },
1618                 { "show-session",      VERB_ANY, VERB_ANY, 0,            show_session      },
1619                 { "activate",          VERB_ANY, 2,        0,            activate          },
1620                 { "lock-session",      VERB_ANY, VERB_ANY, 0,            activate          },
1621                 { "unlock-session",    VERB_ANY, VERB_ANY, 0,            activate          },
1622                 { "lock-sessions",     VERB_ANY, 1,        0,            lock_sessions     },
1623                 { "unlock-sessions",   VERB_ANY, 1,        0,            lock_sessions     },
1624                 { "terminate-session", 2,        VERB_ANY, 0,            activate          },
1625                 { "kill-session",      2,        VERB_ANY, 0,            kill_session      },
1626                 { "list-users",        VERB_ANY, 1,        0,            list_users        },
1627                 { "user-status",       VERB_ANY, VERB_ANY, 0,            show_user         },
1628                 { "show-user",         VERB_ANY, VERB_ANY, 0,            show_user         },
1629                 { "enable-linger",     VERB_ANY, VERB_ANY, 0,            enable_linger     },
1630                 { "disable-linger",    VERB_ANY, VERB_ANY, 0,            enable_linger     },
1631                 { "terminate-user",    2,        VERB_ANY, 0,            terminate_user    },
1632                 { "kill-user",         2,        VERB_ANY, 0,            kill_user         },
1633                 { "list-seats",        VERB_ANY, 1,        0,            list_seats        },
1634                 { "seat-status",       VERB_ANY, VERB_ANY, 0,            show_seat         },
1635                 { "show-seat",         VERB_ANY, VERB_ANY, 0,            show_seat         },
1636                 { "attach",            3,        VERB_ANY, 0,            attach            },
1637                 { "flush-devices",     VERB_ANY, 1,        0,            flush_devices     },
1638                 { "terminate-seat",    2,        VERB_ANY, 0,            terminate_seat    },
1639                 { "poweroff",          VERB_ANY, 1,        0,            poweroff          },
1640                 { "reboot",            VERB_ANY, 1,        0,            reboot            },
1641                 { "suspend",           VERB_ANY, 1,        0,            suspend           },
1642                 { "hibernate",         VERB_ANY, 1,        0,            hibernate         },
1643                 { "hybrid-sleep",      VERB_ANY, 1,        0,            hybrid_sleep      },
1644                 {}
1645         };
1646
1647         return dispatch_verb(argc, argv, verbs, bus);
1648 }
1649
1650 int main(int argc, char *argv[]) {
1651         _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1652         int r;
1653
1654         setlocale(LC_ALL, "");
1655         log_parse_environment();
1656         log_open();
1657
1658         r = parse_argv(argc, argv);
1659         if (r <= 0)
1660                 goto finish;
1661
1662         r = bus_open_transport(arg_transport, arg_host, false, &bus);
1663         if (r < 0) {
1664                 log_error_errno(r, "Failed to create bus connection: %m");
1665                 goto finish;
1666         }
1667
1668         sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1669
1670         r = loginctl_main(argc, argv, bus);
1671
1672 finish:
1673         pager_close();
1674         polkit_agent_close();
1675
1676         strv_free(arg_property);
1677
1678         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1679 }