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