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