summaryrefslogtreecommitdiff
path: root/src/shared/exec-util.c
diff options
context:
space:
mode:
authorMatthias Klumpp <matthias@tenstral.net>2018-09-09 03:18:45 +0200
committerLennart Poettering <lennart@poettering.net>2019-02-18 16:16:02 +0100
commit4b05f0c9d9f6df4e0dab518f8e1ae537bf948f92 (patch)
treecf8d18410cd148191d951b8f7e60006590011166 /src/shared/exec-util.c
parentbde06abd4f3febc149bf137ca68e4abaa2975b4d (diff)
downloadsystemd-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.c57
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;