| 102 | */ |
| 103 | |
| 104 | int CPLSpawn(const char *const papszArgv[], VSILFILE *fin, VSILFILE *fout, |
| 105 | int bDisplayErr) |
| 106 | { |
| 107 | CPLSpawnedProcess *sp = |
| 108 | CPLSpawnAsync(nullptr, papszArgv, TRUE, TRUE, TRUE, nullptr); |
| 109 | if (sp == nullptr) |
| 110 | return -1; |
| 111 | |
| 112 | CPL_FILE_HANDLE in_child = CPLSpawnAsyncGetOutputFileHandle(sp); |
| 113 | if (fin != nullptr) |
| 114 | FillPipeFromFile(fin, in_child); |
| 115 | CPLSpawnAsyncCloseOutputFileHandle(sp); |
| 116 | |
| 117 | CPL_FILE_HANDLE out_child = CPLSpawnAsyncGetInputFileHandle(sp); |
| 118 | if (fout != nullptr) |
| 119 | FillFileFromPipe(out_child, fout); |
| 120 | CPLSpawnAsyncCloseInputFileHandle(sp); |
| 121 | |
| 122 | CPL_FILE_HANDLE err_child = CPLSpawnAsyncGetErrorFileHandle(sp); |
| 123 | CPLString osName; |
| 124 | osName.Printf("/vsimem/child_stderr_" CPL_FRMT_GIB, CPLGetPID()); |
| 125 | VSILFILE *ferr = VSIFOpenL(osName.c_str(), "w"); |
| 126 | |
| 127 | FillFileFromPipe(err_child, ferr); |
| 128 | CPLSpawnAsyncCloseErrorFileHandle(sp); |
| 129 | |
| 130 | CPL_IGNORE_RET_VAL(VSIFCloseL(ferr)); |
| 131 | vsi_l_offset nDataLength = 0; |
| 132 | GByte *pData = VSIGetMemFileBuffer(osName.c_str(), &nDataLength, TRUE); |
| 133 | if (nDataLength > 0) |
| 134 | pData[nDataLength - 1] = '\0'; |
| 135 | if (pData && |
| 136 | strstr(const_cast<const char *>(reinterpret_cast<char *>(pData)), |
| 137 | "An error occurred while forking process") != nullptr) |
| 138 | bDisplayErr = TRUE; |
| 139 | if (pData && bDisplayErr) |
| 140 | CPLError(CE_Failure, CPLE_AppDefined, "[%s error] %s", papszArgv[0], |
| 141 | pData); |
| 142 | CPLFree(pData); |
| 143 | |
| 144 | return CPLSpawnAsyncFinish(sp, TRUE, FALSE); |
| 145 | } |
| 146 | |
| 147 | #if defined(_WIN32) |
| 148 | |