Fixed some issues found by winapi_check.
[wine] / dlls / crtdll / spawn.c
1 /*
2  * CRTDLL spawn functions
3  * 
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  *
9  * These functions differ in whether they pass arguments as an array
10  * (v in the name) or as varags (l in the name), whether they
11  * seach the path (p in the name) and/or whether they take an
12  * environment (e in the name) or pass the parents environment.
13  *                  Args as   Search   Take
14  * Name             varargs?  path?    environment?
15  * spawnl              N         N        N
16  * spawnle             N         N        Y
17  * spawnlp             N         Y        N
18  * spawnlpe            N         Y        Y
19  * spawnv              Y         N        N
20  * spawnve             Y         N        Y
21  * spawnvp             Y         Y        N
22  * spawnvpe            Y         Y        Y
23  *
24  * Implementation Notes:
25  * MT Safe - But only because of missing functionality.
26  * 
27  * After translating input arguments into the required format for
28  * CreateProcess(), the internal function __CRTDLL__spawn() is
29  * called to perform the actual spawning.
30  *
31  * FIXME:
32  * -File handles need some special handling. Sometimes children get
33  *  open file handles, sometimes not. The docs are confusing.
34  * -No check for maximum path/argument/environment size is done.
35  * Unresolved issues Uwe Bonnes 970904:
36  * -system-call calls another wine process, but without debugging arguments
37  *  and uses the first wine executable in the path
38  */
39
40 #include "crtdll.h"
41 #include <errno.h>
42 #include <stdlib.h>
43
44
45 DEFAULT_DEBUG_CHANNEL(crtdll);
46
47 /* Process creation flags */
48 #define _P_WAIT    0
49 #define _P_NOWAIT  1
50 #define _P_OVERLAY 2
51 #define _P_NOWAITO 3
52 #define _P_DETACH  4
53
54
55 extern void __CRTDLL__set_errno(ULONG err);
56 extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count);
57 extern VOID __cdecl CRTDLL_free(void *ptr);
58 extern VOID __cdecl CRTDLL__exit(LONG ret);
59 extern INT CRTDLL_doserrno;
60
61
62 /* INTERNAL: Spawn a child process */
63 static int __CRTDLL__spawn(INT flags, LPCSTR exe, LPSTR args, LPSTR env)
64 {
65   STARTUPINFOA si;
66   PROCESS_INFORMATION pi;
67
68   if ((unsigned)flags > _P_DETACH)
69   {
70     CRTDLL_errno = EINVAL;
71     return -1;
72   }
73
74   FIXME(":must dup/kill streams for child process\n");
75
76   memset(&si, 0, sizeof(si));
77   si.cb = sizeof(si);
78
79   if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
80                       flags == _P_DETACH ? DETACHED_PROCESS : 0,
81                       env, NULL, &si, &pi))
82   {
83     __CRTDLL__set_errno(GetLastError());
84     return -1;
85   }
86
87   switch(flags)
88   {
89   case _P_WAIT:
90     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
91     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
92     CloseHandle(pi.hProcess);
93     CloseHandle(pi.hThread);
94     return pi.dwProcessId;
95   case _P_DETACH:
96     CloseHandle(pi.hProcess);
97     pi.hProcess = 0;
98     /* fall through */
99   case _P_NOWAIT:
100   case _P_NOWAITO:
101     CloseHandle(pi.hThread);
102     return pi.hProcess;
103   case  _P_OVERLAY:
104     CRTDLL__exit(0);
105   }
106   return -1; /* cant reach here */
107 }
108
109
110 /* INTERNAL: Convert argv list to a single 'delim'-seperated string */
111 static LPSTR __CRTDLL__argvtos(LPCSTR *arg, CHAR delim)
112 {
113   LPCSTR *search = arg;
114   LONG size = 0;
115   LPSTR ret;
116
117   if (!arg && !delim)
118     return NULL;
119
120   /* get length */
121   while(*search)
122   {
123     size += strlen(*search) + 1;
124     search++;
125   }
126
127   if (!(ret = (LPSTR)CRTDLL_calloc(size + 1, 1)))
128     return NULL;
129
130   /* fill string */
131   search = arg;
132   size = 0;
133   while(*search)
134   {
135     int strsize = strlen(*search);
136     memcpy(ret+size,*search,strsize);
137     ret[size+strsize] = delim;
138     size += strsize + 1;
139     search++;
140   }
141   return ret;
142 }
143
144
145 /*********************************************************************
146  *                  _cwait       (CRTDLL.069)
147  *
148  * Wait for a spawned process to finish.
149  */
150 INT __cdecl CRTDLL__cwait(LPINT status, INT pid, INT action)
151 {
152   HANDLE hPid = (HANDLE)pid;
153
154   action = action; /* Remove warning */
155
156   if (!WaitForSingleObject(hPid, -1)) /* wait forvever */
157   {
158     if (status)
159     {
160       DWORD stat;
161       GetExitCodeProcess(hPid, &stat);
162       *status = (INT)stat;
163     }
164     return pid;
165   }
166   CRTDLL_doserrno = GetLastError();
167
168   if (CRTDLL_doserrno == ERROR_INVALID_HANDLE)
169     CRTDLL_errno = ECHILD;
170   else
171     __CRTDLL__set_errno(CRTDLL_doserrno);
172
173   return status ? *status = -1 : -1;
174 }
175
176
177 /*********************************************************************
178  *                  _spawnv      (CRTDLL.273)
179  *
180  * Spawn a process.
181  */
182 HANDLE __cdecl CRTDLL__spawnv(INT flags, LPCSTR name, LPCSTR *argv)
183 {
184   return CRTDLL__spawnve(flags, name, argv, NULL);
185 }
186
187
188 /*********************************************************************
189  *                  _spawnve     (CRTDLL.274)
190  *
191  * Spawn a process.
192  */
193 HANDLE __cdecl CRTDLL__spawnve(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
194 {
195   LPSTR args = __CRTDLL__argvtos(argv,' ');
196   LPSTR envs = __CRTDLL__argvtos(envv,0);
197   LPCSTR fullname = name;
198   HANDLE ret = -1;
199
200   FIXME(":not translating name %s to locate program\n",fullname);
201   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
202
203   if (args)
204   {
205     ret = __CRTDLL__spawn(flags, fullname, args, envs);
206     CRTDLL_free(args);
207   }
208   if (envs)
209     CRTDLL_free(envs);
210
211   return ret;
212 }
213
214
215 /*********************************************************************
216  *                  _spawnvp     (CRTDLL.275)
217  *
218  * Spawn a process.
219  */
220 HANDLE __cdecl CRTDLL__spawnvp(INT flags, LPCSTR name, LPCSTR *argv)
221 {
222   return CRTDLL__spawnvpe(flags, name, argv, NULL);
223 }
224
225
226 /*********************************************************************
227  *                  _spawnvpe    (CRTDLL.276)
228  *
229  * Spawn a process.
230  */
231 HANDLE __cdecl CRTDLL__spawnvpe(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
232 {
233   char fullname[MAX_PATH];
234
235   CRTDLL__searchenv(name, "PATH", fullname);
236   return CRTDLL__spawnve(flags, fullname[0] ? fullname : name, argv, envv);
237 }
238
239
240 /*********************************************************************
241  *                  system       (CRTDLL.485)
242  *
243  * Spawn an O/S process.
244  */
245 INT __cdecl CRTDLL_system(LPCSTR cmd)
246 {
247     /* FIXME: should probably launch cmd interpreter in COMSPEC */
248     return __CRTDLL__spawn(_P_WAIT, cmd, NULL, NULL);
249 }