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