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