13 #ifndef __STOUT_OS_WINDOWS_EXEC_HPP__ 14 #define __STOUT_OS_WINDOWS_EXEC_HPP__ 17 #include <processthreadsapi.h> 50 std::map<std::wstring, std::wstring> system_env;
51 wchar_t* env_entry =
nullptr;
56 if (!::CreateEnvironmentBlock((LPVOID*)&env_entry,
nullptr, FALSE)) {
61 wchar_t* env_block = env_entry;
63 while (*env_entry != L
'\0') {
74 std::wstring entry(env_entry);
75 std::wstring::size_type separator = entry.find(L
"=");
76 std::wstring var_name(entry.substr(0, separator));
77 std::wstring varVal(entry.substr(separator + 1));
83 var_name.begin(), var_name.end(), var_name.begin(), ::towupper);
86 system_env.insert_or_assign(var_name.data(), varVal.data());
89 env_entry += entry.length() + 1;
92 ::DestroyEnvironmentBlock(env_block);
111 const Option<std::map<std::string, std::string>>& env)
113 if (env.isNone() || (env.isSome() && env.get().size() == 0)) {
121 CHECK(system_env.
isSome() && system_env.
get().size() > 0);
123 std::map<std::wstring, std::wstring> combined_env;
127 const std::wstring& value,
129 combined_env[key] = value;
134 const std::string& value,
136 combined_env[wide_stringify(key)] = wide_stringify(value);
139 std::wstring env_string;
141 const std::wstring& value,
143 env_string += key + L
'=' + value + L
'\0';
147 env_string.push_back(L
'\0');
171 std::wstring command;
173 for (
auto argit = argv.cbegin(); argit != argv.cend(); ++argit) {
174 std::wstring arg = wide_stringify(*argit);
177 if (!arg.empty() && arg.find_first_of(L
" \t\n\v\"") == arg.npos) {
181 command.push_back(L
'"');
182 for (
auto it = arg.cbegin(); it != arg.cend(); ++it) {
184 unsigned int backslashes = 0;
185 while (it != arg.cend() && *it == L
'\\') {
190 if (it == arg.cend()) {
193 command.append(backslashes * 2, L
'\\');
195 }
else if (*it == L
'"') {
197 command.append(backslashes * 2 + 1, L
'\\');
198 command.push_back(*it);
201 command.append(backslashes, L
'\\');
202 command.push_back(*it);
207 command.push_back(L
'"');
210 if (argit != argv.cend() - 1) {
211 command.push_back(L
' ');
216 command.push_back(L
'\0');
264 const std::string& command,
265 const std::vector<std::string>& argv,
267 const bool create_suspended =
false,
268 const Option<std::array<int_fd, 3>>& pipes =
None(),
269 const std::vector<int_fd>& whitelist_fds = {})
273 std::vector<wchar_t> arg_buffer(arg_string.begin(), arg_string.end());
274 arg_buffer.push_back(L
'\0');
278 DWORD creation_flags =
279 CREATE_UNICODE_ENVIRONMENT | EXTENDED_STARTUPINFO_PRESENT;
280 if (create_suspended) {
281 creation_flags |= CREATE_SUSPENDED;
286 std::vector<wchar_t> env_buffer;
287 if (env_string.
isSome()) {
289 env_buffer.assign(env_string.
get().begin(), env_string.
get().end());
292 wchar_t* process_env = env_buffer.empty() ?
nullptr : env_buffer.data();
294 PROCESS_INFORMATION process_info = {};
296 STARTUPINFOEXW startup_info_ex = {};
297 startup_info_ex.StartupInfo.cb =
sizeof(startup_info_ex);
307 std::vector<HANDLE> handles;
308 if (pipes.isSome()) {
310 foreach (
const int_fd& fd, pipes.get()) {
311 handles.emplace_back(static_cast<HANDLE>(fd));
324 startup_info_ex.StartupInfo.dwFlags |= STARTF_USESTDHANDLES;
325 startup_info_ex.StartupInfo.hStdInput = std::get<0>(pipes.get());
326 startup_info_ex.StartupInfo.hStdOutput = std::get<1>(pipes.get());
327 startup_info_ex.StartupInfo.hStdError = std::get<2>(pipes.get());
330 foreach (
const int_fd& fd, whitelist_fds) {
331 handles.emplace_back(static_cast<HANDLE>(fd));
341 if (attribute_list.isError()) {
342 return Error(attribute_list.error());
345 if (attribute_list.isSome()) {
346 startup_info_ex.lpAttributeList = attribute_list->get();
349 const BOOL result = ::CreateProcessW(
351 static_cast<LPCWSTR>(
nullptr),
352 static_cast<LPWSTR>(arg_buffer.data()),
353 static_cast<LPSECURITY_ATTRIBUTES>(
nullptr),
354 static_cast<LPSECURITY_ATTRIBUTES
>(
nullptr),
357 static_cast<LPVOID>(process_env),
358 static_cast<LPCWSTR
>(
nullptr),
359 &startup_info_ex.StartupInfo,
365 const DWORD create_process_error = ::GetLastError();
375 if (pipes.isSome()) {
382 foreach (
const int_fd& fd, pipes.get()) {
390 foreach (
const int_fd& fd, whitelist_fds) {
397 if (result == FALSE) {
399 create_process_error,
400 "Failed to call `CreateProcess`: " +
stringify(arg_string));
405 static_cast<pid_t>(process_info.dwProcessId)};
413 const std::string& command,
414 const std::vector<std::string>& arguments,
423 LOG(WARNING) << process_data.
error();
431 if (!::GetExitCodeProcess(
433 LOG(WARNING) <<
"Failed to `GetExitCodeProcess`: " << command;
438 return static_cast<int>(
status);
443 const std::string&
file,
444 const std::vector<std::string>& argv)
446 exit(
os::spawn(file, argv).getOrElse(-1));
452 const std::string&
file,
453 const std::vector<std::string>& argv,
454 const std::map<std::string, std::string>& envp)
456 exit(
os::spawn(file, argv, envp).getOrElse(-1));
462 #endif // __STOUT_OS_WINDOWS_EXEC_HPP__ Result< std::shared_ptr< AttributeList > > create_attributes_list_for_handles(const std::vector< HANDLE > &handles)
Definition: inherit.hpp:32
Option< std::wstring > create_process_env(const Option< std::map< std::string, std::string >> &env)
Definition: exec.hpp:110
Definition: errorbase.hpp:36
Definition: option.hpp:29
HANDLE get_handle() const
Definition: windows.hpp:90
Definition: windows.hpp:72
Try< ProcessData > create_process(const std::string &command, const std::vector< std::string > &argv, const Option< std::map< std::string, std::string >> &environment, const bool create_suspended=false, const Option< std::array< int_fd, 3 >> &pipes=None(), const std::vector< int_fd > &whitelist_fds={})
Definition: exec.hpp:263
Result< ProcessStatus > status(pid_t pid)
Definition: proc.hpp:166
Definition: error.hpp:108
Try< Nothing > set_inherit(const int_fd &fd, const bool inherit)
Definition: inherit.hpp:98
Definition: posix_signalhandler.hpp:23
SharedHandle process_handle
Definition: exec.hpp:223
SharedHandle thread_handle
Definition: exec.hpp:224
bool isSome() const
Definition: option.hpp:116
int execvp(const char *file, char *const argv[])
Definition: exec.hpp:58
DWORD pid_t
Definition: windows.hpp:181
URI file(const std::string &path)
Creates a file URI with the given path on the local host.
Definition: file.hpp:33
const T & get() const &
Definition: option.hpp:119
#define foreachpair(KEY, VALUE, ELEMS)
Definition: foreach.hpp:51
std::map< std::string, std::string > environment()
Definition: environment.hpp:24
static Try error(const E &e)
Definition: try.hpp:43
Option< std::map< std::wstring, std::wstring > > get_system_env()
Definition: exec.hpp:48
process::Future< Nothing > transform(process::Owned< Reader< T >> &&reader, const std::function< std::string(const T &)> &func, process::http::Pipe::Writer writer)
This is a helper function that reads records from a Reader, applies a transformation to the records a...
Definition: recordio.hpp:112
Definition: attributes.hpp:24
bool isError() const
Definition: try.hpp:78
std::wstring stringify_args(const std::vector< std::string > &argv)
Definition: exec.hpp:169
pid_t pid
Definition: exec.hpp:225
int int_fd
Definition: int_fd.hpp:35
std::string stringify(int flags)
int execvpe(const char *file, char **argv, char **envp)
Definition: exec.hpp:64
Option< int > spawn(const std::string &file, const std::vector< std::string > &arguments)
Definition: exec.hpp:32