15 #include <util/pragma_push.def>
17 #pragma warning(disable:4668)
19 #pragma warning(disable:5039)
24 #include <util/pragma_pop.def>
36 #include <sys/types.h>
49 int run(
const std::string &what,
const std::vector<std::string> &argv)
51 return run(what, argv,
"",
"",
"");
55 #define STDIN_FILENO 0
56 #define STDOUT_FILENO 1
57 #define STDERR_FILENO 2
67 fdt result_fd = INVALID_HANDLE_VALUE;
70 SECURITY_ATTRIBUTES SecurityAttributes;
71 ZeroMemory(&SecurityAttributes,
sizeof SecurityAttributes);
72 SecurityAttributes.bInheritHandle =
true;
79 result_fd = GetStdHandle(STD_INPUT_HANDLE);
81 result_fd = CreateFileW(
87 FILE_ATTRIBUTE_READONLY,
94 result_fd = GetStdHandle(STD_OUTPUT_HANDLE);
96 result_fd = CreateFileW(
102 FILE_ATTRIBUTE_NORMAL,
109 result_fd = GetStdHandle(STD_ERROR_HANDLE);
111 result_fd = CreateFileW(
117 FILE_ATTRIBUTE_NORMAL,
125 if(result_fd == INVALID_HANDLE_VALUE)
126 perror((
"Failed to open " + name +
" file " +
file).c_str());
133 int flags = 0, mode = 0;
145 flags = O_CREAT | O_WRONLY;
146 mode = S_IRUSR | S_IWUSR;
147 name = fd == STDOUT_FILENO ?
"stdout" :
"stderr";
154 const fdt result_fd = open(
file.c_str(), flags, mode);
157 perror((
"Failed to open " + name +
" file " +
file).c_str());
166 std::wstring quote_windows_arg(
const std::wstring &src)
169 if(src.find_first_of(L
" \t\n\v\"") == src.npos && !src.empty())
172 std::wstring result = L
"\"";
174 for(
auto it = src.begin();; ++it)
176 std::size_t NumberBackslashes = 0;
178 while(it != src.end() && *it == L
'\\')
192 result.append(NumberBackslashes * 2, L
'\\');
202 result.append(NumberBackslashes * 2 + 1, L
'\\');
203 result.push_back(*it);
211 result.append(NumberBackslashes, L
'\\');
212 result.push_back(*it);
216 result.push_back(L
'"');
226 std::string get_last_error_as_string()
229 DWORD error_message_id = GetLastError();
230 if(error_message_id == 0)
233 LPWSTR message_buffer =
nullptr;
234 std::size_t size = FormatMessageW(
235 FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
236 FORMAT_MESSAGE_IGNORE_INSERTS,
239 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
240 (LPWSTR)&message_buffer,
244 std::wstring
message(message_buffer, size);
247 LocalFree(message_buffer);
254 const std::string &what,
255 const std::vector<std::string> &argv,
256 const std::string &std_input,
257 const std::string &std_output,
258 const std::string &std_error)
262 std::wstring cmdline;
265 cmdline = quote_windows_arg(
widen(what));
267 for(std::size_t i = 1; i < argv.size(); i++)
270 cmdline += quote_windows_arg(
widen(argv[i]));
273 PROCESS_INFORMATION piProcInfo;
274 STARTUPINFOW siStartInfo;
276 ZeroMemory(&piProcInfo,
sizeof piProcInfo);
277 ZeroMemory(&siStartInfo,
sizeof siStartInfo);
279 siStartInfo.cb =
sizeof siStartInfo;
285 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
288 std::vector<wchar_t> mutable_cmdline(cmdline.begin(), cmdline.end());
289 mutable_cmdline.push_back(0);
290 wchar_t *cmdline_ptr = mutable_cmdline.data();
292 BOOL bSuccess = CreateProcessW(
307 std::string windows_error = get_last_error_as_string();
309 if(!std_input.empty())
310 CloseHandle(siStartInfo.hStdInput);
311 if(!std_output.empty())
312 CloseHandle(siStartInfo.hStdOutput);
313 if(!std_error.empty())
314 CloseHandle(siStartInfo.hStdError);
317 std::ofstream stderr_stream(std_error);
318 stderr_stream << windows_error;
324 WaitForSingleObject(piProcInfo.hProcess, INFINITE);
326 if(!std_input.empty())
327 CloseHandle(siStartInfo.hStdInput);
328 if(!std_output.empty())
329 CloseHandle(siStartInfo.hStdOutput);
330 if(!std_error.empty())
331 CloseHandle(siStartInfo.hStdError);
336 if(!GetExitCodeProcess(piProcInfo.hProcess, &exit_code))
338 CloseHandle(piProcInfo.hProcess);
339 CloseHandle(piProcInfo.hThread);
343 CloseHandle(piProcInfo.hProcess);
344 CloseHandle(piProcInfo.hThread);
353 if(stdin_fd == -1 || stdout_fd == -1 || stderr_fd == -1)
357 sigset_t new_mask, old_mask;
358 sigemptyset(&new_mask);
359 sigprocmask(SIG_SETMASK, &new_mask, &old_mask);
362 pid_t childpid = fork();
370 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
372 std::vector<char *> _argv(argv.size()+1);
373 for(std::size_t i=0; i<argv.size(); i++)
374 _argv[i]=strdup(argv[i].c_str());
376 _argv[argv.size()]=
nullptr;
378 if(stdin_fd!=STDIN_FILENO)
379 dup2(stdin_fd, STDIN_FILENO);
380 if(stdout_fd!=STDOUT_FILENO)
381 dup2(stdout_fd, STDOUT_FILENO);
382 if(stderr_fd != STDERR_FILENO)
383 dup2(stderr_fd, STDERR_FILENO);
386 execvp(what.c_str(), _argv.data());
389 perror(std::string(
"execvp "+what+
" failed").c_str());
398 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
403 while(waitpid(childpid, &status, 0)==-1)
411 perror(
"Waiting for child process failed");
412 if(stdin_fd!=STDIN_FILENO)
414 if(stdout_fd!=STDOUT_FILENO)
416 if(stderr_fd != STDERR_FILENO)
424 if(stdin_fd!=STDIN_FILENO)
426 if(stdout_fd!=STDOUT_FILENO)
428 if(stderr_fd != STDERR_FILENO)
431 return WEXITSTATUS(status);
437 sigprocmask(SIG_SETMASK, &old_mask,
nullptr);
439 if(stdin_fd!=STDIN_FILENO)
441 if(stdout_fd!=STDOUT_FILENO)
443 if(stderr_fd != STDERR_FILENO)
457 if(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 &&
465 src.find(
'^')==std::string::npos)
475 for(
const char ch : src)
490 if(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 &&
501 src.find(
'\'')==std::string::npos)
512 for(
const char ch : src)
526 const std::string &what,
527 const std::vector<std::string> &argv,
528 const std::string &std_input,
529 std::ostream &std_output,
530 const std::string &std_error)
535 int result =
run(what, argv, std_input, tmpi(), std_error);
537 std::ifstream instream(tmpi());
540 std_output << instream.rdbuf();
549 for(
const auto &arg : argv)
560 if(!std_input.empty())
563 if(!std_error.empty())
566 FILE *stream=popen(command.c_str(),
"r");
571 while((ch=fgetc(stream))!=EOF)
572 std_output << (
unsigned char)ch;
574 return pclose(stream);