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"
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"
43 static OutputFlags
get_output_flags(void) {
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
;
51 typedef struct ExecStatusInfo
{
59 usec_t start_timestamp
;
60 usec_t exit_timestamp
;
65 ExecCommandFlags flags
;
67 LIST_FIELDS(struct ExecStatusInfo
, exec
);
70 static void exec_status_info_free(ExecStatusInfo
*i
) {
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
;
90 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_STRUCT
, is_ex_prop
? "sasasttttuii" : "sasbttttuii");
92 return bus_log_parse_error(r
);
96 r
= sd_bus_message_read(m
, "s", &path
);
98 return bus_log_parse_error(r
);
100 i
->path
= strdup(path
);
104 r
= sd_bus_message_read_strv(m
, &i
->argv
);
106 return bus_log_parse_error(r
);
108 r
= is_ex_prop
? sd_bus_message_read_strv(m
, &ex_opts
) : sd_bus_message_read(m
, "b", &ignore
);
110 return bus_log_parse_error(r
);
112 r
= sd_bus_message_read(m
,
114 &start_timestamp
, &start_timestamp_monotonic
,
115 &exit_timestamp
, &exit_timestamp_monotonic
,
119 return bus_log_parse_error(r
);
122 r
= exec_command_flags_from_strv(ex_opts
, &i
->flags
);
124 return log_error_errno(r
, "Failed to convert strv to ExecCommandFlags: %m");
126 i
->ignore
= FLAGS_SET(i
->flags
, EXEC_COMMAND_IGNORE_FAILURE
);
130 i
->start_timestamp
= (usec_t
) start_timestamp
;
131 i
->exit_timestamp
= (usec_t
) exit_timestamp
;
132 i
->pid
= (pid_t
) pid
;
136 r
= sd_bus_message_exit_container(m
);
138 return bus_log_parse_error(r
);
143 typedef struct UnitCondition
{
150 LIST_FIELDS(struct UnitCondition
, conditions
);
153 static UnitCondition
* unit_condition_free(UnitCondition
*c
) {
161 DEFINE_TRIVIAL_CLEANUP_FUNC(UnitCondition
*, unit_condition_free
);
163 typedef struct UnitStatusInfo
{
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
;
172 const char *description
;
173 const char *following
;
175 char **documentation
;
177 const char *fragment_path
;
178 const char *source_path
;
179 const char *control_group
;
186 const char *load_error
;
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
;
195 bool need_daemon_reload
;
201 const char *status_text
;
202 const char *pid_file
;
206 usec_t start_timestamp
;
207 usec_t exit_timestamp
;
209 int exit_code
, exit_status
;
211 const char *log_namespace
;
213 usec_t condition_timestamp
;
214 bool condition_result
;
215 LIST_HEAD(UnitCondition
, conditions
);
217 usec_t assert_timestamp
;
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
;
228 unsigned n_connections
;
232 /* Pairs of type, path */
236 const char *sysfs_path
;
238 /* Mount, Automount */
245 uint64_t memory_current
;
248 uint64_t memory_high
;
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
;
256 uint64_t ip_ingress_bytes
;
257 uint64_t ip_egress_bytes
;
258 uint64_t io_read_bytes
;
259 uint64_t io_write_bytes
;
261 uint64_t default_memory_min
;
262 uint64_t default_memory_low
;
264 LIST_HEAD(ExecStatusInfo
, exec
);
267 static void unit_status_info_free(UnitStatusInfo
*info
) {
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
);
277 while ((c
= info
->conditions
)) {
278 LIST_REMOVE(conditions
, info
->conditions
, c
);
279 unit_condition_free(c
);
282 while ((p
= info
->exec
)) {
283 LIST_REMOVE(exec
, info
->exec
, p
);
284 exec_status_info_free(p
);
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();
296 *active_on
= *active_off
= "";
299 static void print_status_info(
304 const char *active_on
, *active_off
, *on
, *off
, *ss
, *fs
;
305 _cleanup_free_
char *formatted_path
= NULL
;
314 /* This shows pretty information about a unit. See print_property() for a low-level property
317 format_active_state(i
->active_state
, &active_on
, &active_off
);
319 const SpecialGlyph glyph
= unit_active_state_to_glyph(unit_active_state_from_string(i
->active_state
));
321 printf("%s%s%s %s", active_on
, special_glyph(glyph
), active_off
, strna(i
->id
));
323 if (i
->description
&& !streq_ptr(i
->id
, i
->description
))
324 printf(" - %s", i
->description
);
329 printf(" Follows: unit currently follows state of %s\n", i
->following
);
331 if (STRPTR_IN_SET(i
->load_state
, "error", "not-found", "bad-setting")) {
332 on
= ansi_highlight_red();
337 path
= i
->source_path
?: i
->fragment_path
;
338 if (path
&& terminal_urlify_path(path
, NULL
, &formatted_path
) >= 0)
339 path
= formatted_path
;
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
));
348 printf(" Loaded: %s%s%s (%s; %s%s%s)\n",
349 on
, strna(i
->load_state
), off
,
352 show_preset
? "; vendor preset: " : "",
353 show_preset
? i
->unit_file_preset
: "");
356 printf(" Loaded: %s%s%s (%s)\n",
357 on
, strna(i
->load_state
), off
, path
);
359 printf(" Loaded: %s%s%s\n",
360 on
, strna(i
->load_state
), off
);
363 printf(" Transient: yes\n");
365 if (!strv_isempty(i
->dropin_paths
)) {
366 _cleanup_free_
char *dir
= NULL
;
370 STRV_FOREACH(dropin
, i
->dropin_paths
) {
371 _cleanup_free_
char *dropin_formatted
= NULL
;
380 dir
= dirname_malloc(*dropin
);
388 special_glyph(SPECIAL_GLYPH_TREE_RIGHT
));
391 last
= ! (*(dropin
+ 1) && startswith(*(dropin
+ 1), dir
));
393 if (terminal_urlify_path(*dropin
, basename(*dropin
), &dropin_formatted
) >= 0)
394 df
= dropin_formatted
;
398 printf("%s%s", df
, last
? "\n" : ", ");
402 ss
= streq_ptr(i
->active_state
, i
->sub_state
) ? NULL
: i
->sub_state
;
404 printf(" Active: %s%s (%s)%s",
405 active_on
, strna(i
->active_state
), ss
, active_off
);
407 printf(" Active: %s%s%s",
408 active_on
, strna(i
->active_state
), active_off
);
410 fs
= !isempty(i
->freezer_state
) && !streq(i
->freezer_state
, "running") ? i
->freezer_state
: NULL
;
412 printf(" %s(%s)%s", ansi_highlight_yellow(), fs
, ansi_normal());
414 if (!isempty(i
->result
) && !streq(i
->result
, "success"))
415 printf(" (Result: %s)", i
->result
);
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
;
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
));
429 STRV_FOREACH(t
, i
->triggered_by
) {
430 UnitActiveState state
= _UNIT_ACTIVE_STATE_INVALID
;
432 (void) get_state_one_unit(bus
, *t
, &state
);
433 format_active_state(unit_active_state_to_string(state
), &on
, &off
);
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
,
441 if (endswith(i
->id
, ".timer")) {
442 dual_timestamp nw
, next
= {i
->next_elapse_real
, i
->next_elapse_monotonic
};
445 dual_timestamp_get(&nw
);
446 next_elapse
= calc_next_elapse(&nw
, &next
);
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
));
453 printf(" Trigger: n/a\n");
456 STRV_FOREACH(t
, i
->triggers
) {
457 UnitActiveState state
= _UNIT_ACTIVE_STATE_INVALID
;
459 (void) get_state_one_unit(bus
, *t
, &state
);
460 format_active_state(unit_active_state_to_string(state
), &on
, &off
);
462 printf("%s %s%s%s %s\n",
463 t
== i
->triggers
? " Triggers:" : " ",
464 on
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off
,
468 if (!i
->condition_result
&& i
->condition_timestamp
> 0) {
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
));
477 LIST_FOREACH(conditions
, c
, i
->conditions
)
481 LIST_FOREACH(conditions
, c
, i
->conditions
)
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
),
486 c
->trigger
? "|" : "",
487 c
->negate
? "!" : "",
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",
501 i
->failed_assert_negate
? "!" : "",
502 i
->failed_assert_parameter
);
506 printf(" Device: %s\n", i
->sysfs_path
);
508 printf(" Where: %s\n", i
->where
);
510 printf(" What: %s\n", i
->what
);
512 STRV_FOREACH(t
, i
->documentation
) {
513 _cleanup_free_
char *formatted
= NULL
;
516 if (terminal_urlify(*t
, NULL
, &formatted
) >= 0)
521 printf(" %*s %s\n", 9, t
== i
->documentation
? "Docs:" : "", q
);
524 STRV_FOREACH_PAIR(t
, t2
, i
->listen
)
525 printf(" %*s %s (%s)\n", 9, t
== i
->listen
? "Listen:" : "", *t2
, *t
);
528 printf(" Accepted: %u; Connected: %u;", i
->n_accepted
, i
->n_connections
);
530 printf(" Refused: %u", i
->n_refused
);
534 LIST_FOREACH(exec
, p
, i
->exec
) {
535 _cleanup_free_
char *argv
= NULL
;
538 /* Only show exited processes here */
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"))
547 argv
= strv_join(p
->argv
, " ");
548 printf(" Process: "PID_FMT
" %s=%s ", p
->pid
, p
->name
, strna(argv
));
550 good
= is_clean_exit(p
->code
, p
->status
, EXIT_CLEAN_DAEMON
, NULL
);
552 on
= ansi_highlight_red();
557 printf("%s(code=%s, ", on
, sigchld_code_to_string(p
->code
));
559 if (p
->code
== CLD_EXITED
) {
562 printf("status=%i", p
->status
);
564 c
= exit_status_to_string(p
->status
, EXIT_STATUS_LIBC
| EXIT_STATUS_SYSTEMD
);
569 printf("signal=%s", signal_to_string(p
->status
));
571 printf(")%s\n", off
);
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 */
579 if (p
->pid
== i
->control_pid
)
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
);
589 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
590 _cleanup_free_
char *comm
= NULL
;
592 (void) get_process_comm(i
->main_pid
, &comm
);
594 printf(" (%s)", comm
);
597 } else if (i
->exit_code
> 0) {
598 printf(" (code=%s, ", sigchld_code_to_string(i
->exit_code
));
600 if (i
->exit_code
== CLD_EXITED
) {
603 printf("status=%i", i
->exit_status
);
605 c
= exit_status_to_string(i
->exit_status
,
606 EXIT_STATUS_LIBC
| EXIT_STATUS_SYSTEMD
);
611 printf("signal=%s", signal_to_string(i
->exit_status
));
616 if (i
->control_pid
> 0) {
617 _cleanup_free_
char *c
= NULL
;
620 fputs("; Control PID: ", stdout
);
622 fputs("Cntrl PID: ", stdout
); /* if first in column, abbreviated so it fits alignment */
624 printf(PID_FMT
, i
->control_pid
);
626 if (arg_transport
== BUS_TRANSPORT_LOCAL
) {
627 (void) get_process_comm(i
->control_pid
, &c
);
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
));
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
));
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
));
651 if (i
->tasks_current
!= UINT64_MAX
) {
652 printf(" Tasks: %" PRIu64
, i
->tasks_current
);
654 if (i
->tasks_max
!= UINT64_MAX
)
655 printf(" (limit: %" PRIu64
")\n", i
->tasks_max
);
660 if (i
->memory_current
!= UINT64_MAX
) {
661 printf(" Memory: %s", FORMAT_BYTES(i
->memory_current
));
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
= "";
671 if (i
->memory_min
> 0) {
672 printf("%smin: %s", prefix
, FORMAT_BYTES_CGROUP_PROTECTION(i
->memory_min
));
675 if (i
->memory_low
> 0) {
676 printf("%slow: %s", prefix
, FORMAT_BYTES_CGROUP_PROTECTION(i
->memory_low
));
679 if (i
->memory_high
!= CGROUP_LIMIT_MAX
) {
680 printf("%shigh: %s", prefix
, FORMAT_BYTES(i
->memory_high
));
683 if (i
->memory_max
!= CGROUP_LIMIT_MAX
) {
684 printf("%smax: %s", prefix
, FORMAT_BYTES(i
->memory_max
));
687 if (i
->memory_swap_max
!= CGROUP_LIMIT_MAX
) {
688 printf("%sswap max: %s", prefix
, FORMAT_BYTES(i
->memory_swap_max
));
691 if (i
->memory_limit
!= CGROUP_LIMIT_MAX
) {
692 printf("%slimit: %s", prefix
, FORMAT_BYTES(i
->memory_limit
));
695 if (i
->memory_available
!= CGROUP_LIMIT_MAX
) {
696 printf("%savailable: %s", prefix
, FORMAT_BYTES(i
->memory_available
));
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
));
707 if (i
->control_group
) {
708 _cleanup_(sd_bus_error_free
) sd_bus_error error
= SD_BUS_ERROR_NULL
;
709 static const char prefix
[] = " ";
712 printf(" CGroup: %s\n", i
->control_group
);
714 c
= LESS_BY(columns(), strlen(prefix
));
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
) {
721 /* Fallback for older systemd versions where the GetUnitProcesses() call is not yet available */
724 extra
[k
++] = i
->main_pid
;
726 if (i
->control_pid
> 0)
727 extra
[k
++] = i
->control_pid
;
729 show_cgroup_and_extra(SYSTEMD_CGROUP_CONTROLLER
, i
->control_group
, prefix
, c
, extra
, k
, get_output_flags());
731 log_warning_errno(r
, "Failed to dump process list for '%s', ignoring: %s",
732 i
->id
, bus_error_message(&error
, r
));
735 if (i
->id
&& arg_transport
== BUS_TRANSPORT_LOCAL
)
736 show_journal_by_unit(
742 i
->inactive_exit_timestamp_monotonic
,
745 get_output_flags() | OUTPUT_BEGIN_NEWLINE
,
746 SD_JOURNAL_LOCAL_ONLY
,
747 arg_scope
== UNIT_FILE_SYSTEM
,
750 if (i
->need_daemon_reload
)
751 warn_unit_file_changed(i
->id
);
754 static void show_unit_help(UnitStatusInfo
*i
) {
759 if (!i
->documentation
) {
760 log_info("Documentation for %s not known.", i
->id
);
764 STRV_FOREACH(p
, i
->documentation
)
765 if (startswith(*p
, "man:"))
766 show_man_page(*p
+ 4, false);
768 log_info("Can't show: %s", *p
);
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
;
776 r
= sd_bus_message_read(m
, "u", &u
);
780 i
->main_pid
= (pid_t
) u
;
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
;
790 r
= sd_bus_message_read(m
, "(ss)", NULL
, &message
);
794 if (!isempty(message
))
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
;
805 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
809 while ((r
= sd_bus_message_read(m
, "(ss)", &type
, &path
)) > 0) {
811 r
= strv_extend(p
, type
);
815 r
= strv_extend(p
, path
);
822 r
= sd_bus_message_exit_container(m
);
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
;
836 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sbbsi)");
840 while ((r
= sd_bus_message_read(m
, "(sbbsi)", &cond
, &trigger
, &negate
, ¶m
, &state
)) > 0) {
841 _cleanup_(unit_condition_freep
) UnitCondition
*c
= NULL
;
843 c
= new(UnitCondition
, 1);
847 *c
= (UnitCondition
) {
848 .name
= strdup(cond
),
849 .param
= strdup(param
),
855 if (!c
->name
|| !c
->param
)
858 LIST_PREPEND(conditions
, i
->conditions
, TAKE_PTR(c
));
863 r
= sd_bus_message_exit_container(m
);
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
;
877 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sbbsi)");
881 while ((r
= sd_bus_message_read(m
, "(sbbsi)", &cond
, &trigger
, &negate
, ¶m
, &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
;
892 r
= sd_bus_message_exit_container(m
);
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");
906 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, is_ex_prop
? "(sasasttttuii)" : "(sasbttttuii)");
910 info
= new0(ExecStatusInfo
, 1);
914 LIST_FIND_TAIL(exec
, i
->exec
, last
);
916 while ((r
= exec_status_info_deserialize(m
, info
, is_ex_prop
)) > 0) {
918 info
->name
= strdup(member
);
922 LIST_INSERT_AFTER(exec
, i
->exec
, last
, info
);
925 info
= new0(ExecStatusInfo
, 1);
932 r
= sd_bus_message_exit_container(m
);
939 static int print_property(const char *name
, const char *expected_value
, sd_bus_message
*m
, BusPrintPropertyFlags flags
) {
941 const char *contents
;
947 /* This is a low-level property printer, see print_status_info() for the nicer output */
949 r
= sd_bus_message_peek_type(m
, &bus_type
, &contents
);
955 case SD_BUS_TYPE_INT32
:
956 if (endswith(name
, "ActionExitStatus")) {
959 r
= sd_bus_message_read_basic(m
, bus_type
, &i
);
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]");
969 } else if (streq(name
, "NUMAPolicy")) {
972 r
= sd_bus_message_read_basic(m
, bus_type
, &i
);
976 bus_print_property_valuef(name
, expected_value
, flags
, "%s", strna(mpol_to_string(i
)));
982 case SD_BUS_TYPE_STRUCT
:
984 if (contents
[0] == SD_BUS_TYPE_UINT32
&& streq(name
, "Job")) {
987 r
= sd_bus_message_read(m
, "(uo)", &u
, NULL
);
989 return bus_log_parse_error(r
);
992 bus_print_property_valuef(name
, expected_value
, flags
, "%"PRIu32
, u
);
994 bus_print_property_value(name
, expected_value
, flags
, NULL
);
998 } else if (contents
[0] == SD_BUS_TYPE_STRING
&& streq(name
, "Unit")) {
1001 r
= sd_bus_message_read(m
, "(so)", &s
, NULL
);
1003 return bus_log_parse_error(r
);
1005 bus_print_property_value(name
, expected_value
, flags
, s
);
1009 } else if (contents
[0] == SD_BUS_TYPE_STRING
&& streq(name
, "LoadError")) {
1010 const char *a
= NULL
, *b
= NULL
;
1012 r
= sd_bus_message_read(m
, "(ss)", &a
, &b
);
1014 return bus_log_parse_error(r
);
1016 if (!isempty(a
) || !isempty(b
))
1017 bus_print_property_valuef(name
, expected_value
, flags
, "%s \"%s\"", strempty(a
), strempty(b
));
1019 bus_print_property_value(name
, expected_value
, flags
, NULL
);
1023 } else if (STR_IN_SET(name
, "SystemCallFilter", "SystemCallLog", "RestrictAddressFamilies", "RestrictNetworkInterfaces", "RestrictFileSystems")) {
1024 _cleanup_strv_free_
char **l
= NULL
;
1027 r
= sd_bus_message_enter_container(m
, 'r', "bas");
1029 return bus_log_parse_error(r
);
1031 r
= sd_bus_message_read(m
, "b", &allow_list
);
1033 return bus_log_parse_error(r
);
1035 r
= sd_bus_message_read_strv(m
, &l
);
1037 return bus_log_parse_error(r
);
1039 r
= sd_bus_message_exit_container(m
);
1041 return bus_log_parse_error(r
);
1043 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || allow_list
|| !strv_isempty(l
)) {
1047 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
)) {
1048 fputs(name
, stdout
);
1055 STRV_FOREACH(i
, l
) {
1063 fputc('\n', stdout
);
1068 } else if (STR_IN_SET(name
, "SELinuxContext", "AppArmorProfile", "SmackProcessLabel")) {
1072 r
= sd_bus_message_read(m
, "(bs)", &ignore
, &s
);
1074 return bus_log_parse_error(r
);
1077 bus_print_property_valuef(name
, expected_value
, flags
, "%s%s", ignore
? "-" : "", s
);
1079 bus_print_property_value(name
, expected_value
, flags
, NULL
);
1083 } else if (endswith(name
, "ExitStatus") && streq(contents
, "aiai")) {
1084 const int32_t *status
, *signal
;
1085 size_t n_status
, n_signal
;
1087 r
= sd_bus_message_enter_container(m
, 'r', "aiai");
1089 return bus_log_parse_error(r
);
1091 r
= sd_bus_message_read_array(m
, 'i', (const void **) &status
, &n_status
);
1093 return bus_log_parse_error(r
);
1095 r
= sd_bus_message_read_array(m
, 'i', (const void **) &signal
, &n_signal
);
1097 return bus_log_parse_error(r
);
1099 r
= sd_bus_message_exit_container(m
);
1101 return bus_log_parse_error(r
);
1103 n_status
/= sizeof(int32_t);
1104 n_signal
/= sizeof(int32_t);
1106 if (FLAGS_SET(flags
, BUS_PRINT_PROPERTY_SHOW_EMPTY
) || n_status
> 0 || n_signal
> 0) {
1109 if (!FLAGS_SET(flags
, BUS_PRINT_PROPERTY_ONLY_VALUE
)) {
1110 fputs(name
, stdout
);
1114 for (size_t i
= 0; i
< n_status
; i
++) {
1120 printf("%"PRIi32
, status
[i
]);
1123 for (size_t i
= 0; i
< n_signal
; i
++) {
1126 str
= signal_to_string((int) signal
[i
]);
1136 printf("%"PRIi32
, status
[i
]);
1139 fputc('\n', stdout
);
1146 case SD_BUS_TYPE_ARRAY
:
1148 if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "EnvironmentFiles")) {
1152 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sb)");
1154 return bus_log_parse_error(r
);
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
));
1159 return bus_log_parse_error(r
);
1161 r
= sd_bus_message_exit_container(m
);
1163 return bus_log_parse_error(r
);
1167 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Paths")) {
1168 const char *type
, *path
;
1170 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1172 return bus_log_parse_error(r
);
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
);
1177 return bus_log_parse_error(r
);
1179 r
= sd_bus_message_exit_container(m
);
1181 return bus_log_parse_error(r
);
1185 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "Listen")) {
1186 const char *type
, *path
;
1188 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1190 return bus_log_parse_error(r
);
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
);
1195 return bus_log_parse_error(r
);
1197 r
= sd_bus_message_exit_container(m
);
1199 return bus_log_parse_error(r
);
1203 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "TimersMonotonic")) {
1205 uint64_t v
, next_elapse
;
1207 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(stt)");
1209 return bus_log_parse_error(r
);
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 }",
1215 strna(FORMAT_TIMESPAN(v
, 0)),
1216 strna(FORMAT_TIMESPAN(next_elapse
, 0)));
1218 return bus_log_parse_error(r
);
1220 r
= sd_bus_message_exit_container(m
);
1222 return bus_log_parse_error(r
);
1226 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "TimersCalendar")) {
1227 const char *base
, *spec
;
1228 uint64_t next_elapse
;
1230 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sst)");
1232 return bus_log_parse_error(r
);
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
));
1239 return bus_log_parse_error(r
);
1241 r
= sd_bus_message_exit_container(m
);
1243 return bus_log_parse_error(r
);
1247 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& startswith(name
, "Exec")) {
1248 ExecStatusInfo info
= {};
1249 bool is_ex_prop
= endswith(name
, "Ex");
1251 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, is_ex_prop
? "(sasasttttuii)" : "(sasbttttuii)");
1253 return bus_log_parse_error(r
);
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
;
1259 tt
= strv_join(info
.argv
, " ");
1262 r
= exec_command_flags_to_strv(info
.flags
, &optv
);
1264 return log_error_errno(r
, "Failed to convert ExecCommandFlags to strv: %m");
1266 o
= strv_join(optv
, " ");
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 }",
1273 strna(FORMAT_TIMESTAMP_STYLE(info
.start_timestamp
, arg_timestamp_style
)),
1274 strna(FORMAT_TIMESTAMP_STYLE(info
.exit_timestamp
, arg_timestamp_style
)),
1276 sigchld_code_to_string(info
.code
),
1278 info
.code
== CLD_EXITED
? "" : "/",
1279 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
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 }",
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
)),
1289 sigchld_code_to_string(info
.code
),
1291 info
.code
== CLD_EXITED
? "" : "/",
1292 strempty(info
.code
== CLD_EXITED
? NULL
: signal_to_string(info
.status
)));
1295 strv_free(info
.argv
);
1299 r
= sd_bus_message_exit_container(m
);
1301 return bus_log_parse_error(r
);
1305 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&& streq(name
, "DeviceAllow")) {
1306 const char *path
, *rwm
;
1308 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1310 return bus_log_parse_error(r
);
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
));
1315 return bus_log_parse_error(r
);
1317 r
= sd_bus_message_exit_container(m
);
1319 return bus_log_parse_error(r
);
1323 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&&
1324 STR_IN_SET(name
, "IODeviceWeight", "BlockIODeviceWeight")) {
1328 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1330 return bus_log_parse_error(r
);
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
);
1335 return bus_log_parse_error(r
);
1337 r
= sd_bus_message_exit_container(m
);
1339 return bus_log_parse_error(r
);
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"))) {
1349 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1351 return bus_log_parse_error(r
);
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
);
1356 return bus_log_parse_error(r
);
1358 r
= sd_bus_message_exit_container(m
);
1360 return bus_log_parse_error(r
);
1364 } else if (contents
[0] == SD_BUS_TYPE_STRUCT_BEGIN
&&
1365 streq(name
, "IODeviceLatencyTargetUSec")) {
1369 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(st)");
1371 return bus_log_parse_error(r
);
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));
1377 return bus_log_parse_error(r
);
1379 r
= sd_bus_message_exit_container(m
);
1381 return bus_log_parse_error(r
);
1385 } else if (contents
[0] == SD_BUS_TYPE_BYTE
&& STR_IN_SET(name
, "StandardInputData", "RootHashSignature")) {
1386 _cleanup_free_
char *h
= NULL
;
1391 r
= sd_bus_message_read_array(m
, 'y', &p
, &sz
);
1393 return bus_log_parse_error(r
);
1395 n
= base64mem(p
, sz
, &h
);
1399 bus_print_property_value(name
, expected_value
, flags
, h
);
1403 } else if (STR_IN_SET(name
, "IPAddressAllow", "IPAddressDeny")) {
1404 _cleanup_free_
char *addresses
= NULL
;
1406 r
= sd_bus_message_enter_container(m
, 'a', "(iayu)");
1408 return bus_log_parse_error(r
);
1411 _cleanup_free_
char *str
= NULL
;
1417 r
= sd_bus_message_enter_container(m
, 'r', "iayu");
1419 return bus_log_parse_error(r
);
1423 r
= sd_bus_message_read(m
, "i", &family
);
1425 return bus_log_parse_error(r
);
1427 r
= sd_bus_message_read_array(m
, 'y', &ap
, &an
);
1429 return bus_log_parse_error(r
);
1431 r
= sd_bus_message_read(m
, "u", &prefixlen
);
1433 return bus_log_parse_error(r
);
1435 r
= sd_bus_message_exit_container(m
);
1437 return bus_log_parse_error(r
);
1439 if (!IN_SET(family
, AF_INET
, AF_INET6
))
1442 if (an
!= FAMILY_ADDRESS_SIZE(family
))
1445 if (prefixlen
> FAMILY_ADDRESS_SIZE(family
) * 8)
1448 if (in_addr_prefix_to_string(family
, (const union in_addr_union
*) ap
, prefixlen
, &str
) < 0)
1451 if (!strextend_with_separator(&addresses
, " ", str
))
1455 r
= sd_bus_message_exit_container(m
);
1457 return bus_log_parse_error(r
);
1459 bus_print_property_value(name
, expected_value
, flags
, addresses
);
1463 } else if (STR_IN_SET(name
, "BindPaths", "BindReadOnlyPaths")) {
1464 _cleanup_free_
char *paths
= NULL
;
1465 const char *source
, *dest
;
1469 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ssbt)");
1471 return bus_log_parse_error(r
);
1473 while ((r
= sd_bus_message_read(m
, "(ssbt)", &source
, &dest
, &ignore_enoent
, &rbind
)) > 0) {
1474 _cleanup_free_
char *str
= NULL
;
1476 if (isempty(source
))
1479 if (asprintf(&str
, "%s%s%s%s%s",
1480 ignore_enoent
? "-" : "",
1482 isempty(dest
) ? "" : ":",
1484 rbind
== MS_REC
? ":rbind" : "") < 0)
1487 if (!strextend_with_separator(&paths
, " ", str
))
1491 return bus_log_parse_error(r
);
1493 r
= sd_bus_message_exit_container(m
);
1495 return bus_log_parse_error(r
);
1497 bus_print_property_value(name
, expected_value
, flags
, paths
);
1501 } else if (streq(name
, "TemporaryFileSystem")) {
1502 _cleanup_free_
char *paths
= NULL
;
1503 const char *target
, *option
;
1505 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1507 return bus_log_parse_error(r
);
1509 while ((r
= sd_bus_message_read(m
, "(ss)", &target
, &option
)) > 0) {
1510 _cleanup_free_
char *str
= NULL
;
1512 if (isempty(target
))
1515 if (asprintf(&str
, "%s%s%s", target
, isempty(option
) ? "" : ":", strempty(option
)) < 0)
1518 if (!strextend_with_separator(&paths
, " ", str
))
1522 return bus_log_parse_error(r
);
1524 r
= sd_bus_message_exit_container(m
);
1526 return bus_log_parse_error(r
);
1528 bus_print_property_value(name
, expected_value
, flags
, paths
);
1532 } else if (streq(name
, "LogExtraFields")) {
1533 _cleanup_free_
char *fields
= NULL
;
1537 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "ay");
1539 return bus_log_parse_error(r
);
1541 while ((r
= sd_bus_message_read_array(m
, 'y', &p
, &sz
)) > 0) {
1542 _cleanup_free_
char *str
= NULL
;
1545 if (memchr(p
, 0, sz
))
1548 eq
= memchr(p
, '=', sz
);
1552 if (!journal_field_valid(p
, eq
- (const char*) p
, false))
1555 str
= malloc(sz
+ 1);
1562 if (!utf8_is_valid(str
))
1565 if (!strextend_with_separator(&fields
, " ", str
))
1569 return bus_log_parse_error(r
);
1571 r
= sd_bus_message_exit_container(m
);
1573 return bus_log_parse_error(r
);
1575 bus_print_property_value(name
, expected_value
, flags
, fields
);
1578 } else if (contents
[0] == SD_BUS_TYPE_BYTE
&&
1580 "CPUAffinity", "NUMAMask", "AllowedCPUs", "AllowedMemoryNodes",
1581 "EffectiveCPUs", "EffectiveMemoryNodes")) {
1583 _cleanup_free_
char *affinity
= NULL
;
1584 _cleanup_(cpu_set_reset
) CPUSet set
= {};
1588 r
= sd_bus_message_read_array(m
, 'y', &a
, &n
);
1590 return bus_log_parse_error(r
);
1592 r
= cpu_set_from_dbus(a
, n
, &set
);
1594 return log_error_errno(r
, "Failed to deserialize %s: %m", name
);
1596 affinity
= cpu_set_to_range_string(&set
);
1600 bus_print_property_value(name
, expected_value
, flags
, affinity
);
1603 } else if (streq(name
, "MountImages")) {
1604 _cleanup_free_
char *paths
= NULL
;
1606 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ssba(ss))");
1608 return bus_log_parse_error(r
);
1611 _cleanup_free_
char *str
= NULL
;
1612 const char *source
, *destination
, *partition
, *mount_options
;
1615 r
= sd_bus_message_enter_container(m
, 'r', "ssba(ss)");
1617 return bus_log_parse_error(r
);
1621 r
= sd_bus_message_read(m
, "ssb", &source
, &destination
, &ignore_enoent
);
1623 return bus_log_parse_error(r
);
1625 str
= strjoin(ignore_enoent
? "-" : "",
1632 r
= sd_bus_message_enter_container(m
, 'a', "(ss)");
1634 return bus_log_parse_error(r
);
1636 while ((r
= sd_bus_message_read(m
, "(ss)", &partition
, &mount_options
)) > 0)
1637 if (!strextend_with_separator(&str
, ":", partition
, mount_options
))
1640 return bus_log_parse_error(r
);
1642 if (!strextend_with_separator(&paths
, " ", str
))
1645 r
= sd_bus_message_exit_container(m
);
1647 return bus_log_parse_error(r
);
1649 r
= sd_bus_message_exit_container(m
);
1651 return bus_log_parse_error(r
);
1654 r
= sd_bus_message_exit_container(m
);
1656 return bus_log_parse_error(r
);
1658 bus_print_property_value(name
, expected_value
, flags
, paths
);
1662 } else if (streq(name
, "ExtensionImages")) {
1663 _cleanup_free_
char *paths
= NULL
;
1665 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sba(ss))");
1667 return bus_log_parse_error(r
);
1670 _cleanup_free_
char *str
= NULL
;
1671 const char *source
, *partition
, *mount_options
;
1674 r
= sd_bus_message_enter_container(m
, 'r', "sba(ss)");
1676 return bus_log_parse_error(r
);
1680 r
= sd_bus_message_read(m
, "sb", &source
, &ignore_enoent
);
1682 return bus_log_parse_error(r
);
1684 str
= strjoin(ignore_enoent
? "-" : "", source
);
1688 r
= sd_bus_message_enter_container(m
, 'a', "(ss)");
1690 return bus_log_parse_error(r
);
1692 while ((r
= sd_bus_message_read(m
, "(ss)", &partition
, &mount_options
)) > 0)
1693 if (!strextend_with_separator(&str
, ":", partition
, mount_options
))
1696 return bus_log_parse_error(r
);
1698 if (!strextend_with_separator(&paths
, " ", str
))
1701 r
= sd_bus_message_exit_container(m
);
1703 return bus_log_parse_error(r
);
1705 r
= sd_bus_message_exit_container(m
);
1707 return bus_log_parse_error(r
);
1710 r
= sd_bus_message_exit_container(m
);
1712 return bus_log_parse_error(r
);
1714 bus_print_property_value(name
, expected_value
, flags
, paths
);
1718 } else if (streq(name
, "BPFProgram")) {
1721 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(ss)");
1723 return bus_log_parse_error(r
);
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
);
1728 return bus_log_parse_error(r
);
1730 r
= sd_bus_message_exit_container(m
);
1732 return bus_log_parse_error(r
);
1735 } else if (STR_IN_SET(name
, "SocketBindAllow", "SocketBindDeny")) {
1736 uint16_t nr_ports
, port_min
;
1737 int32_t af
, ip_protocol
;
1739 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(iiqq)");
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
= "";
1745 family
= strempty(af_to_ipv4_ipv6(af
));
1746 colon1
= isempty(family
) ? "" : ":";
1748 if (ip_protocol
!= 0) {
1749 protocol
= ip_protocol_to_tcp_udp(ip_protocol
);
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
);
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));
1767 return bus_log_parse_error(r
);
1769 r
= sd_bus_message_exit_container(m
);
1771 return bus_log_parse_error(r
);
1774 } else if (STR_IN_SET(name
, "StateDirectorySymlink", "RuntimeDirectorySymlink", "CacheDirectorySymlink", "LogsDirectorySymlink")) {
1776 uint64_t symlink_flags
;
1778 r
= sd_bus_message_enter_container(m
, SD_BUS_TYPE_ARRAY
, "(sst)");
1780 return bus_log_parse_error(r
);
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
);
1785 return bus_log_parse_error(r
);
1787 r
= sd_bus_message_exit_container(m
);
1789 return bus_log_parse_error(r
);
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
;
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",
1814 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(systemctl_show_mode
, SystemctlShowMode
);
1816 static int show_one(
1820 SystemctlShowMode show_mode
,
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
) },
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 },
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
,
1942 log_debug("Showing one %s", path
);
1944 r
= bus_map_all_properties(
1946 "org.freedesktop.systemd1",
1948 show_mode
== SYSTEMCTL_SHOW_STATUS
? status_map
: property_map
,
1949 BUS_MAP_BOOLEAN_AS_BOOL
,
1954 return log_error_errno(r
, "Failed to get properties: %s", bus_error_message(&error
, r
));
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
);
1960 if (show_mode
== SYSTEMCTL_SHOW_STATUS
)
1961 return EXIT_PROGRAM_OR_SERVICES_STATUS_UNKNOWN
;
1962 if (show_mode
== SYSTEMCTL_SHOW_HELP
)
1971 if (show_mode
== SYSTEMCTL_SHOW_STATUS
) {
1972 print_status_info(bus
, &info
, ellipsized
);
1974 if (info
.active_state
&& !STR_IN_SET(info
.active_state
, "active", "reloading"))
1975 return EXIT_PROGRAM_NOT_RUNNING
;
1977 return EXIT_PROGRAM_RUNNING_OR_SERVICE_OK
;
1979 } else if (show_mode
== SYSTEMCTL_SHOW_HELP
) {
1980 show_unit_help(&info
);
1984 r
= sd_bus_message_rewind(reply
, true);
1986 return log_error_errno(r
, "Failed to rewind: %s", bus_error_message(&error
, r
));
1988 r
= bus_message_print_all_properties(reply
, print_property
, arg_properties
, arg_print_flags
, &found_properties
);
1990 return bus_log_parse_error(r
);
1992 STRV_FOREACH(pp
, arg_properties
)
1993 if (!set_contains(found_properties
, *pp
))
1994 log_debug("Property %s does not exist.", *pp
);
1999 static int get_unit_dbus_path_by_pid(
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
;
2009 r
= bus_call_method(bus
, bus_systemd_mgr
, "GetUnitByPID", &error
, &reply
, "u", pid
);
2011 return log_error_errno(r
, "Failed to get unit for PID %"PRIu32
": %s", pid
, bus_error_message(&error
, r
));
2013 r
= sd_bus_message_read(reply
, "o", &u
);
2015 return bus_log_parse_error(r
);
2025 static int show_all(
2030 _cleanup_(sd_bus_message_unrefp
) sd_bus_message
*reply
= NULL
;
2031 _cleanup_free_ UnitInfo
*unit_infos
= NULL
;
2035 r
= get_unit_list(bus
, NULL
, NULL
, &unit_infos
, 0, &reply
);
2039 (void) pager_open(arg_pager_flags
);
2043 typesafe_qsort(unit_infos
, c
, unit_info_compare
);
2045 for (const UnitInfo
*u
= unit_infos
; u
< unit_infos
+ c
; u
++) {
2046 _cleanup_free_
char *p
= NULL
;
2048 p
= unit_dbus_path_from_name(u
->id
);
2052 r
= show_one(bus
, p
, u
->id
, SYSTEMCTL_SHOW_STATUS
, new_line
, ellipsized
);
2055 if (r
> 0 && ret
== 0)
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
;
2071 hn
= gethostname_malloc();
2075 r
= bus_map_all_properties(
2077 "org.freedesktop.systemd1",
2078 "/org/freedesktop/systemd1",
2079 machine_info_property_map
,
2085 return log_error_errno(r
, "Failed to read server status: %s", bus_error_message(&error
, r
));
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();
2094 on
= ansi_highlight_yellow();
2095 off
= ansi_normal();
2098 printf("%s%s%s %s\n", on
, special_glyph(SPECIAL_GLYPH_BLACK_CIRCLE
), off
, arg_host
?: hn
);
2100 printf(" State: %s%s%s\n",
2101 on
, strna(mi
.state
), off
);
2103 printf(" Jobs: %" PRIu32
" queued\n", mi
.n_jobs
);
2104 printf(" Failed: %" PRIu32
" units\n", mi
.n_failed_units
);
2106 printf(" Since: %s; %s\n",
2107 FORMAT_TIMESTAMP_STYLE(mi
.timestamp
, arg_timestamp_style
),
2108 FORMAT_TIMESTAMP_RELATIVE(mi
.timestamp
));
2110 printf(" CGroup: %s\n", empty_to_root(mi
.control_group
));
2112 c
= LESS_BY(columns(), strlen(prefix
));
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());
2118 log_warning_errno(r
, "Failed to dump process list for '%s', ignoring: %s",
2119 arg_host
?: hn
, bus_error_message(&error
, r
));
2124 int show(int argc
, char *argv
[], void *userdata
) {
2125 bool new_line
= false, ellipsized
= false;
2126 SystemctlShowMode show_mode
;
2132 show_mode
= systemctl_show_mode_from_string(argv
[0]);
2134 return log_error_errno(show_mode
, "Invalid argument.");
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)");
2141 r
= acquire_bus(BUS_MANAGER
, &bus
);
2145 (void) pager_open(arg_pager_flags
);
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
);
2151 if (show_mode
== SYSTEMCTL_SHOW_STATUS
&& argc
<= 1) {
2153 show_system_status(bus
);
2157 ret
= show_all(bus
, &new_line
, &ellipsized
);
2159 _cleanup_free_
char **patterns
= NULL
;
2162 STRV_FOREACH(name
, strv_skip(argv
, 1)) {
2163 _cleanup_free_
char *path
= NULL
, *unit
= NULL
;
2166 if (safe_atou32(*name
, &id
) < 0) {
2167 if (strv_push(&patterns
, *name
) < 0)
2171 } else if (show_mode
== SYSTEMCTL_SHOW_PROPERTIES
) {
2172 /* Interpret as job id */
2173 if (asprintf(&path
, "/org/freedesktop/systemd1/job/%u", id
) < 0)
2177 /* Interpret as PID */
2178 r
= get_unit_dbus_path_by_pid(bus
, id
, &path
);
2184 r
= unit_name_from_dbus_path(path
, &unit
);
2189 r
= show_one(bus
, path
, unit
, show_mode
, &new_line
, &ellipsized
);
2192 if (r
> 0 && ret
== 0)
2196 if (!strv_isempty(patterns
)) {
2197 _cleanup_strv_free_
char **names
= NULL
;
2199 r
= expand_unit_names(bus
, patterns
, NULL
, &names
, NULL
);
2201 return log_error_errno(r
, "Failed to expand names: %m");
2203 r
= maybe_extend_with_unit_dependencies(bus
, &names
);
2207 STRV_FOREACH(name
, names
) {
2208 _cleanup_free_
char *path
= NULL
;
2210 path
= unit_dbus_path_from_name(*name
);
2214 r
= show_one(bus
, path
, *name
, show_mode
, &new_line
, &ellipsized
);
2217 if (r
> 0 && ret
== 0)
2223 if (ellipsized
&& !arg_quiet
)
2224 printf("Hint: Some lines were ellipsized, use -l to show in full.\n");