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