From 8e8df8292a898ef8f4ac9107a45e86c83fbb3178 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 17 Mar 2023 12:46:51 +0900 Subject: [PATCH 1/5] exec-util: tighten variable scope a bit --- src/shared/exec-util.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 40e9342cd5..d38bfc9e4a 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -203,23 +203,24 @@ int execute_directories( ExecDirFlags flags) { char **dirs = (char**) directories; - _cleanup_free_ char *name = NULL; _cleanup_close_ int fd = -EBADF; int r; pid_t executor_pid; assert(!strv_isempty(dirs)); - r = path_extract_filename(dirs[0], &name); - if (r < 0) - return log_error_errno(r, "Failed to extract file name from '%s': %m", dirs[0]); - if (callbacks) { assert(callback_args); assert(callbacks[STDOUT_GENERATE]); assert(callbacks[STDOUT_COLLECT]); assert(callbacks[STDOUT_CONSUME]); + _cleanup_free_ char *name = NULL; + + r = path_extract_filename(dirs[0], &name); + if (r < 0) + return log_error_errno(r, "Failed to extract file name from '%s': %m", dirs[0]); + fd = open_serialization_fd(name); if (fd < 0) return log_error_errno(fd, "Failed to open serialization file: %m"); From fb0e5f12c6c4e09da8a942ca2a87e54bee4abc6f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 17 Mar 2023 12:56:05 +0900 Subject: [PATCH 2/5] exec-util: drop meaningless casts --- src/shared/exec-util.c | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index d38bfc9e4a..1562911ec6 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -77,7 +77,7 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid, b } static int do_execute( - char **directories, + const char* const* directories, usec_t timeout, gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], void* const callback_args[_STDOUT_CONSUME_MAX], @@ -99,7 +99,7 @@ static int do_execute( */ parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks; - r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, (const char* const*) directories); + r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories); if (r < 0) return log_error_errno(r, "Failed to enumerate executables: %m"); @@ -202,12 +202,11 @@ int execute_directories( char *envp[], ExecDirFlags flags) { - char **dirs = (char**) directories; _cleanup_close_ int fd = -EBADF; int r; pid_t executor_pid; - assert(!strv_isempty(dirs)); + assert(!strv_isempty((char**) directories)); if (callbacks) { assert(callback_args); @@ -217,9 +216,9 @@ int execute_directories( _cleanup_free_ char *name = NULL; - r = path_extract_filename(dirs[0], &name); + r = path_extract_filename(directories[0], &name); if (r < 0) - return log_error_errno(r, "Failed to extract file name from '%s': %m", dirs[0]); + return log_error_errno(r, "Failed to extract file name from '%s': %m", directories[0]); fd = open_serialization_fd(name); if (fd < 0) @@ -234,7 +233,7 @@ int execute_directories( if (r < 0) return r; if (r == 0) { - r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp, flags); + r = do_execute(directories, timeout, callbacks, callback_args, fd, argv, envp, flags); _exit(r < 0 ? EXIT_FAILURE : r); } From 753e38d9849a13ed58970161d89dc4a5834d835d Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Fri, 17 Mar 2023 12:59:40 +0900 Subject: [PATCH 3/5] exec-util: enumerate executables earlier Then, return earlier if no executable found. --- src/shared/exec-util.c | 23 +++++++++++++---------- 1 file changed, 13 insertions(+), 10 deletions(-) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 1562911ec6..e44323e0e9 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -77,7 +77,7 @@ static int do_spawn(const char *path, char *argv[], int stdout_fd, pid_t *pid, b } static int do_execute( - const char* const* directories, + char* const* paths, usec_t timeout, gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], void* const callback_args[_STDOUT_CONSUME_MAX], @@ -87,9 +87,8 @@ static int do_execute( ExecDirFlags flags) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; - _cleanup_strv_free_ char **paths = NULL; - int r; bool parallel_execution; + int r; /* We fork this all off from a child process so that we can somewhat cleanly make * use of SIGALRM to set a time limit. @@ -99,10 +98,6 @@ static int do_execute( */ parallel_execution = FLAGS_SET(flags, EXEC_DIR_PARALLEL) && !callbacks; - r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories); - if (r < 0) - return log_error_errno(r, "Failed to enumerate executables: %m"); - if (parallel_execution) { pids = hashmap_new(NULL); if (!pids) @@ -202,11 +197,19 @@ int execute_directories( char *envp[], ExecDirFlags flags) { + _cleanup_strv_free_ char **paths = NULL; _cleanup_close_ int fd = -EBADF; - int r; pid_t executor_pid; + int r; - assert(!strv_isempty((char**) directories)); + r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories); + if (r < 0) + return log_error_errno(r, "Failed to enumerate executables: %m"); + + if (strv_isempty(paths)) { + log_debug("No executables found."); + return 0; + } if (callbacks) { assert(callback_args); @@ -233,7 +236,7 @@ int execute_directories( if (r < 0) return r; if (r == 0) { - r = do_execute(directories, timeout, callbacks, callback_args, fd, argv, envp, flags); + r = do_execute(paths, timeout, callbacks, callback_args, fd, argv, envp, flags); _exit(r < 0 ? EXIT_FAILURE : r); } From f691157b87371266d0cab1b9e67a3bc3808ce30f Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 16 Mar 2023 11:16:51 +0900 Subject: [PATCH 4/5] exec-util: extract the core logic of execute_directories() as execute_strv() Then, we can use it with a custom enumerator of executables. No functional change, preparation for later commits. --- src/shared/exec-util.c | 54 +++++++++++++++++++++++++++++------------- src/shared/exec-util.h | 10 ++++++++ 2 files changed, 48 insertions(+), 16 deletions(-) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index e44323e0e9..29f8381883 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -188,8 +188,9 @@ static int do_execute( return 0; } -int execute_directories( - const char* const* directories, +int execute_strv( + const char *name, + char* const* paths, usec_t timeout, gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], void* const callback_args[_STDOUT_CONSUME_MAX], @@ -197,32 +198,20 @@ int execute_directories( char *envp[], ExecDirFlags flags) { - _cleanup_strv_free_ char **paths = NULL; _cleanup_close_ int fd = -EBADF; pid_t executor_pid; int r; - r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories); - if (r < 0) - return log_error_errno(r, "Failed to enumerate executables: %m"); - - if (strv_isempty(paths)) { - log_debug("No executables found."); + if (strv_isempty(paths)) return 0; - } if (callbacks) { + assert(name); assert(callback_args); assert(callbacks[STDOUT_GENERATE]); assert(callbacks[STDOUT_COLLECT]); assert(callbacks[STDOUT_CONSUME]); - _cleanup_free_ char *name = NULL; - - r = path_extract_filename(directories[0], &name); - if (r < 0) - return log_error_errno(r, "Failed to extract file name from '%s': %m", directories[0]); - fd = open_serialization_fd(name); if (fd < 0) return log_error_errno(fd, "Failed to open serialization file: %m"); @@ -258,6 +247,39 @@ int execute_directories( return 0; } +int execute_directories( + const char* const* directories, + usec_t timeout, + gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], + void* const callback_args[_STDOUT_CONSUME_MAX], + char *argv[], + char *envp[], + ExecDirFlags flags) { + + _cleanup_strv_free_ char **paths = NULL; + _cleanup_free_ char *name = NULL; + int r; + + assert(!strv_isempty((char**) directories)); + + r = conf_files_list_strv(&paths, NULL, NULL, CONF_FILES_EXECUTABLE|CONF_FILES_REGULAR|CONF_FILES_FILTER_MASKED, directories); + if (r < 0) + return log_error_errno(r, "Failed to enumerate executables: %m"); + + if (strv_isempty(paths)) { + log_debug("No executables found."); + return 0; + } + + if (callbacks) { + r = path_extract_filename(directories[0], &name); + if (r < 0) + return log_error_errno(r, "Failed to extract file name from '%s': %m", directories[0]); + } + + return execute_strv(name, paths, timeout, callbacks, callback_args, argv, envp, flags); +} + static int gather_environment_generate(int fd, void *arg) { char ***env = ASSERT_PTR(arg); _cleanup_fclose_ FILE *f = NULL; diff --git a/src/shared/exec-util.h b/src/shared/exec-util.h index ba4506e5aa..a18c108e1b 100644 --- a/src/shared/exec-util.h +++ b/src/shared/exec-util.h @@ -30,6 +30,16 @@ typedef enum ExecCommandFlags { _EXEC_COMMAND_FLAGS_INVALID = -EINVAL, } ExecCommandFlags; +int execute_strv( + const char *name, + char* const* paths, + usec_t timeout, + gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], + void* const callback_args[_STDOUT_CONSUME_MAX], + char *argv[], + char *envp[], + ExecDirFlags flags); + int execute_directories( const char* const* directories, usec_t timeout, From 6ad9af0b1356ac52db36a21088b553e8eeb9b396 Mon Sep 17 00:00:00 2001 From: Yu Watanabe Date: Thu, 16 Mar 2023 11:34:14 +0900 Subject: [PATCH 5/5] exec-util: introduce EXEC_DIR_SKIP_REMAINING flag Will be used in later commits. --- src/shared/exec-util.c | 24 +++++++++++++++++++++--- src/shared/exec-util.h | 1 + 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 29f8381883..ac68cbc4cb 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -30,6 +30,8 @@ #include "terminal-util.h" #include "tmpfile-util.h" +#define EXIT_SKIP_REMAINING 77 + /* Put this test here for a lack of better place */ assert_cc(EAGAIN == EWOULDBLOCK); @@ -145,11 +147,22 @@ static int do_execute( return log_oom(); t = NULL; } else { - r = wait_for_terminate_and_check(t, pid, WAIT_LOG); + bool skip_remaining = false; + + r = wait_for_terminate_and_check(t, pid, WAIT_LOG_ABNORMAL); if (r < 0) return r; - if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0) - return r; + if (r > 0) { + if (FLAGS_SET(flags, EXEC_DIR_SKIP_REMAINING) && r == EXIT_SKIP_REMAINING) { + log_info("%s succeeded with exit status %i, not executing remaining executables.", *path, r); + skip_remaining = true; + } else if (FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS)) + log_warning("%s failed with exit status %i, ignoring.", *path, r); + else { + log_error("%s failed with exit status %i.", *path, r); + return r; + } + } if (callbacks) { if (lseek(fd, 0, SEEK_SET) < 0) @@ -159,6 +172,9 @@ static int do_execute( if (r < 0) return log_error_errno(r, "Failed to process output from %s: %m", *path); } + + if (skip_remaining) + break; } } @@ -202,6 +218,8 @@ int execute_strv( pid_t executor_pid; int r; + assert(!FLAGS_SET(flags, EXEC_DIR_PARALLEL | EXEC_DIR_SKIP_REMAINING)); + if (strv_isempty(paths)) return 0; diff --git a/src/shared/exec-util.h b/src/shared/exec-util.h index a18c108e1b..91dbe3f3b4 100644 --- a/src/shared/exec-util.h +++ b/src/shared/exec-util.h @@ -19,6 +19,7 @@ typedef enum { EXEC_DIR_PARALLEL = 1 << 0, /* Execute scripts in parallel, if possible */ EXEC_DIR_IGNORE_ERRORS = 1 << 1, /* Ignore non-zero exit status of scripts */ EXEC_DIR_SET_SYSTEMD_EXEC_PID = 1 << 2, /* Set $SYSTEMD_EXEC_PID environment variable */ + EXEC_DIR_SKIP_REMAINING = 1 << 3, /* Ignore remaining executions when one exit with 77. */ } ExecDirFlags; typedef enum ExecCommandFlags {