]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/loginctl.c
Merge pull request #8865 from yuwata/fix-signal
[thirdparty/systemd.git] / src / login / loginctl.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2 /***
3 This file is part of systemd.
4
5 Copyright 2010 Lennart Poettering
6 ***/
7
8 #include <errno.h>
9 #include <getopt.h>
10 #include <locale.h>
11 #include <string.h>
12 #include <unistd.h>
13
14 #include "sd-bus.h"
15
16 #include "alloc-util.h"
17 #include "bus-error.h"
18 #include "bus-unit-util.h"
19 #include "bus-util.h"
20 #include "cgroup-show.h"
21 #include "cgroup-util.h"
22 #include "format-table.h"
23 #include "log.h"
24 #include "logs-show.h"
25 #include "macro.h"
26 #include "pager.h"
27 #include "parse-util.h"
28 #include "process-util.h"
29 #include "sigbus.h"
30 #include "signal-util.h"
31 #include "spawn-polkit-agent.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 "util.h"
38 #include "verbs.h"
39
40 static char **arg_property = NULL;
41 static bool arg_all = false;
42 static bool arg_value = false;
43 static bool arg_full = false;
44 static bool arg_no_pager = false;
45 static bool arg_legend = true;
46 static const char *arg_kill_who = NULL;
47 static int arg_signal = SIGTERM;
48 static BusTransport arg_transport = BUS_TRANSPORT_LOCAL;
49 static char *arg_host = NULL;
50 static bool arg_ask_password = true;
51 static unsigned arg_lines = 10;
52 static OutputMode arg_output = OUTPUT_SHORT;
53
54 static 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_no_pager, false);
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_no_pager, false);
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, *object;
234 uint32_t uid;
235
236 r = sd_bus_message_read(reply, "(uso)", &uid, &user, &object);
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_no_pager, false);
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, *object;
289
290 r = sd_bus_message_read(reply, "(so)", &seat, &object);
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 int 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], *s1;
477 char since2[FORMAT_TIMESTAMP_MAX], *s2;
478 SessionStatusInfo i = {};
479 int r;
480
481 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
482 if (r < 0)
483 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
484
485 if (*new_line)
486 printf("\n");
487
488 *new_line = true;
489
490 printf("%s - ", strna(i.id));
491
492 if (i.name)
493 printf("%s (%"PRIu32")\n", i.name, i.uid);
494 else
495 printf("%"PRIu32"\n", i.uid);
496
497 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
498 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
499
500 if (s1)
501 printf("\t Since: %s; %s\n", s2, s1);
502 else if (s2)
503 printf("\t Since: %s\n", s2);
504
505 if (i.leader > 0) {
506 _cleanup_free_ char *t = NULL;
507
508 printf("\t Leader: %"PRIu32, i.leader);
509
510 get_process_comm(i.leader, &t);
511 if (t)
512 printf(" (%s)", t);
513
514 printf("\n");
515 }
516
517 if (!isempty(i.seat)) {
518 printf("\t Seat: %s", i.seat);
519
520 if (i.vtnr > 0)
521 printf("; vc%u", i.vtnr);
522
523 printf("\n");
524 }
525
526 if (i.tty)
527 printf("\t TTY: %s\n", i.tty);
528 else if (i.display)
529 printf("\t Display: %s\n", i.display);
530
531 if (i.remote_host && i.remote_user)
532 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
533 else if (i.remote_host)
534 printf("\t Remote: %s\n", i.remote_host);
535 else if (i.remote_user)
536 printf("\t Remote: user %s\n", i.remote_user);
537 else if (i.remote)
538 printf("\t Remote: Yes\n");
539
540 if (i.service) {
541 printf("\t Service: %s", i.service);
542
543 if (i.type)
544 printf("; type %s", i.type);
545
546 if (i.class)
547 printf("; class %s", i.class);
548
549 printf("\n");
550 } else if (i.type) {
551 printf("\t Type: %s", i.type);
552
553 if (i.class)
554 printf("; class %s", i.class);
555
556 printf("\n");
557 } else if (i.class)
558 printf("\t Class: %s\n", i.class);
559
560 if (!isempty(i.desktop))
561 printf("\t Desktop: %s\n", i.desktop);
562
563 if (i.state)
564 printf("\t State: %s\n", i.state);
565
566 if (i.scope) {
567 printf("\t Unit: %s\n", i.scope);
568 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
569
570 if (arg_transport == BUS_TRANSPORT_LOCAL) {
571
572 show_journal_by_unit(
573 stdout,
574 i.scope,
575 arg_output,
576 0,
577 i.timestamp.monotonic,
578 arg_lines,
579 0,
580 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
581 SD_JOURNAL_LOCAL_ONLY,
582 true,
583 NULL);
584 }
585 }
586
587 return 0;
588 }
589
590 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
591
592 static const struct bus_properties_map map[] = {
593 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
594 { "Linger", "b", NULL, offsetof(UserStatusInfo, linger) },
595 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
596 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
597 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
598 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
599 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
600 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
601 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
602 {}
603 };
604
605 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
606 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
607 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
608 char since2[FORMAT_TIMESTAMP_MAX], *s2;
609 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
610 int r;
611
612 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, BUS_MAP_BOOLEAN_AS_BOOL, &error, &m, &i);
613 if (r < 0)
614 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
615
616 if (*new_line)
617 printf("\n");
618
619 *new_line = true;
620
621 if (i.name)
622 printf("%s (%"PRIu32")\n", i.name, i.uid);
623 else
624 printf("%"PRIu32"\n", i.uid);
625
626 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
627 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
628
629 if (s1)
630 printf("\t Since: %s; %s\n", s2, s1);
631 else if (s2)
632 printf("\t Since: %s\n", s2);
633
634 if (!isempty(i.state))
635 printf("\t State: %s\n", i.state);
636
637 if (!strv_isempty(i.sessions)) {
638 char **l;
639 printf("\tSessions:");
640
641 STRV_FOREACH(l, i.sessions)
642 printf(" %s%s",
643 streq_ptr(*l, i.display) ? "*" : "",
644 *l);
645
646 printf("\n");
647 }
648
649 printf("\t Linger: %s\n", yes_no(i.linger));
650
651 if (i.slice) {
652 printf("\t Unit: %s\n", i.slice);
653 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
654
655 show_journal_by_unit(
656 stdout,
657 i.slice,
658 arg_output,
659 0,
660 i.timestamp.monotonic,
661 arg_lines,
662 0,
663 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
664 SD_JOURNAL_LOCAL_ONLY,
665 true,
666 NULL);
667 }
668
669 return 0;
670 }
671
672 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
673
674 static const struct bus_properties_map map[] = {
675 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
676 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
677 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
678 {}
679 };
680
681 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
682 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
683 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
684 int r;
685
686 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, 0, &error, &m, &i);
687 if (r < 0)
688 return log_error_errno(r, "Could not get properties: %s", bus_error_message(&error, r));
689
690 if (*new_line)
691 printf("\n");
692
693 *new_line = true;
694
695 printf("%s\n", strna(i.id));
696
697 if (!strv_isempty(i.sessions)) {
698 char **l;
699 printf("\tSessions:");
700
701 STRV_FOREACH(l, i.sessions) {
702 if (streq_ptr(*l, i.active_session))
703 printf(" *%s", *l);
704 else
705 printf(" %s", *l);
706 }
707
708 printf("\n");
709 }
710
711 if (arg_transport == BUS_TRANSPORT_LOCAL) {
712 unsigned c;
713
714 c = columns();
715 if (c > 21)
716 c -= 21;
717 else
718 c = 0;
719
720 printf("\t Devices:\n");
721
722 show_sysfs(i.id, "\t\t ", c, get_output_flags());
723 }
724
725 return 0;
726 }
727
728 #define property(name, fmt, ...) \
729 do { \
730 if (value) \
731 printf(fmt "\n", __VA_ARGS__); \
732 else \
733 printf("%s=" fmt "\n", name, __VA_ARGS__); \
734 } while (0)
735
736 static int print_property(const char *name, sd_bus_message *m, bool value, bool all) {
737 char type;
738 const char *contents;
739 int r;
740
741 assert(name);
742 assert(m);
743
744 r = sd_bus_message_peek_type(m, &type, &contents);
745 if (r < 0)
746 return r;
747
748 switch (type) {
749
750 case SD_BUS_TYPE_STRUCT:
751
752 if (contents[0] == SD_BUS_TYPE_STRING && STR_IN_SET(name, "Display", "Seat", "ActiveSession")) {
753 const char *s;
754
755 r = sd_bus_message_read(m, "(so)", &s, NULL);
756 if (r < 0)
757 return bus_log_parse_error(r);
758
759 if (all || !isempty(s))
760 property(name, "%s", s);
761
762 return 1;
763
764 } else if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "User")) {
765 uint32_t uid;
766
767 r = sd_bus_message_read(m, "(uo)", &uid, NULL);
768 if (r < 0)
769 return bus_log_parse_error(r);
770
771 if (!uid_is_valid(uid)) {
772 log_error("Invalid user ID: " UID_FMT, uid);
773 return -EINVAL;
774 }
775
776 property(name, UID_FMT, uid);
777 return 1;
778 }
779 break;
780
781 case SD_BUS_TYPE_ARRAY:
782
783 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Sessions")) {
784 const char *s;
785 bool space = false;
786
787 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(so)");
788 if (r < 0)
789 return bus_log_parse_error(r);
790
791 if (!value)
792 printf("%s=", name);
793
794 while ((r = sd_bus_message_read(m, "(so)", &s, NULL)) > 0) {
795 printf("%s%s", space ? " " : "", s);
796 space = true;
797 }
798
799 if (space || !value)
800 printf("\n");
801
802 if (r < 0)
803 return bus_log_parse_error(r);
804
805 r = sd_bus_message_exit_container(m);
806 if (r < 0)
807 return bus_log_parse_error(r);
808
809 return 1;
810 }
811 break;
812 }
813
814 return 0;
815 }
816
817 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
818 int r;
819
820 assert(bus);
821 assert(path);
822 assert(new_line);
823
824 if (*new_line)
825 printf("\n");
826
827 *new_line = true;
828
829 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, print_property, arg_property, arg_value, arg_all, NULL);
830 if (r < 0)
831 return bus_log_parse_error(r);
832
833 return 0;
834 }
835
836 static int show_session(int argc, char *argv[], void *userdata) {
837 bool properties, new_line = false;
838 sd_bus *bus = userdata;
839 int r, i;
840 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
841 _cleanup_free_ char *path = NULL;
842
843 assert(bus);
844 assert(argv);
845
846 properties = !strstr(argv[0], "status");
847
848 (void) pager_open(arg_no_pager, false);
849
850 if (argc <= 1) {
851 const char *session, *p = "/org/freedesktop/login1/session/self";
852
853 if (properties)
854 /* If no argument is specified inspect the manager itself */
855 return show_properties(bus, "/org/freedesktop/login1", &new_line);
856
857 /* And in the pretty case, show data of the calling session */
858 session = getenv("XDG_SESSION_ID");
859 if (session) {
860 r = get_session_path(bus, session, &error, &path);
861 if (r < 0) {
862 log_error("Failed to get session path: %s", bus_error_message(&error, r));
863 return r;
864 }
865 p = path;
866 }
867
868 return print_session_status_info(bus, p, &new_line);
869 }
870
871 for (i = 1; i < argc; i++) {
872 r = get_session_path(bus, argv[i], &error, &path);
873 if (r < 0) {
874 log_error("Failed to get session path: %s", bus_error_message(&error, r));
875 return r;
876 }
877
878 if (properties)
879 r = show_properties(bus, path, &new_line);
880 else
881 r = print_session_status_info(bus, path, &new_line);
882
883 if (r < 0)
884 return r;
885 }
886
887 return 0;
888 }
889
890 static int show_user(int argc, char *argv[], void *userdata) {
891 bool properties, new_line = false;
892 sd_bus *bus = userdata;
893 int r, i;
894
895 assert(bus);
896 assert(argv);
897
898 properties = !strstr(argv[0], "status");
899
900 (void) pager_open(arg_no_pager, false);
901
902 if (argc <= 1) {
903 /* If not argument is specified inspect the manager
904 * itself */
905 if (properties)
906 return show_properties(bus, "/org/freedesktop/login1", &new_line);
907
908 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
909 }
910
911 for (i = 1; i < argc; i++) {
912 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
913 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
914 const char *path = NULL;
915 uid_t uid;
916
917 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
918 if (r < 0)
919 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
920
921 r = sd_bus_call_method(
922 bus,
923 "org.freedesktop.login1",
924 "/org/freedesktop/login1",
925 "org.freedesktop.login1.Manager",
926 "GetUser",
927 &error, &reply,
928 "u", (uint32_t) uid);
929 if (r < 0) {
930 log_error("Failed to get user: %s", bus_error_message(&error, r));
931 return r;
932 }
933
934 r = sd_bus_message_read(reply, "o", &path);
935 if (r < 0)
936 return bus_log_parse_error(r);
937
938 if (properties)
939 r = show_properties(bus, path, &new_line);
940 else
941 r = print_user_status_info(bus, path, &new_line);
942
943 if (r < 0)
944 return r;
945 }
946
947 return 0;
948 }
949
950 static int show_seat(int argc, char *argv[], void *userdata) {
951 bool properties, new_line = false;
952 sd_bus *bus = userdata;
953 int r, i;
954
955 assert(bus);
956 assert(argv);
957
958 properties = !strstr(argv[0], "status");
959
960 (void) pager_open(arg_no_pager, false);
961
962 if (argc <= 1) {
963 /* If not argument is specified inspect the manager
964 * itself */
965 if (properties)
966 return show_properties(bus, "/org/freedesktop/login1", &new_line);
967
968 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
969 }
970
971 for (i = 1; i < argc; i++) {
972 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
973 _cleanup_(sd_bus_message_unrefp) sd_bus_message * reply = NULL;
974 const char *path = NULL;
975
976 r = sd_bus_call_method(
977 bus,
978 "org.freedesktop.login1",
979 "/org/freedesktop/login1",
980 "org.freedesktop.login1.Manager",
981 "GetSeat",
982 &error, &reply,
983 "s", argv[i]);
984 if (r < 0) {
985 log_error("Failed to get seat: %s", bus_error_message(&error, r));
986 return r;
987 }
988
989 r = sd_bus_message_read(reply, "o", &path);
990 if (r < 0)
991 return bus_log_parse_error(r);
992
993 if (properties)
994 r = show_properties(bus, path, &new_line);
995 else
996 r = print_seat_status_info(bus, path, &new_line);
997
998 if (r < 0)
999 return r;
1000 }
1001
1002 return 0;
1003 }
1004
1005 static int activate(int argc, char *argv[], void *userdata) {
1006 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1007 sd_bus *bus = userdata;
1008 char *short_argv[3];
1009 int r, i;
1010
1011 assert(bus);
1012 assert(argv);
1013
1014 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1015
1016 if (argc < 2) {
1017 /* No argument? Let's either use $XDG_SESSION_ID (if specified), or an empty
1018 * session name, in which case logind will try to guess our session. */
1019
1020 short_argv[0] = argv[0];
1021 short_argv[1] = getenv("XDG_SESSION_ID") ?: (char*) "";
1022 short_argv[2] = NULL;
1023
1024 argv = short_argv;
1025 argc = 2;
1026 }
1027
1028 for (i = 1; i < argc; i++) {
1029
1030 r = sd_bus_call_method(
1031 bus,
1032 "org.freedesktop.login1",
1033 "/org/freedesktop/login1",
1034 "org.freedesktop.login1.Manager",
1035 streq(argv[0], "lock-session") ? "LockSession" :
1036 streq(argv[0], "unlock-session") ? "UnlockSession" :
1037 streq(argv[0], "terminate-session") ? "TerminateSession" :
1038 "ActivateSession",
1039 &error, NULL,
1040 "s", argv[i]);
1041 if (r < 0) {
1042 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
1043 return r;
1044 }
1045 }
1046
1047 return 0;
1048 }
1049
1050 static int kill_session(int argc, char *argv[], void *userdata) {
1051 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1052 sd_bus *bus = userdata;
1053 int r, i;
1054
1055 assert(bus);
1056 assert(argv);
1057
1058 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1059
1060 if (!arg_kill_who)
1061 arg_kill_who = "all";
1062
1063 for (i = 1; i < argc; i++) {
1064
1065 r = sd_bus_call_method(
1066 bus,
1067 "org.freedesktop.login1",
1068 "/org/freedesktop/login1",
1069 "org.freedesktop.login1.Manager",
1070 "KillSession",
1071 &error, NULL,
1072 "ssi", argv[i], arg_kill_who, arg_signal);
1073 if (r < 0) {
1074 log_error("Could not kill session: %s", bus_error_message(&error, -r));
1075 return r;
1076 }
1077 }
1078
1079 return 0;
1080 }
1081
1082 static int enable_linger(int argc, char *argv[], void *userdata) {
1083 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1084 sd_bus *bus = userdata;
1085 char* short_argv[3];
1086 bool b;
1087 int r, i;
1088
1089 assert(bus);
1090 assert(argv);
1091
1092 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1093
1094 b = streq(argv[0], "enable-linger");
1095
1096 if (argc < 2) {
1097 /* No argument? Let's use an empty user name,
1098 * then logind will use our user. */
1099
1100 short_argv[0] = argv[0];
1101 short_argv[1] = (char*) "";
1102 short_argv[2] = NULL;
1103 argv = short_argv;
1104 argc = 2;
1105 }
1106
1107 for (i = 1; i < argc; i++) {
1108 uid_t uid;
1109
1110 if (isempty(argv[i]))
1111 uid = UID_INVALID;
1112 else {
1113 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1114 if (r < 0)
1115 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1116 }
1117
1118 r = sd_bus_call_method(
1119 bus,
1120 "org.freedesktop.login1",
1121 "/org/freedesktop/login1",
1122 "org.freedesktop.login1.Manager",
1123 "SetUserLinger",
1124 &error, NULL,
1125 "ubb", (uint32_t) uid, b, true);
1126 if (r < 0) {
1127 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
1128 return r;
1129 }
1130 }
1131
1132 return 0;
1133 }
1134
1135 static int terminate_user(int argc, char *argv[], void *userdata) {
1136 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1137 sd_bus *bus = userdata;
1138 int r, i;
1139
1140 assert(bus);
1141 assert(argv);
1142
1143 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1144
1145 for (i = 1; i < argc; i++) {
1146 uid_t uid;
1147
1148 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1149 if (r < 0)
1150 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1151
1152 r = sd_bus_call_method(
1153 bus,
1154 "org.freedesktop.login1",
1155 "/org/freedesktop/login1",
1156 "org.freedesktop.login1.Manager",
1157 "TerminateUser",
1158 &error, NULL,
1159 "u", (uint32_t) uid);
1160 if (r < 0) {
1161 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1162 return r;
1163 }
1164 }
1165
1166 return 0;
1167 }
1168
1169 static int kill_user(int argc, char *argv[], void *userdata) {
1170 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1171 sd_bus *bus = userdata;
1172 int r, i;
1173
1174 assert(bus);
1175 assert(argv);
1176
1177 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1178
1179 if (!arg_kill_who)
1180 arg_kill_who = "all";
1181
1182 for (i = 1; i < argc; i++) {
1183 uid_t uid;
1184
1185 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1186 if (r < 0)
1187 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1188
1189 r = sd_bus_call_method(
1190 bus,
1191 "org.freedesktop.login1",
1192 "/org/freedesktop/login1",
1193 "org.freedesktop.login1.Manager",
1194 "KillUser",
1195 &error, NULL,
1196 "ui", (uint32_t) uid, arg_signal);
1197 if (r < 0) {
1198 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1199 return r;
1200 }
1201 }
1202
1203 return 0;
1204 }
1205
1206 static int attach(int argc, char *argv[], void *userdata) {
1207 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1208 sd_bus *bus = userdata;
1209 int r, i;
1210
1211 assert(bus);
1212 assert(argv);
1213
1214 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1215
1216 for (i = 2; i < argc; i++) {
1217
1218 r = sd_bus_call_method(
1219 bus,
1220 "org.freedesktop.login1",
1221 "/org/freedesktop/login1",
1222 "org.freedesktop.login1.Manager",
1223 "AttachDevice",
1224 &error, NULL,
1225 "ssb", argv[1], argv[i], true);
1226
1227 if (r < 0) {
1228 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1229 return r;
1230 }
1231 }
1232
1233 return 0;
1234 }
1235
1236 static int flush_devices(int argc, char *argv[], void *userdata) {
1237 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1238 sd_bus *bus = userdata;
1239 int r;
1240
1241 assert(bus);
1242 assert(argv);
1243
1244 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1245
1246 r = sd_bus_call_method(
1247 bus,
1248 "org.freedesktop.login1",
1249 "/org/freedesktop/login1",
1250 "org.freedesktop.login1.Manager",
1251 "FlushDevices",
1252 &error, NULL,
1253 "b", true);
1254 if (r < 0)
1255 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1256
1257 return r;
1258 }
1259
1260 static int lock_sessions(int argc, char *argv[], void *userdata) {
1261 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1262 sd_bus *bus = userdata;
1263 int r;
1264
1265 assert(bus);
1266 assert(argv);
1267
1268 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1269
1270 r = sd_bus_call_method(
1271 bus,
1272 "org.freedesktop.login1",
1273 "/org/freedesktop/login1",
1274 "org.freedesktop.login1.Manager",
1275 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1276 &error, NULL,
1277 NULL);
1278 if (r < 0)
1279 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1280
1281 return r;
1282 }
1283
1284 static int terminate_seat(int argc, char *argv[], void *userdata) {
1285 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1286 sd_bus *bus = userdata;
1287 int r, i;
1288
1289 assert(bus);
1290 assert(argv);
1291
1292 polkit_agent_open_if_enabled(arg_transport, arg_ask_password);
1293
1294 for (i = 1; i < argc; i++) {
1295
1296 r = sd_bus_call_method(
1297 bus,
1298 "org.freedesktop.login1",
1299 "/org/freedesktop/login1",
1300 "org.freedesktop.login1.Manager",
1301 "TerminateSeat",
1302 &error, NULL,
1303 "s", argv[i]);
1304 if (r < 0) {
1305 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1306 return r;
1307 }
1308 }
1309
1310 return 0;
1311 }
1312
1313 static int help(int argc, char *argv[], void *userdata) {
1314
1315 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1316 "Send control commands to or query the login manager.\n\n"
1317 " -h --help Show this help\n"
1318 " --version Show package version\n"
1319 " --no-pager Do not pipe output into a pager\n"
1320 " --no-legend Do not show the headers and footers\n"
1321 " --no-ask-password Don't prompt for password\n"
1322 " -H --host=[USER@]HOST Operate on remote host\n"
1323 " -M --machine=CONTAINER Operate on local container\n"
1324 " -p --property=NAME Show only properties by this name\n"
1325 " -a --all Show all properties, including empty ones\n"
1326 " --value When showing properties, only print the value\n"
1327 " -l --full Do not ellipsize output\n"
1328 " --kill-who=WHO Who to send signal to\n"
1329 " -s --signal=SIGNAL Which signal to send\n"
1330 " -n --lines=INTEGER Number of journal entries to show\n"
1331 " -o --output=STRING Change journal output mode (short, short-precise,\n"
1332 " short-iso, short-iso-precise, short-full,\n"
1333 " short-monotonic, short-unix, verbose, export,\n"
1334 " json, json-pretty, json-sse, cat)\n"
1335 "Session Commands:\n"
1336 " list-sessions List sessions\n"
1337 " session-status [ID...] Show session status\n"
1338 " show-session [ID...] Show properties of sessions or the manager\n"
1339 " activate [ID] Activate a session\n"
1340 " lock-session [ID...] Screen lock one or more sessions\n"
1341 " unlock-session [ID...] Screen unlock one or more sessions\n"
1342 " lock-sessions Screen lock all current sessions\n"
1343 " unlock-sessions Screen unlock all current sessions\n"
1344 " terminate-session ID... Terminate one or more sessions\n"
1345 " kill-session ID... Send signal to processes of a session\n\n"
1346 "User Commands:\n"
1347 " list-users List users\n"
1348 " user-status [USER...] Show user status\n"
1349 " show-user [USER...] Show properties of users or the manager\n"
1350 " enable-linger [USER...] Enable linger state of one or more users\n"
1351 " disable-linger [USER...] Disable linger state of one or more users\n"
1352 " terminate-user USER... Terminate all sessions of one or more users\n"
1353 " kill-user USER... Send signal to processes of a user\n\n"
1354 "Seat Commands:\n"
1355 " list-seats List seats\n"
1356 " seat-status [NAME...] Show seat status\n"
1357 " show-seat [NAME...] Show properties of seats or the manager\n"
1358 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1359 " flush-devices Flush all device associations\n"
1360 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1361 , program_invocation_short_name);
1362
1363 return 0;
1364 }
1365
1366 static int parse_argv(int argc, char *argv[]) {
1367
1368 enum {
1369 ARG_VERSION = 0x100,
1370 ARG_VALUE,
1371 ARG_NO_PAGER,
1372 ARG_NO_LEGEND,
1373 ARG_KILL_WHO,
1374 ARG_NO_ASK_PASSWORD,
1375 };
1376
1377 static const struct option options[] = {
1378 { "help", no_argument, NULL, 'h' },
1379 { "version", no_argument, NULL, ARG_VERSION },
1380 { "property", required_argument, NULL, 'p' },
1381 { "all", no_argument, NULL, 'a' },
1382 { "value", no_argument, NULL, ARG_VALUE },
1383 { "full", no_argument, NULL, 'l' },
1384 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1385 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1386 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1387 { "signal", required_argument, NULL, 's' },
1388 { "host", required_argument, NULL, 'H' },
1389 { "machine", required_argument, NULL, 'M' },
1390 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1391 { "lines", required_argument, NULL, 'n' },
1392 { "output", required_argument, NULL, 'o' },
1393 {}
1394 };
1395
1396 int c, r;
1397
1398 assert(argc >= 0);
1399 assert(argv);
1400
1401 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1402
1403 switch (c) {
1404
1405 case 'h':
1406 help(0, NULL, NULL);
1407 return 0;
1408
1409 case ARG_VERSION:
1410 return version();
1411
1412 case 'p': {
1413 r = strv_extend(&arg_property, optarg);
1414 if (r < 0)
1415 return log_oom();
1416
1417 /* If the user asked for a particular
1418 * property, show it to him, even if it is
1419 * empty. */
1420 arg_all = true;
1421 break;
1422 }
1423
1424 case 'a':
1425 arg_all = true;
1426 break;
1427
1428 case ARG_VALUE:
1429 arg_value = true;
1430 break;
1431
1432 case 'l':
1433 arg_full = true;
1434 break;
1435
1436 case 'n':
1437 if (safe_atou(optarg, &arg_lines) < 0) {
1438 log_error("Failed to parse lines '%s'", optarg);
1439 return -EINVAL;
1440 }
1441 break;
1442
1443 case 'o':
1444 arg_output = output_mode_from_string(optarg);
1445 if (arg_output < 0) {
1446 log_error("Unknown output '%s'.", optarg);
1447 return -EINVAL;
1448 }
1449 break;
1450
1451 case ARG_NO_PAGER:
1452 arg_no_pager = true;
1453 break;
1454
1455 case ARG_NO_LEGEND:
1456 arg_legend = false;
1457 break;
1458
1459 case ARG_NO_ASK_PASSWORD:
1460 arg_ask_password = false;
1461 break;
1462
1463 case ARG_KILL_WHO:
1464 arg_kill_who = optarg;
1465 break;
1466
1467 case 's':
1468 arg_signal = signal_from_string(optarg);
1469 if (arg_signal < 0) {
1470 log_error("Failed to parse signal string %s.", optarg);
1471 return -EINVAL;
1472 }
1473 break;
1474
1475 case 'H':
1476 arg_transport = BUS_TRANSPORT_REMOTE;
1477 arg_host = optarg;
1478 break;
1479
1480 case 'M':
1481 arg_transport = BUS_TRANSPORT_MACHINE;
1482 arg_host = optarg;
1483 break;
1484
1485 case '?':
1486 return -EINVAL;
1487
1488 default:
1489 assert_not_reached("Unhandled option");
1490 }
1491
1492 return 1;
1493 }
1494
1495 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1496
1497 static const Verb verbs[] = {
1498 { "help", VERB_ANY, VERB_ANY, 0, help },
1499 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1500 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1501 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1502 { "activate", VERB_ANY, 2, 0, activate },
1503 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1504 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1505 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1506 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1507 { "terminate-session", 2, VERB_ANY, 0, activate },
1508 { "kill-session", 2, VERB_ANY, 0, kill_session },
1509 { "list-users", VERB_ANY, 1, 0, list_users },
1510 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1511 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1512 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1513 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1514 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1515 { "kill-user", 2, VERB_ANY, 0, kill_user },
1516 { "list-seats", VERB_ANY, 1, 0, list_seats },
1517 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1518 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1519 { "attach", 3, VERB_ANY, 0, attach },
1520 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1521 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1522 {}
1523 };
1524
1525 return dispatch_verb(argc, argv, verbs, bus);
1526 }
1527
1528 int main(int argc, char *argv[]) {
1529 sd_bus *bus = NULL;
1530 int r;
1531
1532 setlocale(LC_ALL, "");
1533 log_parse_environment();
1534 log_open();
1535 sigbus_install();
1536
1537 r = parse_argv(argc, argv);
1538 if (r <= 0)
1539 goto finish;
1540
1541 r = bus_connect_transport(arg_transport, arg_host, false, &bus);
1542 if (r < 0) {
1543 log_error_errno(r, "Failed to create bus connection: %m");
1544 goto finish;
1545 }
1546
1547 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1548
1549 r = loginctl_main(argc, argv, bus);
1550
1551 finish:
1552 /* make sure we terminate the bus connection first, and then close the
1553 * pager, see issue #3543 for the details. */
1554 sd_bus_flush_close_unref(bus);
1555 pager_close();
1556 polkit_agent_close();
1557
1558 strv_free(arg_property);
1559
1560 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1561 }