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