// // Process_UNIX.cpp // // $Id: //poco/1.4/Foundation/src/Process_UNIX.cpp#3 $ // // Library: Foundation // Package: Processes // Module: Process // // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH. // and Contributors. // // Permission is hereby granted, free of charge, to any person or organization // obtaining a copy of the software and accompanying documentation covered by // this license (the "Software") to use, reproduce, display, distribute, // execute, and transmit the Software, and to prepare derivative works of the // Software, and to permit third-parties to whom the Software is furnished to // do so, all subject to the following: // // The copyright notices in the Software and this entire statement, including // the above license grant, this restriction and the following disclaimer, // must be included in all copies of the Software, in whole or in part, and // all derivative works of the Software, unless such copies or derivative // works are solely in the form of machine-executable object code generated by // a source language processor. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. // #include "Poco/Process_UNIX.h" #include "Poco/Exception.h" #include "Poco/NumberFormatter.h" #include "Poco/Pipe.h" #include #include #include #include #include #include #if defined(__QNX__) #include #include #include #endif namespace Poco { // // ProcessHandleImpl // ProcessHandleImpl::ProcessHandleImpl(pid_t pid): _pid(pid) { } ProcessHandleImpl::~ProcessHandleImpl() { } pid_t ProcessHandleImpl::id() const { return _pid; } int ProcessHandleImpl::wait() const { int status; int rc; do { rc = waitpid(_pid, &status, 0); } while (rc < 0 && errno == EINTR); if (rc != _pid) throw SystemException("Cannot wait for process", NumberFormatter::format(_pid)); return WEXITSTATUS(status); } // // ProcessImpl // ProcessImpl::PIDImpl ProcessImpl::idImpl() { return getpid(); } void ProcessImpl::timesImpl(long& userTime, long& kernelTime) { struct rusage usage; getrusage(RUSAGE_SELF, &usage); userTime = usage.ru_utime.tv_sec; kernelTime = usage.ru_stime.tv_sec; } 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(command.c_str()); for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) argv[i++] = const_cast(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 envChars; if (!env.empty()) { envChars = getEnvironmentVariablesBuffer(env); envPtr = &environmentChars[0]; } int pid = spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr); delete [] argv; if (pid == -1) throw SystemException("cannot spawn", command); } 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(command.c_str()); for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it) argv[i++] = const_cast(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); } void ProcessImpl::killImpl(const ProcessHandleImpl& handle) { killImpl(handle.id()); } void ProcessImpl::killImpl(PIDImpl pid) { if (kill(pid, SIGKILL) != 0) { switch (errno) { case ESRCH: throw NotFoundException("cannot kill process"); case EPERM: throw NoPermissionException("cannot kill process"); default: throw SystemException("cannot kill process"); } } } void ProcessImpl::requestTerminationImpl(PIDImpl pid) { if (kill(pid, SIGINT) != 0) { switch (errno) { case ESRCH: throw NotFoundException("cannot terminate process"); case EPERM: throw NoPermissionException("cannot terminate process"); default: throw SystemException("cannot terminate process"); } } } } // namespace Poco