update for HEAD-2003091401
[reactos.git] / lib / msvcrt / process / process.c
1 /* $Id$ */
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 }