]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/login/loginctl.c
Merge pull request #509 from dvdhrm/logind
[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 free(*p);
376 *p = strdup(s);
377
378 if (!*p)
379 return -ENOMEM;
380 } else {
381 r = sd_bus_message_read_basic(m, contents[0], userdata);
382 if (r < 0)
383 return r;
384 }
385
386 r = sd_bus_message_skip(m, contents+1);
387 if (r < 0)
388 return r;
389
390 r = sd_bus_message_exit_container(m);
391 if (r < 0)
392 return r;
393
394 return 0;
395 }
396
397 static int prop_map_sessions_strv(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
398 const char *name;
399 int r;
400
401 assert(bus);
402 assert(m);
403
404 r = sd_bus_message_enter_container(m, 'a', "(so)");
405 if (r < 0)
406 return r;
407
408 while ((r = sd_bus_message_read(m, "(so)", &name, NULL)) > 0) {
409 r = strv_extend(userdata, name);
410 if (r < 0)
411 return r;
412 }
413 if (r < 0)
414 return r;
415
416 return sd_bus_message_exit_container(m);
417 }
418
419 static int print_session_status_info(sd_bus *bus, const char *path, bool *new_line) {
420
421 static const struct bus_properties_map map[] = {
422 { "Id", "s", NULL, offsetof(SessionStatusInfo, id) },
423 { "Name", "s", NULL, offsetof(SessionStatusInfo, name) },
424 { "TTY", "s", NULL, offsetof(SessionStatusInfo, tty) },
425 { "Display", "s", NULL, offsetof(SessionStatusInfo, display) },
426 { "RemoteHost", "s", NULL, offsetof(SessionStatusInfo, remote_host) },
427 { "RemoteUser", "s", NULL, offsetof(SessionStatusInfo, remote_user) },
428 { "Service", "s", NULL, offsetof(SessionStatusInfo, service) },
429 { "Desktop", "s", NULL, offsetof(SessionStatusInfo, desktop) },
430 { "Type", "s", NULL, offsetof(SessionStatusInfo, type) },
431 { "Class", "s", NULL, offsetof(SessionStatusInfo, class) },
432 { "Scope", "s", NULL, offsetof(SessionStatusInfo, scope) },
433 { "State", "s", NULL, offsetof(SessionStatusInfo, state) },
434 { "VTNr", "u", NULL, offsetof(SessionStatusInfo, vtnr) },
435 { "Leader", "u", NULL, offsetof(SessionStatusInfo, leader) },
436 { "Remote", "b", NULL, offsetof(SessionStatusInfo, remote) },
437 { "Timestamp", "t", NULL, offsetof(SessionStatusInfo, timestamp.realtime) },
438 { "TimestampMonotonic", "t", NULL, offsetof(SessionStatusInfo, timestamp.monotonic) },
439 { "User", "(uo)", prop_map_first_of_struct, offsetof(SessionStatusInfo, uid) },
440 { "Seat", "(so)", prop_map_first_of_struct, offsetof(SessionStatusInfo, seat) },
441 {}
442 };
443
444 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
445 char since2[FORMAT_TIMESTAMP_MAX], *s2;
446 _cleanup_(session_status_info_clear) SessionStatusInfo i = {};
447 int r;
448
449 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
450 if (r < 0)
451 return log_error_errno(r, "Could not get properties: %m");
452
453 if (*new_line)
454 printf("\n");
455
456 *new_line = true;
457
458 printf("%s - ", strna(i.id));
459
460 if (i.name)
461 printf("%s (%u)\n", i.name, (unsigned) i.uid);
462 else
463 printf("%u\n", (unsigned) i.uid);
464
465 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
466 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
467
468 if (s1)
469 printf("\t Since: %s; %s\n", s2, s1);
470 else if (s2)
471 printf("\t Since: %s\n", s2);
472
473 if (i.leader > 0) {
474 _cleanup_free_ char *t = NULL;
475
476 printf("\t Leader: %u", (unsigned) i.leader);
477
478 get_process_comm(i.leader, &t);
479 if (t)
480 printf(" (%s)", t);
481
482 printf("\n");
483 }
484
485 if (!isempty(i.seat)) {
486 printf("\t Seat: %s", i.seat);
487
488 if (i.vtnr > 0)
489 printf("; vc%u", i.vtnr);
490
491 printf("\n");
492 }
493
494 if (i.tty)
495 printf("\t TTY: %s\n", i.tty);
496 else if (i.display)
497 printf("\t Display: %s\n", i.display);
498
499 if (i.remote_host && i.remote_user)
500 printf("\t Remote: %s@%s\n", i.remote_user, i.remote_host);
501 else if (i.remote_host)
502 printf("\t Remote: %s\n", i.remote_host);
503 else if (i.remote_user)
504 printf("\t Remote: user %s\n", i.remote_user);
505 else if (i.remote)
506 printf("\t Remote: Yes\n");
507
508 if (i.service) {
509 printf("\t Service: %s", i.service);
510
511 if (i.type)
512 printf("; type %s", i.type);
513
514 if (i.class)
515 printf("; class %s", i.class);
516
517 printf("\n");
518 } else if (i.type) {
519 printf("\t Type: %s", i.type);
520
521 if (i.class)
522 printf("; class %s", i.class);
523
524 printf("\n");
525 } else if (i.class)
526 printf("\t Class: %s\n", i.class);
527
528 if (!isempty(i.desktop))
529 printf("\t Desktop: %s\n", i.desktop);
530
531 if (i.state)
532 printf("\t State: %s\n", i.state);
533
534 if (i.scope) {
535 printf("\t Unit: %s\n", i.scope);
536 show_unit_cgroup(bus, "org.freedesktop.systemd1.Scope", i.scope, i.leader);
537
538 if (arg_transport == BUS_TRANSPORT_LOCAL) {
539
540 show_journal_by_unit(
541 stdout,
542 i.scope,
543 arg_output,
544 0,
545 i.timestamp.monotonic,
546 arg_lines,
547 0,
548 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
549 SD_JOURNAL_LOCAL_ONLY,
550 true,
551 NULL);
552 }
553 }
554
555 return 0;
556 }
557
558 static int print_user_status_info(sd_bus *bus, const char *path, bool *new_line) {
559
560 static const struct bus_properties_map map[] = {
561 { "Name", "s", NULL, offsetof(UserStatusInfo, name) },
562 { "Slice", "s", NULL, offsetof(UserStatusInfo, slice) },
563 { "State", "s", NULL, offsetof(UserStatusInfo, state) },
564 { "UID", "u", NULL, offsetof(UserStatusInfo, uid) },
565 { "Timestamp", "t", NULL, offsetof(UserStatusInfo, timestamp.realtime) },
566 { "TimestampMonotonic", "t", NULL, offsetof(UserStatusInfo, timestamp.monotonic) },
567 { "Display", "(so)", prop_map_first_of_struct, offsetof(UserStatusInfo, display) },
568 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(UserStatusInfo, sessions) },
569 {}
570 };
571
572 char since1[FORMAT_TIMESTAMP_RELATIVE_MAX], *s1;
573 char since2[FORMAT_TIMESTAMP_MAX], *s2;
574 _cleanup_(user_status_info_clear) UserStatusInfo i = {};
575 int r;
576
577 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
578 if (r < 0)
579 return log_error_errno(r, "Could not get properties: %m");
580
581 if (*new_line)
582 printf("\n");
583
584 *new_line = true;
585
586 if (i.name)
587 printf("%s (%u)\n", i.name, (unsigned) i.uid);
588 else
589 printf("%u\n", (unsigned) i.uid);
590
591 s1 = format_timestamp_relative(since1, sizeof(since1), i.timestamp.realtime);
592 s2 = format_timestamp(since2, sizeof(since2), i.timestamp.realtime);
593
594 if (s1)
595 printf("\t Since: %s; %s\n", s2, s1);
596 else if (s2)
597 printf("\t Since: %s\n", s2);
598
599 if (!isempty(i.state))
600 printf("\t State: %s\n", i.state);
601
602 if (!strv_isempty(i.sessions)) {
603 char **l;
604 printf("\tSessions:");
605
606 STRV_FOREACH(l, i.sessions) {
607 if (streq_ptr(*l, i.display))
608 printf(" *%s", *l);
609 else
610 printf(" %s", *l);
611 }
612
613 printf("\n");
614 }
615
616 if (i.slice) {
617 printf("\t Unit: %s\n", i.slice);
618 show_unit_cgroup(bus, "org.freedesktop.systemd1.Slice", i.slice, 0);
619
620 show_journal_by_unit(
621 stdout,
622 i.slice,
623 arg_output,
624 0,
625 i.timestamp.monotonic,
626 arg_lines,
627 0,
628 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
629 SD_JOURNAL_LOCAL_ONLY,
630 true,
631 NULL);
632 }
633
634 return 0;
635 }
636
637 static int print_seat_status_info(sd_bus *bus, const char *path, bool *new_line) {
638
639 static const struct bus_properties_map map[] = {
640 { "Id", "s", NULL, offsetof(SeatStatusInfo, id) },
641 { "ActiveSession", "(so)", prop_map_first_of_struct, offsetof(SeatStatusInfo, active_session) },
642 { "Sessions", "a(so)", prop_map_sessions_strv, offsetof(SeatStatusInfo, sessions) },
643 {}
644 };
645
646 _cleanup_(seat_status_info_clear) SeatStatusInfo i = {};
647 int r;
648
649 r = bus_map_all_properties(bus, "org.freedesktop.login1", path, map, &i);
650 if (r < 0)
651 return log_error_errno(r, "Could not get properties: %m");
652
653 if (*new_line)
654 printf("\n");
655
656 *new_line = true;
657
658 printf("%s\n", strna(i.id));
659
660 if (!strv_isempty(i.sessions)) {
661 char **l;
662 printf("\tSessions:");
663
664 STRV_FOREACH(l, i.sessions) {
665 if (streq_ptr(*l, i.active_session))
666 printf(" *%s", *l);
667 else
668 printf(" %s", *l);
669 }
670
671 printf("\n");
672 }
673
674 if (arg_transport == BUS_TRANSPORT_LOCAL) {
675 unsigned c;
676
677 c = columns();
678 if (c > 21)
679 c -= 21;
680 else
681 c = 0;
682
683 printf("\t Devices:\n");
684
685 show_sysfs(i.id, "\t\t ", c);
686 }
687
688 return 0;
689 }
690
691 static int show_properties(sd_bus *bus, const char *path, bool *new_line) {
692 int r;
693
694 if (*new_line)
695 printf("\n");
696
697 *new_line = true;
698
699 r = bus_print_all_properties(bus, "org.freedesktop.login1", path, arg_property, arg_all);
700 if (r < 0)
701 log_error_errno(r, "Could not get properties: %m");
702
703 return r;
704 }
705
706 static int show_session(int argc, char *argv[], void *userdata) {
707 bool properties, new_line = false;
708 sd_bus *bus = userdata;
709 int r, i;
710
711 assert(bus);
712 assert(argv);
713
714 properties = !strstr(argv[0], "status");
715
716 pager_open_if_enabled();
717
718 if (argc <= 1) {
719 /* If not argument is specified inspect the manager
720 * itself */
721 if (properties)
722 return show_properties(bus, "/org/freedesktop/login1", &new_line);
723
724 /* And in the pretty case, show data of the calling session */
725 return print_session_status_info(bus, "/org/freedesktop/login1/session/self", &new_line);
726 }
727
728 for (i = 1; i < argc; i++) {
729 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
730 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
731 const char *path = NULL;
732
733 r = sd_bus_call_method(
734 bus,
735 "org.freedesktop.login1",
736 "/org/freedesktop/login1",
737 "org.freedesktop.login1.Manager",
738 "GetSession",
739 &error, &reply,
740 "s", argv[i]);
741 if (r < 0) {
742 log_error("Failed to get session: %s", bus_error_message(&error, r));
743 return r;
744 }
745
746 r = sd_bus_message_read(reply, "o", &path);
747 if (r < 0)
748 return bus_log_parse_error(r);
749
750 if (properties)
751 r = show_properties(bus, path, &new_line);
752 else
753 r = print_session_status_info(bus, path, &new_line);
754
755 if (r < 0)
756 return r;
757 }
758
759 return 0;
760 }
761
762 static int show_user(int argc, char *argv[], void *userdata) {
763 bool properties, new_line = false;
764 sd_bus *bus = userdata;
765 int r, i;
766
767 assert(bus);
768 assert(argv);
769
770 properties = !strstr(argv[0], "status");
771
772 pager_open_if_enabled();
773
774 if (argc <= 1) {
775 /* If not argument is specified inspect the manager
776 * itself */
777 if (properties)
778 return show_properties(bus, "/org/freedesktop/login1", &new_line);
779
780 return print_user_status_info(bus, "/org/freedesktop/login1/user/self", &new_line);
781 }
782
783 for (i = 1; i < argc; i++) {
784 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
785 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
786 const char *path = NULL;
787 uid_t uid;
788
789 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
790 if (r < 0)
791 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
792
793 r = sd_bus_call_method(
794 bus,
795 "org.freedesktop.login1",
796 "/org/freedesktop/login1",
797 "org.freedesktop.login1.Manager",
798 "GetUser",
799 &error, &reply,
800 "u", (uint32_t) uid);
801 if (r < 0) {
802 log_error("Failed to get user: %s", bus_error_message(&error, r));
803 return r;
804 }
805
806 r = sd_bus_message_read(reply, "o", &path);
807 if (r < 0)
808 return bus_log_parse_error(r);
809
810 if (properties)
811 r = show_properties(bus, path, &new_line);
812 else
813 r = print_user_status_info(bus, path, &new_line);
814
815 if (r < 0)
816 return r;
817 }
818
819 return 0;
820 }
821
822 static int show_seat(int argc, char *argv[], void *userdata) {
823 bool properties, new_line = false;
824 sd_bus *bus = userdata;
825 int r, i;
826
827 assert(bus);
828 assert(argv);
829
830 properties = !strstr(argv[0], "status");
831
832 pager_open_if_enabled();
833
834 if (argc <= 1) {
835 /* If not argument is specified inspect the manager
836 * itself */
837 if (properties)
838 return show_properties(bus, "/org/freedesktop/login1", &new_line);
839
840 return print_seat_status_info(bus, "/org/freedesktop/login1/seat/self", &new_line);
841 }
842
843 for (i = 1; i < argc; i++) {
844 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
845 _cleanup_bus_message_unref_ sd_bus_message * reply = NULL;
846 const char *path = NULL;
847
848 r = sd_bus_call_method(
849 bus,
850 "org.freedesktop.login1",
851 "/org/freedesktop/login1",
852 "org.freedesktop.login1.Manager",
853 "GetSeat",
854 &error, &reply,
855 "s", argv[i]);
856 if (r < 0) {
857 log_error("Failed to get seat: %s", bus_error_message(&error, r));
858 return r;
859 }
860
861 r = sd_bus_message_read(reply, "o", &path);
862 if (r < 0)
863 return bus_log_parse_error(r);
864
865 if (properties)
866 r = show_properties(bus, path, &new_line);
867 else
868 r = print_seat_status_info(bus, path, &new_line);
869
870 if (r < 0)
871 return r;
872 }
873
874 return 0;
875 }
876
877 static int activate(int argc, char *argv[], void *userdata) {
878 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
879 sd_bus *bus = userdata;
880 char *short_argv[3];
881 int r, i;
882
883 assert(bus);
884 assert(argv);
885
886 polkit_agent_open_if_enabled();
887
888 if (argc < 2) {
889 /* No argument? Let's convert this into the empty
890 * session name, which the calls will then resolve to
891 * the caller's session. */
892
893 short_argv[0] = argv[0];
894 short_argv[1] = (char*) "";
895 short_argv[2] = NULL;
896
897 argv = short_argv;
898 argc = 2;
899 }
900
901 for (i = 1; i < argc; i++) {
902
903 r = sd_bus_call_method(
904 bus,
905 "org.freedesktop.login1",
906 "/org/freedesktop/login1",
907 "org.freedesktop.login1.Manager",
908 streq(argv[0], "lock-session") ? "LockSession" :
909 streq(argv[0], "unlock-session") ? "UnlockSession" :
910 streq(argv[0], "terminate-session") ? "TerminateSession" :
911 "ActivateSession",
912 &error, NULL,
913 "s", argv[i]);
914 if (r < 0) {
915 log_error("Failed to issue method call: %s", bus_error_message(&error, -r));
916 return r;
917 }
918 }
919
920 return 0;
921 }
922
923 static int kill_session(int argc, char *argv[], void *userdata) {
924 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
925 sd_bus *bus = userdata;
926 int r, i;
927
928 assert(bus);
929 assert(argv);
930
931 polkit_agent_open_if_enabled();
932
933 if (!arg_kill_who)
934 arg_kill_who = "all";
935
936 for (i = 1; i < argc; i++) {
937
938 r = sd_bus_call_method(
939 bus,
940 "org.freedesktop.login1",
941 "/org/freedesktop/login1",
942 "org.freedesktop.login1.Manager",
943 "KillSession",
944 &error, NULL,
945 "ssi", argv[i], arg_kill_who, arg_signal);
946 if (r < 0) {
947 log_error("Could not kill session: %s", bus_error_message(&error, -r));
948 return r;
949 }
950 }
951
952 return 0;
953 }
954
955 static int enable_linger(int argc, char *argv[], void *userdata) {
956 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
957 sd_bus *bus = userdata;
958 char* short_argv[3];
959 bool b;
960 int r, i;
961
962 assert(bus);
963 assert(argv);
964
965 polkit_agent_open_if_enabled();
966
967 b = streq(argv[0], "enable-linger");
968
969 if (argc < 2) {
970 short_argv[0] = argv[0];
971 short_argv[1] = (char*) "";
972 short_argv[2] = NULL;
973 argv = short_argv;
974 argc = 2;
975 }
976
977 for (i = 1; i < argc; i++) {
978 uid_t uid;
979
980 if (isempty(argv[i]))
981 uid = UID_INVALID;
982 else {
983 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
984 if (r < 0)
985 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
986 }
987
988 r = sd_bus_call_method(
989 bus,
990 "org.freedesktop.login1",
991 "/org/freedesktop/login1",
992 "org.freedesktop.login1.Manager",
993 "SetUserLinger",
994 &error, NULL,
995 "ubb", (uint32_t) uid, b, true);
996 if (r < 0) {
997 log_error("Could not enable linger: %s", bus_error_message(&error, -r));
998 return r;
999 }
1000 }
1001
1002 return 0;
1003 }
1004
1005 static int terminate_user(int argc, char *argv[], void *userdata) {
1006 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1007 sd_bus *bus = userdata;
1008 int r, i;
1009
1010 assert(bus);
1011 assert(argv);
1012
1013 polkit_agent_open_if_enabled();
1014
1015 for (i = 1; i < argc; i++) {
1016 uid_t uid;
1017
1018 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1019 if (r < 0)
1020 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1021
1022 r = sd_bus_call_method(
1023 bus,
1024 "org.freedesktop.login1",
1025 "/org/freedesktop/login1",
1026 "org.freedesktop.login1.Manager",
1027 "TerminateUser",
1028 &error, NULL,
1029 "u", (uint32_t) uid);
1030 if (r < 0) {
1031 log_error("Could not terminate user: %s", bus_error_message(&error, -r));
1032 return r;
1033 }
1034 }
1035
1036 return 0;
1037 }
1038
1039 static int kill_user(int argc, char *argv[], void *userdata) {
1040 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1041 sd_bus *bus = userdata;
1042 int r, i;
1043
1044 assert(bus);
1045 assert(argv);
1046
1047 polkit_agent_open_if_enabled();
1048
1049 if (!arg_kill_who)
1050 arg_kill_who = "all";
1051
1052 for (i = 1; i < argc; i++) {
1053 uid_t uid;
1054
1055 r = get_user_creds((const char**) (argv+i), &uid, NULL, NULL, NULL);
1056 if (r < 0)
1057 return log_error_errno(r, "Failed to look up user %s: %m", argv[i]);
1058
1059 r = sd_bus_call_method(
1060 bus,
1061 "org.freedesktop.login1",
1062 "/org/freedesktop/login1",
1063 "org.freedesktop.login1.Manager",
1064 "KillUser",
1065 &error, NULL,
1066 "ui", (uint32_t) uid, arg_signal);
1067 if (r < 0) {
1068 log_error("Could not kill user: %s", bus_error_message(&error, -r));
1069 return r;
1070 }
1071 }
1072
1073 return 0;
1074 }
1075
1076 static int attach(int argc, char *argv[], void *userdata) {
1077 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1078 sd_bus *bus = userdata;
1079 int r, i;
1080
1081 assert(bus);
1082 assert(argv);
1083
1084 polkit_agent_open_if_enabled();
1085
1086 for (i = 2; 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 "AttachDevice",
1094 &error, NULL,
1095 "ssb", argv[1], argv[i], true);
1096
1097 if (r < 0) {
1098 log_error("Could not attach device: %s", bus_error_message(&error, -r));
1099 return r;
1100 }
1101 }
1102
1103 return 0;
1104 }
1105
1106 static int flush_devices(int argc, char *argv[], void *userdata) {
1107 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1108 sd_bus *bus = userdata;
1109 int r;
1110
1111 assert(bus);
1112 assert(argv);
1113
1114 polkit_agent_open_if_enabled();
1115
1116 r = sd_bus_call_method(
1117 bus,
1118 "org.freedesktop.login1",
1119 "/org/freedesktop/login1",
1120 "org.freedesktop.login1.Manager",
1121 "FlushDevices",
1122 &error, NULL,
1123 "b", true);
1124 if (r < 0)
1125 log_error("Could not flush devices: %s", bus_error_message(&error, -r));
1126
1127 return r;
1128 }
1129
1130 static int lock_sessions(int argc, char *argv[], void *userdata) {
1131 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1132 sd_bus *bus = userdata;
1133 int r;
1134
1135 assert(bus);
1136 assert(argv);
1137
1138 polkit_agent_open_if_enabled();
1139
1140 r = sd_bus_call_method(
1141 bus,
1142 "org.freedesktop.login1",
1143 "/org/freedesktop/login1",
1144 "org.freedesktop.login1.Manager",
1145 streq(argv[0], "lock-sessions") ? "LockSessions" : "UnlockSessions",
1146 &error, NULL,
1147 NULL);
1148 if (r < 0)
1149 log_error("Could not lock sessions: %s", bus_error_message(&error, -r));
1150
1151 return r;
1152 }
1153
1154 static int terminate_seat(int argc, char *argv[], void *userdata) {
1155 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1156 sd_bus *bus = userdata;
1157 int r, i;
1158
1159 assert(bus);
1160 assert(argv);
1161
1162 polkit_agent_open_if_enabled();
1163
1164 for (i = 1; i < argc; i++) {
1165
1166 r = sd_bus_call_method(
1167 bus,
1168 "org.freedesktop.login1",
1169 "/org/freedesktop/login1",
1170 "org.freedesktop.login1.Manager",
1171 "TerminateSeat",
1172 &error, NULL,
1173 "s", argv[i]);
1174 if (r < 0) {
1175 log_error("Could not terminate seat: %s", bus_error_message(&error, -r));
1176 return r;
1177 }
1178 }
1179
1180 return 0;
1181 }
1182
1183 static int help(int argc, char *argv[], void *userdata) {
1184
1185 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
1186 "Send control commands to or query the login manager.\n\n"
1187 " -h --help Show this help\n"
1188 " --version Show package version\n"
1189 " --no-pager Do not pipe output into a pager\n"
1190 " --no-legend Do not show the headers and footers\n"
1191 " --no-ask-password Don't prompt for password\n"
1192 " -H --host=[USER@]HOST Operate on remote host\n"
1193 " -M --machine=CONTAINER Operate on local container\n"
1194 " -p --property=NAME Show only properties by this name\n"
1195 " -a --all Show all properties, including empty ones\n"
1196 " -l --full Do not ellipsize output\n"
1197 " --kill-who=WHO Who to send signal to\n"
1198 " -s --signal=SIGNAL Which signal to send\n"
1199 " -n --lines=INTEGER Number of journal entries to show\n"
1200 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
1201 " verbose, export, json, json-pretty, json-sse, cat)\n\n"
1202 "Session Commands:\n"
1203 " list-sessions List sessions\n"
1204 " session-status [ID...] Show session status\n"
1205 " show-session [ID...] Show properties of sessions or the manager\n"
1206 " activate [ID] Activate a session\n"
1207 " lock-session [ID...] Screen lock one or more sessions\n"
1208 " unlock-session [ID...] Screen unlock one or more sessions\n"
1209 " lock-sessions Screen lock all current sessions\n"
1210 " unlock-sessions Screen unlock all current sessions\n"
1211 " terminate-session ID... Terminate one or more sessions\n"
1212 " kill-session ID... Send signal to processes of a session\n\n"
1213 "User Commands:\n"
1214 " list-users List users\n"
1215 " user-status [USER...] Show user status\n"
1216 " show-user [USER...] Show properties of users or the manager\n"
1217 " enable-linger [USER...] Enable linger state of one or more users\n"
1218 " disable-linger [USER...] Disable linger state of one or more users\n"
1219 " terminate-user USER... Terminate all sessions of one or more users\n"
1220 " kill-user USER... Send signal to processes of a user\n\n"
1221 "Seat Commands:\n"
1222 " list-seats List seats\n"
1223 " seat-status [NAME...] Show seat status\n"
1224 " show-seat [NAME...] Show properties of seats or the manager\n"
1225 " attach NAME DEVICE... Attach one or more devices to a seat\n"
1226 " flush-devices Flush all device associations\n"
1227 " terminate-seat NAME... Terminate all sessions on one or more seats\n"
1228 , program_invocation_short_name);
1229
1230 return 0;
1231 }
1232
1233 static int parse_argv(int argc, char *argv[]) {
1234
1235 enum {
1236 ARG_VERSION = 0x100,
1237 ARG_NO_PAGER,
1238 ARG_NO_LEGEND,
1239 ARG_KILL_WHO,
1240 ARG_NO_ASK_PASSWORD,
1241 };
1242
1243 static const struct option options[] = {
1244 { "help", no_argument, NULL, 'h' },
1245 { "version", no_argument, NULL, ARG_VERSION },
1246 { "property", required_argument, NULL, 'p' },
1247 { "all", no_argument, NULL, 'a' },
1248 { "full", no_argument, NULL, 'l' },
1249 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
1250 { "no-legend", no_argument, NULL, ARG_NO_LEGEND },
1251 { "kill-who", required_argument, NULL, ARG_KILL_WHO },
1252 { "signal", required_argument, NULL, 's' },
1253 { "host", required_argument, NULL, 'H' },
1254 { "machine", required_argument, NULL, 'M' },
1255 { "no-ask-password", no_argument, NULL, ARG_NO_ASK_PASSWORD },
1256 { "lines", required_argument, NULL, 'n' },
1257 { "output", required_argument, NULL, 'o' },
1258 {}
1259 };
1260
1261 int c, r;
1262
1263 assert(argc >= 0);
1264 assert(argv);
1265
1266 while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1267
1268 switch (c) {
1269
1270 case 'h':
1271 help(0, NULL, NULL);
1272 return 0;
1273
1274 case ARG_VERSION:
1275 puts(PACKAGE_STRING);
1276 puts(SYSTEMD_FEATURES);
1277 return 0;
1278
1279 case 'p': {
1280 r = strv_extend(&arg_property, optarg);
1281 if (r < 0)
1282 return log_oom();
1283
1284 /* If the user asked for a particular
1285 * property, show it to him, even if it is
1286 * empty. */
1287 arg_all = true;
1288 break;
1289 }
1290
1291 case 'a':
1292 arg_all = true;
1293 break;
1294
1295 case 'l':
1296 arg_full = true;
1297 break;
1298
1299 case 'n':
1300 if (safe_atou(optarg, &arg_lines) < 0) {
1301 log_error("Failed to parse lines '%s'", optarg);
1302 return -EINVAL;
1303 }
1304 break;
1305
1306 case 'o':
1307 arg_output = output_mode_from_string(optarg);
1308 if (arg_output < 0) {
1309 log_error("Unknown output '%s'.", optarg);
1310 return -EINVAL;
1311 }
1312 break;
1313
1314 case ARG_NO_PAGER:
1315 arg_no_pager = true;
1316 break;
1317
1318 case ARG_NO_LEGEND:
1319 arg_legend = false;
1320 break;
1321
1322 case ARG_NO_ASK_PASSWORD:
1323 arg_ask_password = false;
1324 break;
1325
1326 case ARG_KILL_WHO:
1327 arg_kill_who = optarg;
1328 break;
1329
1330 case 's':
1331 arg_signal = signal_from_string_try_harder(optarg);
1332 if (arg_signal < 0) {
1333 log_error("Failed to parse signal string %s.", optarg);
1334 return -EINVAL;
1335 }
1336 break;
1337
1338 case 'H':
1339 arg_transport = BUS_TRANSPORT_REMOTE;
1340 arg_host = optarg;
1341 break;
1342
1343 case 'M':
1344 arg_transport = BUS_TRANSPORT_MACHINE;
1345 arg_host = optarg;
1346 break;
1347
1348 case '?':
1349 return -EINVAL;
1350
1351 default:
1352 assert_not_reached("Unhandled option");
1353 }
1354
1355 return 1;
1356 }
1357
1358 static int loginctl_main(int argc, char *argv[], sd_bus *bus) {
1359
1360 static const Verb verbs[] = {
1361 { "help", VERB_ANY, VERB_ANY, 0, help },
1362 { "list-sessions", VERB_ANY, 1, VERB_DEFAULT, list_sessions },
1363 { "session-status", VERB_ANY, VERB_ANY, 0, show_session },
1364 { "show-session", VERB_ANY, VERB_ANY, 0, show_session },
1365 { "activate", VERB_ANY, 2, 0, activate },
1366 { "lock-session", VERB_ANY, VERB_ANY, 0, activate },
1367 { "unlock-session", VERB_ANY, VERB_ANY, 0, activate },
1368 { "lock-sessions", VERB_ANY, 1, 0, lock_sessions },
1369 { "unlock-sessions", VERB_ANY, 1, 0, lock_sessions },
1370 { "terminate-session", 2, VERB_ANY, 0, activate },
1371 { "kill-session", 2, VERB_ANY, 0, kill_session },
1372 { "list-users", VERB_ANY, 1, 0, list_users },
1373 { "user-status", VERB_ANY, VERB_ANY, 0, show_user },
1374 { "show-user", VERB_ANY, VERB_ANY, 0, show_user },
1375 { "enable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1376 { "disable-linger", VERB_ANY, VERB_ANY, 0, enable_linger },
1377 { "terminate-user", 2, VERB_ANY, 0, terminate_user },
1378 { "kill-user", 2, VERB_ANY, 0, kill_user },
1379 { "list-seats", VERB_ANY, 1, 0, list_seats },
1380 { "seat-status", VERB_ANY, VERB_ANY, 0, show_seat },
1381 { "show-seat", VERB_ANY, VERB_ANY, 0, show_seat },
1382 { "attach", 3, VERB_ANY, 0, attach },
1383 { "flush-devices", VERB_ANY, 1, 0, flush_devices },
1384 { "terminate-seat", 2, VERB_ANY, 0, terminate_seat },
1385 {}
1386 };
1387
1388 return dispatch_verb(argc, argv, verbs, bus);
1389 }
1390
1391 int main(int argc, char *argv[]) {
1392 _cleanup_bus_flush_close_unref_ sd_bus *bus = NULL;
1393 int r;
1394
1395 setlocale(LC_ALL, "");
1396 log_parse_environment();
1397 log_open();
1398
1399 r = parse_argv(argc, argv);
1400 if (r <= 0)
1401 goto finish;
1402
1403 r = bus_open_transport(arg_transport, arg_host, false, &bus);
1404 if (r < 0) {
1405 log_error_errno(r, "Failed to create bus connection: %m");
1406 goto finish;
1407 }
1408
1409 sd_bus_set_allow_interactive_authorization(bus, arg_ask_password);
1410
1411 r = loginctl_main(argc, argv, bus);
1412
1413 finish:
1414 pager_close();
1415 polkit_agent_close();
1416
1417 strv_free(arg_property);
1418
1419 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1420 }