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