hce-node application  1.4.3
HCE Hierarchical Cluster Engine node application
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
Process.cpp
Go to the documentation of this file.
1 #include <signal.h>
2 #include <stdexcept>
3 #include <string.h>
4 #include <errno.h>
5 #include <limits.h>
6 #include <sstream>
7 #include <iostream>
8 #include <sstream>
9 #include <stdio.h>
10 #include <stdlib.h>
11 #include <sys/stat.h>
12 #include <sys/wait.h>
13 #include <Poco/Thread.h>
14 #include <Poco/PipeStream.h>
15 
16 #include "Process.hpp"
17 
18 void signalHandler(int signum)
19 {
20  pid_t pid = 0;
21  int status = 0;
22  /* Keep asking for a status until we get a definitive result. */
23  do
24  {
25  pid = waitpid (WAIT_ANY, &status, WNOHANG | WUNTRACED);
26  }
27  while (pid <= 0 && errno == EINTR);
28 }
29 
30 namespace HCE
31 {
32 //-----------------------------------------------------------------------------
33 ProcessHandle Process::launch(const std::string& cmd, const Poco::Process::Args& args, const std::string& initialDirectory,
34  std::istream& in, std::ostream& os, std::ostream& es, const Poco::Process::Env& env, CallbackFunction fn)
35 {
36  std::stringstream outMsg, errMsg;
37  std::string inputStream = toString(in);
38 
39  pid_t nPid;
40  int pipeOut[2]; /* pipe to get the exec'ed program out */
41  int pipeErr[2]; /* pipe to get the exec'ed program err */
42 
43  if (pipe(pipeOut) != 0)
44  throw std::runtime_error(strerror(errno));
45 
46  if (pipe(pipeErr) != 0)
47  throw std::runtime_error(strerror(errno));
48 
49  struct sigaction sa;
50  __sigset_t mask;
51  sa.sa_mask = mask;
52  sa.sa_handler = signalHandler;
53  sa.sa_flags = SA_NOCLDWAIT;
54  sigaction (SIGCHLD, &sa, NULL);
55 
56  nPid = fork();
57  if (nPid < 0)
58  {
59  throw std::runtime_error(strerror(errno));
60  }
61  else if (nPid == 0)
62  {
63  //Change File Mask
64  umask(0);
65 
66  //Create a new Signature Id for our child
67  pid_t sid = setsid();
68  if (sid < 0)
69  exit(EXIT_FAILURE);
70 
71  /* dup pipe write to stdout/stderr */
72  dup2(pipeOut[1], STDOUT_FILENO);
73  dup2(pipeErr[1], STDERR_FILENO);
74 
75  /* close unnecessary pipe descriptors for a clean environment */
76  close(pipeOut[0]);
77  close(pipeErr[0]);
78 
79  Poco::Pipe inPipe;
80  Poco::ProcessHandle ph = Poco::Process::launch(cmd, args, initialDirectory, &inPipe, 0, 0, env);
81 
82  Poco::PipeOutputStream istr(inPipe);
83  istr << inputStream;
84  istr.close();
85  inPipe.close();
86 
87  HCE::ProcessHandle handle(ph.id());
88  handle.wait();
89 
90  close(pipeOut[1]);
91  close(pipeErr[1]);
92 
93  Poco::Thread::sleep(500);
94  exit(SUCCESS);
95  }
96  else
97  {
98  close(pipeOut[1]);
99  close(pipeErr[1]);
100 
101  if (fn)
102  fn(nPid);
103  /* read output of stdout/stderr */
104  readFromPipe(pipeOut[0], outMsg);
105  readFromPipe(pipeErr[0], errMsg);
106 
107  HCE::ProcessHandle handle(nPid);
108  handle.wait();
109 
110  close(pipeOut[0]);
111  close(pipeErr[0]);
112  }
113  os << outMsg.str();
114  es << errMsg.str();
115 
116  return ProcessHandle(nPid);
117 }
118 //-----------------------------------------------------------------------------
119 // cppcheck-suppress unusedFunction
120 void Process::writeToPipe(int fd, const std::string& inputData)
121 {
122  FILE* stream = nullptr;
123 
124  if((stream = fdopen( fd, "w" ))==nullptr)
125  exit(ERROR_FDOPEN_WRITE);
126 
127  if (!inputData.empty())
128  fwrite(inputData.c_str(), sizeof(char), inputData.length(), stream);
129 
130  fflush(stream);
131  fclose(stream);
132 }
133 //-----------------------------------------------------------------------------
134 void Process::readFromPipe(int fd, std::stringstream& os)
135 {
136  FILE* stream = nullptr;
137 
138  if((stream = fdopen( fd, "r" ))==nullptr)
139  exit(ERROR_FDOPEN_READ);
140 
141  int ch = 0;
142  while((ch = getc(stream)) != std::char_traits<char>::eof())
143  os << (char)ch;
144 
145  os.flush();
146  fclose(stream);
147 }
148 //-----------------------------------------------------------------------------
149 std::string Process::toString(std::istream& in)
150 {
151  std::string str;
152  in.seekg(0, std::ios::end);
153  str.resize(in.tellg());
154  in.seekg(0, std::ios::beg);
155  in.read(const_cast<char*>(str.c_str()), str.size());
156  return str;
157 }
158 //-----------------------------------------------------------------------------
159 void Process::requestKill(ProcessHandle& handle, unsigned int signum)
160 {
161  requestKill(handle.id(), signum);
162 }
163 //-----------------------------------------------------------------------------
164 void Process::requestKill(pid_t pid, unsigned int signum)
165 {
166  if(kill(pid, signum) != 0)
167  throw std::runtime_error(strerror(errno));
168  int status = 0;
169  wait(&status);
170 }
171 //-----------------------------------------------------------------------------
173 {
174  requestKill(handle.id());
175 }
176 //-----------------------------------------------------------------------------
178 {
179  Process::requestKill(pid, SIGKILL);
180 }
181 //-----------------------------------------------------------------------------
183 {
184  requestTermination(handle.id());
185 }
186 //-----------------------------------------------------------------------------
188 {
189  Process::requestKill(pid, SIGINT);
190 }
191 //-----------------------------------------------------------------------------
193 {
194  return processStatus(handle.id());
195 }
196 //-----------------------------------------------------------------------------
197 std::string Process::processStatus(pid_t pid)
198 {
199  std::string result;
200  char procPath[PATH_MAX]={0};
201 
202  sprintf(procPath, "/proc/%d/status", pid);
203 
204  FILE* proc = fopen(procPath, "r");
205  if (proc)
206  {
207  const unsigned int SZ = 256;
208  char buff[SZ]={0};
209  char state[SZ]={0};
210 
211  fgets(buff, SZ, proc);
212  fgets(buff, SZ, proc);
213  sscanf(buff, "State:\t%20s", state);
214  result = state;
215  fclose(proc);
216  }
217  return result;
218 }
219 //-----------------------------------------------------------------------------
221 {
222  return processParent(handle.id());
223 }
224 //-----------------------------------------------------------------------------
226 {
227  char procPath[PATH_MAX]={0};
228  pid_t ppid = 0;
229 
230  sprintf(procPath, "/proc/%d/status", pid);
231 
232  FILE* proc = fopen(procPath, "r");
233  if (proc)
234  {
235  const unsigned int SZ = 256;
236  char buff[SZ]={0};
237  const char name[] = "PPid";
238 
239  while (!feof(proc))
240  {
241  fgets(buff, SZ, proc);
242  if (strncmp(buff, name, strlen(name))==0)
243  {
244  sscanf(buff, "PPid:\t%10d", &ppid);
245  break;
246  }
247  }
248  fclose(proc);
249  }
250  return ProcessHandle(ppid);
251 }
252 //-----------------------------------------------------------------------------
254 {
255  return isExistProcess(handle.id());
256 }
257 //-----------------------------------------------------------------------------
259 {
260  bool result = false;
261  char procPath[PATH_MAX]={0};
262 
263  sprintf(procPath, "/proc/%d/status", pid);
264 
265  FILE* proc = fopen(procPath, "r");
266  if (proc)
267  {
268  result = true;
269  fclose(proc);
270  }
271  return result;
272 }
273 //-----------------------------------------------------------------------------
274 pid_t Process::id(void)
275 {
276  return getpid();
277 }
278 //-----------------------------------------------------------------------------
279 //-----------------------------------------------------------------------------
280 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args, const std::string& initialDirectory,
281  std::istream& in, std::ostream& out, std::ostream& err, const Poco::Process::Env& env)
282 {
283  return Process::launch(command, args, initialDirectory, in, out, err, env, nullptr);
284 }
285 //-----------------------------------------------------------------------------
286 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args,
287  std::istream& in, std::ostream& out, std::ostream& err, const Poco::Process::Env& env)
288 {
289  std::string initialDirectory;
290  return Process::launch(command, args, initialDirectory, in, out, err, env);
291 }
292 //-----------------------------------------------------------------------------
293 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args, const std::string& initialDirectory,
294  std::istream& in, std::ostream& out, std::ostream& err)
295 {
296  Poco::Process::Env env;
297  return Process::launch(command, args, initialDirectory, in, out, err, env);
298 }
299 //-----------------------------------------------------------------------------
300 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args,
301  std::istream& in, std::ostream& out, std::ostream& err)
302 {
303  std::string initialDirectory;
304  return Process::launch(command, args, initialDirectory, in, out, err);
305 }
306 //-----------------------------------------------------------------------------
307 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args, const std::string& initialDirectory)
308 {
309  std::stringstream inMsg, outMsg, errMsg;
310  return Process::launch(command, args, initialDirectory, inMsg, outMsg, errMsg);
311 }
312 //-----------------------------------------------------------------------------
313 ProcessHandle Process::launch(const std::string& command, const Poco::Process::Args& args)
314 {
315  std::string initialDirectory;
316  return Process::launch(command, args, initialDirectory);
317 }
318 //-----------------------------------------------------------------------------
319 //-----------------------------------------------------------------------------
320 } // end namespace HCE