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