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