ReactOS 0.4.16-dev-853-g88d9285
spawnv.cpp
Go to the documentation of this file.
1//
2// spawnv.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the -v and -ve flavors of the _exec() and _spawn() functions.
7//
8// There are many varieties of the _exec() and _spawn() functions. A high level
9// summary of the behavioral differences is as follows:
10//
11// All of these functions execute a new process. The _spawn() functions all take
12// a 'mode' parameter, which specifies the way in which the process is started.
13// The 'mode' must be one of the _P_-prefixed modes from <process.h>. The _exec()
14// family of functions execute a new process, then call _exit() to terminate the
15// calling process. Each _exit() function is equivalent to the corresponding
16// _spawn() function with the _P_OVERLAY mode.
17//
18// There are eight variants each of _exec() and _spawn(), suffixed with -l, -le,
19// -lp, -lpe, -v, -ve, -vp, and -vpe.
20//
21// If a function has 'e' in its suffix, it accepts an environment with which to
22// create the new process. If a function does not have 'e' in its suffix, it
23// does not accept an environment and instead uses the environment of the calling
24// process. A call to an 'e' function with a null environment argument has the
25// same effect as calling the non-'e'-suffixed equivalent.
26//
27// Each _exec() or _spawn() function has either an 'l' or 'v' suffix. These have
28// equivalent functionality; they differ only in how they accept their arguments.
29// The 'l'-suffixed functions accept the command-line arguments and the environment
30// as varargs. There must be at least one command line argument (conventionally
31// the name of the program to be executed). If the function accepts an environment
32// (if it is 'e'-suffixed), then there must be a null pointer between the last
33// argument and the first environment variable. The arguments are terminated by a
34// null pointer.
35//
36// The 'v'-suffixed functions accept a pair of pointers: one to the argv vector
37// and one to the envp vector. Each is an array of pointers terminated by a null
38// pointer, similar to how arguments and the environment are passed to main().
39//
40// Finally, if a function has a 'p' in its suffix, and if the provided executable
41// file name is just a file name (and does not contain any path component), the
42// %PATH% is searched for an executable with the given name. If a function does
43// not have a 'p' suffix, then the environment is not searched; the executable
44// must be found simply by passing its name to CreateProcess.
45//
46// All functions return -1 and set errno on failure. On success, the _exec()
47// functions do not return. On success, the _spawn() functions return different
48// things, depending on the provided mode. See the CreateProcess invocation
49// logic in this file for details.
50//
51// Note that the only supported modes are wait and overlay.
52//
53// These functions may set errno to one of the following values:
54// * E2BIG: Failed in argument or environment processing because the argument
55// list or environment is too large.
56// * EACCESS: Locking or sharing violation on a file
57// * EMFILE: Too many files open
58// * ENOENT: Failed to find the program (no such file or directory)
59// * ENOEXEC: Failed in a call to exec() due to a bad executable format
60// * ENOMEM: Failed to allocate memory required for the spawn operation
61// * EINVAL: Invalid mode argumnt or process state for spawn (note that most
62// invalid arguments cause the invalid parameter handler to be
63// invoked).
64//
65#include <corecrt_internal.h>
68#include <errno.h>
69#include <io.h>
70#include <mbstring.h>
71#include <process.h>
72#include <stdlib.h>
73#include <string.h>
74
75
76
77// Accumulates the inheritable file handles into *data, in the structure expected
78// by the spawnee (see the lowio initialization code for the logic that decodes
79// this data structure). On success, *data and *size have the handle data array
80// and the size of the handle data, and true is returned. The caller must free
81// *data. On failure, false is returned and errno is set.
83 BYTE** const data,
84 size_t* const size,
85 bool const include_std_handles
86 ) throw()
87{
88 return __acrt_lock_and_call(__acrt_lowio_index_lock, [&]() -> bool
89 {
90 *data = nullptr;
91 *size = 0;
92
93 // Count the number of handles to be inherited:
94 size_t handle_count = 0;
95 for (handle_count = _nhandle; handle_count != 0 && _osfile(handle_count - 1) != 0; --handle_count)
96 {
97 }
98
99 size_t const max_handle_count = (USHRT_MAX - sizeof(int)) / (sizeof(char) + sizeof(intptr_t));
100 _VALIDATE_RETURN_NOEXC(handle_count < max_handle_count, ENOMEM, false);
101
102 size_t const handle_data_header_size = sizeof(int);
103 size_t const handle_data_element_size = sizeof(char) + sizeof(intptr_t);
104
105 unsigned short const handle_data_size = static_cast<unsigned short>(
106 handle_data_header_size +
107 handle_count * handle_data_element_size);
108
109 __crt_unique_heap_ptr<BYTE> handle_data(_calloc_crt_t(BYTE, handle_data_size));
110 _VALIDATE_RETURN_NOEXC(handle_data.get() != nullptr, ENOMEM, false);
111
112 // Set the handle count in the data:
113 *reinterpret_cast<int*>(handle_data.get()) = static_cast<int>(handle_count);
114
115 auto const first_flags = reinterpret_cast<char*>(handle_data.get() + sizeof(int));
116 auto const first_handle = reinterpret_cast<intptr_t UNALIGNED*>(first_flags + (handle_count * sizeof(char)));
117
118 // Copy the handle data:
119 auto flags_it = first_flags;
120 auto handle_it = first_handle;
121 for (size_t i = 0; i != handle_count; ++i, ++flags_it, ++handle_it)
122 {
123 __crt_lowio_handle_data* const pio = _pioinfo(i);
124 if ((pio->osfile & FNOINHERIT) == 0)
125 {
126 *flags_it = pio->osfile;
127 *handle_it = pio->osfhnd;
128 }
129 else
130 {
131 *flags_it = 0;
132 *handle_it = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
133 }
134 }
135
136 // Exclude the first three handles (stdin, stdout, stderr) if asked:
137 if (!include_std_handles)
138 {
139 flags_it = first_flags;
140 handle_it = first_handle;
141 for (size_t i = 0; i != __min(handle_count, 3); ++i, ++flags_it, ++handle_it)
142 {
143 *flags_it = 0;
144 *handle_it = reinterpret_cast<intptr_t>(INVALID_HANDLE_VALUE);
145 }
146 }
147
148 *data = handle_data.detach();
149 *size = handle_data_size;
150 return true;
151 });
152}
153
154
155
156static bool __cdecl should_create_unicode_environment(char) throw() { return false; }
157static bool __cdecl should_create_unicode_environment(wchar_t) throw() { return true; }
158
159
160
161// Spawns a child process. The mode must be one of the _P-modes from <process.h>.
162// The return value depends on the mode:
163// * _P_OVERLAY: On success, calls _exit() and does not return. Returns -1 on failure.
164// * _P_WAIT: Returns (termination_code << 8 + result_code)
165// * _P_DETACH: Returns 0 on success; -1 on failure
166// * Others: Returns a handle to the process. The caller must close the handle.
167template <typename Character>
169 int const mode,
170 Character const* const file_name,
171 Character const* const* const arguments,
172 Character const* const* const environment
173 ) throw()
174{
175 typedef __crt_char_traits<Character> traits;
176
177 _VALIDATE_RETURN(file_name != nullptr, EINVAL, -1);
178 _VALIDATE_RETURN(arguments != nullptr, EINVAL, -1);
179
181
182 __crt_unique_heap_ptr<Character> command_line;
183 __crt_unique_heap_ptr<Character> environment_block;
184 if (traits::pack_command_line_and_environment(
185 arguments,
186 environment,
187 command_line.get_address_of(),
188 environment_block.get_address_of()
189 ) == -1)
190 {
191 return -1;
192 }
193
194 __crt_unique_heap_ptr<BYTE> handle_data;
195 size_t handle_data_size;
196 if (!accumulate_inheritable_handles(handle_data.get_address_of(), &handle_data_size, mode != _P_DETACH))
197 return -1;
198
199 DWORD creation_flags = 0;
200 if (mode == _P_DETACH)
201 creation_flags |= DETACHED_PROCESS;
202
203 if (should_create_unicode_environment(Character()))
204 creation_flags |= CREATE_UNICODE_ENVIRONMENT;
205
206 _doserrno = 0;
207
208 STARTUPINFOW startup_info = { };
209 startup_info.cb = sizeof(startup_info);
210 startup_info.cbReserved2 = static_cast<WORD>(handle_data_size);
211 startup_info.lpReserved2 = handle_data.get();
212
213 PROCESS_INFORMATION process_info;
214 BOOL const create_process_status = traits::create_process(
215 const_cast<Character*>(file_name),
216 command_line.get(),
217 nullptr,
218 nullptr,
219 TRUE,
220 creation_flags,
221 environment_block.get(),
222 nullptr,
223 &startup_info,
224 &process_info);
225
226 __crt_unique_handle process_handle(process_info.hProcess);
227 __crt_unique_handle thread_handle(process_info.hThread);
228
229 if (!create_process_status)
230 {
232 return -1;
233 }
234
235 if (mode == _P_OVERLAY)
236 {
237 // Destroy ourselves:
238 _exit(0);
239 }
240 else if (mode == _P_WAIT)
241 {
242 WaitForSingleObject(process_info.hProcess, static_cast<DWORD>(-1));
243
244 // Return the termination code and exit code. Note that we return
245 // the full exit code.
247 if (0 != GetExitCodeProcess(process_info.hProcess, &exit_code))
248 {
249 return static_cast<int>(exit_code);
250 }
251 else
252 {
254 return -1;
255 }
256 }
257 else if (mode == _P_DETACH)
258 {
259 /* like totally detached asynchronous spawn, dude,
260 close process handle, return 0 for success */
261 return 0;
262 }
263 else
264 {
265 // Asynchronous spawn: return process handle:
266 return reinterpret_cast<intptr_t>(process_handle.detach());
267 }
268}
269
270
271
272template <typename Character>
274 int const mode,
275 Character const* const file_name,
276 Character const* const* const arguments,
277 Character const* const* const environment
278 ) throw()
279{
280 typedef __crt_char_traits<Character> traits;
281
282 _VALIDATE_RETURN(file_name != nullptr, EINVAL, -1);
283 _VALIDATE_RETURN(file_name[0] != '\0', EINVAL, -1);
284 _VALIDATE_RETURN(arguments != nullptr, EINVAL, -1);
285 _VALIDATE_RETURN(arguments[0] != nullptr, EINVAL, -1);
286 _VALIDATE_RETURN(arguments[0][0] != '\0', EINVAL, -1);
287
288 Character const* const final_backslash = traits::tcsrchr(file_name, '\\');
289 Character const* const final_slash = traits::tcsrchr(file_name, '/');
290
291 Character const* mutated_file_name = file_name;
292 Character const* end_of_directory = final_backslash;
293 if (!final_slash)
294 {
295 if (!final_backslash)
296 {
297 Character const* const final_colon = traits::tcsrchr(file_name, ':');
298 if (final_colon)
299 {
300 end_of_directory = final_colon;
301 }
302 else
303 {
304 // The path is a file name only. We force it to be a relative
305 // path name.
306 size_t const file_name_size = traits::tcslen(file_name) + 3;
307 __crt_unique_heap_ptr<Character> buffer(_calloc_crt_t(Character, file_name_size));
308 if (!buffer)
309 return -1;
310
311 static Character const dot_slash[] = { '.', '\\', '\0' };
312 _ERRCHECK(traits::tcscpy_s(buffer.get(), file_name_size, dot_slash));
313 _ERRCHECK(traits::tcscat_s(buffer.get(), file_name_size, file_name));
314
315 mutated_file_name = buffer.detach();
316 end_of_directory = mutated_file_name + 2; // Adjust for ".\"
317 }
318 }
319 }
320 else if (!final_backslash || final_slash > final_backslash)
321 {
322 end_of_directory = final_slash;
323 }
324
325 // If we allocated a file name above, make sure we clean it up:
326 __crt_unique_heap_ptr<Character const> const mutated_file_name_cleanup(file_name == mutated_file_name
327 ? nullptr
328 : mutated_file_name);
329
330 if (traits::tcsrchr(end_of_directory, '.'))
331 {
332 // If an extension was provided, just invoke the path:
333 if (traits::taccess_s(mutated_file_name, 0) == 0)
334 {
335 return execute_command(mode, mutated_file_name, arguments, environment);
336 }
337 }
338 else
339 {
340 // If no extension was provided, try known executable extensions:
341 size_t const buffer_size = traits::tcslen(mutated_file_name) + 5;
342 __crt_unique_heap_ptr<Character> const buffer(_calloc_crt_t(Character, buffer_size));
343 if (!buffer)
344 return -1;
345
346 _ERRCHECK(traits::tcscpy_s(buffer.get(), buffer_size, mutated_file_name));
347 Character* extension_buffer = buffer.get() + buffer_size - 5;
348
349 typedef Character const extension_type[5];
350 static extension_type const extensions[4] =
351 {
352 { '.', 'c', 'o', 'm', '\0' },
353 { '.', 'e', 'x', 'e', '\0' },
354 { '.', 'b', 'a', 't', '\0' },
355 { '.', 'c', 'm', 'd', '\0' }
356 };
357
358 errno_t const saved_errno = errno;
359
360 extension_type const* const first_extension = extensions;
361 extension_type const* const last_extension = first_extension + _countof(extensions);
362 for (auto it = first_extension; it != last_extension; ++it)
363 {
364 _ERRCHECK(traits::tcscpy_s(extension_buffer, 5, *it));
365
366 if (traits::taccess_s(buffer.get(), 0) == 0)
367 {
368 errno = saved_errno;
369 return execute_command(mode, buffer.get(), arguments, environment);
370 }
371 }
372 }
373
374 return -1;
375}
376
377
378
380 char const* const file_name,
381 char const* const* const arguments
382 )
383{
384 return common_spawnv(_P_OVERLAY, file_name, arguments, static_cast<char const* const*>(nullptr));
385}
386
388 char const* const file_name,
389 char const* const* const arguments,
390 char const* const* const environment
391 )
392{
393 return common_spawnv(_P_OVERLAY, file_name, arguments, environment);
394}
395
397 int const mode,
398 char const* const file_name,
399 char const* const* const arguments
400 )
401{
402 return common_spawnv(mode, file_name, arguments, static_cast<char const* const*>(nullptr));
403}
404
406 int const mode,
407 char const* const file_name,
408 char const* const* const arguments,
409 char const* const* const environment
410 )
411{
412 return common_spawnv(mode, file_name, arguments, environment);
413}
414
415
416
418 wchar_t const* const file_name,
419 wchar_t const* const* const arguments
420 )
421{
422 return common_spawnv(_P_OVERLAY, file_name, arguments, static_cast<wchar_t const* const*>(nullptr));
423}
424
426 wchar_t const* const file_name,
427 wchar_t const* const* const arguments,
428 wchar_t const* const* const environment
429 )
430{
431 return common_spawnv(_P_OVERLAY, file_name, arguments, environment);
432}
433
435 int const mode,
436 wchar_t const* const file_name,
437 wchar_t const* const* const arguments
438 )
439{
440 return common_spawnv(mode, file_name, arguments, static_cast<wchar_t const* const*>(nullptr));
441}
442
444 int const mode,
445 wchar_t const* const file_name,
446 wchar_t const* const* const arguments,
447 wchar_t const* const* const environment
448 )
449{
450 return common_spawnv(mode, file_name, arguments, environment);
451}
void _exit(int exitcode)
Definition: _exit.c:25
#define EINVAL
Definition: acclib.h:90
#define ENOMEM
Definition: acclib.h:84
#define __cdecl
Definition: accygwin.h:79
@ __acrt_lowio_index_lock
#define _ERRCHECK(e)
void __cdecl __acrt_errno_map_os_error(unsigned long)
Definition: errno.cpp:91
int _nhandle
Definition: ioinit.cpp:34
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
#define TRUE
Definition: types.h:120
#define INVALID_HANDLE_VALUE
Definition: compat.h:731
BOOL WINAPI GetExitCodeProcess(IN HANDLE hProcess, IN LPDWORD lpExitCode)
Definition: proc.c:1168
unsigned char
Definition: typeof.h:29
unsigned int(__cdecl typeof(jpeg_read_scanlines))(struct jpeg_decompress_struct *
Definition: typeof.h:31
unsigned int BOOL
Definition: ntddk_ex.h:94
unsigned long DWORD
Definition: ntddk_ex.h:95
unsigned short WORD
Definition: ntddk_ex.h:93
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei const GLvoid * data
Definition: gl.h:1950
GLuint buffer
Definition: glext.h:5915
GLsizeiptr size
Definition: glext.h:5919
GLenum mode
Definition: glext.h:6217
GLsizei GLenum const GLvoid GLsizei GLenum GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLint GLint GLint GLshort GLshort GLshort GLubyte GLubyte GLubyte GLuint GLuint GLuint GLushort GLushort GLushort GLbyte GLbyte GLbyte GLbyte GLdouble GLdouble GLdouble GLdouble GLfloat GLfloat GLfloat GLfloat GLint GLint GLint GLint GLshort GLshort GLshort GLshort GLubyte GLubyte GLubyte GLubyte GLuint GLuint GLuint GLuint GLushort GLushort GLushort GLushort GLboolean const GLdouble const GLfloat const GLint const GLshort const GLbyte const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLdouble const GLfloat const GLfloat const GLint const GLint const GLshort const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort const GLdouble const GLfloat const GLint const GLshort GLenum GLenum GLenum GLfloat GLenum GLint GLenum GLenum GLenum GLfloat GLenum GLenum GLint GLenum GLfloat GLenum GLint GLint GLushort GLenum GLenum GLfloat GLenum GLenum GLint GLfloat const GLubyte GLenum GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLint GLint GLsizei GLsizei GLint GLenum GLenum const GLvoid GLenum GLenum const GLfloat GLenum GLenum const GLint GLenum GLenum const GLdouble GLenum GLenum const GLfloat GLenum GLenum const GLint GLsizei GLuint GLfloat GLuint GLbitfield GLfloat GLint GLuint GLboolean GLenum GLfloat GLenum GLbitfield GLenum GLfloat GLfloat GLint GLint const GLfloat GLenum GLfloat GLfloat GLint GLint GLfloat GLfloat GLint GLint const GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat GLint GLfloat GLfloat const GLdouble const GLfloat const GLdouble const GLfloat GLint i
Definition: glfuncs.h:248
#define __min(a, b)
Definition: stdlib.h:102
#define _doserrno
Definition: stdlib.h:131
#define USHRT_MAX
Definition: limits.h:38
#define _VALIDATE_CLEAR_OSSERR_RETURN(expr, errorcode, retexpr)
#define _VALIDATE_RETURN_NOEXC(expr, errorcode, retexpr)
static UINT exit_code
Definition: process.c:78
static LPCWSTR file_name
Definition: protocol.c:147
#define _P_DETACH
Definition: port.h:374
#define _P_WAIT
Definition: port.h:370
#define _P_OVERLAY
Definition: port.h:372
#define UNALIGNED
Definition: pecoff.h:227
#define errno
Definition: errno.h:18
#define _pioinfo(i)
Definition: internal.h:71
#define _osfile(i)
Definition: internal.h:72
#define _countof(array)
Definition: sndvol32.h:70
static bool accumulate_inheritable_handles(BYTE **const data, size_t *const size, bool const include_std_handles)
Definition: spawnv.cpp:82
static bool __cdecl should_create_unicode_environment(char)
Definition: spawnv.cpp:156
intptr_t __cdecl _wexecv(wchar_t const *const file_name, wchar_t const *const *const arguments)
Definition: spawnv.cpp:417
intptr_t __cdecl _wspawnv(int const mode, wchar_t const *const file_name, wchar_t const *const *const arguments)
Definition: spawnv.cpp:434
static intptr_t __cdecl common_spawnv(int const mode, Character const *const file_name, Character const *const *const arguments, Character const *const *const environment)
Definition: spawnv.cpp:273
intptr_t __cdecl _execv(char const *const file_name, char const *const *const arguments)
Definition: spawnv.cpp:379
intptr_t __cdecl _execve(char const *const file_name, char const *const *const arguments, char const *const *const environment)
Definition: spawnv.cpp:387
intptr_t __cdecl _wexecve(wchar_t const *const file_name, wchar_t const *const *const arguments, wchar_t const *const *const environment)
Definition: spawnv.cpp:425
static intptr_t __cdecl execute_command(int const mode, Character const *const file_name, Character const *const *const arguments, Character const *const *const environment)
Definition: spawnv.cpp:168
intptr_t __cdecl _wspawnve(int const mode, wchar_t const *const file_name, wchar_t const *const *const arguments, wchar_t const *const *const environment)
Definition: spawnv.cpp:443
intptr_t __cdecl _spawnv(int const mode, char const *const file_name, char const *const *const arguments)
Definition: spawnv.cpp:396
intptr_t __cdecl _spawnve(int const mode, char const *const file_name, char const *const *const arguments, char const *const *const environment)
Definition: spawnv.cpp:405
wchar_t const *const size_t const buffer_size
Definition: stat.cpp:95
PBYTE lpReserved2
Definition: winbase.h:891
DWORD cb
Definition: winbase.h:877
WORD cbReserved2
Definition: winbase.h:890
DWORD WINAPI WaitForSingleObject(IN HANDLE hHandle, IN DWORD dwMilliseconds)
Definition: synch.c:82
int errno_t
Definition: corecrt.h:615
static BOOL handle_data(struct parsed_symbol *sym)
Definition: undname.c:1061
int intptr_t
Definition: vcruntime.h:134
DWORD WINAPI GetLastError(void)
Definition: except.c:1042
#define CREATE_UNICODE_ENVIRONMENT
Definition: winbase.h:189
#define DETACHED_PROCESS
Definition: winbase.h:182
unsigned char BYTE
Definition: xxhash.c:193
#define const
Definition: zconf.h:233