#ifdef WIN32 # define _WINSOCKAPI_ # include #else # include # include # include # include # include # include #endif #include "uexec.h" #define PIPE_BUF_SIZE 2048 void uexec::main() { char buf[PIPE_BUF_SIZE]; status = -1; // determine input and output file handles for the child // and also their pipe peer handles, if any. if a stream // is not handle-based, create local pipes and pass their // handles to the child process. compref save_in; compref temp_out; int in_peer = invhandle; int child_in = uin->get_handle(); if (child_in == invhandle) { save_in = uin; infile* inf = new infile(); inf->set_bufsize(0); uin = inf; outfile* outf = new outfile(); outf->set_bufsize(0); temp_out = outf; inf->pipe(*outf); child_in = uin->get_handle(); } if ((uin->classid() & 0xffff) == CLASS_INFILE) in_peer = ((infile*)(instm*)uin)->get_peerhandle(); compref save_out; compref temp_in; int out_peer = invhandle; int child_out = uout->get_handle(); if (child_out == invhandle) { save_out = uout; outfile* f = new outfile(); f->set_bufsize(0); uout = f; temp_in = new infile(); temp_in->set_bufsize(0); temp_in->pipe(*f); child_out = uout->get_handle(); } if ((uout->classid() & 0xffff) == CLASS_OUTFILE) out_peer = ((outfile*)(outstm*)uout)->get_peerhandle(); #ifdef WIN32 STARTUPINFO si; ZeroMemory(&si, sizeof(si)); si.cb = sizeof(si); si.dwFlags = STARTF_USESTDHANDLES; si.hStdInput = (HANDLE)child_in; si.hStdOutput = (HANDLE)child_out; si.hStdError = (HANDLE)perr.get_handle(); // build the argument string string args = program; for (int i = 0; i < alength(params); i++) args += ' ' + string(aget(params, i)); PROCESS_INFORMATION pi; if (!CreateProcess(program, unique(args), 0, 0, true, 0, 0, 0, &si, &pi)) throw new exception("Couldn't run '" + program + '\''); #else // unix fork() mess. nothing to stare at, move along, move along... int child_pid = fork(); if (child_pid == -1) throw new exception("fork() failed"); else if (child_pid == 0) // child process { close(0); // close stdin if (in_peer != invhandle) // close input pipe's peer handle, because it's only a duplicate here close(in_peer); dup2(child_in, 0); // 'map' input handle to stdin close(child_in); // ... and close it too close(1); // same for stdout if (out_peer != invhandle) close(out_peer); dup2(child_out, 1); close(child_out); // build the parameter array char** args = (char**)memalloc(alength(params) + 2); args[0] = unique(program); int i; for (i = 1; i <= alength(params); i++) initialize(PTR_TO_STRING(args[i]), string(aget(params, i - 1))); args[i] = nil; execv(program, args); perr.putline("Couldn't run '" + program + '\''); exit(255); } #endif // close descriptors passed to the child for pipes // to be able to shutdown properly if (out_peer != invhandle) uout->close(); if (in_peer != invhandle) uin->close(); while (temp_in != nil || temp_out != nil) { if (temp_out != nil) { int r = save_in->read(buf, sizeof(buf)); if (r > 0) { temp_out->write(buf, r); if (save_in->get_eof()) temp_out = nil; } else temp_out = nil; // automatically closes the stream } if (temp_in != nil) { int r = temp_in->read(buf, sizeof(buf)); if (r > 0) save_out->write(buf, r); else temp_in = nil; // automatically closes the stream } } #ifdef WIN32 if (pi.hProcess != INVALID_HANDLE_VALUE) { WaitForSingleObject(pi.hProcess, INFINITE); unsigned long ret; GetExitCodeProcess(pi.hProcess, &ret); if (ret != STILL_ACTIVE) status = ret; CloseHandle(pi.hThread); CloseHandle(pi.hProcess); pi.hProcess = INVALID_HANDLE_VALUE; #else if (child_pid != -1) { waitpid(child_pid, &status, 0); child_pid = -1; #endif } // restore in/out streams if they were non-handle-based if (save_in != nil) { uin = save_in; save_in = nil; } if (save_out != nil) { uout = save_out; save_out = nil; } }