diff options
author | Matthias Klumpp <matthias@tenstral.net> | 2018-09-09 03:18:45 +0200 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2019-02-18 16:16:02 +0100 |
commit | 4b05f0c9d9f6df4e0dab518f8e1ae537bf948f92 (patch) | |
tree | cf8d18410cd148191d951b8f7e60006590011166 /src/shared/exec-util.c | |
parent | bde06abd4f3febc149bf137ca68e4abaa2975b4d (diff) | |
download | systemd-4b05f0c9d9f6df4e0dab518f8e1ae537bf948f92.tar.gz |
core: Allow to configure execute_directories execution behavior
This adds a new bitfield to `execute_directories()` which allows to
configure whether to ignore non-zero exit statuses of binaries run and
whether to allow parallel execution of commands.
In case errors are not ignored, the exit status of the failed script
will now be returned for error reposrting purposes or other further
future use.
Diffstat (limited to 'src/shared/exec-util.c')
-rw-r--r-- | src/shared/exec-util.c | 57 |
1 files changed, 38 insertions, 19 deletions
diff --git a/src/shared/exec-util.c b/src/shared/exec-util.c index 17a278a00f..2867f08a7a 100644 --- a/src/shared/exec-util.c +++ b/src/shared/exec-util.c @@ -78,24 +78,28 @@ static int do_execute( void* const callback_args[_STDOUT_CONSUME_MAX], int output_fd, char *argv[], - char *envp[]) { + char *envp[], + ExecDirFlags flags) { _cleanup_hashmap_free_free_ Hashmap *pids = NULL; _cleanup_strv_free_ char **paths = NULL; char **path, **e; int r; + bool parallel_execution; /* We fork this all off from a child process so that we can somewhat cleanly make * use of SIGALRM to set a time limit. * - * If callbacks is nonnull, execution is serial. Otherwise, we default to parallel. + * We attempt to perform parallel execution if configured by the user, however + * if `callbacks` is nonnull, execution must be serial. */ + 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); if (r < 0) return log_error_errno(r, "Failed to enumerate executables: %m"); - if (!callbacks) { + if (parallel_execution) { pids = hashmap_new(NULL); if (!pids) return log_oom(); @@ -130,23 +134,28 @@ static int do_execute( if (r <= 0) continue; - if (pids) { + if (parallel_execution) { r = hashmap_put(pids, PID_TO_PTR(pid), t); if (r < 0) return log_oom(); t = NULL; } else { r = wait_for_terminate_and_check(t, pid, WAIT_LOG); - if (r < 0) - continue; - - if (lseek(fd, 0, SEEK_SET) < 0) - return log_error_errno(errno, "Failed to seek on serialization fd: %m"); - - r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]); - fd = -1; - if (r < 0) - return log_error_errno(r, "Failed to process output from %s: %m", *path); + if (FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS)) { + if (r < 0) + continue; + } else if (r > 0) + return r; + + if (callbacks) { + if (lseek(fd, 0, SEEK_SET) < 0) + return log_error_errno(errno, "Failed to seek on serialization fd: %m"); + + r = callbacks[STDOUT_GENERATE](fd, callback_args[STDOUT_GENERATE]); + fd = -1; + if (r < 0) + return log_error_errno(r, "Failed to process output from %s: %m", *path); + } } } @@ -166,7 +175,9 @@ static int do_execute( t = hashmap_remove(pids, PID_TO_PTR(pid)); assert(t); - (void) wait_for_terminate_and_check(t, pid, WAIT_LOG); + r = wait_for_terminate_and_check(t, pid, WAIT_LOG); + if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0) + return r; } return 0; @@ -178,12 +189,14 @@ int execute_directories( gather_stdout_callback_t const callbacks[_STDOUT_CONSUME_MAX], void* const callback_args[_STDOUT_CONSUME_MAX], char *argv[], - char *envp[]) { + char *envp[], + ExecDirFlags flags) { char **dirs = (char**) directories; _cleanup_close_ int fd = -1; char *name; int r; + pid_t executor_pid; assert(!strv_isempty(dirs)); @@ -205,14 +218,20 @@ int execute_directories( * them to finish. Optionally a timeout is applied. If a file with the same name * exists in more than one directory, the earliest one wins. */ - r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG|FORK_WAIT, NULL); + r = safe_fork("(sd-executor)", FORK_RESET_SIGNALS|FORK_DEATHSIG|FORK_LOG, &executor_pid); if (r < 0) return r; if (r == 0) { - r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp); - _exit(r < 0 ? EXIT_FAILURE : EXIT_SUCCESS); + r = do_execute(dirs, timeout, callbacks, callback_args, fd, argv, envp, flags); + _exit(r < 0 ? EXIT_FAILURE : r); } + r = wait_for_terminate_and_check("(sd-executor)", executor_pid, 0); + if (r < 0) + return r; + if (!FLAGS_SET(flags, EXEC_DIR_IGNORE_ERRORS) && r > 0) + return r; + if (!callbacks) return 0; |