231740cd0b6ca813506d7de65214fe8c0cc458a1
[reactos.git] / reactos / lib / msvcrt / process / process.c
1 #include "precomp.h"
2 #include <msvcrt/process.h>
3 #include <msvcrt/stdlib.h>
4 #include <msvcrt/string.h>
5 #include <msvcrt/errno.h>
6 #include <msvcrt/internal/file.h>
7
8 #define NDEBUG
9 #include <msvcrt/msvcrtdbg.h>
10
11 extern int maxfno;
12
13 char const* ext[] =
14 {
15 "",
16 ".bat",
17 ".cmd",
18 ".com",
19 ".exe"
20 };
21
22 const char* find_exec(const char* path, char* rpath)
23 {
24 char *rp;
25 const char *rd;
26 int i, found = 0;
27
28 DPRINT("find_exec('%s', %x)\n", path, rpath);
29
30 if (path == NULL)
31 {
32 return NULL;
33 }
34 if (strlen(path) > FILENAME_MAX - 1)
35 {
36 return path;
37 }
38 /* copy path in rpath */
39 for (rd = path, rp = rpath; *rd; *rp++ = *rd++);
40 *rp = 0;
41 /* try first with the name as is */
42 for (i = 0; i < sizeof(ext) / sizeof(*ext); i++)
43 {
44 strcpy(rp, ext[i]);
45
46 DPRINT("trying '%s'\n", rpath);
47
48 if (_access(rpath, F_OK) == 0 && _access(rpath, D_OK) != 0)
49 {
50 found = 1;
51 break;
52 }
53 }
54 if (!found)
55 {
56 char* env = getenv("PATH");
57 if (env)
58 {
59 char* ep = env;
60 while (*ep && !found)
61 {
62 if (*ep == ';') ep++;
63 rp=rpath;
64 for (; *ep && (*ep != ';'); *rp++ = *ep++);
65 if (rp > rpath)
66 {
67 rp--;
68 if (*rp != '/' && *rp != '\\')
69 {
70 *++rp = '\\';
71 }
72 rp++;
73 }
74 for (rd=path; *rd; *rp++ = *rd++);
75 for (i = 0; i < sizeof(ext) / sizeof(*ext); i++)
76 {
77 strcpy(rp, ext[i]);
78
79 DPRINT("trying '%s'\n", rpath);
80
81 if (_access(rpath, F_OK) == 0 && _access(rpath, D_OK) != 0)
82 {
83 found = 1;
84 break;
85 }
86 }
87 }
88 free(env);
89 }
90 }
91
92 return found ? rpath : path;
93 }
94
95 static char*
96 argvtos(char* const* argv, char delim)
97 {
98 int i, len;
99 char *ptr, *str;
100
101 if (argv == NULL)
102 return NULL;
103
104 for (i = 0, len = 0; argv[i]; i++)
105 {
106 len += strlen(argv[i]) + 1;
107 }
108
109 str = ptr = (char*) malloc(len + 1);
110 if (str == NULL)
111 return NULL;
112
113 for(i = 0; argv[i]; i++)
114 {
115 len = strlen(argv[i]);
116 memcpy(ptr, argv[i], len);
117 ptr += len;
118 *ptr++ = delim;
119 }
120 *ptr = 0;
121
122 return str;
123 }
124
125 static char*
126 valisttos(const char* arg0, va_list alist, char delim)
127 {
128 va_list alist2 = alist;
129 char *ptr, *str;
130 int len;
131
132 if (arg0 == NULL)
133 return NULL;
134
135 ptr = (char*)arg0;
136 len = 0;
137 do
138 {
139 len += strlen(ptr) + 1;
140 ptr = va_arg(alist, char*);
141 }
142 while(ptr != NULL);
143
144 str = (char*) malloc(len + 1);
145 if (str == NULL)
146 return NULL;
147
148 ptr = str;
149 do
150 {
151 len = strlen(arg0);
152 memcpy(ptr, arg0, len);
153 ptr += len;
154 *ptr++ = delim;
155 arg0 = va_arg(alist2, char*);
156 }
157 while(arg0 != NULL);
158 *ptr = 0;
159
160 return str;
161 }
162
163 static int
164 do_spawn(int mode, const char* cmdname, const char* args, const char* envp)
165 {
166 STARTUPINFOA StartupInfo;
167 PROCESS_INFORMATION ProcessInformation;
168 char* fmode;
169 HANDLE* hFile;
170 int i, last;
171 BOOL bResult;
172 DWORD dwExitCode;
173 DWORD dwError;
174
175 DPRINT("do_spawn('%s')\n", cmdname);
176
177 if (mode != _P_NOWAIT && mode != _P_NOWAITO && mode != _P_WAIT && mode != _P_DETACH && mode != _P_OVERLAY)
178 {
179 __set_errno ( EINVAL );
180 return -1;
181 }
182
183 if (0 != _access(cmdname, F_OK))
184 {
185 __set_errno ( ENOENT );
186 return -1;
187 }
188 if (0 == _access(cmdname, D_OK))
189 {
190 __set_errno ( EISDIR );
191 return -1;
192 }
193
194 memset (&StartupInfo, 0, sizeof(StartupInfo));
195 StartupInfo.cb = sizeof(StartupInfo);
196
197 for (last = i = 0; i < maxfno; i++)
198 {
199 if ((void*)-1 != _get_osfhandle(i))
200 {
201 last = i + 1;
202 }
203 }
204
205 if (last)
206 {
207 StartupInfo.cbReserved2 = sizeof(ULONG) + last * (sizeof(char) + sizeof(HANDLE));
208 StartupInfo.lpReserved2 = malloc(StartupInfo.cbReserved2);
209 if (StartupInfo.lpReserved2 == NULL)
210 {
211 __set_errno ( ENOMEM );
212 return -1;
213 }
214
215 *(DWORD*)StartupInfo.lpReserved2 = last;
216 fmode = (char*)(StartupInfo.lpReserved2 + sizeof(ULONG));
217 hFile = (HANDLE*)(StartupInfo.lpReserved2 + sizeof(ULONG) + last * sizeof(char));
218 for (i = 0; i < last; i++)
219 {
220 int _mode = __fileno_getmode(i);
221 HANDLE h = _get_osfhandle(i);
222 /* FIXME: The test of console handles (((ULONG)Handle) & 0x10000003) == 0x3)
223 * is possible wrong
224 */
225 if ((((ULONG)h) & 0x10000003) == 0x3 || _mode & _O_NOINHERIT || (i < 3 && mode == _P_DETACH))
226 {
227 *hFile = INVALID_HANDLE_VALUE;
228 *fmode = 0;
229 }
230 else
231 {
232 DWORD dwFlags;
233 BOOL bFlag;
234 bFlag = GetHandleInformation(h, &dwFlags);
235 if (bFlag && (dwFlags & HANDLE_FLAG_INHERIT))
236 {
237 *hFile = h;
238 *fmode = (_O_ACCMODE & _mode) | (((_O_TEXT | _O_BINARY) & _mode) >> 8);
239 }
240 else
241 {
242 *hFile = INVALID_HANDLE_VALUE;
243 *fmode = 0;
244 }
245 }
246 fmode++;
247 hFile++;
248 }
249 }
250
251 bResult = CreateProcessA((char *)cmdname,
252 (char *)args,
253 NULL,
254 NULL,
255 TRUE,
256 mode == _P_DETACH ? DETACHED_PROCESS : 0,
257 (LPVOID)envp,
258 NULL,
259 &StartupInfo,
260 &ProcessInformation);
261 if (StartupInfo.lpReserved2)
262 {
263 free(StartupInfo.lpReserved2);
264 }
265
266 if (!bResult)
267 {
268 dwError = GetLastError();
269 DPRINT("%x\n", dwError);
270 __set_errno(dwError);
271 return -1;
272 }
273 CloseHandle(ProcessInformation.hThread);
274 switch(mode)
275 {
276 case _P_OVERLAY:
277 _exit(0);
278 case _P_WAIT:
279 WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
280 GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
281 CloseHandle(ProcessInformation.hProcess);
282 return (int)dwExitCode;
283 case _P_DETACH:
284 CloseHandle(ProcessInformation.hProcess);
285 return 0;
286 }
287 return (int)ProcessInformation.hProcess;
288 }
289
290 /*
291 * @implemented
292 */
293 int _spawnl(int mode, const char *cmdname, const char* arg0, ...)
294 {
295 va_list argp;
296 char* args;
297 int ret = -1;
298
299 DPRINT("_spawnl('%s')\n", cmdname);
300
301 va_start(argp, arg0);
302 args = valisttos(arg0, argp, ' ');
303
304 if (args)
305 {
306 ret = do_spawn(mode, cmdname, args, NULL);
307 free(args);
308 }
309 return ret;
310 }
311
312 /*
313 * @implemented
314 */
315 int _spawnv(int mode, const char *cmdname, char* const* argv)
316 {
317 char* args;
318 int ret = -1;
319
320 DPRINT("_spawnv('%s')\n", cmdname);
321
322 args = argvtos(argv, ' ');
323
324 if (args)
325 {
326 ret = do_spawn(mode, cmdname, args, NULL);
327 free(args);
328 }
329 return ret;
330 }
331
332 /*
333 * @implemented
334 */
335 int _spawnle(int mode, const char *cmdname, const char* arg0, ... /*, NULL, const char* const* envp*/)
336 {
337 va_list argp;
338 char* args;
339 char* envs;
340 char* const* ptr;
341 int ret = -1;
342
343 DPRINT("_spawnle('%s')\n", cmdname);
344
345 va_start(argp, arg0);
346 args = valisttos(arg0, argp, ' ');
347 do
348 {
349 ptr = (char* const*)va_arg(argp, char*);
350 }
351 while (ptr != NULL);
352 ptr = (char* const*)va_arg(argp, char*);
353 envs = argvtos(ptr, 0);
354 if (args)
355 {
356 ret = do_spawn(mode, cmdname, args, envs);
357 free(args);
358 }
359 if (envs)
360 {
361 free(envs);
362 }
363 return ret;
364
365 }
366
367 /*
368 * @implemented
369 */
370 int _spawnve(int mode, const char *cmdname, char* const* argv, char* const* envp)
371 {
372 char *args;
373 char *envs;
374 int ret = -1;
375
376 DPRINT("_spawnve('%s')\n", cmdname);
377
378 args = argvtos(argv, ' ');
379 envs = argvtos(envp, 0);
380
381 if (args)
382 {
383 ret = do_spawn(mode, cmdname, args, envs);
384 free(args);
385 }
386 if (envs)
387 {
388 free(envs);
389 }
390 return ret;
391 }
392
393 /*
394 * @implemented
395 */
396 int _spawnvp(int mode, const char* cmdname, char* const* argv)
397 {
398 char pathname[FILENAME_MAX];
399
400 DPRINT("_spawnvp('%s')\n", cmdname);
401
402 return _spawnv(mode, find_exec(cmdname, pathname), argv);
403 }
404
405 /*
406 * @implemented
407 */
408 int _spawnlp(int mode, const char* cmdname, const char* arg0, .../*, NULL*/)
409 {
410 va_list argp;
411 char* args;
412 int ret = -1;
413 char pathname[FILENAME_MAX];
414
415 DPRINT("_spawnlp('%s')\n", cmdname);
416
417 va_start(argp, arg0);
418 args = valisttos(arg0, argp, ' ');
419 if (args)
420 {
421 ret = do_spawn(mode, find_exec(cmdname, pathname), args, NULL);
422 free(args);
423 }
424 return ret;
425 }
426
427
428 /*
429 * @implemented
430 */
431 int _spawnlpe(int mode, const char* cmdname, const char* arg0, .../*, NULL, const char* const* envp*/)
432 {
433 va_list argp;
434 char* args;
435 char* envs;
436 char* const * ptr;
437 int ret = -1;
438 char pathname[FILENAME_MAX];
439
440 DPRINT("_spawnlpe('%s')\n", cmdname);
441
442 va_start(argp, arg0);
443 args = valisttos(arg0, argp, ' ');
444 do
445 {
446 ptr = (char* const*)va_arg(argp, char*);
447 }
448 while (ptr != NULL);
449 ptr = (char* const*)va_arg(argp, char*);
450 envs = argvtos(ptr, 0);
451 if (args)
452 {
453 ret = do_spawn(mode, find_exec(cmdname, pathname), args, envs);
454 free(args);
455 }
456 if (envs)
457 {
458 free(envs);
459 }
460 return ret;
461 }
462
463 /*
464 * @implemented
465 */
466 int _spawnvpe(int mode, const char* cmdname, char* const* argv, char* const* envp)
467 {
468 char pathname[FILENAME_MAX];
469
470 DPRINT("_spawnvpe('%s')\n", cmdname);
471
472 return _spawnve(mode, find_exec(cmdname, pathname), argv, envp);
473 }
474
475 /*
476 * @implemented
477 */
478 int _execl(const char* cmdname, const char* arg0, ...)
479 {
480 char* args;
481 va_list argp;
482 int ret = -1;
483
484 DPRINT("_execl('%s')\n", cmdname);
485
486 va_start(argp, arg0);
487 args = valisttos(arg0, argp, ' ');
488
489 if (args)
490 {
491 ret = do_spawn(P_OVERLAY, cmdname, args, NULL);
492 free(args);
493 }
494 return ret;
495 }
496
497 /*
498 * @implemented
499 */
500 int _execv(const char* cmdname, char* const* argv)
501 {
502 DPRINT("_execv('%s')\n", cmdname);
503 return _spawnv(P_OVERLAY, cmdname, argv);
504 }
505
506 /*
507 * @implemented
508 */
509 int _execle(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
510 {
511 va_list argp;
512 char* args;
513 char* envs;
514 char* const* ptr;
515 int ret = -1;
516
517 DPRINT("_execle('%s')\n", cmdname);
518
519 va_start(argp, arg0);
520 args = valisttos(arg0, argp, ' ');
521 do
522 {
523 ptr = (char* const*)va_arg(argp, char*);
524 }
525 while (ptr != NULL);
526 ptr = (char* const*)va_arg(argp, char*);
527 envs = argvtos(ptr, 0);
528 if (args)
529 {
530 ret = do_spawn(P_OVERLAY, cmdname, args, envs);
531 free(args);
532 }
533 if (envs)
534 {
535 free(envs);
536 }
537 return ret;
538 }
539
540 /*
541 * @implemented
542 */
543 int _execve(const char* cmdname, char* const* argv, char* const* envp)
544 {
545 DPRINT("_execve('%s')\n", cmdname);
546 return _spawnve(P_OVERLAY, cmdname, argv, envp);
547 }
548
549 /*
550 * @implemented
551 */
552 int _execlp(const char* cmdname, const char* arg0, ...)
553 {
554 char* args;
555 va_list argp;
556 int ret = -1;
557 char pathname[FILENAME_MAX];
558
559 DPRINT("_execlp('%s')\n", cmdname);
560
561 va_start(argp, arg0);
562 args = valisttos(arg0, argp, ' ');
563
564 if (args)
565 {
566 ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, NULL);
567 free(args);
568 }
569 return ret;
570 }
571
572 /*
573 * @implemented
574 */
575 int _execvp(const char* cmdname, char* const* argv)
576 {
577 DPRINT("_execvp('%s')\n", cmdname);
578 return _spawnvp(P_OVERLAY, cmdname, argv);
579 }
580
581 /*
582 * @implemented
583 */
584 int _execlpe(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
585 {
586 va_list argp;
587 char* args;
588 char* envs;
589 char* const* ptr;
590 int ret = -1;
591 char pathname[FILENAME_MAX];
592
593 DPRINT("_execlpe('%s')\n", cmdname);
594
595 va_start(argp, arg0);
596 args = valisttos(arg0, argp, ' ');
597 do
598 {
599 ptr = (char* const*)va_arg(argp, char*);
600 }
601 while (ptr != NULL);
602 ptr = (char* const*)va_arg(argp, char*);
603 envs = argvtos(ptr, 0);
604 if (args)
605 {
606 ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, envs);
607 free(args);
608 }
609 if (envs)
610 {
611 free(envs);
612 }
613 return ret;
614 }
615
616 /*
617 * @implemented
618 */
619 int _execvpe(const char* cmdname, char* const* argv, char* const* envp)
620 {
621 DPRINT("_execvpe('%s')\n", cmdname);
622 return _spawnvpe(P_OVERLAY, cmdname, argv, envp);
623 }