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