- CopyAcceleratorTable can cause a buffer overflow because it uses an
[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  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * FIXME:
24  * -File handles need some special handling. Sometimes children get
25  *  open file handles, sometimes not. The docs are confusing
26  * -No check for maximum path/argument/environment size is done
27  */
28 #include "config.h"
29
30 #include <stdarg.h>
31
32 #include "msvcrt.h"
33 #include "wine/debug.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
36
37 /* INTERNAL: Spawn a child process */
38 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
39 {
40   STARTUPINFOA si;
41   PROCESS_INFORMATION pi;
42
43   if (sizeof(HANDLE) != sizeof(int))
44     WARN("This call is unsuitable for your architecture\n");
45
46   if ((unsigned)flags > MSVCRT__P_DETACH)
47   {
48     *MSVCRT__errno() = MSVCRT_EINVAL;
49     return -1;
50   }
51
52   FIXME(":must dup/kill streams for child process\n");
53
54   memset(&si, 0, sizeof(si));
55   si.cb = sizeof(si);
56
57   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
58                      flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
59                      env, NULL, &si, &pi))
60   {
61     msvcrt_set_errno(GetLastError());
62     return -1;
63   }
64
65   switch(flags)
66   {
67   case MSVCRT__P_WAIT:
68     WaitForSingleObject(pi.hProcess, INFINITE);
69     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
70     CloseHandle(pi.hProcess);
71     CloseHandle(pi.hThread);
72     return (int)pi.dwProcessId;
73   case MSVCRT__P_DETACH:
74     CloseHandle(pi.hProcess);
75     pi.hProcess = 0;
76     /* fall through */
77   case MSVCRT__P_NOWAIT:
78   case MSVCRT__P_NOWAITO:
79     CloseHandle(pi.hThread);
80     return (int)pi.hProcess;
81   case  MSVCRT__P_OVERLAY:
82     MSVCRT__exit(0);
83   }
84   return -1; /* can't reach here */
85 }
86
87 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
88  * extra '\0' to terminate it
89  */
90 static char* msvcrt_argvtos(const char* const* arg, char delim)
91 {
92   const char* const* a;
93   long size;
94   char* p;
95   char* ret;
96
97   if (!arg && !delim)
98   {
99       /* Return NULL for an empty environment list */
100       return NULL;
101   }
102
103   /* get length */
104   a = arg;
105   size = 0;
106   while (*a)
107   {
108     size += strlen(*a) + 1;
109     a++;
110   }
111
112   ret = (char*)MSVCRT_malloc(size + 1);
113   if (!ret)
114     return NULL;
115
116   /* fill string */
117   a = arg;
118   p = ret;
119   while (*a)
120   {
121     int len = strlen(*a);
122     memcpy(p,*a,len);
123     p += len;
124     *p++ = delim;
125     a++;
126   }
127   if (delim && p > ret) p[-1] = 0;
128   else *p = 0;
129   return ret;
130 }
131
132 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
133  * extra '\0' to terminate it
134  */
135 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
136 {
137   va_list alist2;
138   long size;
139   const char *arg;
140   char* p;
141   char *ret;
142
143 #ifdef HAVE_VA_COPY
144   va_copy(alist2,alist);
145 #else
146 # ifdef HAVE___VA_COPY
147   __va_copy(alist2,alist);
148 # else
149   alist2 = alist;
150 # endif
151 #endif
152
153   if (!arg0 && !delim)
154   {
155       /* Return NULL for an empty environment list */
156       return NULL;
157   }
158
159   /* get length */
160   arg = arg0;
161   size = 0;
162   do {
163       size += strlen(arg) + 1;
164       arg = va_arg(alist, char*);
165   } while (arg != NULL);
166
167   ret = (char*)MSVCRT_malloc(size + 1);
168   if (!ret)
169     return NULL;
170
171   /* fill string */
172   arg = arg0;
173   p = ret;
174   do {
175       int len = strlen(arg);
176       memcpy(p,arg,len);
177       p += len;
178       *p++ = delim;
179       arg = va_arg(alist2, char*);
180   } while (arg != NULL);
181   if (delim && p > ret) p[-1] = 0;
182   else *p = 0;
183   return ret;
184 }
185
186 /*********************************************************************
187  *              _cwait (MSVCRT.@)
188  */
189 int _cwait(int *status, int pid, int action)
190 {
191   HANDLE hPid = (HANDLE)pid;
192   int doserrno;
193
194   action = action; /* Remove warning */
195
196   if (!WaitForSingleObject(hPid, INFINITE))
197   {
198     if (status)
199     {
200       DWORD stat;
201       GetExitCodeProcess(hPid, &stat);
202       *status = (int)stat;
203     }
204     return (int)pid;
205   }
206   doserrno = GetLastError();
207
208   if (doserrno == ERROR_INVALID_HANDLE)
209   {
210     *MSVCRT__errno() =  MSVCRT_ECHILD;
211     *MSVCRT___doserrno() = doserrno;
212   }
213   else
214     msvcrt_set_errno(doserrno);
215
216   return status ? *status = -1 : -1;
217 }
218
219 /*********************************************************************
220  *              _execl (MSVCRT.@)
221  *
222  * Like on Windows, this function does not handle arguments with spaces
223  * or double-quotes.
224  */
225 int _execl(const char* name, const char* arg0, ...)
226 {
227   va_list ap;
228   char * args;
229   int ret;
230
231   va_start(ap, arg0);
232   args = msvcrt_valisttos(arg0, ap, ' ');
233   va_end(ap);
234
235   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
236   MSVCRT_free(args);
237
238   return ret;
239 }
240
241 /*********************************************************************
242  *              _execle (MSVCRT.@)
243  */
244 int _execle(const char* name, const char* arg0, ...)
245 {
246     FIXME("stub\n");
247     return -1;
248 }
249
250 /*********************************************************************
251  *              _execlp (MSVCRT.@)
252  *
253  * Like on Windows, this function does not handle arguments with spaces
254  * or double-quotes.
255  */
256 int _execlp(const char* name, const char* arg0, ...)
257 {
258   va_list ap;
259   char * args;
260   int ret;
261   char fullname[MAX_PATH];
262
263   _searchenv(name, "PATH", fullname);
264
265   va_start(ap, arg0);
266   args = msvcrt_valisttos(arg0, ap, ' ');
267   va_end(ap);
268
269   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
270   MSVCRT_free(args);
271
272   return ret;
273 }
274
275 /*********************************************************************
276  *              _execlpe (MSVCRT.@)
277  */
278 int _execlpe(const char* name, const char* arg0, ...)
279 {
280     FIXME("stub\n");
281     return -1;
282 }
283
284 /*********************************************************************
285  *              _execv (MSVCRT.@)
286  *
287  * Like on Windows, this function does not handle arguments with spaces
288  * or double-quotes.
289  */
290 int _execv(const char* name, char* const* argv)
291 {
292   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
293 }
294
295 /*********************************************************************
296  *              _execve (MSVCRT.@)
297  *
298  * Like on Windows, this function does not handle arguments with spaces
299  * or double-quotes.
300  */
301 int _execve(const char* name, char* const* argv, const char* const* envv)
302 {
303   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
304 }
305
306 /*********************************************************************
307  *              _execvpe (MSVCRT.@)
308  *
309  * Like on Windows, this function does not handle arguments with spaces
310  * or double-quotes.
311  */
312 int _execvpe(const char* name, char* const* argv, const char* const* envv)
313 {
314   char fullname[MAX_PATH];
315
316   _searchenv(name, "PATH", fullname);
317   return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
318                   (const char* const*) argv, envv);
319 }
320
321 /*********************************************************************
322  *              _execvp (MSVCRT.@)
323  *
324  * Like on Windows, this function does not handle arguments with spaces
325  * or double-quotes.
326  */
327 int _execvp(const char* name, char* const* argv)
328 {
329   return _execvpe(name, argv, NULL);
330 }
331
332 /*********************************************************************
333  *              _spawnl (MSVCRT.@)
334  *
335  * Like on Windows, this function does not handle arguments with spaces
336  * or double-quotes.
337  */
338 int _spawnl(int flags, const char* name, const char* arg0, ...)
339 {
340   va_list ap;
341   char * args;
342   int ret;
343
344   va_start(ap, arg0);
345   args = msvcrt_valisttos(arg0, ap, ' ');
346   va_end(ap);
347
348   ret = msvcrt_spawn(flags, name, args, NULL);
349   MSVCRT_free(args);
350
351   return ret;
352 }
353
354 /*********************************************************************
355  *              _spawnle (MSVCRT.@)
356  */
357 int _spawnle(int flags, const char* name, const char* arg0, ...)
358 {
359     FIXME("stub\n");
360     return -1;
361 }
362
363
364 /*********************************************************************
365  *              _spawnlp (MSVCRT.@)
366  *
367  * Like on Windows, this function does not handle arguments with spaces
368  * or double-quotes.
369  */
370 int _spawnlp(int flags, const char* name, const char* arg0, ...)
371 {
372   va_list ap;
373   char * args;
374   int ret;
375   char fullname[MAX_PATH];
376
377   _searchenv(name, "PATH", fullname);
378
379   va_start(ap, arg0);
380   args = msvcrt_valisttos(arg0, ap, ' ');
381   va_end(ap);
382
383   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
384   MSVCRT_free(args);
385
386   return ret;
387 }
388
389 /*********************************************************************
390  *              _spawnlpe (MSVCRT.@)
391  */
392 int _spawnlpe(int flags, const char* name, const char* arg0, ...)
393 {
394     FIXME("stub\n");
395     return -1;
396 }
397
398 /*********************************************************************
399  *              _spawnve (MSVCRT.@)
400  *
401  * Like on Windows, this function does not handle arguments with spaces
402  * or double-quotes.
403  */
404 int _spawnve(int flags, const char* name, const char* const* argv,
405                             const char* const* envv)
406 {
407   char * args = msvcrt_argvtos(argv,' ');
408   char * envs = msvcrt_argvtos(envv,0);
409   const char *fullname = name;
410   int ret = -1;
411
412   FIXME(":not translating name %s to locate program\n",fullname);
413   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
414
415   if (args)
416   {
417     ret = msvcrt_spawn(flags, fullname, args, envs);
418     MSVCRT_free(args);
419   }
420   if (envs)
421     MSVCRT_free(envs);
422
423   return ret;
424 }
425
426 /*********************************************************************
427  *              _spawnv (MSVCRT.@)
428  *
429  * Like on Windows, this function does not handle arguments with spaces
430  * or double-quotes.
431  */
432 int _spawnv(int flags, const char* name, const char* const* argv)
433 {
434   return _spawnve(flags, name, argv, NULL);
435 }
436
437 /*********************************************************************
438  *              _spawnvpe (MSVCRT.@)
439  *
440  * Like on Windows, this function does not handle arguments with spaces
441  * or double-quotes.
442  */
443 int _spawnvpe(int flags, const char* name, const char* const* argv,
444                             const char* const* envv)
445 {
446   char fullname[MAX_PATH];
447   _searchenv(name, "PATH", fullname);
448   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
449 }
450
451 /*********************************************************************
452  *              _spawnvp (MSVCRT.@)
453  *
454  * Like on Windows, this function does not handle arguments with spaces
455  * or double-quotes.
456  */
457 int _spawnvp(int flags, const char* name, const char* const* argv)
458 {
459   return _spawnvpe(flags, name, argv, NULL);
460 }
461
462 /*********************************************************************
463  *              _popen (MSVCRT.@)
464  */
465 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
466 {
467   FIXME("(command=%s, mode=%s): stub\n", debugstr_a(command), debugstr_a(mode));
468   return NULL;
469 }
470
471 /*********************************************************************
472  *              _wpopen (MSVCRT.@)
473  */
474 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
475 {
476   FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
477   return NULL;
478 }
479
480 /*********************************************************************
481  *              _pclose (MSVCRT.@)
482  */
483 int MSVCRT__pclose(MSVCRT_FILE* file)
484 {
485   FIXME("(file=%p): stub\n", file);
486   return 0;
487 }
488
489 /*********************************************************************
490  *              system (MSVCRT.@)
491  */
492 int MSVCRT_system(const char* cmd)
493 {
494     char* cmdcopy;
495     int res;
496
497     /* Make a writable copy for CreateProcess */
498     cmdcopy=_strdup(cmd);
499     /* FIXME: should probably launch cmd interpreter in COMSPEC */
500     res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
501     MSVCRT_free(cmdcopy);
502     return res;
503 }
504
505 /*********************************************************************
506  *              _loaddll (MSVCRT.@)
507  */
508 int _loaddll(const char* dllname)
509 {
510   return (int)LoadLibraryA(dllname);
511 }
512
513 /*********************************************************************
514  *              _unloaddll (MSVCRT.@)
515  */
516 int _unloaddll(int dll)
517 {
518   if (FreeLibrary((HMODULE)dll))
519     return 0;
520   else
521   {
522     int err = GetLastError();
523     msvcrt_set_errno(err);
524     return err;
525   }
526 }
527
528 /*********************************************************************
529  *              _getdllprocaddr (MSVCRT.@)
530  */
531 void *_getdllprocaddr(int dll, const char *name, int ordinal)
532 {
533     if (name)
534     {
535         if (ordinal != -1) return NULL;
536         return GetProcAddress( (HMODULE)dll, name );
537     }
538     if (HIWORD(ordinal)) return NULL;
539     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
540 }