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.

360 lines
13 KiB

  1. /***
  2. *spawnve.c - Low level routine eventually called by all _spawnXX routines
  3. * also contains all code for _execve, called by _execXX routines
  4. *
  5. * Copyright (c) 1985-2001, Microsoft Corporation. All rights reserved.
  6. *
  7. *Purpose:
  8. *
  9. * This is the low level routine which is eventually invoked by all the
  10. * _spawnXX routines.
  11. *
  12. * This is also the low-level routine which is eventually invoked by
  13. * all of the _execXX routines.
  14. *
  15. *Revision History:
  16. * 03-??-84 RLB created
  17. * 05-??-84 DCW modified to fix bug in initialization of envblock
  18. * pointer (used int 0 which would fail in long model) and
  19. * changed (char *)0 to NULL.
  20. * 03-31-86 SKS modified for OS/2; no OVERLAY mode,
  21. * new format for DOS Exec function
  22. * also check for Xenix or DOS style slash characters
  23. * 10-13-86 SKS pass program name to _cenvarg()
  24. * 11-19-86 SKS handle both kinds of slashes, with support for Kanji
  25. * 01-29-87 BCM don't try ".com" extension in protected mode (OS/2)
  26. * 12-11-87 JCR Added "_LOAD_DS" to declaration
  27. * 05/31/88 SJM Re-written to allow spawn of .CMD files, increase
  28. * speed. Added comexecmd routine.
  29. * 06/01/88 SJM added #ifdef statements for execve.obj compilation
  30. * 10-30-88 GJF Call _dospawn() for EXECVE, not _doexec().
  31. * 07-21-89 GJF Progagated fixes of 11-23-88 and 05-27-89 from CRT tree.
  32. * 11-16-89 GJF Added code to execve/spawnve to ensure a relative or
  33. * or absolute pathname is always used for the executable,
  34. * not just a filename (otherwise DOSEXECPGM will search
  35. * the PATH!). Also, cleaned up some of the erratic
  36. * formatting. Same as 9-15-89 change to CRT version
  37. * 11-20-89 GJF Added const attribute to types of appropriate args.
  38. * 02-08-90 GJF Fixed bug in comexecmd (must free(comname) if and only
  39. * if comname points to a malloc-ed block). Propagated
  40. * from 02-07-90 change in crt6 version.
  41. * 03-08-90 GJF Replaced _LOAD_DS with _CALLTYPE1, added #include
  42. * <cruntime.h> and removed #include <register.h>.
  43. * 04-02-90 GJF Made comexecmd() _CALLTYPE4. Added #include <io.h>
  44. * and a prototype for comexecmd() to fix compiler
  45. * warnings (-W3).
  46. * 05-21-90 GJF Fixed stack checking pragma syntax.
  47. * 07-24-90 SBM Removed redundant include, minor optimization
  48. * 09-27-90 GJF New-style function declarators.
  49. * 12-28-90 SRW Added _CRUISER_ conditional around check_stack pragma
  50. * 01-17-91 GJF ANSI naming.
  51. * 08-21-91 JCR Call access() in before comexecmd (bug fix)
  52. * 01-24-92 JCR upgraded for Win32
  53. * 10-24-92 SKS Remove special treatment for batch files -
  54. * Windows NT will spawn %COMSPEC% automatically
  55. * 11-30-92 KRS Ported _MBCS support from 16-bit tree.
  56. * 04-06-93 SKS Replace _CRTAPI* with __cdecl
  57. * 12-07-93 CFW Rip out Cruiser.
  58. * 12-07-93 CFW Wide char enable.
  59. * 01-10-95 CFW Debug CRT allocs.
  60. * 02-06-98 GJF Changes for Win64: changed return type to intptr_t.
  61. *
  62. *******************************************************************************/
  63. #include <cruntime.h>
  64. #include <io.h>
  65. #include <process.h>
  66. #include <errno.h>
  67. #include <msdos.h>
  68. #include <string.h>
  69. #include <stdlib.h>
  70. #include <internal.h>
  71. #include <mbstring.h>
  72. #include <tchar.h>
  73. #include <dbgint.h>
  74. #define SLASHCHAR _T('\\')
  75. #define XSLASHCHAR _T('/')
  76. #ifndef EXECVE
  77. #ifdef WPRFLAG
  78. static intptr_t __cdecl wcomexecmd(int mode, const wchar_t * name,
  79. const wchar_t * const * argv, const wchar_t * const * envp);
  80. #else
  81. static intptr_t __cdecl comexecmd(int mode, const char * name,
  82. const char * const * argv, const char * const * envp);
  83. #endif
  84. #else /* EXECVE */
  85. #ifdef WPRFLAG
  86. static intptr_t __cdecl wcomexecmd(const wchar_t * name,
  87. const wchar_t * const * argv, const wchar_t * const * envp);
  88. #else
  89. static intptr_t __cdecl comexecmd(const char * name,
  90. const char * const * argv, const char * const * envp);
  91. #endif
  92. #endif /* EXECVE */
  93. /***
  94. *static int comexecmd(mode, name, argv, envp) - do the exec
  95. * or spawn after name fixup
  96. *
  97. *Purpose:
  98. * Spawns a child process with given parameters and environment. Either
  99. * overlays current process or loads in free memory while parent process
  100. * waits. If the named file is a .cmd file, modifies the calling sequence
  101. * and prepends the /c and filename arguments into the command string
  102. *
  103. * Exec doesn't take a mode; instead, the parent process goes away as
  104. * the child process is brought in.
  105. *
  106. *Entry:
  107. * int mode - mode to spawn (WAIT, NOWAIT, or OVERLAY)
  108. * only WAIT and OVERLAY currently supported
  109. *
  110. * **** mode is only used in the spawnve() version ****
  111. *
  112. * _TSCHAR *name - pathname of file to spawn. Includes the extension
  113. * _TSCHAR **argv - vector of parameter strings
  114. * _TSCHAR **envp - vector of environment variables
  115. *
  116. *Exit:
  117. * returns exit code of child process
  118. * if fails, returns -1
  119. *
  120. *Exceptions:
  121. * Returns a value of (-1) to indicate an error in exec'ing the child
  122. * process. errno may be set to:
  123. *
  124. * E2BIG = failed in argument/environment processing (_cenvarg)
  125. * argument list or environment too big;
  126. * EACCESS = locking or sharing violation on file;
  127. * EMFILE = too many files open;
  128. * ENOENT = failed to find program name - no such file or directory;
  129. * ENOEXEC = failed in exec - bad executable format;
  130. * ENOMEM = failed in memory allocation (during malloc, or in
  131. * setting up memory for executing child process).
  132. *
  133. *******************************************************************************/
  134. #ifdef WPRFLAG
  135. static intptr_t __cdecl wcomexecmd (
  136. #else
  137. static intptr_t __cdecl comexecmd (
  138. #endif
  139. #ifndef EXECVE
  140. REG3 int mode,
  141. #endif /* EXECVE */
  142. REG2 const _TSCHAR *name,
  143. const _TSCHAR * const *argv,
  144. const _TSCHAR * const *envp
  145. )
  146. {
  147. _TSCHAR *argblk;
  148. _TSCHAR *envblk;
  149. REG4 intptr_t rc;
  150. #ifdef WPRFLAG
  151. if (_wcenvarg(argv, envp, &argblk, &envblk, name) == -1)
  152. #else
  153. if (_cenvarg(argv, envp, &argblk, &envblk, name) == -1)
  154. #endif
  155. return -1;
  156. #ifndef EXECVE
  157. #ifdef WPRFLAG
  158. rc = _wdospawn(mode, name, argblk, envblk);
  159. #else
  160. rc = _dospawn(mode, name, argblk, envblk);
  161. #endif
  162. #else /* EXECVE */
  163. #ifdef WPRFLAG
  164. rc = _wdospawn(_P_OVERLAY, name, argblk, envblk);
  165. #else
  166. rc = _dospawn(_P_OVERLAY, name, argblk, envblk);
  167. #endif
  168. #endif /* EXECVE */
  169. /* free memory */
  170. _free_crt(argblk);
  171. _free_crt(envblk);
  172. return rc;
  173. }
  174. /***
  175. *int _spawnve(mode, name, argv, envp) - low level _spawnXX library function
  176. *int _execve(name, argv, envp) - low level _execXX library function
  177. *
  178. *Purpose:
  179. * spawns or execs a child process; takes a single pointer to an argument
  180. * list as well as a pointer to the environment; unlike _spawnvpe,
  181. * _spawnve does not search the PATH= list in processing the name
  182. * parameter; mode specifies the parent's execution mode.
  183. *
  184. *Entry:
  185. * int mode - parent process's execution mode:
  186. * must be one of _P_OVERLAY, _P_WAIT, _P_NOWAIT;
  187. * not used for _execve
  188. * _TSCHAR *name - path name of program to spawn;
  189. * _TSCHAR **argv - pointer to array of pointers to child's arguments;
  190. * _TSCHAR **envp - pointer to array of pointers to child's environment
  191. * settings.
  192. *
  193. *Exit:
  194. * Returns : (int) a status value whose meaning is as follows:
  195. * 0 = normal termination of child process;
  196. * positive = exit code of child upon error termination
  197. * (abort or exit(nonzero));
  198. * -1 = child process was not spawned;
  199. * errno indicates what kind of error:
  200. * (E2BIG, EINVAL, ENOENT, ENOEXEC, ENOMEM).
  201. *
  202. *Exceptions:
  203. * Returns a value of (-1) to indicate an error in spawning the child
  204. * process. errno may be set to:
  205. *
  206. * E2BIG = failed in argument/environment processing (_cenvarg) -
  207. * argument list or environment too big;
  208. * EINVAL = invalid mode argument;
  209. * ENOENT = failed to find program name - no such file or directory;
  210. * ENOEXEC = failed in spawn - bad executable format;
  211. * ENOMEM = failed in memory allocation (during malloc, or in
  212. * setting up memory for spawning child process).
  213. *
  214. *******************************************************************************/
  215. /* Extension array - ordered in search order from right to left.
  216. ext_strings = array of extensions
  217. */
  218. static _TSCHAR *ext_strings[] = { _T(".cmd"), _T(".bat"), _T(".exe"), _T(".com") };
  219. enum {CMD, BAT, EXE, COM, EXTFIRST=CMD, EXTLAST=COM};
  220. intptr_t __cdecl
  221. #ifndef EXECVE
  222. _tspawnve (
  223. REG3 int mode,
  224. #else /* EXECVE */
  225. _texecve (
  226. #endif /* EXECVE */
  227. const _TSCHAR *name,
  228. const _TSCHAR * const *argv,
  229. const _TSCHAR * const *envp
  230. )
  231. {
  232. _TSCHAR *ext; /* where the extension goes if we have to add one */
  233. REG1 _TSCHAR *p;
  234. _TSCHAR *q;
  235. REG2 _TSCHAR *pathname = (_TSCHAR *)name;
  236. REG4 intptr_t rc;
  237. REG5 int i;
  238. p = _tcsrchr(pathname, SLASHCHAR);
  239. q = _tcsrchr(pathname, XSLASHCHAR);
  240. /* ensure that pathname is an absolute or relative pathname. also,
  241. * position p to point at the filename portion of pathname (i.e., just
  242. * after the last occurence of a colon, slash or backslash character */
  243. if (!q) {
  244. if (!p)
  245. if (!(p = _tcschr(pathname, _T(':')))) {
  246. /* pathname is a filename only, force it to be
  247. * a relative pathname. note that an extra byte
  248. * is malloc-ed just in case pathname is NULL,
  249. * to keep the heap from being trashed by
  250. * strcpy */
  251. if (!(pathname = _malloc_crt((_tcslen(pathname) + 3) * sizeof(_TSCHAR))))
  252. return(-1);
  253. _tcscpy(pathname, _T(".\\"));
  254. _tcscat(pathname, name);
  255. /* set p to point to the start of the filename
  256. * (i.e., past the ".\\" prefix) */
  257. p = pathname + 2;
  258. }
  259. /* else pathname has drive specifier prefix and p is
  260. * is pointing to the ':' */
  261. }
  262. else if (!p || q > p) /* p == NULL or q > p */
  263. p = q;
  264. rc = -1; /* init to error value */
  265. if (ext = _tcsrchr(p, _T('.'))) {
  266. /* extension given; only do filename */
  267. if (_taccess(pathname, 0) != -1) {
  268. #ifndef EXECVE
  269. #ifdef WPRFLAG
  270. rc = wcomexecmd(mode, pathname, argv, envp);
  271. #else
  272. rc = comexecmd(mode, pathname, argv, envp);
  273. #endif
  274. #else /* EXECVE */
  275. #ifdef WPRFLAG
  276. rc = wcomexecmd(pathname, argv, envp);
  277. #else
  278. rc = comexecmd(pathname, argv, envp);
  279. #endif
  280. #endif /* EXECVE */
  281. }
  282. }
  283. else {
  284. /* no extension; try .cmd/.bat, then .com and .exe */
  285. if (!(p = _malloc_crt((_tcslen(pathname) + 5) * sizeof(_TSCHAR))))
  286. return(-1);
  287. _tcscpy(p, pathname);
  288. ext = p + _tcslen(pathname);
  289. for (i = EXTLAST; i >= EXTFIRST; --i) {
  290. _tcscpy(ext, ext_strings[i]);
  291. if (_taccess(p, 0) != -1) {
  292. #ifndef EXECVE
  293. #ifdef WPRFLAG
  294. rc = wcomexecmd(mode, p, argv, envp);
  295. #else
  296. rc = comexecmd(mode, p, argv, envp);
  297. #endif
  298. #else /* EXECVE */
  299. #ifdef WPRFLAG
  300. rc = wcomexecmd(p, argv, envp);
  301. #else
  302. rc = comexecmd(p, argv, envp);
  303. #endif
  304. #endif /* EXECVE */
  305. break;
  306. }
  307. }
  308. _free_crt(p);
  309. }
  310. if (pathname != name)
  311. _free_crt(pathname);
  312. return rc;
  313. }