push b5232b2081a0e20e4bf07d6ded424d0101e4a589
[wine/hacks.git] / dlls / msvcrt / process.c
blobc6c3a7e460981fc5a05b26fad362aabd6adf2ec1
1 /*
2 * msvcrt.dll spawn/exec functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
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.
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.
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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
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
28 #include "config.h"
30 #include <stdarg.h>
32 #include "msvcrt.h"
33 #include "wine/debug.h"
35 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
37 /* INTERNAL: Spawn a child process */
38 static MSVCRT_intptr_t msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
40 STARTUPINFOA si;
41 PROCESS_INFORMATION pi;
43 if ((unsigned)flags > MSVCRT__P_DETACH)
45 *MSVCRT__errno() = MSVCRT_EINVAL;
46 return -1;
49 memset(&si, 0, sizeof(si));
50 si.cb = sizeof(si);
51 msvcrt_create_io_inherit_block(&si);
52 if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
53 flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
54 env, NULL, &si, &pi))
56 msvcrt_set_errno(GetLastError());
57 MSVCRT_free(si.lpReserved2);
58 return -1;
61 MSVCRT_free(si.lpReserved2);
62 switch(flags)
64 case MSVCRT__P_WAIT:
65 WaitForSingleObject(pi.hProcess, INFINITE);
66 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
67 CloseHandle(pi.hProcess);
68 CloseHandle(pi.hThread);
69 return pi.dwProcessId;
70 case MSVCRT__P_DETACH:
71 CloseHandle(pi.hProcess);
72 pi.hProcess = 0;
73 /* fall through */
74 case MSVCRT__P_NOWAIT:
75 case MSVCRT__P_NOWAITO:
76 CloseHandle(pi.hThread);
77 return (MSVCRT_intptr_t)pi.hProcess;
78 case MSVCRT__P_OVERLAY:
79 MSVCRT__exit(0);
81 return -1; /* can't reach here */
84 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
85 * extra '\0' to terminate it
87 static char* msvcrt_argvtos(const char* const* arg, char delim)
89 const char* const* a;
90 long size;
91 char* p;
92 char* ret;
94 if (!arg && !delim)
96 /* Return NULL for an empty environment list */
97 return NULL;
100 /* get length */
101 a = arg;
102 size = 0;
103 while (*a)
105 size += strlen(*a) + 1;
106 a++;
109 ret = MSVCRT_malloc(size + 1);
110 if (!ret)
111 return NULL;
113 /* fill string */
114 a = arg;
115 p = ret;
116 while (*a)
118 int len = strlen(*a);
119 memcpy(p,*a,len);
120 p += len;
121 *p++ = delim;
122 a++;
124 if (delim && p > ret) p[-1] = 0;
125 else *p = 0;
126 return ret;
129 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
130 * extra '\0' to terminate it
132 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
134 va_list alist2;
135 long size;
136 const char *arg;
137 char* p;
138 char *ret;
140 #ifdef HAVE_VA_COPY
141 va_copy(alist2,alist);
142 #else
143 # ifdef HAVE___VA_COPY
144 __va_copy(alist2,alist);
145 # else
146 alist2 = alist;
147 # endif
148 #endif
150 if (!arg0)
152 /* Return NULL for an empty environment list */
153 return NULL;
156 /* get length */
157 arg = arg0;
158 size = 0;
159 do {
160 size += strlen(arg) + 1;
161 arg = va_arg(alist, char*);
162 } while (arg != NULL);
164 ret = MSVCRT_malloc(size + 1);
165 if (!ret)
166 return NULL;
168 /* fill string */
169 arg = arg0;
170 p = ret;
171 do {
172 int len = strlen(arg);
173 memcpy(p,arg,len);
174 p += len;
175 *p++ = delim;
176 arg = va_arg(alist2, char*);
177 } while (arg != NULL);
178 if (delim && p > ret) p[-1] = 0;
179 else *p = 0;
180 return ret;
183 /*********************************************************************
184 * _cwait (MSVCRT.@)
186 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
188 HANDLE hPid = (HANDLE)pid;
189 int doserrno;
191 action = action; /* Remove warning */
193 if (!WaitForSingleObject(hPid, INFINITE))
195 if (status)
197 DWORD stat;
198 GetExitCodeProcess(hPid, &stat);
199 *status = (int)stat;
201 return pid;
203 doserrno = GetLastError();
205 if (doserrno == ERROR_INVALID_HANDLE)
207 *MSVCRT__errno() = MSVCRT_ECHILD;
208 *MSVCRT___doserrno() = doserrno;
210 else
211 msvcrt_set_errno(doserrno);
213 return status ? *status = -1 : -1;
216 /*********************************************************************
217 * _execl (MSVCRT.@)
219 * Like on Windows, this function does not handle arguments with spaces
220 * or double-quotes.
222 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
224 va_list ap;
225 char * args;
226 MSVCRT_intptr_t ret;
228 va_start(ap, arg0);
229 args = msvcrt_valisttos(arg0, ap, ' ');
230 va_end(ap);
232 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
233 MSVCRT_free(args);
235 return ret;
238 /*********************************************************************
239 * _execle (MSVCRT.@)
241 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
243 FIXME("stub\n");
244 return -1;
247 /*********************************************************************
248 * _execlp (MSVCRT.@)
250 * Like on Windows, this function does not handle arguments with spaces
251 * or double-quotes.
253 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
255 va_list ap;
256 char * args;
257 MSVCRT_intptr_t ret;
258 char fullname[MAX_PATH];
260 _searchenv(name, "PATH", fullname);
262 va_start(ap, arg0);
263 args = msvcrt_valisttos(arg0, ap, ' ');
264 va_end(ap);
266 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
267 MSVCRT_free(args);
269 return ret;
272 /*********************************************************************
273 * _execlpe (MSVCRT.@)
275 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
277 FIXME("stub\n");
278 return -1;
281 /*********************************************************************
282 * _execv (MSVCRT.@)
284 * Like on Windows, this function does not handle arguments with spaces
285 * or double-quotes.
287 MSVCRT_intptr_t CDECL _execv(const char* name, char* const* argv)
289 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
292 /*********************************************************************
293 * _execve (MSVCRT.@)
295 * Like on Windows, this function does not handle arguments with spaces
296 * or double-quotes.
298 MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, char* const* argv, const char* const* envv)
300 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
303 /*********************************************************************
304 * _execvpe (MSVCRT.@)
306 * Like on Windows, this function does not handle arguments with spaces
307 * or double-quotes.
309 MSVCRT_intptr_t CDECL _execvpe(const char* name, char* const* argv, const char* const* envv)
311 char fullname[MAX_PATH];
313 _searchenv(name, "PATH", fullname);
314 return _spawnve(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name,
315 (const char* const*) argv, envv);
318 /*********************************************************************
319 * _execvp (MSVCRT.@)
321 * Like on Windows, this function does not handle arguments with spaces
322 * or double-quotes.
324 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
326 return _execvpe(name, argv, NULL);
329 /*********************************************************************
330 * _spawnl (MSVCRT.@)
332 * Like on Windows, this function does not handle arguments with spaces
333 * or double-quotes.
335 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
337 va_list ap;
338 char * args;
339 MSVCRT_intptr_t ret;
341 va_start(ap, arg0);
342 args = msvcrt_valisttos(arg0, ap, ' ');
343 va_end(ap);
345 ret = msvcrt_spawn(flags, name, args, NULL);
346 MSVCRT_free(args);
348 return ret;
351 /*********************************************************************
352 * _spawnle (MSVCRT.@)
354 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
356 va_list ap;
357 char *args, *envs = NULL;
358 const char * const *envp;
359 MSVCRT_intptr_t ret;
361 va_start(ap, arg0);
362 args = msvcrt_valisttos(arg0, ap, ' ');
363 va_end(ap);
365 va_start(ap, arg0);
366 while (va_arg( ap, char * ) != NULL) /*nothing*/;
367 envp = va_arg( ap, const char * const * );
368 if (envp) envs = msvcrt_argvtos(envp, 0);
369 va_end(ap);
371 ret = msvcrt_spawn(flags, name, args, envs);
373 MSVCRT_free(args);
374 MSVCRT_free(envs);
375 return ret;
379 /*********************************************************************
380 * _spawnlp (MSVCRT.@)
382 * Like on Windows, this function does not handle arguments with spaces
383 * or double-quotes.
385 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
387 va_list ap;
388 char * args;
389 MSVCRT_intptr_t ret;
390 char fullname[MAX_PATH];
392 _searchenv(name, "PATH", fullname);
394 va_start(ap, arg0);
395 args = msvcrt_valisttos(arg0, ap, ' ');
396 va_end(ap);
398 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
399 MSVCRT_free(args);
401 return ret;
404 /*********************************************************************
405 * _spawnlpe (MSVCRT.@)
407 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
409 va_list ap;
410 char *args, *envs = NULL;
411 const char * const *envp;
412 MSVCRT_intptr_t ret;
413 char fullname[MAX_PATH];
415 _searchenv(name, "PATH", fullname);
417 va_start(ap, arg0);
418 args = msvcrt_valisttos(arg0, ap, ' ');
419 va_end(ap);
421 va_start(ap, arg0);
422 while (va_arg( ap, char * ) != NULL) /*nothing*/;
423 envp = va_arg( ap, const char * const * );
424 if (envp) envs = msvcrt_argvtos(envp, 0);
425 va_end(ap);
427 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
429 MSVCRT_free(args);
430 MSVCRT_free(envs);
431 return ret;
434 /*********************************************************************
435 * _spawnve (MSVCRT.@)
437 * Like on Windows, this function does not handle arguments with spaces
438 * or double-quotes.
440 MSVCRT_intptr_t CDECL _spawnve(int flags, const char* name, const char* const* argv,
441 const char* const* envv)
443 char * args = msvcrt_argvtos(argv,' ');
444 char * envs = msvcrt_argvtos(envv,0);
445 char fullname[MAX_PATH];
446 const char *p;
447 int len;
448 MSVCRT_intptr_t ret = -1;
450 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name),debugstr_a(args),
451 envs?"Custom":"Null");
453 /* no check for NULL name.
454 native doesn't do it */
456 p = memchr(name, '\0', MAX_PATH);
457 if( !p )
458 p = name + MAX_PATH - 1;
459 len = p - name;
461 /* extra-long names are silently truncated. */
462 memcpy(fullname, name, len);
464 for( p--; p >= name; p-- )
466 if( *p == '\\' || *p == '/' || *p == ':' || *p == '.' )
467 break;
470 /* if no extension is given, assume .exe */
471 if( (p < name || *p != '.') && len <= MAX_PATH - 5 )
473 FIXME("only trying .exe when no extension given\n");
474 memcpy(fullname+len, ".exe", 4);
475 len += 4;
478 fullname[len] = '\0';
480 if (args)
482 ret = msvcrt_spawn(flags, fullname, args, envs);
483 MSVCRT_free(args);
485 MSVCRT_free(envs);
487 return ret;
490 /*********************************************************************
491 * _spawnv (MSVCRT.@)
493 * Like on Windows, this function does not handle arguments with spaces
494 * or double-quotes.
496 MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
498 return _spawnve(flags, name, argv, NULL);
501 /*********************************************************************
502 * _spawnvpe (MSVCRT.@)
504 * Like on Windows, this function does not handle arguments with spaces
505 * or double-quotes.
507 MSVCRT_intptr_t CDECL _spawnvpe(int flags, const char* name, const char* const* argv,
508 const char* const* envv)
510 char fullname[MAX_PATH];
511 _searchenv(name, "PATH", fullname);
512 return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
515 /*********************************************************************
516 * _spawnvp (MSVCRT.@)
518 * Like on Windows, this function does not handle arguments with spaces
519 * or double-quotes.
521 MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
523 return _spawnvpe(flags, name, argv, NULL);
526 /*********************************************************************
527 * _popen (MSVCRT.@)
528 * FIXME: convert to _wpopen and call that from here instead? But it
529 * would have to convert the command back to ANSI to call msvcrt_spawn,
530 * less than ideal.
532 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
534 static const char wcmd[] = "cmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
535 MSVCRT_FILE *ret;
536 BOOL readPipe = TRUE;
537 int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
538 const char *p;
539 char *cmdcopy;
540 DWORD comSpecLen;
542 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
544 if (!command || !mode)
545 return NULL;
547 textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
548 for (p = mode; *p; p++)
550 switch (*p)
552 case 'W':
553 case 'w':
554 readPipe = FALSE;
555 break;
556 case 'B':
557 case 'b':
558 textmode |= MSVCRT__O_BINARY;
559 textmode &= ~MSVCRT__O_TEXT;
560 break;
561 case 'T':
562 case 't':
563 textmode |= MSVCRT__O_TEXT;
564 textmode &= ~MSVCRT__O_BINARY;
565 break;
568 if (MSVCRT__pipe(fds, 0, textmode) == -1)
569 return NULL;
571 fdToDup = readPipe ? 1 : 0;
572 fdToOpen = readPipe ? 0 : 1;
574 if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
575 goto error;
576 if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
577 goto error;
578 if (readPipe)
580 if ((fdStdErr = MSVCRT__dup(MSVCRT_STDERR_FILENO)) == -1)
581 goto error;
582 if (MSVCRT__dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
583 goto error;
586 MSVCRT__close(fds[fdToDup]);
588 comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
589 if (!comSpecLen)
590 comSpecLen = strlen(wcmd) + 1;
591 cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
592 + strlen(command));
593 if (!GetEnvironmentVariableA(comSpec, cmdcopy, comSpecLen))
594 strcpy(cmdcopy, wcmd);
595 strcat(cmdcopy, cmdFlag);
596 strcat(cmdcopy, command);
597 if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, cmdcopy, NULL) == -1)
599 MSVCRT__close(fds[fdToOpen]);
600 ret = NULL;
602 else
604 ret = MSVCRT__fdopen(fds[fdToOpen], mode);
605 if (!ret)
606 MSVCRT__close(fds[fdToOpen]);
608 HeapFree(GetProcessHeap(), 0, cmdcopy);
609 MSVCRT__dup2(fdStdHandle, fdToDup);
610 MSVCRT__close(fdStdHandle);
611 if (readPipe)
613 MSVCRT__dup2(fdStdErr, MSVCRT_STDERR_FILENO);
614 MSVCRT__close(fdStdErr);
616 return ret;
618 error:
619 if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
620 if (fdStdErr != -1) MSVCRT__close(fdStdErr);
621 MSVCRT__close(fds[0]);
622 MSVCRT__close(fds[1]);
623 return NULL;
626 /*********************************************************************
627 * _wpopen (MSVCRT.@)
629 MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
631 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
632 return NULL;
635 /*********************************************************************
636 * _pclose (MSVCRT.@)
638 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
640 return MSVCRT_fclose(file);
643 /*********************************************************************
644 * system (MSVCRT.@)
646 int CDECL MSVCRT_system(const char* cmd)
648 char* cmdcopy;
649 int res;
651 /* Make a writable copy for CreateProcess */
652 cmdcopy=_strdup(cmd);
653 /* FIXME: should probably launch cmd interpreter in COMSPEC */
654 res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
655 MSVCRT_free(cmdcopy);
656 return res;
659 /*********************************************************************
660 * _loaddll (MSVCRT.@)
662 MSVCRT_intptr_t CDECL _loaddll(const char* dllname)
664 return (MSVCRT_intptr_t)LoadLibraryA(dllname);
667 /*********************************************************************
668 * _unloaddll (MSVCRT.@)
670 int CDECL _unloaddll(MSVCRT_intptr_t dll)
672 if (FreeLibrary((HMODULE)dll))
673 return 0;
674 else
676 int err = GetLastError();
677 msvcrt_set_errno(err);
678 return err;
682 /*********************************************************************
683 * _getdllprocaddr (MSVCRT.@)
685 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
687 if (name)
689 if (ordinal != -1) return NULL;
690 return GetProcAddress( (HMODULE)dll, name );
692 if (HIWORD(ordinal)) return NULL;
693 return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );