xref: /reactos/sdk/lib/crt/process/process.c (revision f4d29a74)
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 
686