1 /* 2 * COPYRIGHT: See COPYING in the top level directory 3 * PROJECT: ReactOS C runtime library 4 * FILE: lib/sdk/crt/stdio/popen.c 5 * PURPOSE: Pipe Functions 6 * PROGRAMMERS: Eric Kohl 7 * Hartmut Birr 8 * Also adapted from Wine team code by Andreas Maier. 9 */ 10 11 #include <precomp.h> 12 #include <tchar.h> 13 14 #ifdef _UNICODE 15 #define sT "S" 16 #else 17 #define sT "s" 18 #endif 19 20 #define MK_STR(s) #s 21 22 int msvcrt_alloc_fd(HANDLE hand, int flag); //FIXME: Remove 23 unsigned split_oflags(unsigned oflags); //FIXME: Remove 24 25 #ifndef _UNICODE 26 struct popen_handle *popen_handles = NULL; 27 DWORD popen_handles_size = 0; 28 29 void msvcrt_free_popen_data(void) 30 { 31 free(popen_handles); 32 } 33 #endif 34 35 /* 36 * @implemented 37 */ 38 FILE *_tpopen (const _TCHAR *cm, const _TCHAR *md) /* program name, pipe mode */ 39 { 40 _TCHAR *szCmdLine=NULL; 41 _TCHAR *szComSpec=NULL; 42 _TCHAR *s; 43 FILE *ret; 44 HANDLE hReadPipe, hWritePipe; 45 BOOL result; 46 STARTUPINFO StartupInfo; 47 PROCESS_INFORMATION ProcessInformation; 48 SECURITY_ATTRIBUTES sa = {sizeof(SECURITY_ATTRIBUTES), NULL, TRUE}; 49 struct popen_handle *container; 50 DWORD i; 51 52 TRACE(MK_STR(_tpopen)"('%"sT"', '%"sT"')\n", cm, md); 53 54 if (cm == NULL) 55 return NULL; 56 57 szComSpec = _tgetenv(_T("COMSPEC")); 58 if (szComSpec == NULL) 59 { 60 szComSpec = _T("cmd.exe"); 61 } 62 63 s = max(_tcsrchr(szComSpec, '\\'), _tcsrchr(szComSpec, '/')); 64 if (s == NULL) 65 s = szComSpec; 66 else 67 s++; 68 69 szCmdLine = malloc((_tcslen(s) + 4 + _tcslen(cm) + 1) * sizeof(_TCHAR)); 70 if (szCmdLine == NULL) 71 { 72 return NULL; 73 } 74 75 _tcscpy(szCmdLine, s); 76 s = _tcsrchr(szCmdLine, '.'); 77 if (s) 78 *s = 0; 79 _tcscat(szCmdLine, _T(" /C ")); 80 _tcscat(szCmdLine, cm); 81 82 if ( !CreatePipe(&hReadPipe,&hWritePipe,&sa,1024)) 83 { 84 free (szCmdLine); 85 return NULL; 86 } 87 88 memset(&ProcessInformation, 0, sizeof(ProcessInformation)); 89 memset(&StartupInfo, 0, sizeof(STARTUPINFO)); 90 StartupInfo.cb = sizeof(STARTUPINFO); 91 92 if (*md == 'r' ) { 93 StartupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE); 94 StartupInfo.hStdOutput = hWritePipe; 95 StartupInfo.dwFlags |= STARTF_USESTDHANDLES; 96 } 97 else if ( *md == 'w' ) { 98 StartupInfo.hStdInput = hReadPipe; 99 StartupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE); 100 StartupInfo.dwFlags |= STARTF_USESTDHANDLES; 101 } 102 103 if (StartupInfo.dwFlags & STARTF_USESTDHANDLES) 104 StartupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE); 105 106 result = CreateProcess(szComSpec, 107 szCmdLine, 108 NULL, 109 NULL, 110 TRUE, 111 0, 112 NULL, 113 NULL, 114 &StartupInfo, 115 &ProcessInformation); 116 free (szCmdLine); 117 118 if (result == FALSE) 119 { 120 CloseHandle(hReadPipe); 121 CloseHandle(hWritePipe); 122 return NULL; 123 } 124 125 CloseHandle(ProcessInformation.hThread); 126 127 _mlock(_POPEN_LOCK); 128 for(i=0; i<popen_handles_size; i++) 129 { 130 if (!popen_handles[i].f) 131 break; 132 } 133 if (i==popen_handles_size) 134 { 135 i = (popen_handles_size ? popen_handles_size*2 : 8); 136 container = realloc(popen_handles, i*sizeof(*container)); 137 if (!container) goto error; 138 139 popen_handles = container; 140 container = popen_handles+popen_handles_size; 141 memset(container, 0, (i-popen_handles_size)*sizeof(*container)); 142 popen_handles_size = i; 143 } 144 else container = popen_handles+i; 145 146 if ( *md == 'r' ) 147 { 148 ret = _tfdopen(msvcrt_alloc_fd(hReadPipe, split_oflags(_fmode)) , _T("r")); 149 CloseHandle(hWritePipe); 150 } 151 else 152 { 153 ret = _tfdopen( msvcrt_alloc_fd(hWritePipe, split_oflags(_fmode)) , _T("w")); 154 CloseHandle(hReadPipe); 155 } 156 157 container->f = ret; 158 container->proc = ProcessInformation.hProcess; 159 _munlock(_POPEN_LOCK); 160 161 return ret; 162 163 error: 164 _munlock(_POPEN_LOCK); 165 if (ProcessInformation.hProcess != 0) 166 CloseHandle(ProcessInformation.hProcess); 167 return NULL; 168 } 169 170 #ifndef _UNICODE 171 172 /* 173 * @implemented 174 */ 175 int CDECL _pclose(FILE* file) 176 { 177 HANDLE h; 178 DWORD i; 179 180 if (!MSVCRT_CHECK_PMT(file != NULL)) return -1; 181 182 _mlock(_POPEN_LOCK); 183 for(i=0; i<popen_handles_size; i++) 184 { 185 if (popen_handles[i].f == file) 186 break; 187 } 188 if(i == popen_handles_size) 189 { 190 _munlock(_POPEN_LOCK); 191 *_errno() = EBADF; 192 return -1; 193 } 194 195 h = popen_handles[i].proc; 196 popen_handles[i].f = NULL; 197 _munlock(_POPEN_LOCK); 198 199 fclose(file); 200 if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i)) 201 { 202 _dosmaperr(GetLastError()); 203 CloseHandle(h); 204 return -1; 205 } 206 207 CloseHandle(h); 208 return i; 209 } 210 211 #endif 212