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