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