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