void launch_process(int child_stdout){ #ifdef _WIN32 stringstream ss; for( unsigned i=0; i < argv_.size(); i++ ){ if (i) ss << ' '; if (argv_[i].find(' ') == string::npos) ss << argv_[i]; else ss << '"' << argv_[i] << '"'; } string args = ss.str(); boost::scoped_array<TCHAR> args_tchar (new TCHAR[args.size() + 1]); size_t i; for(i=0; i < args.size(); i++) args_tchar[i] = args[i]; args_tchar[i] = 0; HANDLE h = (HANDLE)_get_osfhandle(child_stdout); assert(h != INVALID_HANDLE_VALUE); assert(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1)); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.hStdError = h; si.hStdOutput = h; si.dwFlags |= STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0; { stringstream ss; ss << "couldn't start process " << argv_[0]; uassert(13294, ss.str(), success); } CloseHandle(pi.hThread); pid_ = pi.dwProcessId; handles.insert( make_pair( pid_, pi.hProcess ) ); #else pid_ = fork(); assert( pid_ != -1 ); if ( pid_ == 0 ) { // DON'T ASSERT IN THIS BLOCK - very bad things will happen const char** argv = new const char* [argv_.size()+1]; // don't need to free - in child for (unsigned i=0; i < argv_.size(); i++){ argv[i] = argv_[i].c_str(); } argv[argv_.size()] = 0; if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || dup2( child_stdout, STDERR_FILENO ) == -1 ) { cout << "Unable to dup2 child output: " << errnoWithDescription() << endl; ::_Exit(-1); //do not pass go, do not call atexit handlers } const char** env = new const char* [2]; // don't need to free - in child env[0] = NULL; #if defined(HEAP_CHECKING) env[0] = "HEAPCHECK=normal"; env[1] = NULL; // Heap-check for mongos only. 'argv[0]' must be in the path format. if ( argv_[0].find("mongos") != string::npos){ execvpe( argv[ 0 ], const_cast<char**>(argv) , const_cast<char**>(env) ); } #endif // HEAP_CHECKING execvp( argv[ 0 ], const_cast<char**>(argv) ); cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl; ::_Exit(-1); } #endif }
void ProgramRunner::launchProcess( int child_stdout ) { #ifdef _WIN32 stringstream ss; for( unsigned i=0; i < _argv.size(); i++ ) { if (i) ss << ' '; if (_argv[i].find(' ') == string::npos) ss << _argv[i]; else { ss << '"'; // escape all embedded quotes for (size_t j=0; j<_argv[i].size(); ++j) { if (_argv[i][j]=='"') ss << '\\'; ss << _argv[i][j]; } ss << '"'; } } string args = ss.str(); boost::scoped_array<TCHAR> args_tchar (new TCHAR[args.size() + 1]); size_t i; for(i=0; i < args.size(); i++) args_tchar[i] = args[i]; args_tchar[i] = 0; HANDLE h = (HANDLE)_get_osfhandle(child_stdout); verify(h != INVALID_HANDLE_VALUE); verify(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1)); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.hStdError = h; si.hStdOutput = h; si.dwFlags |= STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0; if (!success) { LPSTR lpMsgBuf=0; DWORD dw = GetLastError(); FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL ); stringstream ss; ss << "couldn't start process " << _argv[0] << "; " << lpMsgBuf; uassert(14042, ss.str(), success); LocalFree(lpMsgBuf); } CloseHandle(pi.hThread); _pid = ProcessId::fromNative(pi.dwProcessId); registry._handles.insert( make_pair( _pid, pi.hProcess ) ); #else scoped_array<const char *> argvStorage( new const char* [_argv.size()+1] ); const char** argv = argvStorage.get(); for (unsigned i=0; i < _argv.size(); i++) { argv[i] = _argv[i].c_str(); } argv[_argv.size()] = 0; scoped_array<const char *> envStorage( new const char* [2] ); const char** env = envStorage.get(); env[0] = NULL; env[1] = NULL; pid_t nativePid = fork(); _pid = ProcessId::fromNative(nativePid); // Async signal unsafe functions should not be called in the child process. verify( nativePid != -1 ); if ( nativePid == 0 ) { // DON'T ASSERT IN THIS BLOCK - very bad things will happen if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || dup2( child_stdout, STDERR_FILENO ) == -1 ) { // Async signal unsafe code reporting a terminal error condition. cout << "Unable to dup2 child output: " << errnoWithDescription() << endl; quickExit(-1); //do not pass go, do not call atexit handlers } // NOTE execve is async signal safe, but it is not clear that execvp is async // signal safe. execvp( argv[ 0 ], const_cast<char**>(argv) ); // Async signal unsafe code reporting a terminal error condition. cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl; quickExit(-1); } #endif }
void launch_process(int child_stdout) { #ifdef _WIN32 stringstream ss; for( unsigned i=0; i < argv_.size(); i++ ) { if (i) ss << ' '; if (argv_[i].find(' ') == string::npos) ss << argv_[i]; else { ss << '"'; // escape all embedded quotes for (size_t j=0; j<argv_[i].size(); ++j) { if (argv_[i][j]=='"') ss << '"'; ss << argv_[i][j]; } ss << '"'; } } string args = ss.str(); boost::scoped_array<TCHAR> args_tchar (new TCHAR[args.size() + 1]); size_t i; for(i=0; i < args.size(); i++) args_tchar[i] = args[i]; args_tchar[i] = 0; HANDLE h = (HANDLE)_get_osfhandle(child_stdout); assert(h != INVALID_HANDLE_VALUE); assert(SetHandleInformation(h, HANDLE_FLAG_INHERIT, 1)); STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.hStdError = h; si.hStdOutput = h; si.dwFlags |= STARTF_USESTDHANDLES; PROCESS_INFORMATION pi; ZeroMemory(&pi, sizeof(pi)); bool success = CreateProcess( NULL, args_tchar.get(), NULL, NULL, true, 0, NULL, NULL, &si, &pi) != 0; if (!success) { LPSTR lpMsgBuf=0; DWORD dw = GetLastError(); FormatMessageA( FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, dw, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL ); stringstream ss; ss << "couldn't start process " << argv_[0] << "; " << lpMsgBuf; uassert(14042, ss.str(), success); LocalFree(lpMsgBuf); } CloseHandle(pi.hThread); pid_ = pi.dwProcessId; handles.insert( make_pair( pid_, pi.hProcess ) ); #else pid_ = fork(); assert( pid_ != -1 ); if ( pid_ == 0 ) { // DON'T ASSERT IN THIS BLOCK - very bad things will happen const char** argv = new const char* [argv_.size()+1]; // don't need to free - in child for (unsigned i=0; i < argv_.size(); i++) { argv[i] = argv_[i].c_str(); } argv[argv_.size()] = 0; if ( dup2( child_stdout, STDOUT_FILENO ) == -1 || dup2( child_stdout, STDERR_FILENO ) == -1 ) { cout << "Unable to dup2 child output: " << errnoWithDescription() << endl; ::_Exit(-1); //do not pass go, do not call atexit handlers } const char** env = new const char* [2]; // don't need to free - in child env[0] = NULL; #if defined(HEAP_CHECKING) env[0] = "HEAPCHECK=normal"; env[1] = NULL; // Heap-check for mongos only. 'argv[0]' must be in the path format. if ( argv_[0].find("mongos") != string::npos) { execvpe( argv[ 0 ], const_cast<char**>(argv) , const_cast<char**>(env) ); } #endif // HEAP_CHECKING execvp( argv[ 0 ], const_cast<char**>(argv) ); cout << "Unable to start program " << argv[0] << ' ' << errnoWithDescription() << endl; ::_Exit(-1); } #endif }