update for HEAD-2003021201
[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++ = delim;
154         arg0 = va_arg(alist2, char*);
155     }
156     while(arg0 != NULL);
157     *ptr = 0;
158
159     return str;
160 }
161
162 static int
163 do_spawn(int mode, const char* cmdname, const char* args, const char* envp)
164 {
165     STARTUPINFO StartupInfo;
166     PROCESS_INFORMATION ProcessInformation;
167     char* fmode;
168     HANDLE* hFile;
169     int i, last;
170     BOOL bResult;
171     DWORD dwExitCode;
172     DWORD dwError;
173
174     DPRINT("do_spawn('%s')\n", cmdname);
175
176     if (mode != _P_NOWAIT && mode != _P_NOWAITO && mode != _P_WAIT && mode != _P_DETACH && mode != _P_OVERLAY)
177     {
178        errno = EINVAL;
179        return -1;
180     }
181
182     if (0 != _access(cmdname, F_OK))
183     {
184         errno = ENOENT;
185         return -1;
186     }
187     if (0 == _access(cmdname, D_OK))
188     {
189         errno = EISDIR;
190         return -1;
191     }
192
193     memset (&StartupInfo, 0, sizeof(STARTUPINFO));
194     StartupInfo.cb = sizeof(STARTUPINFO);
195
196     for (last = i = 0; i < maxfno; i++)
197     {
198         if ((void*)-1 != _get_osfhandle(i))
199         {
200             last = i + 1;
201         }
202     }
203
204     if (last)
205     {
206         StartupInfo.cbReserved2 = sizeof(ULONG) + last * (sizeof(char) + sizeof(HANDLE));
207         StartupInfo.lpReserved2 = malloc(StartupInfo.cbReserved2);
208         if (StartupInfo.lpReserved2 == NULL)
209         {
210             errno = ENOMEM;
211             return -1;
212         } 
213
214         *(DWORD*)StartupInfo.lpReserved2 = last;
215         fmode = (char*)(StartupInfo.lpReserved2 + sizeof(ULONG));
216         hFile = (HANDLE*)(StartupInfo.lpReserved2 + sizeof(ULONG) + last * sizeof(char));
217         for (i = 0; i < last; i++)
218         {
219             int _mode = __fileno_getmode(i);
220             HANDLE h = _get_osfhandle(i);
221             /* FIXME: The test of console handles (((ULONG)Handle) & 0x10000003) == 0x3) 
222              *        is possible wrong 
223              */
224             if ((((ULONG)h) & 0x10000003) == 0x3 || _mode & _O_NOINHERIT || (i < 3 && mode == _P_DETACH))
225             {
226                 *hFile = INVALID_HANDLE_VALUE;
227                 *fmode = 0;
228             }
229             else
230             {
231                 DWORD dwFlags;
232                 BOOL bFlag;
233                 bFlag = GetHandleInformation(h, &dwFlags);
234                 if (bFlag && (dwFlags & HANDLE_FLAG_INHERIT))
235                 {
236                     *hFile = h;
237                     *fmode = (_O_ACCMODE & _mode) | (((_O_TEXT | _O_BINARY) & _mode) >> 8);
238                 }
239                 else
240                 {
241                     *hFile = INVALID_HANDLE_VALUE;
242                     *fmode = 0;
243                 }
244             }
245             fmode++;
246             hFile++;
247         }
248     }
249
250     bResult = CreateProcessA((char *)cmdname,
251                              (char *)args,
252                              NULL,
253                              NULL,
254                              TRUE,
255                              mode == _P_DETACH ? DETACHED_PROCESS : 0,
256                              (LPVOID)envp,
257                              NULL,
258                              &StartupInfo,
259                              &ProcessInformation);
260     if (StartupInfo.lpReserved2)
261     {
262         free(StartupInfo.lpReserved2);
263     }
264
265     if (!bResult) 
266     {
267         dwError = GetLastError();
268         DPRINT("%x\n", dwError);
269         __set_errno(dwError);
270         return -1;
271     }
272     CloseHandle(ProcessInformation.hThread);
273     switch(mode)
274     {
275         case _P_OVERLAY:
276             _exit(0);
277         case _P_WAIT:
278             WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
279             GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
280             CloseHandle(ProcessInformation.hProcess);
281             return (int)dwExitCode;
282         case _P_DETACH:
283             CloseHandle(ProcessInformation.hProcess);
284             return 0;
285     }
286     return (int)ProcessInformation.hProcess;
287 }
288
289 int _spawnl(int mode, const char *cmdname, const char* arg0, ...)
290 {
291     va_list argp;
292     char* args;
293     int ret = -1;
294
295     DPRINT("_spawnl('%s')\n", cmdname);
296
297     va_start(argp, arg0);
298     args = valisttos(arg0, argp, ' ');
299
300     if (args)
301     {
302         ret = do_spawn(mode, cmdname, args, NULL);
303         free(args);
304     }
305     return ret;
306 }
307
308 int _spawnv(int mode, const char *cmdname, char* const* argv)
309 {
310     char* args;
311     int ret = -1;
312
313     DPRINT("_spawnv('%s')\n", cmdname);
314
315     args = argvtos(argv, ' ');
316
317     if (args)
318     {
319         ret = do_spawn(mode, cmdname, args, NULL);
320         free(args);
321     }
322     return ret;
323 }
324
325 int _spawnle(int mode, const char *cmdname, const char* arg0, ... /*, NULL, const char* const* envp*/)
326 {
327     va_list argp;
328     char* args;
329     char* envs;
330     char* const* ptr;
331     int ret = -1;
332
333     DPRINT("_spawnle('%s')\n", cmdname);
334
335     va_start(argp, arg0);
336     args = valisttos(arg0, argp, ' ');
337     do
338     {
339         ptr = (char* const*)va_arg(argp, char*);
340     }
341     while (ptr != NULL);
342     envs = argvtos(ptr, 0);
343     if (args)
344     {
345         ret = do_spawn(mode, cmdname, args, envs);
346         free(args);
347     }
348     if (envs)
349     {
350         free(envs);
351     }
352     return ret;
353     
354 }
355
356 int _spawnve(int mode, const char *cmdname, char* const* argv, char* const* envp)
357 {
358     char *args;
359     char *envs;
360     int ret = -1;
361
362     DPRINT("_spawnve('%s')\n", cmdname);
363
364     args = argvtos(argv, ' ');
365     envs = argvtos(envp, 0);
366
367     if (args)
368     {
369         ret = do_spawn(mode, cmdname, args, envs);
370         free(args);
371     }
372     if (envs)
373     {
374         free(envs);
375     }
376     return ret;
377 }
378
379 int _spawnvp(int mode, const char* cmdname, char* const* argv)
380 {
381     char pathname[FILENAME_MAX];
382   
383     DPRINT("_spawnvp('%s')\n", cmdname);
384
385     return _spawnv(mode, find_exec(cmdname, pathname), argv);
386 }
387
388 int _spawnlpe(int mode, const char* cmdname, const char* arg0, .../*, NULL, const char* const* envp*/)
389 {
390     va_list argp;
391     char* args;
392     char* envs;
393     char* const * ptr;
394     int ret = -1;
395     char pathname[FILENAME_MAX];
396
397     DPRINT("_spawnlpe('%s')\n", cmdname);
398
399     va_start(argp, arg0);
400     args = valisttos(arg0, argp, ' ');
401     do
402     {
403         ptr = (char* const*)va_arg(argp, char*);
404     }
405     while (ptr != NULL);
406     envs = argvtos(ptr, 0);
407     if (args)
408     {
409         ret = do_spawn(mode, find_exec(cmdname, pathname), args, envs);
410         free(args);
411     }
412     if (envs)
413     {
414         free(envs);
415     }
416     return ret;
417 }
418
419 int _spawnvpe(int mode, const char* cmdname, char* const* argv, char* const* envp)
420 {
421     char pathname[FILENAME_MAX];
422   
423     DPRINT("_spawnvpe('%s')\n", cmdname);
424
425     return _spawnve(mode, find_exec(cmdname, pathname), argv, envp);
426 }
427
428 int _execl(const char* cmdname, const char* arg0, ...)
429 {
430     char* args;
431     va_list argp;
432     int ret = -1;
433
434     DPRINT("_execl('%s')\n", cmdname);
435
436     va_start(argp, arg0);
437     args = valisttos(arg0, argp, ' ');
438
439     if (args)
440     {
441         ret = do_spawn(P_OVERLAY, cmdname, args, NULL);
442         free(args);
443     }
444     return ret;
445 }
446
447 int _execv(const char* cmdname, char* const* argv)
448 {
449     DPRINT("_execv('%s')\n", cmdname);
450     return _spawnv(P_OVERLAY, cmdname, argv);
451 }
452
453 int _execle(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
454 {
455     va_list argp;
456     char* args;
457     char* envs;
458     char* const* ptr;
459     int ret = -1;
460
461     DPRINT("_execle('%s')\n", cmdname);
462
463     va_start(argp, arg0);
464     args = valisttos(arg0, argp, ' ');
465     do
466     {
467         ptr = (char* const*)va_arg(argp, char*);
468     }
469     while (ptr != NULL);
470     envs = argvtos((char**)ptr, 0);
471     if (args)
472     {
473         ret = do_spawn(P_OVERLAY, cmdname, args, envs);
474         free(args);
475     }
476     if (envs)
477     {
478         free(envs);
479     }
480     return ret;
481 }
482
483 int _execve(const char* cmdname, char* const* argv, char* const* envp)
484 {
485     DPRINT("_execve('%s')\n", cmdname);
486     return _spawnve(P_OVERLAY, cmdname, argv, envp);
487 }
488
489 int _execlp(const char* cmdname, const char* arg0, ...)
490 {
491     char* args;
492     va_list argp;
493     int ret = -1;
494     char pathname[FILENAME_MAX];
495
496     DPRINT("_execlp('%s')\n", cmdname);
497
498     va_start(argp, arg0);
499     args = valisttos(arg0, argp, ' ');
500
501     if (args)
502     {
503         ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, NULL);
504         free(args);
505     }
506     return ret;
507 }
508
509 int _execvp(const char* cmdname, char* const* argv)
510 {
511     DPRINT("_execvp('%s')\n", cmdname);
512     return _spawnvp(P_OVERLAY, cmdname, argv);
513 }
514
515 int _execlpe(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
516 {
517     va_list argp;
518     char* args;
519     char* envs;
520     char* const* ptr;
521     int ret = -1;
522     char pathname[FILENAME_MAX];
523
524     DPRINT("_execlpe('%s')\n", cmdname);
525
526     va_start(argp, arg0);
527     args = valisttos(arg0, argp, ' ');
528     do
529     {
530         ptr = (char* const*)va_arg(argp, char*);
531     }
532     while (ptr != NULL);
533     envs = argvtos(ptr, 0);
534     if (args)
535     {
536         ret = do_spawn(P_OVERLAY, find_exec(cmdname, pathname), args, envs);
537         free(args);
538     }
539     if (envs)
540     {
541         free(envs);
542     }
543     return ret;
544 }
545
546 int _execvpe(const char* cmdname, char* const* argv, char* const* envp)
547 {
548     DPRINT("_execvpe('%s')\n", cmdname);
549     return _spawnvpe(P_OVERLAY, cmdname, argv, envp);
550 }