mirror of
https://github.com/systemd/systemd.git
synced 2024-11-27 12:13:33 +08:00
core/execute: fall back to execve() for scripts
fexecve() fails with ENOENT and we need a fallback. Add appropriate test.
This commit is contained in:
parent
b83d505087
commit
a6d9111c67
@ -4578,8 +4578,7 @@ static int exec_child(
|
||||
}
|
||||
}
|
||||
|
||||
fexecve(executable_fd, final_argv, accum_env);
|
||||
r = -errno;
|
||||
r = fexecve_or_execve(executable_fd, executable, final_argv, accum_env);
|
||||
|
||||
if (exec_fd >= 0) {
|
||||
uint8_t hot = 0;
|
||||
|
@ -443,3 +443,23 @@ ExecCommandFlags exec_command_flags_from_string(const char *s) {
|
||||
else
|
||||
return 1 << idx;
|
||||
}
|
||||
|
||||
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]) {
|
||||
fexecve(executable_fd, argv, envp);
|
||||
if (errno == ENOENT)
|
||||
/* A script? Let's fall back to execve().
|
||||
*
|
||||
* fexecve(3): "If fd refers to a script (i.e., it is an executable text file that names a
|
||||
* script interpreter with a first line that begins with the characters #!) and the
|
||||
* close-on-exec flag has been set for fd, then fexecve() fails with the error ENOENT. This
|
||||
* error occurs because, by the time the script interpreter is executed, fd has already been
|
||||
* closed because of the close-on-exec flag. Thus, the close-on-exec flag can't be set on fd
|
||||
* if it refers to a script."
|
||||
*
|
||||
* Unfortunately, if we unset close-on-exec, the script will be executed just fine, but (at
|
||||
* least in case of bash) the script name, $0, will be shown as /dev/fd/nnn, which breaks
|
||||
* scripts which make use of $0. Thus, let's fall back to execve() in this case.
|
||||
*/
|
||||
execve(executable, argv, envp);
|
||||
return -errno;
|
||||
}
|
||||
|
@ -45,3 +45,5 @@ extern const gather_stdout_callback_t gather_environment[_STDOUT_CONSUME_MAX];
|
||||
|
||||
const char* exec_command_flags_to_string(ExecCommandFlags i);
|
||||
ExecCommandFlags exec_command_flags_from_string(const char *s);
|
||||
|
||||
int fexecve_or_execve(int executable_fd, const char *executable, char *const argv[], char *const envp[]);
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <unistd.h>
|
||||
|
||||
#include "alloc-util.h"
|
||||
#include "exec-util.h"
|
||||
#include "fd-util.h"
|
||||
#include "macro.h"
|
||||
#include "mountpoint-util.h"
|
||||
@ -255,8 +256,8 @@ static void test_find_executable_exec_one(const char *path) {
|
||||
pid = fork();
|
||||
assert_se(pid >= 0);
|
||||
if (pid == 0) {
|
||||
fexecve(fd, STRV_MAKE(t, "--version"), STRV_MAKE(NULL));
|
||||
log_error_errno(errno, "fexecve: %m");
|
||||
r = fexecve_or_execve(fd, t, STRV_MAKE(t, "--version"), STRV_MAKE(NULL));
|
||||
log_error_errno(r, "[f]execve: %m");
|
||||
_exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -268,6 +269,10 @@ static void test_find_executable_exec(void) {
|
||||
|
||||
test_find_executable_exec_one("touch");
|
||||
test_find_executable_exec_one("/bin/touch");
|
||||
|
||||
_cleanup_free_ char *script = NULL;
|
||||
assert_se(get_testdata_dir("test-path-util/script.sh", &script) >= 0);
|
||||
test_find_executable_exec_one(script);
|
||||
}
|
||||
|
||||
static void test_prefixes(void) {
|
||||
|
@ -11,6 +11,8 @@ if install_tests
|
||||
install_dir : testdata_dir)
|
||||
install_subdir('test-path',
|
||||
install_dir : testdata_dir)
|
||||
install_subdir('test-path-util',
|
||||
install_dir : testdata_dir)
|
||||
install_subdir('test-umount',
|
||||
install_dir : testdata_dir)
|
||||
install_subdir('test-network-generator-conversion',
|
||||
|
6
test/test-path-util/script.sh
Executable file
6
test/test-path-util/script.sh
Executable file
@ -0,0 +1,6 @@
|
||||
#!/bin/sh
|
||||
|
||||
echo "$0 $@"
|
||||
test "$(basename $0)" = "script.sh" || exit 1
|
||||
test "$1" = "--version" || exit 2
|
||||
echo "Life is good"
|
Loading…
Reference in New Issue
Block a user