diff --git a/man/systemd-notify.xml b/man/systemd-notify.xml index 0e0cc6cdd09..6c2c8a75a1a 100644 --- a/man/systemd-notify.xml +++ b/man/systemd-notify.xml @@ -240,6 +240,24 @@ + + + + Remove file descriptors from the service's file descriptor store whose names match + the specified case-sensitive shell-style glob. The argument is required, and an explicitly empty + argument is equivalent to * and removes all stored file descriptors. The pattern + should be quoted to prevent expansion by the invoking shell. For example, + --fdstore-wipe='connection-*' removes all descriptors whose names start with + connection-. + + This is equivalent to sending FDSTOREWIPE= with the specified pattern + (or * when the argument is empty) via + sd_notify3. + This option may not be combined with . + + + + diff --git a/shell-completion/bash/systemd-notify b/shell-completion/bash/systemd-notify index 491a54d58b2..dfa7702e6cb 100644 --- a/shell-completion/bash/systemd-notify +++ b/shell-completion/bash/systemd-notify @@ -6,7 +6,7 @@ _systemd_notify() { local cur prev words cword split local i mode=notify do_exec=false after_separator=false parse_options=true local OPTS='-h --help --version --ready --reloading --stopping --pid= --uid= --status= - --booted --no-block --exec --fd= --fdname= --fork -q --quiet' + --booted --no-block --exec --fd= --fdname= --fdstore-wipe= --fork -q --quiet' _init_completion -s || return @@ -17,7 +17,7 @@ _systemd_notify() { ((i < cword)) && parse_options=false continue ;; - --uid|--status|--fd|--fdname) + --uid|--status|--fd|--fdname|--fdstore-wipe) ((i++)) continue ;; @@ -64,7 +64,7 @@ _systemd_notify() { _comp_compgen -- -u return ;; - --status|--fd|--fdname) + --status|--fd|--fdname|--fdstore-wipe) return ;; esac diff --git a/shell-completion/zsh/_systemd b/shell-completion/zsh/_systemd index f555abd06b5..2a610d08837 100644 --- a/shell-completion/zsh/_systemd +++ b/shell-completion/zsh/_systemd @@ -64,6 +64,7 @@ case "$service" in '--ready[Inform the init system about service start-up completion.]' \ '--pid=[Inform the init system about the main PID of the daemon]:daemon main PID:_pids' \ '--status=[Send a free-form status string for the daemon to the init systemd]:status string:' \ + '--fdstore-wipe=[Remove stored file descriptors by name glob]:glob:' \ '--booted[Returns 0 if the system was booted up with systemd]' ;; systemd-tty-ask-password-agent) diff --git a/src/notify/notify.c b/src/notify/notify.c index 9b630ab3903..3f736fea445 100644 --- a/src/notify/notify.c +++ b/src/notify/notify.c @@ -47,6 +47,7 @@ static char **arg_env = NULL; static char **arg_exec = NULL; static FDSet *arg_fds = NULL; static char *arg_fdname = NULL; +static char *arg_fdstore_wipe = NULL; static bool arg_quiet = false; STATIC_DESTRUCTOR_REGISTER(arg_pid, pidref_done); @@ -54,6 +55,7 @@ STATIC_DESTRUCTOR_REGISTER(arg_env, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_exec, strv_freep); STATIC_DESTRUCTOR_REGISTER(arg_fds, fdset_freep); STATIC_DESTRUCTOR_REGISTER(arg_fdname, freep); +STATIC_DESTRUCTOR_REGISTER(arg_fdstore_wipe, freep); COMMAND( "systemd-notify\0", @@ -253,6 +255,19 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { break; + OPTION_LONG("fdstore-wipe", "GLOB", "Remove file descriptors from the store by name glob"): { + const char *pattern = isempty(opts.arg) ? "*" : opts.arg; + + if (!fdname_glob_is_valid(pattern)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "File descriptor name pattern invalid: %s", opts.arg); + + r = free_and_strdup_warn(&arg_fdstore_wipe, pattern); + if (r < 0) + return r; + + break; + } + OPTION_LONG("fork", NULL, "Receive notifications from child rather than sending them"): arg_action = ACTION_FORK; break; @@ -265,7 +280,8 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { return introspect_cli(SD_JSON_FORMAT_OFF); } - bool have_env = arg_ready || arg_stopping || arg_reloading || arg_status || pidref_is_set(&arg_pid) || !fdset_isempty(arg_fds); + bool have_env = arg_ready || arg_stopping || arg_reloading || arg_status || pidref_is_set(&arg_pid) || + !fdset_isempty(arg_fds) || arg_fdstore_wipe; char **args = option_parser_get_args(&opts); @@ -274,6 +290,8 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { case ACTION_NOTIFY: { if (arg_fdname && fdset_isempty(arg_fds)) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No file descriptors passed, but --fdname= used, refusing."); + if (arg_fdstore_wipe && !fdset_isempty(arg_fds)) + return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "--fdstore-wipe= may not be combined with --fd=, refusing."); size_t n_arg_env; @@ -333,7 +351,7 @@ static int parse_argv(int argc, char *argv[], char ***ret_args) { if (have_env && arg_action != ACTION_NOTIFY) return log_error_errno(SYNTHETIC_ERRNO(EINVAL), - "--ready, --reloading, --stopping, --pid=, --status=, --fd= may not be combined with --fork or --booted, refusing."); + "--ready, --reloading, --stopping, --pid=, --status=, --fd=, --fdstore-wipe= may not be combined with --fork or --booted, refusing."); *ret_args = args; @@ -503,9 +521,9 @@ static int action_fork(char *const *_command) { static int run(int argc, char* argv[]) { _cleanup_free_ char *status = NULL, *main_pid = NULL, *main_pidfd_id = NULL, *msg = NULL, - *monotonic_usec = NULL, *fdn = NULL; + *monotonic_usec = NULL, *fdn = NULL, *fdstore_wipe = NULL; _cleanup_strv_free_ char **final_env = NULL; - const char *our_env[10]; + const char *our_env[11]; size_t i = 0; char **args = NULL; /* unnecessary initialization to appease gcc */ int r; @@ -571,6 +589,14 @@ static int run(int argc, char* argv[]) { } } + if (arg_fdstore_wipe) { + fdstore_wipe = strjoin("FDSTOREWIPE=", arg_fdstore_wipe); + if (!fdstore_wipe) + return log_oom(); + + our_env[i++] = fdstore_wipe; + } + if (!fdset_isempty(arg_fds)) { our_env[i++] = "FDSTORE=1";