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