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