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