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