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