LCOV - code coverage report
Current view: directory - port - cpl_spawn.cpp (source / functions) Found Hit Coverage
Test: gdal_filtered.info Lines: 227 163 71.8 %
Date: 2013-03-30 Functions: 14 13 92.9 %

       1                 : /**********************************************************************
       2                 :  * $Id: cpl_spawn.cpp 25766 2013-03-18 21:16:36Z jorgearevalo $
       3                 :  *
       4                 :  * Project:  CPL - Common Portability Library
       5                 :  * Purpose:  Implement CPLSystem().
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  **********************************************************************
       9                 :  * Copyright (c) 2012,Even Rouault
      10                 :  *
      11                 :  * Permission is hereby granted, free of charge, to any person obtaining a
      12                 :  * copy of this software and associated documentation files (the "Software"),
      13                 :  * to deal in the Software without restriction, including without limitation
      14                 :  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      15                 :  * and/or sell copies of the Software, and to permit persons to whom the
      16                 :  * Software is furnished to do so, subject to the following conditions:
      17                 :  * 
      18                 :  * The above copyright notice and this permission notice shall be included
      19                 :  * in all copies or substantial portions of the Software.
      20                 :  * 
      21                 :  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      22                 :  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      23                 :  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
      24                 :  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      25                 :  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
      26                 :  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 
      27                 :  * DEALINGS IN THE SOFTWARE.
      28                 :  ****************************************************************************/
      29                 : 
      30                 : #include "cpl_spawn.h"
      31                 : 
      32                 : #include "cpl_error.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : #include "cpl_multiproc.h"
      36                 : 
      37                 : #define PIPE_BUFFER_SIZE    4096
      38                 : 
      39                 : #define IN_FOR_PARENT   0
      40                 : #define OUT_FOR_PARENT  1
      41                 : 
      42                 : CPL_CVSID("$Id: cpl_spawn.cpp 25766 2013-03-18 21:16:36Z jorgearevalo $");
      43                 : 
      44                 : static void FillFileFromPipe(CPL_FILE_HANDLE pipe_fd, VSILFILE* fout);
      45                 : 
      46                 : //int CPL_DLL CPLSystem( const char* pszApplicationName, const char* pszCommandLine );
      47                 : 
      48                 : /************************************************************************/
      49                 : /*                        FillPipeFromFile()                            */
      50                 : /************************************************************************/
      51                 : 
      52               6 : static void FillPipeFromFile(VSILFILE* fin, CPL_FILE_HANDLE pipe_fd)
      53                 : {
      54                 :     char buf[PIPE_BUFFER_SIZE];
      55               3 :     while(TRUE)
      56                 :     {
      57               6 :         int nRead = (int)VSIFReadL(buf, 1, PIPE_BUFFER_SIZE, fin);
      58               6 :         if( nRead <= 0 )
      59               3 :             break;
      60               3 :         if (!CPLPipeWrite(pipe_fd, buf, nRead))
      61               0 :             break;
      62                 :     }
      63               3 : }
      64                 : 
      65                 : /************************************************************************/
      66                 : /*                            CPLSpawn()                                */
      67                 : /************************************************************************/
      68                 : 
      69                 : /**
      70                 :  * Runs an executable in another process.
      71                 :  *
      72                 :  * This function runs an executable, wait for it to finish and returns
      73                 :  * its exit code.
      74                 :  *
      75                 :  * It is implemented as CreateProcess() on Windows platforms, and fork()/exec()
      76                 :  * on other platforms.
      77                 :  *
      78                 :  * @param papszArgv argument list of the executable to run. papszArgv[0] is the
      79                 :  *                  name of the executable
      80                 :  * @param fin File handle for input data to feed to the standard input of the
      81                 :  *            sub-process. May be NULL.
      82                 :  * @param fout File handle for output data to extract from the standard output of the
      83                 :  *            sub-process. May be NULL.
      84                 :  * @param bDisplayErr Set to TRUE to emit the content of the standard error stream of
      85                 :  *                    the sub-process with CPLError().
      86                 :  *
      87                 :  * @return the exit code of the spawned process, or -1 in case of error.
      88                 :  *
      89                 :  * @since GDAL 1.10.0
      90                 :  */
      91                 : 
      92               7 : int CPLSpawn(const char * const papszArgv[], VSILFILE* fin, VSILFILE* fout,
      93                 :              int bDisplayErr)
      94                 : {
      95               7 :     CPLSpawnedProcess* sp = CPLSpawnAsync(NULL, papszArgv, TRUE, TRUE, TRUE, NULL);
      96               7 :     if( sp == NULL )
      97               0 :         return -1;
      98                 : 
      99               7 :     CPL_FILE_HANDLE in_child = CPLSpawnAsyncGetOutputFileHandle(sp);
     100               7 :     if (fin != NULL)
     101               3 :         FillPipeFromFile(fin, in_child);
     102               7 :     CPLSpawnAsyncCloseOutputFileHandle(sp);
     103                 : 
     104               7 :     CPL_FILE_HANDLE out_child = CPLSpawnAsyncGetInputFileHandle(sp);
     105               7 :     if (fout != NULL)
     106               7 :         FillFileFromPipe(out_child, fout);
     107               7 :     CPLSpawnAsyncCloseInputFileHandle(sp);
     108                 : 
     109               7 :     CPL_FILE_HANDLE err_child = CPLSpawnAsyncGetErrorFileHandle(sp);
     110               7 :     CPLString osName;
     111               7 :     osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID());
     112               7 :     VSILFILE* ferr = VSIFOpenL(osName.c_str(), "w");
     113                 : 
     114               7 :     FillFileFromPipe(err_child, ferr);
     115               7 :     CPLSpawnAsyncCloseErrorFileHandle(sp);
     116                 : 
     117               7 :     VSIFCloseL(ferr);
     118               7 :     vsi_l_offset nDataLength = 0;
     119               7 :     GByte* pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE);
     120               7 :     if( nDataLength > 0 )
     121               0 :         pData[nDataLength-1] = '\0';
     122               7 :     if( pData && strstr((const char*)pData, "An error occured while forking process") != NULL )
     123               0 :         bDisplayErr = TRUE;
     124               7 :     if( pData && bDisplayErr )
     125               0 :         CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", papszArgv[0], pData);
     126               7 :     CPLFree(pData);
     127                 : 
     128               7 :     return CPLSpawnAsyncFinish(sp, TRUE, FALSE);
     129                 : }
     130                 : 
     131                 : #if defined(WIN32)
     132                 : 
     133                 : #include <windows.h>
     134                 : 
     135                 : #if 0
     136                 : /************************************************************************/
     137                 : /*                            CPLSystem()                               */
     138                 : /************************************************************************/
     139                 : 
     140                 : int CPLSystem( const char* pszApplicationName, const char* pszCommandLine )
     141                 : {
     142                 :     int nRet = -1;
     143                 :     PROCESS_INFORMATION processInfo;
     144                 :     STARTUPINFO startupInfo;
     145                 :     ZeroMemory( &processInfo, sizeof(PROCESS_INFORMATION) );
     146                 :     ZeroMemory( &startupInfo, sizeof(STARTUPINFO) );
     147                 :     startupInfo.cb = sizeof(STARTUPINFO);
     148                 : 
     149                 :     char* pszDupedCommandLine = (pszCommandLine) ? CPLStrdup(pszCommandLine) : NULL;
     150                 : 
     151                 :     if( !CreateProcess( pszApplicationName, 
     152                 :                         pszDupedCommandLine, 
     153                 :                         NULL,
     154                 :                         NULL,
     155                 :                         FALSE,
     156                 :                         CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,
     157                 :                         NULL,
     158                 :                         NULL,
     159                 :                         &startupInfo,
     160                 :                         &processInfo) )
     161                 :     {
     162                 :         DWORD err = GetLastError();
     163                 :         CPLDebug("CPL", "'%s' failed : err = %d", pszCommandLine, (int)err);
     164                 :         nRet = -1;
     165                 :     }
     166                 :     else
     167                 :     {
     168                 :         WaitForSingleObject( processInfo.hProcess, INFINITE );
     169                 : 
     170                 :         DWORD exitCode;
     171                 : 
     172                 :         // Get the exit code.
     173                 :         int err = GetExitCodeProcess(processInfo.hProcess, &exitCode);
     174                 : 
     175                 :         CloseHandle(processInfo.hProcess);
     176                 :         CloseHandle(processInfo.hThread);
     177                 : 
     178                 :         if( !err )
     179                 :         {
     180                 :             CPLDebug("CPL", "GetExitCodeProcess() failed : err = %d", err);
     181                 :         }
     182                 :         else
     183                 :             nRet = exitCode;
     184                 :     }
     185                 : 
     186                 :     CPLFree(pszDupedCommandLine);
     187                 : 
     188                 :     return nRet;
     189                 : }
     190                 : #endif
     191                 : 
     192                 : /************************************************************************/
     193                 : /*                          CPLPipeRead()                               */
     194                 : /************************************************************************/
     195                 : 
     196                 : int CPLPipeRead(CPL_FILE_HANDLE fin, void* data, int length)
     197                 : {
     198                 :     GByte* pabyData = (GByte*)data;
     199                 :     int nRemain = length;
     200                 :     while( nRemain > 0 )
     201                 :     {
     202                 :         DWORD nRead = 0;
     203                 :         if (!ReadFile( fin, pabyData, nRemain, &nRead, NULL))
     204                 :             return FALSE;
     205                 :         pabyData += nRead;
     206                 :         nRemain -= nRead;
     207                 :     }
     208                 :     return TRUE;
     209                 : }
     210                 : 
     211                 : /************************************************************************/
     212                 : /*                         CPLPipeWrite()                               */
     213                 : /************************************************************************/
     214                 : 
     215                 : int CPLPipeWrite(CPL_FILE_HANDLE fout, const void* data, int length)
     216                 : {
     217                 :     const GByte* pabyData = (const GByte*)data;
     218                 :     int nRemain = length;
     219                 :     while( nRemain > 0 )
     220                 :     {
     221                 :         DWORD nWritten = 0;
     222                 :         if (!WriteFile(fout, pabyData, nRemain, &nWritten, NULL))
     223                 :             return FALSE;
     224                 :         pabyData += nWritten;
     225                 :         nRemain -= nWritten;
     226                 :     }
     227                 :     return TRUE;
     228                 : }
     229                 : 
     230                 : /************************************************************************/
     231                 : /*                        FillFileFromPipe()                            */
     232                 : /************************************************************************/
     233                 : 
     234                 : static void FillFileFromPipe(CPL_FILE_HANDLE pipe_fd, VSILFILE* fout)
     235                 : {
     236                 :     char buf[PIPE_BUFFER_SIZE];
     237                 :     while(TRUE)
     238                 :     {
     239                 :         DWORD nRead;
     240                 :         if (!ReadFile( pipe_fd, buf, PIPE_BUFFER_SIZE, &nRead, NULL))
     241                 :             break;
     242                 :         if (nRead <= 0)
     243                 :             break;
     244                 :         int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
     245                 :         if (nWritten < (int)nRead)
     246                 :             break;
     247                 :     }
     248                 : }
     249                 : 
     250                 : struct _CPLSpawnedProcess
     251                 : {
     252                 :     HANDLE hProcess;
     253                 :     DWORD  nProcessId;
     254                 :     HANDLE hThread;
     255                 :     CPL_FILE_HANDLE fin;
     256                 :     CPL_FILE_HANDLE fout;
     257                 :     CPL_FILE_HANDLE ferr;
     258                 : };
     259                 : 
     260                 : /************************************************************************/
     261                 : /*                            CPLSpawnAsync()                           */
     262                 : /************************************************************************/
     263                 : 
     264                 : CPLSpawnedProcess* CPLSpawnAsync(int (*pfnMain)(CPL_FILE_HANDLE, CPL_FILE_HANDLE),
     265                 :                                  const char * const papszArgv[],
     266                 :                                  int bCreateInputPipe,
     267                 :                                  int bCreateOutputPipe,
     268                 :                                  int bCreateErrorPipe,
     269                 :                                  char** papszOptions)
     270                 : {
     271                 :     HANDLE pipe_in[2] = {NULL, NULL};
     272                 :     HANDLE pipe_out[2] = {NULL, NULL};
     273                 :     HANDLE pipe_err[2] = {NULL, NULL};
     274                 :     SECURITY_ATTRIBUTES saAttr;
     275                 :     PROCESS_INFORMATION piProcInfo;
     276                 :     STARTUPINFO siStartInfo;
     277                 :     CPLString osCommandLine;
     278                 :     int i;
     279                 :     CPLSpawnedProcess* p = NULL;
     280                 : 
     281                 :     if( papszArgv == NULL )
     282                 :     {
     283                 :         CPLError(CE_Failure, CPLE_AppDefined,
     284                 :                  "On Windows, papszArgv argument must not be NULL");
     285                 :         return NULL;
     286                 :     }
     287                 : 
     288                 :     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
     289                 :     saAttr.bInheritHandle = TRUE;
     290                 :     saAttr.lpSecurityDescriptor = NULL;
     291                 : 
     292                 :     if( bCreateInputPipe )
     293                 :     {
     294                 :         if (!CreatePipe(&pipe_in[IN_FOR_PARENT],&pipe_in[OUT_FOR_PARENT],&saAttr, 0))
     295                 :             goto err_pipe;
     296                 :         /* The child must not inherit from the write side of the pipe_in */
     297                 :         if (!SetHandleInformation(pipe_in[OUT_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     298                 :             goto err_pipe;
     299                 :     }
     300                 : 
     301                 :     if( bCreateOutputPipe )
     302                 :     {
     303                 :         if (!CreatePipe(&pipe_out[IN_FOR_PARENT],&pipe_out[OUT_FOR_PARENT],&saAttr, 0))
     304                 :             goto err_pipe;
     305                 :         /* The child must not inherit from the read side of the pipe_out */
     306                 :         if (!SetHandleInformation(pipe_out[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     307                 :             goto err_pipe;
     308                 :     }
     309                 : 
     310                 :     if( bCreateErrorPipe )
     311                 :     {
     312                 :         if (!CreatePipe(&pipe_err[IN_FOR_PARENT],&pipe_err[OUT_FOR_PARENT],&saAttr, 0))
     313                 :             goto err_pipe;
     314                 :         /* The child must not inherit from the read side of the pipe_err */
     315                 :         if (!SetHandleInformation(pipe_err[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     316                 :             goto err_pipe;
     317                 :     }
     318                 : 
     319                 :     memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
     320                 :     memset(&siStartInfo, 0, sizeof(STARTUPINFO));
     321                 :     siStartInfo.cb = sizeof(STARTUPINFO); 
     322                 :     siStartInfo.hStdInput = (bCreateInputPipe) ? pipe_in[IN_FOR_PARENT] : GetStdHandle(STD_INPUT_HANDLE);
     323                 :     siStartInfo.hStdOutput = (bCreateOutputPipe) ? pipe_out[OUT_FOR_PARENT] : GetStdHandle(STD_OUTPUT_HANDLE);
     324                 :     siStartInfo.hStdError = (bCreateErrorPipe) ? pipe_err[OUT_FOR_PARENT] : GetStdHandle(STD_ERROR_HANDLE);
     325                 :     siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
     326                 : 
     327                 :     for(i=0;papszArgv[i] != NULL;i++)
     328                 :     {
     329                 :         if (i > 0)
     330                 :             osCommandLine += " ";
     331                 :         osCommandLine += papszArgv[i];
     332                 :     }
     333                 : 
     334                 :     if (!CreateProcess(NULL, 
     335                 :                        (CHAR*)osCommandLine.c_str(),
     336                 :                        NULL,          // process security attributes 
     337                 :                        NULL,          // primary thread security attributes 
     338                 :                        TRUE,          // handles are inherited 
     339                 :                        CREATE_NO_WINDOW|NORMAL_PRIORITY_CLASS,             // creation flags 
     340                 :                        NULL,          // use parent's environment 
     341                 :                        NULL,          // use parent's current directory 
     342                 :                        &siStartInfo,
     343                 :                        &piProcInfo))
     344                 :     {
     345                 :         CPLError(CE_Failure, CPLE_AppDefined, "Could not create process %s",
     346                 :                  osCommandLine.c_str());
     347                 :         goto err;
     348                 :     }
     349                 : 
     350                 :     /* Close unused end of pipe */
     351                 :     if( bCreateInputPipe )
     352                 :         CloseHandle(pipe_in[IN_FOR_PARENT]);
     353                 :     if( bCreateOutputPipe )
     354                 :         CloseHandle(pipe_out[OUT_FOR_PARENT]);
     355                 :     if( bCreateErrorPipe )
     356                 :         CloseHandle(pipe_err[OUT_FOR_PARENT]);
     357                 : 
     358                 :     p = (CPLSpawnedProcess*)CPLMalloc(sizeof(CPLSpawnedProcess));
     359                 :     p->hProcess = piProcInfo.hProcess;
     360                 :     p->nProcessId = piProcInfo.dwProcessId;
     361                 :     p->hThread = piProcInfo.hThread;
     362                 :     p->fin = pipe_out[IN_FOR_PARENT];
     363                 :     p->fout = pipe_in[OUT_FOR_PARENT];
     364                 :     p->ferr = pipe_err[IN_FOR_PARENT];
     365                 :     return p;
     366                 : 
     367                 : err_pipe:
     368                 :     CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
     369                 : err:
     370                 :     for(i=0;i<2;i++)
     371                 :     {
     372                 :         if (pipe_in[i] != NULL)
     373                 :             CloseHandle(pipe_in[i]);
     374                 :         if (pipe_out[i] != NULL)
     375                 :             CloseHandle(pipe_out[i]);
     376                 :         if (pipe_err[i] != NULL)
     377                 :             CloseHandle(pipe_err[i]);
     378                 :     }
     379                 : 
     380                 :     return NULL;
     381                 : }
     382                 : 
     383                 : /************************************************************************/
     384                 : /*                  CPLSpawnAsyncGetChildProcessId()                    */
     385                 : /************************************************************************/
     386                 : 
     387                 : CPL_PID CPLSpawnAsyncGetChildProcessId(CPLSpawnedProcess* p)
     388                 : {
     389                 :     return p->nProcessId;
     390                 : }
     391                 : 
     392                 : /************************************************************************/
     393                 : /*                        CPLSpawnAsyncFinish()                         */
     394                 : /************************************************************************/
     395                 : 
     396                 : int CPLSpawnAsyncFinish(CPLSpawnedProcess* p, int bWait, int bKill)
     397                 : {
     398                 :     // Get the exit code.
     399                 :     DWORD exitCode = -1;
     400                 : 
     401                 :     if( bWait )
     402                 :     {
     403                 :         WaitForSingleObject( p->hProcess, INFINITE );
     404                 :         GetExitCodeProcess(p->hProcess, &exitCode);
     405                 :     }
     406                 :     else
     407                 :         exitCode = 0;
     408                 : 
     409                 :     CloseHandle(p->hProcess);
     410                 :     CloseHandle(p->hThread);
     411                 : 
     412                 :     CPLSpawnAsyncCloseInputFileHandle(p);
     413                 :     CPLSpawnAsyncCloseOutputFileHandle(p);
     414                 :     CPLSpawnAsyncCloseErrorFileHandle(p);
     415                 :     CPLFree(p);
     416                 : 
     417                 :     return (int)exitCode;
     418                 : }
     419                 : 
     420                 : /************************************************************************/
     421                 : /*                 CPLSpawnAsyncCloseInputFileHandle()                  */
     422                 : /************************************************************************/
     423                 : 
     424                 : void CPLSpawnAsyncCloseInputFileHandle(CPLSpawnedProcess* p)
     425                 : {
     426                 :     if( p->fin != NULL )
     427                 :         CloseHandle(p->fin);
     428                 :     p->fin = NULL;
     429                 : }
     430                 : 
     431                 : /************************************************************************/
     432                 : /*                 CPLSpawnAsyncCloseOutputFileHandle()                 */
     433                 : /************************************************************************/
     434                 : 
     435                 : void CPLSpawnAsyncCloseOutputFileHandle(CPLSpawnedProcess* p)
     436                 : {
     437                 :     if( p->fout != NULL )
     438                 :         CloseHandle(p->fout);
     439                 :     p->fout = NULL;
     440                 : }
     441                 : 
     442                 : /************************************************************************/
     443                 : /*                 CPLSpawnAsyncCloseErrorFileHandle()                  */
     444                 : /************************************************************************/
     445                 : 
     446                 : void CPLSpawnAsyncCloseErrorFileHandle(CPLSpawnedProcess* p)
     447                 : {
     448                 :     if( p->ferr != NULL )
     449                 :         CloseHandle(p->ferr);
     450                 :     p->ferr = NULL;
     451                 : }
     452                 : 
     453                 : #else
     454                 : 
     455                 : #include <unistd.h>
     456                 : #include <stdio.h>
     457                 : #include <stdlib.h>
     458                 : #include <sys/types.h>
     459                 : #include <sys/wait.h>
     460                 : #include <errno.h>
     461                 : #include <signal.h>
     462                 : #ifdef HAVE_POSIX_SPAWNP
     463                 : #include <spawn.h>
     464                 : #ifdef __APPLE__
     465                 : #include <crt_externs.h>
     466                 : #define environ (*_NSGetEnviron())
     467                 : #else
     468                 : extern char** environ;
     469                 : #endif
     470                 : #endif
     471                 : 
     472                 : #if 0
     473                 : /************************************************************************/
     474                 : /*                            CPLSystem()                               */
     475                 : /************************************************************************/
     476                 : 
     477                 : /**
     478                 :  * Runs an executable in another process.
     479                 :  *
     480                 :  * This function runs an executable, wait for it to finish and returns
     481                 :  * its exit code.
     482                 :  *
     483                 :  * It is implemented as CreateProcess() on Windows platforms, and system()
     484                 :  * on other platforms.
     485                 :  *
     486                 :  * @param pszApplicationName the lpApplicationName for Windows (might be NULL),
     487                 :  *                           or ignored on other platforms.
     488                 :  * @param pszCommandLine the command line, starting with the executable name 
     489                 :  *
     490                 :  * @return the exit code of the spawned process, or -1 in case of error.
     491                 :  *
     492                 :  * @since GDAL 1.10.0
     493                 :  */
     494                 : 
     495                 : int CPLSystem( const char* pszApplicationName, const char* pszCommandLine )
     496                 : {
     497                 :     return system(pszCommandLine);
     498                 : }
     499                 : #endif
     500                 : 
     501                 : /************************************************************************/
     502                 : /*                          CPLPipeRead()                               */
     503                 : /************************************************************************/
     504                 : 
     505                 : /**
     506                 :  * Read data from the standard output of a forked process.
     507                 :  *
     508                 :  * @param p handle returned by CPLSpawnAsyncGetInputFileHandle().
     509                 :  * @param data buffer in which to write.
     510                 :  * @param length number of bytes to read.
     511                 :  *
     512                 :  * @return TRUE in case of success.
     513                 :  *
     514                 :  * @since GDAL 1.10.0
     515                 :  */
     516            1283 : int CPLPipeRead(CPL_FILE_HANDLE fin, void* data, int length)
     517                 : {
     518            1283 :     GByte* pabyData = (GByte*)data;
     519            1283 :     int nRemain = length;
     520            3849 :     while( nRemain > 0 )
     521                 :     {
     522               0 :         while(TRUE)
     523                 :         {
     524            1283 :             int n = read(fin, pabyData, nRemain);
     525            1283 :             if( n < 0 )
     526                 :             {
     527               0 :                 if( errno == EINTR )
     528               0 :                     continue;
     529                 :                 else
     530               0 :                     return FALSE;
     531                 :             }
     532            1283 :             else if( n == 0 )
     533               0 :                 return FALSE;
     534            1283 :             pabyData += n;
     535            1283 :             nRemain -= n;
     536            1283 :             break;
     537                 :         }
     538                 :     }
     539            1283 :     return TRUE;
     540                 : }
     541                 : 
     542                 : /************************************************************************/
     543                 : /*                          CPLPipeWrite()                              */
     544                 : /************************************************************************/
     545                 : 
     546                 : /**
     547                 :  * Write data to the standard input of a forked process.
     548                 :  *
     549                 :  * @param fout handle returned by CPLSpawnAsyncGetOutputFileHandle().
     550                 :  * @param data buffer from which to read.
     551                 :  * @param length number of bytes to write.
     552                 :  *
     553                 :  * @return TRUE in case of success.
     554                 :  *
     555                 :  * @since GDAL 1.10.0
     556                 :  */
     557             243 : int CPLPipeWrite(CPL_FILE_HANDLE fout, const void* data, int length)
     558                 : {
     559             243 :     const GByte* pabyData = (const GByte*)data;
     560             243 :     int nRemain = length;
     561             729 :     while( nRemain > 0 )
     562                 :     {
     563               0 :         while(TRUE)
     564                 :         {
     565             243 :             int n = write(fout, pabyData, nRemain);
     566             243 :             if( n < 0 )
     567                 :             {
     568               0 :                 if( errno == EINTR )
     569               0 :                     continue;
     570                 :                 else
     571               0 :                     return FALSE;
     572                 :             }
     573             243 :             pabyData += n;
     574             243 :             nRemain -= n;
     575             243 :             break;
     576                 :         }
     577                 :     }
     578             243 :     return TRUE;
     579                 : }
     580                 : 
     581                 : /************************************************************************/
     582                 : /*                          FillFileFromPipe()                              */
     583                 : /************************************************************************/
     584                 : 
     585              21 : static void FillFileFromPipe(CPL_FILE_HANDLE pipe_fd, VSILFILE* fout)
     586                 : {
     587                 :     char buf[PIPE_BUFFER_SIZE];
     588               7 :     while(TRUE)
     589                 :     {
     590              21 :         int nRead = read(pipe_fd, buf, PIPE_BUFFER_SIZE);
     591              21 :         if (nRead <= 0)
     592              14 :             break;
     593               7 :         int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
     594               7 :         if (nWritten < nRead)
     595               0 :             break;
     596                 :     }
     597              14 : }
     598                 : 
     599                 : /************************************************************************/
     600                 : /*                            CPLSpawnAsync()                           */
     601                 : /************************************************************************/
     602                 : 
     603                 : struct _CPLSpawnedProcess
     604                 : {
     605                 :     pid_t pid;
     606                 :     CPL_FILE_HANDLE fin;
     607                 :     CPL_FILE_HANDLE fout;
     608                 :     CPL_FILE_HANDLE ferr;
     609                 : #ifdef HAVE_POSIX_SPAWNP
     610                 :     int bFreeActions;
     611                 :     posix_spawn_file_actions_t actions;
     612                 : #endif
     613                 : };
     614                 : 
     615                 : /**
     616                 :  * Runs an executable in another process (or fork the current process)
     617                 :  * and return immediately.
     618                 :  *
     619                 :  * This function launches an executable and returns immediately, while letting
     620                 :  * the sub-process to run asynchronously.
     621                 :  *
     622                 :  * It is implemented as CreateProcess() on Windows platforms, and fork()/exec()
     623                 :  * on other platforms.
     624                 :  *
     625                 :  * On Unix, a pointer of function can be provided to run in the child process,
     626                 :  * without exec()'ing a new executable.
     627                 :  *
     628                 :  * @param pfnMain the function to run in the child process (Unix only).
     629                 :  * @param papszArgv argument list of the executable to run. papszArgv[0] is the
     630                 :  *                  name of the executable.
     631                 :  * @param bCreateInputPipe set to TRUE to create a pipe for the child input stream.
     632                 :  * @param bCreateOutputPipe set to TRUE to create a pipe for the child output stream.
     633                 :  * @param bCreateErrorPipe set to TRUE to create a pipe for the child error stream.
     634                 :  *
     635                 :  * @return a handle, that must be freed with CPLSpawnAsyncFinish()
     636                 :  *
     637                 :  * @since GDAL 1.10.0
     638                 :  */
     639               9 : CPLSpawnedProcess* CPLSpawnAsync(int (*pfnMain)(CPL_FILE_HANDLE, CPL_FILE_HANDLE),
     640                 :                                  const char * const papszArgv[],
     641                 :                                  int bCreateInputPipe,
     642                 :                                  int bCreateOutputPipe,
     643                 :                                  int bCreateErrorPipe,
     644                 :                                  char** papszOptions)
     645                 : {
     646                 :     pid_t pid;
     647               9 :     int pipe_in[2] = { -1, -1 };
     648               9 :     int pipe_out[2] = { -1, -1 };
     649               9 :     int pipe_err[2] = { -1, -1 };
     650                 :     int i;
     651               9 :     char** papszArgvDup = CSLDuplicate((char**)papszArgv);
     652               9 :     int bDup2In = bCreateInputPipe,
     653               9 :         bDup2Out = bCreateOutputPipe,
     654               9 :         bDup2Err = bCreateErrorPipe;
     655                 : 
     656               9 :     if ((bCreateInputPipe && pipe(pipe_in)) ||
     657                 :         (bCreateOutputPipe && pipe(pipe_out)) ||
     658                 :         (bCreateErrorPipe && pipe(pipe_err)))
     659               0 :         goto err_pipe;
     660                 : 
     661                 :     /* If we don't do any file actions, posix_spawnp() might be implemented */
     662                 :     /* efficiently as a vfork()/exec() pair (or if it is not available, we */
     663                 :     /* can use vfork()/exec()), so if the child is cooperative */
     664                 :     /* we pass the pipe handles as commandline arguments */
     665               9 :     if( papszArgv != NULL )
     666                 :     {
     667              98 :         for(i=0; papszArgvDup[i] != NULL; i++)
     668                 :         {
     669              91 :             if( bCreateInputPipe && strcmp(papszArgvDup[i], "{pipe_in}") == 0 )
     670                 :             {
     671               0 :                 CPLFree(papszArgvDup[i]);
     672               0 :                 papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
     673               0 :                     pipe_in[IN_FOR_PARENT], pipe_in[OUT_FOR_PARENT]));
     674               0 :                 bDup2In = FALSE;
     675                 :             }
     676              91 :             else if( bCreateOutputPipe && strcmp(papszArgvDup[i], "{pipe_out}") == 0 )
     677                 :             {
     678               0 :                 CPLFree(papszArgvDup[i]);
     679               0 :                 papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
     680               0 :                     pipe_out[OUT_FOR_PARENT], pipe_out[IN_FOR_PARENT]));
     681               0 :                 bDup2Out = FALSE;
     682                 :             }
     683              91 :             else if( bCreateErrorPipe && strcmp(papszArgvDup[i], "{pipe_err}") == 0 )
     684                 :             {
     685               0 :                 CPLFree(papszArgvDup[i]);
     686               0 :                 papszArgvDup[i] = CPLStrdup(CPLSPrintf("%d,%d",
     687               0 :                     pipe_err[OUT_FOR_PARENT], pipe_err[IN_FOR_PARENT]));
     688               0 :                 bDup2Err = FALSE;
     689                 :             }
     690                 :         }
     691                 :     }
     692                 : 
     693                 : #ifdef HAVE_POSIX_SPAWNP
     694               9 :     if( papszArgv != NULL )
     695                 :     {
     696               7 :         int bHasActions = FALSE;
     697                 :         posix_spawn_file_actions_t actions;
     698                 : 
     699               7 :         if( bDup2In )
     700                 :         {
     701               7 :             if( !bHasActions ) posix_spawn_file_actions_init(&actions);
     702               7 :             posix_spawn_file_actions_adddup2(&actions, pipe_in[IN_FOR_PARENT], fileno(stdin));
     703               7 :             posix_spawn_file_actions_addclose(&actions, pipe_in[OUT_FOR_PARENT]);
     704               7 :             bHasActions = TRUE;
     705                 :         }
     706                 : 
     707               7 :         if( bDup2Out )
     708                 :         {
     709               7 :             if( !bHasActions ) posix_spawn_file_actions_init(&actions);
     710               7 :             posix_spawn_file_actions_adddup2(&actions, pipe_out[OUT_FOR_PARENT], fileno(stdout));
     711               7 :             posix_spawn_file_actions_addclose(&actions, pipe_out[IN_FOR_PARENT]);
     712               7 :             bHasActions = TRUE;
     713                 :         }
     714                 : 
     715               7 :         if( bDup2Err )
     716                 :         {
     717               7 :             if( !bHasActions ) posix_spawn_file_actions_init(&actions);
     718               7 :             posix_spawn_file_actions_adddup2(&actions, pipe_err[OUT_FOR_PARENT], fileno(stderr));
     719               7 :             posix_spawn_file_actions_addclose(&actions, pipe_err[IN_FOR_PARENT]);
     720               7 :             bHasActions = TRUE;
     721                 :         }
     722                 : 
     723               7 :         if( posix_spawnp(&pid, papszArgvDup[0],
     724                 :                          bHasActions ? &actions : NULL,
     725                 :                          NULL,
     726                 :                          (char* const*) papszArgvDup,
     727                 :                          environ) != 0 )
     728                 :         {
     729               0 :             if( bHasActions )
     730               0 :                 posix_spawn_file_actions_destroy(&actions);
     731               0 :             CPLError(CE_Failure, CPLE_AppDefined, "posix_spawnp() failed");
     732               0 :             goto err;
     733                 :         }
     734                 : 
     735               7 :         CSLDestroy(papszArgvDup);
     736                 : 
     737                 :         /* Close unused end of pipe */
     738               7 :         if( bCreateInputPipe )
     739               7 :             close(pipe_in[IN_FOR_PARENT]);
     740               7 :         if( bCreateOutputPipe )
     741               7 :             close(pipe_out[OUT_FOR_PARENT]);
     742               7 :         if( bCreateErrorPipe )
     743               7 :             close(pipe_err[OUT_FOR_PARENT]);
     744                 : 
     745                 :         /* Ignore SIGPIPE */
     746                 :     #ifdef SIGPIPE
     747               7 :         signal (SIGPIPE, SIG_IGN);
     748                 :     #endif
     749               7 :         CPLSpawnedProcess* p = (CPLSpawnedProcess*)CPLMalloc(sizeof(CPLSpawnedProcess));
     750               7 :         if( bHasActions )
     751               7 :             memcpy(&p->actions, &actions, sizeof(actions));
     752               7 :         p->bFreeActions = bHasActions;
     753               7 :         p->pid = pid;
     754               7 :         p->fin = pipe_out[IN_FOR_PARENT];
     755               7 :         p->fout = pipe_in[OUT_FOR_PARENT];
     756               7 :         p->ferr = pipe_err[IN_FOR_PARENT];
     757               7 :         return p;
     758                 :     }
     759                 : #endif // #ifdef HAVE_POSIX_SPAWNP
     760                 : 
     761                 : #ifdef HAVE_VFORK
     762               2 :     if( papszArgv != NULL && !bDup2In && !bDup2Out && !bDup2Err )
     763               0 :         pid = vfork();
     764                 :     else
     765                 : #endif
     766               2 :         pid = fork();
     767               2 :     if (pid == 0)
     768                 :     {
     769                 :         /* Close unused end of pipe */
     770               0 :         if( bDup2In )
     771               0 :             close(pipe_in[OUT_FOR_PARENT]);
     772               0 :         if( bDup2Out )
     773               0 :             close(pipe_out[IN_FOR_PARENT]);
     774               0 :         if( bDup2Err )
     775               0 :             close(pipe_err[IN_FOR_PARENT]);
     776                 : 
     777                 : #ifndef HAVE_POSIX_SPAWNP
     778                 :         if( papszArgv != NULL )
     779                 :         {
     780                 :             if( bDup2In )
     781                 :                 dup2(pipe_in[IN_FOR_PARENT], fileno(stdin));
     782                 :             if( bDup2Out )
     783                 :                 dup2(pipe_out[OUT_FOR_PARENT], fileno(stdout));
     784                 :             if( bDup2Err )
     785                 :                 dup2(pipe_err[OUT_FOR_PARENT], fileno(stderr));
     786                 : 
     787                 :             execvp(papszArgvDup[0], (char* const*) papszArgvDup);
     788                 : 
     789                 :             _exit(1);
     790                 :         }
     791                 :         else
     792                 : #endif // HAVE_POSIX_SPAWNP
     793                 :         {
     794               0 :             if( bCreateErrorPipe )
     795               0 :                 close(pipe_err[OUT_FOR_PARENT]);
     796                 : 
     797               0 :             int nRet = 0;
     798               0 :             if (pfnMain != NULL)
     799                 :                 nRet = pfnMain((bCreateInputPipe) ? pipe_in[IN_FOR_PARENT] : fileno(stdin),
     800               0 :                                (bCreateOutputPipe) ? pipe_out[OUT_FOR_PARENT] : fileno(stdout));
     801               0 :             _exit(nRet);
     802                 :         }
     803                 :     }
     804               2 :     else if( pid > 0 )
     805                 :     {
     806               2 :         CSLDestroy(papszArgvDup);
     807                 : 
     808                 :         /* Close unused end of pipe */
     809               2 :         if( bCreateInputPipe )
     810               2 :             close(pipe_in[IN_FOR_PARENT]);
     811               2 :         if( bCreateOutputPipe )
     812               2 :             close(pipe_out[OUT_FOR_PARENT]);
     813               2 :         if( bCreateErrorPipe )
     814               0 :             close(pipe_err[OUT_FOR_PARENT]);
     815                 : 
     816                 :         /* Ignore SIGPIPE */
     817                 : #ifdef SIGPIPE
     818               2 :         signal (SIGPIPE, SIG_IGN);
     819                 : #endif
     820               2 :         CPLSpawnedProcess* p = (CPLSpawnedProcess*)CPLMalloc(sizeof(CPLSpawnedProcess));
     821                 : #ifdef HAVE_POSIX_SPAWNP
     822               2 :         p->bFreeActions = FALSE;
     823                 : #endif
     824               2 :         p->pid = pid;
     825               2 :         p->fin = pipe_out[IN_FOR_PARENT];
     826               2 :         p->fout = pipe_in[OUT_FOR_PARENT];
     827               2 :         p->ferr = pipe_err[IN_FOR_PARENT];
     828               2 :         return p;
     829                 :     }
     830                 :     else
     831                 :     {
     832               0 :         CPLError(CE_Failure, CPLE_AppDefined, "Fork failed");
     833               0 :         goto err;
     834                 :     }
     835                 : 
     836                 : err_pipe:
     837               0 :     CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
     838                 : err:
     839               0 :     CSLDestroy(papszArgvDup);
     840               0 :     for(i=0;i<2;i++)
     841                 :     {
     842               0 :         if (pipe_in[i] >= 0)
     843               0 :             close(pipe_in[i]);
     844               0 :         if (pipe_out[i] >= 0)
     845               0 :             close(pipe_out[i]);
     846               0 :         if (pipe_err[i] >= 0)
     847               0 :             close(pipe_err[i]);
     848                 :     }
     849                 : 
     850               0 :     return NULL;
     851                 : }
     852                 : 
     853                 : /************************************************************************/
     854                 : /*                  CPLSpawnAsyncGetChildProcessId()                    */
     855                 : /************************************************************************/
     856                 : 
     857               0 : CPL_PID CPLSpawnAsyncGetChildProcessId(CPLSpawnedProcess* p)
     858                 : {
     859               0 :     return p->pid;
     860                 : }
     861                 : 
     862                 : /************************************************************************/
     863                 : /*                        CPLSpawnAsyncFinish()                         */
     864                 : /************************************************************************/
     865                 : 
     866                 : /**
     867                 :  * Wait for the forked process to finish.
     868                 :  *
     869                 :  * @param p handle returned by CPLSpawnAsync()
     870                 :  * @param bWait set to TRUE to wait for the child to terminate. Otherwise the associated
     871                 :  *              handles are just cleaned.
     872                 :  * @param bKill set to TRUE to force child termination (unimplemented right now).
     873                 :  *
     874                 :  * @return the return code of the forked process if bWait == TRUE, 0 otherwise
     875                 :  *
     876                 :  * @since GDAL 1.10.0
     877                 :  */
     878               9 : int CPLSpawnAsyncFinish(CPLSpawnedProcess* p, int bWait, int bKill)
     879                 : {
     880               9 :     int status = 0;
     881                 : 
     882               9 :     if( bWait )
     883                 :     {
     884               0 :         while(1)
     885                 :         {
     886               9 :             status = -1;
     887               9 :             int ret = waitpid (p->pid, &status, 0);
     888               9 :             if (ret < 0)
     889                 :             {
     890               0 :                 if (errno != EINTR)
     891                 :                 {
     892               0 :                     break;
     893                 :                 }
     894                 :             }
     895                 :             else
     896               9 :                 break;
     897                 :         }
     898                 :     }
     899                 :     else
     900               0 :         bWait = FALSE;
     901               9 :     CPLSpawnAsyncCloseInputFileHandle(p);
     902               9 :     CPLSpawnAsyncCloseOutputFileHandle(p);
     903               9 :     CPLSpawnAsyncCloseErrorFileHandle(p);
     904                 : #ifdef HAVE_POSIX_SPAWNP
     905               9 :     if( p->bFreeActions )
     906               7 :         posix_spawn_file_actions_destroy(&p->actions);
     907                 : #endif
     908               9 :     CPLFree(p);
     909               9 :     return status;
     910                 : }
     911                 : 
     912                 : /************************************************************************/
     913                 : /*                 CPLSpawnAsyncCloseInputFileHandle()                  */
     914                 : /************************************************************************/
     915                 : 
     916              16 : void CPLSpawnAsyncCloseInputFileHandle(CPLSpawnedProcess* p)
     917                 : {
     918              16 :     if( p->fin >= 0 )
     919               9 :         close(p->fin);
     920              16 :     p->fin = -1;
     921              16 : }
     922                 : 
     923                 : /************************************************************************/
     924                 : /*                 CPLSpawnAsyncCloseOutputFileHandle()                 */
     925                 : /************************************************************************/
     926                 : 
     927              16 : void CPLSpawnAsyncCloseOutputFileHandle(CPLSpawnedProcess* p)
     928                 : {
     929              16 :     if( p->fout >= 0 )
     930               9 :         close(p->fout);
     931              16 :     p->fout = -1;
     932              16 : }
     933                 : 
     934                 : /************************************************************************/
     935                 : /*                 CPLSpawnAsyncCloseErrorFileHandle()                  */
     936                 : /************************************************************************/
     937                 : 
     938              16 : void CPLSpawnAsyncCloseErrorFileHandle(CPLSpawnedProcess* p)
     939                 : {
     940              16 :     if( p->ferr >= 0 )
     941               7 :         close(p->ferr);
     942              16 :     p->ferr = -1;
     943              16 : }
     944                 : 
     945                 : #endif
     946                 : 
     947                 : /************************************************************************/
     948                 : /*                    CPLSpawnAsyncGetInputFileHandle()                 */
     949                 : /************************************************************************/
     950                 : 
     951                 : /**
     952                 :  * Return the file handle of the standard output of the forked process
     953                 :  * from which to read.
     954                 :  *
     955                 :  * @param p handle returned by CPLSpawnAsync().
     956                 :  *
     957                 :  * @return the file handle.
     958                 :  *
     959                 :  * @since GDAL 1.10.0
     960                 :  */
     961               9 : CPL_FILE_HANDLE CPLSpawnAsyncGetInputFileHandle(CPLSpawnedProcess* p)
     962                 : {
     963               9 :     return p->fin;
     964                 : }
     965                 : 
     966                 : /************************************************************************/
     967                 : /*                   CPLSpawnAsyncGetOutputFileHandle()                 */
     968                 : /************************************************************************/
     969                 : 
     970                 : /**
     971                 :  * Return the file handle of the standard input of the forked process
     972                 :  * into which to write
     973                 :  *
     974                 :  * @param p handle returned by CPLSpawnAsync().
     975                 :  *
     976                 :  * @return the file handle.
     977                 :  *
     978                 :  * @since GDAL 1.10.0
     979                 :  */
     980               9 : CPL_FILE_HANDLE CPLSpawnAsyncGetOutputFileHandle(CPLSpawnedProcess* p)
     981                 : {
     982               9 :     return p->fout;
     983                 : }
     984                 : 
     985                 : /************************************************************************/
     986                 : /*                    CPLSpawnAsyncGetErrorFileHandle()                 */
     987                 : /************************************************************************/
     988                 : 
     989                 : /**
     990                 :  * Return the file handle of the standard error of the forked process
     991                 :  * from which to read.
     992                 :  *
     993                 :  * @param p handle returned by CPLSpawnAsync().
     994                 :  *
     995                 :  * @return the file handle
     996                 :  *
     997                 :  * @since GDAL 1.10.0
     998                 :  */
     999               7 : CPL_FILE_HANDLE CPLSpawnAsyncGetErrorFileHandle(CPLSpawnedProcess* p)
    1000                 : {
    1001               7 :     return p->ferr;
    1002                 : }

Generated by: LCOV version 1.7