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