Process_UNIX.cpp 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261
  1. //
  2. // Process_UNIX.cpp
  3. //
  4. // $Id: //poco/1.4/Foundation/src/Process_UNIX.cpp#3 $
  5. //
  6. // Library: Foundation
  7. // Package: Processes
  8. // Module: Process
  9. //
  10. // Copyright (c) 2004-2006, Applied Informatics Software Engineering GmbH.
  11. // and Contributors.
  12. //
  13. // Permission is hereby granted, free of charge, to any person or organization
  14. // obtaining a copy of the software and accompanying documentation covered by
  15. // this license (the "Software") to use, reproduce, display, distribute,
  16. // execute, and transmit the Software, and to prepare derivative works of the
  17. // Software, and to permit third-parties to whom the Software is furnished to
  18. // do so, all subject to the following:
  19. //
  20. // The copyright notices in the Software and this entire statement, including
  21. // the above license grant, this restriction and the following disclaimer,
  22. // must be included in all copies of the Software, in whole or in part, and
  23. // all derivative works of the Software, unless such copies or derivative
  24. // works are solely in the form of machine-executable object code generated by
  25. // a source language processor.
  26. //
  27. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  28. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  29. // FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
  30. // SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
  31. // FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
  32. // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  33. // DEALINGS IN THE SOFTWARE.
  34. //
  35. #include "Poco/Process_UNIX.h"
  36. #include "Poco/Exception.h"
  37. #include "Poco/NumberFormatter.h"
  38. #include "Poco/Pipe.h"
  39. #include <errno.h>
  40. #include <signal.h>
  41. #include <sys/time.h>
  42. #include <sys/types.h>
  43. #include <sys/resource.h>
  44. #include <sys/wait.h>
  45. #if defined(__QNX__)
  46. #include <process.h>
  47. #include <spawn.h>
  48. #include <cstring>
  49. #endif
  50. namespace Poco {
  51. //
  52. // ProcessHandleImpl
  53. //
  54. ProcessHandleImpl::ProcessHandleImpl(pid_t pid):
  55. _pid(pid)
  56. {
  57. }
  58. ProcessHandleImpl::~ProcessHandleImpl()
  59. {
  60. }
  61. pid_t ProcessHandleImpl::id() const
  62. {
  63. return _pid;
  64. }
  65. int ProcessHandleImpl::wait() const
  66. {
  67. int status;
  68. int rc;
  69. do
  70. {
  71. rc = waitpid(_pid, &status, 0);
  72. }
  73. while (rc < 0 && errno == EINTR);
  74. if (rc != _pid)
  75. throw SystemException("Cannot wait for process", NumberFormatter::format(_pid));
  76. return WEXITSTATUS(status);
  77. }
  78. //
  79. // ProcessImpl
  80. //
  81. ProcessImpl::PIDImpl ProcessImpl::idImpl()
  82. {
  83. return getpid();
  84. }
  85. void ProcessImpl::timesImpl(long& userTime, long& kernelTime)
  86. {
  87. struct rusage usage;
  88. getrusage(RUSAGE_SELF, &usage);
  89. userTime = usage.ru_utime.tv_sec;
  90. kernelTime = usage.ru_stime.tv_sec;
  91. }
  92. ProcessHandleImpl* ProcessImpl::launchImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env)
  93. {
  94. #if defined(__QNX__)
  95. if (initialDirectory.empty())
  96. {
  97. /// use QNX's spawn system call which is more efficient than fork/exec.
  98. char** argv = new char*[args.size() + 2];
  99. int i = 0;
  100. argv[i++] = const_cast<char*>(command.c_str());
  101. for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
  102. argv[i++] = const_cast<char*>(it->c_str());
  103. argv[i] = NULL;
  104. struct inheritance inherit;
  105. std::memset(&inherit, 0, sizeof(inherit));
  106. inherit.flags = SPAWN_ALIGN_DEFAULT | SPAWN_CHECK_SCRIPT | SPAWN_SEARCH_PATH;
  107. int fdmap[3];
  108. fdmap[0] = inPipe ? inPipe->readHandle() : 0;
  109. fdmap[1] = outPipe ? outPipe->writeHandle() : 1;
  110. fdmap[2] = errPipe ? errPipe->writeHandle() : 2;
  111. char** envPtr = 0;
  112. std::vector<char> envChars;
  113. std::vector<char*> envPtrs;
  114. if (!env.empty())
  115. {
  116. envChars = getEnvironmentVariablesBuffer(env);
  117. envPtrs.reserve(env.size() + 1);
  118. char* p = &envChars[0];
  119. while (*p)
  120. {
  121. envPtrs.push_back(p);
  122. while (*p) ++p;
  123. ++p;
  124. }
  125. envPtrs.push_back(0);
  126. envPtr = &envPtrs[0];
  127. }
  128. int pid = spawn(command.c_str(), 3, fdmap, &inherit, argv, envPtr);
  129. delete [] argv;
  130. if (pid == -1)
  131. throw SystemException("cannot spawn", command);
  132. if (inPipe) inPipe->close(Pipe::CLOSE_READ);
  133. if (outPipe) outPipe->close(Pipe::CLOSE_WRITE);
  134. if (errPipe) errPipe->close(Pipe::CLOSE_WRITE);
  135. return new ProcessHandleImpl(pid);
  136. }
  137. else
  138. {
  139. return launchByForkExecImpl(command, args, initialDirectory, inPipe, outPipe, errPipe, env);
  140. }
  141. #else
  142. return launchByForkExecImpl(command, args, initialDirectory, inPipe, outPipe, errPipe, env);
  143. #endif
  144. }
  145. ProcessHandleImpl* ProcessImpl::launchByForkExecImpl(const std::string& command, const ArgsImpl& args, const std::string& initialDirectory, Pipe* inPipe, Pipe* outPipe, Pipe* errPipe, const EnvImpl& env)
  146. {
  147. int pid = fork();
  148. if (pid < 0)
  149. {
  150. throw SystemException("Cannot fork process for", command);
  151. }
  152. else if (pid == 0)
  153. {
  154. if (!initialDirectory.empty())
  155. {
  156. if (chdir(initialDirectory.c_str()) != 0)
  157. {
  158. _exit(72);
  159. }
  160. }
  161. setEnvironmentVariables(env);
  162. // setup redirection
  163. if (inPipe)
  164. {
  165. dup2(inPipe->readHandle(), STDIN_FILENO);
  166. inPipe->close(Pipe::CLOSE_BOTH);
  167. }
  168. // outPipe and errPipe may be the same, so we dup first and close later
  169. if (outPipe) dup2(outPipe->writeHandle(), STDOUT_FILENO);
  170. if (errPipe) dup2(errPipe->writeHandle(), STDERR_FILENO);
  171. if (outPipe) outPipe->close(Pipe::CLOSE_BOTH);
  172. if (errPipe) errPipe->close(Pipe::CLOSE_BOTH);
  173. // close all open file descriptors other than stdin, stdout, stderr
  174. for (int i = 3; i < getdtablesize(); ++i)
  175. close(i);
  176. char** argv = new char*[args.size() + 2];
  177. int i = 0;
  178. argv[i++] = const_cast<char*>(command.c_str());
  179. for (ArgsImpl::const_iterator it = args.begin(); it != args.end(); ++it)
  180. argv[i++] = const_cast<char*>(it->c_str());
  181. argv[i] = NULL;
  182. execvp(command.c_str(), argv);
  183. _exit(72);
  184. }
  185. if (inPipe) inPipe->close(Pipe::CLOSE_READ);
  186. if (outPipe) outPipe->close(Pipe::CLOSE_WRITE);
  187. if (errPipe) errPipe->close(Pipe::CLOSE_WRITE);
  188. return new ProcessHandleImpl(pid);
  189. }
  190. void ProcessImpl::killImpl(const ProcessHandleImpl& handle)
  191. {
  192. killImpl(handle.id());
  193. }
  194. void ProcessImpl::killImpl(PIDImpl pid)
  195. {
  196. if (kill(pid, SIGKILL) != 0)
  197. {
  198. switch (errno)
  199. {
  200. case ESRCH:
  201. throw NotFoundException("cannot kill process");
  202. case EPERM:
  203. throw NoPermissionException("cannot kill process");
  204. default:
  205. throw SystemException("cannot kill process");
  206. }
  207. }
  208. }
  209. void ProcessImpl::requestTerminationImpl(PIDImpl pid)
  210. {
  211. if (kill(pid, SIGINT) != 0)
  212. {
  213. switch (errno)
  214. {
  215. case ESRCH:
  216. throw NotFoundException("cannot terminate process");
  217. case EPERM:
  218. throw NoPermissionException("cannot terminate process");
  219. default:
  220. throw SystemException("cannot terminate process");
  221. }
  222. }
  223. }
  224. } // namespace Poco