diff options
author | crupest <crupest@outlook.com> | 2024-06-01 17:09:44 +0800 |
---|---|---|
committer | crupest <crupest@outlook.com> | 2024-06-08 17:01:55 +0800 |
commit | d1f409530db6f9b712fd672c4c3154cac7eebad1 (patch) | |
tree | 1e48a3e2ff14e66aac2503a74df28cca7d85d02c /src/common/platform | |
parent | ad796a167e33b54c7fa23ea21c73d57dba4fc928 (diff) | |
download | cru-d1f409530db6f9b712fd672c4c3154cac7eebad1.tar.gz cru-d1f409530db6f9b712fd672c4c3154cac7eebad1.tar.bz2 cru-d1f409530db6f9b712fd672c4c3154cac7eebad1.zip |
HALF WORK: refactor something and implement part of subprocess.
Diffstat (limited to 'src/common/platform')
-rw-r--r-- | src/common/platform/unix/PosixSpawnSubProcess.cpp | 88 |
1 files changed, 87 insertions, 1 deletions
diff --git a/src/common/platform/unix/PosixSpawnSubProcess.cpp b/src/common/platform/unix/PosixSpawnSubProcess.cpp index 0eb5615d..8b9a9a47 100644 --- a/src/common/platform/unix/PosixSpawnSubProcess.cpp +++ b/src/common/platform/unix/PosixSpawnSubProcess.cpp @@ -1,8 +1,14 @@ #include "cru/common/platform/unix/PosixSpawnSubProcess.h" +#include "cru/common/Exception.h" +#include "cru/common/Format.h" +#include "cru/common/Guard.h" +#include "cru/common/String.h" #include "cru/common/SubProcess.h" #include <spawn.h> +#include <unistd.h> #include <memory> +#include <unordered_map> namespace cru::platform::unix { PosixSpawnSubProcess::PosixSpawnSubProcess( @@ -40,7 +46,87 @@ io::Stream* PosixSpawnSubProcess::GetStderrStream() { return stderr_buffer_stream_.get(); } -void PosixSpawnSubProcess::PlatformCreateProcess() {} +namespace { +char** CreateCstrArray(const std::vector<String>& argv) { + std::vector<Buffer> utf8_argv; + for (const auto& arg : argv) { + utf8_argv.push_back(arg.ToUtf8Buffer()); + } + char** result = new char*[utf8_argv.size() + 1]; + for (int i = 0; i < utf8_argv.size(); i++) { + result[i] = reinterpret_cast<char*>(utf8_argv[i].Detach()); + } + result[utf8_argv.size()] = nullptr; + return result; +} + +char** CreateCstrArray(const std::unordered_map<String, String>& envp) { + std::vector<String> str_array; + for (auto& [key, value] : envp) { + str_array.push_back(cru::Format(u"{}={}", key, value)); + } + return CreateCstrArray(str_array); +} + +void DestroyCstrArray(char** argv) { + int index = 0; + char* arg = argv[index]; + while (arg) { + delete[] arg; + index++; + arg = argv[index]; + } + delete[] argv; +} +} // namespace + +void PosixSpawnSubProcess::PlatformCreateProcess() { + int error; + auto check_error = [&error](String message) { + if (error == 0) return; + std::unique_ptr<ErrnoException> inner(new ErrnoException({}, error)); + throw SubProcessFailedToStartException(std::move(message), + std::move(inner)); + }; + + posix_spawn_file_actions_t file_actions; + error = posix_spawn_file_actions_init(&file_actions); + check_error(u"Failed to call posix_spawn_file_actions_init."); + Guard file_actions_guard( + [&file_actions] { posix_spawn_file_actions_destroy(&file_actions); }); + + // dup2 stdin/stdout/stderr + error = posix_spawn_file_actions_adddup2( + &file_actions, stdin_pipe_.GetOtherFileDescriptor(), STDIN_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdin."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stdout_pipe_.GetOtherFileDescriptor(), STDOUT_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stdout."); + error = posix_spawn_file_actions_adddup2( + &file_actions, stderr_pipe_.GetOtherFileDescriptor(), STDERR_FILENO); + check_error(u"Failed to call posix_spawn_file_actions_adddup2 on stderr."); + + posix_spawnattr_t attr; + error = posix_spawnattr_init(&attr); + check_error(u"Failed to call posix_spawnattr_init."); + Guard attr_guard([&attr] { posix_spawnattr_destroy(&attr); }); + +#ifdef CRU_PLATFORM_OSX + error = posix_spawnattr_setflags(&attr, POSIX_SPAWN_CLOEXEC_DEFAULT); + check_error(u"Failed to set flag POSIX_SPAWN_CLOEXEC_DEFAULT (osx)."); +#endif + + auto exe = start_info_.program.ToUtf8(); + + auto argv = CreateCstrArray(start_info_.arguments); + Guard argv_guard([argv] { DestroyCstrArray(argv); }); + + auto envp = CreateCstrArray(start_info_.environments); + Guard envp_guard([envp] { DestroyCstrArray(envp); }); + + error = posix_spawnp(&pid_, exe.c_str(), &file_actions, &attr, argv, envp); + check_error(u"Failed to call posix_spawnp."); +} PlatformSubProcessExitResult PosixSpawnSubProcess::PlatformWaitForProcess() {} |