rvm 1.08

exec.cc

Go to the documentation of this file.
00001 #include "config.h"
00002 
00003 #include <iostream>
00004 
00005 #ifdef HAVE_STDLIB_H
00006 #include <stdlib.h>
00007 #endif
00008 #ifdef HAVE_SYS_TYPES_H
00009 #include <sys/types.h>
00010 #endif
00011 #ifdef HAVE_SYS_WAIT_H
00012 #include <sys/wait.h>
00013 #endif
00014 #ifdef HAVE_UNISTD_H
00015 #include <unistd.h>
00016 #endif
00017 #ifdef HAVE_SIGNAL_H
00018 #include <signal.h>
00019 #endif
00020 #ifdef HAVE_SYS_SELECT_H
00021 #include <sys/select.h>
00022 #endif
00023 #include <sys/time.h>
00024 
00025 #include <cerrno>
00026 
00027 #include "asserts.h"
00028 #include "error.h"
00029 #include "fs.h"
00030 #include "exec.h"
00031 
00032 /** C'tor */
00033 execute::execute()
00034 {
00035         clear();
00036 }
00037 
00038 /** D'tor */
00039 execute::~execute()
00040 {
00041         clear();
00042 }
00043 
00044 /** Reset the execute class to default values, kill the child processif one is
00045  * running */
00046 void execute::clear(void)
00047 {
00048         if (child_running() && is_parent())
00049                 signal_child(SIGKILL);
00050 
00051         m_fd1[0] = 0;
00052         m_fd1[1] = 0;
00053         m_fd2[0] = 0;
00054         m_fd2[1] = 0;
00055         m_fd3[0] = 0;
00056         m_fd3[1] = 0;
00057         m_pid = 0;
00058         m_status = 0;
00059         m_in_eof = false;
00060         m_out_eof = false;
00061         m_err_eof = false;
00062         m_child_started = false;
00063 }
00064 
00065 /** Generic signal handler */
00066 static void _signal_handler(int signo)
00067 {
00068         throw(ERROR(0,"Tried to write to a read-only pipe"));
00069 }
00070 
00071 /** Fork a child process */
00072 void execute::fork(void)
00073 {
00074         clear();
00075         if (signal(SIGPIPE, _signal_handler) == SIG_ERR)
00076                 throw(ERROR(errno,"Could not catch SIGPIPIE signal"));
00077         if (pipe(m_fd1) < 0)
00078                 throw(ERROR(errno,"Could not create pipe for in"));
00079         if (pipe(m_fd2) < 0)
00080                 throw(ERROR(errno,"Could not create pipe for out"));
00081         if (pipe(m_fd3) < 0)
00082                 throw(ERROR(errno,"Could not create pipe for err"));
00083         if ((m_pid = ::fork()) < 0)
00084                 throw(ERROR(errno,"Could not fork"));
00085         if (m_pid > 0) {
00086                 // Parent process
00087                 close(m_fd1[0]);
00088                 close(m_fd2[1]);
00089                 close(m_fd3[1]);
00090                 m_child_started = true;
00091         }
00092         else {
00093                 // Child process
00094                 close(m_fd1[1]);
00095                 close(m_fd2[0]);
00096                 close(m_fd3[0]);
00097         }
00098 }
00099 
00100 /** Returns true if called by the child */
00101 bool execute::is_child(void)
00102 {
00103         if (m_pid == 0) {
00104                 return(true);
00105         }
00106         return(false);
00107 }
00108 
00109 /** Returns true if called by the parent */
00110 bool execute::is_parent(void)
00111 {
00112         bool value;
00113 
00114         value = !is_child();
00115 
00116         return(value);
00117 }
00118 
00119 /** Returns the PID */
00120 pid_t execute::my_pid(void)
00121 {
00122         pid_t value;
00123 
00124         value = pid();
00125 
00126         return(value);
00127 }
00128 
00129 /** Called by the child to exit with a particular code */
00130 void execute::exit(int code)
00131 {
00132         if (is_child())
00133 		::exit(code);
00134 }
00135 
00136 /** Called by the child to reroute the child's stdin, stdout, and stderr to
00137  * the parent */
00138 void execute::reroute_stdio(void)
00139 {
00140         if (!is_child())
00141                 return;
00142 
00143         if (m_fd1[0] != STDIN_FILENO) {
00144                 if (dup2(m_fd1[0], STDIN_FILENO) != STDIN_FILENO) {
00145                         error e(errno,ERROR_INSTANCE("dup2() failed for stdin"));
00146                         std::cerr << e << std::endl;
00147                         exit(127);
00148                 }
00149                 close(m_fd1[0]);
00150         }
00151         if (m_fd2[1] != STDOUT_FILENO) {
00152                 if (dup2(m_fd2[1], STDOUT_FILENO) != STDOUT_FILENO) {
00153                         error e(errno,ERROR_INSTANCE("dup2() failed for stdout"));
00154                         std::cerr << e << std::endl;
00155                         exit(127);
00156                 }
00157                 close(m_fd2[1]);
00158         }
00159         if (m_fd3[1] != STDERR_FILENO) {
00160                 if (dup2(m_fd3[1], STDERR_FILENO) != STDERR_FILENO) {
00161                         error e(errno,ERROR_INSTANCE("dup2() failed for stderr"));
00162                         std::cerr << e << std::endl;
00163                         exit(127);
00164                 }
00165                 close(m_fd3[1]);
00166         }
00167 }
00168 
00169 /** Returns the child's PID */
00170 pid_t execute::child_pid(void)
00171 {
00172         return(m_pid);
00173 }
00174 
00175 /** Send a signal to the child */
00176 void execute::signal_child(int signal_no)
00177 {
00178         kill(m_pid, signal_no);
00179 }
00180 
00181 /** Send a HUP signal to the child */
00182 void execute::hup_child(void)
00183 {
00184         signal_child(SIGHUP);
00185 }
00186 
00187 /** Send a KILL signal to the child */
00188 void execute::kill_child(void)
00189 {
00190         signal_child(SIGKILL);
00191 }
00192 
00193 /** Wait for the child to exit */
00194 void execute::wait(void)
00195 {
00196         if (is_parent()) {
00197                 pid_t value;
00198                 value = waitpid(m_pid, &m_status, 0);
00199         }
00200 }
00201 
00202 /** Check the child's status */
00203 pid_t execute::check_child_(void)
00204 {
00205         pid_t value;
00206         
00207         errno = 0;
00208         value = waitpid(m_pid, &m_status, WNOHANG|WUNTRACED);
00209 
00210         return(value);
00211 }
00212 
00213 /** Returns true if the child has been started */
00214 bool execute::child_started(void) const
00215 {
00216         return(m_child_started);
00217 }
00218 
00219 /** Returns true if the child is running */
00220 bool execute::child_running(void)
00221 {
00222         pid_t pid;
00223         
00224         pid = check_child_();
00225         if (pid > 0) return(false); // The child has exited
00226         if ((pid < 0) && (errno == ECHILD)) return(false); // No such child exists
00227         return(true);
00228 }
00229 
00230 /** Returns true of the child has existed */
00231 bool execute::child_exited(void)
00232 {
00233         pid_t pid;
00234 
00235         pid = check_child_();
00236         if (pid > 0) return(true);
00237         if ((pid < 0) && (errno == ECHILD)) return(true);
00238         return(false);
00239 }
00240 
00241 /** Returns true if the child has exited normally */
00242 bool execute::child_exited_normally(void)
00243 {
00244         bool value;
00245 
00246         value = (child_exited() && (child_exit_code() == 0));
00247 
00248         return(value);
00249 }
00250 
00251 /** Returns true if the child was signaled */
00252 bool execute::child_signaled(void)
00253 {
00254         bool value;
00255 
00256         check_child_();
00257         value = WIFSIGNALED(m_status);
00258 
00259         return(value);
00260 }
00261 
00262 /** Returns true if the child returned exit code 0 and no caught signals */
00263 bool execute::child_exited_success(void)
00264 {
00265         bool value;
00266 
00267         value = (child_exited() && (child_exit_code() == 0) && !child_signaled());
00268 
00269         return(value);
00270 }
00271 
00272 /** Return the child's exit code */
00273 int execute::child_exit_code(void)
00274 {
00275         int value;
00276 
00277         check_child_();
00278         value = WEXITSTATUS(m_status);
00279 
00280         return(value);
00281 }
00282 
00283 /** If the child was signaled, return the signal number */
00284 int execute::child_signal_no(void)
00285 {
00286         int value;
00287 
00288         check_child_();
00289         if (child_exited()) {
00290                 value = WTERMSIG(m_status);
00291                 return(value);
00292         }
00293         else {
00294                 value = WSTOPSIG(m_status);
00295                 return(value);
00296         }
00297 }
00298 
00299 /** Return a file descriptor for I/O between parent and child
00300 
00301         If called by the parent, a writeable file descriptor is returned.
00302         If called by the child, a readable file descriptor is returned.
00303 
00304         If retroute_stdio() was called by the child, then the returned file
00305         descriptor is the same as that used by the child for stdin.
00306  */
00307 int execute::in_fd(void)
00308 {
00309         if (is_parent()) {
00310                 // Return write end of input pipe
00311                 return(m_fd1[1]);
00312         }
00313         else {
00314                 // Return read end of input pipe
00315                 return(m_fd1[0]); 
00316         }
00317 }
00318 
00319 /** Return a file descriptor for I/O between parent a child.
00320 
00321         If called by the parent, a readable file descriptor is returned.
00322         If called by the child, a writable file descriptor is returned.
00323 
00324         If reroute_stdio() was called by the child, then the returned file
00325         descriptor is the same as that used by the child for stdout.
00326  */
00327 int execute::out_fd(void)
00328 {
00329         if (is_parent()) {
00330                 // Return read end of output pipe
00331                 return(m_fd2[0]);
00332         }
00333         else {
00334                 // Return write end of output pipe
00335                 return(m_fd2[1]);
00336         }
00337 }
00338 
00339 /** Return a file descriptor for I/O between parent and child.
00340 
00341         If called by the parent, a readable file descriptor is returned.
00342         If called by the child, a writeable file descriptor is returned.
00343 
00344         If reroute_stdio() was called by the child, then the returned file
00345         descriptior is the same as that used by the child for stderr.
00346  */
00347 int execute::err_fd(void)
00348 {
00349         if (is_parent()) {
00350                 // return read end of error pipe
00351                 return(m_fd3[0]); 
00352         }
00353         else {
00354                 // return write end of error pipe
00355                 return(m_fd3[1]); 
00356         }
00357 }
00358 
00359 /** Return true if the file descriptor is ready to be written to */
00360 bool execute::check_write_ready_(int fd)
00361 {
00362         struct timeval timeout = { 0, 0 };
00363         fd_set wset;
00364 
00365         FD_ZERO(&wset);
00366         FD_SET(fd, &wset);
00367         select(fd+1, 0, &wset, 0, &timeout);
00368         if (FD_ISSET(fd, &wset)) {
00369                 return(true);
00370         }
00371         return(false);
00372 }
00373 
00374 /** Return true if the file descriptor has input ready to be read */
00375 bool execute::check_read_ready_(int fd)
00376 {
00377         struct timeval timeout = { 0, 0 };
00378         fd_set rset;
00379 
00380         FD_ZERO(&rset);
00381         FD_SET(fd, &rset);
00382         select(fd+1, &rset, 0, 0, &timeout);
00383         if (FD_ISSET(fd, &rset)) {
00384                 return(true);
00385         }
00386         return(false);
00387 }
00388 
00389 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
00390 void execute::exec(const std::string command)
00391 {
00392         fork();
00393         if (is_parent())
00394                 return;
00395 
00396         /*
00397         {
00398                 bool wait_for_debugger = true;
00399 
00400                 std::cerr << "Waiting for debugger to attach..." << std::endl;
00401                 while (wait_for_debugger);
00402                 std::cerr << "Debugger attached." << std::endl;
00403         }
00404         */
00405         reroute_stdio();
00406         
00407         execl("/bin/sh", "sh", "-c", command.c_str(), (char *)0);
00408         exit(127);
00409 }
00410 
00411 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
00412 void execute::exec(const std::string binary, const std::vector<std::string> argv)
00413 {
00414         char *bin = 0;
00415         char *base = 0;
00416         char **args = 0;
00417         uint16 c;
00418         size_t size;
00419 
00420         fork();
00421         if (is_parent())
00422                 return;
00423         
00424         /*
00425         {
00426                 bool wait_for_debugger = true;
00427 
00428                 std::cerr << "Waiting for debugger to attach..." << std::endl;
00429                 while (wait_for_debugger);
00430                 std::cerr << "Debugger attached." << std::endl;
00431         }
00432         */
00433 
00434         reroute_stdio();
00435 
00436         bin = (char *)binary.c_str();
00437         base = bin+strlen(bin);
00438         while ((base > bin) && (*base != '/')) {
00439                 base--;
00440         }
00441         if (*base == '/') {
00442                 base++;
00443         }
00444         size = (argv.size() + 2) * sizeof(char *);
00445         args = (char **)malloc(size);
00446         memset((void *)args, 0, size);
00447         if (args == 0) {
00448                 exit(127);
00449         }
00450         args[0] = base;
00451         for (c = 0; c < argv.size(); c++) {
00452                 args[c+1] = (char *)argv[c].c_str();
00453         }
00454         args[c+1] = 0;
00455 
00456         execv(bin, args);
00457         exit(127);
00458 }
00459 
00460 /** Check I/O for input
00461 
00462         If called by the parent, check if ready to write to child's input.
00463         If called by the child, check if input is ready to be read.
00464 
00465         If reroute_stdio() was called by the child, then this pipe is the same as
00466         used by the child for stdin.
00467  */
00468 bool execute::in_ready(void)
00469 {
00470         bool value;
00471 
00472         if (is_parent())
00473                 value = check_write_ready_(in_fd());
00474         else
00475                 value = check_read_ready_(in_fd());
00476         
00477         return(value);
00478 }
00479 
00480 /** Check I/O for output
00481 
00482         If called by the parent, check if output from child is ready to be read.
00483         If called by the child, check if output to parent is ready to be written to.
00484 
00485         If reroute_stdio() was called by the child, then this pipe is the same as
00486         used by the child for stdout.
00487  */
00488 bool execute::out_ready(void)
00489 {
00490         bool value;
00491 
00492         if (is_parent())
00493                 value = check_read_ready_(out_fd());
00494         else
00495                 value = check_write_ready_(out_fd());
00496         
00497         return(value);
00498 }
00499 
00500 /** Check I/O for output
00501 
00502         If called by the parent, check if output from child is ready to be read.
00503         If called by the child, check if output to parent is ready to be written to.
00504 
00505         If reroute_stdio() was called by the child, then this pipe is the same as
00506         used by the child for stderr.
00507  */
00508 bool execute::err_ready(void)
00509 {
00510         bool value;
00511 
00512         if (is_parent())
00513                 value = check_read_ready_(err_fd());
00514         else
00515                 value = check_write_ready_(err_fd());
00516         
00517         return(value);
00518 }
00519 
00520 /** Check for input EOF */
00521 bool execute::in_eof(void)
00522 {
00523         return(m_in_eof);
00524 }
00525 
00526 /** Check for output EOF */
00527 bool execute::out_eof(void)
00528 {
00529         return(m_out_eof);
00530 }
00531 
00532 /** Check for err EOF */
00533 bool execute::err_eof(void)
00534 {
00535         return(m_err_eof);
00536 }
00537 
00538 /** Allow child to read input from in_fd() */
00539 int execute::in_read(char* buf, const int len)
00540 {
00541         int n;
00542         int err;
00543 
00544         n = read(in_fd(), buf, len);
00545         err = errno;
00546         errno = 0;
00547         if (n > 0) {
00548                 return(n);
00549         }
00550         if (child_started() && !child_running() && (err != EAGAIN))
00551                 m_in_eof = true;
00552         return(0);
00553 }
00554 
00555 /** Allow parent to write output to in_fd() */
00556 int execute::in_write(const char* buf, const int len)
00557 {
00558         int n;
00559         int err;
00560 
00561         n = write(in_fd(), buf, len);
00562         err = errno;
00563         errno = 0;
00564         if (n > 0) {
00565                 return(n);
00566         }
00567         if (child_started() && !child_running() && (err != EAGAIN))
00568                 m_in_eof = true;
00569         return(0);
00570 }
00571 
00572 /** Allow parent to read out_fd() */
00573 int execute::out_read(char* buf, const int len)
00574 {
00575         int n;
00576         int err;
00577 
00578         n = read(out_fd(), buf, len);
00579         err = errno;
00580         errno = 0;
00581         if (n > 0) {
00582                 return(n);
00583         }
00584         if (child_started() && !child_running() && (err != EAGAIN))
00585                 m_out_eof = true;
00586         return(0);
00587 }
00588 
00589 /** Allow child to write to out_fd() */
00590 int execute::out_write(const char* buf, const int len)
00591 {
00592         int n;
00593         int err;
00594 
00595         n = write(out_fd(), buf, len);
00596         err = errno;
00597         errno = 0;
00598         if (n > 0) {
00599                 return(n);
00600         }
00601         if (child_started() && !child_running() && (err != EAGAIN))
00602                 m_out_eof = true;
00603         return(0);
00604 }
00605 
00606 /** Allow parent to read from err_fd() */
00607 int execute::err_read(char* buf, const int len)
00608 {
00609         int n;
00610         int err;
00611 
00612         n = read(err_fd(), buf, len);
00613         err = errno;
00614         errno = 0;
00615         if (n > 0) {
00616                 return(n);
00617         }
00618         if (child_started() && !child_running() && (err != EAGAIN))
00619                 m_err_eof = true;
00620         return(0);
00621 }
00622 
00623 /** Allow child to write to err_fd() */
00624 int execute::err_write(const char* buf, const int len)
00625 {
00626         int n;
00627         int err;
00628 
00629         n = write(err_fd(), buf, len);
00630         err = errno;
00631         errno = 0;
00632         if (n > 0) {
00633                 return(n);
00634         }
00635         if (child_started() && !child_running() && (err != EAGAIN))
00636                 m_err_eof = true;
00637         return(0);
00638 }
00639 
00640 /** Dump execute object information -- used for debugging */
00641 void execute::print(std::ostream& out)
00642 {
00643         out << "execute::is_child() = " << is_child() << std::endl;
00644         out << "execute::is_parent() = " << is_parent() << std::endl;
00645         out << "execute::my_pid() = " << my_pid() << std::endl;
00646         out << "execute::child_running() = " << child_running() << std::endl;
00647         out << "execute::child_exited() = " << child_exited() << std::endl;
00648         out << "execute::child_exited_normally() = " << child_exited_normally() 
00649                 << std::endl;
00650         out << "execute::child_exited_success() = " << child_exited_success() 
00651                 << std::endl;
00652         out << "execute::child_signaled() = " << child_signaled() << std::endl;
00653         out << "execute::child_exit_code() = " << child_exit_code() << std::endl;
00654         out << "execute::child_signal_no() = " << child_signal_no() << std::endl;
00655         out << "execute::in_fd() = " << in_fd() << std::endl;
00656         out << "execute::out_fd() = " << out_fd() << std::endl;
00657         out << "execute::err_fd() = " << err_fd() << std::endl;
00658         out << "execute::in_ready() = " << in_ready() << std::endl;
00659         out << "execute::out_ready() = " << out_ready() << std::endl;
00660         out << "execute::err_ready() = " << err_ready() << std::endl;
00661 }
00662 
00663 /** Convenience function to call execute::print() */
00664 std::ostream& operator << (std::ostream& out, execute& exe)
00665 {
00666         exe.print(out);
00667 
00668         return(out);
00669 }
00670 
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Defines