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