1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
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"
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 "string-table.h"
33 #include "systemctl-list-machines.h"
34 #include "systemctl-list-units.h"
35 #include "systemctl-show.h"
36 #include "systemctl-sysv-compat.h"
37 #include "systemctl-util.h"
38 #include "systemctl.h"
39 #include "terminal-util.h"
42 static OutputFlags
get_output_flags(void) {
44 FLAGS_SET(arg_print_flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) * OUTPUT_SHOW_ALL
|
45 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
46 colors_enabled() * OUTPUT_COLOR
|
47 !arg_quiet
* OUTPUT_WARN_CUTOFF
;
50 typedef struct ExecStatusInfo
{
58 usec_t start_timestamp
;
59 usec_t exit_timestamp
;
64 ExecCommandFlags flags
;
66 LIST_FIELDS(struct ExecStatusInfo
, exec
);
69 static void exec_status_info_free(ExecStatusInfo
*i
) {
78 static int exec_status_info_deserialize(sd_bus_message
*m
, ExecStatusInfo
*i
, bool is_ex_prop
) {
79 _cleanup_strv_free_
char **ex_opts
= NULL
;
80 uint64_t start_timestamp
, exit_timestamp
, start_timestamp_monotonic
, exit_timestamp_monotonic
;
89 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, is_ex_prop
? "sasasttttuii" : "sasbttttuii");
91 return bus_log_parse_error(r
);
95 r
= sd_bus_message_read(m
, "s", &path
);
97 return bus_log_parse_error(r
);
99 i
->path
= strdup(path
);
103 r
= sd_bus_message_read_strv(m
, &i
->argv
);
105 return bus_log_parse_error(r
);
107 r
= is_ex_prop
? sd_bus_message_read_strv(m
, &ex_opts
) : sd_bus_message_read(m
, "b", &ignore
);
109 return bus_log_parse_error(r
);
111 r
= sd_bus_message_read(m
,
113 &start_timestamp
, &start_timestamp_monotonic
,
114 &exit_timestamp
, &exit_timestamp_monotonic
,
118 return bus_log_parse_error(r
);
121 r
= exec_command_flags_from_strv(ex_opts
, &i
->flags
);
123 return log_error_errno(r
, "Failed to convert strv to ExecCommandFlags: %m");
125 i
->ignore
= FLAGS_SET(i
->flags
, EXEC_COMMAND_IGNORE_FAILURE
);
129 i
->start_timestamp
= (usec_t
) start_timestamp
;
130 i
->exit_timestamp
= (usec_t
) exit_timestamp
;
131 i
->pid
= (pid_t
) pid
;
135 r
= sd_bus_message_exit_container(m
);
137 return bus_log_parse_error(r
);
142 typedef struct UnitCondition
{
149 LIST_FIELDS(struct UnitCondition
, conditions
);
152 static UnitCondition
* unit_condition_free(UnitCondition
*c
) {
160 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition
*, unit_condition_free
);
162 typedef struct UnitStatusInfo
{
164 const char *load_state
;
165 const char *active_state
;
166 const char *freezer_state
;
167 const char *sub_state
;
168 const char *unit_file_state
;
169 const char *unit_file_preset
;
171 const char *description
;
172 const char *following
;
174 char **documentation
;
176 const char *fragment_path
;
177 const char *source_path
;
178 const char *control_group
;
185 const char *load_error
;
188 usec_t inactive_exit_timestamp
;
189 usec_t inactive_exit_timestamp_monotonic
;
190 usec_t active_enter_timestamp
;
191 usec_t active_exit_timestamp
;
192 usec_t inactive_enter_timestamp
;
194 bool need_daemon_reload
;
200 const char *status_text
;
201 const char *pid_file
;
205 usec_t start_timestamp
;
206 usec_t exit_timestamp
;
208 int exit_code
, exit_status
;
210 const char *log_namespace
;
212 usec_t condition_timestamp
;
213 bool condition_result
;
214 LIST_HEAD(UnitCondition
, conditions
);
216 usec_t assert_timestamp
;
218 bool failed_assert_trigger
;
219 bool failed_assert_negate
;
220 const char *failed_assert
;
221 const char *failed_assert_parameter
;
222 usec_t next_elapse_real
;
223 usec_t next_elapse_monotonic
;
227 unsigned n_connections
;
231 /* Pairs of type, path */
235 const char *sysfs_path
;
237 /* Mount, Automount */
244 uint64_t memory_current
;
247 uint64_t memory_high
;
249 uint64_t memory_swap_max
;
250 uint64_t memory_limit
;
251 uint64_t memory_available
;
252 uint64_t cpu_usage_nsec
;
253 uint64_t tasks_current
;
255 uint64_t ip_ingress_bytes
;
256 uint64_t ip_egress_bytes
;
257 uint64_t io_read_bytes
;
258 uint64_t io_write_bytes
;
260 uint64_t default_memory_min
;
261 uint64_t default_memory_low
;
263 LIST_HEAD(ExecStatusInfo
, exec
);
266 static void unit_status_info_free(UnitStatusInfo
*info
) {
270 strv_free(info
->documentation
);
271 strv_free(info
->dropin_paths
);
272 strv_free(info
->triggered_by
);
273 strv_free(info
->triggers
);
274 strv_free(info
->listen
);
276 while ((c
= info
->conditions
)) {
277 LIST_REMOVE(conditions
, info
->conditions
, c
);
278 unit_condition_free(c
);
281 while ((p
= info
->exec
)) {
282 LIST_REMOVE(exec
, info
->exec
, p
);
283 exec_status_info_free(p
);
287 static void format_active_state(const char *active_state
, const char **active_on
, const char **active_off
) {
288 if (streq_ptr(active_state
, "failed")) {
289 *active_on
= ansi_highlight_red();
290 *active_off
= ansi_normal();
291 } else if (STRPTR_IN_SET(active_state
, "active", "reloading")) {
292 *active_on
= ansi_highlight_green();
293 *active_off
= ansi_normal();
295 *active_on
= *active_off
= "";
298 static void print_status_info(
303 const char *active_on
, *active_off
, *on
, *off
, *ss
, *fs
;
304 _cleanup_free_
char *formatted_path
= NULL
;
313 /* This shows pretty information about a unit. See print_property() for a low-level property
316 format_active_state(i
->active_state
, &active_on
, &active_off
);
318 const SpecialGlyph glyph
= unit_active_state_to_glyph(unit_active_state_from_string(i
->active_state
));
320 printf("%s%s%s %s", active_on
, special_glyph(glyph
), active_off
, strna(i
->id
));
322 if (i
->description
&& !streq_ptr(i
->id
, i
->description
))
323 printf(" - %s", i
->description
);
328 printf(" Follows: unit currently follows state of %s\n", i
->following
);
330 if (STRPTR_IN_SET(i
->load_state
, "error", "not-found", "bad-setting")) {
331 on
= ansi_highlight_red();
336 path
= i
->source_path
?: i
->fragment_path
;
337 if (path
&& terminal_urlify_path(path
, NULL
, &formatted_path
) >= 0)
338 path
= formatted_path
;
340 if (!isempty(i
->load_error
))
341 printf(" Loaded: %s%s%s (Reason: %s)\n",
342 on
, strna(i
->load_state
), off
, i
->load_error
);
343 else if (path
&& !isempty(i
->unit_file_state
)) {
344 bool show_preset
= !isempty(i
->unit_file_preset
) &&
345 show_preset_for_state(unit_file_state_from_string(i
->unit_file_state
));
347 printf(" Loaded: %s%s%s (%s; %s%s%s)\n",
348 on
, strna(i
->load_state
), off
,
351 show_preset
? "; vendor preset: " : "",
352 show_preset
? i
->unit_file_preset
: "");
355 printf(" Loaded: %s%s%s (%s)\n",
356 on
, strna(i
->load_state
), off
, path
);
358 printf(" Loaded: %s%s%s\n",
359 on
, strna(i
->load_state
), off
);
362 printf(" Transient: yes\n");
364 if (!strv_isempty(i
->dropin_paths
)) {
365 _cleanup_free_
char *dir
= NULL
;
369 STRV_FOREACH(dropin
, i
->dropin_paths
) {
370 _cleanup_free_
char *dropin_formatted
= NULL
;
379 dir
= dirname_malloc(*dropin
);
387 special_glyph(SPECIAL_GLYPH_TREE_RIGHT
));
390 last
= ! (*(dropin
+ 1) && startswith(*(dropin
+ 1), dir
));
392 if (terminal_urlify_path(*dropin
, basename(*dropin
), &dropin_formatted
) >= 0)
393 df
= dropin_formatted
;
397 printf("%s%s", df
, last
? "\n" : ", ");
401 ss
= streq_ptr(i
->active_state
, i
->sub_state
) ? NULL
: i
->sub_state
;
403 printf(" Active: %s%s (%s)%s",
404 active_on
, strna(i
->active_state
), ss
, active_off
);
406 printf(" Active: %s%s%s",
407 active_on
, strna(i
->active_state
), active_off
);
409 fs
= !isempty(i
->freezer_state
) && !streq(i
->freezer_state
, "running") ? i
->freezer_state
: NULL
;
411 printf(" %s(%s)%s", ansi_highlight_yellow(), fs
, ansi_normal());
413 if (!isempty(i
->result
) && !streq(i
->result
, "success"))
414 printf(" (Result: %s)", i
->result
);
416 timestamp
= STRPTR_IN_SET(i
->active_state
, "active", "reloading") ? i
->active_enter_timestamp
:
417 STRPTR_IN_SET(i
->active_state
, "inactive", "failed") ? i
->inactive_enter_timestamp
:
418 STRPTR_IN_SET(i
->active_state
, "activating") ? i
->inactive_exit_timestamp
:
419 i
->active_exit_timestamp
;
421 if (timestamp
> 0 && timestamp
< USEC_INFINITY
)
422 printf(" since %s; %s\n",
423 FORMAT_TIMESTAMP_STYLE(timestamp
, arg_timestamp_style
),
424 FORMAT_TIMESTAMP_RELATIVE(timestamp
));
428 STRV_FOREACH(t
, i
->triggered_by
) {
429 UnitActiveState state
= _UNIT_ACTIVE_STATE_INVALID
;
431 (void) get_state_one_unit(bus
, *t
, &state
);
432 format_active_state(unit_active_state_to_string(state
), &on
, &off
);
434 printf("%s %s%s%s %s\n",
435 t
== i
->triggered_by
? "TriggeredBy:" : " ",
436 on
, special_glyph(unit_active_state_to_glyph(state
)), off
,
440 if (endswith(i
->id
, ".timer")) {
441 dual_timestamp nw
, next
= {i
->next_elapse_real
, i
->next_elapse_monotonic
};
444 dual_timestamp_get(&nw
);
445 next_elapse
= calc_next_elapse(&nw
, &next
);
447 if (next_elapse
> 0 && next_elapse
< USEC_INFINITY
)
448 printf(" Trigger: %s; %s\n",
449 FORMAT_TIMESTAMP_STYLE(next_elapse
, arg_timestamp_style
),
450 FORMAT_TIMESTAMP_RELATIVE(next_elapse
));
452 printf(" Trigger: n/a\n");
455 STRV_FOREACH(t
, i
->triggers
) {
456 UnitActiveState state
= _UNIT_ACTIVE_STATE_INVALID
;
458 (void) get_state_one_unit(bus
, *t
, &state
);
459 format_active_state(unit_active_state_to_string(state
), &on
, &off
);
461 printf("%s %s%s%s %s\n",
462 t
== i
->triggers
? " Triggers:" : " ",
463 on
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off
,
467 if (!i
->condition_result
&& i
->condition_timestamp
> 0) {
471 printf(" Condition: start %scondition failed%s at %s; %s\n",
472 ansi_highlight_yellow(), ansi_normal(),
473 FORMAT_TIMESTAMP_STYLE(i
->condition_timestamp
, arg_timestamp_style
),
474 FORMAT_TIMESTAMP_RELATIVE(i
->condition_timestamp
));
476 LIST_FOREACH(conditions
, c
, i
->conditions
)
480 LIST_FOREACH(conditions
, c
, i
->conditions
)
482 printf(" %s %s=%s%s%s was not met\n",
483 --n
? special_glyph(SPECIAL_GLYPH_TREE_BRANCH
) : special_glyph(SPECIAL_GLYPH_TREE_RIGHT
),
485 c
->trigger
? "|" : "",
486 c
->negate
? "!" : "",
490 if (!i
->assert_result
&& i
->assert_timestamp
> 0) {
491 printf(" Assert: start %sassertion failed%s at %s; %s\n",
492 ansi_highlight_red(), ansi_normal(),
493 FORMAT_TIMESTAMP_STYLE(i
->assert_timestamp
, arg_timestamp_style
),
494 FORMAT_TIMESTAMP_RELATIVE(i
->assert_timestamp
));
495 if (i
->failed_assert_trigger
)
496 printf(" none of the trigger assertions were met\n");
497 else if (i
->failed_assert
)
498 printf(" %s=%s%s was not met\n",
500 i
->failed_assert_negate
? "!" : "",
501 i
->failed_assert_parameter
);
505 printf(" Device: %s\n", i
->sysfs_path
);
507 printf(" Where: %s\n", i
->where
);
509 printf(" What: %s\n", i
->what
);
511 STRV_FOREACH(t
, i
->documentation
) {
512 _cleanup_free_
char *formatted
= NULL
;
515 if (terminal_urlify(*t
, NULL
, &formatted
) >= 0)
520 printf(" %*s %s\n", 9, t
== i
->documentation
? "Docs:" : "", q
);
523 STRV_FOREACH_PAIR(t
, t2
, i
->listen
)
524 printf(" %*s %s (%s)\n", 9, t
== i
->listen
? "Listen:" : "", *t2
, *t
);
527 printf(" Accepted: %u; Connected: %u;", i
->n_accepted
, i
->n_connections
);
529 printf(" Refused: %u", i
->n_refused
);
533 LIST_FOREACH(exec
, p
, i
->exec
) {
534 _cleanup_free_
char *argv
= NULL
;
537 /* Only show exited processes here */
541 /* Don't print ExecXYZEx= properties here since it will appear as a
542 * duplicate of the non-Ex= variant. */
543 if (endswith(p
->name
, "Ex"))
546 argv
= strv_join(p
->argv
, " ");
547 printf(" Process: "PID_FMT
" %s=%s ", p
->pid
, p
->name
, strna(argv
));
549 good
= is_clean_exit(p
->code
, p
->status
, EXIT_CLEAN_DAEMON
, NULL
);
551 on
= ansi_highlight_red();
556 printf("%s(code=%s, ", on
, sigchld_code_to_string(p
->code
));
558 if (p
->code
== CLD_EXITED
) {
561 printf("status=%i", p
->status
);
563 c
= exit_status_to_string(p
->status
, EXIT_STATUS_LIBC
| EXIT_STATUS_SYSTEMD
);
568 printf("signal=%s", signal_to_string(p
->status
));
570 printf(")%s\n", off
);
572 if (i
->main_pid
== p
->pid
&&
573 i
->start_timestamp
== p
->start_timestamp
&&
574 i
->exit_timestamp
== p
->start_timestamp
)
575 /* Let's not show this twice */
578 if (p
->pid
== i
->control_pid
)
582 if (i
->main_pid
> 0 || i
->control_pid
> 0) {
583 if (i
->main_pid
> 0) {
584 printf(" Main PID: "PID_FMT
, i
->main_pid
);
588 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
589 _cleanup_free_
char *comm
= NULL
;
591 (void) get_process_comm(i
->main_pid
, &comm
);
593 printf(" (%s)", comm
);
596 } else if (i
->exit_code
> 0) {
597 printf(" (code=%s, ", sigchld_code_to_string(i
->exit_code
));
599 if (i
->exit_code
== CLD_EXITED
) {
602 printf("status=%i", i
->exit_status
);
604 c
= exit_status_to_string(i
->exit_status
,
605 EXIT_STATUS_LIBC
| EXIT_STATUS_SYSTEMD
);
610 printf("signal=%s", signal_to_string(i
->exit_status
));
615 if (i
->control_pid
> 0) {
616 _cleanup_free_
char *c
= NULL
;
619 fputs("; Control PID: ", stdout
);
621 fputs("Cntrl PID: ", stdout
); /* if first in column, abbreviated so it fits alignment */
623 printf(PID_FMT
, i
->control_pid
);
625 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
626 (void) get_process_comm(i
->control_pid
, &c
);
636 printf(" Status: \"%s\"\n", i
->status_text
);
637 if (i
->status_errno
> 0)
638 printf(" Error: %i (%s)\n", i
->status_errno
, strerror_safe(i
->status_errno
));
640 if (i
->ip_ingress_bytes
!= UINT64_MAX
&& i
->ip_egress_bytes
!= UINT64_MAX
)
641 printf(" IP: %s in, %s out\n",
642 FORMAT_BYTES(i
->ip_ingress_bytes
),
643 FORMAT_BYTES(i
->ip_egress_bytes
));
645 if (i
->io_read_bytes
!= UINT64_MAX
&& i
->io_write_bytes
!= UINT64_MAX
)
646 printf(" IO: %s read, %s written\n",
647 FORMAT_BYTES(i
->io_read_bytes
),
648 FORMAT_BYTES(i
->io_write_bytes
));
650 if (i
->tasks_current
!= UINT64_MAX
) {
651 printf(" Tasks: %" PRIu64
, i
->tasks_current
);
653 if (i
->tasks_max
!= UINT64_MAX
)
654 printf(" (limit: %" PRIu64
")\n", i
->tasks_max
);
659 if (i
->memory_current
!= UINT64_MAX
) {
660 printf(" Memory: %s", FORMAT_BYTES(i
->memory_current
));
662 if (i
->memory_min
> 0 || i
->memory_low
> 0 ||
663 i
->memory_high
!= CGROUP_LIMIT_MAX
|| i
->memory_max
!= CGROUP_LIMIT_MAX
||
664 i
->memory_swap_max
!= CGROUP_LIMIT_MAX
||
665 i
->memory_available
!= CGROUP_LIMIT_MAX
||
666 i
->memory_limit
!= CGROUP_LIMIT_MAX
) {
667 const char *prefix
= "";
670 if (i
->memory_min
> 0) {
671 printf("%smin: %s", prefix
, FORMAT_BYTES_CGROUP_PROTECTION(i
->memory_min
));
674 if (i
->memory_low
> 0) {
675 printf("%slow: %s", prefix
, FORMAT_BYTES_CGROUP_PROTECTION(i
->memory_low
));
678 if (i
->memory_high
!= CGROUP_LIMIT_MAX
) {
679 printf("%shigh: %s", prefix
, FORMAT_BYTES(i
->memory_high
));
682 if (i
->memory_max
!= CGROUP_LIMIT_MAX
) {
683 printf("%smax: %s", prefix
, FORMAT_BYTES(i
->memory_max
));
686 if (i
->memory_swap_max
!= CGROUP_LIMIT_MAX
) {
687 printf("%sswap max: %s", prefix
, FORMAT_BYTES(i
->memory_swap_max
));
690 if (i
->memory_limit
!= CGROUP_LIMIT_MAX
) {
691 printf("%slimit: %s", prefix
, FORMAT_BYTES(i
->memory_limit
));
694 if (i
->memory_available
!= CGROUP_LIMIT_MAX
) {
695 printf("%savailable: %s", prefix
, FORMAT_BYTES(i
->memory_available
));
703 if (i
->cpu_usage_nsec
!= UINT64_MAX
)
704 printf(" CPU: %s\n", FORMAT_TIMESPAN(i
->cpu_usage_nsec
/ NSEC_PER_USEC
, USEC_PER_MSEC
));
706 if (i
->control_group
) {
707 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
708 static const char prefix
[] = " ";
711 printf(" CGroup: %s\n", i
->control_group
);
714 if (c
> sizeof(prefix
) - 1)
715 c
-= sizeof(prefix
) - 1;
719 r
= unit_show_processes(bus
, i
->id
, i
->control_group
, prefix
, c
, get_output_flags(), &error
);
724 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
727 extra
[k
++] = i
->main_pid
;
729 if (i
->control_pid
> 0)
730 extra
[k
++] = i
->control_pid
;
732 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, i
->control_group
, prefix
, c
, extra
, k
, get_output_flags());
734 log_warning_errno(r
, "Failed to dump process list for '%s', ignoring: %s",
735 i
->id
, bus_error_message(&error
, r
));
738 if (i
->id
&& arg_transport
== BUS_TRANSPORT_LOCAL
)
739 show_journal_by_unit(
745 i
->inactive_exit_timestamp_monotonic
,
748 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
749 SD_JOURNAL_LOCAL_ONLY
,
750 arg_scope
== UNIT_FILE_SYSTEM
,
753 if (i
->need_daemon_reload
)
754 warn_unit_file_changed(i
->id
);
757 static void show_unit_help(UnitStatusInfo
*i
) {
762 if (!i
->documentation
) {
763 log_info("Documentation for %s not known.", i
->id
);
767 STRV_FOREACH(p
, i
->documentation
)
768 if (startswith(*p
, "man:"))
769 show_man_page(*p
+ 4, false);
771 log_info("Can't show: %s", *p
);
774 static int map_main_pid(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
775 UnitStatusInfo
*i
= userdata
;
779 r
= sd_bus_message_read(m
, "u", &u
);
783 i
->main_pid
= (pid_t
) u
;
789 static int map_load_error(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
790 const char *message
, **p
= userdata
;
793 r
= sd_bus_message_read(m
, "(ss)", NULL
, &message
);
797 if (!isempty(message
))
803 static int map_listen(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
804 const char *type
, *path
;
805 char ***p
= userdata
;
808 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
812 while ((r
= sd_bus_message_read(m
, "(ss)", &type
, &path
)) > 0) {
814 r
= strv_extend(p
, type
);
818 r
= strv_extend(p
, path
);
825 r
= sd_bus_message_exit_container(m
);
832 static int map_conditions(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
833 UnitStatusInfo
*i
= userdata
;
834 const char *cond
, *param
;
839 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sbbsi)");
843 while ((r
= sd_bus_message_read(m
, "(sbbsi)", &cond
, &trigger
, &negate
, ¶m
, &state
)) > 0) {
844 _cleanup_(unit_condition_freep
) UnitCondition
*c
= NULL
;
846 c
= new(UnitCondition
, 1);
850 *c
= (UnitCondition
) {
851 .name
= strdup(cond
),
852 .param
= strdup(param
),
858 if (!c
->name
|| !c
->param
)
861 LIST_PREPEND(conditions
, i
->conditions
, TAKE_PTR(c
));
866 r
= sd_bus_message_exit_container(m
);
873 static int map_asserts(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
874 UnitStatusInfo
*i
= userdata
;
875 const char *cond
, *param
;
880 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sbbsi)");
884 while ((r
= sd_bus_message_read(m
, "(sbbsi)", &cond
, &trigger
, &negate
, ¶m
, &state
)) > 0) {
885 if (state
< 0 && (!trigger
|| !i
->failed_assert
)) {
886 i
->failed_assert
= cond
;
887 i
->failed_assert_trigger
= trigger
;
888 i
->failed_assert_negate
= negate
;
889 i
->failed_assert_parameter
= param
;
895 r
= sd_bus_message_exit_container(m
);
902 static int map_exec(sd_bus
*bus
, const char *member
, sd_bus_message
*m
, sd_bus_error
*error
, void *userdata
) {
903 _cleanup_free_ ExecStatusInfo
*info
= NULL
;
904 ExecStatusInfo
*last
;
905 UnitStatusInfo
*i
= userdata
;
906 bool is_ex_prop
= endswith(member
, "Ex");
909 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, is_ex_prop
? "(sasasttttuii)" : "(sasbttttuii)");
913 info
= new0(ExecStatusInfo
, 1);
917 LIST_FIND_TAIL(exec
, i
->exec
, last
);
919 while ((r
= exec_status_info_deserialize(m
, info
, is_ex_prop
)) > 0) {
921 info
->name
= strdup(member
);
925 LIST_INSERT_AFTER(exec
, i
->exec
, last
, info
);
928 info
= new0(ExecStatusInfo
, 1);
935 r
= sd_bus_message_exit_container(m
);
942 static int print_property(const char *name
, const char *expected_value
, sd_bus_message
*m
, BusPrintPropertyFlags flags
) {
944 const char *contents
;
950 /* This is a low-level property printer, see print_status_info() for the nicer output */
952 r
= sd_bus_message_peek_type(m
, &bus_type
, &contents
);
958 case SD_BUS_TYPE_INT32
:
959 if (endswith(name
, "ActionExitStatus")) {
962 r
= sd_bus_message_read_basic(m
, bus_type
, &i
);
966 if (i
>= 0 && i
<= 255)
967 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIi32
, i
);
968 else if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
))
969 bus_print_property_value(name
, expected_value
, flags
, "[not set]");
972 } else if (streq(name
, "NUMAPolicy")) {
975 r
= sd_bus_message_read_basic(m
, bus_type
, &i
);
979 bus_print_property_valuef(name
, expected_value
, flags
, "%s", strna(mpol_to_string(i
)));
985 case SD_BUS_TYPE_STRUCT
:
987 if (contents
[0] == SD_BUS_TYPE_UINT32
&& streq(name
, "Job")) {
990 r
= sd_bus_message_read(m
, "(uo)", &u
, NULL
);
992 return bus_log_parse_error(r
);
995 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
997 bus_print_property_value(name
, expected_value
, flags
, NULL
);
1001 } else if (contents
[0] == SD_BUS_TYPE_STRING
&& streq(name
, "Unit")) {
1004 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
1006 return bus_log_parse_error(r
);
1008 bus_print_property_value(name
, expected_value
, flags
, s
);
1012 } else if (contents
[0] == SD_BUS_TYPE_STRING
&& streq(name
, "LoadError")) {
1013 const char *a
= NULL
, *b
= NULL
;
1015 r
= sd_bus_message_read(m
, "(ss)", &a
, &b
);
1017 return bus_log_parse_error(r
);
1019 if (!isempty(a
) || !isempty(b
))
1020 bus_print_property_valuef(name
, expected_value
, flags
, "%s \"%s\"", strempty(a
), strempty(b
));
1022 bus_print_property_value(name
, expected_value
, flags
, NULL
);
1026 } else if (STR_IN_SET(name
, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces")) {
1027 _cleanup_strv_free_
char **l
= NULL
;
1030 r
= sd_bus_message_enter_container(m
, 'r', "bas");
1032 return bus_log_parse_error(r
);
1034 r
= sd_bus_message_read(m
, "b", &allow_list
);
1036 return bus_log_parse_error(r
);
1038 r
= sd_bus_message_read_strv(m
, &l
);
1040 return bus_log_parse_error(r
);
1042 r
= sd_bus_message_exit_container(m
);
1044 return bus_log_parse_error(r
);
1046 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || allow_list
|| !strv_isempty(l
)) {
1050 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
)) {
1051 fputs(name
, stdout
);
1058 STRV_FOREACH(i
, l
) {
1066 fputc('\n', stdout
);
1071 } else if (STR_IN_SET(name
, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
1075 r
= sd_bus_message_read(m
, "(bs)", &ignore
, &s
);
1077 return bus_log_parse_error(r
);
1080 bus_print_property_valuef(name
, expected_value
, flags
, "%s%s", ignore
? "-" : "", s
);
1082 bus_print_property_value(name
, expected_value
, flags
, NULL
);
1086 } else if (endswith(name
, "ExitStatus") && streq(contents
, "aiai")) {
1087 const int32_t *status
, *signal
;
1088 size_t n_status
, n_signal
;
1090 r
= sd_bus_message_enter_container(m
, 'r', "aiai");
1092 return bus_log_parse_error(r
);
1094 r
= sd_bus_message_read_array(m
, 'i', (const void **) &status
, &n_status
);
1096 return bus_log_parse_error(r
);
1098 r
= sd_bus_message_read_array(m
, 'i', (const void **) &signal
, &n_signal
);
1100 return bus_log_parse_error(r
);
1102 r
= sd_bus_message_exit_container(m
);
1104 return bus_log_parse_error(r
);
1106 n_status
/= sizeof(int32_t);
1107 n_signal
/= sizeof(int32_t);
1109 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n_status
> 0 || n_signal
> 0) {
1112 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
)) {
1113 fputs(name
, stdout
);
1117 for (size_t i
= 0; i
< n_status
; i
++) {
1123 printf("%"PRIi32
, status
[i
]);
1126 for (size_t i
= 0; i
< n_signal
; i
++) {
1129 str
= signal_to_string((int) signal
[i
]);
1139 printf("%"PRIi32
, status
[i
]);
1142 fputc('\n', stdout
);
1149 case SD_BUS_TYPE_ARRAY
:
1151 if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "EnvironmentFiles")) {
1155 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sb)");
1157 return bus_log_parse_error(r
);
1159 while ((r
= sd_bus_message_read(m
, "(sb)", &path
, &ignore
)) > 0)
1160 bus_print_property_valuef(name
, expected_value
, flags
, "%s (ignore_errors=%s)", path
, yes_no(ignore
));
1162 return bus_log_parse_error(r
);
1164 r
= sd_bus_message_exit_container(m
);
1166 return bus_log_parse_error(r
);
1170 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Paths")) {
1171 const char *type
, *path
;
1173 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1175 return bus_log_parse_error(r
);
1177 while ((r
= sd_bus_message_read(m
, "(ss)", &type
, &path
)) > 0)
1178 bus_print_property_valuef(name
, expected_value
, flags
, "%s (%s)", path
, type
);
1180 return bus_log_parse_error(r
);
1182 r
= sd_bus_message_exit_container(m
);
1184 return bus_log_parse_error(r
);
1188 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Listen")) {
1189 const char *type
, *path
;
1191 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1193 return bus_log_parse_error(r
);
1195 while ((r
= sd_bus_message_read(m
, "(ss)", &type
, &path
)) > 0)
1196 bus_print_property_valuef(name
, expected_value
, flags
, "%s (%s)", path
, type
);
1198 return bus_log_parse_error(r
);
1200 r
= sd_bus_message_exit_container(m
);
1202 return bus_log_parse_error(r
);
1206 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "TimersMonotonic")) {
1208 uint64_t v
, next_elapse
;
1210 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(stt)");
1212 return bus_log_parse_error(r
);
1214 while ((r
= sd_bus_message_read(m
, "(stt)", &base
, &v
, &next_elapse
)) > 0)
1215 bus_print_property_valuef(name
, expected_value
, flags
,
1216 "{ %s=%s ; next_elapse=%s }",
1218 strna(FORMAT_TIMESPAN(v
, 0)),
1219 strna(FORMAT_TIMESPAN(next_elapse
, 0)));
1221 return bus_log_parse_error(r
);
1223 r
= sd_bus_message_exit_container(m
);
1225 return bus_log_parse_error(r
);
1229 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "TimersCalendar")) {
1230 const char *base
, *spec
;
1231 uint64_t next_elapse
;
1233 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sst)");
1235 return bus_log_parse_error(r
);
1237 while ((r
= sd_bus_message_read(m
, "(sst)", &base
, &spec
, &next_elapse
)) > 0)
1238 bus_print_property_valuef(name
, expected_value
, flags
,
1239 "{ %s=%s ; next_elapse=%s }", base
, spec
,
1240 FORMAT_TIMESTAMP_STYLE(next_elapse
, arg_timestamp_style
));
1242 return bus_log_parse_error(r
);
1244 r
= sd_bus_message_exit_container(m
);
1246 return bus_log_parse_error(r
);
1250 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& startswith(name
, "Exec")) {
1251 ExecStatusInfo info
= {};
1252 bool is_ex_prop
= endswith(name
, "Ex");
1254 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, is_ex_prop
? "(sasasttttuii)" : "(sasbttttuii)");
1256 return bus_log_parse_error(r
);
1258 while ((r
= exec_status_info_deserialize(m
, &info
, is_ex_prop
)) > 0) {
1259 _cleanup_strv_free_
char **optv
= NULL
;
1260 _cleanup_free_
char *tt
= NULL
, *o
= NULL
;
1262 tt
= strv_join(info
.argv
, " ");
1265 r
= exec_command_flags_to_strv(info
.flags
, &optv
);
1267 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
1269 o
= strv_join(optv
, " ");
1271 bus_print_property_valuef(name
, expected_value
, flags
,
1272 "{ path=%s ; argv[]=%s ; flags=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT
" ; code=%s ; status=%i%s%s }",
1276 strna(FORMAT_TIMESTAMP_STYLE(info
.start_timestamp
, arg_timestamp_style
)),
1277 strna(FORMAT_TIMESTAMP_STYLE(info
.exit_timestamp
, arg_timestamp_style
)),
1279 sigchld_code_to_string(info
.code
),
1281 info
.code
== CLD_EXITED
? "" : "/",
1282 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
1284 bus_print_property_valuef(name
, expected_value
, flags
,
1285 "{ path=%s ; argv[]=%s ; ignore_errors=%s ; start_time=[%s] ; stop_time=[%s] ; pid="PID_FMT
" ; code=%s ; status=%i%s%s }",
1288 yes_no(info
.ignore
),
1289 strna(FORMAT_TIMESTAMP_STYLE(info
.start_timestamp
, arg_timestamp_style
)),
1290 strna(FORMAT_TIMESTAMP_STYLE(info
.exit_timestamp
, arg_timestamp_style
)),
1292 sigchld_code_to_string(info
.code
),
1294 info
.code
== CLD_EXITED
? "" : "/",
1295 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
1298 strv_free(info
.argv
);
1302 r
= sd_bus_message_exit_container(m
);
1304 return bus_log_parse_error(r
);
1308 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "DeviceAllow")) {
1309 const char *path
, *rwm
;
1311 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1313 return bus_log_parse_error(r
);
1315 while ((r
= sd_bus_message_read(m
, "(ss)", &path
, &rwm
)) > 0)
1316 bus_print_property_valuef(name
, expected_value
, flags
, "%s %s", strna(path
), strna(rwm
));
1318 return bus_log_parse_error(r
);
1320 r
= sd_bus_message_exit_container(m
);
1322 return bus_log_parse_error(r
);
1326 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&&
1327 STR_IN_SET(name
, "IODeviceWeight", "BlockIODeviceWeight")) {
1331 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1333 return bus_log_parse_error(r
);
1335 while ((r
= sd_bus_message_read(m
, "(st)", &path
, &weight
)) > 0)
1336 bus_print_property_valuef(name
, expected_value
, flags
, "%s %"PRIu64
, strna(path
), weight
);
1338 return bus_log_parse_error(r
);
1340 r
= sd_bus_message_exit_container(m
);
1342 return bus_log_parse_error(r
);
1346 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&&
1347 (cgroup_io_limit_type_from_string(name
) >= 0 ||
1348 STR_IN_SET(name
, "BlockIOReadBandwidth", "BlockIOWriteBandwidth"))) {
1352 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1354 return bus_log_parse_error(r
);
1356 while ((r
= sd_bus_message_read(m
, "(st)", &path
, &bandwidth
)) > 0)
1357 bus_print_property_valuef(name
, expected_value
, flags
, "%s %"PRIu64
, strna(path
), bandwidth
);
1359 return bus_log_parse_error(r
);
1361 r
= sd_bus_message_exit_container(m
);
1363 return bus_log_parse_error(r
);
1367 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&&
1368 streq(name
, "IODeviceLatencyTargetUSec")) {
1372 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1374 return bus_log_parse_error(r
);
1376 while ((r
= sd_bus_message_read(m
, "(st)", &path
, &target
)) > 0)
1377 bus_print_property_valuef(name
, expected_value
, flags
, "%s %s", strna(path
),
1378 FORMAT_TIMESPAN(target
, 1));
1380 return bus_log_parse_error(r
);
1382 r
= sd_bus_message_exit_container(m
);
1384 return bus_log_parse_error(r
);
1388 } else if (contents
[0] == SD_BUS_TYPE_BYTE
&& STR_IN_SET(name
, "StandardInputData", "RootHashSignature")) {
1389 _cleanup_free_
char *h
= NULL
;
1394 r
= sd_bus_message_read_array(m
, 'y', &p
, &sz
);
1396 return bus_log_parse_error(r
);
1398 n
= base64mem(p
, sz
, &h
);
1402 bus_print_property_value(name
, expected_value
, flags
, h
);
1406 } else if (STR_IN_SET(name
, "IPAddressAllow", "IPAddressDeny")) {
1407 _cleanup_free_
char *addresses
= NULL
;
1409 r
= sd_bus_message_enter_container(m
, 'a', "(iayu)");
1411 return bus_log_parse_error(r
);
1414 _cleanup_free_
char *str
= NULL
;
1420 r
= sd_bus_message_enter_container(m
, 'r', "iayu");
1422 return bus_log_parse_error(r
);
1426 r
= sd_bus_message_read(m
, "i", &family
);
1428 return bus_log_parse_error(r
);
1430 r
= sd_bus_message_read_array(m
, 'y', &ap
, &an
);
1432 return bus_log_parse_error(r
);
1434 r
= sd_bus_message_read(m
, "u", &prefixlen
);
1436 return bus_log_parse_error(r
);
1438 r
= sd_bus_message_exit_container(m
);
1440 return bus_log_parse_error(r
);
1442 if (!IN_SET(family
, AF_INET
, AF_INET6
))
1445 if (an
!= FAMILY_ADDRESS_SIZE(family
))
1448 if (prefixlen
> FAMILY_ADDRESS_SIZE(family
) * 8)
1451 if (in_addr_prefix_to_string(family
, (const union in_addr_union
*) ap
, prefixlen
, &str
) < 0)
1454 if (!strextend_with_separator(&addresses
, " ", str
))
1458 r
= sd_bus_message_exit_container(m
);
1460 return bus_log_parse_error(r
);
1462 bus_print_property_value(name
, expected_value
, flags
, addresses
);
1466 } else if (STR_IN_SET(name
, "BindPaths", "BindReadOnlyPaths")) {
1467 _cleanup_free_
char *paths
= NULL
;
1468 const char *source
, *dest
;
1472 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ssbt)");
1474 return bus_log_parse_error(r
);
1476 while ((r
= sd_bus_message_read(m
, "(ssbt)", &source
, &dest
, &ignore_enoent
, &rbind
)) > 0) {
1477 _cleanup_free_
char *str
= NULL
;
1479 if (isempty(source
))
1482 if (asprintf(&str
, "%s%s%s%s%s",
1483 ignore_enoent
? "-" : "",
1485 isempty(dest
) ? "" : ":",
1487 rbind
== MS_REC
? ":rbind" : "") < 0)
1490 if (!strextend_with_separator(&paths
, " ", str
))
1494 return bus_log_parse_error(r
);
1496 r
= sd_bus_message_exit_container(m
);
1498 return bus_log_parse_error(r
);
1500 bus_print_property_value(name
, expected_value
, flags
, paths
);
1504 } else if (streq(name
, "TemporaryFileSystem")) {
1505 _cleanup_free_
char *paths
= NULL
;
1506 const char *target
, *option
;
1508 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1510 return bus_log_parse_error(r
);
1512 while ((r
= sd_bus_message_read(m
, "(ss)", &target
, &option
)) > 0) {
1513 _cleanup_free_
char *str
= NULL
;
1515 if (isempty(target
))
1518 if (asprintf(&str
, "%s%s%s", target
, isempty(option
) ? "" : ":", strempty(option
)) < 0)
1521 if (!strextend_with_separator(&paths
, " ", str
))
1525 return bus_log_parse_error(r
);
1527 r
= sd_bus_message_exit_container(m
);
1529 return bus_log_parse_error(r
);
1531 bus_print_property_value(name
, expected_value
, flags
, paths
);
1535 } else if (streq(name
, "LogExtraFields")) {
1536 _cleanup_free_
char *fields
= NULL
;
1540 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "ay");
1542 return bus_log_parse_error(r
);
1544 while ((r
= sd_bus_message_read_array(m
, 'y', &p
, &sz
)) > 0) {
1545 _cleanup_free_
char *str
= NULL
;
1548 if (memchr(p
, 0, sz
))
1551 eq
= memchr(p
, '=', sz
);
1555 if (!journal_field_valid(p
, eq
- (const char*) p
, false))
1558 str
= malloc(sz
+ 1);
1565 if (!utf8_is_valid(str
))
1568 if (!strextend_with_separator(&fields
, " ", str
))
1572 return bus_log_parse_error(r
);
1574 r
= sd_bus_message_exit_container(m
);
1576 return bus_log_parse_error(r
);
1578 bus_print_property_value(name
, expected_value
, flags
, fields
);
1581 } else if (contents
[0] == SD_BUS_TYPE_BYTE
&&
1583 "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes",
1584 "EffectiveCPUs", "EffectiveMemoryNodes")) {
1586 _cleanup_free_
char *affinity
= NULL
;
1587 _cleanup_(cpu_set_reset
) CPUSet set
= {};
1591 r
= sd_bus_message_read_array(m
, 'y', &a
, &n
);
1593 return bus_log_parse_error(r
);
1595 r
= cpu_set_from_dbus(a
, n
, &set
);
1597 return log_error_errno(r
, "Failed to deserialize %s: %m", name
);
1599 affinity
= cpu_set_to_range_string(&set
);
1603 bus_print_property_value(name
, expected_value
, flags
, affinity
);
1606 } else if (streq(name
, "MountImages")) {
1607 _cleanup_free_
char *paths
= NULL
;
1609 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ssba(ss))");
1611 return bus_log_parse_error(r
);
1614 _cleanup_free_
char *str
= NULL
;
1615 const char *source
, *destination
, *partition
, *mount_options
;
1618 r
= sd_bus_message_enter_container(m
, 'r', "ssba(ss)");
1622 r
= sd_bus_message_read(m
, "ssb", &source
, &destination
, &ignore_enoent
);
1626 str
= strjoin(ignore_enoent
? "-" : "",
1633 r
= sd_bus_message_enter_container(m
, 'a', "(ss)");
1637 while ((r
= sd_bus_message_read(m
, "(ss)", &partition
, &mount_options
)) > 0)
1638 if (!strextend_with_separator(&str
, ":", partition
, ":", mount_options
))
1643 if (!strextend_with_separator(&paths
, " ", str
))
1646 r
= sd_bus_message_exit_container(m
);
1650 r
= sd_bus_message_exit_container(m
);
1655 return bus_log_parse_error(r
);
1657 r
= sd_bus_message_exit_container(m
);
1659 return bus_log_parse_error(r
);
1661 bus_print_property_value(name
, expected_value
, flags
, paths
);
1665 } else if (streq(name
, "BPFProgram")) {
1668 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1670 return bus_log_parse_error(r
);
1672 while ((r
= sd_bus_message_read(m
, "(ss)", &a
, &p
)) > 0)
1673 bus_print_property_valuef(name
, expected_value
, flags
, "%s:%s", a
, p
);
1675 return bus_log_parse_error(r
);
1677 r
= sd_bus_message_exit_container(m
);
1679 return bus_log_parse_error(r
);
1682 } else if (STR_IN_SET(name
, "SocketBindAllow", "SocketBindDeny")) {
1683 uint16_t nr_ports
, port_min
;
1684 int32_t af
, ip_protocol
;
1686 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(iiqq)");
1688 return bus_log_parse_error(r
);
1689 while ((r
= sd_bus_message_read(m
, "(iiqq)", &af
, &ip_protocol
, &nr_ports
, &port_min
)) > 0) {
1690 const char *family
, *colon1
, *protocol
= "", *colon2
= "";
1692 family
= strempty(af_to_ipv4_ipv6(af
));
1693 colon1
= isempty(family
) ? "" : ":";
1695 if (ip_protocol
!= 0) {
1696 protocol
= ip_protocol_to_tcp_udp(ip_protocol
);
1701 bus_print_property_valuef(name
, expected_value
, flags
, "%s%s%s%sany",
1702 family
, colon1
, protocol
, colon2
);
1703 else if (nr_ports
== 1)
1704 bus_print_property_valuef(
1705 name
, expected_value
, flags
, "%s%s%s%s%hu",
1706 family
, colon1
, protocol
, colon2
, port_min
);
1708 bus_print_property_valuef(
1709 name
, expected_value
, flags
, "%s%s%s%s%hu-%hu",
1710 family
, colon1
, protocol
, colon2
, port_min
,
1711 (uint16_t) (port_min
+ nr_ports
- 1));
1714 return bus_log_parse_error(r
);
1716 r
= sd_bus_message_exit_container(m
);
1718 return bus_log_parse_error(r
);
1729 typedef enum SystemctlShowMode
{
1730 SYSTEMCTL_SHOW_PROPERTIES
,
1731 SYSTEMCTL_SHOW_STATUS
,
1732 SYSTEMCTL_SHOW_HELP
,
1733 _SYSTEMCTL_SHOW_MODE_MAX
,
1734 _SYSTEMCTL_SHOW_MODE_INVALID
= -EINVAL
,
1735 } SystemctlShowMode
;
1737 static const char* const systemctl_show_mode_table
[_SYSTEMCTL_SHOW_MODE_MAX
] = {
1738 [SYSTEMCTL_SHOW_PROPERTIES
] = "show",
1739 [SYSTEMCTL_SHOW_STATUS
] = "status",
1740 [SYSTEMCTL_SHOW_HELP
] = "help",
1743 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode
, SystemctlShowMode
);
1745 static int show_one(
1749 SystemctlShowMode show_mode
,
1753 static const struct bus_properties_map property_map
[] = {
1754 { "LoadState", "s", NULL
, offsetof(UnitStatusInfo
, load_state
) },
1755 { "ActiveState", "s", NULL
, offsetof(UnitStatusInfo
, active_state
) },
1756 { "FreezerState", "s", NULL
, offsetof(UnitStatusInfo
, freezer_state
) },
1757 { "Documentation", "as", NULL
, offsetof(UnitStatusInfo
, documentation
) },
1760 { "Id", "s", NULL
, offsetof(UnitStatusInfo
, id
) },
1761 { "LoadState", "s", NULL
, offsetof(UnitStatusInfo
, load_state
) },
1762 { "ActiveState", "s", NULL
, offsetof(UnitStatusInfo
, active_state
) },
1763 { "FreezerState", "s", NULL
, offsetof(UnitStatusInfo
, freezer_state
) },
1764 { "SubState", "s", NULL
, offsetof(UnitStatusInfo
, sub_state
) },
1765 { "UnitFileState", "s", NULL
, offsetof(UnitStatusInfo
, unit_file_state
) },
1766 { "UnitFilePreset", "s", NULL
, offsetof(UnitStatusInfo
, unit_file_preset
) },
1767 { "Description", "s", NULL
, offsetof(UnitStatusInfo
, description
) },
1768 { "Following", "s", NULL
, offsetof(UnitStatusInfo
, following
) },
1769 { "Documentation", "as", NULL
, offsetof(UnitStatusInfo
, documentation
) },
1770 { "FragmentPath", "s", NULL
, offsetof(UnitStatusInfo
, fragment_path
) },
1771 { "SourcePath", "s", NULL
, offsetof(UnitStatusInfo
, source_path
) },
1772 { "ControlGroup", "s", NULL
, offsetof(UnitStatusInfo
, control_group
) },
1773 { "DropInPaths", "as", NULL
, offsetof(UnitStatusInfo
, dropin_paths
) },
1774 { "LoadError", "(ss)", map_load_error
, offsetof(UnitStatusInfo
, load_error
) },
1775 { "Result", "s", NULL
, offsetof(UnitStatusInfo
, result
) },
1776 { "TriggeredBy", "as", NULL
, offsetof(UnitStatusInfo
, triggered_by
) },
1777 { "Triggers", "as", NULL
, offsetof(UnitStatusInfo
, triggers
) },
1778 { "InactiveExitTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, inactive_exit_timestamp
) },
1779 { "InactiveExitTimestampMonotonic", "t", NULL
, offsetof(UnitStatusInfo
, inactive_exit_timestamp_monotonic
) },
1780 { "ActiveEnterTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, active_enter_timestamp
) },
1781 { "ActiveExitTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, active_exit_timestamp
) },
1782 { "InactiveEnterTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, inactive_enter_timestamp
) },
1783 { "NeedDaemonReload", "b", NULL
, offsetof(UnitStatusInfo
, need_daemon_reload
) },
1784 { "Transient", "b", NULL
, offsetof(UnitStatusInfo
, transient
) },
1785 { "ExecMainPID", "u", NULL
, offsetof(UnitStatusInfo
, main_pid
) },
1786 { "MainPID", "u", map_main_pid
, 0 },
1787 { "ControlPID", "u", NULL
, offsetof(UnitStatusInfo
, control_pid
) },
1788 { "StatusText", "s", NULL
, offsetof(UnitStatusInfo
, status_text
) },
1789 { "PIDFile", "s", NULL
, offsetof(UnitStatusInfo
, pid_file
) },
1790 { "StatusErrno", "i", NULL
, offsetof(UnitStatusInfo
, status_errno
) },
1791 { "ExecMainStartTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, start_timestamp
) },
1792 { "ExecMainExitTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, exit_timestamp
) },
1793 { "ExecMainCode", "i", NULL
, offsetof(UnitStatusInfo
, exit_code
) },
1794 { "ExecMainStatus", "i", NULL
, offsetof(UnitStatusInfo
, exit_status
) },
1795 { "LogNamespace", "s", NULL
, offsetof(UnitStatusInfo
, log_namespace
) },
1796 { "ConditionTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, condition_timestamp
) },
1797 { "ConditionResult", "b", NULL
, offsetof(UnitStatusInfo
, condition_result
) },
1798 { "Conditions", "a(sbbsi)", map_conditions
, 0 },
1799 { "AssertTimestamp", "t", NULL
, offsetof(UnitStatusInfo
, assert_timestamp
) },
1800 { "AssertResult", "b", NULL
, offsetof(UnitStatusInfo
, assert_result
) },
1801 { "Asserts", "a(sbbsi)", map_asserts
, 0 },
1802 { "NextElapseUSecRealtime", "t", NULL
, offsetof(UnitStatusInfo
, next_elapse_real
) },
1803 { "NextElapseUSecMonotonic", "t", NULL
, offsetof(UnitStatusInfo
, next_elapse_monotonic
) },
1804 { "NAccepted", "u", NULL
, offsetof(UnitStatusInfo
, n_accepted
) },
1805 { "NConnections", "u", NULL
, offsetof(UnitStatusInfo
, n_connections
) },
1806 { "NRefused", "u", NULL
, offsetof(UnitStatusInfo
, n_refused
) },
1807 { "Accept", "b", NULL
, offsetof(UnitStatusInfo
, accept
) },
1808 { "Listen", "a(ss)", map_listen
, offsetof(UnitStatusInfo
, listen
) },
1809 { "SysFSPath", "s", NULL
, offsetof(UnitStatusInfo
, sysfs_path
) },
1810 { "Where", "s", NULL
, offsetof(UnitStatusInfo
, where
) },
1811 { "What", "s", NULL
, offsetof(UnitStatusInfo
, what
) },
1812 { "MemoryCurrent", "t", NULL
, offsetof(UnitStatusInfo
, memory_current
) },
1813 { "MemoryAvailable", "t", NULL
, offsetof(UnitStatusInfo
, memory_available
) },
1814 { "DefaultMemoryMin", "t", NULL
, offsetof(UnitStatusInfo
, default_memory_min
) },
1815 { "DefaultMemoryLow", "t", NULL
, offsetof(UnitStatusInfo
, default_memory_low
) },
1816 { "MemoryMin", "t", NULL
, offsetof(UnitStatusInfo
, memory_min
) },
1817 { "MemoryLow", "t", NULL
, offsetof(UnitStatusInfo
, memory_low
) },
1818 { "MemoryHigh", "t", NULL
, offsetof(UnitStatusInfo
, memory_high
) },
1819 { "MemoryMax", "t", NULL
, offsetof(UnitStatusInfo
, memory_max
) },
1820 { "MemorySwapMax", "t", NULL
, offsetof(UnitStatusInfo
, memory_swap_max
) },
1821 { "MemoryLimit", "t", NULL
, offsetof(UnitStatusInfo
, memory_limit
) },
1822 { "CPUUsageNSec", "t", NULL
, offsetof(UnitStatusInfo
, cpu_usage_nsec
) },
1823 { "TasksCurrent", "t", NULL
, offsetof(UnitStatusInfo
, tasks_current
) },
1824 { "TasksMax", "t", NULL
, offsetof(UnitStatusInfo
, tasks_max
) },
1825 { "IPIngressBytes", "t", NULL
, offsetof(UnitStatusInfo
, ip_ingress_bytes
) },
1826 { "IPEgressBytes", "t", NULL
, offsetof(UnitStatusInfo
, ip_egress_bytes
) },
1827 { "IOReadBytes", "t", NULL
, offsetof(UnitStatusInfo
, io_read_bytes
) },
1828 { "IOWriteBytes", "t", NULL
, offsetof(UnitStatusInfo
, io_write_bytes
) },
1829 { "ExecCondition", "a(sasbttttuii)", map_exec
, 0 },
1830 { "ExecConditionEx", "a(sasasttttuii)", map_exec
, 0 },
1831 { "ExecStartPre", "a(sasbttttuii)", map_exec
, 0 },
1832 { "ExecStartPreEx", "a(sasasttttuii)", map_exec
, 0 },
1833 { "ExecStart", "a(sasbttttuii)", map_exec
, 0 },
1834 { "ExecStartEx", "a(sasasttttuii)", map_exec
, 0 },
1835 { "ExecStartPost", "a(sasbttttuii)", map_exec
, 0 },
1836 { "ExecStartPostEx", "a(sasasttttuii)", map_exec
, 0 },
1837 { "ExecReload", "a(sasbttttuii)", map_exec
, 0 },
1838 { "ExecReloadEx", "a(sasasttttuii)", map_exec
, 0 },
1839 { "ExecStopPre", "a(sasbttttuii)", map_exec
, 0 },
1840 { "ExecStop", "a(sasbttttuii)", map_exec
, 0 },
1841 { "ExecStopEx", "a(sasasttttuii)", map_exec
, 0 },
1842 { "ExecStopPost", "a(sasbttttuii)", map_exec
, 0 },
1843 { "ExecStopPostEx", "a(sasasttttuii)", map_exec
, 0 },
1847 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1848 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1849 _cleanup_set_free_ Set
*found_properties
= NULL
;
1850 _cleanup_(unit_status_info_free
) UnitStatusInfo info
= {
1851 .memory_current
= UINT64_MAX
,
1852 .memory_high
= CGROUP_LIMIT_MAX
,
1853 .memory_max
= CGROUP_LIMIT_MAX
,
1854 .memory_swap_max
= CGROUP_LIMIT_MAX
,
1855 .memory_limit
= UINT64_MAX
,
1856 .memory_available
= CGROUP_LIMIT_MAX
,
1857 .cpu_usage_nsec
= UINT64_MAX
,
1858 .tasks_current
= UINT64_MAX
,
1859 .tasks_max
= UINT64_MAX
,
1860 .ip_ingress_bytes
= UINT64_MAX
,
1861 .ip_egress_bytes
= UINT64_MAX
,
1862 .io_read_bytes
= UINT64_MAX
,
1863 .io_write_bytes
= UINT64_MAX
,
1871 log_debug("Showing one %s", path
);
1873 r
= bus_map_all_properties(
1875 "org.freedesktop.systemd1",
1877 show_mode
== SYSTEMCTL_SHOW_STATUS
? status_map
: property_map
,
1878 BUS_MAP_BOOLEAN_AS_BOOL
,
1883 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
1885 if (unit
&& streq_ptr(info
.load_state
, "not-found") && streq_ptr(info
.active_state
, "inactive")) {
1886 log_full(show_mode
== SYSTEMCTL_SHOW_PROPERTIES
? LOG_DEBUG
: LOG_ERR
,
1887 "Unit %s could not be found.", unit
);
1889 if (show_mode
== SYSTEMCTL_SHOW_STATUS
)
1890 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN
;
1891 else if (show_mode
== SYSTEMCTL_SHOW_HELP
)
1900 if (show_mode
== SYSTEMCTL_SHOW_STATUS
) {
1901 print_status_info(bus
, &info
, ellipsized
);
1903 if (info
.active_state
&& !STR_IN_SET(info
.active_state
, "active", "reloading"))
1904 return EXIT_PROGRAM_NOT_RUNNING
;
1906 return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK
;
1908 } else if (show_mode
== SYSTEMCTL_SHOW_HELP
) {
1909 show_unit_help(&info
);
1913 r
= sd_bus_message_rewind(reply
, true);
1915 return log_error_errno(r
, "Failed to rewind: %s", bus_error_message(&error
, r
));
1917 r
= bus_message_print_all_properties(reply
, print_property
, arg_properties
, arg_print_flags
, &found_properties
);
1919 return bus_log_parse_error(r
);
1921 STRV_FOREACH(pp
, arg_properties
)
1922 if (!set_contains(found_properties
, *pp
))
1923 log_debug("Property %s does not exist.", *pp
);
1928 static int get_unit_dbus_path_by_pid(
1933 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1934 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1938 r
= bus_call_method(bus
, bus_systemd_mgr
, "GetUnitByPID", &error
, &reply
, "u", pid
);
1940 return log_error_errno(r
, "Failed to get unit for PID %"PRIu32
": %s", pid
, bus_error_message(&error
, r
));
1942 r
= sd_bus_message_read(reply
, "o", &u
);
1944 return bus_log_parse_error(r
);
1954 static int show_all(
1959 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
1960 _cleanup_free_ UnitInfo
*unit_infos
= NULL
;
1964 r
= get_unit_list(bus
, NULL
, NULL
, &unit_infos
, 0, &reply
);
1968 (void) pager_open(arg_pager_flags
);
1972 typesafe_qsort(unit_infos
, c
, unit_info_compare
);
1974 for (const UnitInfo
*u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
1975 _cleanup_free_
char *p
= NULL
;
1977 p
= unit_dbus_path_from_name(u
->id
);
1981 r
= show_one(bus
, p
, u
->id
, SYSTEMCTL_SHOW_STATUS
, new_line
, ellipsized
);
1984 else if (r
> 0 && ret
== 0)
1991 static int show_system_status(sd_bus
*bus
) {
1992 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
1993 _cleanup_(machine_info_clear
) struct machine_info mi
= {};
1994 _cleanup_free_
char *hn
= NULL
;
1995 const char *on
, *off
;
1998 hn
= gethostname_malloc();
2002 r
= bus_map_all_properties(
2004 "org.freedesktop.systemd1",
2005 "/org/freedesktop/systemd1",
2006 machine_info_property_map
,
2012 return log_error_errno(r
, "Failed to read server status: %s", bus_error_message(&error
, r
));
2014 if (streq_ptr(mi
.state
, "degraded")) {
2015 on
= ansi_highlight_red();
2016 off
= ansi_normal();
2017 } else if (streq_ptr(mi
.state
, "running")) {
2018 on
= ansi_highlight_green();
2019 off
= ansi_normal();
2021 on
= ansi_highlight_yellow();
2022 off
= ansi_normal();
2025 printf("%s%s%s %s\n", on
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off
, arg_host
? arg_host
: hn
);
2027 printf(" State: %s%s%s\n",
2028 on
, strna(mi
.state
), off
);
2030 printf(" Jobs: %" PRIu32
" queued\n", mi
.n_jobs
);
2031 printf(" Failed: %" PRIu32
" units\n", mi
.n_failed_units
);
2033 printf(" Since: %s; %s\n",
2034 FORMAT_TIMESTAMP_STYLE(mi
.timestamp
, arg_timestamp_style
),
2035 FORMAT_TIMESTAMP_RELATIVE(mi
.timestamp
));
2037 printf(" CGroup: %s\n", mi
.control_group
?: "/");
2038 if (IN_SET(arg_transport
,
2039 BUS_TRANSPORT_LOCAL
,
2040 BUS_TRANSPORT_MACHINE
)) {
2041 static const char prefix
[] = " ";
2045 if (c
> sizeof(prefix
) - 1)
2046 c
-= sizeof(prefix
) - 1;
2050 show_cgroup(SYSTEMD_CGROUP_CONTROLLER
, strempty(mi
.control_group
), prefix
, c
, get_output_flags());
2056 int show(int argc
, char *argv
[], void *userdata
) {
2057 bool new_line
= false, ellipsized
= false;
2058 SystemctlShowMode show_mode
;
2064 show_mode
= systemctl_show_mode_from_string(argv
[0]);
2066 return log_error_errno(show_mode
, "Invalid argument.");
2068 if (show_mode
== SYSTEMCTL_SHOW_HELP
&& argc
<= 1)
2069 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
2070 "'help' command expects one or more unit names.\n"
2071 "(Alternatively, help for systemctl itself may be shown with --help)");
2073 r
= acquire_bus(BUS_MANAGER
, &bus
);
2077 (void) pager_open(arg_pager_flags
);
2079 /* If no argument is specified inspect the manager itself */
2080 if (show_mode
== SYSTEMCTL_SHOW_PROPERTIES
&& argc
<= 1)
2081 return show_one(bus
, "/org/freedesktop/systemd1", NULL
, show_mode
, &new_line
, &ellipsized
);
2083 if (show_mode
== SYSTEMCTL_SHOW_STATUS
&& argc
<= 1) {
2085 show_system_status(bus
);
2089 ret
= show_all(bus
, &new_line
, &ellipsized
);
2091 _cleanup_free_
char **patterns
= NULL
;
2094 STRV_FOREACH(name
, strv_skip(argv
, 1)) {
2095 _cleanup_free_
char *path
= NULL
, *unit
= NULL
;
2098 if (safe_atou32(*name
, &id
) < 0) {
2099 if (strv_push(&patterns
, *name
) < 0)
2103 } else if (show_mode
== SYSTEMCTL_SHOW_PROPERTIES
) {
2104 /* Interpret as job id */
2105 if (asprintf(&path
, "/org/freedesktop/systemd1/job/%u", id
) < 0)
2109 /* Interpret as PID */
2110 r
= get_unit_dbus_path_by_pid(bus
, id
, &path
);
2116 r
= unit_name_from_dbus_path(path
, &unit
);
2121 r
= show_one(bus
, path
, unit
, show_mode
, &new_line
, &ellipsized
);
2124 else if (r
> 0 && ret
== 0)
2128 if (!strv_isempty(patterns
)) {
2129 _cleanup_strv_free_
char **names
= NULL
;
2131 r
= expand_unit_names(bus
, patterns
, NULL
, &names
, NULL
);
2133 return log_error_errno(r
, "Failed to expand names: %m");
2135 r
= maybe_extend_with_unit_dependencies(bus
, &names
);
2139 STRV_FOREACH(name
, names
) {
2140 _cleanup_free_
char *path
= NULL
;
2142 path
= unit_dbus_path_from_name(*name
);
2146 r
= show_one(bus
, path
, *name
, show_mode
, &new_line
, &ellipsized
);
2149 if (r
> 0 && ret
== 0)
2155 if (ellipsized
&& !arg_quiet
)
2156 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");