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