branch update for HEAD-2003050101
[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     STARTUPINFO 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        errno = EINVAL;
180        return -1;
181     }
182
183     if (0 != _access(cmdname, F_OK))
184     {
185         errno = ENOENT;
186         return -1;
187     }
188     if (0 == _access(cmdname, D_OK))
189     {
190         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             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 int _spawnl(int mode, const char *cmdname, const char* arg0, ...)
291 {
292     va_list argp;
293     char* args;
294     int ret = -1;
295
296     DPRINT("_spawnl('%s')\n", cmdname);
297
298     va_start(argp, arg0);
299     args = valisttos(arg0, argp, ' ');
300
301     if (args)
302     {
303         ret = do_spawn(mode, cmdname, args, NULL);
304         free(args);
305     }
306     return ret;
307 }
308
309 int _spawnv(int mode, const char *cmdname, char* const* argv)
310 {
311     char* args;
312     int ret = -1;
313
314     DPRINT("_spawnv('%s')\n", cmdname);
315
316     args = argvtos(argv, ' ');
317
318     if (args)
319     {
320         ret = do_spawn(mode, cmdname, args, NULL);
321         free(args);
322     }
323     return ret;
324 }
325
326 int _spawnle(int mode, const char *cmdname, const char* arg0, ... /*, NULL, const char* const* envp*/)
327 {
328     va_list argp;
329     char* args;
330     char* envs;
331     char* const* ptr;
332     int ret = -1;
333
334     DPRINT("_spawnle('%s')\n", cmdname);
335
336     va_start(argp, arg0);
337     args = valisttos(arg0, argp, ' ');
338     do
339     {
340         ptr = (char* const*)va_arg(argp, char*);
341     }
342     while (ptr != NULL);
343     envs = argvtos(ptr, 0);
344     if (args)
345     {
346         ret = do_spawn(mode, cmdname, args, envs);
347         free(args);
348     }
349     if (envs)
350     {
351         free(envs);
352     }
353     return ret;
354     
355 }
356
357 int _spawnve(int mode, const char *cmdname, char* const* argv, char* const* envp)
358 {
359     char *args;
360     char *envs;
361     int ret = -1;
362
363     DPRINT("_spawnve('%s')\n", cmdname);
364
365     args = argvtos(argv, ' ');
366     envs = argvtos(envp, 0);
367
368     if (args)
369     {
370         ret = do_spawn(mode, cmdname, args, envs);
371         free(args);
372     }
373     if (envs)
374     {
375         free(envs);
376     }
377     return ret;
378 }
379
380 int _spawnvp(int mode, const char* cmdname, char* const* argv)
381 {
382     char pathname[FILENAME_MAX];
383   
384     DPRINT("_spawnvp('%s')\n", cmdname);
385
386     return _spawnv(mode, find_exec(cmdname, pathname), argv);
387 }
388
389 int _spawnlp(int mode, const char* cmdname, const char* arg0, .../*, NULL*/)
390 {
391     va_list argp;
392     char* args;
393     int ret = -1;
394     char pathname[FILENAME_MAX];
395
396     DPRINT("_spawnlp('%s')\n", cmdname);
397
398     va_start(argp, arg0);
399     args = valisttos(arg0, argp, ' ');
400     if (args)
401     {
402         ret = do_spawn(mode, find_exec(cmdname, pathname), args, NULL);
403         free(args);
404     }
405     return ret;
406 }
407
408
409 int _spawnlpe(int mode, const char* cmdname, const char* arg0, .../*, NULL, const char* const* envp*/)
410 {
411     va_list argp;
412     char* args;
413     char* envs;
414     char* const * ptr;
415     int ret = -1;
416     char pathname[FILENAME_MAX];
417
418     DPRINT("_spawnlpe('%s')\n", cmdname);
419
420     va_start(argp, arg0);
421     args = valisttos(arg0, argp, ' ');
422     do
423     {
424         ptr = (char* const*)va_arg(argp, char*);
425     }
426     while (ptr != NULL);
427     envs = argvtos(ptr, 0);
428     if (args)
429     {
430         ret = do_spawn(mode, find_exec(cmdname, pathname), args, envs);
431         free(args);
432     }
433     if (envs)
434     {
435         free(envs);
436     }
437     return ret;
438 }
439
440 int _spawnvpe(int mode, const char* cmdname, char* const* argv, char* const* envp)
441 {
442     char pathname[FILENAME_MAX];
443   
444     DPRINT("_spawnvpe('%s')\n", cmdname);
445
446     return _spawnve(mode, find_exec(cmdname, pathname), argv, envp);
447 }
448
449 int _execl(const char* cmdname, const char* arg0, ...)
450 {
451     char* args;
452     va_list argp;
453     int ret = -1;
454
455     DPRINT("_execl('%s')\n", cmdname);
456
457     va_start(argp, arg0);
458     args = valisttos(arg0, argp, ' ');
459
460     if (args)
461     {
462         ret = do_spawn(P_OVERLAY, cmdname, args, NULL);
463         free(args);
464     }
465     return ret;
466 }
467
468 int _execv(const char* cmdname, char* const* argv)
469 {
470     DPRINT("_execv('%s')\n", cmdname);
471     return _spawnv(P_OVERLAY, cmdname, argv);
472 }
473
474 int _execle(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
475 {
476     va_list argp;
477     char* args;
478     char* envs;
479     char* const* ptr;
480     int ret = -1;
481
482     DPRINT("_execle('%s')\n", cmdname);
483
484     va_start(argp, arg0);
485     args = valisttos(arg0, argp, ' ');
486     do
487     {
488         ptr = (char* const*)va_arg(argp, char*);
489     }
490     while (ptr != NULL);
491     envs = argvtos((char**)ptr, 0);
492     if (args)
493     {
494         ret = do_spawn(P_OVERLAY, cmdname, args, envs);
495         free(args);
496     }
497     if (envs)
498     {
499         free(envs);
500     }
501     return ret;
502 }
503
504 int _execve(const char* cmdname, char* const* argv, char* const* envp)
505 {
506     DPRINT("_execve('%s')\n", cmdname);
507     return _spawnve(P_OVERLAY, cmdname, argv, envp);
508 }
509
510 int _execlp(const char* cmdname, const char* arg0, ...)
511 {
512     char* args;
513     va_list argp;
514     int ret = -1;
515     char pathname[FILENAME_MAX];
516
517     DPRINT("_execlp('%s')\n", cmdname);
518
519     va_start(argp, arg0);
520     args = valisttos(arg0, argp, ' ');
521
522     if (args)
523     {
524         ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, NULL);
525         free(args);
526     }
527     return ret;
528 }
529
530 int _execvp(const char* cmdname, char* const* argv)
531 {
532     DPRINT("_execvp('%s')\n", cmdname);
533     return _spawnvp(P_OVERLAY, cmdname, argv);
534 }
535
536 int _execlpe(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
537 {
538     va_list argp;
539     char* args;
540     char* envs;
541     char* const* ptr;
542     int ret = -1;
543     char pathname[FILENAME_MAX];
544
545     DPRINT("_execlpe('%s')\n", cmdname);
546
547     va_start(argp, arg0);
548     args = valisttos(arg0, argp, ' ');
549     do
550     {
551         ptr = (char* const*)va_arg(argp, char*);
552     }
553     while (ptr != NULL);
554     envs = argvtos(ptr, 0);
555     if (args)
556     {
557         ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, envs);
558         free(args);
559     }
560     if (envs)
561     {
562         free(envs);
563     }
564     return ret;
565 }
566
567 int _execvpe(const char* cmdname, char* const* argv, char* const* envp)
568 {
569     DPRINT("_execvpe('%s')\n", cmdname);
570     return _spawnvpe(P_OVERLAY, cmdname, argv, envp);
571 }