fix(process): report Linux exec failures
This commit is contained in:
@@ -6,6 +6,7 @@
|
||||
#include <izo/system.hpp>
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/sysinfo.h>
|
||||
#include <sys/utsname.h>
|
||||
@@ -75,19 +76,42 @@ std::filesystem::path get_known_path(known_path path, std::string* error_message
|
||||
|
||||
process_result launch_process(const process_options& options) {
|
||||
if (options.executable.empty()) return {false, 0, "Executable path is required"};
|
||||
int error_pipe[2];
|
||||
if (pipe2(error_pipe, O_CLOEXEC) != 0) return {false, 0, std::strerror(errno)};
|
||||
const pid_t child = fork();
|
||||
if (child < 0) return {false, 0, std::strerror(errno)};
|
||||
if (child < 0) {
|
||||
const std::string error = std::strerror(errno);
|
||||
close(error_pipe[0]);
|
||||
close(error_pipe[1]);
|
||||
return {false, 0, error};
|
||||
}
|
||||
if (child == 0) {
|
||||
close(error_pipe[0]);
|
||||
if (options.detached) setsid();
|
||||
if (!options.working_directory.empty() && chdir(options.working_directory.c_str()) != 0) _exit(126);
|
||||
if (!options.working_directory.empty() && chdir(options.working_directory.c_str()) != 0) {
|
||||
const int error = errno;
|
||||
write(error_pipe[1], &error, sizeof(error));
|
||||
_exit(126);
|
||||
}
|
||||
std::vector<std::string> values{options.executable.string()};
|
||||
values.insert(values.end(), options.arguments.begin(), options.arguments.end());
|
||||
std::vector<char*> argv;
|
||||
for (auto& value : values) argv.push_back(value.data());
|
||||
argv.push_back(nullptr);
|
||||
execvp(argv[0], argv.data());
|
||||
const int error = errno;
|
||||
write(error_pipe[1], &error, sizeof(error));
|
||||
_exit(127);
|
||||
}
|
||||
close(error_pipe[1]);
|
||||
int child_error = 0;
|
||||
const ssize_t error_bytes = read(error_pipe[0], &child_error, sizeof(child_error));
|
||||
close(error_pipe[0]);
|
||||
if (error_bytes > 0) {
|
||||
int status = 0;
|
||||
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {}
|
||||
return {false, 0, std::strerror(child_error)};
|
||||
}
|
||||
std::thread([child] {
|
||||
int status = 0;
|
||||
while (waitpid(child, &status, 0) < 0 && errno == EINTR) {}
|
||||
|
||||
Reference in New Issue
Block a user