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