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