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