15 #include <util/pragma_push.def>
17 #pragma warning(disable:4668)
19 #pragma warning(disable:5039)
24 #include <util/pragma_pop.def>
48 int run(
const std::string &what,
const std::vector<std::string> &argv)
50 return run(what, argv,
"",
"",
"");
54 #define STDIN_FILENO 0
55 #define STDOUT_FILENO 1
56 #define STDERR_FILENO 2
66 fdt result_fd = INVALID_HANDLE_VALUE;
69 SECURITY_ATTRIBUTES SecurityAttributes;
70 ZeroMemory(&SecurityAttributes,
sizeof SecurityAttributes);
71 SecurityAttributes.bInheritHandle =
true;
78 result_fd = GetStdHandle(STD_INPUT_HANDLE);
80 result_fd = CreateFileW(
86 FILE_ATTRIBUTE_READONLY,
93 result_fd = GetStdHandle(STD_OUTPUT_HANDLE);
95 result_fd = CreateFileW(
101 FILE_ATTRIBUTE_NORMAL,
108 result_fd = GetStdHandle(STD_ERROR_HANDLE);
110 result_fd = CreateFileW(
116 FILE_ATTRIBUTE_NORMAL,
124 if(result_fd == INVALID_HANDLE_VALUE)
125 perror((
"Failed to open " + name +
" file " + file).c_str());
132 int flags = 0, mode = 0;
144 flags = O_CREAT | O_WRONLY;
145 mode = S_IRUSR | S_IWUSR;
146 name = fd == STDOUT_FILENO ?
"stdout" :
"stderr";
153 const fdt result_fd =
open(file.c_str(), flags, mode);
156 perror((
"Failed to open " + name +
" file " + file).c_str());
165 std::wstring quote_windows_arg(
const std::wstring &src)
168 if(src.find_first_of(L
" \t\n\v\"") == src.npos && !src.empty())
171 std::wstring result = L
"\"";
173 for(
auto it = src.begin();; ++it)
175 std::size_t NumberBackslashes = 0;
177 while(it != src.end() && *it == L
'\\')
191 result.append(NumberBackslashes * 2, L
'\\');
201 result.append(NumberBackslashes * 2 + 1, L
'\\');
202 result.push_back(*it);
210 result.append(NumberBackslashes, L
'\\');
211 result.push_back(*it);
215 result.push_back(L
'"');
225 std::string get_last_error_as_string()
228 DWORD error_message_id = GetLastError();
229 if(error_message_id == 0)
232 LPWSTR message_buffer =
nullptr;
233 std::size_t size = FormatMessageW(
234 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
235 FORMAT_MESSAGE_IGNORE_INSERTS,
238 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
239 (LPWSTR)&message_buffer,
243 std::wstring message(message_buffer, size);
246 LocalFree(message_buffer);
253 const std::string &what,
254 const std::vector<std::string> &argv,
255 const std::string &std_input,
256 const std::string &std_output,
257 const std::string &std_error)
261 std::wstring cmdline;
264 cmdline = quote_windows_arg(
widen(what));
266 for(std::size_t i = 1; i < argv.size(); i++)
269 cmdline += quote_windows_arg(
widen(argv[i]));
272 PROCESS_INFORMATION piProcInfo;
273 STARTUPINFOW siStartInfo;
275 ZeroMemory(&piProcInfo,
sizeof piProcInfo);
276 ZeroMemory(&siStartInfo,
sizeof siStartInfo);
278 siStartInfo.cb =
sizeof siStartInfo;
284 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
287 std::vector<wchar_t> mutable_cmdline(cmdline.begin(), cmdline.end());
288 mutable_cmdline.push_back(0);
289 wchar_t *cmdline_ptr = mutable_cmdline.data();
291 BOOL bSuccess = CreateProcessW(
306 std::string windows_error = get_last_error_as_string();
308 if(!std_input.empty())
309 CloseHandle(siStartInfo.hStdInput);
310 if(!std_output.empty())
311 CloseHandle(siStartInfo.hStdOutput);
312 if(!std_error.empty())
313 CloseHandle(siStartInfo.hStdError);
316 std::ofstream stderr_stream(std_error);
317 stderr_stream << windows_error;
323 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
325 if(!std_input.empty())
326 CloseHandle(siStartInfo.hStdInput);
327 if(!std_output.empty())
328 CloseHandle(siStartInfo.hStdOutput);
329 if(!std_error.empty())
330 CloseHandle(siStartInfo.hStdError);
335 if(!GetExitCodeProcess(piProcInfo.hProcess, &exit_code))
337 CloseHandle(piProcInfo.hProcess);
338 CloseHandle(piProcInfo.hThread);
342 CloseHandle(piProcInfo.hProcess);
343 CloseHandle(piProcInfo.hThread);
352 if(stdin_fd == -1 || stdout_fd == -1 || stderr_fd == -1)
356 sigset_t new_mask, old_mask;
357 sigemptyset(&new_mask);
358 sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
361 pid_t childpid = fork();
369 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
371 std::vector<char *> _argv(argv.size()+1);
372 for(std::size_t i=0; i<argv.size(); i++)
373 _argv[i]=
strdup(argv[i].c_str());
375 _argv[argv.size()]=
nullptr;
377 if(stdin_fd!=STDIN_FILENO)
378 dup2(stdin_fd, STDIN_FILENO);
379 if(stdout_fd!=STDOUT_FILENO)
380 dup2(stdout_fd, STDOUT_FILENO);
381 if(stderr_fd != STDERR_FILENO)
382 dup2(stderr_fd, STDERR_FILENO);
385 execvp(what.c_str(), _argv.data());
388 perror(std::string(
"execvp "+what+
" failed").c_str());
397 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
402 while(waitpid(childpid, &status, 0)==-1)
410 perror(
"Waiting for child process failed");
411 if(stdin_fd!=STDIN_FILENO)
413 if(stdout_fd!=STDOUT_FILENO)
415 if(stderr_fd != STDERR_FILENO)
423 if(stdin_fd!=STDIN_FILENO)
425 if(stdout_fd!=STDOUT_FILENO)
427 if(stderr_fd != STDERR_FILENO)
430 return WEXITSTATUS(status);
436 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
438 if(stdin_fd!=STDIN_FILENO)
440 if(stdout_fd!=STDOUT_FILENO)
442 if(stderr_fd != STDERR_FILENO)
456 if(src.find(
' ')==std::string::npos &&
457 src.find(
'"')==std::string::npos &&
458 src.find(
'&')==std::string::npos &&
459 src.find(
'|')==std::string::npos &&
460 src.find(
'(')==std::string::npos &&
461 src.find(
')')==std::string::npos &&
462 src.find(
'<')==std::string::npos &&
463 src.find(
'>')==std::string::npos &&
464 src.find(
'^')==std::string::npos)
474 for(
const char ch : src)
489 if(src.find(
' ')==std::string::npos &&
490 src.find(
'"')==std::string::npos &&
491 src.find(
'*')==std::string::npos &&
492 src.find(
'$')==std::string::npos &&
493 src.find(
'\\')==std::string::npos &&
494 src.find(
'?')==std::string::npos &&
495 src.find(
'&')==std::string::npos &&
496 src.find(
'|')==std::string::npos &&
497 src.find(
'>')==std::string::npos &&
498 src.find(
'<')==std::string::npos &&
499 src.find(
'^')==std::string::npos &&
500 src.find(
'\'')==std::string::npos)
511 for(
const char ch : src)
525 const std::string &what,
526 const std::vector<std::string> &argv,
527 const std::string &std_input,
528 std::ostream &std_output,
529 const std::string &std_error)
534 int result =
run(what, argv, std_input, tmpi(), std_error);
536 std::ifstream instream(tmpi());
539 std_output << instream.rdbuf();
548 for(
const auto &arg : argv)
559 if(!std_input.empty())
562 if(!std_error.empty())
565 FILE *stream=popen(command.c_str(),
"r");
570 while((ch=
fgetc(stream))!=EOF)
571 std_output << (
unsigned char)ch;
573 int result = pclose(stream);
574 return WEXITSTATUS(result);
int open(const char *pathname, int flags,...)
output_type narrow(input_type input)
Run-time checked narrowing cast.
int run(const std::string &what, const std::vector< std::string > &argv)
static fdt stdio_redirection(int fd, const std::string &file)
open given file to replace either stdin, stderr, stdout
std::string shell_quote(const std::string &src)
quote a string for bash and CMD
void remove_signal_catcher()
void register_child(pid_t pid)
#define UNREACHABLE
This should be used to mark dead code.
void perror(const char *s)
char * strdup(const char *str)
std::wstring widen(const char *s)