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
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 CDECL
_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 CDECL
_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 CDECL
_execle(const char* name
, const char* arg0
, ...)
247 /*********************************************************************
250 * Like on Windows, this function does not handle arguments with spaces
253 MSVCRT_intptr_t CDECL
_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 CDECL
_execlpe(const char* name
, const char* arg0
, ...)
281 /*********************************************************************
284 * Like on Windows, this function does not handle arguments with spaces
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 /*********************************************************************
295 * Like on Windows, this function does not handle arguments with spaces
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
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 /*********************************************************************
321 * Like on Windows, this function does not handle arguments with spaces
324 MSVCRT_intptr_t CDECL
_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 CDECL
_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 CDECL
_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
);
379 /*********************************************************************
380 * _spawnlp (MSVCRT.@)
382 * Like on Windows, this function does not handle arguments with spaces
385 MSVCRT_intptr_t CDECL
_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 CDECL
_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
);
434 /*********************************************************************
435 * _spawnve (MSVCRT.@)
437 * Like on Windows, this function does not handle arguments with spaces
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
];
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
);
458 p
= name
+ MAX_PATH
- 1;
461 /* extra-long names are silently truncated. */
462 memcpy(fullname
, name
, len
);
464 for( p
--; p
>= name
; p
-- )
466 if( *p
== '\\' || *p
== '/' || *p
== ':' || *p
== '.' )
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);
478 fullname
[len
] = '\0';
482 ret
= msvcrt_spawn(flags
, fullname
, args
, envs
);
490 /*********************************************************************
493 * Like on Windows, this function does not handle arguments with spaces
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
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
521 MSVCRT_intptr_t CDECL
_spawnvp(int flags
, const char* name
, const char* const* argv
)
523 return _spawnvpe(flags
, name
, argv
, NULL
);
526 /*********************************************************************
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,
532 MSVCRT_FILE
* CDECL
MSVCRT__popen(const char* command
, const char* mode
)
534 static const char wcmd
[] = "cmd", cmdFlag
[] = " /C ", comSpec
[] = "COMSPEC";
536 BOOL readPipe
= TRUE
;
537 int textmode
, fds
[2], fdToDup
, fdToOpen
, fdStdHandle
= -1, fdStdErr
= -1;
542 TRACE("(command=%s, mode=%s)\n", debugstr_a(command
), debugstr_a(mode
));
544 if (!command
|| !mode
)
547 textmode
= *__p__fmode() & (MSVCRT__O_BINARY
| MSVCRT__O_TEXT
);
548 for (p
= mode
; *p
; p
++)
558 textmode
|= MSVCRT__O_BINARY
;
559 textmode
&= ~MSVCRT__O_TEXT
;
563 textmode
|= MSVCRT__O_TEXT
;
564 textmode
&= ~MSVCRT__O_BINARY
;
568 if (_pipe(fds
, 0, textmode
) == -1)
571 fdToDup
= readPipe
? 1 : 0;
572 fdToOpen
= readPipe
? 0 : 1;
574 if ((fdStdHandle
= _dup(fdToDup
)) == -1)
576 if (_dup2(fds
[fdToDup
], fdToDup
) != 0)
580 if ((fdStdErr
= _dup(MSVCRT_STDERR_FILENO
)) == -1)
582 if (_dup2(fds
[fdToDup
], MSVCRT_STDERR_FILENO
) != 0)
586 _close(fds
[fdToDup
]);
588 comSpecLen
= GetEnvironmentVariableA(comSpec
, NULL
, 0);
590 comSpecLen
= strlen(wcmd
) + 1;
591 cmdcopy
= HeapAlloc(GetProcessHeap(), 0, comSpecLen
+ strlen(cmdFlag
)
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 _close(fds
[fdToOpen
]);
604 ret
= MSVCRT__fdopen(fds
[fdToOpen
], mode
);
606 _close(fds
[fdToOpen
]);
608 HeapFree(GetProcessHeap(), 0, cmdcopy
);
609 _dup2(fdStdHandle
, fdToDup
);
613 _dup2(fdStdErr
, MSVCRT_STDERR_FILENO
);
619 if (fdStdHandle
!= -1) _close(fdStdHandle
);
620 if (fdStdErr
!= -1) _close(fdStdErr
);
626 /*********************************************************************
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
));
635 /*********************************************************************
638 int CDECL
MSVCRT__pclose(MSVCRT_FILE
* file
)
640 return MSVCRT_fclose(file
);
643 /*********************************************************************
646 int CDECL
MSVCRT_system(const char* cmd
)
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
);
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
))
676 int err
= GetLastError();
677 msvcrt_set_errno(err
);
682 /*********************************************************************
683 * _getdllprocaddr (MSVCRT.@)
685 void * CDECL
_getdllprocaddr(MSVCRT_intptr_t dll
, const char *name
, int ordinal
)
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
);