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 		::wait(&m_status);
00198 }
00199 
00200 /** Check the child's status */
00201 pid_t execute::check_child_(void)
00202 {
00203         pid_t value;
00204         
00205         value = waitpid(m_pid, &m_status, WNOHANG|WUNTRACED);
00206 
00207         return(value);
00208 }
00209 
00210 /** Returns true if the child has been started */
00211 bool execute::child_started(void) const
00212 {
00213         return(m_child_started);
00214 }
00215 
00216 /** Returns true if the child is running */
00217 bool execute::child_running(void)
00218 {
00219         bool value;
00220 
00221         // value = (check_child_() == 0); // Should this be != -1 instead?
00222         value = (check_child_() != -1);
00223 
00224         return(value);
00225 }
00226 
00227 /** Returns true of the child has existed */
00228 bool execute::child_exited(void)
00229 {
00230         bool value;
00231 
00232         value = (check_child_() == -1);
00233 
00234         return(value);
00235 }
00236 
00237 /** Returns true if the child has exited normally */
00238 bool execute::child_exited_normally(void)
00239 {
00240         bool value;
00241 
00242         // TODO: Something's screwy here...
00243         // value = (child_exited() && WIFEXITED(m_status));
00244         value = (child_exited() && (child_exit_code() == 0));
00245 
00246         return(value);
00247 }
00248 
00249 /** Returns true if the child was signaled */
00250 bool execute::child_signaled(void)
00251 {
00252         bool value;
00253 
00254         check_child_();
00255         value = WIFSIGNALED(m_status);
00256 
00257         return(value);
00258 }
00259 
00260 /** Return the child's exit code */
00261 int execute::child_exit_code(void)
00262 {
00263         int value;
00264 
00265         // TODO: Something's screwy here...
00266         check_child_();
00267         value = WEXITSTATUS(m_status);
00268 
00269         return(value);
00270 }
00271 
00272 /** If the child was signaled, return the signal number */
00273 int execute::child_signal_no(void)
00274 {
00275         int value;
00276 
00277         check_child_();
00278         if (child_exited()) {
00279                 value = WTERMSIG(m_status);
00280                 return(value);
00281         }
00282         else {
00283                 value = WSTOPSIG(m_status);
00284                 return(value);
00285         }
00286 }
00287 
00288 /** Return a file descriptor for I/O between parent and child
00289 
00290         If called by the parent, a writeable file descriptor is returned.
00291         If called by the child, a readable file descriptor is returned.
00292 
00293         If retroute_stdio() was called by the child, then the returned file
00294         descriptor is the same as that used by the child for stdin.
00295  */
00296 int execute::in_fd(void)
00297 {
00298         if (is_parent()) {
00299                 // Return write end of input pipe
00300                 return(m_fd1[1]);
00301         }
00302         else {
00303                 // Return read end of input pipe
00304                 return(m_fd1[0]); 
00305         }
00306 }
00307 
00308 /** Return a file descriptor for I/O between parent a child.
00309 
00310         If called by the parent, a readable file descriptor is returned.
00311         If called by the child, a writable file descriptor is returned.
00312 
00313         If reroute_stdio() was called by the child, then the returned file
00314         descriptor is the same as that used by the child for stdout.
00315  */
00316 int execute::out_fd(void)
00317 {
00318         if (is_parent()) {
00319                 // Return read end of output pipe
00320                 return(m_fd2[0]);
00321         }
00322         else {
00323                 // Return write end of output pipe
00324                 return(m_fd2[1]);
00325         }
00326 }
00327 
00328 /** Return a file descriptor for I/O between parent and child.
00329 
00330         If called by the parent, a readable file descriptor is returned.
00331         If called by the child, a writeable file descriptor is returned.
00332 
00333         If reroute_stdio() was called by the child, then the returned file
00334         descriptior is the same as that used by the child for stderr.
00335  */
00336 int execute::err_fd(void)
00337 {
00338         if (is_parent()) {
00339                 // return read end of error pipe
00340                 return(m_fd3[0]); 
00341         }
00342         else {
00343                 // return write end of error pipe
00344                 return(m_fd3[1]); 
00345         }
00346 }
00347 
00348 /** Return true if the file descriptor is ready to be written to */
00349 bool execute::check_write_ready_(int fd)
00350 {
00351         struct timeval timeout = { 0, 0 };
00352         fd_set wset;
00353 
00354         FD_ZERO(&wset);
00355         FD_SET(fd, &wset);
00356         select(fd+1, 0, &wset, 0, &timeout);
00357         if (FD_ISSET(fd, &wset)) {
00358                 return(true);
00359         }
00360         return(false);
00361 }
00362 
00363 /** Return true if the file descriptor has input ready to be read */
00364 bool execute::check_read_ready_(int fd)
00365 {
00366         struct timeval timeout = { 0, 0 };
00367         fd_set rset;
00368 
00369         FD_ZERO(&rset);
00370         FD_SET(fd, &rset);
00371         select(fd+1, &rset, 0, 0, &timeout);
00372         if (FD_ISSET(fd, &rset)) {
00373                 return(true);
00374         }
00375         return(false);
00376 }
00377 
00378 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
00379 void execute::exec(const std::string command)
00380 {
00381         fork();
00382         if (is_parent())
00383                 return;
00384 
00385         /*
00386         {
00387                 bool wait_for_debugger = true;
00388 
00389                 std::cerr << "Waiting for debugger to attach..." << std::endl;
00390                 while (wait_for_debugger);
00391                 std::cerr << "Debugger attached." << std::endl;
00392         }
00393         */
00394         reroute_stdio();
00395         
00396         execl("/bin/sh", "sh", "-c", command.c_str(), (char *)0);
00397         exit(127);
00398 }
00399 
00400 /** Execute a command, rerouting stdin, stdout, and stderr to parent */
00401 void execute::exec(const std::string binary, const std::vector<std::string> argv)
00402 {
00403         char *bin = 0;
00404         char *base = 0;
00405         char **args = 0;
00406         uint16 c;
00407         size_t size;
00408 
00409         fork();
00410         if (is_parent())
00411                 return;
00412         
00413         /*
00414         {
00415                 bool wait_for_debugger = true;
00416 
00417                 std::cerr << "Waiting for debugger to attach..." << std::endl;
00418                 while (wait_for_debugger);
00419                 std::cerr << "Debugger attached." << std::endl;
00420         }
00421         */
00422 
00423         reroute_stdio();
00424 
00425         bin = (char *)binary.c_str();
00426         base = bin+strlen(bin);
00427         while ((base > bin) && (*base != '/')) {
00428                 base--;
00429         }
00430         if (*base == '/') {
00431                 base++;
00432         }
00433         size = (argv.size() + 2) * sizeof(char *);
00434         args = (char **)malloc(size);
00435         memset((void *)args, 0, size);
00436         if (args == 0) {
00437                 exit(127);
00438         }
00439         args[0] = base;
00440         for (c = 0; c < argv.size(); c++) {
00441                 args[c+1] = (char *)argv[c].c_str();
00442         }
00443         args[c+1] = 0;
00444 
00445         execv(bin, args);
00446         exit(127);
00447 }
00448 
00449 /** Check I/O for input
00450 
00451         If called by the parent, check if ready to write to child's input.
00452         If called by the child, check if input is ready to be read.
00453 
00454         If reroute_stdio() was called by the child, then this pipe is the same as
00455         used by the child for stdin.
00456  */
00457 bool execute::in_ready(void)
00458 {
00459         bool value;
00460 
00461         if (is_parent())
00462                 value = check_write_ready_(in_fd());
00463         else
00464                 value = check_read_ready_(in_fd());
00465         
00466         return(value);
00467 }
00468 
00469 /** Check I/O for output
00470 
00471         If called by the parent, check if output from child is ready to be read.
00472         If called by the child, check if output to parent is ready to be written to.
00473 
00474         If reroute_stdio() was called by the child, then this pipe is the same as
00475         used by the child for stdout.
00476  */
00477 bool execute::out_ready(void)
00478 {
00479         bool value;
00480 
00481         if (is_parent())
00482                 value = check_read_ready_(out_fd());
00483         else
00484                 value = check_write_ready_(out_fd());
00485         
00486         return(value);
00487 }
00488 
00489 /** Check I/O for output
00490 
00491         If called by the parent, check if output from child is ready to be read.
00492         If called by the child, check if output to parent is ready to be written to.
00493 
00494         If reroute_stdio() was called by the child, then this pipe is the same as
00495         used by the child for stderr.
00496  */
00497 bool execute::err_ready(void)
00498 {
00499         bool value;
00500 
00501         if (is_parent())
00502                 value = check_read_ready_(err_fd());
00503         else
00504                 value = check_write_ready_(err_fd());
00505         
00506         return(value);
00507 }
00508 
00509 /** Check for input EOF */
00510 bool execute::in_eof(void)
00511 {
00512         return(m_in_eof);
00513 }
00514 
00515 /** Check for output EOF */
00516 bool execute::out_eof(void)
00517 {
00518         return(m_out_eof);
00519 }
00520 
00521 /** Check for err EOF */
00522 bool execute::err_eof(void)
00523 {
00524         return(m_err_eof);
00525 }
00526 
00527 /** Allow child to read input from in_fd() */
00528 int execute::in_read(char* buf, const int len)
00529 {
00530         int n;
00531         int err;
00532 
00533         n = read(in_fd(), buf, len);
00534         err = errno;
00535         errno = 0;
00536         if (n > 0) {
00537                 return(n);
00538         }
00539         if (child_started() && !child_running() && (err != EAGAIN))
00540                 m_in_eof = true;
00541         return(0);
00542 }
00543 
00544 /** Allow parent to write output to in_fd() */
00545 int execute::in_write(const char* buf, const int len)
00546 {
00547         int n;
00548         int err;
00549 
00550         n = write(in_fd(), buf, len);
00551         err = errno;
00552         errno = 0;
00553         if (n > 0) {
00554                 return(n);
00555         }
00556         if (child_started() && !child_running() && (err != EAGAIN))
00557                 m_in_eof = true;
00558         return(0);
00559 }
00560 
00561 /** Allow parent to read out_fd() */
00562 int execute::out_read(char* buf, const int len)
00563 {
00564         int n;
00565         int err;
00566 
00567         n = read(out_fd(), buf, len);
00568         err = errno;
00569         errno = 0;
00570         if (n > 0) {
00571                 return(n);
00572         }
00573         if (child_started() && !child_running() && (err != EAGAIN))
00574                 m_out_eof = true;
00575         return(0);
00576 }
00577 
00578 /** Allow child to write to out_fd() */
00579 int execute::out_write(const char* buf, const int len)
00580 {
00581         int n;
00582         int err;
00583 
00584         n = write(out_fd(), buf, len);
00585         err = errno;
00586         errno = 0;
00587         if (n > 0) {
00588                 return(n);
00589         }
00590         if (child_started() && !child_running() && (err != EAGAIN))
00591                 m_out_eof = true;
00592         return(0);
00593 }
00594 
00595 /** Allow parent to read from err_fd() */
00596 int execute::err_read(char* buf, const int len)
00597 {
00598         int n;
00599         int err;
00600 
00601         n = read(err_fd(), buf, len);
00602         err = errno;
00603         errno = 0;
00604         if (n > 0) {
00605                 return(n);
00606         }
00607         if (child_started() && !child_running() && (err != EAGAIN))
00608                 m_err_eof = true;
00609         return(0);
00610 }
00611 
00612 /** Allow child to write to err_fd() */
00613 int execute::err_write(const char* buf, const int len)
00614 {
00615         int n;
00616         int err;
00617 
00618         n = write(err_fd(), buf, len);
00619         err = errno;
00620         errno = 0;
00621         if (n > 0) {
00622                 return(n);
00623         }
00624         if (child_started() && !child_running() && (err != EAGAIN))
00625                 m_err_eof = true;
00626         return(0);
00627 }
00628 
00629 /** Dump execute object information -- used for debugging */
00630 void execute::print(std::ostream& out)
00631 {
00632         out << "execute::is_child() = " << is_child() << std::endl;
00633         out << "execute::is_parent() = " << is_parent() << std::endl;
00634         out << "execute::my_pid() = " << my_pid() << std::endl;
00635         out << "execute::child_running() = " << child_running() << std::endl;
00636         out << "execute::child_exited() = " << child_exited() << std::endl;
00637         out << "execute::child_exited_normally() = " << child_exited_normally() 
00638                 << std::endl;
00639         out << "execute::child_signaled() = " << child_signaled() << std::endl;
00640         out << "execute::child_exit_code() = " << child_exit_code() << std::endl;
00641         out << "execute::child_signal_no() = " << child_signal_no() << std::endl;
00642         out << "execute::in_fd() = " << in_fd() << std::endl;
00643         out << "execute::out_fd() = " << out_fd() << std::endl;
00644         out << "execute::err_fd() = " << err_fd() << std::endl;
00645         out << "execute::in_ready() = " << in_ready() << std::endl;
00646         out << "execute::out_ready() = " << out_ready() << std::endl;
00647         out << "execute::err_ready() = " << err_ready() << std::endl;
00648 }
00649 
00650 /** Convenience function to call execute::print() */
00651 std::ostream& operator << (std::ostream& out, execute& exe)
00652 {
00653         exe.print(out);
00654 
00655         return(out);
00656 }
00657 

Generated on Thu Jun 5 11:12:56 2008 for rvm by  doxygen 1.5.1