]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/systemctl/systemctl-show.c
fix: UnsetProperty example in systemd.link.xml
[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
0bbd8e18
DDM
5#include "sd-bus.h"
6#include "sd-journal.h"
7
a4817536 8#include "af-list.h"
daf71ef6 9#include "bus-error.h"
daf71ef6
LP
10#include "bus-map-properties.h"
11#include "bus-print-properties.h"
12#include "bus-unit-procs.h"
0bbd8e18
DDM
13#include "bus-unit-util.h"
14#include "bus-util.h"
daf71ef6
LP
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"
98b7c5e2 22#include "hostname-setup.h"
daf71ef6 23#include "in-addr-util.h"
0bbd8e18 24#include "install.h"
60477eb9 25#include "ip-protocol-list.h"
adce225a 26#include "journal-file.h"
daf71ef6 27#include "list.h"
0bbd8e18 28#include "logs-show.h"
daf71ef6
LP
29#include "memory-util.h"
30#include "numa-util.h"
cd48e23f 31#include "open-file.h"
1e35e81b 32#include "output-mode.h"
0bbd8e18 33#include "pager.h"
daf71ef6
LP
34#include "parse-util.h"
35#include "path-util.h"
36#include "pretty-print.h"
37#include "process-util.h"
0bbd8e18 38#include "set.h"
daf71ef6
LP
39#include "signal-util.h"
40#include "sort-util.h"
038cae09 41#include "special.h"
0bbd8e18 42#include "systemctl-list-units.h"
daf71ef6 43#include "string-table.h"
0bbd8e18
DDM
44#include "string-util.h"
45#include "strv.h"
1cf40697 46#include "systemctl.h"
daf71ef6 47#include "systemctl-list-machines.h"
daf71ef6
LP
48#include "systemctl-show.h"
49#include "systemctl-sysv-compat.h"
50#include "systemctl-util.h"
daf71ef6
LP
51#include "terminal-util.h"
52#include "utf8.h"
53
54static OutputFlags get_output_flags(void) {
55 return
255b1fc8 56 FLAGS_SET(arg_print_flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) * OUTPUT_SHOW_ALL |
daf71ef6
LP
57 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
58 colors_enabled() * OUTPUT_COLOR |
59 !arg_quiet * OUTPUT_WARN_CUTOFF;
60}
61
62typedef 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
eb506199 78 LIST_FIELDS(struct ExecStatusInfo, exec_status_info_list);
daf71ef6
LP
79} ExecStatusInfo;
80
81static 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
90static 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);
ab5d52b7 104 if (r == 0)
daf71ef6
LP
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
154typedef 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
75db809a 164static UnitCondition* unit_condition_free(UnitCondition *c) {
daf71ef6 165 if (!c)
75db809a 166 return NULL;
daf71ef6
LP
167
168 free(c->name);
169 free(c->param);
75db809a 170 return mfree(c);
daf71ef6 171}
daf71ef6
LP
172DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition*, unit_condition_free);
173
174typedef 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
a41699c9
AO
206 uint64_t runtime_max_sec;
207
b1ec4836
MY
208 uint32_t job_id;
209
f1d345ed
LP
210 sd_id128_t invocation_id;
211
daf71ef6
LP
212 bool need_daemon_reload;
213 bool transient;
214
215 /* Service */
f488e97a 216 bool running;
daf71ef6
LP
217 pid_t main_pid;
218 pid_t control_pid;
daf71ef6 219 const char *pid_file;
f488e97a
MY
220 const char *status_text;
221 const char *status_bus_error;
222 const char *status_varlink_error;
daf71ef6
LP
223 int status_errno;
224
8489c294
LP
225 uint32_t fd_store_max;
226 uint32_t n_fd_store;
227
daf71ef6
LP
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
9ca16f6f
LP
266 /* Slice */
267 unsigned concurrency_hard_max;
268 unsigned concurrency_soft_max;
269 unsigned n_currently_active;
270
daf71ef6
LP
271 /* CGroup */
272 uint64_t memory_current;
6c71db76 273 uint64_t memory_peak;
37533c94 274 uint64_t memory_swap_current;
aac3384e 275 uint64_t memory_swap_peak;
26caa668 276 uint64_t memory_zswap_current;
daf71ef6
LP
277 uint64_t memory_min;
278 uint64_t memory_low;
53fda560 279 uint64_t startup_memory_low;
daf71ef6 280 uint64_t memory_high;
53fda560 281 uint64_t startup_memory_high;
daf71ef6 282 uint64_t memory_max;
53fda560 283 uint64_t startup_memory_max;
daf71ef6 284 uint64_t memory_swap_max;
53fda560 285 uint64_t startup_memory_swap_max;
d7fe0a67 286 uint64_t memory_zswap_max;
53fda560 287 uint64_t startup_memory_zswap_max;
daf71ef6 288 uint64_t memory_limit;
93ff34e4 289 uint64_t memory_available;
daf71ef6
LP
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;
53fda560 300 uint64_t default_startup_memory_low;
daf71ef6 301
eb506199 302 LIST_HEAD(ExecStatusInfo, exec_status_info_list);
daf71ef6
LP
303} UnitStatusInfo;
304
6e8c5e97 305static void unit_status_info_done(UnitStatusInfo *info) {
daf71ef6
LP
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
9aad490e
DT
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);
daf71ef6
LP
314}
315
316static 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();
5162829e 320 } else if (STRPTR_IN_SET(active_state, "active", "reloading", "refreshing")) {
daf71ef6
LP
321 *active_on = ansi_highlight_green();
322 *active_off = ansi_normal();
323 } else
324 *active_on = *active_off = "";
325}
326
354ca980 327static 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
daf71ef6
LP
341static void print_status_info(
342 sd_bus *bus,
343 UnitStatusInfo *i,
344 bool *ellipsized) {
345
f843f85d 346 const char *active_on, *active_off, *on, *off, *ss, *fs;
c1e0dc9c 347 const char *enable_on, *enable_off, *preset_on, *preset_off;
daf71ef6 348 _cleanup_free_ char *formatted_path = NULL;
daf71ef6
LP
349 usec_t timestamp;
350 const char *path;
daf71ef6
LP
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);
354ca980 359 format_enable_state(i->unit_file_state, &enable_on, &enable_off);
c1e0dc9c 360 format_enable_state(i->unit_file_preset, &preset_on, &preset_off);
daf71ef6 361
1ae9b0cf 362 const Glyph icon = unit_active_state_to_glyph(unit_active_state_from_string(i->active_state));
9ae5fed6 363
1ae9b0cf 364 printf("%s%s%s %s", active_on, glyph(icon), active_off, strna(i->id));
daf71ef6
LP
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)
1d406dce 372 printf(" Follows: unit currently follows state of %s\n", i->following);
daf71ef6
LP
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
354ca980 391 printf(" Loaded: %s%s%s (%s; %s%s%s%s%s%s%s)\n",
daf71ef6
LP
392 on, strna(i->load_state), off,
393 path,
354ca980 394 enable_on, i->unit_file_state, enable_off,
c1e0dc9c
ZJS
395 show_preset ? "; preset: " : "",
396 preset_on, show_preset ? i->unit_file_preset : "", preset_off);
daf71ef6
LP
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;
daf71ef6
LP
411
412 STRV_FOREACH(dropin, i->dropin_paths) {
6b783209 413 _cleanup_free_ char *dropin_formatted = NULL, *dropin_basename = NULL;
daf71ef6
LP
414 const char *df;
415
416 if (!dir || last) {
417 printf(dir ? " " :
418 " Drop-In: ");
419
420 dir = mfree(dir);
421
45519d13
LP
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;
daf71ef6
LP
426 }
427
428 printf("%s\n"
429 " %s", dir,
1ae9b0cf 430 glyph(GLYPH_TREE_RIGHT));
daf71ef6
LP
431 }
432
433 last = ! (*(dropin + 1) && startswith(*(dropin + 1), dir));
434
6b783209
W
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)
daf71ef6
LP
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
5162829e
LB
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;
daf71ef6 469
0da36375 470 if (timestamp_is_set(timestamp)) {
f843f85d
YW
471 printf(" since %s; %s\n",
472 FORMAT_TIMESTAMP_STYLE(timestamp, arg_timestamp_style),
473 FORMAT_TIMESTAMP_RELATIVE(timestamp));
a41699c9
AO
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 }
0802f62e
DDM
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 }
a41699c9 494 } else
daf71ef6
LP
495 printf("\n");
496
b1ec4836
MY
497 if (i->job_id != 0)
498 printf(" Job: %" PRIu32 "\n", i->job_id);
499
f1d345ed
LP
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
daf71ef6
LP
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:" : " ",
1ae9b0cf 511 on, glyph(unit_active_state_to_glyph(state)), off,
daf71ef6
LP
512 *t);
513 }
514
515 if (endswith(i->id, ".timer")) {
0086ef19 516 dual_timestamp nw, next = {i->next_elapse_real, i->next_elapse_monotonic};
daf71ef6
LP
517 usec_t next_elapse;
518
fa5a0251 519 dual_timestamp_now(&nw);
daf71ef6 520 next_elapse = calc_next_elapse(&nw, &next);
daf71ef6 521
0da36375 522 if (timestamp_is_set(next_elapse))
f843f85d
YW
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");
daf71ef6
LP
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:" : " ",
1ae9b0cf 538 on, glyph(GLYPH_BLACK_CIRCLE), off,
daf71ef6
LP
539 *t);
540 }
541
542 if (!i->condition_result && i->condition_timestamp > 0) {
daf71ef6
LP
543 int n = 0;
544
4e1ac54e 545 printf(" Condition: start %scondition unmet%s at %s; %s\n",
daf71ef6 546 ansi_highlight_yellow(), ansi_normal(),
0086ef19 547 FORMAT_TIMESTAMP_STYLE(i->condition_timestamp, arg_timestamp_style),
f843f85d 548 FORMAT_TIMESTAMP_RELATIVE(i->condition_timestamp));
daf71ef6
LP
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",
1ae9b0cf 557 --n ? glyph(GLYPH_TREE_BRANCH) : glyph(GLYPH_TREE_RIGHT),
daf71ef6
LP
558 c->name,
559 c->trigger ? "|" : "",
560 c->negate ? "!" : "",
561 c->param);
562 }
563
564 if (!i->assert_result && i->assert_timestamp > 0) {
f843f85d 565 printf(" Assert: start %sassertion failed%s at %s; %s\n",
daf71ef6 566 ansi_highlight_red(), ansi_normal(),
0086ef19 567 FORMAT_TIMESTAMP_STYLE(i->assert_timestamp, arg_timestamp_style),
f843f85d 568 FORMAT_TIMESTAMP_RELATIVE(i->assert_timestamp));
daf71ef6
LP
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
eb506199 607 LIST_FOREACH(exec_status_info_list, p, i->exec_status_info_list) {
daf71ef6
LP
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) {
e879434d 625 on = p->ignore ? ansi_highlight_yellow() : ansi_highlight_red();
daf71ef6
LP
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
d7d74854 665 (void) pid_get_comm(i->main_pid, &comm);
daf71ef6
LP
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
4146960e 695 fputs(" Cntrl PID: ", stdout); /* if first in column, abbreviated so it fits alignment */
daf71ef6
LP
696
697 printf(PID_FMT, i->control_pid);
698
699 if (arg_transport == BUS_TRANSPORT_LOCAL) {
d7d74854 700 (void) pid_get_comm(i->control_pid, &c);
daf71ef6
LP
701 if (c)
702 printf(" (%s)", c);
703 }
704 }
705
706 printf("\n");
707 }
708
709 if (i->status_text)
bf821455 710 printf(" Status: \"%s%s%s\"\n", ansi_highlight_cyan(), i->status_text, ansi_normal());
f488e97a
MY
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');
38553034 731 }
daf71ef6 732
9ca16f6f
LP
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
2b59bf51 753 if (i->ip_ingress_bytes != UINT64_MAX && i->ip_egress_bytes != UINT64_MAX)
daf71ef6 754 printf(" IP: %s in, %s out\n",
2b59bf51
ZJS
755 FORMAT_BYTES(i->ip_ingress_bytes),
756 FORMAT_BYTES(i->ip_egress_bytes));
daf71ef6 757
2b59bf51 758 if (i->io_read_bytes != UINT64_MAX && i->io_write_bytes != UINT64_MAX)
daf71ef6 759 printf(" IO: %s read, %s written\n",
2b59bf51
ZJS
760 FORMAT_BYTES(i->io_read_bytes),
761 FORMAT_BYTES(i->io_write_bytes));
daf71ef6 762
f5fbe71d 763 if (i->tasks_current != UINT64_MAX) {
daf71ef6
LP
764 printf(" Tasks: %" PRIu64, i->tasks_current);
765
f5fbe71d 766 if (i->tasks_max != UINT64_MAX)
54646b1c 767 printf("%s (limit: %" PRIu64 ")%s\n", ansi_grey(), i->tasks_max, ansi_normal());
daf71ef6
LP
768 else
769 printf("\n");
770 }
771
8489c294
LP
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
2747cd6d
MY
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
f5fbe71d 778 if (i->memory_current != UINT64_MAX) {
2b59bf51 779 printf(" Memory: %s", FORMAT_BYTES(i->memory_current));
daf71ef6 780
2747cd6d 781 bool show_memory_zswap_current = !IN_SET(i->memory_zswap_current, 0, CGROUP_LIMIT_MAX),
8f9acf8e
MY
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);
2747cd6d 785 if (show_memory_peak ||
8f9acf8e 786 show_memory_swap_peak || /* We don't need to check memory_swap_current, as if peak is 0 that must also be 0 */
26caa668 787 show_memory_zswap_current ||
f380473e 788 show_memory_available ||
6c71db76 789 i->memory_min > 0 ||
53fda560
LB
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 ||
daf71ef6
LP
795 i->memory_limit != CGROUP_LIMIT_MAX) {
796 const char *prefix = "";
797
798 printf(" (");
799 if (i->memory_min > 0) {
9ca7e3d0 800 printf("%smin: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_min));
483ab075 801 prefix = ", ";
daf71ef6
LP
802 }
803 if (i->memory_low > 0) {
9ca7e3d0 804 printf("%slow: %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->memory_low));
483ab075 805 prefix = ", ";
daf71ef6 806 }
53fda560
LB
807 if (i->startup_memory_low > 0) {
808 printf("%slow (startup): %s", prefix, FORMAT_BYTES_CGROUP_PROTECTION(i->startup_memory_low));
483ab075 809 prefix = ", ";
53fda560 810 }
daf71ef6 811 if (i->memory_high != CGROUP_LIMIT_MAX) {
2b59bf51 812 printf("%shigh: %s", prefix, FORMAT_BYTES(i->memory_high));
483ab075 813 prefix = ", ";
daf71ef6 814 }
53fda560
LB
815 if (i->startup_memory_high != CGROUP_LIMIT_MAX) {
816 printf("%shigh (startup): %s", prefix, FORMAT_BYTES(i->startup_memory_high));
483ab075 817 prefix = ", ";
53fda560 818 }
daf71ef6 819 if (i->memory_max != CGROUP_LIMIT_MAX) {
2b59bf51 820 printf("%smax: %s", prefix, FORMAT_BYTES(i->memory_max));
483ab075 821 prefix = ", ";
daf71ef6 822 }
53fda560
LB
823 if (i->startup_memory_max != CGROUP_LIMIT_MAX) {
824 printf("%smax (startup): %s", prefix, FORMAT_BYTES(i->startup_memory_max));
483ab075 825 prefix = ", ";
53fda560 826 }
daf71ef6 827 if (i->memory_swap_max != CGROUP_LIMIT_MAX) {
2b59bf51 828 printf("%sswap max: %s", prefix, FORMAT_BYTES(i->memory_swap_max));
483ab075 829 prefix = ", ";
daf71ef6 830 }
53fda560
LB
831 if (i->startup_memory_swap_max != CGROUP_LIMIT_MAX) {
832 printf("%sswap max (startup): %s", prefix, FORMAT_BYTES(i->startup_memory_swap_max));
483ab075 833 prefix = ", ";
53fda560 834 }
d7fe0a67
PV
835 if (i->memory_zswap_max != CGROUP_LIMIT_MAX) {
836 printf("%szswap max: %s", prefix, FORMAT_BYTES(i->memory_zswap_max));
483ab075 837 prefix = ", ";
d7fe0a67 838 }
53fda560
LB
839 if (i->startup_memory_zswap_max != CGROUP_LIMIT_MAX) {
840 printf("%szswap max (startup): %s", prefix, FORMAT_BYTES(i->startup_memory_zswap_max));
483ab075 841 prefix = ", ";
53fda560 842 }
daf71ef6 843 if (i->memory_limit != CGROUP_LIMIT_MAX) {
2b59bf51 844 printf("%slimit: %s", prefix, FORMAT_BYTES(i->memory_limit));
483ab075 845 prefix = ", ";
daf71ef6 846 }
f380473e 847 if (show_memory_available) {
2b59bf51 848 printf("%savailable: %s", prefix, FORMAT_BYTES(i->memory_available));
483ab075 849 prefix = ", ";
93ff34e4 850 }
2747cd6d 851 if (show_memory_peak) {
6c71db76 852 printf("%speak: %s", prefix, FORMAT_BYTES(i->memory_peak));
483ab075 853 prefix = ", ";
6c71db76 854 }
2747cd6d 855 if (show_memory_swap_peak) {
483ab075 856 printf("%sswap: %s, swap peak: %s", prefix,
7bf87a64 857 FORMAT_BYTES(i->memory_swap_current), FORMAT_BYTES(i->memory_swap_peak));
483ab075 858 prefix = ", ";
aac3384e 859 }
26caa668
FS
860 if (show_memory_zswap_current) {
861 printf("%szswap: %s", prefix, FORMAT_BYTES(i->memory_zswap_current));
483ab075 862 prefix = ", ";
26caa668 863 }
daf71ef6
LP
864 printf(")");
865 }
866 printf("\n");
2747cd6d
MY
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');
daf71ef6
LP
875 }
876
5291f26d
ZJS
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));
daf71ef6
LP
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
a0dde733 887 c = LESS_BY(columns(), strlen(prefix));
daf71ef6
LP
888
889 r = unit_show_processes(bus, i->id, i->control_group, prefix, c, get_output_flags(), &error);
35ac0260 890 if (r == -EBADR && arg_transport == BUS_TRANSPORT_LOCAL) {
daf71ef6
LP
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,
8ac0810f 914 /* n_columns = */ 0,
daf71ef6
LP
915 i->inactive_exit_timestamp_monotonic,
916 arg_lines,
daf71ef6
LP
917 get_output_flags() | OUTPUT_BEGIN_NEWLINE,
918 SD_JOURNAL_LOCAL_ONLY,
4870133b 919 arg_runtime_scope == RUNTIME_SCOPE_SYSTEM,
daf71ef6
LP
920 ellipsized);
921
922 if (i->need_daemon_reload)
923 warn_unit_file_changed(i->id);
924}
925
926static void show_unit_help(UnitStatusInfo *i) {
67bc612c
ZJS
927 bool previous_man_page = false;
928
daf71ef6
LP
929 assert(i);
930
931 if (!i->documentation) {
932 log_info("Documentation for %s not known.", i->id);
933 return;
934 }
935
67bc612c
ZJS
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 }
daf71ef6
LP
959}
960
961static 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
976static 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
990static 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
69f3c619 1001 r = strv_extend_many(p, type, path);
daf71ef6
LP
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
1015static 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
1056static 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
1085static 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
cc232fa0 1100 last = LIST_FIND_TAIL(exec_status_info_list, i->exec_status_info_list);
daf71ef6
LP
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
eb506199 1108 LIST_INSERT_AFTER(exec_status_info_list, i->exec_status_info_list, last, info);
daf71ef6
LP
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
255b1fc8 1125static int print_property(const char *name, const char *expected_value, sd_bus_message *m, BusPrintPropertyFlags flags) {
daf71ef6
LP
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)
255b1fc8
YW
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]");
daf71ef6
LP
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
255b1fc8 1162 bus_print_property_valuef(name, expected_value, flags, "%s", strna(mpol_to_string(i)));
daf71ef6
LP
1163
1164 return 1;
1165 }
1166 break;
1167
a59e5c62
FS
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
daf71ef6
LP
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)
255b1fc8
YW
1192 bus_print_property_valuef(name, expected_value, flags, "%"PRIu32, u);
1193 else
1194 bus_print_property_value(name, expected_value, flags, NULL);
daf71ef6
LP
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
255b1fc8 1205 bus_print_property_value(name, expected_value, flags, s);
daf71ef6
LP
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))
255b1fc8
YW
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);
daf71ef6
LP
1220
1221 return 1;
1222
e59ccd03 1223 } else if (STR_IN_SET(name, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces", "RestrictFileSystems")) {
daf71ef6
LP
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
255b1fc8 1243 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || allow_list || !strv_isempty(l)) {
daf71ef6 1244 bool first = true;
daf71ef6 1245
255b1fc8 1246 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
daf71ef6
LP
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))
255b1fc8
YW
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);
daf71ef6
LP
1279
1280 return 1;
1281
1282 } else if (endswith(name, "ExitStatus") && streq(contents, "aiai")) {
1283 const int32_t *status, *signal;
deaf4b86 1284 size_t n_status, n_signal;
daf71ef6
LP
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
255b1fc8 1305 if (FLAGS_SET(flags, BUS_PRINT_PROPERTY_SHOW_EMPTY) || n_status > 0 || n_signal > 0) {
daf71ef6
LP
1306 bool first = true;
1307
255b1fc8 1308 if (!FLAGS_SET(flags, BUS_PRINT_PROPERTY_ONLY_VALUE)) {
daf71ef6
LP
1309 fputs(name, stdout);
1310 fputc('=', stdout);
1311 }
1312
deaf4b86 1313 for (size_t i = 0; i < n_status; i++) {
daf71ef6
LP
1314 if (first)
1315 first = false;
1316 else
1317 fputc(' ', stdout);
1318
1319 printf("%"PRIi32, status[i]);
1320 }
1321
deaf4b86 1322 for (size_t i = 0; i < n_signal; i++) {
daf71ef6
LP
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)
255b1fc8 1356 bus_print_property_valuef(name, expected_value, flags, "%s (ignore_errors=%s)", path, yes_no(ignore));
daf71ef6
LP
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)
255b1fc8 1374 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
daf71ef6
LP
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)
255b1fc8 1392 bus_print_property_valuef(name, expected_value, flags, "%s (%s)", path, type);
daf71ef6
LP
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
5291f26d 1410 while ((r = sd_bus_message_read(m, "(stt)", &base, &v, &next_elapse)) > 0)
255b1fc8 1411 bus_print_property_valuef(name, expected_value, flags,
5291f26d
ZJS
1412 "{ %s=%s ; next_elapse=%s }",
1413 base,
1414 strna(FORMAT_TIMESPAN(v, 0)),
1415 strna(FORMAT_TIMESPAN(next_elapse, 0)));
daf71ef6
LP
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
0086ef19 1433 while ((r = sd_bus_message_read(m, "(sst)", &base, &spec, &next_elapse)) > 0)
255b1fc8 1434 bus_print_property_valuef(name, expected_value, flags,
0086ef19
ZJS
1435 "{ %s=%s ; next_elapse=%s }", base, spec,
1436 FORMAT_TIMESTAMP_STYLE(next_elapse, arg_timestamp_style));
daf71ef6
LP
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) {
daf71ef6 1455 _cleanup_strv_free_ char **optv = NULL;
c2b2df60 1456 _cleanup_free_ char *tt = NULL, *o = NULL;
daf71ef6
LP
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
255b1fc8 1467 bus_print_property_valuef(name, expected_value, flags,
daf71ef6
LP
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),
0086ef19
ZJS
1472 strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
1473 strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
daf71ef6
LP
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
255b1fc8 1480 bus_print_property_valuef(name, expected_value, flags,
daf71ef6
LP
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),
0086ef19
ZJS
1485 strna(FORMAT_TIMESTAMP_STYLE(info.start_timestamp, arg_timestamp_style)),
1486 strna(FORMAT_TIMESTAMP_STYLE(info.exit_timestamp, arg_timestamp_style)),
daf71ef6
LP
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)
255b1fc8 1512 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path), strna(rwm));
daf71ef6
LP
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
5fde5c03 1522 } else if (contents[0] == SD_BUS_TYPE_STRUCT_BEGIN && streq(name, "IODeviceWeight")) {
daf71ef6
LP
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)
255b1fc8 1531 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), weight);
daf71ef6
LP
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 &&
5fde5c03 1542 cgroup_io_limit_type_from_string(name) >= 0) {
daf71ef6
LP
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)
255b1fc8 1551 bus_print_property_valuef(name, expected_value, flags, "%s %"PRIu64, strna(path), bandwidth);
daf71ef6
LP
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")) {
daf71ef6
LP
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)
255b1fc8 1571 bus_print_property_valuef(name, expected_value, flags, "%s %s", strna(path),
5291f26d 1572 FORMAT_TIMESPAN(target, 1));
daf71ef6
LP
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
255b1fc8 1596 bus_print_property_value(name, expected_value, flags, h);
daf71ef6
LP
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 (;;) {
daf71ef6
LP
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
c71384a9
ZJS
1644 if (!strextend_with_separator(&addresses, " ",
1645 IN_ADDR_PREFIX_TO_STRING(family, ap, prefixlen)))
daf71ef6
LP
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
255b1fc8 1653 bus_print_property_value(name, expected_value, flags, addresses);
daf71ef6
LP
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
c2bc710b 1681 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
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
255b1fc8 1691 bus_print_property_value(name, expected_value, flags, paths);
daf71ef6
LP
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
c2bc710b 1712 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
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
255b1fc8 1722 bus_print_property_value(name, expected_value, flags, paths);
daf71ef6
LP
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
c2bc710b 1759 if (!strextend_with_separator(&fields, " ", str))
daf71ef6
LP
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
255b1fc8 1769 bus_print_property_value(name, expected_value, flags, fields);
daf71ef6
LP
1770
1771 return 1;
255b1fc8
YW
1772 } else if (contents[0] == SD_BUS_TYPE_BYTE &&
1773 STR_IN_SET(name,
1774 "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes",
1775 "EffectiveCPUs", "EffectiveMemoryNodes")) {
1776
daf71ef6 1777 _cleanup_free_ char *affinity = NULL;
296fe3d5 1778 _cleanup_(cpu_set_done) CPUSet set = {};
daf71ef6
LP
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
255b1fc8 1794 bus_print_property_value(name, expected_value, flags, affinity);
daf71ef6 1795
c00b95d5
QD
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
daf71ef6 1814 return 1;
69c751c6
ZJS
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
daf71ef6
LP
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)
8ec6108c
LB
1852 return bus_log_parse_error(r);
1853 if (r == 0)
1854 break;
daf71ef6
LP
1855
1856 r = sd_bus_message_read(m, "ssb", &source, &destination, &ignore_enoent);
8ec6108c
LB
1857 if (r < 0)
1858 return bus_log_parse_error(r);
daf71ef6
LP
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)
8ec6108c 1869 return bus_log_parse_error(r);
daf71ef6 1870
742a011a 1871 while ((r = sd_bus_message_read(m, "(ss)", &partition, &mount_options)) > 0)
8ec6108c 1872 if (!strextend_with_separator(&str, ":", partition, mount_options))
daf71ef6 1873 return log_oom();
daf71ef6 1874 if (r < 0)
8ec6108c 1875 return bus_log_parse_error(r);
daf71ef6 1876
c2bc710b 1877 if (!strextend_with_separator(&paths, " ", str))
daf71ef6
LP
1878 return log_oom();
1879
1880 r = sd_bus_message_exit_container(m);
1881 if (r < 0)
8ec6108c 1882 return bus_log_parse_error(r);
daf71ef6
LP
1883
1884 r = sd_bus_message_exit_container(m);
1885 if (r < 0)
8ec6108c 1886 return bus_log_parse_error(r);
daf71ef6 1887 }
daf71ef6
LP
1888
1889 r = sd_bus_message_exit_container(m);
1890 if (r < 0)
1891 return bus_log_parse_error(r);
1892
255b1fc8 1893 bus_print_property_value(name, expected_value, flags, paths);
60c16c5c
LB
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);
daf71ef6
LP
1950
1951 return 1;
1952
9e009a14
JK
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)
255b1fc8 1961 bus_print_property_valuef(name, expected_value, flags, "%s:%s", a, p);
9e009a14
JK
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);
18ef723e
JK
1968
1969 return 1;
1970 } else if (STR_IN_SET(name, "SocketBindAllow", "SocketBindDeny")) {
1971 uint16_t nr_ports, port_min;
4883a04f 1972 int32_t af, ip_protocol;
18ef723e 1973
4883a04f 1974 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(iiqq)");
18ef723e
JK
1975 if (r < 0)
1976 return bus_log_parse_error(r);
4883a04f 1977 while ((r = sd_bus_message_read(m, "(iiqq)", &af, &ip_protocol, &nr_ports, &port_min)) > 0) {
60477eb9 1978 const char *family, *colon1, *protocol = "", *colon2 = "";
a4817536
LP
1979
1980 family = strempty(af_to_ipv4_ipv6(af));
60477eb9
JK
1981 colon1 = isempty(family) ? "" : ":";
1982
1983 if (ip_protocol != 0) {
1984 protocol = ip_protocol_to_tcp_udp(ip_protocol);
1985 colon2 = "";
1986 }
a4817536 1987
18ef723e 1988 if (nr_ports == 0)
60477eb9
JK
1989 bus_print_property_valuef(name, expected_value, flags, "%s%s%s%sany",
1990 family, colon1, protocol, colon2);
18ef723e
JK
1991 else if (nr_ports == 1)
1992 bus_print_property_valuef(
60477eb9
JK
1993 name, expected_value, flags, "%s%s%s%s%hu",
1994 family, colon1, protocol, colon2, port_min);
18ef723e
JK
1995 else
1996 bus_print_property_valuef(
60477eb9
JK
1997 name, expected_value, flags, "%s%s%s%s%hu-%hu",
1998 family, colon1, protocol, colon2, port_min,
18ef723e
JK
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);
9e009a14
JK
2007
2008 return 1;
211a3d87
LB
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
cd48e23f
RP
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
3543456f
RW
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
211a3d87 2073 return 1;
daf71ef6
LP
2074 }
2075
2076 break;
2077 }
2078
2079 return 0;
2080}
2081
2082typedef enum SystemctlShowMode{
2083 SYSTEMCTL_SHOW_PROPERTIES,
2084 SYSTEMCTL_SHOW_STATUS,
2085 SYSTEMCTL_SHOW_HELP,
2086 _SYSTEMCTL_SHOW_MODE_MAX,
2d93c20e 2087 _SYSTEMCTL_SHOW_MODE_INVALID = -EINVAL,
daf71ef6
LP
2088} SystemctlShowMode;
2089
2090static const char* const systemctl_show_mode_table[_SYSTEMCTL_SHOW_MODE_MAX] = {
2091 [SYSTEMCTL_SHOW_PROPERTIES] = "show",
8dc40c25
ZJS
2092 [SYSTEMCTL_SHOW_STATUS] = "status",
2093 [SYSTEMCTL_SHOW_HELP] = "help",
daf71ef6
LP
2094};
2095
2096DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode, SystemctlShowMode);
2097
2098static 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[] = {
538291b0 2107 { "Id", "s", NULL, offsetof(UnitStatusInfo, id) },
daf71ef6
LP
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) },
b1ec4836 2119 { "Job", "(uo)", bus_map_job_id, offsetof(UnitStatusInfo, job_id) },
daf71ef6
LP
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) },
f1d345ed
LP
2138 { "RuntimeMaxUSec", "t", NULL, offsetof(UnitStatusInfo, runtime_max_sec) },
2139 { "InvocationID", "s", bus_map_id128, offsetof(UnitStatusInfo, invocation_id) },
daf71ef6
LP
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) },
daf71ef6 2145 { "PIDFile", "s", NULL, offsetof(UnitStatusInfo, pid_file) },
f488e97a 2146 { "StatusText", "s", NULL, offsetof(UnitStatusInfo, status_text) },
daf71ef6 2147 { "StatusErrno", "i", NULL, offsetof(UnitStatusInfo, status_errno) },
f488e97a
MY
2148 { "StatusBusError", "s", NULL, offsetof(UnitStatusInfo, status_bus_error) },
2149 { "StatusVarlinkError", "s", NULL, offsetof(UnitStatusInfo, status_varlink_error) },
8489c294
LP
2150 { "FileDescriptorStoreMax", "u", NULL, offsetof(UnitStatusInfo, fd_store_max) },
2151 { "NFileDescriptorStore", "u", NULL, offsetof(UnitStatusInfo, n_fd_store) },
daf71ef6
LP
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) },
9ca16f6f
LP
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) },
daf71ef6 2176 { "MemoryCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_current) },
6c71db76 2177 { "MemoryPeak", "t", NULL, offsetof(UnitStatusInfo, memory_peak) },
37533c94 2178 { "MemorySwapCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_swap_current) },
aac3384e 2179 { "MemorySwapPeak", "t", NULL, offsetof(UnitStatusInfo, memory_swap_peak) },
58cde42f 2180 { "MemoryZSwapCurrent", "t", NULL, offsetof(UnitStatusInfo, memory_zswap_current) },
93ff34e4 2181 { "MemoryAvailable", "t", NULL, offsetof(UnitStatusInfo, memory_available) },
daf71ef6
LP
2182 { "DefaultMemoryMin", "t", NULL, offsetof(UnitStatusInfo, default_memory_min) },
2183 { "DefaultMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_memory_low) },
53fda560 2184 { "DefaultStartupMemoryLow", "t", NULL, offsetof(UnitStatusInfo, default_startup_memory_low) },
daf71ef6
LP
2185 { "MemoryMin", "t", NULL, offsetof(UnitStatusInfo, memory_min) },
2186 { "MemoryLow", "t", NULL, offsetof(UnitStatusInfo, memory_low) },
53fda560 2187 { "StartupMemoryLow", "t", NULL, offsetof(UnitStatusInfo, startup_memory_low) },
daf71ef6 2188 { "MemoryHigh", "t", NULL, offsetof(UnitStatusInfo, memory_high) },
53fda560 2189 { "StartupMemoryHigh", "t", NULL, offsetof(UnitStatusInfo, startup_memory_high) },
daf71ef6 2190 { "MemoryMax", "t", NULL, offsetof(UnitStatusInfo, memory_max) },
53fda560 2191 { "StartupMemoryMax", "t", NULL, offsetof(UnitStatusInfo, startup_memory_max) },
daf71ef6 2192 { "MemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_swap_max) },
53fda560 2193 { "StartupMemorySwapMax", "t", NULL, offsetof(UnitStatusInfo, startup_memory_swap_max) },
d7fe0a67 2194 { "MemoryZSwapMax", "t", NULL, offsetof(UnitStatusInfo, memory_zswap_max) },
53fda560 2195 { "StartupMemoryZSwapMax", "t", NULL, offsetof(UnitStatusInfo, startup_memory_zswap_max) },
daf71ef6
LP
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;
6e8c5e97 2225 _cleanup_(unit_status_info_done) UnitStatusInfo info = {
b59052be 2226 .runtime_max_sec = USEC_INFINITY,
f5fbe71d 2227 .memory_current = UINT64_MAX,
daf71ef6 2228 .memory_high = CGROUP_LIMIT_MAX,
5f68f63e 2229 .startup_memory_high = CGROUP_LIMIT_MAX,
daf71ef6 2230 .memory_max = CGROUP_LIMIT_MAX,
5f68f63e 2231 .startup_memory_max = CGROUP_LIMIT_MAX,
daf71ef6 2232 .memory_swap_max = CGROUP_LIMIT_MAX,
5f68f63e 2233 .startup_memory_swap_max = CGROUP_LIMIT_MAX,
d7fe0a67 2234 .memory_zswap_max = CGROUP_LIMIT_MAX,
5f68f63e
LP
2235 .startup_memory_zswap_max = CGROUP_LIMIT_MAX,
2236 .memory_limit = CGROUP_LIMIT_MAX,
6c71db76 2237 .memory_peak = CGROUP_LIMIT_MAX,
37533c94 2238 .memory_swap_current = CGROUP_LIMIT_MAX,
aac3384e 2239 .memory_swap_peak = CGROUP_LIMIT_MAX,
26caa668 2240 .memory_zswap_current = CGROUP_LIMIT_MAX,
93ff34e4 2241 .memory_available = CGROUP_LIMIT_MAX,
f5fbe71d
YW
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,
daf71ef6
LP
2247 .io_read_bytes = UINT64_MAX,
2248 .io_write_bytes = UINT64_MAX,
2249 };
daf71ef6
LP
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")) {
75312ada 2270 log_full(show_mode == SYSTEMCTL_SHOW_PROPERTIES ? LOG_DEBUG : LOG_ERR,
daf71ef6
LP
2271 "Unit %s could not be found.", unit);
2272
2273 if (show_mode == SYSTEMCTL_SHOW_STATUS)
2274 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN;
ab5d52b7 2275 if (show_mode == SYSTEMCTL_SHOW_HELP)
daf71ef6
LP
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
5162829e 2287 if (info.active_state && !STR_IN_SET(info.active_state, "active", "reloading", "refreshing"))
daf71ef6
LP
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
255b1fc8 2301 r = bus_message_print_all_properties(reply, print_property, arg_properties, arg_print_flags, &found_properties);
daf71ef6
LP
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
daf71ef6
LP
2312static int show_all(
2313 sd_bus *bus,
a6e33464 2314 SystemctlShowMode show_mode,
daf71ef6
LP
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;
daf71ef6
LP
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
384c2c32 2327 pager_open(arg_pager_flags);
daf71ef6
LP
2328
2329 c = (unsigned) r;
2330
2331 typesafe_qsort(unit_infos, c, unit_info_compare);
2332
deaf4b86 2333 for (const UnitInfo *u = unit_infos; u < unit_infos + c; u++) {
daf71ef6
LP
2334 _cleanup_free_ char *p = NULL;
2335
2336 p = unit_dbus_path_from_name(u->id);
2337 if (!p)
2338 return log_oom();
2339
a6e33464 2340 r = show_one(bus, p, u->id, show_mode, new_line, ellipsized);
daf71ef6
LP
2341 if (r < 0)
2342 return r;
ab5d52b7 2343 if (r > 0 && ret == 0)
daf71ef6
LP
2344 ret = r;
2345 }
2346
2347 return ret;
2348}
2349
2350static int show_system_status(sd_bus *bus) {
daf71ef6
LP
2351 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2352 _cleanup_(machine_info_clear) struct machine_info mi = {};
038cae09 2353 static const char prefix[] = " ";
daf71ef6
LP
2354 _cleanup_free_ char *hn = NULL;
2355 const char *on, *off;
038cae09 2356 unsigned c;
daf71ef6
LP
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
1ae9b0cf 2386 printf("%s%s%s %s\n", on, glyph(GLYPH_BLACK_CIRCLE), off, arg_host ?: hn);
daf71ef6
LP
2387
2388 printf(" State: %s%s%s\n",
2389 on, strna(mi.state), off);
2390
45bff9b4 2391 printf(" Units: %" PRIu32 " loaded (incl. loaded aliases)\n", mi.n_names);
daf71ef6
LP
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",
0086ef19 2396 FORMAT_TIMESTAMP_STYLE(mi.timestamp, arg_timestamp_style),
32fc5c47 2397 FORMAT_TIMESTAMP_RELATIVE(mi.timestamp));
daf71ef6 2398
45bff9b4
LP
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
27ba2ad2 2404 printf(" CGroup: %s\n", empty_to_root(mi.control_group));
daf71ef6 2405
038cae09 2406 c = LESS_BY(columns(), strlen(prefix));
daf71ef6 2407
038cae09
LP
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 */
daf71ef6 2410 show_cgroup(SYSTEMD_CGROUP_CONTROLLER, strempty(mi.control_group), prefix, c, get_output_flags());
038cae09
LP
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));
daf71ef6
LP
2414
2415 return 0;
2416}
2417
32baf64d 2418int verb_show(int argc, char *argv[], void *userdata) {
daf71ef6
LP
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)
71fae19e 2428 return log_error_errno(show_mode, "Invalid argument '%s'.", argv[0]);
daf71ef6
LP
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
384c2c32 2439 pager_open(arg_pager_flags);
daf71ef6 2440
a6e33464
ZJS
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)
0b51a1c8
YW
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);
a6e33464
ZJS
2456 if (r < 0)
2457 return r;
daf71ef6 2458
a6e33464
ZJS
2459 new_line = true;
2460 }
daf71ef6 2461
a6e33464
ZJS
2462 if (arg_all || arg_states || arg_types)
2463 ret = show_all(bus, show_mode, &new_line, &ellipsized);
daf71ef6
LP
2464 } else {
2465 _cleanup_free_ char **patterns = NULL;
daf71ef6
LP
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 */
d95705cc 2483 r = lookup_unit_by_pidref(bus, (pid_t) id, &unit, &path);
daf71ef6 2484 if (r < 0) {
d95705cc 2485 RET_GATHER(ret, r);
daf71ef6
LP
2486 continue;
2487 }
daf71ef6
LP
2488 }
2489
2490 r = show_one(bus, path, unit, show_mode, &new_line, &ellipsized);
2491 if (r < 0)
2492 return r;
ab5d52b7 2493 if (r > 0 && ret == 0)
daf71ef6
LP
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) {
c2b2df60 2509 _cleanup_free_ char *path = NULL;
daf71ef6
LP
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}