Branch data 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 : 16 : 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 : 12 : static int help(int argc, char *argv[], void *userdata) {
1274 : 12 : _cleanup_free_ char *link = NULL;
1275 : : int r;
1276 : :
1277 : 12 : (void) pager_open(arg_pager_flags);
1278 : :
1279 : 12 : r = terminal_urlify_man("loginctl", "1", &link);
1280 [ - + ]: 12 : if (r < 0)
1281 : 0 : return log_oom();
1282 : :
1283 : 12 : 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 : 12 : return 0;
1336 : : }
1337 : :
1338 : 16 : 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 [ - + ]: 16 : assert(argc >= 0);
1371 [ - + ]: 16 : assert(argv);
1372 : :
1373 [ + - ]: 16 : while ((c = getopt_long(argc, argv, "hp:als:H:M:n:o:", options, NULL)) >= 0)
1374 : :
1375 [ + - - - : 16 : switch (c) {
- - - - -
- - - - -
- + - ]
1376 : :
1377 : 12 : case 'h':
1378 : 12 : 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 : 4 : case '?':
1468 : 4 : 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 : 16 : static int run(int argc, char *argv[]) {
1511 : 16 : _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
1512 : : int r;
1513 : :
1514 : 16 : setlocale(LC_ALL, "");
1515 : 16 : log_show_color(true);
1516 : 16 : log_parse_environment();
1517 : 16 : log_open();
1518 : :
1519 : : /* The journal merging logic potentially needs a lot of fds. */
1520 : 16 : (void) rlimit_nofile_bump(HIGH_RLIMIT_NOFILE);
1521 : :
1522 : 16 : sigbus_install();
1523 : :
1524 : 16 : r = parse_argv(argc, argv);
1525 [ + - ]: 16 : if (r <= 0)
1526 : 16 : 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 : 16 : DEFINE_MAIN_FUNCTION(run);
|