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