exec.cpp

Go to the documentation of this file.
00001 /***************************************************************************
00002                           exec.cpp  -  description
00003                              -------------------
00004     begin                : Thu Dec 9 2004
00005     copyright            : (C) 2004 by VooDooMan
00006     email                : vdmfun@hotmail.com
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010 
00011 VooDoo cIRCle - an IRC (ro)bot
00012 Copyright (C) 2004 by Marian VooDooMan Meravy (vdmfun@hotmail.com)
00013 
00014 This program is free software; you can redistribute it and/or
00015 modify it under the terms of the GNU General Public License
00016 as published by the Free Software Foundation; either version 2
00017 of the License, or (at your option) any later version.
00018 
00019 This program is distributed in the hope that it will be useful,
00020 but WITHOUT ANY WARRANTY; without even the implied warranty of
00021 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00022 GNU General Public License for more details.
00023 
00024 You should have received a copy of the GNU General Public License
00025 along with this program; if not, write to the Free Software
00026 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00027 
00028 ****************************************************************************/
00029 
00030 /*!
00031     \file
00032     \brief Handles child processes. Used to platform abstraction
00033 */
00034 
00035 //---------------------------------------------------------------------------
00036 
00037 #include <string>
00038 #ifndef _WIN32
00039 #   include <sys/types.h>
00040 #   include <sys/stat.h>
00041 #   include <sys/poll.h>
00042 #   include <stdio.h>
00043 #else
00044 #   include <windows.h>
00045 #endif
00046 #include <errno.h>
00047 
00048 using namespace std;
00049 
00050 #include "exec.h"
00051 
00052 #include "params.h"
00053 
00054 //---------------------------------------------------------------------------
00055 #ifndef _MSC_VER
00056 #pragma package(smart_init)
00057 #endif
00058 
00059 /*!
00060     \brief Reads console output (stdout) from executed command
00061     \author VooDooMan
00062     \version 1
00063     \date 2004
00064     \param h Handle returned by exec_async_exec
00065     \param lpBuffer Returns address of buffer, without NUL terminator (RAW)
00066     \warning lpBuffer MUST be deallocated by delete[]
00067     \param buffer_size Returns lpBuffer length in bytes
00068     \return Returns number of read bytes (=buffer_size)
00069 */
00070 int exec_read_output(s_exec_handle* h, char*& lpBuffer, int& buffer_size)
00071 {
00072     if(!h->out_buffer) {
00073         lpBuffer=new char[32];
00074         return buffer_size=0;
00075     }
00076     lpBuffer=h->out_buffer;
00077     buffer_size=h->out_buffer_size;
00078     h->out_buffer=NULL;
00079     h->out_buffer_size=0;
00080     return buffer_size;
00081 }
00082 
00083 /*!
00084     \brief Executes command asynchronously
00085     \author VooDooMan
00086     \version 1
00087     \date 2004
00088     \param cmd Executable
00089     \param params Command-line parameters
00090     \param dir Full path name of working directory of new process
00091     \return Returns handle to new process
00092 */
00093 s_exec_handle* exec_async_exec(const char* cmd, const char* params, const char* dir)
00094 {
00095 #ifdef _WIN32
00096     _STARTUPINFOA SI;
00097     memset(&SI,0,sizeof(SI));
00098     GetStartupInfoA(&SI);
00099     SI.dwFlags=STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES;
00100     SI.wShowWindow=SW_HIDE;
00101     string ln=cmd;
00102     if(ln.length()>0 && ln[0]!='\"' && ln.find(0x20,0)!=string::npos)
00103         ln=(string)"\""+ln+"\"";
00104     ln+=" ";
00105     ln+=params;
00106 
00107     s_exec_handle* h=new s_exec_handle;
00108     memset(&(h->PI),0,sizeof(h->PI));
00109 
00110     {
00111         HANDLE hOutputReadTmp,hOutputRead,hOutputWrite;
00112         HANDLE hInputWriteTmp,hInputRead,hInputWrite;
00113         HANDLE hErrorWrite;
00114         SECURITY_ATTRIBUTES sa;
00115         memset(&sa,0,sizeof(sa));
00116         sa.nLength=sizeof(sa);
00117         sa.lpSecurityDescriptor=NULL;
00118         sa.bInheritHandle=TRUE;
00119         CreatePipe(&hOutputReadTmp,&hOutputWrite,&sa,0);
00120         DuplicateHandle(GetCurrentProcess(),hOutputWrite,GetCurrentProcess(),&hErrorWrite,0,TRUE,DUPLICATE_SAME_ACCESS);
00121         CreatePipe(&hInputRead,&hInputWriteTmp,&sa,0);
00122         DuplicateHandle(GetCurrentProcess(),hOutputReadTmp,GetCurrentProcess(),&hOutputRead,0,FALSE,DUPLICATE_SAME_ACCESS);
00123         DuplicateHandle(GetCurrentProcess(),hInputWriteTmp,GetCurrentProcess(),&hInputWrite,0,FALSE,DUPLICATE_SAME_ACCESS);
00124         CloseHandle(hOutputReadTmp);
00125         CloseHandle(hInputWriteTmp);
00126 
00127         h->hOutputWrite=hOutputWrite;
00128         h->hOutputRead=hOutputRead;
00129 
00130         h->hInputRead=hInputRead;
00131         h->hInputWrite=hInputWrite;
00132 
00133         h->hErrorWrite=hErrorWrite;
00134 
00135         SI.hStdOutput=h->hOutputWrite;
00136         SI.hStdInput=h->hInputRead;
00137         SI.hStdError=h->hErrorWrite;
00138     }
00139     char fully_qualified_path[_MAX_PATH+128+1];
00140     LPTSTR* dummy=NULL;
00141     if(GetFullPathName(dir,sizeof(fully_qualified_path)-1,fully_qualified_path,dummy))
00142         h->error=!CreateProcessA(NULL,(LPSTR)ln.c_str(),NULL,NULL,true,NORMAL_PRIORITY_CLASS,NULL,(LPSTR)fully_qualified_path,&SI,&(h->PI));
00143     else
00144         h->error=!CreateProcessA(NULL,(LPSTR)ln.c_str(),NULL,NULL,true,NORMAL_PRIORITY_CLASS,NULL,NULL,&SI,&(h->PI));
00145 
00146     h->os_hnd=h->PI.hProcess;
00147     return h;
00148 #else
00149     int size=0;
00150     if(cmd)
00151         size+=strlen(cmd);
00152     else {
00153         s_exec_handle* h=new s_exec_handle;
00154         h->os_hnd=NULL;
00155         h->error=true;
00156         h->out_buffer=NULL;
00157         h->out_buffer_size=0;
00158         return h;
00159     }
00160     if(params)
00161         size+=strlen(params);
00162     if(dir)
00163         size+=strlen(dir);
00164     char* ln=new char[size+1024];
00165     ln[0]=0;
00166     if(dir) {
00167         strcpy(ln,"cd ");
00168         if(dir[0]!='\"')
00169             strcat(ln,"\"");
00170         strcat(ln,dir);
00171         if(dir[0]!='\"')
00172             strcat(ln,"\"");
00173         strcat(ln,"; ");
00174     }
00175     strcat(ln,cmd);
00176     if(params) {
00177         strcat(ln," ");
00178         strcat(ln,params);
00179     }
00180     FILE* hnd=popen(ln,"r");
00181     delete[] ln;
00182     s_exec_handle* h=new s_exec_handle;
00183     h->os_hnd=hnd;
00184     h->error=!hnd;
00185     h->out_buffer=NULL;
00186     h->out_buffer_size=0;
00187     return h;
00188 #endif
00189 }
00190 
00191 /*!
00192     \brief Checks wheter process is still active
00193     \param h Handle of process
00194     \return Returns true if process is still active, false if has exited
00195 */
00196 bool exec_process_active(s_exec_handle* h)
00197 {
00198     if(h==NULL)
00199         return false;
00200     if(h->os_hnd==NULL)
00201         return false;
00202 #ifdef _WIN32
00203     DWORD dwExitCode;
00204     GetExitCodeProcess(h->os_hnd,&dwExitCode);
00205     if(dwExitCode!=STILL_ACTIVE) {
00206         HANDLE hPipeRead=h->hOutputRead;
00207 
00208         DWORD nBytesRead;
00209 
00210         int buffer_size=GetFileSize(hPipeRead,NULL);
00211         if(buffer_size>0) {
00212             h->out_buffer=(char*)malloc(buffer_size);
00213             h->out_buffer_size=buffer_size;
00214             ReadFile(hPipeRead,h->out_buffer,h->out_buffer_size,&nBytesRead,NULL);
00215         } else {
00216             // hmm...
00217             h->out_buffer=(char*)malloc(1);
00218             h->out_buffer_size=0;
00219         }
00220         exec_process_end(h);
00221         h->os_hnd=NULL;
00222         h->exit_code=dwExitCode;
00223     }
00224     return dwExitCode==STILL_ACTIVE;
00225 #else
00226     pollfd to_poll;
00227     to_poll.fd=fileno(h->os_hnd);
00228     to_poll.events=POLLIN|POLLPRI;
00229     /* Retval will always be greater than 0 or -1 in this case.
00230        Since we're doing it while blocking */
00231     if(poll(&to_poll,1,1)<0) {
00232         h->out_buffer=(char*)malloc(1);
00233         h->out_buffer_size=0;
00234         exec_process_end(h);
00235         h->os_hnd=NULL;
00236         h->exit_code=-1;
00237         return false;
00238     }
00239     if((to_poll.revents&POLLIN)==POLLIN || (to_poll.revents&POLLPRI)==POLLPRI) {
00240         int size=128;
00241         char* tmp=new char[size+1];
00242     again:
00243         size=fread(tmp,1,size,h->os_hnd);
00244         if(size>0) {
00245             tmp[size]=0;
00246             if(!h->out_buffer) {
00247                 h->out_buffer=(char*)malloc(size);
00248                 h->out_buffer_size=size;
00249                 memcpy(h->out_buffer,tmp,size);
00250             } else {
00251                 int pos=h->out_buffer_size;
00252                 h->out_buffer_size+=size;
00253                 h->out_buffer=(char*)realloc(h->out_buffer,h->out_buffer_size);
00254                 memcpy(&(h->out_buffer[pos]),tmp,size);
00255             }
00256             size=128;
00257             goto again;
00258         }
00259         delete[] tmp;
00260         return true;
00261     }
00262     if((to_poll.revents&POLLHUP)==POLLHUP) {
00263         h->exit_code=pclose(h->os_hnd);
00264         h->os_hnd=NULL;
00265         int pos=h->out_buffer_size;
00266         h->out_buffer_size+=1;
00267         h->out_buffer=(char*)realloc(h->out_buffer,h->out_buffer_size);
00268         h->out_buffer[pos]=0;
00269         return false;
00270     }
00271     return true;
00272 #endif
00273     return true;
00274 }
00275 
00276 /*!
00277     \brief Gets exit code of terminated process
00278     \param h Handle of process
00279     \return Returns exit code
00280 */
00281 DWORD exec_get_exit_code(s_exec_handle* h)
00282 {
00283     if(!h)
00284         return (DWORD)-1;
00285     if(h->os_hnd==NULL)
00286         return h->exit_code;
00287     if(exec_process_active(h))
00288         return (DWORD)-2;
00289 #ifndef _WIN32
00290     h->exit_code=pclose(h->os_hnd);
00291     h->os_hnd=NULL;
00292     return h->exit_code;
00293 #else
00294     DWORD dwExitCode;
00295     GetExitCodeProcess(h->os_hnd,&dwExitCode);
00296     if(dwExitCode==STILL_ACTIVE)
00297         return (DWORD)-2;
00298     return dwExitCode;
00299 #endif
00300 }
00301 
00302 /*!
00303     \brief Deallocates resorces created by exec_async_exec
00304     \author VooDooMan
00305     \version 2
00306     \date 2005
00307     \param h Handle of process
00308     \return Returns exit code of process
00309 */
00310 int exec_process_end(s_exec_handle* h)
00311 {
00312 #ifdef _WIN32
00313     if(!h->os_hnd)
00314         return 0;
00315 
00316     DWORD dwExitCode;
00317     GetExitCodeProcess(h->os_hnd,&dwExitCode);
00318 
00319     if(h->hOutputWrite)
00320         CloseHandle(h->hOutputWrite);
00321     h->hOutputWrite=NULL;
00322 
00323     if(h->hOutputRead)
00324         CloseHandle(h->hOutputRead);
00325     h->hOutputRead=NULL;
00326 
00327     if(h->hInputWrite)
00328         CloseHandle(h->hInputWrite);
00329     h->hInputWrite=NULL;
00330 
00331     if(h->hInputRead)
00332         CloseHandle(h->hInputRead);
00333     h->hInputRead=NULL;
00334 
00335     if(h->hErrorWrite)
00336         CloseHandle(h->hErrorWrite);
00337     h->hErrorWrite=NULL;
00338 
00339     CloseHandle(h->PI.hProcess);
00340     CloseHandle(h->PI.hThread);
00341     /*bool ok=*/TerminateProcess(h->os_hnd,0);
00342 
00343     return dwExitCode;
00344 #else
00345     if(!h)
00346         return -1;
00347     if(h->os_hnd)
00348         h->exit_code=pclose(h->os_hnd);
00349     h->os_hnd=NULL;
00350     if(h->out_buffer) {
00351         free(h->out_buffer);
00352         h->out_buffer=NULL;
00353         h->out_buffer_size=0;
00354     }
00355     return h->exit_code;
00356 #endif
00357 }
00358 
00359 /*!
00360     \brief Hardly terminates the child process
00361     \author VooDooMan
00362     \version 1
00363     \date 2004
00364     \param h Process descriptor
00365     \param error_code Error code to end the process with
00366 */
00367 void exec_terminate_process(s_exec_handle* h, int error_code)
00368 {
00369 #ifdef _WIN32
00370     TerminateProcess(h->os_hnd,error_code);
00371     CloseHandle(h->PI.hProcess);
00372     CloseHandle(h->PI.hThread);
00373     h->os_hnd=NULL;
00374     if(h->out_buffer) {
00375         free(h->out_buffer);
00376         h->out_buffer=NULL;
00377         h->out_buffer_size=0;
00378     }
00379 #else
00380     if(h->os_hnd) {
00381         h->exit_code=pclose(h->os_hnd);
00382         h->os_hnd=NULL;
00383         if(h->out_buffer) {
00384             free(h->out_buffer);
00385             h->out_buffer=NULL;
00386             h->out_buffer_size=0;
00387         }
00388     }
00389 #endif
00390 }
00391 
00392 /*!
00393     \brief Executes the process without capturing output console (stdout)
00394     \author VooDooMan
00395     \version 1
00396     \date 2004
00397     \param cmd Path to process, cannot be NULL
00398     \param params Parameters to command line, can be NULL
00399     \param dir Working direstory of new process, can be NULL
00400     \return Returns handle to child process (need to be deallocated by delete!)
00401     \warning Returned handle need to be deallocated by delete!
00402 */
00403 s_exec_handle* exec_async_exec2(const char* cmd, const char* params, const char* dir)
00404 {
00405 #ifdef _WIN32
00406     _STARTUPINFOA SI;
00407     memset(&SI,0,sizeof(SI));
00408     GetStartupInfoA(&SI);
00409     SI.dwFlags=STARTF_USESHOWWINDOW | STARTF_FORCEOFFFEEDBACK | STARTF_USESTDHANDLES;
00410     SI.wShowWindow=SW_HIDE;
00411     string ln=cmd;
00412     if(ln.length()>0 && ln[0]!='\"' && ln.find(0x20,0)!=string::npos)
00413         ln=(string)"\""+ln+"\"";
00414     if(params) {
00415         ln+=" ";
00416         ln+=params;
00417     }
00418 
00419     s_exec_handle* h=new s_exec_handle;
00420     memset(&(h->PI),0,sizeof(h->PI));
00421 
00422     {
00423         h->hOutputWrite=NULL;
00424         h->hOutputRead=NULL;
00425 
00426         h->hInputRead=NULL;
00427         h->hInputWrite=NULL;
00428 
00429         h->hErrorWrite=NULL;
00430     }
00431     char fully_qualified_path[_MAX_PATH+128+1];
00432     LPTSTR* dummy=NULL;
00433     if(GetFullPathName(dir,sizeof(fully_qualified_path)-1,fully_qualified_path,dummy))
00434         h->error=!CreateProcessA(NULL,(LPSTR)ln.c_str(),NULL,NULL,false,NORMAL_PRIORITY_CLASS,NULL,(LPSTR)fully_qualified_path,&SI,&(h->PI));
00435     else
00436         h->error=!CreateProcessA(NULL,(LPSTR)ln.c_str(),NULL,NULL,false,NORMAL_PRIORITY_CLASS,NULL,NULL,&SI,&(h->PI));
00437 
00438     h->os_hnd=h->PI.hProcess;
00439     return h;
00440 #else
00441     int size=0;
00442     if(cmd)
00443         size+=strlen(cmd);
00444     else {
00445         s_exec_handle* h=new s_exec_handle;
00446         h->os_hnd=NULL;
00447         h->error=true;
00448         h->out_buffer=NULL;
00449         h->out_buffer_size=0;
00450         return h;
00451     }
00452     if(params)
00453         size+=strlen(params);
00454     if(dir)
00455         size+=strlen(dir);
00456     char* ln=new char[size+1024];
00457     ln[0]=0;
00458     if(dir) {
00459         strcpy(ln,"cd ");
00460         if(dir[0]!='\"')
00461             strcat(ln,"\"");
00462         strcat(ln,dir);
00463         if(dir[0]!='\"')
00464             strcat(ln,"\"");
00465         strcat(ln,"; ");
00466     }
00467     strcat(ln,cmd);
00468     if(params) {
00469         strcat(ln," ");
00470         strcat(ln,params);
00471     }
00472     FILE* hnd=popen(ln,"r");
00473     delete[] ln;
00474     s_exec_handle* h=new s_exec_handle;
00475     h->os_hnd=hnd;
00476     h->error=!hnd;
00477     h->out_buffer=NULL;
00478     h->out_buffer_size=0;
00479     return h;
00480 #endif
00481 }
00482 

Generated on Sun Jul 10 03:22:52 2005 for VooDoo cIRCle by doxygen 1.4.3

Hosted by SourceForge.net Logo