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