// Copyright (c) FIRST and other WPILib contributors. // Open Source Software; you can modify and/or share it under the terms of // the WPILib BSD license file in the root directory of this project. #include "wpinet/uv/Process.h" #include #include "wpinet/uv/Loop.h" #include "wpinet/uv/Pipe.h" namespace wpi::uv { std::shared_ptr Process::SpawnArray(Loop& loop, std::string_view file, std::span options) { if (loop.IsClosing()) { return nullptr; } // convert Option array to libuv structure uv_process_options_t coptions; coptions.exit_cb = [](uv_process_t* handle, int64_t status, int signal) { auto& h = *static_cast(handle->data); h.exited(status, signal); }; SmallString<128> fileBuf{file}; coptions.file = fileBuf.c_str(); coptions.cwd = nullptr; coptions.flags = 0; coptions.uid = 0; coptions.gid = 0; SmallVector argsBuf; SmallVector envBuf; struct StdioContainer : public uv_stdio_container_t { StdioContainer() { flags = UV_IGNORE; data.fd = 0; } }; SmallVector stdioBuf; for (auto&& o : options) { switch (o.m_type) { case Option::kArg: argsBuf.push_back(const_cast(o.m_data.str)); break; case Option::kEnv: envBuf.push_back(const_cast(o.m_data.str)); break; case Option::kCwd: coptions.cwd = o.m_data.str[0] == '\0' ? nullptr : o.m_data.str; break; case Option::kUid: coptions.uid = o.m_data.uid; coptions.flags |= UV_PROCESS_SETUID; break; case Option::kGid: coptions.gid = o.m_data.gid; coptions.flags |= UV_PROCESS_SETGID; break; case Option::kSetFlags: coptions.flags |= o.m_data.flags; break; case Option::kClearFlags: coptions.flags &= ~o.m_data.flags; break; case Option::kStdioIgnore: { size_t index = o.m_data.stdio.index; if (index >= stdioBuf.size()) { stdioBuf.resize(index + 1); } stdioBuf[index].flags = UV_IGNORE; stdioBuf[index].data.fd = 0; break; } case Option::kStdioInheritFd: { size_t index = o.m_data.stdio.index; if (index >= stdioBuf.size()) { stdioBuf.resize(index + 1); } stdioBuf[index].flags = UV_INHERIT_FD; stdioBuf[index].data.fd = o.m_data.stdio.fd; break; } case Option::kStdioInheritPipe: { size_t index = o.m_data.stdio.index; if (index >= stdioBuf.size()) { stdioBuf.resize(index + 1); } stdioBuf[index].flags = UV_INHERIT_STREAM; stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream(); break; } case Option::kStdioCreatePipe: { size_t index = o.m_data.stdio.index; if (index >= stdioBuf.size()) { stdioBuf.resize(index + 1); } stdioBuf[index].flags = static_cast(UV_CREATE_PIPE | o.m_data.stdio.flags); stdioBuf[index].data.stream = o.m_data.stdio.pipe->GetRawStream(); break; } default: break; } } if (argsBuf.empty()) { argsBuf.push_back(const_cast(coptions.file)); } argsBuf.push_back(nullptr); coptions.args = argsBuf.data(); if (envBuf.empty()) { coptions.env = nullptr; } else { envBuf.push_back(nullptr); coptions.env = envBuf.data(); } coptions.stdio_count = stdioBuf.size(); coptions.stdio = static_cast(stdioBuf.data()); auto h = std::make_shared(private_init{}); int err = uv_spawn(loop.GetRaw(), h->GetRaw(), &coptions); if (err < 0) { loop.ReportError(err); return nullptr; } h->Keep(); return h; } } // namespace wpi::uv