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