[CRT] spawn: define a unicode environment when needed
[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 DWORD dwFlags = 0;
207
208 TRACE(MK_STR(do_spawnT)"(%i,'%"sT"','%"sT"','%"sT"')",mode,cmdname,args,envp);
209
210
211 if (mode != _P_NOWAIT && mode != _P_NOWAITO && mode != _P_WAIT && mode != _P_DETACH && mode != _P_OVERLAY)
212 {
213 _set_errno ( EINVAL );
214 return( -1);
215 }
216
217 if (0 != _taccess(cmdname, F_OK))
218 {
219 _set_errno ( ENOENT );
220 return(-1);
221 }
222 if (0 == access_dirT(cmdname))
223 {
224 _set_errno ( EISDIR );
225 return(-1);
226 }
227
228 memset (&StartupInfo, 0, sizeof(StartupInfo));
229 StartupInfo.cb = sizeof(StartupInfo);
230
231 #if 0
232
233 for (last = i = 0; i < FDINFO_FD_MAX; i++)
234 {
235 if ((void*)-1 != _get_osfhandle(i))
236 {
237 last = i + 1;
238 }
239 }
240
241 if (last)
242 {
243 StartupInfo.cbReserved2 = sizeof(ULONG) + last * (sizeof(char) + sizeof(HANDLE));
244 StartupInfo.lpReserved2 = malloc(StartupInfo.cbReserved2);
245 if (StartupInfo.lpReserved2 == NULL)
246 {
247 _set_errno ( ENOMEM );
248 return -1;
249 }
250
251 *(DWORD*)StartupInfo.lpReserved2 = last;
252 fmode = (char*)(StartupInfo.lpReserved2 + sizeof(ULONG));
253 hFile = (HANDLE*)(StartupInfo.lpReserved2 + sizeof(ULONG) + last * sizeof(char));
254 for (i = 0; i < last; i++)
255 {
256 int _mode = __fileno_getmode(i);
257 HANDLE h = _get_osfhandle(i);
258 /* FIXME: The test of console handles (((ULONG)Handle) & 0x10000003) == 0x3)
259 * is possible wrong
260 */
261 if ((((ULONG)h) & 0x10000003) == 0x3 || _mode & _O_NOINHERIT || (i < 3 && mode == _P_DETACH))
262 {
263 *hFile = INVALID_HANDLE_VALUE;
264 *fmode = 0;
265 }
266 else
267 {
268 DWORD dwFlags;
269 BOOL bFlag;
270 bFlag = GetHandleInformation(h, &dwFlags);
271 if (bFlag && (dwFlags & HANDLE_FLAG_INHERIT))
272 {
273 *hFile = h;
274 *fmode = (_O_ACCMODE & _mode) | (((_O_TEXT | _O_BINARY) & _mode) >> 8);
275 }
276 else
277 {
278 *hFile = INVALID_HANDLE_VALUE;
279 *fmode = 0;
280 }
281 }
282 fmode++;
283 hFile++;
284 }
285 }
286 #endif
287
288 create_io_inherit_block(&StartupInfo.cbReserved2, &StartupInfo.lpReserved2);
289
290 if (mode == _P_DETACH)
291 {
292 dwFlags |= DETACHED_PROCESS;
293 }
294 #ifdef _UNICODE
295 dwFlags |= CREATE_UNICODE_ENVIRONMENT;
296 #endif
297
298 bResult = CreateProcess((_TCHAR *)cmdname,
299 (_TCHAR *)args,
300 NULL,
301 NULL,
302 TRUE,
303 dwFlags,
304 (LPVOID)envp,
305 NULL,
306 &StartupInfo,
307 &ProcessInformation);
308
309 if (StartupInfo.lpReserved2)
310 {
311 free(StartupInfo.lpReserved2);
312 }
313
314 if (!bResult)
315 {
316 dwError = GetLastError();
317 ERR("%x\n", dwError);
318 _dosmaperr(dwError);
319 return(-1);
320 }
321 CloseHandle(ProcessInformation.hThread);
322 switch(mode)
323 {
324 case _P_NOWAIT:
325 case _P_NOWAITO:
326 return((intptr_t)ProcessInformation.hProcess);
327 case _P_OVERLAY:
328 CloseHandle(ProcessInformation.hProcess);
329 _exit(0);
330 case _P_WAIT:
331 WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
332 GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
333 CloseHandle(ProcessInformation.hProcess);
334 return( (int)dwExitCode); //CORRECT?
335 case _P_DETACH:
336 CloseHandle(ProcessInformation.hProcess);
337 return( 0);
338 }
339 return( (intptr_t)ProcessInformation.hProcess);
340 }
341
342 /*
343 * @implemented
344 */
345 intptr_t _tspawnl(int mode, const _TCHAR *cmdname, const _TCHAR* arg0, ...)
346 {
347 va_list argp;
348 _TCHAR* args;
349 intptr_t ret = -1;
350
351 TRACE(MK_STR(_tspawnl)"('%"sT"')\n", cmdname);
352
353 va_start(argp, arg0);
354 args = valisttosT(arg0, argp, ' ');
355
356 if (args)
357 {
358 ret = do_spawnT(mode, cmdname, args, NULL);
359 free(args);
360 }
361 va_end(argp);
362 return ret;
363 }
364
365 /*
366 * @implemented
367 */
368 intptr_t _tspawnv(int mode, const _TCHAR *cmdname, const _TCHAR* const* argv)
369 {
370 _TCHAR* args;
371 intptr_t ret = -1;
372
373 TRACE(MK_STR(_tspawnv)"('%"sT"')\n", cmdname);
374
375 args = argvtosT(argv, ' ');
376
377 if (args)
378 {
379 ret = do_spawnT(mode, cmdname, args, NULL);
380 free(args);
381 }
382 return ret;
383 }
384
385 /*
386 * @implemented
387 */
388 intptr_t _tspawnle(int mode, const _TCHAR *cmdname, const _TCHAR* arg0, ... /*, NULL, const char* const* envp*/)
389 {
390 va_list argp;
391 _TCHAR* args;
392 _TCHAR* envs;
393 _TCHAR const * const* ptr;
394 intptr_t ret = -1;
395
396 TRACE(MK_STR(_tspawnle)"('%"sT"')\n", cmdname);
397
398 va_start(argp, arg0);
399 args = valisttosT(arg0, argp, ' ');
400 do
401 {
402 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
403 }
404 while (ptr != NULL);
405 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
406 envs = argvtosT(ptr, 0);
407 if (args)
408 {
409 ret = do_spawnT(mode, cmdname, args, envs);
410 free(args);
411 }
412 if (envs)
413 {
414 free(envs);
415 }
416 va_end(argp);
417 return ret;
418
419 }
420
421 /*
422 * @implemented
423 */
424 intptr_t _tspawnve(int mode, const _TCHAR *cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp)
425 {
426 _TCHAR *args;
427 _TCHAR *envs;
428 intptr_t ret = -1;
429
430 TRACE(MK_STR(_tspawnve)"('%"sT"')\n", cmdname);
431
432 args = argvtosT(argv, ' ');
433 envs = argvtosT(envp, 0);
434
435 if (args)
436 {
437 ret = do_spawnT(mode, cmdname, args, envs);
438 free(args);
439 }
440 if (envs)
441 {
442 free(envs);
443 }
444 return ret;
445 }
446
447 /*
448 * @implemented
449 */
450 intptr_t _tspawnvp(int mode, const _TCHAR* cmdname, const _TCHAR* const* argv)
451 {
452 _TCHAR pathname[FILENAME_MAX];
453
454 TRACE(MK_STR(_tspawnvp)"('%"sT"')\n", cmdname);
455
456 return _tspawnv(mode, find_execT(cmdname, pathname), argv);
457 }
458
459 /*
460 * @implemented
461 */
462 intptr_t _tspawnlp(int mode, const _TCHAR* cmdname, const _TCHAR* arg0, .../*, NULL*/)
463 {
464 va_list argp;
465 _TCHAR* args;
466 intptr_t ret = -1;
467 _TCHAR pathname[FILENAME_MAX];
468
469 TRACE(MK_STR(_tspawnlp)"('%"sT"')\n", cmdname);
470
471 va_start(argp, arg0);
472 args = valisttosT(arg0, argp, ' ');
473 if (args)
474 {
475 ret = do_spawnT(mode, find_execT(cmdname, pathname), args, NULL);
476 free(args);
477 }
478 va_end(argp);
479 return ret;
480 }
481
482
483 /*
484 * @implemented
485 */
486 intptr_t _tspawnlpe(int mode, const _TCHAR* cmdname, const _TCHAR* arg0, .../*, NULL, const char* const* envp*/)
487 {
488 va_list argp;
489 _TCHAR* args;
490 _TCHAR* envs;
491 _TCHAR const* const * ptr;
492 intptr_t ret = -1;
493 _TCHAR pathname[FILENAME_MAX];
494
495 TRACE(MK_STR(_tspawnlpe)"('%"sT"')\n", cmdname);
496
497 va_start(argp, arg0);
498 args = valisttosT(arg0, argp, ' ');
499 do
500 {
501 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
502 }
503 while (ptr != NULL);
504 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
505 envs = argvtosT(ptr, 0);
506 if (args)
507 {
508 ret = do_spawnT(mode, find_execT(cmdname, pathname), args, envs);
509 free(args);
510 }
511 if (envs)
512 {
513 free(envs);
514 }
515 va_end(argp);
516 return ret;
517 }
518
519 /*
520 * @implemented
521 */
522 intptr_t _tspawnvpe(int mode, const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp)
523 {
524 _TCHAR pathname[FILENAME_MAX];
525
526 TRACE(MK_STR(_tspawnvpe)"('%"sT"')\n", cmdname);
527
528 return _tspawnve(mode, find_execT(cmdname, pathname), argv, envp);
529 }
530
531 /*
532 * @implemented
533 */
534 intptr_t _texecl(const _TCHAR* cmdname, const _TCHAR* arg0, ...)
535 {
536 _TCHAR* args;
537 va_list argp;
538 intptr_t ret = -1;
539
540 TRACE(MK_STR(_texecl)"('%"sT"')\n", cmdname);
541
542 va_start(argp, arg0);
543 args = valisttosT(arg0, argp, ' ');
544
545 if (args)
546 {
547 ret = do_spawnT(_P_OVERLAY, cmdname, args, NULL);
548 free(args);
549 }
550 va_end(argp);
551 return ret;
552 }
553
554 /*
555 * @implemented
556 */
557 intptr_t _texecv(const _TCHAR* cmdname, const _TCHAR* const* argv)
558 {
559 TRACE(MK_STR(_texecv)"('%"sT"')\n", cmdname);
560 return _tspawnv(_P_OVERLAY, cmdname, argv);
561 }
562
563 /*
564 * @implemented
565 */
566 intptr_t _texecle(const _TCHAR* cmdname, const _TCHAR* arg0, ... /*, NULL, char* const* envp */)
567 {
568 va_list argp;
569 _TCHAR* args;
570 _TCHAR* envs;
571 _TCHAR const* const* ptr;
572 intptr_t ret = -1;
573
574 TRACE(MK_STR(_texecle)"('%"sT"')\n", cmdname);
575
576 va_start(argp, arg0);
577 args = valisttosT(arg0, argp, ' ');
578 do
579 {
580 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
581 }
582 while (ptr != NULL);
583 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
584 envs = argvtosT(ptr, 0);
585 if (args)
586 {
587 ret = do_spawnT(_P_OVERLAY, cmdname, args, envs);
588 free(args);
589 }
590 if (envs)
591 {
592 free(envs);
593 }
594 va_end(argp);
595 return ret;
596 }
597
598 /*
599 * @implemented
600 */
601 intptr_t _texecve(const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp)
602 {
603 TRACE(MK_STR(_texecve)"('%"sT"')\n", cmdname);
604 return _tspawnve(_P_OVERLAY, cmdname, argv, envp);
605 }
606
607 /*
608 * @implemented
609 */
610 intptr_t _texeclp(const _TCHAR* cmdname, const _TCHAR* arg0, ...)
611 {
612 _TCHAR* args;
613 va_list argp;
614 intptr_t ret = -1;
615 _TCHAR pathname[FILENAME_MAX];
616
617 TRACE(MK_STR(_texeclp)"('%"sT"')\n", cmdname);
618
619 va_start(argp, arg0);
620 args = valisttosT(arg0, argp, ' ');
621
622 if (args)
623 {
624 ret = do_spawnT(_P_OVERLAY, find_execT(cmdname, pathname), args, NULL);
625 free(args);
626 }
627 va_end(argp);
628 return ret;
629 }
630
631 /*
632 * @implemented
633 */
634 intptr_t _texecvp(const _TCHAR* cmdname, const _TCHAR* const* argv)
635 {
636 TRACE(MK_STR(_texecvp)"('%"sT"')\n", cmdname);
637 return _tspawnvp(_P_OVERLAY, cmdname, argv);
638 }
639
640 /*
641 * @implemented
642 */
643 intptr_t _texeclpe(const _TCHAR* cmdname, const _TCHAR* arg0, ... /*, NULL, char* const* envp */)
644 {
645 va_list argp;
646 _TCHAR* args;
647 _TCHAR* envs;
648 _TCHAR const* const* ptr;
649 intptr_t ret = -1;
650 _TCHAR pathname[FILENAME_MAX];
651
652 TRACE(MK_STR(_texeclpe)"('%"sT"')\n", cmdname);
653
654 va_start(argp, arg0);
655 args = valisttosT(arg0, argp, ' ');
656 do
657 {
658 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
659 }
660 while (ptr != NULL);
661 ptr = (_TCHAR const* const*)va_arg(argp, _TCHAR*);
662 envs = argvtosT(ptr, 0);
663 if (args)
664 {
665 ret = do_spawnT(_P_OVERLAY, find_execT(cmdname, pathname), args, envs);
666 free(args);
667 }
668 if (envs)
669 {
670 free(envs);
671 }
672 va_end(argp);
673 return ret;
674 }
675
676 /*
677 * @implemented
678 */
679 intptr_t _texecvpe(const _TCHAR* cmdname, const _TCHAR* const* argv, const _TCHAR* const* envp)
680 {
681 TRACE(MK_STR(_texecvpe)"('%"sT"')\n", cmdname);
682 return _tspawnvpe(_P_OVERLAY, cmdname, argv, envp);
683 }
684
685