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