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