LTP GCOV extension - code coverage report
Current view: directory - ogr/ogrsf_frmts/gpsbabel - ogrgpsbabelfork.cpp
Test: gdal_filtered.info
Date: 2010-07-12 Instrumented lines: 75
Code covered: 60.0 % Executed lines: 45

       1                 : /******************************************************************************
       2                 :  * $Id: ogrgpsbabelfork.cpp 19787 2010-05-31 22:26:57Z rouault $
       3                 :  *
       4                 :  * Project:  OpenGIS Simple Features Reference Implementation
       5                 :  * Purpose:  Utility to fork a process and pipe data into/from it
       6                 :  * Author:   Even Rouault, <even dot rouault at mines dash paris dot org>
       7                 :  *
       8                 :  ******************************************************************************
       9                 :  * Copyright (c) 2010, 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
      22                 :  * OR 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_port.h"
      31                 : #include "cpl_vsi.h"
      32                 : #include "cpl_error.h"
      33                 : #include "cpl_conv.h"
      34                 : #include "cpl_string.h"
      35                 : #include "cpl_multiproc.h"
      36                 : 
      37                 : #include "ogr_gpsbabel.h"
      38                 : 
      39                 : #define PIPE_BUFFER_SIZE    4096
      40                 : 
      41                 : #define IN_FOR_PARENT   0
      42                 : #define OUT_FOR_PARENT  1
      43                 : 
      44                 : 
      45                 : #ifndef WIN32
      46                 : 
      47                 : #include <unistd.h>
      48                 : #include <stdio.h>
      49                 : #include <stdlib.h>
      50                 : #include <sys/types.h>
      51                 : #include <sys/wait.h>
      52                 : #include <errno.h>
      53                 : 
      54                 : 
      55               3 : static void WriteToPipe(FILE* fin, int pipe_fd)
      56                 : {
      57                 :     char buf[PIPE_BUFFER_SIZE];
      58               0 :     while(TRUE)
      59                 :     {
      60               3 :         int nRead = (int)VSIFReadL(buf, 1, PIPE_BUFFER_SIZE, fin);
      61               3 :         int nWritten = write(pipe_fd, buf, nRead);
      62               3 :         if (nWritten < nRead || nRead < PIPE_BUFFER_SIZE)
      63                 :             break;
      64                 :     }
      65               3 : }
      66                 : 
      67               9 : static void ReadFromPipe(int pipe_fd, FILE* fout)
      68                 : {
      69                 :     char buf[PIPE_BUFFER_SIZE];
      70               3 :     while(TRUE)
      71                 :     {
      72               9 :         int nRead = read(pipe_fd, buf, PIPE_BUFFER_SIZE);
      73               9 :         if (nRead <= 0)
      74               6 :             break;
      75               3 :         int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
      76               3 :         if (nWritten < nRead)
      77               0 :             break;
      78                 :     }
      79               6 : }
      80                 : 
      81               3 : int ForkAndPipe(const char * const argv[], FILE* fin, FILE* fout)
      82                 : {
      83                 :     pid_t pid;
      84               3 :     int pipe_in[2] = { -1, -1 };
      85               3 :     int pipe_out[2] = { -1, -1 };
      86               3 :     int pipe_err[2] = { -1, -1 };
      87                 :     int i;
      88                 : 
      89               3 :     if (pipe(pipe_in) ||
      90                 :         pipe(pipe_out) ||
      91                 :         pipe(pipe_err))
      92               0 :         goto err_pipe;
      93                 : 
      94               3 :     pid = fork();
      95               3 :     if (pid == 0)
      96                 :     {
      97                 :         /* Close unused end of pipe */
      98               0 :         close(pipe_in[OUT_FOR_PARENT]);
      99               0 :         close(pipe_out[IN_FOR_PARENT]);
     100               0 :         close(pipe_err[IN_FOR_PARENT]);
     101                 : 
     102               0 :         dup2(pipe_in[IN_FOR_PARENT], fileno(stdin));
     103               0 :         dup2(pipe_out[OUT_FOR_PARENT], fileno(stdout));
     104               0 :         dup2(pipe_err[OUT_FOR_PARENT], fileno(stderr));
     105                 : 
     106               0 :         execvp(argv[0], (char* const*) argv);
     107                 : 
     108               0 :         char* pszErr = strerror(errno);
     109                 : 
     110               0 :         fprintf(stderr, "An error occured while forking process %s : %s", argv[0], pszErr);
     111                 : 
     112               0 :         exit(1);
     113                 :     }
     114               3 :     else if (pid < 0)
     115                 :     {
     116               0 :         CPLError(CE_Failure, CPLE_AppDefined, "fork() failed");
     117               0 :         goto err;
     118                 :     }
     119                 :     else
     120                 :     {
     121                 :         /* Close unused end of pipe */
     122               3 :         close(pipe_in[IN_FOR_PARENT]);
     123               3 :         close(pipe_out[OUT_FOR_PARENT]);
     124               3 :         close(pipe_err[OUT_FOR_PARENT]);
     125                 : 
     126                 :         /* Ignore SIGPIPE */
     127                 : #ifdef SIGPIPE
     128               3 :         signal (SIGPIPE, SIG_IGN);
     129                 : #endif
     130                 : 
     131               3 :         if (fin != NULL)
     132               3 :             WriteToPipe(fin, pipe_in[OUT_FOR_PARENT]);
     133               3 :         close(pipe_in[OUT_FOR_PARENT]);
     134                 : 
     135               3 :         if (fout != NULL)
     136               3 :             ReadFromPipe(pipe_out[IN_FOR_PARENT], fout);
     137               3 :         close(pipe_out[IN_FOR_PARENT]);
     138                 : 
     139               3 :         CPLString osName;
     140               3 :         osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID());
     141               3 :         FILE* ferr = VSIFOpenL(osName.c_str(), "w");
     142               3 :         ReadFromPipe(pipe_err[IN_FOR_PARENT], ferr);
     143               3 :         close(pipe_err[IN_FOR_PARENT]);
     144               3 :         VSIFCloseL(ferr);
     145               3 :         vsi_l_offset nDataLength = 0;
     146               3 :         GByte* pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE);
     147               3 :         if (pData)
     148               0 :             CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", argv[0], pData);
     149               3 :         CPLFree(pData);
     150                 : 
     151               0 :         while(1)
     152                 :         {
     153                 :             int status;
     154               3 :             int ret = waitpid (pid, &status, 0);
     155               3 :             if (ret < 0)
     156                 :             {
     157               0 :                 if (errno != EINTR)
     158                 :                 {
     159               0 :                     break;
     160                 :                 }
     161                 :             }
     162                 :             else
     163               3 :                 break;
     164                 :         }
     165               3 :         return pData == NULL;
     166                 :     }
     167               0 : err_pipe:
     168               0 :     CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
     169               0 : err:
     170               0 :     for(i=0;i<2;i++)
     171                 :     {
     172               0 :         if (pipe_in[i] >= 0)
     173               0 :             close(pipe_in[i]);
     174               0 :         if (pipe_out[i] >= 0)
     175               0 :             close(pipe_out[i]);
     176               0 :         if (pipe_err[i] >= 0)
     177               0 :             close(pipe_err[i]);
     178                 :     }
     179                 : 
     180               0 :     return FALSE;
     181                 : }
     182                 : 
     183                 : #else
     184                 : 
     185                 : #include <windows.h>
     186                 : 
     187                 : static void WriteToPipe(FILE* fin, HANDLE pipe_fd)
     188                 : {
     189                 :     char buf[PIPE_BUFFER_SIZE];
     190                 :     while(TRUE)
     191                 :     {
     192                 :         int nRead = (int)VSIFReadL(buf, 1, PIPE_BUFFER_SIZE, fin);
     193                 :         DWORD nWritten;
     194                 :         if (!WriteFile(pipe_fd, buf, nRead, &nWritten, NULL))
     195                 :             break;
     196                 :         if ((int)nWritten < nRead || nRead < PIPE_BUFFER_SIZE)
     197                 :             break;
     198                 :     }
     199                 : }
     200                 : 
     201                 : static void ReadFromPipe(HANDLE pipe_fd, FILE* fout)
     202                 : {
     203                 :     char buf[PIPE_BUFFER_SIZE];
     204                 :     while(TRUE)
     205                 :     {
     206                 :         DWORD nRead;
     207                 :         if (!ReadFile( pipe_fd, buf, PIPE_BUFFER_SIZE, &nRead, NULL))
     208                 :             break;
     209                 :         if (nRead <= 0)
     210                 :             break;
     211                 :         int nWritten = (int)VSIFWriteL(buf, 1, nRead, fout);
     212                 :         if (nWritten < (int)nRead)
     213                 :             break;
     214                 :     }
     215                 : }
     216                 : 
     217                 : int ForkAndPipe(const char * const argv[], FILE* fin, FILE* fout)
     218                 : {
     219                 :     HANDLE pipe_in[2] = {NULL, NULL};
     220                 :     HANDLE pipe_out[2] = {NULL, NULL};
     221                 :     HANDLE pipe_err[2] = {NULL, NULL};
     222                 :     SECURITY_ATTRIBUTES saAttr;
     223                 :     PROCESS_INFORMATION piProcInfo;
     224                 :     STARTUPINFO siStartInfo;
     225                 :     CPLString osCommandLine;
     226                 :     int i;
     227                 :     CPLString osName;
     228                 :     FILE* ferr;
     229                 :     vsi_l_offset nDataLength = 0;
     230                 :     GByte* pData;
     231                 : 
     232                 :     saAttr.nLength = sizeof(SECURITY_ATTRIBUTES);
     233                 :     saAttr.bInheritHandle = TRUE;
     234                 :     saAttr.lpSecurityDescriptor = NULL;
     235                 : 
     236                 :     if (!CreatePipe(&pipe_in[IN_FOR_PARENT],&pipe_in[OUT_FOR_PARENT],&saAttr, 0))
     237                 :         goto err_pipe;
     238                 :     /* The child must not inherit from the write side of the pipe_in */
     239                 :     if (!SetHandleInformation(pipe_in[OUT_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     240                 :         goto err_pipe;
     241                 : 
     242                 :     if (!CreatePipe(&pipe_out[IN_FOR_PARENT],&pipe_out[OUT_FOR_PARENT],&saAttr, 0))
     243                 :         goto err_pipe;
     244                 :     /* The child must not inherit from the read side of the pipe_out */
     245                 :     if (!SetHandleInformation(pipe_out[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     246                 :         goto err_pipe;
     247                 : 
     248                 :     if (!CreatePipe(&pipe_err[IN_FOR_PARENT],&pipe_err[OUT_FOR_PARENT],&saAttr, 0))
     249                 :         goto err_pipe;
     250                 :     /* The child must not inherit from the read side of the pipe_err */
     251                 :     if (!SetHandleInformation(pipe_err[IN_FOR_PARENT],HANDLE_FLAG_INHERIT,0))
     252                 :         goto err_pipe;
     253                 : 
     254                 :     memset(&piProcInfo, 0, sizeof(PROCESS_INFORMATION));
     255                 :     memset(&siStartInfo, 0, sizeof(STARTUPINFO));
     256                 :     siStartInfo.cb = sizeof(STARTUPINFO); 
     257                 :     siStartInfo.hStdInput = pipe_in[IN_FOR_PARENT];
     258                 :     siStartInfo.hStdOutput = pipe_out[OUT_FOR_PARENT];
     259                 :     siStartInfo.hStdError = pipe_err[OUT_FOR_PARENT];
     260                 :     siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
     261                 : 
     262                 :     for(i=0;argv[i] != NULL;i++)
     263                 :     {
     264                 :         if (i > 0)
     265                 :             osCommandLine += " ";
     266                 :         osCommandLine += argv[i];
     267                 :     }
     268                 : 
     269                 :     if (!CreateProcess(NULL, 
     270                 :                        (CHAR*)osCommandLine.c_str(),
     271                 :                        NULL,          // process security attributes 
     272                 :                        NULL,          // primary thread security attributes 
     273                 :                        TRUE,          // handles are inherited 
     274                 :                        0,             // creation flags 
     275                 :                        NULL,          // use parent's environment 
     276                 :                        NULL,          // use parent's current directory 
     277                 :                        &siStartInfo,
     278                 :                        &piProcInfo))
     279                 :     {
     280                 :         CPLError(CE_Failure, CPLE_AppDefined, "Could not create process %s",
     281                 :                  osCommandLine.c_str());
     282                 :         goto err;
     283                 :     }
     284                 : 
     285                 :     CloseHandle(piProcInfo.hProcess);
     286                 :     CloseHandle(piProcInfo.hThread);
     287                 :     CloseHandle(pipe_in[IN_FOR_PARENT]);
     288                 : 
     289                 :     if (fin != NULL)
     290                 :         WriteToPipe(fin, pipe_in[OUT_FOR_PARENT]);
     291                 :     CloseHandle(pipe_in[OUT_FOR_PARENT]);
     292                 : 
     293                 :     CloseHandle(pipe_out[OUT_FOR_PARENT]);
     294                 :     if (fout != NULL)
     295                 :         ReadFromPipe(pipe_out[IN_FOR_PARENT], fout);
     296                 : 
     297                 :     osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID());
     298                 :     ferr = VSIFOpenL(osName.c_str(), "w");
     299                 :     CloseHandle(pipe_err[OUT_FOR_PARENT]);
     300                 :     ReadFromPipe(pipe_err[IN_FOR_PARENT], ferr);
     301                 :     VSIFCloseL(ferr);
     302                 :     pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE);
     303                 :     if (pData)
     304                 :         CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", argv[0], pData);
     305                 :     CPLFree(pData);
     306                 : 
     307                 :     CloseHandle(pipe_out[IN_FOR_PARENT]);
     308                 :     CloseHandle(pipe_err[IN_FOR_PARENT]);
     309                 : 
     310                 :     return pData == NULL;
     311                 : 
     312                 : err_pipe:
     313                 :     CPLError(CE_Failure, CPLE_AppDefined, "Could not create pipe");
     314                 : err:
     315                 :     for(i=0;i<2;i++)
     316                 :     {
     317                 :         if (pipe_in[i] != NULL)
     318                 :             CloseHandle(pipe_in[i]);
     319                 :         if (pipe_out[i] != NULL)
     320                 :             CloseHandle(pipe_out[i]);
     321                 :         if (pipe_err[i] != NULL)
     322                 :             CloseHandle(pipe_err[i]);
     323                 :     }
     324                 : 
     325                 :     return FALSE;
     326                 : }
     327                 : 
     328                 : #endif

Generated by: LTP GCOV extension version 1.5