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