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