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