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 int msvcrt_spawn(int flags
, const char* exe
, char* cmdline
, char* env
)
41 PROCESS_INFORMATION pi
;
43 if (sizeof(HANDLE
) != sizeof(int))
44 WARN("This call is unsuitable for your architecture\n");
46 if ((unsigned)flags
> MSVCRT__P_DETACH
)
48 *MSVCRT__errno() = MSVCRT_EINVAL
;
52 memset(&si
, 0, sizeof(si
));
54 msvcrt_create_io_inherit_block(&si
);
55 if (!CreateProcessA(exe
, cmdline
, NULL
, NULL
, TRUE
,
56 flags
== MSVCRT__P_DETACH
? DETACHED_PROCESS
: 0,
59 msvcrt_set_errno(GetLastError());
60 MSVCRT_free(si
.lpReserved2
);
64 MSVCRT_free(si
.lpReserved2
);
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
);
77 case MSVCRT__P_NOWAIT
:
78 case MSVCRT__P_NOWAITO
:
79 CloseHandle(pi
.hThread
);
80 return (int)pi
.hProcess
;
81 case MSVCRT__P_OVERLAY
:
84 return -1; /* can't reach here */
87 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
88 * extra '\0' to terminate it
90 static char* msvcrt_argvtos(const char* const* arg
, char delim
)
99 /* Return NULL for an empty environment list */
108 size
+= strlen(*a
) + 1;
112 ret
= (char*)MSVCRT_malloc(size
+ 1);
121 int len
= strlen(*a
);
127 if (delim
&& p
> ret
) p
[-1] = 0;
132 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
133 * extra '\0' to terminate it
135 static char* msvcrt_valisttos(const char* arg0
, va_list alist
, char delim
)
144 va_copy(alist2
,alist
);
146 # ifdef HAVE___VA_COPY
147 __va_copy(alist2
,alist
);
155 /* Return NULL for an empty environment list */
163 size
+= strlen(arg
) + 1;
164 arg
= va_arg(alist
, char*);
165 } while (arg
!= NULL
);
167 ret
= (char*)MSVCRT_malloc(size
+ 1);
175 int len
= strlen(arg
);
179 arg
= va_arg(alist2
, char*);
180 } while (arg
!= NULL
);
181 if (delim
&& p
> ret
) p
[-1] = 0;
186 /*********************************************************************
189 int _cwait(int *status
, int pid
, int action
)
191 HANDLE hPid
= (HANDLE
)pid
;
194 action
= action
; /* Remove warning */
196 if (!WaitForSingleObject(hPid
, INFINITE
))
201 GetExitCodeProcess(hPid
, &stat
);
206 doserrno
= GetLastError();
208 if (doserrno
== ERROR_INVALID_HANDLE
)
210 *MSVCRT__errno() = MSVCRT_ECHILD
;
211 *MSVCRT___doserrno() = doserrno
;
214 msvcrt_set_errno(doserrno
);
216 return status
? *status
= -1 : -1;
219 /*********************************************************************
222 * Like on Windows, this function does not handle arguments with spaces
225 int _execl(const char* name
, const char* arg0
, ...)
232 args
= msvcrt_valisttos(arg0
, ap
, ' ');
235 ret
= msvcrt_spawn(MSVCRT__P_OVERLAY
, name
, args
, NULL
);
241 /*********************************************************************
244 int _execle(const char* name
, const char* arg0
, ...)
250 /*********************************************************************
253 * Like on Windows, this function does not handle arguments with spaces
256 int _execlp(const char* name
, const char* arg0
, ...)
261 char fullname
[MAX_PATH
];
263 _searchenv(name
, "PATH", fullname
);
266 args
= msvcrt_valisttos(arg0
, ap
, ' ');
269 ret
= msvcrt_spawn(MSVCRT__P_OVERLAY
, fullname
[0] ? fullname
: name
, args
, NULL
);
275 /*********************************************************************
276 * _execlpe (MSVCRT.@)
278 int _execlpe(const char* name
, const char* arg0
, ...)
284 /*********************************************************************
287 * Like on Windows, this function does not handle arguments with spaces
290 int _execv(const char* name
, char* const* argv
)
292 return _spawnve(MSVCRT__P_OVERLAY
, name
, (const char* const*) argv
, NULL
);
295 /*********************************************************************
298 * Like on Windows, this function does not handle arguments with spaces
301 int _execve(const char* name
, char* const* argv
, const char* const* envv
)
303 return _spawnve(MSVCRT__P_OVERLAY
, name
, (const char* const*) argv
, envv
);
306 /*********************************************************************
307 * _execvpe (MSVCRT.@)
309 * Like on Windows, this function does not handle arguments with spaces
312 int _execvpe(const char* name
, char* const* argv
, const char* const* envv
)
314 char fullname
[MAX_PATH
];
316 _searchenv(name
, "PATH", fullname
);
317 return _spawnve(MSVCRT__P_OVERLAY
, fullname
[0] ? fullname
: name
,
318 (const char* const*) argv
, envv
);
321 /*********************************************************************
324 * Like on Windows, this function does not handle arguments with spaces
327 int _execvp(const char* name
, char* const* argv
)
329 return _execvpe(name
, argv
, NULL
);
332 /*********************************************************************
335 * Like on Windows, this function does not handle arguments with spaces
338 int _spawnl(int flags
, const char* name
, const char* arg0
, ...)
345 args
= msvcrt_valisttos(arg0
, ap
, ' ');
348 ret
= msvcrt_spawn(flags
, name
, args
, NULL
);
354 /*********************************************************************
355 * _spawnle (MSVCRT.@)
357 int _spawnle(int flags
, const char* name
, const char* arg0
, ...)
360 char *args
, *envs
= NULL
;
361 const char * const *envp
;
365 args
= msvcrt_valisttos(arg0
, ap
, ' ');
369 while (va_arg( ap
, char * ) != NULL
) /*nothing*/;
370 envp
= va_arg( ap
, const char * const * );
371 if (envp
) envs
= msvcrt_argvtos(envp
, 0);
374 ret
= msvcrt_spawn(flags
, name
, args
, envs
);
377 if (envs
) MSVCRT_free(envs
);
382 /*********************************************************************
383 * _spawnlp (MSVCRT.@)
385 * Like on Windows, this function does not handle arguments with spaces
388 int _spawnlp(int flags
, const char* name
, const char* arg0
, ...)
393 char fullname
[MAX_PATH
];
395 _searchenv(name
, "PATH", fullname
);
398 args
= msvcrt_valisttos(arg0
, ap
, ' ');
401 ret
= msvcrt_spawn(flags
, fullname
[0] ? fullname
: name
, args
, NULL
);
407 /*********************************************************************
408 * _spawnlpe (MSVCRT.@)
410 int _spawnlpe(int flags
, const char* name
, const char* arg0
, ...)
413 char *args
, *envs
= NULL
;
414 const char * const *envp
;
416 char fullname
[MAX_PATH
];
418 _searchenv(name
, "PATH", fullname
);
421 args
= msvcrt_valisttos(arg0
, ap
, ' ');
425 while (va_arg( ap
, char * ) != NULL
) /*nothing*/;
426 envp
= va_arg( ap
, const char * const * );
427 if (envp
) envs
= msvcrt_argvtos(envp
, 0);
430 ret
= msvcrt_spawn(flags
, fullname
[0] ? fullname
: name
, args
, envs
);
433 if (envs
) MSVCRT_free(envs
);
437 /*********************************************************************
438 * _spawnve (MSVCRT.@)
440 * Like on Windows, this function does not handle arguments with spaces
443 int _spawnve(int flags
, const char* name
, const char* const* argv
,
444 const char* const* envv
)
446 char * args
= msvcrt_argvtos(argv
,' ');
447 char * envs
= msvcrt_argvtos(envv
,0);
448 const char *fullname
= name
;
451 FIXME(":not translating name %s to locate program\n",fullname
);
452 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name
),debugstr_a(args
),
453 envs
?"Custom":"Null");
457 ret
= msvcrt_spawn(flags
, fullname
, args
, envs
);
466 /*********************************************************************
469 * Like on Windows, this function does not handle arguments with spaces
472 int _spawnv(int flags
, const char* name
, const char* const* argv
)
474 return _spawnve(flags
, name
, argv
, NULL
);
477 /*********************************************************************
478 * _spawnvpe (MSVCRT.@)
480 * Like on Windows, this function does not handle arguments with spaces
483 int _spawnvpe(int flags
, const char* name
, const char* const* argv
,
484 const char* const* envv
)
486 char fullname
[MAX_PATH
];
487 _searchenv(name
, "PATH", fullname
);
488 return _spawnve(flags
, fullname
[0] ? fullname
: name
, argv
, envv
);
491 /*********************************************************************
492 * _spawnvp (MSVCRT.@)
494 * Like on Windows, this function does not handle arguments with spaces
497 int _spawnvp(int flags
, const char* name
, const char* const* argv
)
499 return _spawnvpe(flags
, name
, argv
, NULL
);
502 /*********************************************************************
504 * FIXME: convert to _wpopen and call that from here instead? But it
505 * would have to convert the command back to ANSI to call msvcrt_spawn,
508 MSVCRT_FILE
* MSVCRT__popen(const char* command
, const char* mode
)
510 static const char wcmd
[] = "wcmd", cmdFlag
[] = " /C ", comSpec
[] = "COMSPEC";
512 BOOL readPipe
= TRUE
;
513 int textmode
, fds
[2], fdToDup
, fdToOpen
, fdStdHandle
= -1, fdStdErr
= -1;
518 TRACE("(command=%s, mode=%s)\n", debugstr_a(command
), debugstr_a(mode
));
520 if (!command
|| !mode
)
523 textmode
= *__p__fmode() & (MSVCRT__O_BINARY
| MSVCRT__O_TEXT
);
524 for (p
= mode
; *p
; p
++)
534 textmode
|= MSVCRT__O_BINARY
;
535 textmode
&= ~MSVCRT__O_TEXT
;
539 textmode
|= MSVCRT__O_TEXT
;
540 textmode
&= ~MSVCRT__O_BINARY
;
544 textmode
|= MSVCRT__O_NOINHERIT
;
545 if (_pipe(fds
, 0, textmode
) == -1)
548 fdToDup
= readPipe
? 1 : 0;
549 fdToOpen
= readPipe
? 0 : 1;
551 if ((fdStdHandle
= _dup(fdToDup
)) == -1)
553 if (_dup2(fds
[fdToDup
], fdToDup
) != 0)
557 if ((fdStdErr
= _dup(MSVCRT_STDERR_FILENO
)) == -1)
559 if (_dup2(fds
[fdToDup
], MSVCRT_STDERR_FILENO
) != 0)
563 _close(fds
[fdToDup
]);
565 comSpecLen
= GetEnvironmentVariableA(comSpec
, NULL
, 0);
567 comSpecLen
= strlen(wcmd
) + 1;
568 cmdcopy
= HeapAlloc(GetProcessHeap(), 0, comSpecLen
+ strlen(cmdFlag
)
570 if (!GetEnvironmentVariableA(comSpec
, cmdcopy
, comSpecLen
))
571 strcpy(cmdcopy
, wcmd
);
572 strcat(cmdcopy
, cmdFlag
);
573 strcat(cmdcopy
, command
);
574 if (msvcrt_spawn(MSVCRT__P_NOWAIT
, NULL
, cmdcopy
, NULL
) == -1)
576 _close(fds
[fdToOpen
]);
581 ret
= MSVCRT__fdopen(fds
[fdToOpen
], mode
);
583 _close(fds
[fdToOpen
]);
585 HeapFree(GetProcessHeap(), 0, cmdcopy
);
586 _dup2(fdStdHandle
, fdToDup
);
590 _dup2(fdStdErr
, MSVCRT_STDERR_FILENO
);
596 if (fdStdHandle
!= -1) _close(fdStdHandle
);
597 if (fdStdErr
!= -1) _close(fdStdErr
);
603 /*********************************************************************
606 MSVCRT_FILE
* MSVCRT__wpopen(const MSVCRT_wchar_t
* command
, const MSVCRT_wchar_t
* mode
)
608 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command
), debugstr_w(mode
));
612 /*********************************************************************
615 int MSVCRT__pclose(MSVCRT_FILE
* file
)
617 return MSVCRT_fclose(file
);
620 /*********************************************************************
623 int MSVCRT_system(const char* cmd
)
628 /* Make a writable copy for CreateProcess */
629 cmdcopy
=_strdup(cmd
);
630 /* FIXME: should probably launch cmd interpreter in COMSPEC */
631 res
=msvcrt_spawn(MSVCRT__P_WAIT
, NULL
, cmdcopy
, NULL
);
632 MSVCRT_free(cmdcopy
);
636 /*********************************************************************
637 * _loaddll (MSVCRT.@)
639 int _loaddll(const char* dllname
)
641 return (int)LoadLibraryA(dllname
);
644 /*********************************************************************
645 * _unloaddll (MSVCRT.@)
647 int _unloaddll(int dll
)
649 if (FreeLibrary((HMODULE
)dll
))
653 int err
= GetLastError();
654 msvcrt_set_errno(err
);
659 /*********************************************************************
660 * _getdllprocaddr (MSVCRT.@)
662 void *_getdllprocaddr(int dll
, const char *name
, int ordinal
)
666 if (ordinal
!= -1) return NULL
;
667 return GetProcAddress( (HMODULE
)dll
, name
);
669 if (HIWORD(ordinal
)) return NULL
;
670 return GetProcAddress( (HMODULE
)dll
, (LPCSTR
)(ULONG_PTR
)ordinal
);