Example #1
0
HB_FHANDLE hb_fsProcessOpen( const char * pszFileName,
                             HB_FHANDLE * phStdin, HB_FHANDLE * phStdout,
                             HB_FHANDLE * phStderr,
                             HB_BOOL fDetach, HB_ULONG * pulPID )
{
   HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR },
              hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR },
              hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR };
   HB_FHANDLE hResult = FS_ERROR;
   HB_ERRCODE errCode;
   HB_BOOL fError = HB_FALSE;

   HB_TRACE( HB_TR_DEBUG, ( "hb_fsProcessOpen(%s, %p, %p, %p, %d, %p)", pszFileName, phStdin, phStdout, phStderr, fDetach, pulPID ) );

   if( phStdin != NULL )
      fError = ! hb_fsPipeCreate( hPipeIn );
   if( ! fError && phStdout != NULL )
      fError = ! hb_fsPipeCreate( hPipeOut );
   if( ! fError && phStderr != NULL )
   {
      if( phStdout == phStderr )
      {
         hPipeErr[ 0 ] = hPipeOut[ 0 ];
         hPipeErr[ 1 ] = hPipeOut[ 1 ];
      }
      else
         fError = ! hb_fsPipeCreate( hPipeErr );
   }

   if( ! fError )
   {
#if defined( HB_OS_WIN )

      PROCESS_INFORMATION pi;
      STARTUPINFO si;
      DWORD dwFlags = 0;
      LPTSTR lpCommand = HB_CHARDUP( pszFileName );

#  if ! defined( HB_OS_WIN_CE )
      if( phStdin != NULL )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 1 ] ), HANDLE_FLAG_INHERIT, 0 );
      if( phStdout != NULL )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 0 ] ), HANDLE_FLAG_INHERIT, 0 );
      if( phStderr != NULL && phStdout != phStderr )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 0 ] ), HANDLE_FLAG_INHERIT, 0 );
#  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  = ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 0 ] );
         si.hStdOutput = ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 1 ] );
         si.hStdError  = ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 1 ] );
#  ifdef DETACHED_PROCESS
         dwFlags |= DETACHED_PROCESS;
#  endif
      }
      else
      {
         si.hStdInput  = phStdin  ? ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 0 ] ) : GetStdHandle( STD_INPUT_HANDLE );
         si.hStdOutput = phStdout ? ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 1 ] ) : GetStdHandle( STD_OUTPUT_HANDLE );
         si.hStdError  = phStderr ? ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 1 ] ) : 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 ) 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 = pi.dwProcessId;
         CloseHandle( pi.hThread );
         hResult = ( HB_FHANDLE ) pi.hProcess;
      }

#elif defined( HB_OS_OS2 )

      HFILE hNull = ( HFILE ) FS_ERROR;
      ULONG ulState = 0;
      APIRET ret = NO_ERROR;
      PID pid = ( PID ) -1;
      PHB_GT pGT;

      if( fDetach && ( ! phStdin || ! phStdout || ! phStderr ) )
      {
         HB_FHANDLE hFile;

         ret = hb_fsOS2DosOpen( "NUL:", &hFile, &ulState, 0,
                                FILE_NORMAL, OPEN_ACCESS_READWRITE,
                                OPEN_ACTION_OPEN_IF_EXISTS );
         if( ret == NO_ERROR )
            hNull = ( HFILE ) hFile;
      }

      if( ret == NO_ERROR && phStdin != NULL )
      {
         ret = DosQueryFHState( hPipeIn[ 1 ], &ulState );
         if( ret == NO_ERROR && ( ulState & OPEN_FLAGS_NOINHERIT ) == 0 )
            ret = DosSetFHState( hPipeIn[ 1 ], ( ulState & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
      }
      if( ret == NO_ERROR && phStdout != NULL )
      {
         ret = DosQueryFHState( hPipeOut[ 0 ], &ulState );
         if( ret == NO_ERROR && ( ulState & OPEN_FLAGS_NOINHERIT ) == 0 )
            ret = DosSetFHState( hPipeOut[ 0 ], ( ulState & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
      }
      if( ret == NO_ERROR && phStderr != NULL && phStdout != phStderr )
      {
         ret = DosQueryFHState( hPipeErr[ 0 ], &ulState );
         if( ret == NO_ERROR && ( ulState & OPEN_FLAGS_NOINHERIT ) == 0 )
            ret = DosSetFHState( hPipeErr[ 0 ], ( ulState & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
      }

      if( ret == NO_ERROR && ( pGT = hb_gt_Base() ) != NULL )
      {
         ULONG ulStateIn, ulStateOut, ulStateErr;
         HFILE hStdIn, hStdErr, hStdOut, hDup;

         ulStateIn = ulStateOut = ulStateErr = OPEN_FLAGS_NOINHERIT;
         hStdIn  = hStdErr = hStdOut = ( HFILE ) FS_ERROR;

         if( ret == NO_ERROR && ( phStdin != NULL || fDetach ) )
         {
            hDup = 0;
            ret = DosDupHandle( hDup, &hStdIn );
            if( ret == NO_ERROR )
            {
               ret = DosQueryFHState( hStdIn, &ulStateIn );
               if( ret == NO_ERROR && ( ulStateIn & OPEN_FLAGS_NOINHERIT ) == 0 )
                  ret = DosSetFHState( hStdIn, ( ulStateIn & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
               if( ret == NO_ERROR )
                  ret = DosDupHandle( phStdin != NULL ? ( HFILE ) hPipeIn[ 0 ] : hNull, &hDup );
            }
         }

         if( ret == NO_ERROR && ( phStdout != NULL || fDetach ) )
         {
            hDup = 1;
            ret = DosDupHandle( hDup, &hStdOut );
            if( ret == NO_ERROR )
            {
               ret = DosQueryFHState( hStdOut, &ulStateOut );
               if( ret == NO_ERROR && ( ulStateOut & OPEN_FLAGS_NOINHERIT ) == 0 )
                  ret = DosSetFHState( hStdOut, ( ulStateOut & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
               if( ret == NO_ERROR )
                  ret = DosDupHandle( phStdout != NULL ? ( HFILE ) hPipeOut[ 1 ] : hNull, &hDup );
            }
         }

         if( ret == NO_ERROR && ( phStderr != NULL || fDetach ) )
         {
            hDup = 2;
            ret = DosDupHandle( hDup, &hStdErr );
            if( ret == NO_ERROR )
            {
               ret = DosQueryFHState( hStdErr, &ulStateErr );
               if( ret == NO_ERROR && ( ulStateErr & OPEN_FLAGS_NOINHERIT ) == 0 )
                  ret = DosSetFHState( hStdErr, ( ulStateErr & 0xFF00 ) | OPEN_FLAGS_NOINHERIT );
               if( ret == NO_ERROR )
                  ret = DosDupHandle( phStderr != NULL ? ( HFILE ) hPipeErr[ 1 ] : hNull, &hDup );
            }
         }

         if( ret == NO_ERROR )
         {
            char * pArgs = hb_buildArgsOS2( pszFileName, &ret );
            char uchLoadError[ CCHMAXPATH ] = { 0 };
            RESULTCODES ChildRC = { 0, 0 };

            if( pArgs )
            {
               ret = DosExecPgm( uchLoadError, sizeof( uchLoadError ),
                                 fDetach ? EXEC_BACKGROUND : EXEC_ASYNCRESULT,
                                 ( PCSZ ) pArgs, NULL /* env */,
                                 &ChildRC,
                                 ( PCSZ ) pArgs );
               if( ret == NO_ERROR )
                  pid = ChildRC.codeTerminate;
               hb_freeArgsOS2( pArgs );
            }
         }

         if( hNull != ( HFILE ) FS_ERROR )
            DosClose( hNull );

         if( hStdIn != ( HFILE ) FS_ERROR )
         {
            hDup = 0;
            DosDupHandle( hStdIn, &hDup );
            DosClose( hStdIn );
            if( ( ulStateIn & OPEN_FLAGS_NOINHERIT ) == 0 )
               DosSetFHState( hDup, ulStateIn & 0xFF00 );
         }
         if( hStdOut != ( HFILE ) FS_ERROR )
         {
            hDup = 1;
            DosDupHandle( hStdOut, &hDup );
            DosClose( hStdOut );
            if( ( ulStateOut & OPEN_FLAGS_NOINHERIT ) == 0 )
               DosSetFHState( hDup, ulStateOut & 0xFF00 );
         }
         if( hStdErr != ( HFILE ) FS_ERROR )
         {
            hDup = 2;
            DosDupHandle( hStdErr, &hDup );
            DosClose( hStdErr );
            if( ( ulStateErr & OPEN_FLAGS_NOINHERIT ) == 0 )
               DosSetFHState( hDup, ulStateErr & 0xFF00 );
         }

         hb_gt_BaseFree( pGT );
      }
      else
      {
         if( hNull != ( HFILE ) FS_ERROR )
            DosClose( hNull );
         if( ret == NO_ERROR )
            ret = ( APIRET ) FS_ERROR;
      }

      fError = ret != NO_ERROR;
      if( ! fError )
      {
         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_fsSetError( ( HB_ERRCODE ) ret );

#elif defined( HB_OS_UNIX ) && \
      ! defined( HB_OS_VXWORKS ) && ! defined( HB_OS_SYMBIAN )

      char ** argv = hb_buildArgs( pszFileName );
      pid_t pid = fork();

      if( pid == -1 )
         fError = HB_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 )
               hb_fsClose( hNull );
         }

         if( phStdin != NULL )
         {
            dup2( hPipeIn[ 0 ], 0 );
            hb_fsClose( hPipeIn[ 1 ] );
         }
         if( phStdout != NULL )
         {
            dup2( hPipeOut[ 1 ], 1 );
            hb_fsClose( hPipeOut[ 0 ] );
         }
         if( phStderr != NULL )
         {
            dup2( hPipeErr[ 1 ], 2 );
            if( phStdout != phStderr )
               hb_fsClose( hPipeErr[ 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 )
               hb_fsClose( i );
         }

         /* reset extended process attributes */
         if( setuid( getuid() ) == -1 ) {}
         if( setgid( getgid() ) == -1 ) {}

         /* execute command */
         {
#  if defined( __WATCOMC__ )
            execvp( argv[ 0 ], ( const char ** ) argv );
#  else
            execvp( argv[ 0 ], argv );
#  endif
            exit( -1 );
         }
      }
      hb_fsSetIOError( ! fError, 0 );

      hb_freeArgs( argv );

#elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN )

      int hStdIn, hStdOut, hStdErr;
      char ** argv;
      int 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__ ) || defined( __WATCOMC__ )
      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 );
      close( hStdIn );

      dup2( hStdOut, 1 );
      close( hStdOut );

      dup2( hStdErr, 2 );
      close( hStdErr );

      if( pid < 0 )
         fError = HB_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 );

#else
      int iTODO; /* TODO: for given platform */

      HB_SYMBOL_UNUSED( pszFileName );
      HB_SYMBOL_UNUSED( fDetach );
      HB_SYMBOL_UNUSED( pulPID );

      hb_fsSetError( ( HB_ERRCODE ) FS_ERROR );
#endif
   }

   errCode = hb_fsError();

   if( hPipeIn[ 0 ] != FS_ERROR )
      hb_fsClose( hPipeIn[ 0 ] );
   if( hPipeIn[ 1 ] != FS_ERROR )
      hb_fsClose( hPipeIn[ 1 ] );
   if( hPipeOut[ 0 ] != FS_ERROR )
      hb_fsClose( hPipeOut[ 0 ] );
   if( hPipeOut[ 1 ] != FS_ERROR )
      hb_fsClose( hPipeOut[ 1 ] );
   if( phStdout != phStderr )
   {
      if( hPipeErr[ 0 ] != FS_ERROR )
         hb_fsClose( hPipeErr[ 0 ] );
      if( hPipeErr[ 1 ] != FS_ERROR )
         hb_fsClose( hPipeErr[ 1 ] );
   }

   hb_fsSetError( errCode );

   return hResult;
}
Example #2
0
HB_FHANDLE hb_fsProcessOpen( const char * pszFilename,
                             HB_FHANDLE * phStdin, HB_FHANDLE * phStdout,
                             HB_FHANDLE * phStderr,
                             HB_BOOL fDetach, HB_ULONG * pulPID )
{
   HB_FHANDLE hPipeIn [ 2 ] = { FS_ERROR, FS_ERROR },
              hPipeOut[ 2 ] = { FS_ERROR, FS_ERROR },
              hPipeErr[ 2 ] = { FS_ERROR, FS_ERROR };
   HB_FHANDLE hResult = FS_ERROR;
   HB_BOOL fError = HB_FALSE;

   HB_TRACE( HB_TR_DEBUG, ( "hb_fsProcessOpen(%s, %p, %p, %p, %d, %p)", pszFilename, phStdin, phStdout, phStderr, fDetach, pulPID ) );

   if( phStdin != NULL )
      fError = ! hb_fsPipeCreate( hPipeIn );
   if( ! fError && phStdout != NULL )
      fError = ! hb_fsPipeCreate( hPipeOut );
   if( ! fError && phStderr != NULL )
   {
      if( phStdout == phStderr )
      {
         hPipeErr[ 0 ] = hPipeOut[ 0 ];
         hPipeErr[ 1 ] = hPipeOut[ 1 ];
      }
      else
         fError = ! hb_fsPipeCreate( hPipeErr );
   }

   if( ! fError )
   {
#if defined( HB_OS_WIN )

      PROCESS_INFORMATION pi;
      STARTUPINFO si;
      DWORD dwFlags = 0;
      LPTSTR lpCommand = HB_CHARDUP( pszFilename );

#  if ! defined( HB_OS_WIN_CE )
      if( phStdin != NULL )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 1 ] ), HANDLE_FLAG_INHERIT, 0 );
      if( phStdout != NULL )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 0 ] ), HANDLE_FLAG_INHERIT, 0 );
      if( phStderr != NULL && phStdout != phStderr )
         SetHandleInformation( ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 0 ] ), HANDLE_FLAG_INHERIT, 0 );
#  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  = ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 0 ] );
         si.hStdOutput = ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 1 ] );
         si.hStdError  = ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 1 ] );
#  ifdef DETACHED_PROCESS
         dwFlags |= DETACHED_PROCESS;
#  endif
      }
      else
      {
         si.hStdInput  = phStdin  ? ( HANDLE ) hb_fsGetOsHandle( hPipeIn [ 0 ] ) : GetStdHandle( STD_INPUT_HANDLE );
         si.hStdOutput = phStdout ? ( HANDLE ) hb_fsGetOsHandle( hPipeOut[ 1 ] ) : GetStdHandle( STD_OUTPUT_HANDLE );
         si.hStdError  = phStderr ? ( HANDLE ) hb_fsGetOsHandle( hPipeErr[ 1 ] ) : 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 ) 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 = pi.dwProcessId;
         CloseHandle( pi.hThread );
         hResult = ( HB_FHANDLE ) pi.hProcess;
      }

#elif defined( HB_OS_UNIX ) && \
      ! defined( HB_OS_VXWORKS ) && ! defined( HB_OS_SYMBIAN )

      pid_t pid = fork();

      if( pid == -1 )
         fError = HB_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 )
               hb_fsClose( hNull );
         }

         if( phStdin != NULL )
         {
            dup2( hPipeIn[ 0 ], 0 );
            hb_fsClose( hPipeIn[ 1 ] );
         }
         if( phStdout != NULL )
         {
            dup2( hPipeOut[ 1 ], 1 );
            hb_fsClose( hPipeOut[ 0 ] );
         }
         if( phStderr != NULL )
         {
            dup2( hPipeErr[ 1 ], 2 );
            if( phStdout != phStderr )
               hb_fsClose( hPipeErr[ 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 )
               hb_fsClose( i );
         }

         /* reset extended process attributes */
         setuid( getuid() );
         setgid( getgid() );

         /* execute command */
         {
            char ** argv;

            argv = hb_buildArgs( pszFilename );
#  if defined( __WATCOMC__ )
            execvp( argv[ 0 ], ( const char ** ) argv );
#  else
            execvp( argv[ 0 ], argv );
#  endif
            hb_freeArgs( argv );
            exit( -1 );
         }
      }

#elif defined( HB_OS_OS2 ) || defined( HB_OS_WIN )

      int hStdIn, hStdOut, hStdErr;
      char ** argv;
      int 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__ ) || defined( __WATCOMC__ )
      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 );
      close( hStdIn );

      dup2( hStdOut, 1 );
      close( hStdOut );

      dup2( hStdErr, 2 );
      close( hStdErr );

      if( pid < 0 )
         fError = HB_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
   int iTODO; /* TODO: for given platform */

   HB_SYMBOL_UNUSED( pszFilename );
   HB_SYMBOL_UNUSED( fDetach );
   HB_SYMBOL_UNUSED( pulPID );

   hb_fsSetError( ( HB_ERRCODE ) FS_ERROR );
#endif
   }

   hb_fsSetIOError( ! fError, 0 );

   if( hPipeIn[ 0 ] != FS_ERROR )
      hb_fsClose( hPipeIn[ 0 ] );
   if( hPipeIn[ 1 ] != FS_ERROR )
      hb_fsClose( hPipeIn[ 1 ] );
   if( hPipeOut[ 0 ] != FS_ERROR )
      hb_fsClose( hPipeOut[ 0 ] );
   if( hPipeOut[ 1 ] != FS_ERROR )
      hb_fsClose( hPipeOut[ 1 ] );
   if( phStdout != phStderr )
   {
      if( hPipeErr[ 0 ] != FS_ERROR )
         hb_fsClose( hPipeErr[ 0 ] );
      if( hPipeErr[ 1 ] != FS_ERROR )
         hb_fsClose( hPipeErr[ 1 ] );
   }

   return hResult;
}