rvm  1.11
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
exec.cc
Go to the documentation of this file.
1 #include "config.h"
2 
3 #include <iostream>
4 
5 #ifdef HAVE_STDLIB_H
6 #include <stdlib.h>
7 #endif
8 #ifdef HAVE_SYS_TYPES_H
9 #include <sys/types.h>
10 #endif
11 #ifdef HAVE_SYS_WAIT_H
12 #include <sys/wait.h>
13 #endif
14 #ifdef HAVE_UNISTD_H
15 #include <unistd.h>
16 #endif
17 #ifdef HAVE_SIGNAL_H
18 #include <signal.h>
19 #endif
20 #ifdef HAVE_SYS_SELECT_H
21 #include <sys/select.h>
22 #endif
23 #include <sys/time.h>
24 
25 #include <cerrno>
26 
27 #include "asserts.h"
28 #include "error.h"
29 #include "fs.h"
30 #include "exec.h"
31 
32 /** C'tor */
34 {
35  clear();
36 }
37 
38 /** D'tor */
40 {
41  clear();
42 }
43 
44 /** Reset the execute class to default values, kill the child processif one is
45  * running */
46 void execute::clear(void)
47 {
48  if (child_running() && is_parent())
49  signal_child(SIGKILL);
50 
51  m_fd1[0] = 0;
52  m_fd1[1] = 0;
53  m_fd2[0] = 0;
54  m_fd2[1] = 0;
55  m_fd3[0] = 0;
56  m_fd3[1] = 0;
57  m_pid = 0;
58  m_status = 0;
59  m_in_eof = false;
60  m_out_eof = false;
61  m_err_eof = false;
62  m_child_started = false;
63 }
64 
65 /** Generic signal handler */
66 static void _signal_handler(int signo)
67 {
68  throw(ERROR(0,"Tried to write to a read-only pipe"));
69 }
70 
71 /** Fork a child process */
72 void execute::fork(void)
73 {
74  clear();
75  if (signal(SIGPIPE, _signal_handler) == SIG_ERR)
76  throw(ERROR(errno,"Could not catch SIGPIPIE signal"));
77  if (pipe(m_fd1) < 0)
78  throw(ERROR(errno,"Could not create pipe for in"));
79  if (pipe(m_fd2) < 0)
80  throw(ERROR(errno,"Could not create pipe for out"));
81  if (pipe(m_fd3) < 0)
82  throw(ERROR(errno,"Could not create pipe for err"));
83  if ((m_pid = ::fork()) < 0)
84  throw(ERROR(errno,"Could not fork"));
85  if (m_pid > 0) {
86  // Parent process
87  close(m_fd1[0]);
88  close(m_fd2[1]);
89  close(m_fd3[1]);
90  m_child_started = true;
91  }
92  else {
93  // Child process
94  close(m_fd1[1]);
95  close(m_fd2[0]);
96  close(m_fd3[0]);
97  }
98 }
99 
100 /** Returns true if called by the child */
102 {
103  if (m_pid == 0) {
104  return(true);
105  }
106  return(false);
107 }
108 
109 /** Returns true if called by the parent */
111 {
112  bool value;
113 
114  value = !is_child();
115 
116  return(value);
117 }
118 
119 /** Returns the PID */
120 pid_t execute::my_pid(void)
121 {
122  pid_t value;
123 
124  value = pid();
125 
126  return(value);
127 }
128 
129 /** Called by the child to exit with a particular code */
130 void execute::exit(int code)
131 {
132  if (is_child())
133  ::exit(code);
134 }
135 
136 /** Called by the child to reroute the child's stdin, stdout, and stderr to
137  * the parent */
139 {
140  if (!is_child())
141  return;
142 
143  if (m_fd1[0] != STDIN_FILENO) {
144  if (dup2(m_fd1[0], STDIN_FILENO) != STDIN_FILENO) {
145  error e(errno,ERROR_INSTANCE("dup2() failed for stdin"));
146  std::cerr << e << std::endl;
147  exit(127);
148  }
149  close(m_fd1[0]);
150  }
151  if (m_fd2[1] != STDOUT_FILENO) {
152  if (dup2(m_fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
153  error e(errno,ERROR_INSTANCE("dup2() failed for stdout"));
154  std::cerr << e << std::endl;
155  exit(127);
156  }
157  close(m_fd2[1]);
158  }
159  if (m_fd3[1] != STDERR_FILENO) {
160  if (dup2(m_fd3[1], STDERR_FILENO) != STDERR_FILENO) {
161  error e(errno,ERROR_INSTANCE("dup2() failed for stderr"));
162  std::cerr << e << std::endl;
163  exit(127);
164  }
165  close(m_fd3[1]);
166  }
167 }
168 
169 /** Returns the child's PID */
171 {
172  return(m_pid);
173 }
174 
175 /** Send a signal to the child */
176 void execute::signal_child(int signal_no)
177 {
178  kill(m_pid, signal_no);
179 }
180 
181 /** Send a HUP signal to the child */
183 {
184  signal_child(SIGHUP);
185 }
186 
187 /** Send a KILL signal to the child */
189 {
190  signal_child(SIGKILL);
191 }
192 
193 /** Wait for the child to exit */
194 void execute::wait(void)
195 {
196  if (is_parent()) {
197  pid_t value;
198  value = waitpid(m_pid, &m_status, 0);
199  }
200 }
201 
202 /** Check the child's status */
204 {
205  pid_t value;
206 
207  errno = 0;
208  value = waitpid(m_pid, &m_status, WNOHANG|WUNTRACED);
209 
210  return(value);
211 }
212 
213 /** Returns true if the child has been started */
214 bool execute::child_started(void) const
215 {
216  return(m_child_started);
217 }
218 
219 /** Returns true if the child is running */
221 {
222  pid_t pid;
223 
224  pid = check_child_();
225  if (pid > 0) return(false); // The child has exited
226  if ((pid < 0) && (errno == ECHILD)) return(false); // No such child exists
227  return(true);
228 }
229 
230 /** Returns true of the child has existed */
232 {
233  pid_t pid;
234 
235  pid = check_child_();
236  if (pid > 0) return(true);
237  if ((pid < 0) && (errno == ECHILD)) return(true);
238  return(false);
239 }
240 
241 /** Returns true if the child has exited normally */
243 {
244  bool value;
245 
246  value = (child_exited() && (child_exit_code() == 0));
247 
248  return(value);
249 }
250 
251 /** Returns true if the child was signaled */
253 {
254  bool value;
255 
256  check_child_();
257  value = WIFSIGNALED(m_status);
258 
259  return(value);
260 }
261 
262 /** Returns true if the child returned exit code 0 and no caught signals */
264 {
265  bool value;
266 
267  value = (child_exited() && (child_exit_code() == 0) && !child_signaled());
268 
269  return(value);
270 }
271 
272 /** Return the child's exit code */
274 {
275  int value;
276 
277  check_child_();
278  value = WEXITSTATUS(m_status);
279 
280  return(value);
281 }
282 
283 /** If the child was signaled, return the signal number */
285 {
286  int value;
287 
288  check_child_();
289  if (child_exited()) {
290  value = WTERMSIG(m_status);
291  return(value);
292  }
293  else {
294  value = WSTOPSIG(m_status);
295  return(value);
296  }
297 }
298 
299 /** Return a file descriptor for I/O between parent and child
300 
301  If called by the parent, a writeable file descriptor is returned.
302  If called by the child, a readable file descriptor is returned.
303 
304  If retroute_stdio() was called by the child, then the returned file
305  descriptor is the same as that used by the child for stdin.
306  */
307 int execute::in_fd(void)
308 {
309  if (is_parent()) {
310  // Return write end of input pipe
311  return(m_fd1[1]);
312  }
313  else {
314  // Return read end of input pipe
315  return(m_fd1[0]);
316  }
317 }
318 
319 /** Return a file descriptor for I/O between parent a child.
320 
321  If called by the parent, a readable file descriptor is returned.
322  If called by the child, a writable file descriptor is returned.
323 
324  If reroute_stdio() was called by the child, then the returned file
325  descriptor is the same as that used by the child for stdout.
326  */
328 {
329  if (is_parent()) {
330  // Return read end of output pipe
331  return(m_fd2[0]);
332  }
333  else {
334  // Return write end of output pipe
335  return(m_fd2[1]);
336  }
337 }
338 
339 /** Return a file descriptor for I/O between parent and child.
340 
341  If called by the parent, a readable file descriptor is returned.
342  If called by the child, a writeable file descriptor is returned.
343 
344  If reroute_stdio() was called by the child, then the returned file
345  descriptior is the same as that used by the child for stderr.
346  */
348 {
349  if (is_parent()) {
350  // return read end of error pipe
351  return(m_fd3[0]);
352  }
353  else {
354  // return write end of error pipe
355  return(m_fd3[1]);
356  }
357 }
358 
359 /** Return true if the file descriptor is ready to be written to */
361 {
362  struct timeval timeout = { 0, 0 };
363  fd_set wset;
364 
365  FD_ZERO(&wset);
366  FD_SET(fd, &wset);
367  select(fd+1, 0, &wset, 0, &timeout);
368  if (FD_ISSET(fd, &wset)) {
369  return(true);
370  }
371  return(false);
372 }
373 
374 /** Return true if the file descriptor has input ready to be read */
376 {
377  struct timeval timeout = { 0, 0 };
378  fd_set rset;
379 
380  FD_ZERO(&rset);
381  FD_SET(fd, &rset);
382  select(fd+1, &rset, 0, 0, &timeout);
383  if (FD_ISSET(fd, &rset)) {
384  return(true);
385  }
386  return(false);
387 }
388 
389 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
390 void execute::exec(const std::string command)
391 {
392  fork();
393  if (is_parent())
394  return;
395 
396  /*
397  {
398  bool wait_for_debugger = true;
399 
400  std::cerr << "Waiting for debugger to attach..." << std::endl;
401  while (wait_for_debugger);
402  std::cerr << "Debugger attached." << std::endl;
403  }
404  */
405  reroute_stdio();
406 
407  execl("/bin/sh", "sh", "-c", command.c_str(), (char *)0);
408  exit(127);
409 }
410 
411 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
412 void execute::exec(const std::string binary, const std::vector<std::string> argv)
413 {
414  char *bin = 0;
415  char *base = 0;
416  char **args = 0;
417  uint16 c;
418  size_t size;
419 
420  fork();
421  if (is_parent())
422  return;
423 
424  /*
425  {
426  bool wait_for_debugger = true;
427 
428  std::cerr << "Waiting for debugger to attach..." << std::endl;
429  while (wait_for_debugger);
430  std::cerr << "Debugger attached." << std::endl;
431  }
432  */
433 
434  reroute_stdio();
435 
436  bin = (char *)binary.c_str();
437  base = bin+strlen(bin);
438  while ((base > bin) && (*base != '/')) {
439  base--;
440  }
441  if (*base == '/') {
442  base++;
443  }
444  size = (argv.size() + 2) * sizeof(char *);
445  args = (char **)malloc(size);
446  memset((void *)args, 0, size);
447  if (args == 0) {
448  exit(127);
449  }
450  args[0] = base;
451  for (c = 0; c < argv.size(); c++) {
452  args[c+1] = (char *)argv[c].c_str();
453  }
454  args[c+1] = 0;
455 
456  execv(bin, args);
457  exit(127);
458 }
459 
460 /** Check I/O for input
461 
462  If called by the parent, check if ready to write to child's input.
463  If called by the child, check if input is ready to be read.
464 
465  If reroute_stdio() was called by the child, then this pipe is the same as
466  used by the child for stdin.
467  */
469 {
470  bool value;
471 
472  if (is_parent())
473  value = check_write_ready_(in_fd());
474  else
475  value = check_read_ready_(in_fd());
476 
477  return(value);
478 }
479 
480 /** Check I/O for output
481 
482  If called by the parent, check if output from child is ready to be read.
483  If called by the child, check if output to parent is ready to be written to.
484 
485  If reroute_stdio() was called by the child, then this pipe is the same as
486  used by the child for stdout.
487  */
489 {
490  bool value;
491 
492  if (is_parent())
493  value = check_read_ready_(out_fd());
494  else
495  value = check_write_ready_(out_fd());
496 
497  return(value);
498 }
499 
500 /** Check I/O for output
501 
502  If called by the parent, check if output from child is ready to be read.
503  If called by the child, check if output to parent is ready to be written to.
504 
505  If reroute_stdio() was called by the child, then this pipe is the same as
506  used by the child for stderr.
507  */
509 {
510  bool value;
511 
512  if (is_parent())
513  value = check_read_ready_(err_fd());
514  else
515  value = check_write_ready_(err_fd());
516 
517  return(value);
518 }
519 
520 /** Check for input EOF */
521 bool execute::in_eof(void)
522 {
523  return(m_in_eof);
524 }
525 
526 /** Check for output EOF */
528 {
529  return(m_out_eof);
530 }
531 
532 /** Check for err EOF */
534 {
535  return(m_err_eof);
536 }
537 
538 /** Allow child to read input from in_fd() */
539 int execute::in_read(char* buf, const int len)
540 {
541  int n;
542  int err;
543 
544  n = read(in_fd(), buf, len);
545  err = errno;
546  errno = 0;
547  if (n > 0) {
548  return(n);
549  }
550  if (child_started() && !child_running() && (err != EAGAIN))
551  m_in_eof = true;
552  return(0);
553 }
554 
555 /** Allow parent to write output to in_fd() */
556 int execute::in_write(const char* buf, const int len)
557 {
558  int n;
559  int err;
560 
561  n = write(in_fd(), buf, len);
562  err = errno;
563  errno = 0;
564  if (n > 0) {
565  return(n);
566  }
567  if (child_started() && !child_running() && (err != EAGAIN))
568  m_in_eof = true;
569  return(0);
570 }
571 
572 /** Allow parent to read out_fd() */
573 int execute::out_read(char* buf, const int len)
574 {
575  int n;
576  int err;
577 
578  n = read(out_fd(), buf, len);
579  err = errno;
580  errno = 0;
581  if (n > 0) {
582  return(n);
583  }
584  if (child_started() && !child_running() && (err != EAGAIN))
585  m_out_eof = true;
586  return(0);
587 }
588 
589 /** Allow child to write to out_fd() */
590 int execute::out_write(const char* buf, const int len)
591 {
592  int n;
593  int err;
594 
595  n = write(out_fd(), buf, len);
596  err = errno;
597  errno = 0;
598  if (n > 0) {
599  return(n);
600  }
601  if (child_started() && !child_running() && (err != EAGAIN))
602  m_out_eof = true;
603  return(0);
604 }
605 
606 /** Allow parent to read from err_fd() */
607 int execute::err_read(char* buf, const int len)
608 {
609  int n;
610  int err;
611 
612  n = read(err_fd(), buf, len);
613  err = errno;
614  errno = 0;
615  if (n > 0) {
616  return(n);
617  }
618  if (child_started() && !child_running() && (err != EAGAIN))
619  m_err_eof = true;
620  return(0);
621 }
622 
623 /** Allow child to write to err_fd() */
624 int execute::err_write(const char* buf, const int len)
625 {
626  int n;
627  int err;
628 
629  n = write(err_fd(), buf, len);
630  err = errno;
631  errno = 0;
632  if (n > 0) {
633  return(n);
634  }
635  if (child_started() && !child_running() && (err != EAGAIN))
636  m_err_eof = true;
637  return(0);
638 }
639 
640 /** Dump execute object information -- used for debugging */
641 void execute::print(std::ostream& out)
642 {
643  out << "execute::is_child() = " << is_child() << std::endl;
644  out << "execute::is_parent() = " << is_parent() << std::endl;
645  out << "execute::my_pid() = " << my_pid() << std::endl;
646  out << "execute::child_running() = " << child_running() << std::endl;
647  out << "execute::child_exited() = " << child_exited() << std::endl;
648  out << "execute::child_exited_normally() = " << child_exited_normally()
649  << std::endl;
650  out << "execute::child_exited_success() = " << child_exited_success()
651  << std::endl;
652  out << "execute::child_signaled() = " << child_signaled() << std::endl;
653  out << "execute::child_exit_code() = " << child_exit_code() << std::endl;
654  out << "execute::child_signal_no() = " << child_signal_no() << std::endl;
655  out << "execute::in_fd() = " << in_fd() << std::endl;
656  out << "execute::out_fd() = " << out_fd() << std::endl;
657  out << "execute::err_fd() = " << err_fd() << std::endl;
658  out << "execute::in_ready() = " << in_ready() << std::endl;
659  out << "execute::out_ready() = " << out_ready() << std::endl;
660  out << "execute::err_ready() = " << err_ready() << std::endl;
661 }
662 
663 /** Convenience function to call execute::print() */
664 std::ostream& operator << (std::ostream& out, execute& exe)
665 {
666  exe.print(out);
667 
668  return(out);
669 }
670 
const pid_t pid(void)
Return the PID of this process.
Definition: fs.cc:162
void reroute_stdio(void)
Called by the child to reroute the child's stdin, stdout, and stderr to the parent.
Definition: exec.cc:138
execute()
C'tor.
Definition: exec.cc:33
int child_signal_no(void)
If the child was signaled, return the signal number.
Definition: exec.cc:284
~execute()
D'tor.
Definition: exec.cc:39
pid_t child_pid(void)
Returns the child's PID.
Definition: exec.cc:170
int m_fd2[2]
Definition: exec.h:77
int m_fd3[2]
Definition: exec.h:78
bool err_eof(void)
Check for err EOF.
Definition: exec.cc:533
bool out_eof(void)
Check for output EOF.
Definition: exec.cc:527
void fork(void)
Fork a child process.
Definition: exec.cc:72
std::ostream & operator<<(std::ostream &out, execute &exe)
Convenience function to call execute::print()
Definition: exec.cc:664
void kill_child(void)
Send a KILL signal to the child.
Definition: exec.cc:188
static void _signal_handler(int signo)
Generic signal handler.
Definition: exec.cc:66
int err_read(char *buf, const int len)
Allow parent to read from err_fd()
Definition: exec.cc:607
void exit(int code=0)
Called by the child to exit with a particular code.
Definition: exec.cc:130
void signal_child(int signal_no)
Send a signal to the child.
Definition: exec.cc:176
pid_t m_pid
Definition: exec.h:79
bool err_ready(void)
Check I/O for output.
Definition: exec.cc:508
bool out_ready(void)
Check I/O for output.
Definition: exec.cc:488
bool child_started(void) const
Returns true if the child has been started.
Definition: exec.cc:214
int in_write(const char *buf, const int len)
Allow parent to write output to in_fd()
Definition: exec.cc:556
int out_fd(void)
Return a file descriptor for I/O between parent a child.
Definition: exec.cc:327
void hup_child(void)
Send a HUP signal to the child.
Definition: exec.cc:182
bool m_out_eof
Definition: exec.h:82
bool child_running(void)
Returns true if the child is running.
Definition: exec.cc:220
int m_status
Definition: exec.h:80
void clear(void)
Reset the execute class to default values, kill the child processif one is running.
Definition: exec.cc:46
bool child_exited_success(void)
Returns true if the child returned exit code 0 and no caught signals.
Definition: exec.cc:263
bool m_in_eof
Definition: exec.h:81
void exec(const std::string command)
Execute a command, rerouting stdin, stdout, and stderr to parent.
Definition: exec.cc:390
int err_write(const char *buf, const int len)
Allow child to write to err_fd()
Definition: exec.cc:624
int out_read(char *buf, const int len)
Allow parent to read out_fd()
Definition: exec.cc:573
bool m_err_eof
Definition: exec.h:83
bool child_signaled(void)
Returns true if the child was signaled.
Definition: exec.cc:252
An error class.
Definition: error.h:72
int child_exit_code(void)
Return the child's exit code.
Definition: exec.cc:273
void print(std::ostream &out)
Dump execute object information – used for debugging.
Definition: exec.cc:641
bool child_exited_normally(void)
Returns true if the child has exited normally.
Definition: exec.cc:242
bool check_read_ready_(int fd)
Return true if the file descriptor has input ready to be read.
Definition: exec.cc:375
Fork a child process or execute an external program.
Definition: exec.h:21
pid_t check_child_(void)
Check the child's status.
Definition: exec.cc:203
int in_read(char *buf, const int len)
Allow child to read input from in_fd()
Definition: exec.cc:539
bool in_ready(void)
Check I/O for input.
Definition: exec.cc:468
bool in_eof(void)
Check for input EOF.
Definition: exec.cc:521
bool child_exited(void)
Returns true of the child has existed.
Definition: exec.cc:231
pid_t my_pid(void)
Returns the PID.
Definition: exec.cc:120
int err_fd(void)
Return a file descriptor for I/O between parent and child.
Definition: exec.cc:347
#define ERROR_INSTANCE(s)
Definition: error.h:67
int out_write(const char *buf, const int len)
Allow child to write to out_fd()
Definition: exec.cc:590
#define ERROR(e, s)
Definition: error.h:120
bool check_write_ready_(int fd)
Return true if the file descriptor is ready to be written to.
Definition: exec.cc:360
void wait(void)
Wait for the child to exit.
Definition: exec.cc:194
bool is_child(void)
Returns true if called by the child.
Definition: exec.cc:101
int m_fd1[2]
Definition: exec.h:76
bool is_parent(void)
Returns true if called by the parent.
Definition: exec.cc:110
int in_fd(void)
Return a file descriptor for I/O between parent and child.
Definition: exec.cc:307
bool m_child_started
Definition: exec.h:84