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