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