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