ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env) { #if defined(__QNX__) if (initialDirectory.empty()) { /// use QNX's spawn system call which is more efficient than fork/exec. char** argv = new char*[args.size() + 2]; int i = 0; argv[i++] = const_cast<char*>(command.c_str()); for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) argv[i++] = const_cast<char*>(it->c_str()); argv[i] = NULL; struct inheritance inherit; std::memset(&inherit, 0, sizeof(inherit)); inherit.flags = SPAWN_ALIGN_DEFAULT | SPAWN_CHECK_SCRIPT | SPAWN_SEARCH_PATH; int fdmap[3]; fdmap[0] = inPipe ? inPipe->readHandle() : 0; fdmap[1] = outPipe ? outPipe->writeHandle() : 1; fdmap[2] = errPipe ? errPipe->writeHandle() : 2; char** envPtr = 0; std::vector<char> envChars; std::vector<char*> envPtrs; if (!env.empty()) { envChars = getEnvironmentVariablesBuffer(env); envPtrs.reserve(env.size() + 1); char* p = &envChars[0]; while (*p) { envPtrs.push_back(p); while (*p) ++p; ++p; } envPtrs.push_back(0); envPtr = &envPtrs[0]; } int pid = spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr); delete [] argv; if (pid == -1) throw SystemException("cannot spawn", command); if (inPipe) inPipe->close(Pipe::CLOSE_READ); if (outPipe) outPipe->close(Pipe::CLOSE_WRITE); if (errPipe) errPipe->close(Pipe::CLOSE_WRITE); return new ProcessHandleImpl(pid); } else { return launchByForkExecImpl(command, args, initialDirectory, inPipe, outPipe, errPipe, env); } #else return launchByForkExecImpl(command, args, initialDirectory, inPipe, outPipe, errPipe, env); #endif }
ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env) { int pid = fork(); if (pid < 0) { throw SystemException("Cannot fork process for", command); } else if (pid == 0) { if (!initialDirectory.empty()) { if (chdir(initialDirectory.c_str()) != 0) { _exit(72); } } setEnvironmentVariables(env); // setup redirection if (inPipe) { dup2(inPipe->readHandle(), STDIN_FILENO); inPipe->close(Pipe::CLOSE_BOTH); } // outPipe and errPipe may be the same, so we dup first and close later if (outPipe) dup2(outPipe->writeHandle(), STDOUT_FILENO); if (errPipe) dup2(errPipe->writeHandle(), STDERR_FILENO); if (outPipe) outPipe->close(Pipe::CLOSE_BOTH); if (errPipe) errPipe->close(Pipe::CLOSE_BOTH); // close all open file descriptors other than stdin, stdout, stderr for (int i = 3; i < getdtablesize(); ++i) close(i); char** argv = new char*[args.size() + 2]; int i = 0; argv[i++] = const_cast<char*>(command.c_str()); for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) argv[i++] = const_cast<char*>(it->c_str()); argv[i] = NULL; execvp(command.c_str(), argv); _exit(72); } if (inPipe) inPipe->close(Pipe::CLOSE_READ); if (outPipe) outPipe->close(Pipe::CLOSE_WRITE); if (errPipe) errPipe->close(Pipe::CLOSE_WRITE); return new ProcessHandleImpl(pid); }
ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env) { char** argv = new char*[args.size() + 2]; int i = 0; argv[i++] = const_cast<char*>(command.c_str()); for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) argv[i++] = const_cast<char*>(it->c_str()); argv[i] = NULL; try { int pid = vfork(); if (pid < 0) { throw SystemException("Cannot fork process for", command); } else if (pid == 0) { if (!initialDirectory.empty()) { if (chdir(initialDirectory.c_str()) != 0) { std::stringstream str; str << "Cannot set initial directory to '" << initialDirectory << "' when forking process for"; throw SystemException(str.str(), command); } } setEnvironmentVariables(environment_variables); if (execvp(command.c_str(), argv) == -1) throw SystemException("Cannot execute command", command); } else { delete [] argv; return new ProcessHandleImpl(pid); } } catch (...) { delete [] argv; throw; } }