ReactOS 0.4.16-dev-959-g2ec3a19
spawnvp.cpp
Go to the documentation of this file.
1//
2// spawnvp.cpp
3//
4// Copyright (c) Microsoft Corporation. All rights reserved.
5//
6// Defines the -vp and -vpe flavors of the _exec() and _spawn() functions. See
7// the comments in spawnv.cpp for details of the various flavors of these
8// functions.
9//
10#include <corecrt_internal.h>
12#include <errno.h>
13#include <stdlib.h>
14#include <string.h>
15#include <malloc.h>
16#include <process.h>
17#include <mbstring.h>
18
19
20
21template <typename Character>
23 int const mode,
24 Character const* const file_name,
25 Character const* const* const arguments,
26 Character const* const* const environment
27 ) throw()
28{
29 typedef __crt_char_traits<Character> traits;
30
31 _VALIDATE_RETURN(file_name != nullptr, EINVAL, -1);
32 _VALIDATE_RETURN(file_name[0] != '\0', EINVAL, -1);
33 _VALIDATE_RETURN(arguments != nullptr, EINVAL, -1);
34 _VALIDATE_RETURN(arguments[0] != nullptr, EINVAL, -1);
35 _VALIDATE_RETURN(arguments[0][0] != '\0', EINVAL, -1);
36
37 __crt_errno_guard const guard_errno;
38
39 // Attempt to perform the spawn with the given file name. If this succeeds
40 // and is a spawn operation (mode != _P_OVERLAY), then it returns a status
41 // code other than -1 and we can just return it. If this succeds and is an
42 // exec operation (mode == _P_OVERLAY), then this call does not return.
43 intptr_t const initial_result = traits::tspawnve(mode, file_name, arguments, environment);
44 if (initial_result != -1)
45 return initial_result;
46
47 // If the spawn attempt failed, try to determine why. ENOENT indicates that
48 // the spawn operation itself failed, and there's nothing we can do:
49 if (errno != ENOENT)
50 return -1;
51
52 // If the file name is an absolute or relative path, then we do not search
53 // the %PATH%, so there is nothing left to do:
54 if (traits::tcschr(file_name, '\\') != nullptr)
55 return -1;
56
57 if (traits::tcschr(file_name, '/') != nullptr)
58 return -1;
59
60 if (file_name[1] == ':')
61 return -1;
62
63 // Otherwise, the file name string just names an executable. Let's try
64 // appending it to each path in the %PATH% and see if we can find the
65 // file to execute:
66 Character const path_name[] = { 'P', 'A', 'T', 'H', '\0' };
67 __crt_unique_heap_ptr<Character> path_value;
68 if (_ERRCHECK_EINVAL(traits::tdupenv_s_crt(path_value.get_address_of(), nullptr, path_name)) != 0)
69 return -1;
70
71 if (!path_value)
72 return -1;
73
74 // This will be used to store alternative path names to the executable:
75 __crt_unique_heap_ptr<Character> const owned_file_buffer(_calloc_crt_t(Character, _MAX_PATH));
76 if (!owned_file_buffer)
77 return -1;
78
79 Character* file_buffer = owned_file_buffer.get();
80 Character* path_state = path_value.get();
81 while ((path_state = traits::tgetpath(path_state, file_buffer, _MAX_PATH - 1)) != 0)
82 {
83 if (!*file_buffer)
84 break;
85
86 // Append a '\' if necessary:
87 Character* const last_character_it = file_buffer + traits::tcslen(file_buffer) - 1;
88 if (last_character_it != traits::tcsrchr(file_buffer, '\\') &&
89 last_character_it != traits::tcsrchr(file_buffer, '/'))
90 {
91 Character const backslash_string[] = { '\\', '\0' };
92 _ERRCHECK(traits::tcscat_s(file_buffer, _MAX_PATH, backslash_string));
93 }
94
95 // Make sure that the buffer is sufficiently large to hold the file name
96 // concatenated onto the end of this %PATH% component. If it is not, we
97 // return immediately (errno will still be set from the last call to
98 // _spawnve().
99 if (traits::tcslen(file_buffer) + traits::tcslen(file_name) >= _MAX_PATH)
100 break;
101
102 _ERRCHECK(traits::tcscat_s(file_buffer, _MAX_PATH, file_name));
103
104 // Try the spawn again with the newly constructed path. Like before, if
105 // this succeeds and is a spawn operation, then a status is returned and
106 // we can return immediately. If this succeeds and is an exec operation,
107 // the call does not return.
108 errno = 0;
109 intptr_t const result = traits::tspawnve(mode, file_buffer, arguments, environment);
110 if (result != -1)
111 return result;
112
113 // Two classes of failures are acceptable here: either the operation
114 // failed because the spawn operation itself failed (e.g., if the file
115 // could not be found)...
117 continue;
118
119 // ...or the path is a UNC path...
120 bool const is_unc_path_with_slashes =
121 traits::tcschr(file_buffer, '/') == file_buffer &&
122 traits::tcschr(file_buffer + 1, '/') == file_buffer + 1;
123
124 bool const is_unc_path_with_backslashes =
125 traits::tcschr(file_buffer, '\\') == file_buffer &&
126 traits::tcschr(file_buffer + 1, '\\') == file_buffer + 1;
127
128 if (is_unc_path_with_slashes || is_unc_path_with_backslashes)
129 continue;
130
131 // ...otherwise, we report the error back to the caller:
132 break;
133 }
134
135 return -1;
136}
137
138
139
141 char const* const file_name,
142 char const* const* const arguments
143 )
144{
145 return common_spawnvp(_P_OVERLAY, file_name, arguments, static_cast<char const* const* const>(nullptr));
146}
147
149 char const* const file_name,
150 char const* const* const arguments,
151 char const* const* const environment
152 )
153{
154 return common_spawnvp(_P_OVERLAY, file_name, arguments, environment);
155}
156
158 int const mode,
159 char const* const file_name,
160 char const* const* const arguments
161 )
162{
163 return common_spawnvp(mode, file_name, arguments, static_cast<char const* const* const>(nullptr));
164}
165
167 int const mode,
168 char const* const file_name,
169 char const* const* const arguments,
170 char const* const* const environment
171 )
172{
173 return common_spawnvp(mode, file_name, arguments, environment);
174}
175
176
177
179 wchar_t const* const file_name,
180 wchar_t const* const* const arguments
181 )
182{
183 return common_spawnvp(_P_OVERLAY, file_name, arguments, static_cast<wchar_t const* const* const>(nullptr));
184}
185
187 wchar_t const* const file_name,
188 wchar_t const* const* const arguments,
189 wchar_t const* const* const environment
190 )
191{
192 return common_spawnvp(_P_OVERLAY, file_name, arguments, environment);
193}
194
196 int const mode,
197 wchar_t const* const file_name,
198 wchar_t const* const* const arguments
199 )
200{
201 return common_spawnvp(mode, file_name, arguments, static_cast<wchar_t const* const* const>(nullptr));
202}
203
205 int const mode,
206 wchar_t const* const file_name,
207 wchar_t const* const* const arguments,
208 wchar_t const* const* const environment
209 )
210{
211 return common_spawnvp(mode, file_name, arguments, environment);
212}
#define ENOENT
Definition: acclib.h:79
#define EINVAL
Definition: acclib.h:90
#define __cdecl
Definition: accygwin.h:79
#define _ERRCHECK(e)
#define _ERRCHECK_EINVAL(e)
#define _VALIDATE_RETURN(expr, errorcode, retexpr)
static char * path_name(DOS_FILE *file)
Definition: check.c:208
GLenum mode
Definition: glext.h:6217
GLuint64EXT * result
Definition: glext.h:11304
#define _doserrno
Definition: stdlib.h:131
#define _MAX_PATH
Definition: utility.h:77
static LPCWSTR file_name
Definition: protocol.c:147
#define _P_OVERLAY
Definition: port.h:372
static char * file_buffer
Definition: regtests2xml.c:46
#define errno
Definition: errno.h:18
intptr_t __cdecl _wexecvpe(wchar_t const *const file_name, wchar_t const *const *const arguments, wchar_t const *const *const environment)
Definition: spawnvp.cpp:186
intptr_t __cdecl _execvpe(char const *const file_name, char const *const *const arguments, char const *const *const environment)
Definition: spawnvp.cpp:148
intptr_t __cdecl _wexecvp(wchar_t const *const file_name, wchar_t const *const *const arguments)
Definition: spawnvp.cpp:178
static intptr_t __cdecl common_spawnvp(int const mode, Character const *const file_name, Character const *const *const arguments, Character const *const *const environment)
Definition: spawnvp.cpp:22
intptr_t __cdecl _spawnvp(int const mode, char const *const file_name, char const *const *const arguments)
Definition: spawnvp.cpp:157
intptr_t __cdecl _spawnvpe(int const mode, char const *const file_name, char const *const *const arguments, char const *const *const environment)
Definition: spawnvp.cpp:166
intptr_t __cdecl _wspawnvp(int const mode, wchar_t const *const file_name, wchar_t const *const *const arguments)
Definition: spawnvp.cpp:195
intptr_t __cdecl _wspawnvpe(int const mode, wchar_t const *const file_name, wchar_t const *const *const arguments, wchar_t const *const *const environment)
Definition: spawnvp.cpp:204
intptr_t __cdecl _execvp(char const *const file_name, char const *const *const arguments)
Definition: spawnvp.cpp:140
int intptr_t
Definition: vcruntime.h:134
#define ERROR_NOT_READY
Definition: winerror.h:124
#define const
Definition: zconf.h:233