00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027 #include "PipeProcess.h"
00028
00029 #ifdef WIN32
00030 #include <windows.h>
00031 #include <process.h>
00032 #include <sys/types.h>
00033 #include <sys/stat.h>
00034 #include <fcntl.h>
00035 #include <stdio.h>
00036 typedef int ssize_t;
00037 typedef HANDLE fd_t;
00038 typedef SOCKET socket_t;
00039 #else
00040 #include <sys/types.h>
00041 #include <sys/stat.h>
00042 #include <fcntl.h>
00043 #include <sys/wait.h>
00044 #include <unistd.h>
00045 #include <sys/socket.h>
00046 #include <netinet/in.h>
00047 #include <netdb.h>
00048 typedef int fd_t;
00049 typedef int socket_t;
00050 #endif
00051
00052 #include <cstring>
00053 #include <iostream>
00054 #include <sstream>
00055
00056 #define BUFSIZE (64*1024-1)
00057 #define STEPSIZE (1024)
00058
00059
00060 namespace sofa
00061 {
00062
00063 namespace helper
00064 {
00065
00066 namespace system
00067 {
00068
00069 PipeProcess::PipeProcess()
00070 {
00071 }
00072
00073 PipeProcess::~PipeProcess()
00074 {
00075 }
00081 bool PipeProcess::executeProcess(const std::string &command, const std::vector<std::string> &args, const std::string &filenameStdin, std::string & outString, std::string & errorString)
00082 {
00083 std::string fileIN = filenameStdin;
00084
00085
00086 fileIN = "";
00087
00088 fd_t fds[2][2];
00089
00090
00091 char** cargs;
00092 std::string newCommand(command);
00093
00094 cargs = new char* [args.size()+2];
00095 cargs[0] = (char*)command.c_str();
00096 for (unsigned int i=1 ; i< args.size() + 1 ; i++)
00097 cargs[i] = (char*)args[i-1].c_str();
00098 cargs[args.size() + 1] = NULL;
00099
00100 fd_t fdin;
00101 fd_t fdout;
00102 fd_t fderr;
00103
00104 #ifdef WIN32
00105 fdin = GetStdHandle(STD_INPUT_HANDLE);
00106
00107 fdout = GetStdHandle(STD_OUTPUT_HANDLE);
00108 fderr = GetStdHandle(STD_ERROR_HANDLE);
00109
00110 for (unsigned int i=0 ; i< args.size() ; i++)
00111 newCommand += " " + args[i];
00112
00113 #else
00114 fdin = 0;
00115 fdout = 1;
00116 fderr = 2;
00117 #endif
00118
00119 outString = "";
00120 errorString = "";
00121 std::stringstream outStream;
00122 std::stringstream errorStream;
00123
00124 #ifdef WIN32
00125 SECURITY_ATTRIBUTES saAttr;
00126
00127 saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
00128 saAttr.bInheritHandle = TRUE;
00129 saAttr.lpSecurityDescriptor = NULL;
00130 if (!CreatePipe(&fds[0][0],&fds[0][1],&saAttr,0) || !CreatePipe(&fds[1][0],&fds[1][1],&saAttr,0))
00131 #else
00132 if (pipe(fds[0]) || pipe(fds[1]))
00133 #endif
00134 {
00135 std::cerr << "pipe failed."<<std::endl;
00136 return false;
00137 }
00138 #ifdef WIN32
00139 HANDLE hFile = 0;
00140 if (fileIN != "")
00141 hFile = CreateFileA( (fileIN.c_str()),
00142 GENERIC_READ,
00143 FILE_SHARE_READ,
00144 NULL,
00145 OPEN_EXISTING,
00146 FILE_ATTRIBUTE_NORMAL,
00147 NULL);
00148
00149 if (hFile == INVALID_HANDLE_VALUE) {
00150 std::cerr<<"failed to open file for stdin\n";
00151 }
00152
00153
00154 SetHandleInformation( fds[0][0], HANDLE_FLAG_INHERIT, 0);
00155 SetHandleInformation( fds[1][0], HANDLE_FLAG_INHERIT, 0);
00156 SetHandleInformation( fdin, HANDLE_FLAG_INHERIT, 1);
00157 PROCESS_INFORMATION piProcInfo;
00158 STARTUPINFOA siStartInfo;
00159 ZeroMemory( &piProcInfo, sizeof(PROCESS_INFORMATION) );
00160 ZeroMemory( &siStartInfo, sizeof(STARTUPINFOA) );
00161 siStartInfo.cb = sizeof(STARTUPINFOA);
00162 if (fileIN != "")
00163 siStartInfo.hStdInput = hFile;
00164 else siStartInfo.hStdInput = fdin;
00165
00166 siStartInfo.hStdOutput = fds[0][1];
00167 siStartInfo.hStdError = fds[1][1];
00168 siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
00169 if (!CreateProcessA(NULL,
00170 (char*)newCommand.c_str(),
00171 NULL,
00172 NULL,
00173 TRUE,
00174 0,
00175 NULL,
00176 NULL,
00177 &siStartInfo,
00178 &piProcInfo))
00179 {
00180 std::cerr << "CreateProcess failed : "<<GetLastError()<<std::endl;
00181 return 1;
00182 }
00183
00184 {
00185
00186 char buf[2][BUFSIZE];
00187 int nfill[2];
00188 CloseHandle(fds[0][1]);
00189 CloseHandle(fds[1][1]);
00190 unsigned long exit = 0;
00191 for (int i=0;i<2;i++)
00192 nfill[i] = 0;
00193 for(int i=0;;i++)
00194 {
00195 GetExitCodeProcess(piProcInfo.hProcess,&exit);
00196 if (exit != STILL_ACTIVE)
00197 break;
00198
00199 bool busy = false;
00200 for (int i=0;i<2;i++)
00201 {
00202 DWORD n = BUFSIZE-nfill[i];
00203 if (n > STEPSIZE) n = STEPSIZE;
00204 DWORD bread = 0;
00205 DWORD avail = 0;
00206 PeekNamedPipe(fds[i][0],buf[i]+nfill[i],n,&bread,&avail,NULL);
00207
00208 if (bread>0)
00209 {
00210 busy = true;
00211 ReadFile(fds[i][0], buf[i]+nfill[i], n, &n, NULL);
00212 nfill[i] += n;
00213 {
00214
00215 if (i==0)
00216 outStream << std::string(buf[i],nfill[i]);
00217 else
00218 errorStream << std::string(buf[i],nfill[i]);
00219
00220
00221 nfill[i] = 0;
00222 }
00223 }
00224 }
00225 if (!busy)
00226 Sleep(0);
00227 }
00228 CloseHandle(fds[0][0]);
00229 CloseHandle(fds[1][0]);
00230 int status=exit;
00231 CloseHandle(piProcInfo.hProcess);
00232 CloseHandle(piProcInfo.hThread);
00233
00234 #else
00235 int filefd = 0;
00236 if (fileIN != "")
00237 filefd = open(fileIN.c_str(),O_RDONLY);
00238
00239 pid_t pid;
00240 pid = fork();
00241 if (pid < 0)
00242 {
00243 std::cerr << "fork failed."<<std::endl;
00244 return false;
00245 }
00246 else if (pid == 0)
00247 {
00248 close(fds[0][0]);
00249 close(fds[1][0]);
00250
00251 if (fileIN != "")
00252 dup2(filefd, 0);
00253 else dup2(open("/dev/null",O_RDONLY),0);
00254
00255 dup2(fds[0][1],1);
00256 dup2(fds[1][1],2);
00257
00258 int retexec = execvp(command.c_str(), cargs);
00259 std::cerr << "PipeProcess : ERROR: execlp( "<< command.c_str() << " " ;
00260 for (unsigned int i=0; i<args.size() + 1 ; i++)
00261 std::cerr << cargs[i] << " ";
00262 std::cerr << ") returned "<<retexec<<std::endl;
00263 return false;
00264 }
00265 else
00266 {
00267
00268 char buf[2][BUFSIZE];
00269 int nfill[2];
00270 close(fds[0][1]);
00271 close(fds[1][1]);
00272 fd_set rfds;
00273 int nfd = fdin+1;
00274 FD_ZERO(&rfds);
00275 FD_SET(fdin, &rfds);
00276 int nopen = 0;
00277 for (int i=0;i<2;i++)
00278 {
00279
00280 FD_SET(fds[i][0], &rfds);
00281 if (fds[i][0] >= nfd) nfd = fds[i][0]+1;
00282
00283
00284
00285 nfill[i] = 0;
00286 ++nopen;
00287 }
00288 fd_set ready;
00289 ready = rfds;
00290 while (nopen> 0 && select(nfd, &ready, NULL, NULL, NULL)> 0)
00291 {
00292
00293
00294
00295
00296
00297
00298
00299
00300
00301
00302
00303
00304
00305 for (int i=0;i<2;i++)
00306 {
00307 if (FD_ISSET(fds[i][0], &ready))
00308 {
00309 int n = BUFSIZE-nfill[i];
00310 if (n> STEPSIZE) n = STEPSIZE;
00311 n = read(fds[i][0], buf[i]+nfill[i], n);
00312
00313 if (n == 0)
00314 {
00315 if (nfill[i]> 1)
00316 {
00317 buf[i][nfill[i]] = '\n';
00318 if (i==0)
00319 outStream << std::string(buf[i],nfill[i]+1);
00320 else
00321 errorStream << std::string(buf[i],nfill[i]+1);
00322 }
00323 --nopen;
00324 FD_CLR(fds[i][0], &rfds);
00325 }
00326 else
00327 {
00328 nfill[i] += n;
00329
00330
00331 if (i==0)
00332 outStream << std::string(buf[i],nfill[i]);
00333 else
00334 errorStream << std::string(buf[i],nfill[i]);
00335
00336
00337 nfill[i] = 0;
00338 }
00339
00340 }
00341 }
00342 ready = rfds;
00343 }
00344 close(fds[0][0]);
00345 close(fds[1][0]);
00346 int status=0;
00347 waitpid(pid,&status,0);
00348
00349 if (fdout != 1)
00350 close(fdout);
00351 close(filefd);
00352 #endif
00353
00354
00355 outString = outStream.str();
00356 errorString = errorStream.str();
00357 return (status == 0);
00358 }
00359 }
00360
00361 }
00362 }
00363 }
00364