d9cdc52849dfd85c3e625b97d21db94d128258da
[reactos.git] / lib / msvcrt / process / process.c
1 /* $Id$ */
2 #include <windows.h>
3 #include <msvcrt/process.h>
4 #include <msvcrt/stdlib.h>
5 #include <msvcrt/fcntl.h>
6 #include <msvcrt/errno.h>
7
8 #define NDEBUG
9 #include <msvcrt/msvcrtdbg.h>
10
11 extern int maxfno;
12
13 static char* 
14 argvtos(char* const* argv, char delim)
15 {
16     int i, len;
17     char *ptr, *str;
18
19     if (argv == NULL)
20         return NULL;
21
22     for (i = 0, len = 0; argv[i]; i++) 
23     {
24         len += strlen(argv[i]) + 1;
25     }
26
27     str = ptr = (char*) malloc(len + 1);
28     if (str == NULL)
29         return NULL;
30
31     for(i = 0; argv[i]; i++) 
32     {
33         len = strlen(argv[i]);
34         memcpy(ptr, argv[i], len);
35         ptr += len;
36         *ptr++ = delim;
37     }
38     *ptr = 0;
39
40     return str;
41 }
42
43 static char* 
44 valisttos(const char* arg0, va_list alist, char delim)
45 {
46     va_list alist2 = alist;
47     char *ptr, *str;
48     int len;
49
50     if (arg0 == NULL)
51         return NULL;
52
53     ptr = (char*)arg0;
54     len = 0;
55     do
56     {
57         len += strlen(ptr) + 1;
58         ptr = va_arg(alist, char*);
59     }
60     while(ptr != NULL);
61
62     str = (char*) malloc(len + 1);
63     if (str == NULL)
64         return NULL;
65
66     ptr = str;
67     do
68     {
69         len = strlen(arg0);
70         memcpy(ptr, arg0, len);
71         *ptr++ = delim;
72         arg0 = va_arg(alist2, char*);
73     }
74     while(arg0 != NULL);
75     *ptr = 0;
76
77     return str;
78 }
79
80 static int
81 do_spawn(int mode, const char* cmdname, const char* args, const char* envp)
82 {
83     STARTUPINFO StartupInfo;
84     PROCESS_INFORMATION ProcessInformation;
85     char* fmode;
86     HANDLE* hFile;
87     int i, last;
88     BOOL bResult;
89     DWORD dwExitCode;
90     DWORD dwError;
91
92     DPRINT("do_spawn('%s')\n", cmdname);
93
94     if (mode != _P_NOWAIT && mode != _P_NOWAITO && mode != _P_WAIT && mode != _P_DETACH && mode != _P_OVERLAY)
95     {
96        errno = EINVAL;
97        return -1;
98     }
99
100     if (0 != _access(cmdname, F_OK))
101     {
102         errno = ENOENT;
103         return -1;
104     }
105     if (0 == _access(cmdname, D_OK))
106     {
107         errno = EISDIR;
108         return -1;
109     }
110
111     memset (&StartupInfo, 0, sizeof(STARTUPINFO));
112     StartupInfo.cb = sizeof(STARTUPINFO);
113
114     for (last = i = 0; i < maxfno; i++)
115     {
116         if ((void*)-1 != _get_osfhandle(i))
117         {
118             last = i + 1;
119         }
120     }
121
122     if (last)
123     {
124         StartupInfo.cbReserved2 = sizeof(ULONG) + last * (sizeof(char) + sizeof(HANDLE));
125         StartupInfo.lpReserved2 = malloc(StartupInfo.cbReserved2);
126         if (StartupInfo.lpReserved2 == NULL)
127         {
128             errno = ENOMEM;
129             return -1;
130         } 
131
132         *(DWORD*)StartupInfo.lpReserved2 = last;
133         fmode = (char*)(StartupInfo.lpReserved2 + sizeof(ULONG));
134         hFile = (HANDLE*)(StartupInfo.lpReserved2 + sizeof(ULONG) + last * sizeof(char));
135         for (i = 0; i < last; i++)
136         {
137             int _mode = __fileno_getmode(i);
138             HANDLE h = _get_osfhandle(i);
139             /* FIXME: The test of console handles (((ULONG)Handle) & 0x10000003) == 0x3) 
140              *        is possible wrong 
141              */
142             if ((((ULONG)h) & 0x10000003) == 0x3 || _mode & _O_NOINHERIT || (i < 3 && mode == _P_DETACH))
143             {
144                 *hFile = INVALID_HANDLE_VALUE;
145                 *fmode = 0;
146             }
147             else
148             {
149                 DWORD dwFlags;
150                 BOOL bFlag;
151                 bFlag = GetHandleInformation(h, &dwFlags);
152                 if (bFlag && (dwFlags & HANDLE_FLAG_INHERIT))
153                 {
154                     *hFile = h;
155                     *fmode = (_O_ACCMODE & _mode) | (((_O_TEXT | _O_BINARY) & _mode) >> 8);
156                 }
157                 else
158                 {
159                     *hFile = INVALID_HANDLE_VALUE;
160                     *fmode = 0;
161                 }
162                 fmode++;
163                 hFile++;
164             }
165         }
166     }
167
168     bResult = CreateProcessA((char *)cmdname,
169                              (char *)args,
170                              NULL,
171                              NULL,
172                              TRUE,
173                              mode == _P_DETACH ? DETACHED_PROCESS : 0,
174                              (LPVOID)envp,
175                              NULL,
176                              &StartupInfo,
177                              &ProcessInformation);
178     if (StartupInfo.lpReserved2)
179     {
180         free(StartupInfo.lpReserved2);
181     }
182
183     if (!bResult) 
184     {
185         dwError = GetLastError();
186         DPRINT("%x\n", dwError);
187         __set_errno(dwError);
188         return -1;
189     }
190     CloseHandle(ProcessInformation.hThread);
191     switch(mode)
192     {
193         case _P_OVERLAY:
194             _exit(0);
195         case _P_WAIT:
196             WaitForSingleObject(ProcessInformation.hProcess, INFINITE);
197             GetExitCodeProcess(ProcessInformation.hProcess, &dwExitCode);
198             CloseHandle(ProcessInformation.hProcess);
199             return (int)dwExitCode;
200         case _P_DETACH:
201             CloseHandle(ProcessInformation.hProcess);
202             return 0;
203     }
204     return (int)ProcessInformation.hProcess;
205 }
206
207 int _spawnl(int mode, const char *cmdname, const char* arg0, ...)
208 {
209     va_list argp;
210     char* args;
211     int ret = -1;
212
213     DPRINT("_spawnl('%s')\n", cmdname);
214
215     va_start(argp, arg0);
216     args = valisttos(arg0, argp, ' ');
217
218     if (args)
219     {
220         ret = do_spawn(mode, cmdname, args, NULL);
221         free(args);
222     }
223     return ret;
224 }
225
226 int _spawnv(int mode, const char *cmdname, char* const* argv)
227 {
228     char* args;
229     int ret = -1;
230
231     DPRINT("_spawnv('%s')\n", cmdname);
232
233     args = argvtos(argv, ' ');
234
235     if (args)
236     {
237         ret = do_spawn(mode, cmdname, args, NULL);
238         free(args);
239     }
240     return ret;
241 }
242
243 int _spawnle(int mode, const char *cmdname, const char* arg0, ... /*, NULL, const char* const* envp*/)
244 {
245     va_list argp;
246     char* args;
247     char* envs;
248     char* const* ptr;
249     int ret = -1;
250
251     DPRINT("_spawnle('%s')\n", cmdname);
252
253     va_start(argp, arg0);
254     args = valisttos(arg0, argp, ' ');
255     do
256     {
257         ptr = (char* const*)va_arg(argp, char*);
258     }
259     while (ptr != NULL);
260     envs = argvtos(ptr, 0);
261     if (args)
262     {
263         ret = do_spawn(mode, cmdname, args, envs);
264         free(args);
265     }
266     if (envs)
267     {
268         free(envs);
269     }
270     return ret;
271     
272 }
273
274 int _spawnve(int mode, const char *cmdname, char* const* argv, char* const* envp)
275 {
276     char *args;
277     char *envs;
278     int ret = -1;
279
280     DPRINT("_spawnve('%s')\n", cmdname);
281
282     args = argvtos(argv, ' ');
283     envs = argvtos(envp, 0);
284
285     if (args)
286     {
287         ret = do_spawn(mode, cmdname, args, envs);
288         free(args);
289     }
290     if (envs)
291     {
292         free(envs);
293     }
294     return ret;
295 }
296
297 int _spawnvp(int mode, const char* cmdname, char* const* argv)
298 {
299     char pathname[FILENAME_MAX];
300   
301     DPRINT("_spawnvp('%s')\n", cmdname);
302
303     _searchenv(cmdname, "PATH", pathname);
304
305     return _spawnv(mode, pathname[0] ? pathname : cmdname, argv);
306 }
307
308 int _spawnlpe(int mode, const char* cmdname, const char* arg0, .../*, NULL, const char* const* envp*/)
309 {
310     va_list argp;
311     char* args;
312     char* envs;
313     char* const * ptr;
314     int ret = -1;
315     char pathname[FILENAME_MAX];
316
317     DPRINT("_spawnlpe('%s')\n", cmdname);
318
319     _searchenv(cmdname, "PATH", pathname);
320
321     va_start(argp, arg0);
322     args = valisttos(arg0, argp, ' ');
323     do
324     {
325         ptr = (char* const*)va_arg(argp, char*);
326     }
327     while (ptr != NULL);
328     envs = argvtos(ptr, 0);
329     if (args)
330     {
331         ret = do_spawn(mode, pathname[0] ? pathname : cmdname, args, envs);
332         free(args);
333     }
334     if (envs)
335     {
336         free(envs);
337     }
338     return ret;
339 }
340
341 int _spawnvpe(int mode, const char* cmdname, char* const* argv, char* const* envp)
342 {
343     char pathname[FILENAME_MAX];
344   
345     DPRINT("_spawnvpe('%s')\n", cmdname);
346
347     _searchenv(cmdname, "PATH", pathname);
348
349     return _spawnve(mode, pathname[0] ? pathname : cmdname, argv, envp);
350 }
351
352 int _execl(const char* cmdname, const char* arg0, ...)
353 {
354     char* args;
355     va_list argp;
356     int ret = -1;
357
358     DPRINT("_execl('%s')\n", cmdname);
359
360     va_start(argp, arg0);
361     args = valisttos(arg0, argp, ' ');
362
363     if (args)
364     {
365         ret = do_spawn(P_OVERLAY, cmdname, args, NULL);
366         free(args);
367     }
368     return ret;
369 }
370
371 int _execv(const char* cmdname, char* const* argv)
372 {
373     DPRINT("_execv('%s')\n", cmdname);
374     return _spawnv(P_OVERLAY, cmdname, argv);
375 }
376
377 int _execle(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
378 {
379     va_list argp;
380     char* args;
381     char* envs;
382     char* const* ptr;
383     int ret = -1;
384
385     DPRINT("_execle('%s')\n", cmdname);
386
387     va_start(argp, arg0);
388     args = valisttos(arg0, argp, ' ');
389     do
390     {
391         ptr = (char* const*)va_arg(argp, char*);
392     }
393     while (ptr != NULL);
394     envs = argvtos((char**)ptr, 0);
395     if (args)
396     {
397         ret = do_spawn(P_OVERLAY, cmdname, args, envs);
398         free(args);
399     }
400     if (envs)
401     {
402         free(envs);
403     }
404     return ret;
405 }
406
407 int _execve(const char* cmdname, char* const* argv, char* const* envp)
408 {
409     DPRINT("_execve('%s')\n", cmdname);
410     return _spawnve(P_OVERLAY, cmdname, argv, envp);
411 }
412
413 int _execlp(const char* cmdname, const char* arg0, ...)
414 {
415     char* args;
416     va_list argp;
417     int ret = -1;
418     char pathname[FILENAME_MAX];
419
420     DPRINT("_execlp('%s')\n", cmdname);
421
422     _searchenv(cmdname, "PATH", pathname);
423
424     va_start(argp, arg0);
425     args = valisttos(arg0, argp, ' ');
426
427     if (args)
428     {
429         ret = do_spawn(P_OVERLAY, pathname[0] ? pathname : cmdname, args, NULL);
430         free(args);
431     }
432     return ret;
433 }
434
435 int _execvp(const char* cmdname, char* const* argv)
436 {
437     DPRINT("_execvp('%s')\n", cmdname);
438     return _spawnvp(P_OVERLAY, cmdname, argv);
439 }
440
441 int _execlpe(const char* cmdname, const char* arg0, ... /*, NULL, char* const* envp */)
442 {
443     va_list argp;
444     char* args;
445     char* envs;
446     char* const* ptr;
447     int ret = -1;
448     char pathname[FILENAME_MAX];
449
450     DPRINT("_execlpe('%s')\n", cmdname);
451
452     _searchenv(cmdname, "PATH", pathname);
453
454     va_start(argp, arg0);
455     args = valisttos(arg0, argp, ' ');
456     do
457     {
458         ptr = (char* const*)va_arg(argp, char*);
459     }
460     while (ptr != NULL);
461     envs = argvtos(ptr, 0);
462     if (args)
463     {
464         ret = do_spawn(P_OVERLAY, pathname[0] ? pathname : cmdname, args, envs);
465         free(args);
466     }
467     if (envs)
468     {
469         free(envs);
470     }
471     return ret;
472 }
473
474 int _execvpe(const char* cmdname, char* const* argv, char* const* envp)
475 {
476     DPRINT("_execvpe('%s')\n", cmdname);
477     return _spawnvpe(P_OVERLAY, cmdname, argv, envp);
478 }