int __cdecl _tspawnvpe ( int modeflag, REG3 const _TSCHAR *filename, const _TSCHAR * const *argv, const _TSCHAR * const *envptr ) { int i; REG1 _TSCHAR *env; REG2 _TSCHAR *buf = NULL; _TSCHAR *pfin; _ASSERTE(filename != NULL); _ASSERTE(*filename != _T('\0')); _ASSERTE(argv != NULL); _ASSERTE(*argv != NULL); _ASSERTE(**argv != _T('\0')); if ( (i = _tspawnve(modeflag, filename, argv, envptr)) != -1 /* everything worked just fine; return i */ || (errno != ENOENT) /* couldn't spawn the process, return failure */ || (_tcschr(filename, XSLASHCHAR) != NULL) /* filename contains a '/', return failure */ || !(env = _tgetenv(_T("PATH"))) /* no PATH environment string name, return failure */ || ( (buf = _malloc_crt(_MAX_PATH * sizeof(_TSCHAR))) == NULL ) /* cannot allocate buffer to build alternate pathnames, return * failure */ ) { goto done; } /* could not find the file as specified, search PATH. try each * component of the PATH until we get either no error return, or the * error is not ENOENT and the component is not a UNC name, or we run * out of components to try. */ #ifdef WPRFLAG while ( (env = _wgetpath(env, buf, _MAX_PATH - 1)) && (*buf) ) { #else /* WPRFLAG */ while ( (env = _getpath(env, buf, _MAX_PATH - 1)) && (*buf) ) { #endif /* WPRFLAG */ pfin = buf + _tcslen(buf) - 1; /* if necessary, append a '/' */ #ifdef _MBCS if (*pfin == SLASHCHAR) { if (pfin != _mbsrchr(buf,SLASHCHAR)) /* fin is the second byte of a double-byte char */ strcat(buf, SLASH ); } else if (*pfin !=XSLASHCHAR) strcat(buf, SLASH); #else /* _MBCS */ if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) _tcscat(buf, SLASH); #endif /* _MBCS */ /* check that the final path will be of legal size. if so, * build it. otherwise, return to the caller (return value * and errno rename set from initial call to _spawnve()). */ if ( (_tcslen(buf) + _tcslen(filename)) < _MAX_PATH ) _tcscat(buf, filename); else break; /* try spawning it. if successful, or if errno comes back with a * value other than ENOENT and the pathname is not a UNC name, * return to the caller. */ if ( (i = _tspawnve(modeflag, buf, argv, envptr)) != -1 || ((errno != ENOENT) #ifdef _MBCS && (!ISPSLASH(buf) || !ISPSLASH(buf+1))) ) #else /* _MBCS */ && (!ISSLASH(*buf) || !ISSLASH(*(buf+1)))) ) #endif /* _MBCS */ break; } done: if (buf != NULL) _free_crt(buf); return(i); }
FILE * __cdecl _tpopen ( const _TSCHAR *cmdstring, const _TSCHAR *type ) { int phdls[2]; /* I/O handles for pipe */ int ph_open[2]; /* flags, set if correspond phdls is open */ int i1; /* index into phdls[] */ int i2; /* index into phdls[] */ int tm = 0; /* flag indicating text or binary mode */ int stdhdl; /* either STDIN or STDOUT */ HANDLE newhnd; /* ...in calls to DuplicateHandle API */ FILE *pstream = NULL; /* stream to be associated with pipe */ HANDLE prochnd; /* handle for current process */ _TSCHAR *cmdexe; /* pathname for the command processor */ _TSCHAR *envbuf = NULL; /* buffer for the env variable */ intptr_t childhnd; /* handle for child process (cmd.exe) */ IDpair *locidpair; /* pointer to IDpair table entry */ _TSCHAR *buf = NULL, *pfin, *env; _TSCHAR *CommandLine; size_t CommandLineSize = 0; _TSCHAR _type[3] = {0, 0, 0}; /* Info for spawning the child. */ STARTUPINFO StartupInfo; /* Info for spawning a child */ BOOL childstatus = 0; PROCESS_INFORMATION ProcessInfo; /* child process information */ errno_t save_errno; int fh_lock_held = 0; int popen_lock_held = 0; /* first check for errors in the arguments */ _VALIDATE_RETURN((cmdstring != NULL), EINVAL,NULL); _VALIDATE_RETURN((type != NULL), EINVAL,NULL); while (*type == _T(' ')) { type++; } _VALIDATE_RETURN(((*type == _T('w')) || (*type == _T('r'))), EINVAL,NULL); _type[0] = *type; ++type; while (*type == _T(' ')) { ++type; } _VALIDATE_RETURN(((*type == 0) || (*type == _T('t')) || (*type == _T('b'))), EINVAL, NULL); _type[1] = *type; /* do the _pipe(). note that neither of the resulting handles will * be inheritable. */ if ( _type[1] == _T('t') ) tm = _O_TEXT; else if ( _type[1] == _T('b') ) tm = _O_BINARY; tm |= _O_NOINHERIT; if ( _pipe( phdls, PSIZE, tm ) == -1 ) goto error1; /* test _type[0] and set stdhdl, i1 and i2 accordingly. */ if ( _type[0] == _T('w') ) { stdhdl = STDIN; i1 = 0; i2 = 1; } else { stdhdl = STDOUT; i1 = 1; i2 = 0; } /* ASSERT LOCK FOR IDPAIRS HERE!!!! */ if ( !_mtinitlocknum( _POPEN_LOCK )) { _close( phdls[0] ); _close( phdls[1] ); return NULL; } _mlock( _POPEN_LOCK ); __try { /* set flags to indicate pipe handles are open. note, these are only * used for error recovery. */ ph_open[ 0 ] = ph_open[ 1 ] = 1; /* get the process handle, it will be needed in some API calls */ prochnd = GetCurrentProcess(); if ( !DuplicateHandle( prochnd, (HANDLE)_osfhnd( phdls[i1] ), prochnd, &newhnd, 0L, TRUE, /* inheritable */ DUPLICATE_SAME_ACCESS ) ) { goto error2; } (void)_close( phdls[i1] ); ph_open[ i1 ] = 0; /* associate a stream with phdls[i2]. note that if there are no * errors, pstream is the return value to the caller. */ if ( (pstream = _tfdopen( phdls[i2], _type )) == NULL ) goto error2; /* next, set locidpair to a free entry in the idpairs table. */ if ( (locidpair = idtab( NULL )) == NULL ) goto error3; /* Find what to use. command.com or cmd.exe */ if ( (_ERRCHECK_EINVAL(_tdupenv_s_crt(&envbuf, NULL, _T("COMSPEC"))) != 0) || (envbuf == NULL) ) { unsigned int osver = 0; _get_osver(&osver); cmdexe = ( osver & 0x8000 ) ? _T("command.com") : _T("cmd.exe"); } else { cmdexe = envbuf; } /* * Initialise the variable for passing to CreateProcess */ memset(&StartupInfo, 0, sizeof(StartupInfo)); StartupInfo.cb = sizeof(StartupInfo); /* Used by os for duplicating the Handles. */ StartupInfo.dwFlags = STARTF_USESTDHANDLES; StartupInfo.hStdInput = stdhdl == STDIN ? (HANDLE) newhnd : (HANDLE) _osfhnd(0); StartupInfo.hStdOutput = stdhdl == STDOUT ? (HANDLE) newhnd : (HANDLE) _osfhnd(1); StartupInfo.hStdError = (HANDLE) _osfhnd(2); CommandLineSize = _tcslen(cmdexe) + _tcslen(_T(" /c ")) + (_tcslen(cmdstring)) +1; if ((CommandLine = _calloc_crt( CommandLineSize, sizeof(_TSCHAR))) == NULL) goto error3; _ERRCHECK(_tcscpy_s(CommandLine, CommandLineSize, cmdexe)); _ERRCHECK(_tcscat_s(CommandLine, CommandLineSize, _T(" /c "))); _ERRCHECK(_tcscat_s(CommandLine, CommandLineSize, cmdstring)); /* Check if cmdexe can be accessed. If yes CreateProcess else try * searching path. */ save_errno = errno; if (_taccess_s(cmdexe, 0) == 0) { childstatus = CreateProcess( (LPTSTR) cmdexe, (LPTSTR) CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo ); } else { TCHAR* envPath = NULL; size_t envPathSize = 0; if ((buf = _calloc_crt(_MAX_PATH, sizeof(_TSCHAR))) == NULL) { _free_crt(buf); _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; errno = save_errno; goto error3; } if (_ERRCHECK_EINVAL(_tdupenv_s_crt(&envPath, NULL, _T("PATH"))) != 0) { _free_crt(envPath); _free_crt(buf); _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; errno = save_errno; goto error3; } env = envPath; #ifdef WPRFLAG while ( (env = _wgetpath(env, buf, _MAX_PATH -1)) && (*buf) ) { #else /* WPRFLAG */ while ( (env = _getpath(env, buf, _MAX_PATH -1)) && (*buf) ) { #endif /* WPRFLAG */ pfin = buf + _tcslen(buf) -1; #ifdef _MBCS if (*pfin == SLASHCHAR) { if (pfin != _mbsrchr(buf, SLASHCHAR)) _ERRCHECK(strcat_s(buf, _MAX_PATH, SLASH)); } else if (*pfin != XSLASHCHAR) _ERRCHECK(strcat_s(buf, _MAX_PATH, SLASH)); #else /* _MBCS */ if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) _ERRCHECK(_tcscat_s(buf, _MAX_PATH, SLASH)); #endif /* _MBCS */ /* check that the final path will be of legal size. if so, * build it. otherwise, return to the caller (return value * and errno rename set from initial call to _spawnve()). */ if ( (_tcslen(buf) + _tcslen(cmdexe)) < _MAX_PATH ) _ERRCHECK(_tcscat_s(buf, _MAX_PATH, cmdexe)); else break; /* Check if buf can be accessed. If yes CreateProcess else try * again. */ if (_taccess_s(buf, 0) == 0) { childstatus = CreateProcess( (LPTSTR) buf, CommandLine, NULL, NULL, TRUE, 0, NULL, NULL, &StartupInfo, &ProcessInfo ); break; } } _free_crt(envPath); _free_crt(buf); } _free_crt(CommandLine); _free_crt(envbuf); cmdexe = NULL; CloseHandle((HANDLE)newhnd); CloseHandle((HANDLE)ProcessInfo.hThread); errno = save_errno; /* check if the CreateProcess was sucessful. */ if ( childstatus) childhnd = (intptr_t)ProcessInfo.hProcess; else goto error4; locidpair->prochnd = childhnd; locidpair->stream = pstream; /* success, return the stream to the caller */ goto done; /** * error handling code. all detected errors end up here, entering * via a goto one of the labels. note that the logic is currently * a straight fall-thru scheme (e.g., if entered at error4, the * code for error4, error3,...,error1 is all executed). **********************************************************************/ error4: /* make sure locidpair is reusable */ locidpair->stream = NULL; error3: /* close pstream (also, clear ph_open[i2] since the stream * close will also close the pipe handle) */ (void)fclose( pstream ); ph_open[ i2 ] = 0; pstream = NULL; error2: /* close handles on pipe (if they are still open) */ if ( ph_open[i1] ) _close( phdls[i1] ); if ( ph_open[i2] ) _close( phdls[i2] ); done: ;} __finally { _munlock(_POPEN_LOCK); } error1: return pstream; } #ifndef _UNICODE /*** *int _pclose(pstream) - wait on a child command and close the stream on the * associated pipe * *Purpose: * Closes pstream then waits on the associated child command. The * argument, pstream, must be the return value from a previous call to * _popen. _pclose first looks up the process handle of child command * started by that _popen and does a cwait on it. Then, it closes pstream * and returns the exit status of the child command to the caller. * *Entry: * FILE *pstream - file stream returned by a previous call to _popen * *Exit: * If successful, _pclose returns the exit status of the child command. * The format of the return value is that same as for cwait, except that * the low order and high order bytes are swapped. * * If an error occurs, -1 is returned. * *Exceptions: * *******************************************************************************/ int __cdecl _pclose ( FILE *pstream ) { IDpair *locidpair; /* pointer to entry in idpairs table */ int termstat; /* termination status word */ int retval = -1; /* return value (to caller) */ errno_t save_errno; _VALIDATE_RETURN((pstream != NULL), EINVAL, -1); if (!_mtinitlocknum(_POPEN_LOCK)) return -1; _mlock(_POPEN_LOCK); __try { if ((locidpair = idtab(pstream)) == NULL) { /* invalid pstream, exit with retval == -1 */ errno = EBADF; goto done; } /* close pstream */ (void)fclose(pstream); /* wait on the child (copy of the command processor) and all of its * children. */ save_errno = errno; errno = 0; if ( (_cwait(&termstat, locidpair->prochnd, _WAIT_GRANDCHILD) != -1) || (errno == EINTR) ) retval = termstat; errno = save_errno; /* Mark the IDpairtable entry as free (note: prochnd was closed by the * preceding call to _cwait). */ locidpair->stream = NULL; locidpair->prochnd = 0; /* only return path! */ done: ; } __finally { _munlock(_POPEN_LOCK); } return(retval); }