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