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.

277 lines
10 KiB

  1. /***
  2. *dospawn.c - spawn a child process
  3. *
  4. * Copyright (c) 1989-2001, Microsoft Corporation. All rights reserved.
  5. *
  6. *Purpose:
  7. * defines _dospawn - spawn a child process
  8. *
  9. *Revision History:
  10. * 06-07-89 PHG Module created, based on asm version
  11. * 03-08-90 GJF Made calling type _CALLTYPE2 (for now), added #include
  12. * <cruntime.h> and fixed the copyright. Also, cleaned
  13. * up the formatting a bit.
  14. * 04-02-90 GJF Now _CALLTYPE1. Added const to type of name arg.
  15. * 07-24-90 SBM Removed '32' from API names
  16. * 09-27-90 GJF New-style function declarator.
  17. * 10-30-90 GJF Added _p_overlay (temporary hack).
  18. * 12-04-90 SRW Changed to include <oscalls.h> instead of <doscalls.h>
  19. * 12-06-90 SRW Added _CRUISER_ and _WIN32 conditionals.
  20. * 01-16-91 SRW Fixed return value for dospawn [_WIN32_]
  21. * 01-17-91 GJF ANSI naming.
  22. * 01-25-91 SRW Changed CreateProcess parameters [_WIN32_]
  23. * 01-29-91 SRW Changed CreateProcess parameters again [_WIN32_]
  24. * 02-05-91 SRW Changed to pass _osfile and _osfhnd arrays as binary
  25. * data to child process. [_WIN32_]
  26. * 02-18-91 SRW Fixed code to return correct process handle and close
  27. * handle for P_WAIT case. [_WIN32_]
  28. * 04-05-91 SRW Fixed code to free StartupInfo.lpReserved2 after
  29. * CreateProcess call. [_WIN32_]
  30. * 04-26-91 SRW Removed level 3 warnings (_WIN32_)
  31. * 12-02-91 SRW Fixed command line setup code to not append an extra
  32. * space [_WIN32_]
  33. * 12-16-91 GJF Return full 32-bit exit code from the child process
  34. * [_WIN32_].
  35. * 02-14-92 GJF Replaced _nfile with _nhandle for Win32.
  36. * 02-18-92 GJF Merged in 12-16-91 change from \\vangogh version
  37. * 11-20-92 SKS errno/_doserrno must be 0 in case of success. This
  38. * will distinguish a child process return code of -1L
  39. * (errno == 0) from an actual error (where errno != 0).
  40. * 01-08-93 CFW Added code to handle _P_DETACH case; add fdwCreate
  41. * variable, nuke stdin, stdout, stderr entries of _osfile
  42. * & _osfhnd tables, close process handle to completely
  43. * detach process
  44. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  45. * 12-07-93 CFW Rip out Cruiser.
  46. * 12-07-93 CFW Wide char enable, remove _p_overlay.
  47. * 01-05-94 CFW Unremove _p_overlay.
  48. * 01-10-95 CFW Debug CRT allocs.
  49. * 06-12-95 GJF Revised passing of C file handles to work from the
  50. * ioinfo arrays.
  51. * 07-10-95 GJF Use UNALIGNED to avoid choking RISC platforms.
  52. * 05-17-96 GJF Don't pass info on handles marked FNOINHERIT (new
  53. * flag) to the child process.
  54. * 02-05-98 GJF Changes for Win64: return type changed to intptr_t.
  55. * 01-09-00 PML Sign-extend exit code for _P_WAIT on Win64.
  56. * 07-07-01 BWT Return -1 if unable to alloc file ptr table (lpReserved2).
  57. *
  58. *******************************************************************************/
  59. #include <cruntime.h>
  60. #include <oscalls.h>
  61. #include <internal.h>
  62. #include <msdos.h>
  63. #include <process.h>
  64. #include <string.h>
  65. #include <errno.h>
  66. #include <stdlib.h>
  67. #include <tchar.h>
  68. #include <dbgint.h>
  69. #ifndef WPRFLAG
  70. int _p_overlay = 2;
  71. #endif
  72. /***
  73. *int _dospawn(mode, name, cmdblk, envblk) - spawn a child process
  74. *
  75. *Purpose:
  76. * Spawns a child process
  77. *
  78. *Entry:
  79. * int mode - _P_WAIT, _P_NOWAIT, _P_NOWAITO, _P_OVERLAY, or _P_DETACH
  80. * _TSCHAR *name - name of program to execute
  81. * _TSCHAR *cmdblk - parameter block
  82. * _TSCHAR *envblk - environment block
  83. *
  84. *Exit:
  85. * _P_OVERLAY: -1 = error, otherwise doesn't return
  86. * _P_WAIT: termination code << 8 + result code
  87. * _P_DETACH: -1 = error, 0 = success
  88. * others: PID of process
  89. *
  90. *Exceptions:
  91. *
  92. *******************************************************************************/
  93. #ifdef WPRFLAG
  94. intptr_t __cdecl _wdospawn (
  95. #else
  96. intptr_t __cdecl _dospawn (
  97. #endif
  98. int mode,
  99. const _TSCHAR *name,
  100. _TSCHAR *cmdblk,
  101. _TSCHAR *envblk
  102. )
  103. {
  104. char syncexec, asyncresult, background;
  105. LPTSTR CommandLine;
  106. STARTUPINFO StartupInfo;
  107. PROCESS_INFORMATION ProcessInformation;
  108. BOOL CreateProcessStatus;
  109. ULONG dosretval; /* OS return value */
  110. DWORD exitcode;
  111. intptr_t retval;
  112. DWORD fdwCreate = 0; /* flags for CreateProcess */
  113. int i;
  114. ioinfo *pio;
  115. char *posfile;
  116. UNALIGNED intptr_t *posfhnd;
  117. int nh; /* number of file handles to be
  118. passed to the child */
  119. /* translate input mode value to individual flags */
  120. syncexec = asyncresult = background = 0;
  121. switch (mode) {
  122. case _P_WAIT: syncexec=1; break; /* synchronous execution */
  123. case 2: /* _P_OVERLAY */
  124. case _P_NOWAITO: break; /* asynchronous execution */
  125. case _P_NOWAIT: asyncresult=1; break; /* asynch + remember result */
  126. case _P_DETACH: background=1; break; /* detached in null scrn grp */
  127. default:
  128. /* invalid mode */
  129. errno = EINVAL;
  130. _doserrno = 0; /* not a Dos error */
  131. return -1;
  132. }
  133. /*
  134. * Loop over null separate arguments, and replace null separators
  135. * with spaces to turn it back into a single null terminated
  136. * command line.
  137. */
  138. CommandLine = cmdblk;
  139. while (*cmdblk) {
  140. while (*cmdblk) {
  141. cmdblk++;
  142. }
  143. /*
  144. * If not last argument, turn null separator into a space.
  145. */
  146. if (cmdblk[1] != _T('\0')) {
  147. *cmdblk++ = _T(' ');
  148. }
  149. }
  150. memset(&StartupInfo,0,sizeof(StartupInfo));
  151. StartupInfo.cb = sizeof(StartupInfo);
  152. for ( nh = _nhandle ;
  153. nh && !_osfile(nh - 1) ;
  154. nh-- ) ;
  155. StartupInfo.cbReserved2 = (WORD)(sizeof( int ) + (nh *
  156. (sizeof( char ) +
  157. sizeof( intptr_t ))));
  158. StartupInfo.lpReserved2 = _calloc_crt( StartupInfo.cbReserved2, 1 );
  159. if (!StartupInfo.lpReserved2) {
  160. errno = ENOMEM;
  161. return -1;
  162. }
  163. *((UNALIGNED int *)(StartupInfo.lpReserved2)) = nh;
  164. for ( i = 0,
  165. posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
  166. posfhnd = (UNALIGNED intptr_t *)(StartupInfo.lpReserved2 +
  167. sizeof( int ) + (nh * sizeof( char ))) ;
  168. i < nh ;
  169. i++, posfile++, posfhnd++ )
  170. {
  171. pio = _pioinfo(i);
  172. if ( (pio->osfile & FNOINHERIT) == 0 ) {
  173. *posfile = pio->osfile;
  174. *posfhnd = pio->osfhnd;
  175. }
  176. else {
  177. *posfile = 0;
  178. *posfhnd = (intptr_t)INVALID_HANDLE_VALUE;
  179. }
  180. }
  181. /*
  182. * if the child process is detached, it cannot access the console, so
  183. * we must nuke the information passed for the first three handles.
  184. */
  185. if ( background ) {
  186. for ( i = 0,
  187. posfile = (char *)(StartupInfo.lpReserved2 + sizeof( int )),
  188. posfhnd = (UNALIGNED intptr_t *)(StartupInfo.lpReserved2 + sizeof( int )
  189. + (nh * sizeof( char ))) ;
  190. i < __min( nh, 3 ) ;
  191. i++, posfile++, posfhnd++ )
  192. {
  193. *posfile = 0;
  194. *posfhnd = (intptr_t)INVALID_HANDLE_VALUE;
  195. }
  196. fdwCreate |= DETACHED_PROCESS;
  197. }
  198. /**
  199. * Set errno to 0 to distinguish a child process
  200. * which returns -1L from an error in the spawning
  201. * (which will set errno to something non-zero
  202. **/
  203. _doserrno = errno = 0 ;
  204. #ifdef WPRFLAG
  205. /* indicate to CreateProcess that environment block is wide */
  206. fdwCreate |= CREATE_UNICODE_ENVIRONMENT;
  207. #endif
  208. CreateProcessStatus = CreateProcess( (LPTSTR)name,
  209. CommandLine,
  210. NULL,
  211. NULL,
  212. TRUE,
  213. fdwCreate,
  214. envblk,
  215. NULL,
  216. &StartupInfo,
  217. &ProcessInformation
  218. );
  219. dosretval = GetLastError();
  220. _free_crt( StartupInfo.lpReserved2 );
  221. if (!CreateProcessStatus) {
  222. _dosmaperr(dosretval);
  223. return -1;
  224. }
  225. if (mode == 2 /* _P_OVERLAY */) {
  226. /* destroy ourselves */
  227. _exit(0);
  228. }
  229. else if (mode == _P_WAIT) {
  230. WaitForSingleObject(ProcessInformation.hProcess, (DWORD)(-1L));
  231. /* return termination code and exit code -- note we return
  232. the full exit code */
  233. GetExitCodeProcess(ProcessInformation.hProcess, &exitcode);
  234. retval = (intptr_t)(int)exitcode;
  235. CloseHandle(ProcessInformation.hProcess);
  236. }
  237. else if (mode == _P_DETACH) {
  238. /* like totally detached asynchronous spawn, dude,
  239. close process handle, return 0 for success */
  240. CloseHandle(ProcessInformation.hProcess);
  241. retval = (intptr_t)0;
  242. }
  243. else {
  244. /* asynchronous spawn -- return PID */
  245. retval = (intptr_t)ProcessInformation.hProcess;
  246. }
  247. CloseHandle(ProcessInformation.hThread);
  248. return retval;
  249. }