aboutsummaryrefslogtreecommitdiff
path: root/src/common/platform
diff options
context:
space:
mode:
authorcrupest <crupest@outlook.com>2024-06-01 17:09:44 +0800
committercrupest <crupest@outlook.com>2024-06-08 17:01:55 +0800
commitd1f409530db6f9b712fd672c4c3154cac7eebad1 (patch)
tree1e48a3e2ff14e66aac2503a74df28cca7d85d02c /src/common/platform
parentad796a167e33b54c7fa23ea21c73d57dba4fc928 (diff)
downloadcru-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.cpp88
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() {}