Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

218 lines
7.8 KiB

  1. /***
  2. *spawnvpe.c - spawn a child process with given environ (search PATH)
  3. *
  4. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _spawnvpe() - spawn a child process with given environ (search
  8. * PATH)
  9. *
  10. *Revision History:
  11. * 04-15-84 DFW written
  12. * 10-29-85 TC added spawnvpe capability
  13. * 11-19-86 SKS handle both kinds of slashes
  14. * 12-01-86 JMB added Kanji file name support under conditional KANJI
  15. * switches. Corrected header info. Removed bogus check
  16. * for env = b after call to strncpy
  17. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  18. * 09-05-88 SKS Treat EACCES the same as ENOENT -- keep trying
  19. * 10-17-88 GJF Removed copy of PATH string to local array, changed
  20. * bbuf to be a malloc-ed buffer. Removed bogus limits
  21. * on the size of that PATH string.
  22. * 10-25-88 GJF Don't search PATH when relative pathname is given (per
  23. * Stevesa). Also, if the name built from PATH component
  24. * and filename is a UNC name, allow any error.
  25. * 05-17-89 MT Added "include <jstring.h>" under KANJI switch
  26. * 05-24-89 PHG Reduce _amblksiz to use minimal memory (DOS only)
  27. * 08-29-89 GJF Use _getpath() to retrieve PATH components, fixing
  28. * several problems in handling unusual or bizarre
  29. * PATH's.
  30. * 11-20-89 GJF Added const attribute to types of filename, argv and
  31. * envptr.
  32. * 03-08-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  33. * <cruntime.h> and removed #include <register.h>
  34. * 07-24-90 SBM Removed redundant includes, replaced <assertm.h> by
  35. * <assert.h>
  36. * 09-27-90 GJF New-style function declarator.
  37. * 01-17-91 GJF ANSI naming.
  38. * 09-25-91 JCR Changed ifdef "OS2" to "_DOS_" (unused in 32-bit tree)
  39. * 11-30-92 KRS Port _MBCS code from 16-bit tree.
  40. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  41. * 12-07-93 CFW Wide char enable.
  42. * 01-10-95 CFW Debug CRT allocs.
  43. * 02-06-95 CFW assert -> _ASSERTE.
  44. * 02-06-98 GJF Changes for Win64: changed return type to intptr_t.
  45. *
  46. *******************************************************************************/
  47. #include <cruntime.h>
  48. #include <errno.h>
  49. #include <stdlib.h>
  50. #include <string.h>
  51. #include <malloc.h>
  52. #include <internal.h>
  53. #include <process.h>
  54. #include <mbstring.h>
  55. #include <tchar.h>
  56. #include <dbgint.h>
  57. #define SLASH _T("\\")
  58. #define SLASHCHAR _T('\\')
  59. #define XSLASHCHAR _T('/')
  60. #define DELIMITER _T(";")
  61. #ifdef _MBCS
  62. /* note, the macro below assumes p is to pointer to a single-byte character
  63. * or the 1st byte of a double-byte character, in a string.
  64. */
  65. #define ISPSLASH(p) ( ((p) == _mbschr((p), SLASHCHAR)) || ((p) == \
  66. _mbschr((p), XSLASHCHAR)) )
  67. #else
  68. #define ISSLASH(c) ( ((c) == SLASHCHAR) || ((c) == XSLASHCHAR) )
  69. #endif
  70. /***
  71. *_spawnvpe(modeflag, filename, argv, envptr) - spawn a child process
  72. *
  73. *Purpose:
  74. * Spawns a child process with the given arguments and environ,
  75. * searches along PATH for given file until found.
  76. * Formats the parameters and calls _spawnve to do the actual work. The
  77. * NULL environment pointer indicates that the new process will inherit
  78. * the parents process's environment. NOTE - at least one argument must
  79. * be present. This argument is always, by convention, the name of the
  80. * file being spawned.
  81. *
  82. *Entry:
  83. * int modeflag - defines mode of spawn (WAIT, NOWAIT, or OVERLAY)
  84. * only WAIT and OVERLAY supported
  85. * _TSCHAR *filename - name of file to execute
  86. * _TSCHAR **argv - vector of parameters
  87. * _TSCHAR **envptr - vector of environment variables
  88. *
  89. *Exit:
  90. * returns exit code of spawned process
  91. * if fails, returns -1
  92. *
  93. *Exceptions:
  94. *
  95. *******************************************************************************/
  96. intptr_t __cdecl _tspawnvpe (
  97. int modeflag,
  98. REG3 const _TSCHAR *filename,
  99. const _TSCHAR * const *argv,
  100. const _TSCHAR * const *envptr
  101. )
  102. {
  103. intptr_t i;
  104. REG1 _TSCHAR *env;
  105. REG2 _TSCHAR *buf = NULL;
  106. _TSCHAR *pfin;
  107. #ifdef _DOS_
  108. int tempamblksiz; /* old _amblksiz */
  109. #endif
  110. _ASSERTE(filename != NULL);
  111. _ASSERTE(*filename != _T('\0'));
  112. _ASSERTE(argv != NULL);
  113. _ASSERTE(*argv != NULL);
  114. _ASSERTE(**argv != _T('\0'));
  115. #ifdef _DOS_
  116. tempamblksiz = _amblksiz;
  117. _amblksiz = 0x10; /* reduce _amblksiz for efficient mallocs */
  118. #endif
  119. if (
  120. (i = _tspawnve(modeflag, filename, argv, envptr)) != -1
  121. /* everything worked just fine; return i */
  122. || (errno != ENOENT)
  123. /* couldn't spawn the process, return failure */
  124. || (_tcschr(filename, XSLASHCHAR) != NULL)
  125. /* filename contains a '/', return failure */
  126. #ifdef _DOS_
  127. || (_tcschr(filename,SLASHCHAR) != NULL)
  128. /* filename contains a '\', return failure */
  129. || *filename && *(filename+1) == _T(':')
  130. /* drive specification, return failure */
  131. #endif
  132. || !(env = _tgetenv(_T("PATH")))
  133. /* no PATH environment string name, return failure */
  134. || ( (buf = _malloc_crt(_MAX_PATH * sizeof(_TSCHAR))) == NULL )
  135. /* cannot allocate buffer to build alternate pathnames, return
  136. * failure */
  137. ) {
  138. #ifdef _DOS_
  139. _amblksiz = tempamblksiz; /* restore old _amblksiz */
  140. #endif
  141. goto done;
  142. }
  143. #ifdef _DOS_
  144. _amblksiz = tempamblksiz; /* restore old _amblksiz */
  145. #endif
  146. /* could not find the file as specified, search PATH. try each
  147. * component of the PATH until we get either no error return, or the
  148. * error is not ENOENT and the component is not a UNC name, or we run
  149. * out of components to try.
  150. */
  151. #ifdef WPRFLAG
  152. while ( (env = _wgetpath(env, buf, _MAX_PATH - 1)) && (*buf) ) {
  153. #else
  154. while ( (env = _getpath(env, buf, _MAX_PATH - 1)) && (*buf) ) {
  155. #endif
  156. pfin = buf + _tcslen(buf) - 1;
  157. /* if necessary, append a '/'
  158. */
  159. #ifdef _MBCS
  160. if (*pfin == SLASHCHAR) {
  161. if (pfin != _mbsrchr(buf,SLASHCHAR))
  162. /* fin is the second byte of a double-byte char */
  163. strcat(buf, SLASH );
  164. }
  165. else if (*pfin !=XSLASHCHAR)
  166. strcat(buf, SLASH);
  167. #else
  168. if (*pfin != SLASHCHAR && *pfin != XSLASHCHAR)
  169. _tcscat(buf, SLASH);
  170. #endif
  171. /* check that the final path will be of legal size. if so,
  172. * build it. otherwise, return to the caller (return value
  173. * and errno rename set from initial call to _spawnve()).
  174. */
  175. if ( (_tcslen(buf) + _tcslen(filename)) < _MAX_PATH )
  176. _tcscat(buf, filename);
  177. else
  178. break;
  179. /* try spawning it. if successful, or if errno comes back with a
  180. * value other than ENOENT and the pathname is not a UNC name,
  181. * return to the caller.
  182. */
  183. if ( (i = _tspawnve(modeflag, buf, argv, envptr)) != -1
  184. || ((errno != ENOENT)
  185. #ifdef _MBCS
  186. && (!ISPSLASH(buf) || !ISPSLASH(buf+1))) )
  187. #else
  188. && (!ISSLASH(*buf) || !ISSLASH(*(buf+1)))) )
  189. #endif
  190. break;
  191. }
  192. done:
  193. if (buf != NULL)
  194. _free_crt(buf);
  195. return(i);
  196. }