Added an unknown VxD error code.
[wine] / dlls / msvcrt / process.c
1 /*
2  * msvcrt.dll spawn/exec 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  * FIXME:
10  * -File handles need some special handling. Sometimes children get
11  *  open file handles, sometimes not. The docs are confusing
12  * -No check for maximum path/argument/environment size is done
13  */
14 #include "msvcrt.h"
15 #include "ms_errno.h"
16
17 #include "msvcrt/process.h"
18 #include "msvcrt/stdlib.h"
19
20 DEFAULT_DEBUG_CHANNEL(msvcrt);
21
22 /* FIXME: Check file extensions for app to run */
23 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
24 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
25 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
26 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
27
28 /* INTERNAL: Spawn a child process */
29 static int msvcrt_spawn(int flags, const char* exe, char* args, char* env)
30 {
31   STARTUPINFOA si;
32   PROCESS_INFORMATION pi;
33
34   if (sizeof(HANDLE) != sizeof(int))
35     WARN("This call is unsuitable for your architecture\n");
36
37   if ((unsigned)flags > _P_DETACH)
38   {
39     SET_THREAD_VAR(errno,MSVCRT_EINVAL);
40     return -1;
41   }
42
43   FIXME(":must dup/kill streams for child process\n");
44
45   memset(&si, 0, sizeof(si));
46   si.cb = sizeof(si);
47
48   if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
49                      flags == _P_DETACH ? DETACHED_PROCESS : 0,
50                      env, NULL, &si, &pi))
51   {
52     MSVCRT__set_errno(GetLastError());
53     return -1;
54   }
55
56   switch(flags)
57   {
58   case _P_WAIT:
59     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
60     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
61     CloseHandle(pi.hProcess);
62     CloseHandle(pi.hThread);
63     return (int)pi.dwProcessId;
64   case _P_DETACH:
65     CloseHandle(pi.hProcess);
66     pi.hProcess = 0;
67     /* fall through */
68   case _P_NOWAIT:
69   case _P_NOWAITO:
70     CloseHandle(pi.hThread);
71     return (int)pi.hProcess;
72   case  _P_OVERLAY:
73     MSVCRT__exit(0);
74   }
75   return -1; /* can't reach here */
76 }
77
78 /* INTERNAL: Convert argv list to a single 'delim'-separated string */
79 static char* msvcrt_argvtos(const char* const* arg, char delim)
80 {
81   const char* const* search = arg;
82   long size = 0;
83   char *ret;
84
85   if (!arg && !delim)
86     return NULL;
87
88   /* get length */
89   while(*search)
90   {
91     size += strlen(*search) + 1;
92     search++;
93   }
94
95   if (!(ret = (char *)MSVCRT_calloc(size + 1, 1)))
96     return NULL;
97
98   /* fill string */
99   search = arg;
100   size = 0;
101   while(*search)
102   {
103     int strsize = strlen(*search);
104     memcpy(ret+size,*search,strsize);
105     ret[size+strsize] = delim;
106     size += strsize + 1;
107     search++;
108   }
109   return ret;
110 }
111
112 /* INTERNAL: Convert va_list to a single 'delim'-separated string */
113 static char* msvcrt_valisttos(const char* arg0, va_list ap, char delim)
114 {
115   va_list search = ap;
116   long size;
117   char *arg;
118   char *ret;
119   int strsize;
120
121   if (!arg0 && !delim)
122     return NULL;
123
124   /* get length */
125   size = strlen(arg0) + 1;
126   while((arg = va_arg(search, char *)) != NULL)
127   {
128     size += strlen(arg) + 1;
129   }
130
131   if (!(ret = (char *)MSVCRT_calloc(size + 1, 1)))
132     return NULL;
133
134   /* fill string */
135   search = ap;
136   size = 0;
137   strsize = strlen(arg0);
138   memcpy(ret+size,arg0,strsize);
139   ret[size+strsize] = delim;
140   size += strsize + 1;
141   while((arg = va_arg(search, char *)) != NULL)
142   {
143     strsize = strlen(search);
144     memcpy(ret+size,search,strsize);
145     ret[size+strsize] = delim;
146     size += strsize + 1;
147   }
148   return ret;
149 }
150
151 /*********************************************************************
152  *              _cwait (MSVCRT.@)
153  */
154 int _cwait(int *status, int pid, int action)
155 {
156   HANDLE hPid = (HANDLE)pid;
157   int doserrno;
158
159   action = action; /* Remove warning */
160
161   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
162   {
163     if (status)
164     {
165       DWORD stat;
166       GetExitCodeProcess(hPid, &stat);
167       *status = (int)stat;
168     }
169     return (int)pid;
170   }
171   doserrno = GetLastError();
172
173   if (doserrno == ERROR_INVALID_HANDLE)
174   {
175     SET_THREAD_VAR(errno, MSVCRT_ECHILD);
176     SET_THREAD_VAR(doserrno,doserrno);
177   }
178   else
179     MSVCRT__set_errno(doserrno);
180
181   return status ? *status = -1 : -1;
182 }
183
184 /*********************************************************************
185  *              _execl (MSVCRT.@)
186  */
187 int _execl(const char* name, const char* arg0, ...)
188 {
189   va_list ap;
190   char * args;
191   int ret;
192
193   va_start(ap, arg0);
194   args = msvcrt_valisttos(arg0, ap, ' ');
195   va_end(ap);
196
197   ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
198   MSVCRT_free(args);
199
200   return ret;
201 }
202
203 /*********************************************************************
204  *              _execlp (MSVCRT.@)
205  */
206 int _execlp(const char* name, const char* arg0, ...)
207 {
208   va_list ap;
209   char * args;
210   int ret;
211   char fullname[MAX_PATH];
212
213   _searchenv(name, "PATH", fullname);
214
215   va_start(ap, arg0);
216   args = msvcrt_valisttos(arg0, ap, ' ');
217   va_end(ap);
218
219   ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
220   MSVCRT_free(args);
221
222   return ret;
223 }
224
225 /*********************************************************************
226  *              _execv (MSVCRT.@)
227  */
228 int _execv(const char* name, char* const* argv)
229 {
230   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
231 }
232
233 /*********************************************************************
234  *              _execve (MSVCRT.@)
235  */
236 int _execve(const char* name, char* const* argv, const char* const* envv)
237 {
238   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
239 }
240
241 /*********************************************************************
242  *              _execvpe (MSVCRT.@)
243  */
244 int _execvpe(const char* name, char* const* argv, const char* const* envv)
245 {
246   char fullname[MAX_PATH];
247
248   _searchenv(name, "PATH", fullname);
249   return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
250                   (const char* const*) argv, envv);
251 }
252
253 /*********************************************************************
254  *              _execvp (MSVCRT.@)
255  */
256 int _execvp(const char* name, char* const* argv)
257 {
258   return _execvpe(name, argv, NULL);
259 }
260
261 /*********************************************************************
262  *              _spawnl (MSVCRT.@)
263  */
264 int _spawnl(int flags, const char* name, const char* arg0, ...)
265 {
266   va_list ap;
267   char * args;
268   int ret;
269
270   va_start(ap, arg0);
271   args = msvcrt_valisttos(arg0, ap, ' ');
272   va_end(ap);
273
274   ret = msvcrt_spawn(flags, name, args, NULL);
275   MSVCRT_free(args);
276
277   return ret;
278 }
279
280 /*********************************************************************
281  *              _spawnlp (MSVCRT.@)
282  */
283 int _spawnlp(int flags, const char* name, const char* arg0, ...)
284 {
285   va_list ap;
286   char * args;
287   int ret;
288   char fullname[MAX_PATH];
289
290   _searchenv(name, "PATH", fullname);
291
292   va_start(ap, arg0);
293   args = msvcrt_valisttos(arg0, ap, ' ');
294   va_end(ap);
295
296   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
297   MSVCRT_free(args);
298
299   return ret;
300 }
301
302 /*********************************************************************
303  *              _spawnve (MSVCRT.@)
304  */
305 int _spawnve(int flags, const char* name, const char* const* argv,
306                             const char* const* envv)
307 {
308   char * args = msvcrt_argvtos(argv,' ');
309   char * envs = msvcrt_argvtos(envv,0);
310   const char *fullname = name;
311   int ret = -1;
312
313   FIXME(":not translating name %s to locate program\n",fullname);
314   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
315
316   if (args)
317   {
318     ret = msvcrt_spawn(flags, fullname, args, envs);
319     MSVCRT_free(args);
320   }
321   if (envs)
322     MSVCRT_free(envs);
323
324   return ret;
325 }
326
327 /*********************************************************************
328  *              _spawnv (MSVCRT.@)
329  */
330 int _spawnv(int flags, const char* name, const char* const* argv)
331 {
332   return _spawnve(flags, name, argv, NULL);
333 }
334
335 /*********************************************************************
336  *              _spawnvpe (MSVCRT.@)
337  */
338 int _spawnvpe(int flags, const char* name, const char* const* argv,
339                             const char* const* envv)
340 {
341   char fullname[MAX_PATH];
342   _searchenv(name, "PATH", fullname);
343   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
344 }
345
346 /*********************************************************************
347  *              _spawnvp (MSVCRT.@)
348  */
349 int _spawnvp(int flags, const char* name, const char* const* argv)
350 {
351   return _spawnvpe(flags, name, argv, NULL);
352 }
353
354 /*********************************************************************
355  *              system (MSVCRT.@)
356  */
357 int MSVCRT_system(const char* cmd)
358 {
359   /* FIXME: should probably launch cmd interpreter in COMSPEC */
360   return msvcrt_spawn(_P_WAIT, cmd, NULL, NULL);
361 }
362
363 /*********************************************************************
364  *              _loaddll (MSVCRT.@)
365  */
366 int _loaddll(const char* dllname)
367 {
368   return LoadLibraryA(dllname);
369 }
370
371 /*********************************************************************
372  *              _unloaddll (MSVCRT.@)
373  */
374 int _unloaddll(int dll)
375 {
376   if (FreeLibrary((HANDLE)dll))
377     return 0;
378   else
379   {
380     int err = GetLastError();
381     MSVCRT__set_errno(err);
382     return err;
383   }
384 }
385