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