/*** *spawnvpe.c - spawn a child process with given environ (search PATH) * * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved. * *Purpose: * defines _spawnvpe() - spawn a child process with given environ (search * PATH) * *Revision History: * 04-15-84 DFW written * 10-29-85 TC added spawnvpe capability * 11-19-86 SKS handle both kinds of slashes * 12-01-86 JMB added Kanji file name support under conditional KANJI * switches. Corrected header info. Removed bogus check * for env = b after call to strncpy * 12-11-87 JCR Added "_LOAD_DS" to declaration * 09-05-88 SKS Treat EACCES the same as ENOENT -- keep trying * 10-17-88 GJF Removed copy of PATH string to local array, changed * bbuf to be a malloc-ed buffer. Removed bogus limits * on the size of that PATH string. * 10-25-88 GJF Don't search PATH when relative pathname is given (per * Stevesa). Also, if the name built from PATH component * and filename is a UNC name, allow any error. * 05-17-89 MT Added "include " under KANJI switch * 05-24-89 PHG Reduce _amblksiz to use minimal memory (DOS only) * 08-29-89 GJF Use _getpath() to retrieve PATH components, fixing * several problems in handling unusual or bizarre * PATH's. * 11-20-89 GJF Added const attribute to types of filename, argv and * envptr. * 03-08-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include * and removed #include * 07-24-90 SBM Removed redundant includes, replaced by * * 09-27-90 GJF New-style function declarator. * 01-17-91 GJF ANSI naming. * 09-25-91 JCR Changed ifdef "OS2" to "_DOS_" (unused in 32-bit tree) * 11-30-92 KRS Port _MBCS code from 16-bit tree. * 04-06-93 SKS Replace _CRTAPI* with __cdecl * 12-07-93 CFW Wide char enable. * 01-10-95 CFW Debug CRT allocs. * 02-06-95 CFW assert -> _ASSERTE. * 02-06-98 GJF Changes for Win64: changed return type to intptr_t. * *******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #define SLASH _T("\\") #define SLASHCHAR _T('\\') #define XSLASHCHAR _T('/') #define DELIMITER _T(";") #ifdef _MBCS /* note, the macro below assumes p is to pointer to a single-byte character * or the 1st byte of a double-byte character, in a string. */ #define ISPSLASH(p) ( ((p) == _mbschr((p), SLASHCHAR)) || ((p) == \ _mbschr((p), XSLASHCHAR)) ) #else #define ISSLASH(c) ( ((c) == SLASHCHAR) || ((c) == XSLASHCHAR) ) #endif /*** *_spawnvpe(modeflag, filename, argv, envptr) - spawn a child process * *Purpose: * Spawns a child process with the given arguments and environ, * searches along PATH for given file until found. * Formats the parameters and calls _spawnve to do the actual work. The * NULL environment pointer indicates that the new process will inherit * the parents process's environment. NOTE - at least one argument must * be present. This argument is always, by convention, the name of the * file being spawned. * *Entry: * int modeflag - defines mode of spawn (WAIT, NOWAIT, or OVERLAY) * only WAIT and OVERLAY supported * _TSCHAR *filename - name of file to execute * _TSCHAR **argv - vector of parameters * _TSCHAR **envptr - vector of environment variables * *Exit: * returns exit code of spawned process * if fails, returns -1 * *Exceptions: * *******************************************************************************/ intptr_t __cdecl _tspawnvpe ( int modeflag, REG3 const _TSCHAR *filename, const _TSCHAR * const *argv, const _TSCHAR * const *envptr ) { intptr_t i; REG1 _TSCHAR *env; REG2 _TSCHAR *buf = NULL; _TSCHAR *pfin; #ifdef _DOS_ int tempamblksiz; /* old _amblksiz */ #endif _ASSERTE(filename != NULL); _ASSERTE(*filename != _T('\0')); _ASSERTE(argv != NULL); _ASSERTE(*argv != NULL); _ASSERTE(**argv != _T('\0')); #ifdef _DOS_ tempamblksiz = _amblksiz; _amblksiz = 0x10; /* reduce _amblksiz for efficient mallocs */ #endif 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 */ #ifdef _DOS_ || (_tcschr(filename,SLASHCHAR) != NULL) /* filename contains a '\', return failure */ || *filename && *(filename+1) == _T(':') /* drive specification, return failure */ #endif || !(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 */ ) { #ifdef _DOS_ _amblksiz = tempamblksiz; /* restore old _amblksiz */ #endif goto done; } #ifdef _DOS_ _amblksiz = tempamblksiz; /* restore old _amblksiz */ #endif /* 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 while ( (env = _getpath(env, buf, _MAX_PATH - 1)) && (*buf) ) { #endif 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 if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR) _tcscat(buf, SLASH); #endif /* 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 && (!ISSLASH(*buf) || !ISSLASH(*(buf+1)))) ) #endif break; } done: if (buf != NULL) _free_crt(buf); return(i); }