From 9b16161f343164f6adce8f5c248c6af3f5b814a0 Mon Sep 17 00:00:00 2001 From: Ivan Kruglov Date: Tue, 11 Aug 2026 07:47:32 -0700 Subject: [PATCH 1/3] analyze: allow --json= for the chid, blame and identify-tpm2 verbs verb_chid(), verb_blame() and verb_identify_tpm2() all render their output via table_print_with_pager() with arg_json_format_flags, so JSON output has been implemented for them since they were introduced. However, none of them was ever added to the verb allowlist that gates --json=, so e.g. "systemd-analyze chid --json=pretty" failed with: Option --json= is only supported for security, inspect-elf, ... Add them to the allowlist (and the error message) so the option is accepted. These are the only remaining verbs that render through arg_json_format_flags but were not allowlisted. Note that has-tpm2 is deliberately not included: verb_has_tpm2() defers to verb_has_tpm2_generic(), which writes plain text via printf() and has no JSON support, so accepting --json= there would silently ignore it. This went unnoticed for chid because the TEST-65-ANALYZE coverage for it is guarded behind a check for SMBIOS board_vendor and a non-container environment, so it only runs on bare-metal/VM runners. --- src/analyze/analyze.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/analyze/analyze.c b/src/analyze/analyze.c index fbdbc83fe7..d6675f5eb0 100644 --- a/src/analyze/analyze.c +++ b/src/analyze/analyze.c @@ -625,9 +625,9 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { "Option --offline= requires one or more units to perform a security review."); if (arg_json_format_flags != SD_JSON_FORMAT_OFF && - !STRPTR_IN_SET(verb, "security", "inspect-elf", "dlopen-metadata", "plot", "fdstore", "pcrs", "nvpcrs", "architectures", "capability", "exit-status")) + !STRPTR_IN_SET(verb, "security", "inspect-elf", "dlopen-metadata", "plot", "fdstore", "pcrs", "nvpcrs", "architectures", "capability", "exit-status", "chid", "blame", "identify-tpm2")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "Option --json= is only supported for security, inspect-elf, dlopen-metadata, plot, fdstore, pcrs, nvpcrs, architectures, capability, exit-status right now."); + "Option --json= is only supported for security, inspect-elf, dlopen-metadata, plot, fdstore, pcrs, nvpcrs, architectures, capability, exit-status, chid, blame, identify-tpm2 right now."); if (arg_threshold != 100 && !streq_ptr(verb, "security")) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), From b3f76af401cb2d3f95c9b5975acec2caed1632d8 Mon Sep 17 00:00:00 2001 From: Ivan Kruglov Date: Wed, 12 Aug 2026 03:54:10 -0700 Subject: [PATCH 2/3] shell-completion: offer --json= for the standalone verbs that support it Several verbs in the STANDALONE bucket accept --json=, but that bucket only offers --help --version --system --user --global --no-pager, so completion never suggested the option for them. Split those verbs out into a new STANDALONE_JSON bucket that additionally offers --json=off/pretty/short. The verbs are moved rather than copied, as ${VERBS[*]} is used to complete the verb list itself. --- shell-completion/bash/systemd-analyze | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/shell-completion/bash/systemd-analyze b/shell-completion/bash/systemd-analyze index b194c74b63..04b4e56e12 100644 --- a/shell-completion/bash/systemd-analyze +++ b/shell-completion/bash/systemd-analyze @@ -77,7 +77,8 @@ _systemd_analyze() { ) local -A VERBS=( - [STANDALONE]='time blame unit-files unit-paths exit-status compare-versions timestamp timespan pcrs nvpcrs srk has-tpm2 identify-tpm2 smbios11 chid image-policy' + [STANDALONE]='time unit-files unit-paths compare-versions timestamp timespan srk has-tpm2 smbios11 image-policy' + [STANDALONE_JSON]='blame exit-status pcrs nvpcrs identify-tpm2 chid' [CRITICAL_CHAIN]='critical-chain' [DOT]='dot' [DUMP]='dump' @@ -153,6 +154,11 @@ _systemd_analyze() { comps='--help --version --system --user --global --no-pager' fi + elif __contains_word "$verb" ${VERBS[STANDALONE_JSON]}; then + if [[ $cur = -* ]]; then + comps='--help --version --system --user --global --no-pager --json=off --json=pretty --json=short' + fi + elif __contains_word "$verb" ${VERBS[CRITICAL_CHAIN]}; then if [[ $cur = -* ]]; then comps='--help --version --system --user --fuzz --no-pager' From 46a91a1867dc76f5d0254993ff42d5d7a55fd946 Mon Sep 17 00:00:00 2001 From: Ivan Kruglov Date: Wed, 12 Aug 2026 03:54:33 -0700 Subject: [PATCH 3/3] test: cover --json= for the blame and identify-tpm2 verbs Both verbs render through arg_json_format_flags but --json= was rejected for them until the previous commit, and nothing in TEST-65-ANALYZE exercised it. Add coverage in line with the other JSON-capable verbs. identify-tpm2 is only invoked when has-tpm2 reports full support, as it fails with EOPNOTSUPP when built without TPM2 support. --- test/units/TEST-65-ANALYZE.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/units/TEST-65-ANALYZE.sh b/test/units/TEST-65-ANALYZE.sh index a470883aff..05a7b7f0c1 100755 --- a/test/units/TEST-65-ANALYZE.sh +++ b/test/units/TEST-65-ANALYZE.sh @@ -18,6 +18,7 @@ systemd-analyze time || : systemd-analyze critical-chain || : # blame systemd-analyze blame +systemd-analyze blame --json=pretty systemd-run --wait --user --pipe -M testuser@.host systemd-analyze blame --no-pager (! systemd-analyze blame --global) # plot @@ -1139,6 +1140,8 @@ systemd-analyze security --instance=tmp systemd-growfs@.service systemd-analyze has-tpm2 ||: if systemd-analyze has-tpm2 -q ; then echo "have tpm2" + systemd-analyze identify-tpm2 + systemd-analyze identify-tpm2 --json=pretty else echo "have no tpm2" fi