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