ef57d96092dcd2368b8d531f7fa5ceddb6b43312
[reactos.git] / reactos / lib / msvcrt / process / spawnve.c
1 /* Copyright (C) 1998 DJ Delorie, see COPYING.DJ for details */
2 /* Copyright (C) 1996 DJ Delorie, see COPYING.DJ for details */
3 /* Copyright (C) 1995 DJ Delorie, see COPYING.DJ for details */
4
5 #include <windows.h>
6
7 #include <msvcrt/stdio.h>
8 #include <msvcrt/stdlib.h>
9 #include <msvcrt/string.h>
10 #include <msvcrt/errno.h>
11 //#include <msvcrt/limits.h>
12 #include <msvcrt/process.h>
13 #include <msvcrt/ctype.h>
14 #include <msvcrt/io.h>
15
16 #define NDEBUG
17 #include <msvcrt/msvcrtdbg.h>
18
19
20 #ifndef F_OK
21 #define F_OK 0x01
22 #endif
23 #ifndef R_OK
24 #define R_OK 0x02
25 #endif
26 #ifndef W_OK
27 #define W_OK 0x04
28 #endif
29 #ifndef X_OK
30 #define X_OK 0x08
31 #endif
32 #ifndef D_OK
33 #define D_OK 0x10
34 #endif
35
36 // information about crtdll file handles is not passed to child
37 int _fileinfo_dll = 0;
38
39 static int
40 direct_exec_tail(const char *program, const char *args,
41 const char * envp,
42 PROCESS_INFORMATION *ProcessInformation)
43 {
44
45 static STARTUPINFO StartupInfo;
46
47 StartupInfo.cb = sizeof(STARTUPINFO);
48 StartupInfo.lpReserved= NULL;
49 StartupInfo.dwFlags = 0 /*STARTF_USESTDHANDLES*/;
50 StartupInfo.wShowWindow = SW_SHOWDEFAULT;
51 StartupInfo.lpReserved2 = NULL;
52 StartupInfo.cbReserved2 = 0;
53 StartupInfo.hStdInput = _get_osfhandle(0);
54 StartupInfo.hStdOutput = _get_osfhandle(1);
55 StartupInfo.hStdError = _get_osfhandle(2);
56
57
58 if (! CreateProcessA((char *)program,(char *)args,NULL,NULL,TRUE,0,(LPVOID)envp,NULL,&StartupInfo,ProcessInformation) )
59 {
60 __set_errno( GetLastError() );
61 return -1;
62 }
63
64 return (int)ProcessInformation->hProcess;
65 }
66
67 static int vdm_exec(const char *program, char **argv, char **envp,
68 PROCESS_INFORMATION *ProcessInformation)
69 {
70 static char args[1024];
71 int i = 0;
72 args[0] = 0;
73
74 strcpy(args,"vdm.exe ");
75 while(argv[i] != NULL ) {
76 strcat(args,argv[i]);
77 strcat(args," ");
78 i++;
79 }
80
81 return direct_exec_tail(program,args,envp,ProcessInformation);
82 }
83
84 static int go32_exec(const char *program, char **argv, char **envp,
85 PROCESS_INFORMATION *ProcessInformation)
86 {
87 char * penvblock, * ptr;
88 char * args;
89 int i, len, result;
90
91 for (i = 0, len = 0; envp[i]; i++) {
92 len += strlen(envp[i]) + 1;
93 }
94 penvblock = ptr = (char*)malloc(len + 1);
95 if (penvblock == NULL)
96 return -1;
97
98 for(i = 0, *ptr = 0; envp[i]; i++) {
99 strcpy(ptr, envp[i]);
100 ptr += strlen(envp[i]) + 1;
101 }
102 *ptr = 0;
103
104 for(i = 0, len = 0; argv[i]; i++) {
105 len += strlen(argv[i]) + 1;
106 }
107
108 args = (char*) malloc(len + 1);
109 if (args == NULL)
110 {
111 free(penvblock);
112 return -1;
113 }
114
115 for(i = 0, *args = 0; argv[i]; i++) {
116 strcat(args,argv[i]);
117 if (argv[i+1] != NULL) {
118 strcat(args," ");
119 }
120 }
121
122 result = direct_exec_tail(program,args,(const char*)penvblock,ProcessInformation);
123 free(args);
124 free(penvblock);
125 return result;
126 }
127
128 int
129 command_exec(const char *program, char **argv, char **envp,
130 PROCESS_INFORMATION *ProcessInformation)
131 {
132 static char args[1024];
133 int i = 0;
134
135
136
137 args[0] = 0;
138
139 strcpy(args,"cmd.exe /c ");
140 while(argv[i] != NULL ) {
141 strcat(args,argv[i]);
142 strcat(args," ");
143 i++;
144 }
145
146 return direct_exec_tail(program,args,envp,ProcessInformation);
147
148 }
149
150 static int script_exec(const char *program, char **argv, char **envp,
151 PROCESS_INFORMATION *ProcessInformation)
152 {
153 return 0;
154 }
155
156
157 /* Note: the following list is not supposed to mention *every*
158 possible extension of an executable file. It only mentions
159 those extensions that can be *omitted* when you invoke the
160 executable from one of the shells used on MSDOS. */
161 static struct {
162 const char *extension;
163 int (*interp)(const char *, char **, char **,
164 PROCESS_INFORMATION *);
165 } interpreters[] = {
166 { ".com", vdm_exec },
167 { ".exe", go32_exec },
168 { ".dll", go32_exec },
169 { ".cmd", command_exec },
170 { ".bat", command_exec },
171 { ".btm", command_exec },
172 { ".sh", script_exec }, /* for compatibility with ms_sh */
173 { ".ksh", script_exec },
174 { ".pl", script_exec }, /* Perl */
175 { ".sed", script_exec },
176 { "", go32_exec },
177 { 0, script_exec }, /* every extension not mentioned above calls it */
178 { 0, 0 },
179 };
180
181 /* This is the index into the above array of the interpreter
182 which is called when the program filename has no extension. */
183 #define INTERP_NO_EXT (sizeof(interpreters)/sizeof(interpreters[0]) - 3)
184
185 /*-------------------------------------------------*/
186
187
188
189
190 int _spawnve(int mode, const char *path, char *const argv[], char *const envp[])
191 {
192 /* This is the one that does the work! */
193 PROCESS_INFORMATION ProcessInformation;
194 union { char *const *x; char **p; } u;
195 int i = -1;
196 char **argvp;
197 char **envpp;
198 char rpath[FILENAME_MAX], *rp, *rd=0;
199 int e = errno;
200 int is_dir = 0;
201 int found = 0;
202 DWORD ExitCode;
203
204 DPRINT("_spawnve('%s')\n", path);
205
206 if (path == 0 || argv[0] == 0)
207 {
208 errno = EINVAL;
209 DPRINT("??\n");
210 return -1;
211 }
212 if (strlen(path) > FILENAME_MAX - 1)
213 {
214 errno = ENAMETOOLONG;
215 DPRINT("??\n");
216 return -1;
217 }
218
219 u.x = argv; argvp = u.p;
220 u.x = envp; envpp = u.p;
221
222 fflush(stdout); /* just in case */
223 for (rp=rpath; *path; *rp++ = *path++)
224 {
225 if (*path == '.')
226 rd = rp;
227 if (*path == '\\' || *path == '/')
228 rd = 0;
229 }
230 *rp = 0;
231
232 /* If LFN is supported on the volume where rpath resides, we
233 might have something like foo.bar.exe or even foo.exe.com.
234 If so, look for RPATH.ext before even trying RPATH itself. */
235 if (!rd)
236 {
237 for (i=0; interpreters[i].extension; i++)
238 {
239 strcpy(rp, interpreters[i].extension);
240 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0)))
241 {
242 found = 1;
243 break;
244 }
245 }
246 }
247
248 if (!found)
249 {
250 const char *rpath_ext;
251
252 if (rd)
253 {
254 i = 0;
255 rpath_ext = rd;
256 }
257 else
258 {
259 i = INTERP_NO_EXT;
260 rpath_ext = "";
261 }
262 for ( ; interpreters[i].extension; i++)
263 if (_stricmp(rpath_ext, interpreters[i].extension) == 0
264 && _access(rpath, F_OK) == 0
265 && !(is_dir = (_access(rpath, D_OK) == 0)))
266 {
267 found = 1;
268 break;
269 }
270 }
271 if (!found)
272 {
273 DPRINT("??\n");
274 errno = is_dir ? EISDIR : ENOENT;
275 return -1;
276 }
277 errno = e;
278 i = interpreters[i].interp(rpath, argvp, envpp, &ProcessInformation);
279 if (mode == P_OVERLAY)
280 exit(i);
281 if (mode == P_WAIT)
282 {
283 WaitForSingleObject(ProcessInformation.hProcess,INFINITE);
284 GetExitCodeProcess(ProcessInformation.hProcess,&ExitCode);
285 i = (int)ExitCode;
286 CloseHandle(ProcessInformation.hThread);
287 CloseHandle(ProcessInformation.hProcess);
288 }
289 else
290 {
291 CloseHandle(ProcessInformation.hThread);
292 }
293 return i;
294 }
295
296
297
298
299 const char * find_exec(char * path,char *rpath)
300 {
301 char *rp, *rd=0;
302 int i;
303 int is_dir = 0;
304 int found = 0;
305 if (path == 0 )
306 return 0;
307 if (strlen(path) > FILENAME_MAX - 1)
308 return path;
309
310 /* copy path in rpath */
311 for (rd=path,rp=rpath; *rd; *rp++ = *rd++)
312 ;
313 *rp = 0;
314 /* try first with the name as is */
315 for (i=0; interpreters[i].extension; i++)
316 {
317 strcpy(rp, interpreters[i].extension);
318 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0)))
319 {
320 found = 1;
321 break;
322 }
323 }
324
325 if (!found)
326 {
327 /* search in the PATH */
328 char winpath[MAX_PATH];
329 if( GetEnvironmentVariableA("PATH",winpath,MAX_PATH))
330 {
331 char *ep=winpath;
332 while( *ep)
333 {
334 if(*ep == ';') ep++;
335 rp=rpath;
336 for ( ; *ep && (*ep != ';') ; *rp++ = *ep++)
337 ;
338 *rp++='/';
339 for (rd=path ; *rd ; *rp++ = *rd++)
340 ;
341
342 for (i=0; interpreters[i].extension; i++)
343 {
344 strcpy(rp, interpreters[i].extension);
345 if (_access(rpath, F_OK) == 0 && !(is_dir = (_access(rpath, D_OK) == 0)))
346 {
347 found = 1;
348 break;
349 }
350 }
351 if (found) break;
352 }
353 }
354 }
355 if (!found)
356 return path;
357
358 return rpath;
359 }
360
361 int _spawnvpe(int nMode, const char* szPath, char* const* szaArgv, char* const* szaEnv)
362 {
363 char rpath[FILENAME_MAX];
364
365 return _spawnve(nMode, find_exec((char*)szPath,rpath), szaArgv, szaEnv);
366
367 }