00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013 #include <iostream>
00014 #include <fcntl.h>
00015 #include <syslog.h>
00016
00017 #include "assa/Fork.h"
00018 #include "assa/CmdLineOpts.h"
00019 #include "assa/SigAction.h"
00020 #include "assa/EventHandler.h"
00021 #include "assa/SigHandler.h"
00022
00023 using namespace ASSA;
00024
00025
00026
00027
00028 ASSA_DECL_SINGLETON(ForkList);
00029
00030
00031
00032
00033
00034 int
00035 ChildStatusHandler::
00036 handle_signal (int signum_)
00037 {
00038 trace_with_mask("ChildStatusHandler::handle_signal", FORK);
00039 DL((FORK, "Caught signal # %d\n", signum_));
00040
00041 if (signum_ == SIGCHLD) {
00042 int status;
00043 m_caught = true;
00044 pid_t ret = ::wait (&status);
00045 DL((FORK,"wait() = %d (PID)\n", ret));
00046
00047 if (ret > 0 && (WIFEXITED (status))) {
00048 m_exit_status = WEXITSTATUS (status);
00049 }
00050 else {
00051 m_exit_status = ret;
00052 }
00053 }
00054 DL((FORK,"child exit_status = %d\n", m_exit_status));
00055 return 0;
00056 }
00057
00058
00059 Fork::
00060 Fork (Fork::state_t state_, Fork::wait4status_t catch_status_)
00061 {
00062 trace_with_mask("Fork::Fork",FORK);
00063
00064 if (catch_status_ == COLLECT_STATUS) {
00065 m_local_sh.install (SIGCHLD, &m_chstath, 0, 0, &m_old_disp);
00066 }
00067
00068 if ((m_pid = fork()) < 0) {
00069 EL((ERROR,"failed to fork() - out of swap space?\n"));
00070 exit (1);
00071 }
00072
00073 if (m_pid) {
00074 if (state_ != LEAVE_ALONE) {
00075 ForkList::get_instance()->
00076 m_list.push_back (new fnode_t (m_pid, state_));
00077 }
00078 if (catch_status_ == COLLECT_STATUS) {
00079 if (! m_chstath.caught ()) {
00080 pause ();
00081 }
00082 m_local_sh.remove (SIGCHLD, &m_chstath, &m_old_disp, 0);
00083 }
00084 }
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106
00107
00108
00109
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119
00120 int
00121 Fork::
00122 fork_exec (const string& cmd_,
00123 const string& args_,
00124 Fork::wait4status_t wait_for_completion_,
00125 bool ignore_output_)
00126 {
00127 trace_with_mask("Fork[static]::fork_exec",FORK);
00128
00129 DL((FORK,"exec \"%s %s\")\n", cmd_.c_str (), args_.c_str ()));
00130 if (cmd_.size () == 0) {
00131 return -1;
00132 }
00133
00134 Fork f (Fork::LEAVE_ALONE, wait_for_completion_);
00135
00136 if (f.isChild ()) {
00137 string arg_list (cmd_);
00138 arg_list += " " + args_;
00139 int argc = 0;
00140 char** argv = 0;
00141 CmdLineOpts::str_to_argv (arg_list, argc, argv);
00142
00146 if (ignore_output_) {
00147 for (int i = 0; i < 1024; i++) {
00148 (void) close(i);
00149 }
00150 pid_t nullfd = open("/dev/null", O_WRONLY | O_CREAT, 0666);
00151 if (nullfd == -1) {
00152 syslog (LOG_ERR,"failed to open \"/dev/null\"");
00153 _exit (-1);
00154 }
00155
00156 (void) dup2 (nullfd, 1);
00157 (void) dup2 (nullfd, 2);
00158 (void) close (nullfd);
00159 }
00160
00161 execvp (cmd_.c_str (), argv);
00162
00163 EL((ERROR,"fork_exec (\"%s\") failed\n", cmd_.c_str ()));
00164 _exit (-1);
00165 }
00166
00167 if (! wait_for_completion_) {
00168 return f.getChildPID ();
00169 }
00170
00171 return f.get_exit_status ();
00172 }
00173
00174 ForkList::
00175 ~ForkList()
00176 {
00177 trace_with_mask("ForkList::~ForkList",FORK);
00178
00179 list<fnode_t* >::iterator i;
00180 pid_t pid;
00181
00182
00183
00184
00185 for (i = m_list.begin(); i != m_list.end(); i++) {
00186 if ((*i)->needKill()) {
00187 ::kill((*i)->getPID(), SIGTERM);
00188 }
00189 }
00190
00191
00192 while ( ! m_list.empty() ) {
00193 pid = ::wait(NULL);
00194 if ( pid < 0 ) {
00195 EL((ERROR,"Error on wait()\n"));
00196 exit (EXIT_FAILURE);
00197 }
00198
00199
00200
00201 list<fnode_t* >::iterator j;
00202
00203 for (j = m_list.begin(); j != m_list.end(); j++) {
00204 if ((*j)->getPID() == pid) {
00205 fnode_t* ep = *j;
00206 m_list.erase(j);
00207 delete ep;
00208 break;
00209 }
00210 }
00211 }
00212 }
00213