From: Lukas Nykryn Date: Mon, 12 Aug 2024 13:15:15 +0000 (+0200) Subject: systemd-run: add unit and invocation_id JSON output X-Git-Tag: v257-rc1~713 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=fe5a6c47af675bc0020c545d86fb103492e1d77c;p=thirdparty%2Fsystemd.git systemd-run: add unit and invocation_id JSON output --- diff --git a/man/systemd-run.xml b/man/systemd-run.xml index e1986c1f52f..83c62afb592 100644 --- a/man/systemd-run.xml +++ b/man/systemd-run.xml @@ -530,6 +530,7 @@ + All command line arguments after the first non-option argument become part of the command line of diff --git a/shell-completion/bash/systemd-run b/shell-completion/bash/systemd-run index 4bc82060e94..4537211ae55 100644 --- a/shell-completion/bash/systemd-run +++ b/shell-completion/bash/systemd-run @@ -38,7 +38,7 @@ _systemd_run() { --unit -p --property --slice --description --service-type --uid --gid --nice --working-directory -E --setenv --on-active --on-boot --on-startup --on-unit-active --on-unit-inactive --on-calendar --path-property --socket-property --timer-property -H --host -M --machine --expand-environment - --background + --background --json ) local OPTS="${opts_with_values[*]} --no-ask-password --scope -u --slice-inherit -r --remain-after-exit --send-sighup -d --same-dir -t --pty -P --pipe -S --shell -q --quiet --ignore-failure @@ -126,6 +126,11 @@ _systemd_run() { COMPREPLY=( $(compgen -W '$comps' -- "$cur" ) ) return 0 ;; + --json) + local comps='pretty short off' + COMPREPLY=( $(compgen -W '$comps' -- "$cur") ) + return 0 + ;; esac COMPREPLY=( $(compgen -W '${OPTS[*]}' -- "$cur") ) diff --git a/shell-completion/zsh/_systemd-run b/shell-completion/zsh/_systemd-run index d3ec2e28efe..4bb864da219 100644 --- a/shell-completion/zsh/_systemd-run +++ b/shell-completion/zsh/_systemd-run @@ -59,6 +59,7 @@ _arguments \ ))' \ '(-t --pty)'{-t,--pty}'[The service connects to the terminal]' \ '(-q --quiet)'{-q,--quiet}'[Suppresses additional informational output]' \ + '--json=[Output as JSON]:JSON:(pretty short off)' \ '(-r --remain-after-exit)'{-r,--remain-after-exit}'[Leave service around until explicitly stopped]' \ '(-d --same-dir)'{-d,--same-dir}'[Run on the current working directory]' \ '--scope[Run this as scope rather than service]' \ diff --git a/src/run/run.c b/src/run/run.c index e86e89b51b3..62140062ab3 100644 --- a/src/run/run.c +++ b/src/run/run.c @@ -8,6 +8,7 @@ #include "sd-bus.h" #include "sd-event.h" +#include "sd-json.h" #include "alloc-util.h" #include "build.h" @@ -83,6 +84,7 @@ static char **arg_cmdline = NULL; static char *arg_exec_path = NULL; static bool arg_ignore_failure = false; static char *arg_background = NULL; +static sd_json_format_flags_t arg_json_format_flags = SD_JSON_FORMAT_OFF; STATIC_DESTRUCTOR_REGISTER(arg_description, freep); STATIC_DESTRUCTOR_REGISTER(arg_environment, strv_freep); @@ -133,6 +135,7 @@ static int help(void) { " STDERR\n" " -P --pipe Pass STDIN/STDOUT/STDERR directly to service\n" " -q --quiet Suppress information messages during runtime\n" + " --json=pretty|short|off Print unit name and invocation id as JSON\n" " -G --collect Unload unit after it ran, even when failed\n" " -S --shell Invoke a $SHELL interactively\n" " --ignore-failure Ignore the exit status of the invoked process\n" @@ -263,6 +266,7 @@ static int parse_argv(int argc, char *argv[]) { ARG_SHELL, ARG_IGNORE_FAILURE, ARG_BACKGROUND, + ARG_JSON, }; static const struct option options[] = { @@ -311,6 +315,7 @@ static int parse_argv(int argc, char *argv[]) { { "shell", no_argument, NULL, 'S' }, { "ignore-failure", no_argument, NULL, ARG_IGNORE_FAILURE }, { "background", required_argument, NULL, ARG_BACKGROUND }, + { "json", required_argument, NULL, ARG_JSON }, {}, }; @@ -618,6 +623,12 @@ static int parse_argv(int argc, char *argv[]) { return r; break; + case ARG_JSON: + r = parse_json_argument(optarg, &arg_json_format_flags); + if (r <= 0) + return r; + break; + case '?': return -EINVAL; @@ -1686,6 +1697,33 @@ static int chown_to_capsule(const char *path, const char *capsule) { return chmod_and_chown(path, 0600, st.st_uid, st.st_gid); } +static int print_unit_invocation(const char *unit, sd_id128_t invocation_id) { + _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL; + int r; + + assert(unit); + + if (FLAGS_SET(arg_json_format_flags, SD_JSON_FORMAT_OFF)) { + if (sd_id128_is_null(invocation_id)) + log_info("Running as unit: %s", unit); + else + log_info("Running as unit: %s; invocation ID: " SD_ID128_FORMAT_STR, unit, SD_ID128_FORMAT_VAL(invocation_id)); + return 0; + } + + r = sd_json_variant_set_field_string(&v, "unit", unit); + if (r < 0) + return r; + + if (!sd_id128_is_null(invocation_id)) { + r = sd_json_variant_set_field_string(&v, "invocation_id", SD_ID128_TO_STRING(invocation_id)); + if (r < 0) + return r; + } + + return sd_json_variant_dump(v, arg_json_format_flags, stdout, NULL); +} + static int start_transient_service(sd_bus *bus) { _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL, *reply = NULL; _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL; @@ -1807,15 +1845,15 @@ static int start_transient_service(sd_bus *bus) { } if (!arg_quiet) { - sd_id128_t invocation_id; + sd_id128_t invocation_id = SD_ID128_NULL; r = acquire_invocation_id(bus, service, &invocation_id); if (r < 0) return r; - if (r == 0) /* No invocation UUID set */ - log_info("Running as unit: %s", service); - else - log_info("Running as unit: %s; invocation ID: " SD_ID128_FORMAT_STR, service, SD_ID128_FORMAT_VAL(invocation_id)); + + r = print_unit_invocation(service, invocation_id); + if (r < 0) + return r; } if (arg_wait || arg_stdio != ARG_STDIO_NONE) { @@ -1976,7 +2014,7 @@ static int start_transient_scope(sd_bus *bus) { _cleanup_strv_free_ char **env = NULL, **user_env = NULL; _cleanup_free_ char *scope = NULL; const char *object = NULL; - sd_id128_t invocation_id; + sd_id128_t invocation_id = SD_ID128_NULL; bool allow_pidfd = true; int r; @@ -2131,10 +2169,9 @@ static int start_transient_scope(sd_bus *bus) { return log_oom(); if (!arg_quiet) { - if (sd_id128_is_null(invocation_id)) - log_info("Running as unit: %s", scope); - else - log_info("Running as unit: %s; invocation ID: " SD_ID128_FORMAT_STR, scope, SD_ID128_FORMAT_VAL(invocation_id)); + r = print_unit_invocation(scope, invocation_id); + if (r < 0) + return r; } if (arg_expand_environment > 0) { diff --git a/test/units/TEST-74-AUX-UTILS.run.sh b/test/units/TEST-74-AUX-UTILS.run.sh index b4ff72e440d..9e0a429e414 100755 --- a/test/units/TEST-74-AUX-UTILS.run.sh +++ b/test/units/TEST-74-AUX-UTILS.run.sh @@ -205,6 +205,8 @@ SHELL=/bin/true systemd-run --shell SHELL=/bin/true systemd-run --scope --shell systemd-run --wait --pty true systemd-run --wait --machine=.host --pty true +systemd-run --json=short /bin/true | jq . >/dev/null +systemd-run --json=pretty /bin/true | jq . >/dev/null (! SHELL=/bin/false systemd-run --quiet --shell) (! systemd-run)