/* * $Id$ */ /* * Harbour Project source code: * low level functions to create, wait and terminate processes * * Copyright 2009 Przemyslaw Czerpak * www - http://www.harbour-project.org * based on xHarbour code by * Copyright 2003 Giancarlo Niccolai * www - http://www.xharbour.org * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) * any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this software; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307 USA (or visit the web site http://www.gnu.org/). * * As a special exception, the Harbour Project gives permission for * additional uses of the text contained in its release of Harbour. * * The exception is that, if you link the Harbour libraries with other * files to produce an executable, this does not by itself cause the * resulting executable to be covered by the GNU General Public License. * Your use of that executable is in no way restricted on account of * linking the Harbour library code into it. * * This exception does not however invalidate any other reasons why * the executable file might be covered by the GNU General Public License. * * This exception applies only to the code released by the Harbour * Project under the name Harbour. If you copy code from other * Harbour Project or Free Software Foundation releases into a copy of * Harbour, as the General Public License permits, the exception does * not apply to the code that you add in this way. To avoid misleading * anyone as to the status of such modified files, you must delete * this exception notice from them. * * If you write modifications of your own for Harbour, it is your choice * whether to permit this exception to apply to your modifications. * If you do not wish that, delete this exception notice. * */ #define HB_OS_WIN_USED /* #define HB_IO_WIN_OFF */ #include "hbapi.h" #include "hbapifs.h" #include "hbvm.h" #if defined( HB_OS_UNIX ) # include # include # include # include # include # include # include #elif defined( HB_OS_OS2 ) || ( defined( HB_OS_WIN ) && !defined( HB_IO_WIN ) ) # include # include # include # if defined( HB_OS_OS2 ) && defined( __GNUC__ ) # include # endif #elif defined( HB_OS_DOS ) # include # include # if defined( __DJGPP__ ) # include # include # else # include # endif #endif #if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) || defined( HB_OS_UNIX ) || \ ( defined( HB_OS_WIN ) && !defined( HB_IO_WIN ) ) /* convert command to argument list using standard bourne shell encoding: * "" and '' can be used to group parameters with blank characters, * the escape character is '\', quoting by '' disables escape character. */ static char ** hb_buildArgs( const char *pszFilename ) { const char * src; char ** argv, * dst, cQuote = 0; int argc = 0; while( HB_ISSPACE( *pszFilename ) ) ++pszFilename; src = pszFilename; while( *src ) { #if defined( HB_OS_UNIX ) if( *src == '\\' && cQuote != '\'' ) { if( src[ 1 ] ) ++src; } else #endif if( *src == cQuote ) cQuote = 0; else if( cQuote == 0 ) { #if defined( HB_OS_UNIX ) if( *src == '"' || *src == '\'' ) #else if( *src == '"' ) #endif cQuote = *src; else if( HB_ISSPACE( *src ) ) { while( HB_ISSPACE( src[ 1 ] ) ) ++src; if( src[ 1 ] ) ++argc; } } ++src; } dst = ( char * ) hb_xgrab( strlen( pszFilename ) + 1 ); argv = ( char ** ) hb_xgrab( ( argc + 2 ) * sizeof( char * ) ); argv[ 0 ] = dst; argv[ argc + 1 ] = NULL; argc = 0; cQuote = 0; src = pszFilename; while( *src ) { #if defined( HB_OS_UNIX ) if( *src == '\\' && cQuote != '\'' ) { if( src[ 1 ] ) { *dst++ = src[ 1 ]; ++src; } } else #endif if( *src == cQuote ) cQuote = 0; else if( cQuote != 0 ) *dst++ = *src; else { #if defined( HB_OS_UNIX ) if( *src == '"' || *src == '\'' ) #else if( *src == '"' ) #endif cQuote = *src; else if( HB_ISSPACE( *src ) ) { *dst++ = '\0'; while( HB_ISSPACE( src[ 1 ] ) ) ++src; if( src[ 1 ] ) argv[ ++argc ] = dst; } else *dst++ = *src; } ++src; } *dst = 0; return argv; } static void hb_freeArgs( char ** argv ) { hb_xfree( argv[ 0 ] ); hb_xfree( argv ); } #endif #if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) /* || defined( HB_OS_WIN_CE ) */ static int hb_fsProcessExec( const char *pszFilename, HB_FHANDLE hStdin, HB_FHANDLE hStdout, HB_FHANDLE hStderr ) { int iResult = FS_ERROR; HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessExec(%s, %p, %p, %p, %d, %p)", pszFilename, ( void * ) ( HB_PTRDIFF ) hStdin, ( void * ) ( HB_PTRDIFF ) hStdout, ( void * ) ( HB_PTRDIFF ) hStderr)); #if defined( HB_IO_WIN ) PROCESS_INFORMATION pi; STARTUPINFO si; DWORD dwFlags = 0; #if defined( UNICODE ) LPWSTR lpCommand = hb_mbtowc( pszFilename ); #else char * lpCommand = hb_strdup( pszFilename ); #endif BOOL fError; memset( &pi, 0, sizeof( pi ) ); memset( &si, 0, sizeof( si ) ); si.cb = sizeof( si ); si.hStdInput = hStdin == FS_ERROR ? GetStdHandle( STD_INPUT_HANDLE ) : hStdin; si.hStdOutput = hStdout == FS_ERROR ? GetStdHandle( STD_OUTPUT_HANDLE ) : hStdout; si.hStdError = hStderr == FS_ERROR ? GetStdHandle( STD_ERROR_HANDLE ) : hStderr; #ifdef STARTF_USESTDHANDLES si.dwFlags = STARTF_USESTDHANDLES; #endif hb_vmUnlock(); fError = ! CreateProcess( NULL, /* lpAppName */ lpCommand, NULL, /* lpProcessAttr */ NULL, /* lpThreadAttr */ TRUE, /* bInheritHandles */ dwFlags, /* dwCreationFlags */ NULL, /* lpEnvironment */ NULL, /* lpCurrentDirectory */ &si, &pi ); hb_fsSetIOError( !fError, 0 ); if( !fError ) { CloseHandle( pi.hThread ); if( WaitForSingleObject( pi.hProcess, INFINITE ) == WAIT_OBJECT_0 ) { DWORD dwResult = 0; fError = !GetExitCodeProcess( pi.hProcess, &dwResult ); iResult = !fError ? ( int ) dwResult : -2; } hb_fsSetIOError( !fError, 0 ); CloseHandle( pi.hProcess ); } hb_vmLock(); hb_xfree( lpCommand ); #elif defined( HB_OS_DOS ) || defined( HB_OS_WIN ) || defined( HB_OS_OS2 ) || \ defined( HB_OS_UNIX ) int iStdIn, iStdOut, iStdErr; char ** argv; argv = hb_buildArgs( pszFilename ); hb_vmUnlock(); iStdIn = iStdOut = iStdErr = FS_ERROR; if( hStdin != FS_ERROR ) { iStdIn = dup( 0 ); dup2( hStdin, 0 ); } if( hStdout != FS_ERROR ) { iStdOut = dup( 1 ); dup2( hStdout, 1 ); } if( hStderr != FS_ERROR ) { iStdErr = dup( 2 ); dup2( hStderr, 2 ); } #if defined( HB_OS_UNIX ) { pid_t pid = fork(); if( pid == 0 ) { /* close all non std* handles */ { int iMaxFD, i; iMaxFD = sysconf( _SC_OPEN_MAX ); if( iMaxFD < 3 ) iMaxFD = 1024; for( i = 3; i < iMaxFD; ++i ) close( i ); } /* reset extended process attributes */ setuid( getuid() ); setgid( getgid() ); /* execute command */ execvp( argv[ 0 ], argv ); exit(1); } else if( pid != -1 ) { int iStatus; iResult = waitpid( pid, &iStatus, 0 ); #ifdef ERESTARTSYS if( iResult < 0 && errno != ERESTARTSYS ) #else if( iResult < 0 ) #endif iResult = -2; else if( iResult == 0 ) iResult = -1; else iResult = WIFEXITED( iStatus ) ? WEXITSTATUS( iStatus ) : 0; } } #elif defined( _MSC_VER ) || defined( __LCC__ ) || \ defined( __XCC__ ) || defined( __POCC__ ) iResult = _spawnvp( _P_WAIT, argv[ 0 ], argv ); #elif defined( __MINGW32__ ) iResult = spawnvp( P_WAIT, argv[ 0 ], ( const char * const * ) argv ); #else iResult = spawnvp( P_WAIT, argv[ 0 ], ( char * const * ) argv ); #endif hb_fsSetIOError( iResult >= 0, 0 ); if( iStdIn != FS_ERROR ) dup2( iStdIn, 0 ); if( iStdOut != FS_ERROR ) dup2( iStdOut, 1 ); if( iStdErr != FS_ERROR ) dup2( iStdErr, 2 ); hb_vmLock(); hb_freeArgs( argv ); #else { int TODO; /* TODO: for given platform */ HB_SYMBOL_UNUSED( pszFilename ); HB_SYMBOL_UNUSED( hStdin ); HB_SYMBOL_UNUSED( hStdout ); HB_SYMBOL_UNUSED( hStderr ); hb_fsSetError( ( USHORT ) FS_ERROR ); } #endif return iResult; } #endif HB_FHANDLE hb_fsProcessOpen( const char *pszFilename, HB_FHANDLE *phStdin, HB_FHANDLE *phStdout, HB_FHANDLE *phStderr, BOOL fDetach, ULONG *pulPID ) { HB_FHANDLE hResult = FS_ERROR; HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessOpen(%s, %p, %p, %p, %d, %p)", pszFilename, phStdin, phStdout, phStderr, fDetach, pulPID)); #if defined( HB_IO_WIN ) { #if defined( HB_OS_WIN_CE ) # define CreatePipe( hIn, hOut, sa, flags ) ( FALSE ) #endif BOOL fError = FALSE; HANDLE hPipes[ 6 ]; SECURITY_ATTRIBUTES sa; int i; for( i = 0; i < 6; ++i ) hPipes[ i ] = INVALID_HANDLE_VALUE; memset( &sa, 0, sizeof( sa ) ); sa.nLength = sizeof( sa ); sa.bInheritHandle = TRUE; if( phStdin != NULL ) fError = !CreatePipe( &hPipes[0], &hPipes[1], &sa, 0 ); if( !fError && phStdout != NULL ) fError = !CreatePipe( &hPipes[2], &hPipes[3], &sa, 0 ); if( !fError && phStderr != NULL ) { if( phStdout == phStderr ) { hPipes[4] = hPipes[2]; hPipes[5] = hPipes[3]; } else fError = !CreatePipe( &hPipes[4], &hPipes[5], &sa, 0 ); } if( fError ) hb_fsSetIOError( FALSE, 0 ); else { PROCESS_INFORMATION pi; STARTUPINFO si; DWORD dwFlags = 0; #if defined( UNICODE ) LPWSTR lpCommand = hb_mbtowc( pszFilename ); #else char * lpCommand = hb_strdup( pszFilename ); #endif memset( &pi, 0, sizeof( pi ) ); memset( &si, 0, sizeof( si ) ); si.cb = sizeof( si ); #ifdef STARTF_USESTDHANDLES si.dwFlags = STARTF_USESTDHANDLES; #endif if( fDetach ) { #ifdef STARTF_USESHOWWINDOW si.dwFlags |= STARTF_USESHOWWINDOW; #endif si.wShowWindow = SW_HIDE; si.hStdInput = hPipes[ 0 ]; si.hStdOutput = hPipes[ 3 ]; si.hStdError = hPipes[ 5 ]; #ifdef DETACHED_PROCESS dwFlags |= DETACHED_PROCESS; #endif } else { si.hStdInput = phStdin ? hPipes[ 0 ] : GetStdHandle( STD_INPUT_HANDLE ); si.hStdOutput = phStdout ? hPipes[ 3 ] : GetStdHandle( STD_OUTPUT_HANDLE ); si.hStdError = phStderr ? hPipes[ 5 ] : GetStdHandle( STD_ERROR_HANDLE ); } fError = ! CreateProcess( NULL, /* lpAppName */ lpCommand, NULL, /* lpProcessAttr */ NULL, /* lpThreadAttr */ TRUE, /* bInheritHandles */ dwFlags, /* dwCreationFlags */ NULL, /* lpEnvironment */ NULL, /* lpCurrentDirectory */ &si, &pi ); hb_fsSetIOError( !fError, 0 ); hb_xfree( lpCommand ); if( !fError ) { if( phStdin != NULL ) { *phStdin = ( HB_FHANDLE ) hPipes[ 1 ]; hPipes[ 1 ] = INVALID_HANDLE_VALUE; } if( phStdout != NULL ) { *phStdout = ( HB_FHANDLE ) hPipes[ 2 ]; hPipes[ 2 ] = INVALID_HANDLE_VALUE; } if( phStderr != NULL ) { *phStderr = ( HB_FHANDLE ) hPipes[ 4 ]; hPipes[ 4 ] = INVALID_HANDLE_VALUE; } if( pulPID ) *pulPID = pi.dwProcessId; CloseHandle( pi.hThread ); hResult = ( HB_FHANDLE ) pi.hProcess; } } for( i = phStdout == phStderr ? 3 : 5; i >= 0; --i ) { if( hPipes[ i ] != INVALID_HANDLE_VALUE ) CloseHandle( hPipes[ i ] ); } } #elif defined( HB_OS_UNIX ) { BOOL fError = FALSE; HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR }, hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR }, hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR }; if( phStdin != NULL ) fError = pipe( hPipeIn ) != 0; if( !fError && phStdout != NULL ) fError = pipe( hPipeOut ) != 0; if( !fError && phStderr != NULL ) { if( phStdout == phStderr ) { hPipeErr[ 0 ] = hPipeOut[ 0 ]; hPipeErr[ 1 ] = hPipeOut[ 1 ]; } else fError = pipe( hPipeErr ) != 0; } if( !fError ) { pid_t pid = fork(); if( pid == -1 ) fError = TRUE; else if( pid != 0 ) /* parent process */ { if( phStdin != NULL ) { *phStdin = ( HB_FHANDLE ) hPipeIn[ 1 ]; hPipeIn[ 1 ] = FS_ERROR; } if( phStdout != NULL ) { *phStdout = ( HB_FHANDLE ) hPipeOut[ 0 ]; hPipeOut[ 0 ] = FS_ERROR; } if( phStderr != NULL ) { *phStderr = ( HB_FHANDLE ) hPipeErr[ 0 ]; hPipeErr[ 0 ] = FS_ERROR; } if( pulPID ) *pulPID = pid; hResult = ( HB_FHANDLE ) pid; } else /* child process */ { if( fDetach && ( !phStdin || !phStdout || !phStderr ) ) { HB_FHANDLE hNull = open( "/dev/null", O_RDWR ); if( !phStdin ) dup2( hNull, 0 ); if( !phStdout ) dup2( hNull, 1 ); if( !phStderr ) dup2( hNull, 2 ); if( hNull != FS_ERROR ) close( hNull ); } if( phStdin != NULL ) dup2( hPipeIn[ 0 ], 0 ); if( phStdout != NULL ) dup2( hPipeOut[ 1 ], 1 ); if( phStderr != NULL ) dup2( hPipeErr[ 1 ], 2 ); /* close all non std* handles */ { int iMaxFD, i; iMaxFD = sysconf( _SC_OPEN_MAX ); if( iMaxFD < 3 ) iMaxFD = 1024; for( i = 3; i < iMaxFD; ++i ) close( i ); } /* reset extended process attributes */ setuid( getuid() ); setgid( getgid() ); /* execute command */ { #if 0 char * argv[4]; argv[0] = ( char * ) "sh"; argv[1] = ( char * ) "-c"; argv[2] = ( char * ) pszFilename; argv[3] = ( char * ) 0; execv( "/bin/sh", argv ); #else char ** argv; argv = hb_buildArgs( pszFilename ); execvp( argv[ 0 ], argv ); hb_freeArgs( argv ); #endif exit(1); } } } hb_fsSetIOError( !fError, 0 ); if( hPipeIn[ 0 ] != FS_ERROR ) close( hPipeIn[ 0 ] ); if( hPipeIn[ 1 ] != FS_ERROR ) close( hPipeIn[ 1 ] ); if( hPipeOut[ 0 ] != FS_ERROR ) close( hPipeOut[ 0 ] ); if( hPipeOut[ 1 ] != FS_ERROR ) close( hPipeOut[ 1 ] ); if( phStdout != phStderr ) { if( hPipeErr[ 0 ] != FS_ERROR ) close( hPipeErr[ 0 ] ); if( hPipeErr[ 1 ] != FS_ERROR ) close( hPipeErr[ 1 ] ); } } #elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) { #if defined( HB_OS_OS2 ) && defined( __GNUC__ ) # define _hb_pipe( e, p ) do { \ (e) = pipe( (p) ) != 0; \ if( !(e) ) \ { \ setmode( (p)[ 0 ], O_BINARY ); \ setmode( (p)[ 1 ], O_BINARY ); \ } \ } while( 0 ) #else # define pid_t int # define _hb_pipe( e, p ) do { \ (e) = _pipe( (p), 2048, _O_BINARY ) != 0; \ } while( 0 ) #endif BOOL fError = FALSE; HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR }, hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR }, hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR }; if( phStdin != NULL ) { _hb_pipe( fError, hPipeIn ); } if( !fError && phStdout != NULL ) { _hb_pipe( fError, hPipeOut ); } if( !fError && phStderr != NULL ) { if( phStdout == phStderr ) { hPipeErr[ 0 ] = hPipeOut[ 0 ]; hPipeErr[ 1 ] = hPipeOut[ 1 ]; } else { _hb_pipe( fError, hPipeErr ); } } if( !fError ) { int hStdIn, hStdOut, hStdErr; char ** argv; pid_t pid; hStdIn = dup( 0 ); hStdOut = dup( 1 ); hStdErr = dup( 2 ); if( fDetach && ( !phStdin || !phStdout || !phStderr ) ) { HB_FHANDLE hNull = open( "NUL:", O_RDWR ); if( !phStdin ) dup2( hNull, 0 ); if( !phStdout ) dup2( hNull, 1 ); if( !phStderr ) dup2( hNull, 2 ); if( hNull != FS_ERROR ) close( hNull ); } if( phStdin != NULL ) dup2( hPipeIn[ 0 ], 0 ); if( phStdout != NULL ) dup2( hPipeOut[ 1 ], 1 ); if( phStderr != NULL ) dup2( hPipeErr[ 1 ], 2 ); argv = hb_buildArgs( pszFilename ); #if defined( _MSC_VER ) || defined( __LCC__ ) || \ defined( __XCC__ ) || defined( __POCC__ ) pid = _spawnvp( _P_NOWAIT, argv[ 0 ], argv ); #elif defined( __MINGW32__ ) pid = spawnvp( P_NOWAIT, argv[ 0 ], ( const char * const * ) argv ); #else pid = spawnvp( P_NOWAIT, argv[ 0 ], ( char * const * ) argv ); #endif hb_freeArgs( argv ); dup2( hStdIn, 0 ); dup2( hStdOut, 1 ); dup2( hStdErr, 2 ); if( pid < 0 ) fError = TRUE; else if( pid != 0 ) /* parent process */ { if( phStdin != NULL ) { *phStdin = ( HB_FHANDLE ) hPipeIn[ 1 ]; hPipeIn[ 1 ] = FS_ERROR; } if( phStdout != NULL ) { *phStdout = ( HB_FHANDLE ) hPipeOut[ 0 ]; hPipeOut[ 0 ] = FS_ERROR; } if( phStderr != NULL ) { *phStderr = ( HB_FHANDLE ) hPipeErr[ 0 ]; hPipeErr[ 0 ] = FS_ERROR; } if( pulPID ) *pulPID = pid; hResult = ( HB_FHANDLE ) pid; } } hb_fsSetIOError( !fError, 0 ); if( hPipeIn[ 0 ] != FS_ERROR ) close( hPipeIn[ 0 ] ); if( hPipeIn[ 1 ] != FS_ERROR ) close( hPipeIn[ 1 ] ); if( hPipeOut[ 0 ] != FS_ERROR ) close( hPipeOut[ 0 ] ); if( hPipeOut[ 1 ] != FS_ERROR ) close( hPipeOut[ 1 ] ); if( phStdout != phStderr ) { if( hPipeErr[ 0 ] != FS_ERROR ) close( hPipeErr[ 0 ] ); if( hPipeErr[ 1 ] != FS_ERROR ) close( hPipeErr[ 1 ] ); } } #else { int TODO; /* TODO: for given platform */ HB_SYMBOL_UNUSED( pszFilename ); HB_SYMBOL_UNUSED( phStdin ); HB_SYMBOL_UNUSED( phStdout ); HB_SYMBOL_UNUSED( phStderr ); HB_SYMBOL_UNUSED( fDetach ); HB_SYMBOL_UNUSED( pulPID ); hb_fsSetError( ( USHORT ) FS_ERROR ); } #endif return hResult; } int hb_fsProcessValue( HB_FHANDLE hProcess, BOOL fWait ) { int iRetStatus = -1; HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessValue(%p, %d)", ( void * ) ( HB_PTRDIFF ) hProcess, fWait)); #if defined( HB_IO_WIN ) { BOOL fError = TRUE; DWORD dwResult; HANDLE hProc = ( HANDLE ) hb_fsGetOsHandle( hProcess ); if( hProc ) { hb_vmUnlock(); dwResult = WaitForSingleObject( hProc, fWait ? INFINITE : 0 ); if( dwResult == WAIT_OBJECT_0 ) { fError = !GetExitCodeProcess( hProc, &dwResult ); iRetStatus = !fError ? ( int ) dwResult : -2; } hb_fsSetIOError( !fError, 0 ); if( !fError ) CloseHandle( hProc ); hb_vmLock(); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #elif defined( HB_OS_UNIX ) || ( defined( HB_OS_OS2 ) && defined( __GNUC__ ) ) { int iStatus; pid_t pid = ( pid_t ) hProcess; if( pid > 0 ) { hb_vmUnlock(); iRetStatus = waitpid( pid, &iStatus, fWait ? 0 : WNOHANG ); hb_fsSetIOError( iRetStatus >= 0, 0 ); #ifdef ERESTARTSYS if( iRetStatus < 0 && errno != ERESTARTSYS ) #else if( iRetStatus < 0 ) #endif iRetStatus = -2; else if( iRetStatus == 0 ) iRetStatus = -1; else iRetStatus = WIFEXITED( iStatus ) ? WEXITSTATUS( iStatus ) : 0; hb_vmLock(); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN ) { int iPid = ( int ) hProcess; HB_SYMBOL_UNUSED( fWait ); if( iPid > 0 ) { hb_vmUnlock(); #if defined( __BORLANDC__ ) iPid = cwait( &iRetStatus, iPid, 0 ); #else iPid = _cwait( &iRetStatus, iPid, 0 ); #endif hb_fsSetIOError( iPid > 0, 0 ); if( iPid != ( int ) hProcess ) iRetStatus = -1; hb_vmLock(); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #else { int TODO; /* TODO: for given platform */ HB_SYMBOL_UNUSED( hProcess ); HB_SYMBOL_UNUSED( fWait ); hb_fsSetError( ( USHORT ) FS_ERROR ); } #endif return iRetStatus; } /* Closes/kills process. The handle is still valid until you * catch it with hb_fsProcessValue. */ BOOL hb_fsProcessClose( HB_FHANDLE hProcess, BOOL fGentle ) { BOOL fResult = FALSE; HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessClose(%p, %d)", ( void * ) ( HB_PTRDIFF ) hProcess, fGentle)); #if defined( HB_IO_WIN ) { HANDLE hProc = ( HANDLE ) hb_fsGetOsHandle( hProcess ); if( hProc ) { if( TerminateProcess( hProc, fGentle ? 0 : 1 ) ) fResult = TRUE; hb_fsSetIOError( fResult, 0 ); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #elif defined( HB_OS_UNIX ) || ( defined( HB_OS_OS2 ) && defined( __GNUC__ ) ) { pid_t pid = ( pid_t ) hProcess; if( pid > 0 ) { if( kill( pid, fGentle ? SIGTERM : SIGKILL ) == 0 ) fResult = TRUE; hb_fsSetIOError( fResult, 0 ); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #elif defined( HB_OS_WIN ) { HANDLE hProc = OpenProcess( PROCESS_TERMINATE, FALSE, hProcess ); if( hProc ) { if( TerminateProcess( hProc, fGentle ? 0 : 1 ) ) fResult = TRUE; hb_fsSetIOError( fResult, 0 ); CloseHandle( hProc ); } else hb_fsSetError( ( USHORT ) FS_ERROR ); } #else { int TODO; /* TODO: for given platform */ HB_SYMBOL_UNUSED( hProcess ); HB_SYMBOL_UNUSED( fGentle ); hb_fsSetError( ( USHORT ) FS_ERROR ); } #endif return fResult; } #define HB_STD_BUFFER_SIZE 4096 int hb_fsProcessRun( const char * pszFilename, const char * pStdInBuf, ULONG ulStdInLen, char ** pStdOutPtr, ULONG * pulStdOut, char ** pStdErrPtr, ULONG * pulStdErr, BOOL fDetach ) { HB_FHANDLE hStdin, hStdout, hStderr, *phStdin, *phStdout, *phStderr; char * pOutBuf, *pErrBuf; ULONG ulOutSize, ulErrSize, ulOutBuf, ulErrBuf; int iResult; HB_TRACE(HB_TR_DEBUG, ("hb_fsProcessRun(%s, %p, %lu, %p, %p, %p, %p, %d)", pStdInBuf, ulStdInLen, pStdOutPtr, pulStdOut, pStdErrPtr, pulStdErr, fDetach)); ulOutBuf = ulErrBuf = ulOutSize = ulErrSize = 0; pOutBuf = pErrBuf = NULL; hStdin = hStdout = hStderr = FS_ERROR; phStdin = pStdInBuf ? &hStdin : NULL; phStdout = pStdOutPtr && pulStdOut ? &hStdout : NULL; phStderr = pStdErrPtr && pulStdErr ? &hStderr : NULL; #if defined( HB_OS_DOS ) || defined( HB_OS_OS2 ) /* || defined( HB_OS_WIN_CE ) */ { #if defined( HB_OS_UNIX ) # define _HB_NULLHANDLE() open( "/dev/null", O_RDWR ) #else # define _HB_NULLHANDLE() open( "NUL:", O_RDWR ) #endif char sTmpIn[ HB_PATH_MAX ]; char sTmpOut[ HB_PATH_MAX ]; char sTmpErr[ HB_PATH_MAX ]; sTmpIn[ 0 ] = sTmpOut[ 0 ] = sTmpErr[ 0 ] = '\0'; if( pStdInBuf ) { hStdin = hb_fsCreateTempEx( sTmpIn, NULL, NULL, NULL, FC_NORMAL ); if( ulStdInLen ) { hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); hb_fsSeek( hStdin, 0, FS_SET ); } } else if( fDetach ) hStdin = _HB_NULLHANDLE(); if( pStdOutPtr && pulStdOut ) hStdout = hb_fsCreateTempEx( sTmpOut, NULL, NULL, NULL, FC_NORMAL ); else if( fDetach ) hStdout = _HB_NULLHANDLE(); if( pStdErrPtr && pulStdErr ) hStderr = hb_fsCreateTempEx( sTmpErr, NULL, NULL, NULL, FC_NORMAL ); else if( fDetach ) hStderr = _HB_NULLHANDLE(); iResult = hb_fsProcessExec( pszFilename, hStdin, hStdout, hStderr ); if( hStdin != FS_ERROR ) { hb_fsClose( hStdin ); if( sTmpIn[ 0 ] ) hb_fsDelete( sTmpIn ); } if( hStdout != FS_ERROR ) { if( pStdOutPtr && pulStdOut ) { ulOutBuf = hb_fsSeek( hStdout, 0, FS_END ); if( ulOutBuf ) { pOutBuf = ( char * ) hb_xgrab( ulOutBuf + 1 ); hb_fsSeek( hStdout, 0, FS_SET ); ulOutBuf = hb_fsReadLarge( hStdout, pOutBuf, ulOutBuf ); } } hb_fsClose( hStdout ); if( sTmpOut[ 0 ] ) hb_fsDelete( sTmpOut ); } if( hStderr != FS_ERROR ) { if( pStdErrPtr && pulStdErr ) { ulErrBuf = hb_fsSeek( hStderr, 0, FS_END ); if( ulErrBuf ) { pErrBuf = ( char * ) hb_xgrab( ulErrBuf + 1 ); hb_fsSeek( hStderr, 0, FS_SET ); ulErrBuf = hb_fsReadLarge( hStderr, pErrBuf, ulErrBuf ); } } hb_fsClose( hStderr ); if( sTmpErr[ 0 ] ) hb_fsDelete( sTmpErr ); } } #else { HB_FHANDLE hProcess; iResult = -1; hProcess = hb_fsProcessOpen( pszFilename, phStdin, phStdout, phStderr, fDetach, NULL ); if( hProcess != FS_ERROR ) { #if defined( HB_IO_WIN ) DWORD dwResult, dwCount; HANDLE lpHandles[ 4 ]; ULONG ul; if( ulStdInLen == 0 && hStdin != FS_ERROR ) { hb_fsClose( hStdin ); hStdin = FS_ERROR; } for( ;; ) { dwCount = 0; if( ulStdInLen && hStdin != FS_ERROR ) lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStdin ); if( hStdout != FS_ERROR ) lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStdout ); if( hStderr != FS_ERROR ) lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hStderr ); lpHandles[ dwCount++ ] = ( HANDLE ) hb_fsGetOsHandle( hProcess ); dwResult = WaitForMultipleObjects( dwCount, lpHandles, FALSE, INFINITE ); if( /* dwResult >= WAIT_OBJECT_0 && */ dwResult < WAIT_OBJECT_0 + dwCount ) { if( ulStdInLen && hStdin != FS_ERROR && lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStdin ) ) { ul = hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); pStdInBuf += ul; ulStdInLen -= ul; if( ulStdInLen == 0 ) { hb_fsClose( hStdin ); hStdin = FS_ERROR; } } else if( hStdout != FS_ERROR && lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStdout ) ) { if( ulOutBuf == ulOutSize ) { ulOutSize += HB_STD_BUFFER_SIZE; pOutBuf = ( char * ) hb_xrealloc( pOutBuf, ulOutSize + 1 ); } ul = hb_fsReadLarge( hStdout, pOutBuf + ulOutBuf, ulOutSize - ulOutBuf ); if( ul == 0 ) { hb_fsClose( hStdout ); hStdout = FS_ERROR; } else ulOutBuf += ul; } else if( hStderr != FS_ERROR && lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hStderr ) ) { if( ulErrBuf == ulErrSize ) { ulErrSize += HB_STD_BUFFER_SIZE; pErrBuf = ( char * ) hb_xrealloc( pErrBuf, ulErrSize + 1 ); } ul = hb_fsReadLarge( hStderr, pErrBuf + ulErrBuf, ulErrSize - ulErrBuf ); if( ul == 0 ) { hb_fsClose( hStderr ); hStderr = FS_ERROR; } else ulErrBuf += ul; } else if( lpHandles[ dwResult ] == ( HANDLE ) hb_fsGetOsHandle( hProcess ) ) { if( GetExitCodeProcess( ( HANDLE ) hb_fsGetOsHandle( hProcess ), &dwResult ) ) iResult = ( int ) dwResult; else iResult = -2; break; } } else break; } if( hStdin != FS_ERROR ) hb_fsClose( hStdin ); if( hStdout != FS_ERROR ) hb_fsClose( hStdout ); if( hStderr != FS_ERROR ) hb_fsClose( hStderr ); #elif defined( HB_OS_UNIX ) fd_set rfds, wfds, *prfds, *pwfds; HB_FHANDLE fdMax; ULONG ul; int n; if( ulStdInLen == 0 && hStdin != FS_ERROR ) { hb_fsClose( hStdin ); hStdin = FS_ERROR; } for( ;; ) { fdMax = 0; prfds = pwfds = NULL; if( hStdout != FS_ERROR || hStderr != FS_ERROR ) { FD_ZERO( &rfds ); if( hStdout != FS_ERROR ) { FD_SET( hStdout, &rfds ); if( hStdout > fdMax ) fdMax = hStdout; } if( hStderr != FS_ERROR ) { FD_SET( hStderr, &rfds ); if( hStderr > fdMax ) fdMax = hStderr; } prfds = &rfds; } if( ulStdInLen && hStdin != FS_ERROR ) { FD_ZERO( &wfds ); FD_SET( hStdin, &wfds ); if( hStdin > fdMax ) fdMax = hStdin; pwfds = &wfds; } if( prfds == NULL && pwfds == NULL ) break; hb_vmUnlock(); n = select( fdMax + 1, prfds, pwfds, NULL, NULL ); if( n > 0 ) { if( ulStdInLen && hStdin != FS_ERROR && FD_ISSET( hStdin, &wfds ) ) { ul = hb_fsWriteLarge( hStdin, pStdInBuf, ulStdInLen ); pStdInBuf += ul; ulStdInLen -= ul; if( ulStdInLen == 0 ) { hb_fsClose( hStdin ); hStdin = FS_ERROR; } } if( hStdout != FS_ERROR && FD_ISSET( hStdout, &rfds ) ) { if( ulOutBuf == ulOutSize ) { ulOutSize += HB_STD_BUFFER_SIZE; pOutBuf = ( char * ) hb_xrealloc( pOutBuf, ulOutSize + 1 ); } ul = hb_fsReadLarge( hStdout, pOutBuf + ulOutBuf, ulOutSize - ulOutBuf ); if( ul == 0 ) { /* zero bytes read after positive select() * - writing process closed the pipe */ hb_fsClose( hStdout ); hStdout = FS_ERROR; } else ulOutBuf += ul; } if( hStderr != FS_ERROR && FD_ISSET( hStderr, &rfds ) ) { if( ulErrBuf == ulErrSize ) { ulErrSize += HB_STD_BUFFER_SIZE; pErrBuf = ( char * ) hb_xrealloc( pErrBuf, ulErrSize + 1 ); } ul = hb_fsReadLarge( hStderr, pErrBuf + ulErrBuf, ulErrSize - ulErrBuf ); if( ul == 0 ) { /* zero bytes read after positive select() * - writing process closed the pipe */ hb_fsClose( hStderr ); hStderr = FS_ERROR; } else ulErrBuf += ul; } } hb_vmLock(); } if( hStdin != FS_ERROR ) hb_fsClose( hStdin ); if( hStdout != FS_ERROR ) hb_fsClose( hStdout ); if( hStderr != FS_ERROR ) hb_fsClose( hStderr ); iResult = hb_fsProcessValue( hProcess, TRUE ); #else int TODO; HB_SYMBOL_UNUSED( ulStdInLen ); #endif } } #endif if( phStdout ) { *pStdOutPtr = pOutBuf; *pulStdOut = ulOutBuf; } if( phStderr ) { *pStdErrPtr = pErrBuf; *pulStdErr = ulErrBuf; } return iResult; } /* temporary hack for still missing sysconf() in Watcom 1.8 */ #if defined( HB_OS_LINUX ) && defined( __WATCOMC__ ) _WCRTLINK long sysconf( int __name ) { int iTODO; switch( __name ) { case _SC_OPEN_MAX: return 1024; case _SC_CLK_TCK: return 100; case /* _SC_PAGE_SIZE */ 30: return 4096; } return -1; } #endif