]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-show.c
Merge pull request #25389 from fbuihuu/update-test-for-opensuse
[thirdparty/systemd.git] / src / systemctl / systemctl-show.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
daf71ef6
LP
2
3#include <sys/mount.h>
4
a4817536 5#include "af-list.h"
daf71ef6
LP
6#include "bus-error.h"
7#include "bus-locator.h"
8#include "bus-map-properties.h"
9#include "bus-print-properties.h"
10#include "bus-unit-procs.h"
11#include "cgroup-show.h"
12#include "cpu-set-util.h"
13#include "errno-util.h"
14#include "exec-util.h"
15#include "exit-status.h"
16#include "format-util.h"
17#include "hexdecoct.h"
18#include "hostname-util.h"
19#include "in-addr-util.h"
60477eb9 20#include "ip-protocol-list.h"
adce225a 21#include "journal-file.h"
daf71ef6
LP
22#include "list.h"
23#include "locale-util.h"
24#include "memory-util.h"
25#include "numa-util.h"
26#include "parse-util.h"
27#include "path-util.h"
28#include "pretty-print.h"
29#include "process-util.h"
30#include "signal-util.h"
31#include "sort-util.h"
038cae09 32#include "special.h"
daf71ef6
LP
33#include "string-table.h"
34#include "systemctl-list-machines.h"
35#include "systemctl-list-units.h"
36#include "systemctl-show.h"
37#include "systemctl-sysv-compat.h"
38#include "systemctl-util.h"
39#include "systemctl.h"
40#include "terminal-util.h"
41#include "utf8.h"
42
43static OutputFlags get_output_flags(void) {
44 return
255b1fc8 45 FLAGS_SET(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) * OUTPUT_SHOW_ALL |
daf71ef6
LP
46 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
47 colors_enabled() * OUTPUT_COLOR |
48 !arg_quiet * OUTPUT_WARN_CUTOFF;
49}
50
51typedef struct ExecStatusInfo {
52 char *name;
53
54 char *path;
55 char **argv;
56
57 bool ignore;
58
59 usec_t start_timestamp;
60 usec_t exit_timestamp;
61 pid_t pid;
62 int code;
63 int status;
64
65 ExecCommandFlags flags;
66
eb506199 67 LIST_FIELDS(struct ExecStatusInfo, exec_status_info_list);
daf71ef6
LP
68} ExecStatusInfo;
69
70static void exec_status_info_free(ExecStatusInfo *i) {
71 assert(i);
72
73 free(i->name);
74 free(i->path);
75 strv_free(i->argv);
76 free(i);
77}
78
79static int exec_status_info_deserialize(sd_bus_message *m, ExecStatusInfo *i, bool is_ex_prop) {
80 _cleanup_strv_free_ char **ex_opts = NULL;
81 uint64_t start_timestamp, exit_timestamp, start_timestamp_monotonic, exit_timestamp_monotonic;
82 const char *path;
83 uint32_t pid;
84 int32_t code, status;
85 int ignore, r;
86
87 assert(m);
88 assert(i);
89
90 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_STRUCT, is_ex_prop ? "sasasttttuii" : "sasbttttuii");
91 if (r < 0)
92 return bus_log_parse_error(r);
ab5d52b7 93 if (r == 0)
daf71ef6
LP
94 return 0;
95
96 r = sd_bus_message_read(m, "s", &path);
97 if (r < 0)
98 return bus_log_parse_error(r);
99
100 i->path = strdup(path);
101 if (!i->path)
102 return log_oom();
103
104 r = sd_bus_message_read_strv(m, &i->argv);
105 if (r < 0)
106 return bus_log_parse_error(r);
107
108 r = is_ex_prop ? sd_bus_message_read_strv(m, &ex_opts) : sd_bus_message_read(m, "b", &ignore);
109 if (r < 0)
110 return bus_log_parse_error(r);
111
112 r = sd_bus_message_read(m,
113 "ttttuii",
114 &start_timestamp, &start_timestamp_monotonic,
115 &exit_timestamp, &exit_timestamp_monotonic,
116 &pid,
117 &code, &status);
118 if (r < 0)
119 return bus_log_parse_error(r);
120
121 if (is_ex_prop) {
122 r = exec_command_flags_from_strv(ex_opts, &i->flags);
123 if (r < 0)
124 return log_error_errno(r, "Failed to convert strv to ExecCommandFlags: %m");
125
126 i->ignore = FLAGS_SET(i->flags, EXEC_COMMAND_IGNORE_FAILURE);
127 } else
128 i->ignore = ignore;
129
130 i->start_timestamp = (usec_t) start_timestamp;
131 i->exit_timestamp = (usec_t) exit_timestamp;
132 i->pid = (pid_t) pid;
133 i->code = code;
134 i->status = status;
135
136 r = sd_bus_message_exit_container(m);
137 if (r < 0)
138 return bus_log_parse_error(r);
139
140 return 1;
141}
142
143typedef struct UnitCondition {
144 char *name;
145 char *param;
146 bool trigger;
147 bool negate;
148 int tristate;
149
150 LIST_FIELDS(struct UnitCondition, conditions);
151} UnitCondition;
152
75db809a 153static UnitCondition* unit_condition_free(UnitCondition *c) {
daf71ef6 154 if (!c)
75db809a 155 return NULL;
daf71ef6
LP
156
157 free(c->name);
158 free(c->param);
75db809a 159 return mfree(c);
daf71ef6 160}
daf71ef6
LP
161DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
162
163typedef struct UnitStatusInfo {
164 const char *id;
165 const char *load_state;
166 const char *active_state;
167 const char *freezer_state;
168 const char *sub_state;
169 const char *unit_file_state;
170 const char *unit_file_preset;
171
172 const char *description;
173 const char *following;
174
175 char **documentation;
176
177 const char *fragment_path;
178 const char *source_path;
179 const char *control_group;
180
181 char **dropin_paths;
182
183 char **triggered_by;
184 char **triggers;
185
186 const char *load_error;
187 const char *result;
188
189 usec_t inactive_exit_timestamp;
190 usec_t inactive_exit_timestamp_monotonic;
191 usec_t active_enter_timestamp;
192 usec_t active_exit_timestamp;
193 usec_t inactive_enter_timestamp;
194
a41699c9
AO
195 uint64_t runtime_max_sec;
196
daf71ef6
LP
197 bool need_daemon_reload;
198 bool transient;
199
200 /* Service */
201 pid_t main_pid;
202 pid_t control_pid;
203 const char *status_text;
204 const char *pid_file;
205 bool running:1;
206 int status_errno;
207
208 usec_t start_timestamp;
209 usec_t exit_timestamp;
210
211 int exit_code, exit_status;
212
213 const char *log_namespace;
214
215 usec_t condition_timestamp;
216 bool condition_result;
217 LIST_HEAD(UnitCondition, conditions);
218
219 usec_t assert_timestamp;
220 bool assert_result;
221 bool failed_assert_trigger;
222 bool failed_assert_negate;
223 const char *failed_assert;
224 const char *failed_assert_parameter;
225 usec_t next_elapse_real;
226 usec_t next_elapse_monotonic;
227
228 /* Socket */
229 unsigned n_accepted;
230 unsigned n_connections;
231 unsigned n_refused;
232 bool accept;
233
234 /* Pairs of type, path */
235 char **listen;
236
237 /* Device */
238 const char *sysfs_path;
239
240 /* Mount, Automount */
241 const char *where;
242
243 /* Swap */
244 const char *what;
245
246 /* CGroup */
247 uint64_t memory_current;
248 uint64_t memory_min;
249 uint64_t memory_low;
250 uint64_t memory_high;
251 uint64_t memory_max;
252 uint64_t memory_swap_max;
d7fe0a67 253 uint64_t memory_zswap_max;
daf71ef6 254 uint64_t memory_limit;
93ff34e4 255 uint64_t memory_available;
daf71ef6
LP
256 uint64_t cpu_usage_nsec;
257 uint64_t tasks_current;
258 uint64_t tasks_max;
259 uint64_t ip_ingress_bytes;
260 uint64_t ip_egress_bytes;
261 uint64_t io_read_bytes;
262 uint64_t io_write_bytes;
263
264 uint64_t default_memory_min;
265 uint64_t default_memory_low;
266
eb506199 267 LIST_HEAD(ExecStatusInfo, exec_status_info_list);
daf71ef6
LP
268} UnitStatusInfo;
269
270static void unit_status_info_free(UnitStatusInfo *info) {
271 ExecStatusInfo *p;
272 UnitCondition *c;
273
274 strv_free(info->documentation);
275 strv_free(info->dropin_paths);
276 strv_free(info->triggered_by);
277 strv_free(info->triggers);
278 strv_free(info->listen);
279
280 while ((c = info->conditions)) {
281 LIST_REMOVE(conditions, info->conditions, c);
282 unit_condition_free(c);
283 }
284
eb506199
ZJS
285 while ((p = info->exec_status_info_list)) {
286 LIST_REMOVE(exec_status_info_list, info->exec_status_info_list, p);
daf71ef6
LP
287 exec_status_info_free(p);
288 }
289}
290
291static void format_active_state(const char *active_state, const char **active_on, const char **active_off) {
292 if (streq_ptr(active_state, "failed")) {
293 *active_on = ansi_highlight_red();
294 *active_off = ansi_normal();
295 } else if (STRPTR_IN_SET(active_state, "active", "reloading")) {
296 *active_on = ansi_highlight_green();
297 *active_off = ansi_normal();
298 } else
299 *active_on = *active_off = "";
300}
301
354ca980 302static void format_enable_state(const char *enable_state, const char **enable_on, const char **enable_off) {
303 assert(enable_on);
304 assert(enable_off);
305
306 if (streq_ptr(enable_state, "disabled")) {
307 *enable_on = ansi_highlight_yellow();
308 *enable_off = ansi_normal();
309 } else if (streq_ptr(enable_state, "enabled")) {
310 *enable_on = ansi_highlight_green();
311 *enable_off = ansi_normal();
312 } else
313 *enable_on = *enable_off = "";
314}
315
daf71ef6
LP
316static void print_status_info(
317 sd_bus *bus,
318 UnitStatusInfo *i,
319 bool *ellipsized) {
320
f843f85d 321 const char *active_on, *active_off, *on, *off, *ss, *fs;
c1e0dc9c 322 const char *enable_on, *enable_off, *preset_on, *preset_off;
daf71ef6 323 _cleanup_free_ char *formatted_path = NULL;
daf71ef6
LP
324 usec_t timestamp;
325 const char *path;
daf71ef6
LP
326 int r;
327
328 assert(i);
329
330 /* This shows pretty information about a unit. See print_property() for a low-level property
331 * printer */
332
333 format_active_state(i->active_state, &active_on, &active_off);
354ca980 334 format_enable_state(i->unit_file_state, &enable_on, &enable_off);
c1e0dc9c 335 format_enable_state(i->unit_file_preset, &preset_on, &preset_off);
daf71ef6 336
9ae5fed6
J
337 const SpecialGlyph glyph = unit_active_state_to_glyph(unit_active_state_from_string(i->active_state));
338
339 printf("%s%s%s %s", active_on, special_glyph(glyph), active_off, strna(i->id));
daf71ef6
LP
340
341 if (i->description && !streq_ptr(i->id, i->description))
342 printf(" - %s", i->description);
343
344 printf("\n");
345
346 if (i->following)
1d406dce 347 printf(" Follows: unit currently follows state of %s\n", i->following);
daf71ef6
LP
348
349 if (STRPTR_IN_SET(i->load_state, "error", "not-found", "bad-setting")) {
350 on = ansi_highlight_red();
351 off = ansi_normal();
352 } else
353 on = off = "";
354
355 path = i->source_path ?: i->fragment_path;
356 if (path && terminal_urlify_path(path, NULL, &formatted_path) >= 0)
357 path = formatted_path;
358
359 if (!isempty(i->load_error))
360 printf(" Loaded: %s%s%s (Reason: %s)\n",
361 on, strna(i->load_state), off, i->load_error);
362 else if (path && !isempty(i->unit_file_state)) {
363 bool show_preset = !isempty(i->unit_file_preset) &&
364 show_preset_for_state(unit_file_state_from_string(i->unit_file_state));
365
354ca980 366 printf(" Loaded: %s%s%s (%s; %s%s%s%s%s%s%s)\n",
daf71ef6
LP
367 on, strna(i->load_state), off,
368 path,
354ca980 369 enable_on, i->unit_file_state, enable_off,
c1e0dc9c
ZJS
370 show_preset ? "; preset: " : "",
371 preset_on, show_preset ? i->unit_file_preset : "", preset_off);
daf71ef6
LP
372
373 } else if (path)
374 printf(" Loaded: %s%s%s (%s)\n",
375 on, strna(i->load_state), off, path);
376 else
377 printf(" Loaded: %s%s%s\n",
378 on, strna(i->load_state), off);
379
380 if (i->transient)
381 printf(" Transient: yes\n");
382
383 if (!strv_isempty(i->dropin_paths)) {
384 _cleanup_free_ char *dir = NULL;
385 bool last = false;
daf71ef6
LP
386
387 STRV_FOREACH(dropin, i->dropin_paths) {
388 _cleanup_free_ char *dropin_formatted = NULL;
389 const char *df;
390
391 if (!dir || last) {
392 printf(dir ? " " :
393 " Drop-In: ");
394
395 dir = mfree(dir);
396
45519d13
LP
397 r = path_extract_directory(*dropin, &dir);
398 if (r < 0) {
399 log_error_errno(r, "Failed to extract directory of '%s': %m", *dropin);
400 break;
daf71ef6
LP
401 }
402
403 printf("%s\n"
404 " %s", dir,
405 special_glyph(SPECIAL_GLYPH_TREE_RIGHT));
406 }
407
408 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
409
410 if (terminal_urlify_path(*dropin, basename(*dropin), &dropin_formatted) >= 0)
411 df = dropin_formatted;
412 else
413 df = *dropin;
414
415 printf("%s%s", df, last ? "\n" : ", ");
416 }
417 }
418
419 ss = streq_ptr(i->active_state, i->sub_state) ? NULL : i->sub_state;
420 if (ss)
421 printf(" Active: %s%s (%s)%s",
422 active_on, strna(i->active_state), ss, active_off);
423 else
424 printf(" Active: %s%s%s",
425 active_on, strna(i->active_state), active_off);
426
427 fs = !isempty(i->freezer_state) && !streq(i->freezer_state, "running") ? i->freezer_state : NULL;
428 if (fs)
429 printf(" %s(%s)%s", ansi_highlight_yellow(), fs, ansi_normal());
430
431 if (!isempty(i->result) && !streq(i->result, "success"))
432 printf(" (Result: %s)", i->result);
433
434 timestamp = STRPTR_IN_SET(i->active_state, "active", "reloading") ? i->active_enter_timestamp :
435 STRPTR_IN_SET(i->active_state, "inactive", "failed") ? i->inactive_enter_timestamp :
436 STRPTR_IN_SET(i->active_state, "activating") ? i->inactive_exit_timestamp :
437 i->active_exit_timestamp;
438
0da36375 439 if (timestamp_is_set(timestamp)) {
f843f85d
YW
440 printf(" since %s; %s\n",
441 FORMAT_TIMESTAMP_STYLE(timestamp, arg_timestamp_style),
442 FORMAT_TIMESTAMP_RELATIVE(timestamp));
a41699c9
AO
443 if (streq_ptr(i->active_state, "active") && i->runtime_max_sec < USEC_INFINITY) {
444 usec_t until_timestamp;
445
446 until_timestamp = usec_add(timestamp, i->runtime_max_sec);
447 printf(" Until: %s; %s\n",
448 FORMAT_TIMESTAMP_STYLE(until_timestamp, arg_timestamp_style),
449 FORMAT_TIMESTAMP_RELATIVE(until_timestamp));
450 }
0802f62e
DDM
451
452 if (!endswith(i->id, ".target") &&
453 STRPTR_IN_SET(i->active_state, "inactive", "failed") &&
454 timestamp_is_set(i->active_enter_timestamp) &&
455 timestamp_is_set(i->active_exit_timestamp) &&
456 i->active_exit_timestamp >= i->active_enter_timestamp) {
457
458 usec_t duration;
459
460 duration = i->active_exit_timestamp - i->active_enter_timestamp;
461 printf(" Duration: %s\n", FORMAT_TIMESPAN(duration, MSEC_PER_SEC));
462 }
a41699c9 463 } else
daf71ef6
LP
464 printf("\n");
465
466 STRV_FOREACH(t, i->triggered_by) {
467 UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
468
469 (void) get_state_one_unit(bus, *t, &state);
470 format_active_state(unit_active_state_to_string(state), &on, &off);
471
472 printf("%s %s%s%s %s\n",
473 t == i->triggered_by ? "TriggeredBy:" : " ",
9ae5fed6 474 on, special_glyph(unit_active_state_to_glyph(state)), off,
daf71ef6
LP
475 *t);
476 }
477
478 if (endswith(i->id, ".timer")) {
0086ef19 479 dual_timestamp nw, next = {i->next_elapse_real, i->next_elapse_monotonic};
daf71ef6
LP
480 usec_t next_elapse;
481
daf71ef6
LP
482 dual_timestamp_get(&nw);
483 next_elapse = calc_next_elapse(&nw, &next);
daf71ef6 484
0da36375 485 if (timestamp_is_set(next_elapse))
f843f85d
YW
486 printf(" Trigger: %s; %s\n",
487 FORMAT_TIMESTAMP_STYLE(next_elapse, arg_timestamp_style),
488 FORMAT_TIMESTAMP_RELATIVE(next_elapse));
489 else
490 printf(" Trigger: n/a\n");
daf71ef6
LP
491 }
492
493 STRV_FOREACH(t, i->triggers) {
494 UnitActiveState state = _UNIT_ACTIVE_STATE_INVALID;
495
496 (void) get_state_one_unit(bus, *t, &state);
497 format_active_state(unit_active_state_to_string(state), &on, &off);
498
499 printf("%s %s%s%s %s\n",
500 t == i->triggers ? " Triggers:" : " ",
501 on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off,
502 *t);
503 }
504
505 if (!i->condition_result && i->condition_timestamp > 0) {
daf71ef6
LP
506 int n = 0;
507
f843f85d 508 printf(" Condition: start %scondition failed%s at %s; %s\n",
daf71ef6 509 ansi_highlight_yellow(), ansi_normal(),
0086ef19 510 FORMAT_TIMESTAMP_STYLE(i->condition_timestamp, arg_timestamp_style),
f843f85d 511 FORMAT_TIMESTAMP_RELATIVE(i->condition_timestamp));
daf71ef6
LP
512
513 LIST_FOREACH(conditions, c, i->conditions)
514 if (c->tristate < 0)
515 n++;
516
517 LIST_FOREACH(conditions, c, i->conditions)
518 if (c->tristate < 0)
519 printf(" %s %s=%s%s%s was not met\n",
520 --n ? special_glyph(SPECIAL_GLYPH_TREE_BRANCH) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT),
521 c->name,
522 c->trigger ? "|" : "",
523 c->negate ? "!" : "",
524 c->param);
525 }
526
527 if (!i->assert_result && i->assert_timestamp > 0) {
f843f85d 528 printf(" Assert: start %sassertion failed%s at %s; %s\n",
daf71ef6 529 ansi_highlight_red(), ansi_normal(),
0086ef19 530 FORMAT_TIMESTAMP_STYLE(i->assert_timestamp, arg_timestamp_style),
f843f85d 531 FORMAT_TIMESTAMP_RELATIVE(i->assert_timestamp));
daf71ef6
LP
532 if (i->failed_assert_trigger)
533 printf(" none of the trigger assertions were met\n");
534 else if (i->failed_assert)
535 printf(" %s=%s%s was not met\n",
536 i->failed_assert,
537 i->failed_assert_negate ? "!" : "",
538 i->failed_assert_parameter);
539 }
540
541 if (i->sysfs_path)
542 printf(" Device: %s\n", i->sysfs_path);
543 if (i->where)
544 printf(" Where: %s\n", i->where);
545 if (i->what)
546 printf(" What: %s\n", i->what);
547
548 STRV_FOREACH(t, i->documentation) {
549 _cleanup_free_ char *formatted = NULL;
550 const char *q;
551
552 if (terminal_urlify(*t, NULL, &formatted) >= 0)
553 q = formatted;
554 else
555 q = *t;
556
557 printf(" %*s %s\n", 9, t == i->documentation ? "Docs:" : "", q);
558 }
559
560 STRV_FOREACH_PAIR(t, t2, i->listen)
561 printf(" %*s %s (%s)\n", 9, t == i->listen ? "Listen:" : "", *t2, *t);
562
563 if (i->accept) {
564 printf(" Accepted: %u; Connected: %u;", i->n_accepted, i->n_connections);
565 if (i->n_refused)
566 printf(" Refused: %u", i->n_refused);
567 printf("\n");
568 }
569
eb506199 570 LIST_FOREACH(exec_status_info_list, p, i->exec_status_info_list) {
daf71ef6
LP
571 _cleanup_free_ char *argv = NULL;
572 bool good;
573
574 /* Only show exited processes here */
575 if (p->code == 0)
576 continue;
577
578 /* Don't print ExecXYZEx= properties here since it will appear as a
579 * duplicate of the non-Ex= variant. */
580 if (endswith(p->name, "Ex"))
581 continue;
582
583 argv = strv_join(p->argv, " ");
584 printf(" Process: "PID_FMT" %s=%s ", p->pid, p->name, strna(argv));
585
586 good = is_clean_exit(p->code, p->status, EXIT_CLEAN_DAEMON, NULL);
587 if (!good) {
e879434d 588 on = p->ignore ? ansi_highlight_yellow() : ansi_highlight_red();
daf71ef6
LP
589 off = ansi_normal();
590 } else
591 on = off = "";
592
593 printf("%s(code=%s, ", on, sigchld_code_to_string(p->code));
594
595 if (p->code == CLD_EXITED) {
596 const char *c;
597
598 printf("status=%i", p->status);
599
600 c = exit_status_to_string(p->status, EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
601 if (c)
602 printf("/%s", c);
603
604 } else
605 printf("signal=%s", signal_to_string(p->status));
606
607 printf(")%s\n", off);
608
609 if (i->main_pid == p->pid &&
610 i->start_timestamp == p->start_timestamp &&
611 i->exit_timestamp == p->start_timestamp)
612 /* Let's not show this twice */
613 i->main_pid = 0;
614
615 if (p->pid == i->control_pid)
616 i->control_pid = 0;
617 }
618
619 if (i->main_pid > 0 || i->control_pid > 0) {
620 if (i->main_pid > 0) {
621 printf(" Main PID: "PID_FMT, i->main_pid);
622
623 if (i->running) {
624
625 if (arg_transport == BUS_TRANSPORT_LOCAL) {
626 _cleanup_free_ char *comm = NULL;
627
628 (void) get_process_comm(i->main_pid, &comm);
629 if (comm)
630 printf(" (%s)", comm);
631 }
632
633 } else if (i->exit_code > 0) {
634 printf(" (code=%s, ", sigchld_code_to_string(i->exit_code));
635
636 if (i->exit_code == CLD_EXITED) {
637 const char *c;
638
639 printf("status=%i", i->exit_status);
640
641 c = exit_status_to_string(i->exit_status,
642 EXIT_STATUS_LIBC | EXIT_STATUS_SYSTEMD);
643 if (c)
644 printf("/%s", c);
645
646 } else
647 printf("signal=%s", signal_to_string(i->exit_status));
648 printf(")");
649 }
650 }
651
652 if (i->control_pid > 0) {
653 _cleanup_free_ char *c = NULL;
654
655 if (i->main_pid > 0)
656 fputs("; Control PID: ", stdout);
657 else
658 fputs("Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
659
660 printf(PID_FMT, i->control_pid);
661
662 if (arg_transport == BUS_TRANSPORT_LOCAL) {
663 (void) get_process_comm(i->control_pid, &c);
664 if (c)
665 printf(" (%s)", c);
666 }
667 }
668
669 printf("\n");
670 }
671
672 if (i->status_text)
673 printf(" Status: \"%s\"\n", i->status_text);
38553034
ZJS
674 if (i->status_errno > 0) {
675 errno = i->status_errno;
676 printf(" Error: %i (%m)\n", i->status_errno);
677 }
daf71ef6 678
2b59bf51 679 if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX)
daf71ef6 680 printf(" IP: %s in, %s out\n",
2b59bf51
ZJS
681 FORMAT_BYTES(i->ip_ingress_bytes),
682 FORMAT_BYTES(i->ip_egress_bytes));
daf71ef6 683
2b59bf51 684 if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX)
daf71ef6 685 printf(" IO: %s read, %s written\n",
2b59bf51
ZJS
686 FORMAT_BYTES(i->io_read_bytes),
687 FORMAT_BYTES(i->io_write_bytes));
daf71ef6 688
f5fbe71d 689 if (i->tasks_current != UINT64_MAX) {
daf71ef6
LP
690 printf(" Tasks: %" PRIu64, i->tasks_current);
691
f5fbe71d 692 if (i->tasks_max != UINT64_MAX)
daf71ef6
LP
693 printf(" (limit: %" PRIu64 ")\n", i->tasks_max);
694 else
695 printf("\n");
696 }
697
f5fbe71d 698 if (i->memory_current != UINT64_MAX) {
2b59bf51 699 printf(" Memory: %s", FORMAT_BYTES(i->memory_current));
daf71ef6
LP
700
701 if (i->memory_min > 0 || i->memory_low > 0 ||
702 i->memory_high != CGROUP_LIMIT_MAX || i->memory_max != CGROUP_LIMIT_MAX ||
703 i->memory_swap_max != CGROUP_LIMIT_MAX ||
d7fe0a67 704 i->memory_zswap_max != CGROUP_LIMIT_MAX ||
93ff34e4 705 i->memory_available != CGROUP_LIMIT_MAX ||
daf71ef6
LP
706 i->memory_limit != CGROUP_LIMIT_MAX) {
707 const char *prefix = "";
708
709 printf(" (");
710 if (i->memory_min > 0) {
9ca7e3d0 711 printf("%smin: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_min));
daf71ef6
LP
712 prefix = " ";
713 }
714 if (i->memory_low > 0) {
9ca7e3d0 715 printf("%slow: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_low));
daf71ef6
LP
716 prefix = " ";
717 }
718 if (i->memory_high != CGROUP_LIMIT_MAX) {
2b59bf51 719 printf("%shigh: %s", prefix, FORMAT_BYTES(i->memory_high));
daf71ef6
LP
720 prefix = " ";
721 }
722 if (i->memory_max != CGROUP_LIMIT_MAX) {
2b59bf51 723 printf("%smax: %s", prefix, FORMAT_BYTES(i->memory_max));
daf71ef6
LP
724 prefix = " ";
725 }
726 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
2b59bf51 727 printf("%sswap max: %s", prefix, FORMAT_BYTES(i->memory_swap_max));
daf71ef6
LP
728 prefix = " ";
729 }
d7fe0a67
PV
730 if (i->memory_zswap_max != CGROUP_LIMIT_MAX) {
731 printf("%szswap max: %s", prefix, FORMAT_BYTES(i->memory_zswap_max));
732 prefix = " ";
733 }
daf71ef6 734 if (i->memory_limit != CGROUP_LIMIT_MAX) {
2b59bf51 735 printf("%slimit: %s", prefix, FORMAT_BYTES(i->memory_limit));
daf71ef6
LP
736 prefix = " ";
737 }
93ff34e4 738 if (i->memory_available != CGROUP_LIMIT_MAX) {
2b59bf51 739 printf("%savailable: %s", prefix, FORMAT_BYTES(i->memory_available));
93ff34e4
LB
740 prefix = " ";
741 }
daf71ef6
LP
742 printf(")");
743 }
744 printf("\n");
745 }
746
5291f26d
ZJS
747 if (i->cpu_usage_nsec != UINT64_MAX)
748 printf(" CPU: %s\n", FORMAT_TIMESPAN(i->cpu_usage_nsec / NSEC_PER_USEC, USEC_PER_MSEC));
daf71ef6
LP
749
750 if (i->control_group) {
751 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
752 static const char prefix[] = " ";
753 unsigned c;
754
755 printf(" CGroup: %s\n", i->control_group);
756
a0dde733 757 c = LESS_BY(columns(), strlen(prefix));
daf71ef6
LP
758
759 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
35ac0260 760 if (r == -EBADR && arg_transport == BUS_TRANSPORT_LOCAL) {
daf71ef6
LP
761 unsigned k = 0;
762 pid_t extra[2];
763
764 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
765
766 if (i->main_pid > 0)
767 extra[k++] = i->main_pid;
768
769 if (i->control_pid > 0)
770 extra[k++] = i->control_pid;
771
772 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER, i->control_group, prefix, c, extra, k, get_output_flags());
773 } else if (r < 0)
774 log_warning_errno(r, "Failed to dump process list for '%s', ignoring: %s",
775 i->id, bus_error_message(&error, r));
776 }
777
778 if (i->id && arg_transport == BUS_TRANSPORT_LOCAL)
779 show_journal_by_unit(
780 stdout,
781 i->id,
782 i->log_namespace,
783 arg_output,
784 0,
785 i->inactive_exit_timestamp_monotonic,
786 arg_lines,
787 getuid(),
788 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
789 SD_JOURNAL_LOCAL_ONLY,
b380b643 790 arg_scope == LOOKUP_SCOPE_SYSTEM,
daf71ef6
LP
791 ellipsized);
792
793 if (i->need_daemon_reload)
794 warn_unit_file_changed(i->id);
795}
796
797static void show_unit_help(UnitStatusInfo *i) {
daf71ef6
LP
798 assert(i);
799
800 if (!i->documentation) {
801 log_info("Documentation for %s not known.", i->id);
802 return;
803 }
804
805 STRV_FOREACH(p, i->documentation)
806 if (startswith(*p, "man:"))
807 show_man_page(*p + 4, false);
808 else
809 log_info("Can't show: %s", *p);
810}
811
812static int map_main_pid(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
813 UnitStatusInfo *i = userdata;
814 uint32_t u;
815 int r;
816
817 r = sd_bus_message_read(m, "u", &u);
818 if (r < 0)
819 return r;
820
821 i->main_pid = (pid_t) u;
822 i->running = u > 0;
823
824 return 0;
825}
826
827static int map_load_error(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
828 const char *message, **p = userdata;
829 int r;
830
831 r = sd_bus_message_read(m, "(ss)", NULL, &message);
832 if (r < 0)
833 return r;
834
835 if (!isempty(message))
836 *p = message;
837
838 return 0;
839}
840
841static int map_listen(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
842 const char *type, *path;
843 char ***p = userdata;
844 int r;
845
846 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
847 if (r < 0)
848 return r;
849
850 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0) {
851
852 r = strv_extend(p, type);
853 if (r < 0)
854 return r;
855
856 r = strv_extend(p, path);
857 if (r < 0)
858 return r;
859 }
860 if (r < 0)
861 return r;
862
863 r = sd_bus_message_exit_container(m);
864 if (r < 0)
865 return r;
866
867 return 0;
868}
869
870static int map_conditions(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
871 UnitStatusInfo *i = userdata;
872 const char *cond, *param;
873 int trigger, negate;
874 int32_t state;
875 int r;
876
877 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
878 if (r < 0)
879 return r;
880
881 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
882 _cleanup_(unit_condition_freep) UnitCondition *c = NULL;
883
884 c = new(UnitCondition, 1);
885 if (!c)
886 return -ENOMEM;
887
888 *c = (UnitCondition) {
889 .name = strdup(cond),
890 .param = strdup(param),
891 .trigger = trigger,
892 .negate = negate,
893 .tristate = state,
894 };
895
896 if (!c->name || !c->param)
897 return -ENOMEM;
898
899 LIST_PREPEND(conditions, i->conditions, TAKE_PTR(c));
900 }
901 if (r < 0)
902 return r;
903
904 r = sd_bus_message_exit_container(m);
905 if (r < 0)
906 return r;
907
908 return 0;
909}
910
911static int map_asserts(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
912 UnitStatusInfo *i = userdata;
913 const char *cond, *param;
914 int trigger, negate;
915 int32_t state;
916 int r;
917
918 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sbbsi)");
919 if (r < 0)
920 return r;
921
922 while ((r = sd_bus_message_read(m, "(sbbsi)", &cond, &trigger, &negate, &param, &state)) > 0) {
923 if (state < 0 && (!trigger || !i->failed_assert)) {
924 i->failed_assert = cond;
925 i->failed_assert_trigger = trigger;
926 i->failed_assert_negate = negate;
927 i->failed_assert_parameter = param;
928 }
929 }
930 if (r < 0)
931 return r;
932
933 r = sd_bus_message_exit_container(m);
934 if (r < 0)
935 return r;
936
937 return 0;
938}
939
940static int map_exec(sd_bus *bus, const char *member, sd_bus_message *m, sd_bus_error *error, void *userdata) {
941 _cleanup_free_ ExecStatusInfo *info = NULL;
942 ExecStatusInfo *last;
943 UnitStatusInfo *i = userdata;
944 bool is_ex_prop = endswith(member, "Ex");
945 int r;
946
947 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
948 if (r < 0)
949 return r;
950
951 info = new0(ExecStatusInfo, 1);
952 if (!info)
953 return -ENOMEM;
954
eb506199 955 LIST_FIND_TAIL(exec_status_info_list, i->exec_status_info_list, last);
daf71ef6
LP
956
957 while ((r = exec_status_info_deserialize(m, info, is_ex_prop)) > 0) {
958
959 info->name = strdup(member);
960 if (!info->name)
961 return -ENOMEM;
962
eb506199 963 LIST_INSERT_AFTER(exec_status_info_list, i->exec_status_info_list, last, info);
daf71ef6
LP
964 last = info;
965
966 info = new0(ExecStatusInfo, 1);
967 if (!info)
968 return -ENOMEM;
969 }
970 if (r < 0)
971 return r;
972
973 r = sd_bus_message_exit_container(m);
974 if (r < 0)
975 return r;
976
977 return 0;
978}
979
255b1fc8 980static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) {
daf71ef6
LP
981 char bus_type;
982 const char *contents;
983 int r;
984
985 assert(name);
986 assert(m);
987
988 /* This is a low-level property printer, see print_status_info() for the nicer output */
989
990 r = sd_bus_message_peek_type(m, &bus_type, &contents);
991 if (r < 0)
992 return r;
993
994 switch (bus_type) {
995
996 case SD_BUS_TYPE_INT32:
997 if (endswith(name, "ActionExitStatus")) {
998 int32_t i;
999
1000 r = sd_bus_message_read_basic(m, bus_type, &i);
1001 if (r < 0)
1002 return r;
1003
1004 if (i >= 0 && i <= 255)
255b1fc8
YW
1005 bus_print_property_valuef(name, expected_value, flags, "%"PRIi32, i);
1006 else if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY))
1007 bus_print_property_value(name, expected_value, flags, "[not set]");
daf71ef6
LP
1008
1009 return 1;
1010 } else if (streq(name, "NUMAPolicy")) {
1011 int32_t i;
1012
1013 r = sd_bus_message_read_basic(m, bus_type, &i);
1014 if (r < 0)
1015 return r;
1016
255b1fc8 1017 bus_print_property_valuef(name, expected_value, flags, "%s", strna(mpol_to_string(i)));
daf71ef6
LP
1018
1019 return 1;
1020 }
1021 break;
1022
a59e5c62
FS
1023 case SD_BUS_TYPE_UINT64:
1024 if (endswith(name, "Timestamp")) {
1025 uint64_t timestamp;
1026
1027 r = sd_bus_message_read_basic(m, bus_type, &timestamp);
1028 if (r < 0)
1029 return r;
1030
1031 bus_print_property_value(name, expected_value, flags, FORMAT_TIMESTAMP_STYLE(timestamp, arg_timestamp_style));
1032
1033 return 1;
1034 }
1035 break;
1036
daf71ef6
LP
1037 case SD_BUS_TYPE_STRUCT:
1038
1039 if (contents[0] == SD_BUS_TYPE_UINT32 && streq(name, "Job")) {
1040 uint32_t u;
1041
1042 r = sd_bus_message_read(m, "(uo)", &u, NULL);
1043 if (r < 0)
1044 return bus_log_parse_error(r);
1045
1046 if (u > 0)
255b1fc8
YW
1047 bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u);
1048 else
1049 bus_print_property_value(name, expected_value, flags, NULL);
daf71ef6
LP
1050
1051 return 1;
1052
1053 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "Unit")) {
1054 const char *s;
1055
1056 r = sd_bus_message_read(m, "(so)", &s, NULL);
1057 if (r < 0)
1058 return bus_log_parse_error(r);
1059
255b1fc8 1060 bus_print_property_value(name, expected_value, flags, s);
daf71ef6
LP
1061
1062 return 1;
1063
1064 } else if (contents[0] == SD_BUS_TYPE_STRING && streq(name, "LoadError")) {
1065 const char *a = NULL, *b = NULL;
1066
1067 r = sd_bus_message_read(m, "(ss)", &a, &b);
1068 if (r < 0)
1069 return bus_log_parse_error(r);
1070
1071 if (!isempty(a) || !isempty(b))
255b1fc8
YW
1072 bus_print_property_valuef(name, expected_value, flags, "%s \"%s\"", strempty(a), strempty(b));
1073 else
1074 bus_print_property_value(name, expected_value, flags, NULL);
daf71ef6
LP
1075
1076 return 1;
1077
e59ccd03 1078 } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces", "RestrictFileSystems")) {
daf71ef6
LP
1079 _cleanup_strv_free_ char **l = NULL;
1080 int allow_list;
1081
1082 r = sd_bus_message_enter_container(m, 'r', "bas");
1083 if (r < 0)
1084 return bus_log_parse_error(r);
1085
1086 r = sd_bus_message_read(m, "b", &allow_list);
1087 if (r < 0)
1088 return bus_log_parse_error(r);
1089
1090 r = sd_bus_message_read_strv(m, &l);
1091 if (r < 0)
1092 return bus_log_parse_error(r);
1093
1094 r = sd_bus_message_exit_container(m);
1095 if (r < 0)
1096 return bus_log_parse_error(r);
1097
255b1fc8 1098 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || allow_list || !strv_isempty(l)) {
daf71ef6 1099 bool first = true;
daf71ef6 1100
255b1fc8 1101 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
daf71ef6
LP
1102 fputs(name, stdout);
1103 fputc('=', stdout);
1104 }
1105
1106 if (!allow_list)
1107 fputc('~', stdout);
1108
1109 STRV_FOREACH(i, l) {
1110 if (first)
1111 first = false;
1112 else
1113 fputc(' ', stdout);
1114
1115 fputs(*i, stdout);
1116 }
1117 fputc('\n', stdout);
1118 }
1119
1120 return 1;
1121
1122 } else if (STR_IN_SET(name, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
1123 int ignore;
1124 const char *s;
1125
1126 r = sd_bus_message_read(m, "(bs)", &ignore, &s);
1127 if (r < 0)
1128 return bus_log_parse_error(r);
1129
1130 if (!isempty(s))
255b1fc8
YW
1131 bus_print_property_valuef(name, expected_value, flags, "%s%s", ignore ? "-" : "", s);
1132 else
1133 bus_print_property_value(name, expected_value, flags, NULL);
daf71ef6
LP
1134
1135 return 1;
1136
1137 } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
1138 const int32_t *status, *signal;
deaf4b86 1139 size_t n_status, n_signal;
daf71ef6
LP
1140
1141 r = sd_bus_message_enter_container(m, 'r', "aiai");
1142 if (r < 0)
1143 return bus_log_parse_error(r);
1144
1145 r = sd_bus_message_read_array(m, 'i', (const void **) &status, &n_status);
1146 if (r < 0)
1147 return bus_log_parse_error(r);
1148
1149 r = sd_bus_message_read_array(m, 'i', (const void **) &signal, &n_signal);
1150 if (r < 0)
1151 return bus_log_parse_error(r);
1152
1153 r = sd_bus_message_exit_container(m);
1154 if (r < 0)
1155 return bus_log_parse_error(r);
1156
1157 n_status /= sizeof(int32_t);
1158 n_signal /= sizeof(int32_t);
1159
255b1fc8 1160 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || n_status > 0 || n_signal > 0) {
daf71ef6
LP
1161 bool first = true;
1162
255b1fc8 1163 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
daf71ef6
LP
1164 fputs(name, stdout);
1165 fputc('=', stdout);
1166 }
1167
deaf4b86 1168 for (size_t i = 0; i < n_status; i++) {
daf71ef6
LP
1169 if (first)
1170 first = false;
1171 else
1172 fputc(' ', stdout);
1173
1174 printf("%"PRIi32, status[i]);
1175 }
1176
deaf4b86 1177 for (size_t i = 0; i < n_signal; i++) {
daf71ef6
LP
1178 const char *str;
1179
1180 str = signal_to_string((int) signal[i]);
1181
1182 if (first)
1183 first = false;
1184 else
1185 fputc(' ', stdout);
1186
1187 if (str)
1188 fputs(str, stdout);
1189 else
1190 printf("%"PRIi32, status[i]);
1191 }
1192
1193 fputc('\n', stdout);
1194 }
1195 return 1;
1196 }
1197
1198 break;
1199
1200 case SD_BUS_TYPE_ARRAY:
1201
1202 if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "EnvironmentFiles")) {
1203 const char *path;
1204 int ignore;
1205
1206 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sb)");
1207 if (r < 0)
1208 return bus_log_parse_error(r);
1209
1210 while ((r = sd_bus_message_read(m, "(sb)", &path, &ignore)) > 0)
255b1fc8 1211 bus_print_property_valuef(name, expected_value, flags, "%s (ignore_errors=%s)", path, yes_no(ignore));
daf71ef6
LP
1212 if (r < 0)
1213 return bus_log_parse_error(r);
1214
1215 r = sd_bus_message_exit_container(m);
1216 if (r < 0)
1217 return bus_log_parse_error(r);
1218
1219 return 1;
1220
1221 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Paths")) {
1222 const char *type, *path;
1223
1224 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1225 if (r < 0)
1226 return bus_log_parse_error(r);
1227
1228 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
255b1fc8 1229 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
daf71ef6
LP
1230 if (r < 0)
1231 return bus_log_parse_error(r);
1232
1233 r = sd_bus_message_exit_container(m);
1234 if (r < 0)
1235 return bus_log_parse_error(r);
1236
1237 return 1;
1238
1239 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "Listen")) {
1240 const char *type, *path;
1241
1242 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1243 if (r < 0)
1244 return bus_log_parse_error(r);
1245
1246 while ((r = sd_bus_message_read(m, "(ss)", &type, &path)) > 0)
255b1fc8 1247 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
daf71ef6
LP
1248 if (r < 0)
1249 return bus_log_parse_error(r);
1250
1251 r = sd_bus_message_exit_container(m);
1252 if (r < 0)
1253 return bus_log_parse_error(r);
1254
1255 return 1;
1256
1257 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersMonotonic")) {
1258 const char *base;
1259 uint64_t v, next_elapse;
1260
1261 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(stt)");
1262 if (r < 0)
1263 return bus_log_parse_error(r);
1264
5291f26d 1265 while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0)
255b1fc8 1266 bus_print_property_valuef(name, expected_value, flags,
5291f26d
ZJS
1267 "{ %s=%s ; next_elapse=%s }",
1268 base,
1269 strna(FORMAT_TIMESPAN(v, 0)),
1270 strna(FORMAT_TIMESPAN(next_elapse, 0)));
daf71ef6
LP
1271 if (r < 0)
1272 return bus_log_parse_error(r);
1273
1274 r = sd_bus_message_exit_container(m);
1275 if (r < 0)
1276 return bus_log_parse_error(r);
1277
1278 return 1;
1279
1280 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "TimersCalendar")) {
1281 const char *base, *spec;
1282 uint64_t next_elapse;
1283
1284 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
1285 if (r < 0)
1286 return bus_log_parse_error(r);
1287
0086ef19 1288 while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0)
255b1fc8 1289 bus_print_property_valuef(name, expected_value, flags,
0086ef19
ZJS
1290 "{ %s=%s ; next_elapse=%s }", base, spec,
1291 FORMAT_TIMESTAMP_STYLE(next_elapse, arg_timestamp_style));
daf71ef6
LP
1292 if (r < 0)
1293 return bus_log_parse_error(r);
1294
1295 r = sd_bus_message_exit_container(m);
1296 if (r < 0)
1297 return bus_log_parse_error(r);
1298
1299 return 1;
1300
1301 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && startswith(name, "Exec")) {
1302 ExecStatusInfo info = {};
1303 bool is_ex_prop = endswith(name, "Ex");
1304
1305 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, is_ex_prop ? "(sasasttttuii)" : "(sasbttttuii)");
1306 if (r < 0)
1307 return bus_log_parse_error(r);
1308
1309 while ((r = exec_status_info_deserialize(m, &info, is_ex_prop)) > 0) {
daf71ef6 1310 _cleanup_strv_free_ char **optv = NULL;
c2b2df60 1311 _cleanup_free_ char *tt = NULL, *o = NULL;
daf71ef6
LP
1312
1313 tt = strv_join(info.argv, " ");
1314
1315 if (is_ex_prop) {
1316 r = exec_command_flags_to_strv(info.flags, &optv);
1317 if (r < 0)
1318 return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
1319
1320 o = strv_join(optv, " ");
1321
255b1fc8 1322 bus_print_property_valuef(name, expected_value, flags,
daf71ef6
LP
1323 "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
1324 strna(info.path),
1325 strna(tt),
1326 strna(o),
0086ef19
ZJS
1327 strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
1328 strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
daf71ef6
LP
1329 info.pid,
1330 sigchld_code_to_string(info.code),
1331 info.status,
1332 info.code == CLD_EXITED ? "" : "/",
1333 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1334 } else
255b1fc8 1335 bus_print_property_valuef(name, expected_value, flags,
daf71ef6
LP
1336 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT" ; code=%s ; status=%i%s%s }",
1337 strna(info.path),
1338 strna(tt),
1339 yes_no(info.ignore),
0086ef19
ZJS
1340 strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
1341 strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
daf71ef6
LP
1342 info.pid,
1343 sigchld_code_to_string(info.code),
1344 info.status,
1345 info.code == CLD_EXITED ? "" : "/",
1346 strempty(info.code == CLD_EXITED ? NULL : signal_to_string(info.status)));
1347
1348 free(info.path);
1349 strv_free(info.argv);
1350 zero(info);
1351 }
1352
1353 r = sd_bus_message_exit_container(m);
1354 if (r < 0)
1355 return bus_log_parse_error(r);
1356
1357 return 1;
1358
1359 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "DeviceAllow")) {
1360 const char *path, *rwm;
1361
1362 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1363 if (r < 0)
1364 return bus_log_parse_error(r);
1365
1366 while ((r = sd_bus_message_read(m, "(ss)", &path, &rwm)) > 0)
255b1fc8 1367 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path), strna(rwm));
daf71ef6
LP
1368 if (r < 0)
1369 return bus_log_parse_error(r);
1370
1371 r = sd_bus_message_exit_container(m);
1372 if (r < 0)
1373 return bus_log_parse_error(r);
1374
1375 return 1;
1376
1377 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1378 STR_IN_SET(name, "IODeviceWeight", "BlockIODeviceWeight")) {
1379 const char *path;
1380 uint64_t weight;
1381
1382 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1383 if (r < 0)
1384 return bus_log_parse_error(r);
1385
1386 while ((r = sd_bus_message_read(m, "(st)", &path, &weight)) > 0)
255b1fc8 1387 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), weight);
daf71ef6
LP
1388 if (r < 0)
1389 return bus_log_parse_error(r);
1390
1391 r = sd_bus_message_exit_container(m);
1392 if (r < 0)
1393 return bus_log_parse_error(r);
1394
1395 return 1;
1396
1397 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1398 (cgroup_io_limit_type_from_string(name) >= 0 ||
1399 STR_IN_SET(name, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
1400 const char *path;
1401 uint64_t bandwidth;
1402
1403 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1404 if (r < 0)
1405 return bus_log_parse_error(r);
1406
1407 while ((r = sd_bus_message_read(m, "(st)", &path, &bandwidth)) > 0)
255b1fc8 1408 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), bandwidth);
daf71ef6
LP
1409 if (r < 0)
1410 return bus_log_parse_error(r);
1411
1412 r = sd_bus_message_exit_container(m);
1413 if (r < 0)
1414 return bus_log_parse_error(r);
1415
1416 return 1;
1417
1418 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN &&
1419 streq(name, "IODeviceLatencyTargetUSec")) {
daf71ef6
LP
1420 const char *path;
1421 uint64_t target;
1422
1423 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(st)");
1424 if (r < 0)
1425 return bus_log_parse_error(r);
1426
1427 while ((r = sd_bus_message_read(m, "(st)", &path, &target)) > 0)
255b1fc8 1428 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path),
5291f26d 1429 FORMAT_TIMESPAN(target, 1));
daf71ef6
LP
1430 if (r < 0)
1431 return bus_log_parse_error(r);
1432
1433 r = sd_bus_message_exit_container(m);
1434 if (r < 0)
1435 return bus_log_parse_error(r);
1436
1437 return 1;
1438
1439 } else if (contents[0] == SD_BUS_TYPE_BYTE && STR_IN_SET(name, "StandardInputData", "RootHashSignature")) {
1440 _cleanup_free_ char *h = NULL;
1441 const void *p;
1442 size_t sz;
1443 ssize_t n;
1444
1445 r = sd_bus_message_read_array(m, 'y', &p, &sz);
1446 if (r < 0)
1447 return bus_log_parse_error(r);
1448
1449 n = base64mem(p, sz, &h);
1450 if (n < 0)
1451 return log_oom();
1452
255b1fc8 1453 bus_print_property_value(name, expected_value, flags, h);
daf71ef6
LP
1454
1455 return 1;
1456
1457 } else if (STR_IN_SET(name, "IPAddressAllow", "IPAddressDeny")) {
1458 _cleanup_free_ char *addresses = NULL;
1459
1460 r = sd_bus_message_enter_container(m, 'a', "(iayu)");
1461 if (r < 0)
1462 return bus_log_parse_error(r);
1463
1464 for (;;) {
daf71ef6
LP
1465 uint32_t prefixlen;
1466 int32_t family;
1467 const void *ap;
1468 size_t an;
1469
1470 r = sd_bus_message_enter_container(m, 'r', "iayu");
1471 if (r < 0)
1472 return bus_log_parse_error(r);
1473 if (r == 0)
1474 break;
1475
1476 r = sd_bus_message_read(m, "i", &family);
1477 if (r < 0)
1478 return bus_log_parse_error(r);
1479
1480 r = sd_bus_message_read_array(m, 'y', &ap, &an);
1481 if (r < 0)
1482 return bus_log_parse_error(r);
1483
1484 r = sd_bus_message_read(m, "u", &prefixlen);
1485 if (r < 0)
1486 return bus_log_parse_error(r);
1487
1488 r = sd_bus_message_exit_container(m);
1489 if (r < 0)
1490 return bus_log_parse_error(r);
1491
1492 if (!IN_SET(family, AF_INET, AF_INET6))
1493 continue;
1494
1495 if (an != FAMILY_ADDRESS_SIZE(family))
1496 continue;
1497
1498 if (prefixlen > FAMILY_ADDRESS_SIZE(family) * 8)
1499 continue;
1500
c71384a9
ZJS
1501 if (!strextend_with_separator(&addresses, " ",
1502 IN_ADDR_PREFIX_TO_STRING(family, ap, prefixlen)))
daf71ef6
LP
1503 return log_oom();
1504 }
1505
1506 r = sd_bus_message_exit_container(m);
1507 if (r < 0)
1508 return bus_log_parse_error(r);
1509
255b1fc8 1510 bus_print_property_value(name, expected_value, flags, addresses);
daf71ef6
LP
1511
1512 return 1;
1513
1514 } else if (STR_IN_SET(name, "BindPaths", "BindReadOnlyPaths")) {
1515 _cleanup_free_ char *paths = NULL;
1516 const char *source, *dest;
1517 int ignore_enoent;
1518 uint64_t rbind;
1519
1520 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssbt)");
1521 if (r < 0)
1522 return bus_log_parse_error(r);
1523
1524 while ((r = sd_bus_message_read(m, "(ssbt)", &source, &dest, &ignore_enoent, &rbind)) > 0) {
1525 _cleanup_free_ char *str = NULL;
1526
1527 if (isempty(source))
1528 continue;
1529
1530 if (asprintf(&str, "%s%s%s%s%s",
1531 ignore_enoent ? "-" : "",
1532 source,
1533 isempty(dest) ? "" : ":",
1534 strempty(dest),
1535 rbind == MS_REC ? ":rbind" : "") < 0)
1536 return log_oom();
1537
c2bc710b 1538 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
1539 return log_oom();
1540 }
1541 if (r < 0)
1542 return bus_log_parse_error(r);
1543
1544 r = sd_bus_message_exit_container(m);
1545 if (r < 0)
1546 return bus_log_parse_error(r);
1547
255b1fc8 1548 bus_print_property_value(name, expected_value, flags, paths);
daf71ef6
LP
1549
1550 return 1;
1551
1552 } else if (streq(name, "TemporaryFileSystem")) {
1553 _cleanup_free_ char *paths = NULL;
1554 const char *target, *option;
1555
1556 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1557 if (r < 0)
1558 return bus_log_parse_error(r);
1559
1560 while ((r = sd_bus_message_read(m, "(ss)", &target, &option)) > 0) {
1561 _cleanup_free_ char *str = NULL;
1562
1563 if (isempty(target))
1564 continue;
1565
1566 if (asprintf(&str, "%s%s%s", target, isempty(option) ? "" : ":", strempty(option)) < 0)
1567 return log_oom();
1568
c2bc710b 1569 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
1570 return log_oom();
1571 }
1572 if (r < 0)
1573 return bus_log_parse_error(r);
1574
1575 r = sd_bus_message_exit_container(m);
1576 if (r < 0)
1577 return bus_log_parse_error(r);
1578
255b1fc8 1579 bus_print_property_value(name, expected_value, flags, paths);
daf71ef6
LP
1580
1581 return 1;
1582
1583 } else if (streq(name, "LogExtraFields")) {
1584 _cleanup_free_ char *fields = NULL;
1585 const void *p;
1586 size_t sz;
1587
1588 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "ay");
1589 if (r < 0)
1590 return bus_log_parse_error(r);
1591
1592 while ((r = sd_bus_message_read_array(m, 'y', &p, &sz)) > 0) {
1593 _cleanup_free_ char *str = NULL;
1594 const char *eq;
1595
1596 if (memchr(p, 0, sz))
1597 continue;
1598
1599 eq = memchr(p, '=', sz);
1600 if (!eq)
1601 continue;
1602
1603 if (!journal_field_valid(p, eq - (const char*) p, false))
1604 continue;
1605
1606 str = malloc(sz + 1);
1607 if (!str)
1608 return log_oom();
1609
1610 memcpy(str, p, sz);
1611 str[sz] = '\0';
1612
1613 if (!utf8_is_valid(str))
1614 continue;
1615
c2bc710b 1616 if (!strextend_with_separator(&fields, " ", str))
daf71ef6
LP
1617 return log_oom();
1618 }
1619 if (r < 0)
1620 return bus_log_parse_error(r);
1621
1622 r = sd_bus_message_exit_container(m);
1623 if (r < 0)
1624 return bus_log_parse_error(r);
1625
255b1fc8 1626 bus_print_property_value(name, expected_value, flags, fields);
daf71ef6
LP
1627
1628 return 1;
255b1fc8
YW
1629 } else if (contents[0] == SD_BUS_TYPE_BYTE &&
1630 STR_IN_SET(name,
1631 "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes",
1632 "EffectiveCPUs", "EffectiveMemoryNodes")) {
1633
daf71ef6
LP
1634 _cleanup_free_ char *affinity = NULL;
1635 _cleanup_(cpu_set_reset) CPUSet set = {};
1636 const void *a;
1637 size_t n;
1638
1639 r = sd_bus_message_read_array(m, 'y', &a, &n);
1640 if (r < 0)
1641 return bus_log_parse_error(r);
1642
1643 r = cpu_set_from_dbus(a, n, &set);
1644 if (r < 0)
1645 return log_error_errno(r, "Failed to deserialize %s: %m", name);
1646
1647 affinity = cpu_set_to_range_string(&set);
1648 if (!affinity)
1649 return log_oom();
1650
255b1fc8 1651 bus_print_property_value(name, expected_value, flags, affinity);
daf71ef6
LP
1652
1653 return 1;
1654 } else if (streq(name, "MountImages")) {
1655 _cleanup_free_ char *paths = NULL;
1656
1657 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ssba(ss))");
1658 if (r < 0)
1659 return bus_log_parse_error(r);
1660
1661 for (;;) {
1662 _cleanup_free_ char *str = NULL;
1663 const char *source, *destination, *partition, *mount_options;
1664 int ignore_enoent;
1665
1666 r = sd_bus_message_enter_container(m, 'r', "ssba(ss)");
1667 if (r < 0)
8ec6108c
LB
1668 return bus_log_parse_error(r);
1669 if (r == 0)
1670 break;
daf71ef6
LP
1671
1672 r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
8ec6108c
LB
1673 if (r < 0)
1674 return bus_log_parse_error(r);
daf71ef6
LP
1675
1676 str = strjoin(ignore_enoent ? "-" : "",
1677 source,
1678 ":",
1679 destination);
1680 if (!str)
1681 return log_oom();
1682
1683 r = sd_bus_message_enter_container(m, 'a', "(ss)");
1684 if (r < 0)
8ec6108c 1685 return bus_log_parse_error(r);
daf71ef6 1686
742a011a 1687 while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0)
8ec6108c 1688 if (!strextend_with_separator(&str, ":", partition, mount_options))
daf71ef6 1689 return log_oom();
daf71ef6 1690 if (r < 0)
8ec6108c 1691 return bus_log_parse_error(r);
daf71ef6 1692
c2bc710b 1693 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
1694 return log_oom();
1695
1696 r = sd_bus_message_exit_container(m);
1697 if (r < 0)
8ec6108c 1698 return bus_log_parse_error(r);
daf71ef6
LP
1699
1700 r = sd_bus_message_exit_container(m);
1701 if (r < 0)
8ec6108c 1702 return bus_log_parse_error(r);
daf71ef6 1703 }
daf71ef6
LP
1704
1705 r = sd_bus_message_exit_container(m);
1706 if (r < 0)
1707 return bus_log_parse_error(r);
1708
255b1fc8 1709 bus_print_property_value(name, expected_value, flags, paths);
60c16c5c
LB
1710
1711 return 1;
1712
1713 } else if (streq(name, "ExtensionImages")) {
1714 _cleanup_free_ char *paths = NULL;
1715
1716 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sba(ss))");
1717 if (r < 0)
1718 return bus_log_parse_error(r);
1719
1720 for (;;) {
1721 _cleanup_free_ char *str = NULL;
1722 const char *source, *partition, *mount_options;
1723 int ignore_enoent;
1724
1725 r = sd_bus_message_enter_container(m, 'r', "sba(ss)");
1726 if (r < 0)
1727 return bus_log_parse_error(r);
1728 if (r == 0)
1729 break;
1730
1731 r = sd_bus_message_read(m, "sb", &source, &ignore_enoent);
1732 if (r < 0)
1733 return bus_log_parse_error(r);
1734
1735 str = strjoin(ignore_enoent ? "-" : "", source);
1736 if (!str)
1737 return log_oom();
1738
1739 r = sd_bus_message_enter_container(m, 'a', "(ss)");
1740 if (r < 0)
1741 return bus_log_parse_error(r);
1742
1743 while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0)
1744 if (!strextend_with_separator(&str, ":", partition, mount_options))
1745 return log_oom();
1746 if (r < 0)
1747 return bus_log_parse_error(r);
1748
1749 if (!strextend_with_separator(&paths, " ", str))
1750 return log_oom();
1751
1752 r = sd_bus_message_exit_container(m);
1753 if (r < 0)
1754 return bus_log_parse_error(r);
1755
1756 r = sd_bus_message_exit_container(m);
1757 if (r < 0)
1758 return bus_log_parse_error(r);
1759 }
1760
1761 r = sd_bus_message_exit_container(m);
1762 if (r < 0)
1763 return bus_log_parse_error(r);
1764
1765 bus_print_property_value(name, expected_value, flags, paths);
daf71ef6
LP
1766
1767 return 1;
1768
9e009a14
JK
1769 } else if (streq(name, "BPFProgram")) {
1770 const char *a, *p;
1771
1772 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(ss)");
1773 if (r < 0)
1774 return bus_log_parse_error(r);
1775
1776 while ((r = sd_bus_message_read(m, "(ss)", &a, &p)) > 0)
255b1fc8 1777 bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p);
9e009a14
JK
1778 if (r < 0)
1779 return bus_log_parse_error(r);
1780
1781 r = sd_bus_message_exit_container(m);
1782 if (r < 0)
1783 return bus_log_parse_error(r);
18ef723e
JK
1784
1785 return 1;
1786 } else if (STR_IN_SET(name, "SocketBindAllow", "SocketBindDeny")) {
1787 uint16_t nr_ports, port_min;
4883a04f 1788 int32_t af, ip_protocol;
18ef723e 1789
4883a04f 1790 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(iiqq)");
18ef723e
JK
1791 if (r < 0)
1792 return bus_log_parse_error(r);
4883a04f 1793 while ((r = sd_bus_message_read(m, "(iiqq)", &af, &ip_protocol, &nr_ports, &port_min)) > 0) {
60477eb9 1794 const char *family, *colon1, *protocol = "", *colon2 = "";
a4817536
LP
1795
1796 family = strempty(af_to_ipv4_ipv6(af));
60477eb9
JK
1797 colon1 = isempty(family) ? "" : ":";
1798
1799 if (ip_protocol != 0) {
1800 protocol = ip_protocol_to_tcp_udp(ip_protocol);
1801 colon2 = "";
1802 }
a4817536 1803
18ef723e 1804 if (nr_ports == 0)
60477eb9
JK
1805 bus_print_property_valuef(name, expected_value, flags, "%s%s%s%sany",
1806 family, colon1, protocol, colon2);
18ef723e
JK
1807 else if (nr_ports == 1)
1808 bus_print_property_valuef(
60477eb9
JK
1809 name, expected_value, flags, "%s%s%s%s%hu",
1810 family, colon1, protocol, colon2, port_min);
18ef723e
JK
1811 else
1812 bus_print_property_valuef(
60477eb9
JK
1813 name, expected_value, flags, "%s%s%s%s%hu-%hu",
1814 family, colon1, protocol, colon2, port_min,
18ef723e
JK
1815 (uint16_t) (port_min + nr_ports - 1));
1816 }
1817 if (r < 0)
1818 return bus_log_parse_error(r);
1819
1820 r = sd_bus_message_exit_container(m);
1821 if (r < 0)
1822 return bus_log_parse_error(r);
9e009a14
JK
1823
1824 return 1;
211a3d87
LB
1825 } else if (STR_IN_SET(name, "StateDirectorySymlink", "RuntimeDirectorySymlink", "CacheDirectorySymlink", "LogsDirectorySymlink")) {
1826 const char *a, *p;
1827 uint64_t symlink_flags;
1828
1829 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sst)");
1830 if (r < 0)
1831 return bus_log_parse_error(r);
1832
1833 while ((r = sd_bus_message_read(m, "(sst)", &a, &p, &symlink_flags)) > 0)
1834 bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p);
1835 if (r < 0)
1836 return bus_log_parse_error(r);
1837
1838 r = sd_bus_message_exit_container(m);
1839 if (r < 0)
1840 return bus_log_parse_error(r);
1841
1842 return 1;
daf71ef6
LP
1843 }
1844
1845 break;
1846 }
1847
1848 return 0;
1849}
1850
1851typedef enum SystemctlShowMode{
1852 SYSTEMCTL_SHOW_PROPERTIES,
1853 SYSTEMCTL_SHOW_STATUS,
1854 SYSTEMCTL_SHOW_HELP,
1855 _SYSTEMCTL_SHOW_MODE_MAX,
2d93c20e 1856 _SYSTEMCTL_SHOW_MODE_INVALID = -EINVAL,
daf71ef6
LP
1857} SystemctlShowMode;
1858
1859static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
1860 [SYSTEMCTL_SHOW_PROPERTIES] = "show",
1861 [SYSTEMCTL_SHOW_STATUS] = "status",
1862 [SYSTEMCTL_SHOW_HELP] = "help",
1863};
1864
1865DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
1866
1867static int show_one(
1868 sd_bus *bus,
1869 const char *path,
1870 const char *unit,
1871 SystemctlShowMode show_mode,
1872 bool *new_line,
1873 bool *ellipsized) {
1874
1875 static const struct bus_properties_map property_map[] = {
1876 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
1877 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
1878 { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
1879 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
1880 {}
1881 }, status_map[] = {
1882 { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
1883 { "LoadState", "s", NULL, offsetof(UnitStatusInfo, load_state) },
1884 { "ActiveState", "s", NULL, offsetof(UnitStatusInfo, active_state) },
1885 { "FreezerState", "s", NULL, offsetof(UnitStatusInfo, freezer_state) },
1886 { "SubState", "s", NULL, offsetof(UnitStatusInfo, sub_state) },
1887 { "UnitFileState", "s", NULL, offsetof(UnitStatusInfo, unit_file_state) },
1888 { "UnitFilePreset", "s", NULL, offsetof(UnitStatusInfo, unit_file_preset) },
1889 { "Description", "s", NULL, offsetof(UnitStatusInfo, description) },
1890 { "Following", "s", NULL, offsetof(UnitStatusInfo, following) },
1891 { "Documentation", "as", NULL, offsetof(UnitStatusInfo, documentation) },
1892 { "FragmentPath", "s", NULL, offsetof(UnitStatusInfo, fragment_path) },
1893 { "SourcePath", "s", NULL, offsetof(UnitStatusInfo, source_path) },
1894 { "ControlGroup", "s", NULL, offsetof(UnitStatusInfo, control_group) },
1895 { "DropInPaths", "as", NULL, offsetof(UnitStatusInfo, dropin_paths) },
1896 { "LoadError", "(ss)", map_load_error, offsetof(UnitStatusInfo, load_error) },
1897 { "Result", "s", NULL, offsetof(UnitStatusInfo, result) },
1898 { "TriggeredBy", "as", NULL, offsetof(UnitStatusInfo, triggered_by) },
1899 { "Triggers", "as", NULL, offsetof(UnitStatusInfo, triggers) },
1900 { "InactiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp) },
1901 { "InactiveExitTimestampMonotonic", "t", NULL, offsetof(UnitStatusInfo, inactive_exit_timestamp_monotonic) },
1902 { "ActiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_enter_timestamp) },
1903 { "ActiveExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, active_exit_timestamp) },
a41699c9 1904 { "RuntimeMaxUSec", "t", NULL, offsetof(UnitStatusInfo, runtime_max_sec) },
daf71ef6
LP
1905 { "InactiveEnterTimestamp", "t", NULL, offsetof(UnitStatusInfo, inactive_enter_timestamp) },
1906 { "NeedDaemonReload", "b", NULL, offsetof(UnitStatusInfo, need_daemon_reload) },
1907 { "Transient", "b", NULL, offsetof(UnitStatusInfo, transient) },
1908 { "ExecMainPID", "u", NULL, offsetof(UnitStatusInfo, main_pid) },
1909 { "MainPID", "u", map_main_pid, 0 },
1910 { "ControlPID", "u", NULL, offsetof(UnitStatusInfo, control_pid) },
1911 { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
1912 { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
1913 { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
1914 { "ExecMainStartTimestamp", "t", NULL, offsetof(UnitStatusInfo, start_timestamp) },
1915 { "ExecMainExitTimestamp", "t", NULL, offsetof(UnitStatusInfo, exit_timestamp) },
1916 { "ExecMainCode", "i", NULL, offsetof(UnitStatusInfo, exit_code) },
1917 { "ExecMainStatus", "i", NULL, offsetof(UnitStatusInfo, exit_status) },
1918 { "LogNamespace", "s", NULL, offsetof(UnitStatusInfo, log_namespace) },
1919 { "ConditionTimestamp", "t", NULL, offsetof(UnitStatusInfo, condition_timestamp) },
1920 { "ConditionResult", "b", NULL, offsetof(UnitStatusInfo, condition_result) },
1921 { "Conditions", "a(sbbsi)", map_conditions, 0 },
1922 { "AssertTimestamp", "t", NULL, offsetof(UnitStatusInfo, assert_timestamp) },
1923 { "AssertResult", "b", NULL, offsetof(UnitStatusInfo, assert_result) },
1924 { "Asserts", "a(sbbsi)", map_asserts, 0 },
1925 { "NextElapseUSecRealtime", "t", NULL, offsetof(UnitStatusInfo, next_elapse_real) },
1926 { "NextElapseUSecMonotonic", "t", NULL, offsetof(UnitStatusInfo, next_elapse_monotonic) },
1927 { "NAccepted", "u", NULL, offsetof(UnitStatusInfo, n_accepted) },
1928 { "NConnections", "u", NULL, offsetof(UnitStatusInfo, n_connections) },
1929 { "NRefused", "u", NULL, offsetof(UnitStatusInfo, n_refused) },
1930 { "Accept", "b", NULL, offsetof(UnitStatusInfo, accept) },
1931 { "Listen", "a(ss)", map_listen, offsetof(UnitStatusInfo, listen) },
1932 { "SysFSPath", "s", NULL, offsetof(UnitStatusInfo, sysfs_path) },
1933 { "Where", "s", NULL, offsetof(UnitStatusInfo, where) },
1934 { "What", "s", NULL, offsetof(UnitStatusInfo, what) },
1935 { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
93ff34e4 1936 { "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
daf71ef6
LP
1937 { "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
1938 { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
1939 { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
1940 { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
1941 { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
1942 { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
1943 { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
d7fe0a67 1944 { "MemoryZSwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_zswap_max) },
daf71ef6
LP
1945 { "MemoryLimit", "t", NULL, offsetof(UnitStatusInfo, memory_limit) },
1946 { "CPUUsageNSec", "t", NULL, offsetof(UnitStatusInfo, cpu_usage_nsec) },
1947 { "TasksCurrent", "t", NULL, offsetof(UnitStatusInfo, tasks_current) },
1948 { "TasksMax", "t", NULL, offsetof(UnitStatusInfo, tasks_max) },
1949 { "IPIngressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_ingress_bytes) },
1950 { "IPEgressBytes", "t", NULL, offsetof(UnitStatusInfo, ip_egress_bytes) },
1951 { "IOReadBytes", "t", NULL, offsetof(UnitStatusInfo, io_read_bytes) },
1952 { "IOWriteBytes", "t", NULL, offsetof(UnitStatusInfo, io_write_bytes) },
1953 { "ExecCondition", "a(sasbttttuii)", map_exec, 0 },
1954 { "ExecConditionEx", "a(sasasttttuii)", map_exec, 0 },
1955 { "ExecStartPre", "a(sasbttttuii)", map_exec, 0 },
1956 { "ExecStartPreEx", "a(sasasttttuii)", map_exec, 0 },
1957 { "ExecStart", "a(sasbttttuii)", map_exec, 0 },
1958 { "ExecStartEx", "a(sasasttttuii)", map_exec, 0 },
1959 { "ExecStartPost", "a(sasbttttuii)", map_exec, 0 },
1960 { "ExecStartPostEx", "a(sasasttttuii)", map_exec, 0 },
1961 { "ExecReload", "a(sasbttttuii)", map_exec, 0 },
1962 { "ExecReloadEx", "a(sasasttttuii)", map_exec, 0 },
1963 { "ExecStopPre", "a(sasbttttuii)", map_exec, 0 },
1964 { "ExecStop", "a(sasbttttuii)", map_exec, 0 },
1965 { "ExecStopEx", "a(sasasttttuii)", map_exec, 0 },
1966 { "ExecStopPost", "a(sasbttttuii)", map_exec, 0 },
1967 { "ExecStopPostEx", "a(sasasttttuii)", map_exec, 0 },
1968 {}
1969 };
1970
1971 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1972 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1973 _cleanup_set_free_ Set *found_properties = NULL;
1974 _cleanup_(unit_status_info_free) UnitStatusInfo info = {
f5fbe71d 1975 .memory_current = UINT64_MAX,
daf71ef6
LP
1976 .memory_high = CGROUP_LIMIT_MAX,
1977 .memory_max = CGROUP_LIMIT_MAX,
1978 .memory_swap_max = CGROUP_LIMIT_MAX,
d7fe0a67 1979 .memory_zswap_max = CGROUP_LIMIT_MAX,
f5fbe71d 1980 .memory_limit = UINT64_MAX,
93ff34e4 1981 .memory_available = CGROUP_LIMIT_MAX,
f5fbe71d
YW
1982 .cpu_usage_nsec = UINT64_MAX,
1983 .tasks_current = UINT64_MAX,
1984 .tasks_max = UINT64_MAX,
1985 .ip_ingress_bytes = UINT64_MAX,
1986 .ip_egress_bytes = UINT64_MAX,
daf71ef6
LP
1987 .io_read_bytes = UINT64_MAX,
1988 .io_write_bytes = UINT64_MAX,
1989 };
daf71ef6
LP
1990 int r;
1991
1992 assert(path);
1993 assert(new_line);
1994
1995 log_debug("Showing one %s", path);
1996
1997 r = bus_map_all_properties(
1998 bus,
1999 "org.freedesktop.systemd1",
2000 path,
2001 show_mode == SYSTEMCTL_SHOW_STATUS ? status_map : property_map,
2002 BUS_MAP_BOOLEAN_AS_BOOL,
2003 &error,
2004 &reply,
2005 &info);
2006 if (r < 0)
2007 return log_error_errno(r, "Failed to get properties: %s", bus_error_message(&error, r));
2008
2009 if (unit && streq_ptr(info.load_state, "not-found") && streq_ptr(info.active_state, "inactive")) {
75312ada 2010 log_full(show_mode == SYSTEMCTL_SHOW_PROPERTIES ? LOG_DEBUG : LOG_ERR,
daf71ef6
LP
2011 "Unit %s could not be found.", unit);
2012
2013 if (show_mode == SYSTEMCTL_SHOW_STATUS)
2014 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
ab5d52b7 2015 if (show_mode == SYSTEMCTL_SHOW_HELP)
daf71ef6
LP
2016 return -ENOENT;
2017 }
2018
2019 if (*new_line)
2020 printf("\n");
2021
2022 *new_line = true;
2023
2024 if (show_mode == SYSTEMCTL_SHOW_STATUS) {
2025 print_status_info(bus, &info, ellipsized);
2026
2027 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading"))
2028 return EXIT_PROGRAM_NOT_RUNNING;
2029
2030 return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK;
2031
2032 } else if (show_mode == SYSTEMCTL_SHOW_HELP) {
2033 show_unit_help(&info);
2034 return 0;
2035 }
2036
2037 r = sd_bus_message_rewind(reply, true);
2038 if (r < 0)
2039 return log_error_errno(r, "Failed to rewind: %s", bus_error_message(&error, r));
2040
255b1fc8 2041 r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_print_flags, &found_properties);
daf71ef6
LP
2042 if (r < 0)
2043 return bus_log_parse_error(r);
2044
2045 STRV_FOREACH(pp, arg_properties)
2046 if (!set_contains(found_properties, *pp))
2047 log_debug("Property %s does not exist.", *pp);
2048
2049 return 0;
2050}
2051
2052static int get_unit_dbus_path_by_pid(
2053 sd_bus *bus,
2054 uint32_t pid,
2055 char **unit) {
2056
2057 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2058 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2059 char *u;
2060 int r;
2061
2062 r = bus_call_method(bus, bus_systemd_mgr, "GetUnitByPID", &error, &reply, "u", pid);
2063 if (r < 0)
2064 return log_error_errno(r, "Failed to get unit for PID %"PRIu32": %s", pid, bus_error_message(&error, r));
2065
2066 r = sd_bus_message_read(reply, "o", &u);
2067 if (r < 0)
2068 return bus_log_parse_error(r);
2069
2070 u = strdup(u);
2071 if (!u)
2072 return log_oom();
2073
2074 *unit = u;
2075 return 0;
2076}
2077
2078static int show_all(
2079 sd_bus *bus,
a6e33464 2080 SystemctlShowMode show_mode,
daf71ef6
LP
2081 bool *new_line,
2082 bool *ellipsized) {
2083
2084 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
2085 _cleanup_free_ UnitInfo *unit_infos = NULL;
daf71ef6
LP
2086 unsigned c;
2087 int r, ret = 0;
2088
2089 r = get_unit_list(bus, NULL, NULL, &unit_infos, 0, &reply);
2090 if (r < 0)
2091 return r;
2092
384c2c32 2093 pager_open(arg_pager_flags);
daf71ef6
LP
2094
2095 c = (unsigned) r;
2096
2097 typesafe_qsort(unit_infos, c, unit_info_compare);
2098
deaf4b86 2099 for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) {
daf71ef6
LP
2100 _cleanup_free_ char *p = NULL;
2101
2102 p = unit_dbus_path_from_name(u->id);
2103 if (!p)
2104 return log_oom();
2105
a6e33464 2106 r = show_one(bus, p, u->id, show_mode, new_line, ellipsized);
daf71ef6
LP
2107 if (r < 0)
2108 return r;
ab5d52b7 2109 if (r > 0 && ret == 0)
daf71ef6
LP
2110 ret = r;
2111 }
2112
2113 return ret;
2114}
2115
2116static int show_system_status(sd_bus *bus) {
daf71ef6
LP
2117 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2118 _cleanup_(machine_info_clear) struct machine_info mi = {};
038cae09 2119 static const char prefix[] = " ";
daf71ef6
LP
2120 _cleanup_free_ char *hn = NULL;
2121 const char *on, *off;
038cae09 2122 unsigned c;
daf71ef6
LP
2123 int r;
2124
2125 hn = gethostname_malloc();
2126 if (!hn)
2127 return log_oom();
2128
2129 r = bus_map_all_properties(
2130 bus,
2131 "org.freedesktop.systemd1",
2132 "/org/freedesktop/systemd1",
2133 machine_info_property_map,
2134 BUS_MAP_STRDUP,
2135 &error,
2136 NULL,
2137 &mi);
2138 if (r < 0)
2139 return log_error_errno(r, "Failed to read server status: %s", bus_error_message(&error, r));
2140
2141 if (streq_ptr(mi.state, "degraded")) {
2142 on = ansi_highlight_red();
2143 off = ansi_normal();
2144 } else if (streq_ptr(mi.state, "running")) {
2145 on = ansi_highlight_green();
2146 off = ansi_normal();
2147 } else {
2148 on = ansi_highlight_yellow();
2149 off = ansi_normal();
2150 }
2151
5e1b4929 2152 printf("%s%s%s %s\n", on, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE), off, arg_host ?: hn);
daf71ef6
LP
2153
2154 printf(" State: %s%s%s\n",
2155 on, strna(mi.state), off);
2156
45bff9b4 2157 printf(" Units: %" PRIu32 " loaded (incl. loaded aliases)\n", mi.n_names);
daf71ef6
LP
2158 printf(" Jobs: %" PRIu32 " queued\n", mi.n_jobs);
2159 printf(" Failed: %" PRIu32 " units\n", mi.n_failed_units);
2160
2161 printf(" Since: %s; %s\n",
0086ef19 2162 FORMAT_TIMESTAMP_STYLE(mi.timestamp, arg_timestamp_style),
32fc5c47 2163 FORMAT_TIMESTAMP_RELATIVE(mi.timestamp));
daf71ef6 2164
45bff9b4
LP
2165 printf(" systemd: %s\n", mi.version);
2166
2167 if (!isempty(mi.tainted))
2168 printf(" Tainted: %s%s%s\n", ansi_highlight_yellow(), mi.tainted, ansi_normal());
2169
27ba2ad2 2170 printf(" CGroup: %s\n", empty_to_root(mi.control_group));
daf71ef6 2171
038cae09 2172 c = LESS_BY(columns(), strlen(prefix));
daf71ef6 2173
038cae09
LP
2174 r = unit_show_processes(bus, SPECIAL_ROOT_SLICE, mi.control_group, prefix, c, get_output_flags(), &error);
2175 if (r == -EBADR && arg_transport == BUS_TRANSPORT_LOCAL) /* Compatibility for really old systemd versions */
daf71ef6 2176 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
038cae09
LP
2177 else if (r < 0)
2178 log_warning_errno(r, "Failed to dump process list for '%s', ignoring: %s",
2179 arg_host ?: hn, bus_error_message(&error, r));
daf71ef6
LP
2180
2181 return 0;
2182}
2183
32baf64d 2184int verb_show(int argc, char *argv[], void *userdata) {
daf71ef6
LP
2185 bool new_line = false, ellipsized = false;
2186 SystemctlShowMode show_mode;
2187 int r, ret = 0;
2188 sd_bus *bus;
2189
2190 assert(argv);
2191
2192 show_mode = systemctl_show_mode_from_string(argv[0]);
2193 if (show_mode < 0)
71fae19e 2194 return log_error_errno(show_mode, "Invalid argument '%s'.", argv[0]);
daf71ef6
LP
2195
2196 if (show_mode == SYSTEMCTL_SHOW_HELP && argc <= 1)
2197 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2198 "'help' command expects one or more unit names.\n"
2199 "(Alternatively, help for systemctl itself may be shown with --help)");
2200
2201 r = acquire_bus(BUS_MANAGER, &bus);
2202 if (r < 0)
2203 return r;
2204
384c2c32 2205 pager_open(arg_pager_flags);
daf71ef6 2206
a6e33464
ZJS
2207 if (argc <= 1) {
2208 /* If no argument or filter is specified inspect the manager itself:
2209 * systemctl status → we show status of the manager
2210 * systemctl status --all → status of the manager + status of all units
2211 * systemctl status --state=… → status of units in listed states
2212 * systemctl status --type=… → status of units of listed types
2213 * systemctl status --failed → status of failed units, mirroring systemctl list-units --failed
2214 */
2215
2216 if (!arg_states && !arg_types) {
2217 if (show_mode == SYSTEMCTL_SHOW_PROPERTIES)
0b51a1c8
YW
2218 /* systemctl show --all → show properties of the manager */
2219 return show_one(bus, "/org/freedesktop/systemd1", NULL, show_mode, &new_line, &ellipsized);
2220
2221 r = show_system_status(bus);
a6e33464
ZJS
2222 if (r < 0)
2223 return r;
daf71ef6 2224
a6e33464
ZJS
2225 new_line = true;
2226 }
daf71ef6 2227
a6e33464
ZJS
2228 if (arg_all || arg_states || arg_types)
2229 ret = show_all(bus, show_mode, &new_line, &ellipsized);
daf71ef6
LP
2230 } else {
2231 _cleanup_free_ char **patterns = NULL;
daf71ef6
LP
2232
2233 STRV_FOREACH(name, strv_skip(argv, 1)) {
2234 _cleanup_free_ char *path = NULL, *unit = NULL;
2235 uint32_t id;
2236
2237 if (safe_atou32(*name, &id) < 0) {
2238 if (strv_push(&patterns, *name) < 0)
2239 return log_oom();
2240
2241 continue;
2242 } else if (show_mode == SYSTEMCTL_SHOW_PROPERTIES) {
2243 /* Interpret as job id */
2244 if (asprintf(&path, "/org/freedesktop/systemd1/job/%u", id) < 0)
2245 return log_oom();
2246
2247 } else {
2248 /* Interpret as PID */
2249 r = get_unit_dbus_path_by_pid(bus, id, &path);
2250 if (r < 0) {
2251 ret = r;
2252 continue;
2253 }
2254
2255 r = unit_name_from_dbus_path(path, &unit);
2256 if (r < 0)
2257 return log_oom();
2258 }
2259
2260 r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
2261 if (r < 0)
2262 return r;
ab5d52b7 2263 if (r > 0 && ret == 0)
daf71ef6
LP
2264 ret = r;
2265 }
2266
2267 if (!strv_isempty(patterns)) {
2268 _cleanup_strv_free_ char **names = NULL;
2269
2270 r = expand_unit_names(bus, patterns, NULL, &names, NULL);
2271 if (r < 0)
2272 return log_error_errno(r, "Failed to expand names: %m");
2273
2274 r = maybe_extend_with_unit_dependencies(bus, &names);
2275 if (r < 0)
2276 return r;
2277
2278 STRV_FOREACH(name, names) {
c2b2df60 2279 _cleanup_free_ char *path = NULL;
daf71ef6
LP
2280
2281 path = unit_dbus_path_from_name(*name);
2282 if (!path)
2283 return log_oom();
2284
2285 r = show_one(bus, path, *name, show_mode, &new_line, &ellipsized);
2286 if (r < 0)
2287 return r;
2288 if (r > 0 && ret == 0)
2289 ret = r;
2290 }
2291 }
2292 }
2293
2294 if (ellipsized && !arg_quiet)
2295 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");
2296
2297 return ret;
2298}