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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
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
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)
41 PROCESS_INFORMATION pi;
43 if ((unsigned)flags > MSVCRT__P_DETACH)
45 *MSVCRT__errno() = MSVCRT_EINVAL;
49 memset(&si, 0, 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,
56 msvcrt_set_errno(GetLastError());
57 MSVCRT_free(si.lpReserved2);
61 MSVCRT_free(si.lpReserved2);
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);
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:
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)
96 /* Return NULL for an empty environment list */
105 size += strlen(*a) + 1;
109 ret = (char*)MSVCRT_malloc(size + 1);
118 int len = strlen(*a);
124 if (delim && p > ret) p[-1] = 0;
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)
141 va_copy(alist2,alist);
143 # ifdef HAVE___VA_COPY
144 __va_copy(alist2,alist);
152 /* Return NULL for an empty environment list */
160 size += strlen(arg) + 1;
161 arg = va_arg(alist, char*);
162 } while (arg != NULL);
164 ret = (char*)MSVCRT_malloc(size + 1);
172 int len = strlen(arg);
176 arg = va_arg(alist2, char*);
177 } while (arg != NULL);
178 if (delim && p > ret) p[-1] = 0;
183 /*********************************************************************
186 MSVCRT_intptr_t _cwait(int *status, MSVCRT_intptr_t pid, int action)
188 HANDLE hPid = (HANDLE)pid;
191 action = action; /* Remove warning */
193 if (!WaitForSingleObject(hPid, INFINITE))
198 GetExitCodeProcess(hPid, &stat);
203 doserrno = GetLastError();
205 if (doserrno == ERROR_INVALID_HANDLE)
207 *MSVCRT__errno() = MSVCRT_ECHILD;
208 *MSVCRT___doserrno() = doserrno;
211 msvcrt_set_errno(doserrno);
213 return status ? *status = -1 : -1;
216 /*********************************************************************
219 * Like on Windows, this function does not handle arguments with spaces
222 MSVCRT_intptr_t _execl(const char* name, const char* arg0, ...)
229 args = msvcrt_valisttos(arg0, ap, ' ');
232 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL);
238 /*********************************************************************
241 MSVCRT_intptr_t _execle(const char* name, const char* arg0, ...)
247 /*********************************************************************
250 * Like on Windows, this function does not handle arguments with spaces
253 MSVCRT_intptr_t _execlp(const char* name, const char* arg0, ...)
258 char fullname[MAX_PATH];
260 _searchenv(name, "PATH", fullname);
263 args = msvcrt_valisttos(arg0, ap, ' ');
266 ret = msvcrt_spawn(MSVCRT__P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
272 /*********************************************************************
273 * _execlpe (MSVCRT.@)
275 MSVCRT_intptr_t _execlpe(const char* name, const char* arg0, ...)
281 /*********************************************************************
284 * Like on Windows, this function does not handle arguments with spaces
287 MSVCRT_intptr_t _execv(const char* name, char* const* argv)
289 return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
292 /*********************************************************************
295 * Like on Windows, this function does not handle arguments with spaces
298 MSVCRT_intptr_t _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
309 MSVCRT_intptr_t _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 /*********************************************************************
321 * Like on Windows, this function does not handle arguments with spaces
324 MSVCRT_intptr_t _execvp(const char* name, char* const* argv)
326 return _execvpe(name, argv, NULL);
329 /*********************************************************************
332 * Like on Windows, this function does not handle arguments with spaces
335 MSVCRT_intptr_t _spawnl(int flags, const char* name, const char* arg0, ...)
342 args = msvcrt_valisttos(arg0, ap, ' ');
345 ret = msvcrt_spawn(flags, name, args, NULL);
351 /*********************************************************************
352 * _spawnle (MSVCRT.@)
354 MSVCRT_intptr_t _spawnle(int flags, const char* name, const char* arg0, ...)
357 char *args, *envs = NULL;
358 const char * const *envp;
362 args = msvcrt_valisttos(arg0, ap, ' ');
366 while (va_arg( ap, char * ) != NULL) /*nothing*/;
367 envp = va_arg( ap, const char * const * );
368 if (envp) envs = msvcrt_argvtos(envp, 0);
371 ret = msvcrt_spawn(flags, name, args, envs);
374 if (envs) MSVCRT_free(envs);
379 /*********************************************************************
380 * _spawnlp (MSVCRT.@)
382 * Like on Windows, this function does not handle arguments with spaces
385 MSVCRT_intptr_t _spawnlp(int flags, const char* name, const char* arg0, ...)
390 char fullname[MAX_PATH];
392 _searchenv(name, "PATH", fullname);
395 args = msvcrt_valisttos(arg0, ap, ' ');
398 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
404 /*********************************************************************
405 * _spawnlpe (MSVCRT.@)
407 MSVCRT_intptr_t _spawnlpe(int flags, const char* name, const char* arg0, ...)
410 char *args, *envs = NULL;
411 const char * const *envp;
413 char fullname[MAX_PATH];
415 _searchenv(name, "PATH", fullname);
418 args = msvcrt_valisttos(arg0, ap, ' ');
422 while (va_arg( ap, char * ) != NULL) /*nothing*/;
423 envp = va_arg( ap, const char * const * );
424 if (envp) envs = msvcrt_argvtos(envp, 0);
427 ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, envs);
430 if (envs) MSVCRT_free(envs);
434 /*********************************************************************
435 * _spawnve (MSVCRT.@)
437 * Like on Windows, this function does not handle arguments with spaces
440 MSVCRT_intptr_t _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 const char *fullname = name;
446 MSVCRT_intptr_t ret = -1;
448 FIXME(":not translating name %s to locate program\n",fullname);
449 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name),debugstr_a(args),
450 envs?"Custom":"Null");
454 ret = msvcrt_spawn(flags, fullname, args, envs);
463 /*********************************************************************
466 * Like on Windows, this function does not handle arguments with spaces
469 MSVCRT_intptr_t _spawnv(int flags, const char* name, const char* const* argv)
471 return _spawnve(flags, name, argv, NULL);
474 /*********************************************************************
475 * _spawnvpe (MSVCRT.@)
477 * Like on Windows, this function does not handle arguments with spaces
480 MSVCRT_intptr_t _spawnvpe(int flags, const char* name, const char* const* argv,
481 const char* const* envv)
483 char fullname[MAX_PATH];
484 _searchenv(name, "PATH", fullname);
485 return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
488 /*********************************************************************
489 * _spawnvp (MSVCRT.@)
491 * Like on Windows, this function does not handle arguments with spaces
494 MSVCRT_intptr_t _spawnvp(int flags, const char* name, const char* const* argv)
496 return _spawnvpe(flags, name, argv, NULL);
499 /*********************************************************************
501 * FIXME: convert to _wpopen and call that from here instead? But it
502 * would have to convert the command back to ANSI to call msvcrt_spawn,
505 MSVCRT_FILE* MSVCRT__popen(const char* command, const char* mode)
507 static const char wcmd[] = "wcmd", cmdFlag[] = " /C ", comSpec[] = "COMSPEC";
509 BOOL readPipe = TRUE;
510 int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
515 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
517 if (!command || !mode)
520 textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
521 for (p = mode; *p; p++)
531 textmode |= MSVCRT__O_BINARY;
532 textmode &= ~MSVCRT__O_TEXT;
536 textmode |= MSVCRT__O_TEXT;
537 textmode &= ~MSVCRT__O_BINARY;
541 if (_pipe(fds, 0, textmode) == -1)
544 fdToDup = readPipe ? 1 : 0;
545 fdToOpen = readPipe ? 0 : 1;
547 if ((fdStdHandle = _dup(fdToDup)) == -1)
549 if (_dup2(fds[fdToDup], fdToDup) != 0)
553 if ((fdStdErr = _dup(MSVCRT_STDERR_FILENO)) == -1)
555 if (_dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
559 _close(fds[fdToDup]);
561 comSpecLen = GetEnvironmentVariableA(comSpec, NULL, 0);
563 comSpecLen = strlen(wcmd) + 1;
564 cmdcopy = HeapAlloc(GetProcessHeap(), 0, comSpecLen + strlen(cmdFlag)
566 if (!GetEnvironmentVariableA(comSpec, cmdcopy, comSpecLen))
567 strcpy(cmdcopy, wcmd);
568 strcat(cmdcopy, cmdFlag);
569 strcat(cmdcopy, command);
570 if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, cmdcopy, NULL) == -1)
572 _close(fds[fdToOpen]);
577 ret = MSVCRT__fdopen(fds[fdToOpen], mode);
579 _close(fds[fdToOpen]);
581 HeapFree(GetProcessHeap(), 0, cmdcopy);
582 _dup2(fdStdHandle, fdToDup);
586 _dup2(fdStdErr, MSVCRT_STDERR_FILENO);
592 if (fdStdHandle != -1) _close(fdStdHandle);
593 if (fdStdErr != -1) _close(fdStdErr);
599 /*********************************************************************
602 MSVCRT_FILE* MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
604 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
608 /*********************************************************************
611 int MSVCRT__pclose(MSVCRT_FILE* file)
613 return MSVCRT_fclose(file);
616 /*********************************************************************
619 int MSVCRT_system(const char* cmd)
624 /* Make a writable copy for CreateProcess */
625 cmdcopy=_strdup(cmd);
626 /* FIXME: should probably launch cmd interpreter in COMSPEC */
627 res=msvcrt_spawn(MSVCRT__P_WAIT, NULL, cmdcopy, NULL);
628 MSVCRT_free(cmdcopy);
632 /*********************************************************************
633 * _loaddll (MSVCRT.@)
635 MSVCRT_intptr_t _loaddll(const char* dllname)
637 return (MSVCRT_intptr_t)LoadLibraryA(dllname);
640 /*********************************************************************
641 * _unloaddll (MSVCRT.@)
643 int _unloaddll(MSVCRT_intptr_t dll)
645 if (FreeLibrary((HMODULE)dll))
649 int err = GetLastError();
650 msvcrt_set_errno(err);
655 /*********************************************************************
656 * _getdllprocaddr (MSVCRT.@)
658 void *_getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
662 if (ordinal != -1) return NULL;
663 return GetProcAddress( (HMODULE)dll, name );
665 if (HIWORD(ordinal)) return NULL;
666 return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );