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