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"
34 #include "wine/unicode.h"
36 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt
);
38 /* INTERNAL: Spawn a child process */
39 static MSVCRT_intptr_t
msvcrt_spawn(int flags
, const char* exe
, char* cmdline
, char* env
)
42 PROCESS_INFORMATION pi
;
44 if ((unsigned)flags
> MSVCRT__P_DETACH
)
46 *MSVCRT__errno() = MSVCRT_EINVAL
;
50 memset(&si
, 0, sizeof(si
));
52 msvcrt_create_io_inherit_block(&si
.cbReserved2
, &si
.lpReserved2
);
53 if (!CreateProcessA(exe
, cmdline
, NULL
, NULL
, TRUE
,
54 flags
== MSVCRT__P_DETACH
? DETACHED_PROCESS
: 0,
57 msvcrt_set_errno(GetLastError());
58 MSVCRT_free(si
.lpReserved2
);
62 MSVCRT_free(si
.lpReserved2
);
66 WaitForSingleObject(pi
.hProcess
, INFINITE
);
67 GetExitCodeProcess(pi
.hProcess
,&pi
.dwProcessId
);
68 CloseHandle(pi
.hProcess
);
69 CloseHandle(pi
.hThread
);
70 return pi
.dwProcessId
;
71 case MSVCRT__P_DETACH
:
72 CloseHandle(pi
.hProcess
);
75 case MSVCRT__P_NOWAIT
:
76 case MSVCRT__P_NOWAITO
:
77 CloseHandle(pi
.hThread
);
78 return (MSVCRT_intptr_t
)pi
.hProcess
;
79 case MSVCRT__P_OVERLAY
:
82 return -1; /* can't reach here */
85 static MSVCRT_intptr_t
msvcrt_spawn_wide(int flags
, const MSVCRT_wchar_t
* exe
, MSVCRT_wchar_t
* cmdline
, MSVCRT_wchar_t
* env
)
88 PROCESS_INFORMATION pi
;
90 if ((unsigned)flags
> MSVCRT__P_DETACH
)
92 *MSVCRT__errno() = MSVCRT_EINVAL
;
96 memset(&si
, 0, sizeof(si
));
98 msvcrt_create_io_inherit_block(&si
.cbReserved2
, &si
.lpReserved2
);
99 if (!CreateProcessW(exe
, cmdline
, NULL
, NULL
, TRUE
,
100 flags
== MSVCRT__P_DETACH
? DETACHED_PROCESS
: 0,
101 env
, NULL
, &si
, &pi
))
103 msvcrt_set_errno(GetLastError());
104 MSVCRT_free(si
.lpReserved2
);
108 MSVCRT_free(si
.lpReserved2
);
112 WaitForSingleObject(pi
.hProcess
, INFINITE
);
113 GetExitCodeProcess(pi
.hProcess
,&pi
.dwProcessId
);
114 CloseHandle(pi
.hProcess
);
115 CloseHandle(pi
.hThread
);
116 return pi
.dwProcessId
;
117 case MSVCRT__P_DETACH
:
118 CloseHandle(pi
.hProcess
);
121 case MSVCRT__P_NOWAIT
:
122 case MSVCRT__P_NOWAITO
:
123 CloseHandle(pi
.hThread
);
124 return (MSVCRT_intptr_t
)pi
.hProcess
;
125 case MSVCRT__P_OVERLAY
:
128 return -1; /* can't reach here */
131 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
132 * extra '\0' to terminate it
134 static char* msvcrt_argvtos(const char* const* arg
, char delim
)
136 const char* const* a
;
143 /* Return NULL for an empty environment list */
152 size
+= strlen(*a
) + 1;
156 ret
= MSVCRT_malloc(size
+ 1);
165 int len
= strlen(*a
);
171 if (delim
&& p
> ret
) p
[-1] = 0;
176 static MSVCRT_wchar_t
* msvcrt_argvtos_wide(const MSVCRT_wchar_t
* const* arg
, MSVCRT_wchar_t delim
)
178 const MSVCRT_wchar_t
* const* a
;
185 /* Return NULL for an empty environment list */
194 size
+= strlenW(*a
) + 1;
198 ret
= MSVCRT_malloc((size
+ 1) * sizeof(MSVCRT_wchar_t
));
207 int len
= strlenW(*a
);
208 memcpy(p
,*a
,len
* sizeof(MSVCRT_wchar_t
));
213 if (delim
&& p
> ret
) p
[-1] = 0;
218 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
219 * extra '\0' to terminate it
221 static char* msvcrt_valisttos(const char* arg0
, va_list alist
, char delim
)
230 va_copy(alist2
,alist
);
232 # ifdef HAVE___VA_COPY
233 __va_copy(alist2
,alist
);
241 /* Return NULL for an empty environment list */
249 size
+= strlen(arg
) + 1;
250 arg
= va_arg(alist
, char*);
251 } while (arg
!= NULL
);
253 ret
= MSVCRT_malloc(size
+ 1);
261 int len
= strlen(arg
);
265 arg
= va_arg(alist2
, char*);
266 } while (arg
!= NULL
);
267 if (delim
&& p
> ret
) p
[-1] = 0;
272 /*********************************************************************
275 MSVCRT_intptr_t CDECL
_cwait(int *status
, MSVCRT_intptr_t pid
, int action
)
277 HANDLE hPid
= (HANDLE
)pid
;
280 action
= action
; /* Remove warning */
282 if (!WaitForSingleObject(hPid
, INFINITE
))
287 GetExitCodeProcess(hPid
, &stat
);
292 doserrno
= GetLastError();
294 if (doserrno
== ERROR_INVALID_HANDLE
)
296 *MSVCRT__errno() = MSVCRT_ECHILD
;
297 *MSVCRT___doserrno() = doserrno
;
300 msvcrt_set_errno(doserrno
);
302 return status
? *status
= -1 : -1;
305 /*********************************************************************
308 * Like on Windows, this function does not handle arguments with spaces
311 MSVCRT_intptr_t CDECL
_execl(const char* name
, const char* arg0
, ...)
318 args
= msvcrt_valisttos(arg0
, ap
, ' ');
321 ret
= msvcrt_spawn(MSVCRT__P_OVERLAY
, name
, args
, NULL
);
327 /*********************************************************************
330 MSVCRT_intptr_t CDECL
_execle(const char* name
, const char* arg0
, ...)
336 /*********************************************************************
339 * Like on Windows, this function does not handle arguments with spaces
342 MSVCRT_intptr_t CDECL
_execlp(const char* name
, const char* arg0
, ...)
347 char fullname
[MAX_PATH
];
349 _searchenv(name
, "PATH", fullname
);
352 args
= msvcrt_valisttos(arg0
, ap
, ' ');
355 ret
= msvcrt_spawn(MSVCRT__P_OVERLAY
, fullname
[0] ? fullname
: name
, args
, NULL
);
361 /*********************************************************************
362 * _execlpe (MSVCRT.@)
364 MSVCRT_intptr_t CDECL
_execlpe(const char* name
, const char* arg0
, ...)
370 /*********************************************************************
373 * Like on Windows, this function does not handle arguments with spaces
376 MSVCRT_intptr_t CDECL
_execv(const char* name
, char* const* argv
)
378 return _spawnve(MSVCRT__P_OVERLAY
, name
, (const char* const*) argv
, NULL
);
381 /*********************************************************************
384 * Like on Windows, this function does not handle arguments with spaces
387 MSVCRT_intptr_t CDECL
MSVCRT__execve(const char* name
, char* const* argv
, const char* const* envv
)
389 return _spawnve(MSVCRT__P_OVERLAY
, name
, (const char* const*) argv
, envv
);
392 /*********************************************************************
393 * _execvpe (MSVCRT.@)
395 * Like on Windows, this function does not handle arguments with spaces
398 MSVCRT_intptr_t CDECL
_execvpe(const char* name
, char* const* argv
, const char* const* envv
)
400 char fullname
[MAX_PATH
];
402 _searchenv(name
, "PATH", fullname
);
403 return _spawnve(MSVCRT__P_OVERLAY
, fullname
[0] ? fullname
: name
,
404 (const char* const*) argv
, envv
);
407 /*********************************************************************
410 * Like on Windows, this function does not handle arguments with spaces
413 MSVCRT_intptr_t CDECL
_execvp(const char* name
, char* const* argv
)
415 return _execvpe(name
, argv
, NULL
);
418 /*********************************************************************
421 * Like on Windows, this function does not handle arguments with spaces
424 MSVCRT_intptr_t CDECL
_spawnl(int flags
, const char* name
, const char* arg0
, ...)
431 args
= msvcrt_valisttos(arg0
, ap
, ' ');
434 ret
= msvcrt_spawn(flags
, name
, args
, NULL
);
440 /*********************************************************************
441 * _spawnle (MSVCRT.@)
443 MSVCRT_intptr_t CDECL
_spawnle(int flags
, const char* name
, const char* arg0
, ...)
446 char *args
, *envs
= NULL
;
447 const char * const *envp
;
451 args
= msvcrt_valisttos(arg0
, ap
, ' ');
455 while (va_arg( ap
, char * ) != NULL
) /*nothing*/;
456 envp
= va_arg( ap
, const char * const * );
457 if (envp
) envs
= msvcrt_argvtos(envp
, 0);
460 ret
= msvcrt_spawn(flags
, name
, args
, envs
);
468 /*********************************************************************
469 * _spawnlp (MSVCRT.@)
471 * Like on Windows, this function does not handle arguments with spaces
474 MSVCRT_intptr_t CDECL
_spawnlp(int flags
, const char* name
, const char* arg0
, ...)
479 char fullname
[MAX_PATH
];
481 _searchenv(name
, "PATH", fullname
);
484 args
= msvcrt_valisttos(arg0
, ap
, ' ');
487 ret
= msvcrt_spawn(flags
, fullname
[0] ? fullname
: name
, args
, NULL
);
493 /*********************************************************************
494 * _spawnlpe (MSVCRT.@)
496 MSVCRT_intptr_t CDECL
_spawnlpe(int flags
, const char* name
, const char* arg0
, ...)
499 char *args
, *envs
= NULL
;
500 const char * const *envp
;
502 char fullname
[MAX_PATH
];
504 _searchenv(name
, "PATH", fullname
);
507 args
= msvcrt_valisttos(arg0
, ap
, ' ');
511 while (va_arg( ap
, char * ) != NULL
) /*nothing*/;
512 envp
= va_arg( ap
, const char * const * );
513 if (envp
) envs
= msvcrt_argvtos(envp
, 0);
516 ret
= msvcrt_spawn(flags
, fullname
[0] ? fullname
: name
, args
, envs
);
523 /*********************************************************************
524 * _spawnve (MSVCRT.@)
526 * Like on Windows, this function does not handle arguments with spaces
529 MSVCRT_intptr_t CDECL
_spawnve(int flags
, const char* name
, const char* const* argv
,
530 const char* const* envv
)
532 char * args
= msvcrt_argvtos(argv
,' ');
533 char * envs
= msvcrt_argvtos(envv
,0);
534 char fullname
[MAX_PATH
];
537 MSVCRT_intptr_t ret
= -1;
539 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_a(name
),debugstr_a(args
),
540 envs
?"Custom":"Null");
542 /* no check for NULL name.
543 native doesn't do it */
545 p
= memchr(name
, '\0', MAX_PATH
);
547 p
= name
+ MAX_PATH
- 1;
550 /* extra-long names are silently truncated. */
551 memcpy(fullname
, name
, len
);
553 for( p
--; p
>= name
; p
-- )
555 if( *p
== '\\' || *p
== '/' || *p
== ':' || *p
== '.' )
559 /* if no extension is given, assume .exe */
560 if( (p
< name
|| *p
!= '.') && len
<= MAX_PATH
- 5 )
562 FIXME("only trying .exe when no extension given\n");
563 memcpy(fullname
+len
, ".exe", 4);
567 fullname
[len
] = '\0';
571 ret
= msvcrt_spawn(flags
, fullname
, args
, envs
);
579 /*********************************************************************
580 * _wspawnve (MSVCRT.@)
582 * Unicode version of _spawnve
584 MSVCRT_intptr_t CDECL
_wspawnve(int flags
, const MSVCRT_wchar_t
* name
, const MSVCRT_wchar_t
* const* argv
,
585 const MSVCRT_wchar_t
* const* envv
)
587 MSVCRT_wchar_t
* args
= msvcrt_argvtos_wide(argv
,' ');
588 MSVCRT_wchar_t
* envs
= msvcrt_argvtos_wide(envv
,0);
589 MSVCRT_wchar_t fullname
[MAX_PATH
];
590 const MSVCRT_wchar_t
*p
;
592 MSVCRT_intptr_t ret
= -1;
594 TRACE(":call (%s), params (%s), env (%s)\n",debugstr_w(name
),debugstr_w(args
),
595 envs
?"Custom":"Null");
597 /* no check for NULL name.
598 native doesn't do it */
600 p
= memchrW(name
, '\0', MAX_PATH
);
602 p
= name
+ MAX_PATH
- 1;
605 /* extra-long names are silently truncated. */
606 memcpy(fullname
, name
, len
* sizeof(MSVCRT_wchar_t
));
608 for( p
--; p
>= name
; p
-- )
610 if( *p
== '\\' || *p
== '/' || *p
== ':' || *p
== '.' )
614 /* if no extension is given, assume .exe */
615 if( (p
< name
|| *p
!= '.') && len
<= MAX_PATH
- 5 )
617 static const MSVCRT_wchar_t dotexe
[] = {'.','e','x','e'};
619 FIXME("only trying .exe when no extension given\n");
620 memcpy(fullname
+len
, dotexe
, 4 * sizeof(MSVCRT_wchar_t
));
624 fullname
[len
] = '\0';
628 ret
= msvcrt_spawn_wide(flags
, fullname
, args
, envs
);
636 /*********************************************************************
639 * Like on Windows, this function does not handle arguments with spaces
642 MSVCRT_intptr_t CDECL
_spawnv(int flags
, const char* name
, const char* const* argv
)
644 return _spawnve(flags
, name
, argv
, NULL
);
647 /*********************************************************************
648 * _wspawnv (MSVCRT.@)
650 * Unicode version of _spawnv
652 MSVCRT_intptr_t CDECL
_wspawnv(int flags
, const MSVCRT_wchar_t
* name
, const MSVCRT_wchar_t
* const* argv
)
654 return _wspawnve(flags
, name
, argv
, NULL
);
657 /*********************************************************************
658 * _spawnvpe (MSVCRT.@)
660 * Like on Windows, this function does not handle arguments with spaces
663 MSVCRT_intptr_t CDECL
_spawnvpe(int flags
, const char* name
, const char* const* argv
,
664 const char* const* envv
)
666 char fullname
[MAX_PATH
];
667 _searchenv(name
, "PATH", fullname
);
668 return _spawnve(flags
, fullname
[0] ? fullname
: name
, argv
, envv
);
671 /*********************************************************************
672 * _wspawnvpe (MSVCRT.@)
674 * Unicode version of _spawnvpe
676 MSVCRT_intptr_t CDECL
_wspawnvpe(int flags
, const MSVCRT_wchar_t
* name
, const MSVCRT_wchar_t
* const* argv
,
677 const MSVCRT_wchar_t
* const* envv
)
679 static const MSVCRT_wchar_t path
[] = {'P','A','T','H',0};
680 MSVCRT_wchar_t fullname
[MAX_PATH
];
682 _wsearchenv(name
, path
, fullname
);
683 return _wspawnve(flags
, fullname
[0] ? fullname
: name
, argv
, envv
);
686 /*********************************************************************
687 * _spawnvp (MSVCRT.@)
689 * Like on Windows, this function does not handle arguments with spaces
692 MSVCRT_intptr_t CDECL
_spawnvp(int flags
, const char* name
, const char* const* argv
)
694 return _spawnvpe(flags
, name
, argv
, NULL
);
697 /*********************************************************************
698 * _wspawnvp (MSVCRT.@)
700 * Unicode version of _spawnvp
702 MSVCRT_intptr_t CDECL
_wspawnvp(int flags
, const MSVCRT_wchar_t
* name
, const MSVCRT_wchar_t
* const* argv
)
704 return _wspawnvpe(flags
, name
, argv
, NULL
);
707 /*********************************************************************
709 * FIXME: convert to _wpopen and call that from here instead? But it
710 * would have to convert the command back to ANSI to call msvcrt_spawn,
713 MSVCRT_FILE
* CDECL
MSVCRT__popen(const char* command
, const char* mode
)
715 static const char wcmd
[] = "cmd", cmdFlag
[] = " /C ", comSpec
[] = "COMSPEC";
717 BOOL readPipe
= TRUE
;
718 int textmode
, fds
[2], fdToDup
, fdToOpen
, fdStdHandle
= -1, fdStdErr
= -1;
723 TRACE("(command=%s, mode=%s)\n", debugstr_a(command
), debugstr_a(mode
));
725 if (!command
|| !mode
)
728 textmode
= *__p__fmode() & (MSVCRT__O_BINARY
| MSVCRT__O_TEXT
);
729 for (p
= mode
; *p
; p
++)
739 textmode
|= MSVCRT__O_BINARY
;
740 textmode
&= ~MSVCRT__O_TEXT
;
744 textmode
|= MSVCRT__O_TEXT
;
745 textmode
&= ~MSVCRT__O_BINARY
;
749 if (MSVCRT__pipe(fds
, 0, textmode
) == -1)
752 fdToDup
= readPipe
? 1 : 0;
753 fdToOpen
= readPipe
? 0 : 1;
755 if ((fdStdHandle
= MSVCRT__dup(fdToDup
)) == -1)
757 if (MSVCRT__dup2(fds
[fdToDup
], fdToDup
) != 0)
761 if ((fdStdErr
= MSVCRT__dup(MSVCRT_STDERR_FILENO
)) == -1)
763 if (MSVCRT__dup2(fds
[fdToDup
], MSVCRT_STDERR_FILENO
) != 0)
767 MSVCRT__close(fds
[fdToDup
]);
769 comSpecLen
= GetEnvironmentVariableA(comSpec
, NULL
, 0);
771 comSpecLen
= strlen(wcmd
) + 1;
772 cmdcopy
= HeapAlloc(GetProcessHeap(), 0, comSpecLen
+ strlen(cmdFlag
)
774 if (!GetEnvironmentVariableA(comSpec
, cmdcopy
, comSpecLen
))
775 strcpy(cmdcopy
, wcmd
);
776 strcat(cmdcopy
, cmdFlag
);
777 strcat(cmdcopy
, command
);
778 if (msvcrt_spawn(MSVCRT__P_NOWAIT
, NULL
, cmdcopy
, NULL
) == -1)
780 MSVCRT__close(fds
[fdToOpen
]);
785 ret
= MSVCRT__fdopen(fds
[fdToOpen
], mode
);
787 MSVCRT__close(fds
[fdToOpen
]);
789 HeapFree(GetProcessHeap(), 0, cmdcopy
);
790 MSVCRT__dup2(fdStdHandle
, fdToDup
);
791 MSVCRT__close(fdStdHandle
);
794 MSVCRT__dup2(fdStdErr
, MSVCRT_STDERR_FILENO
);
795 MSVCRT__close(fdStdErr
);
800 if (fdStdHandle
!= -1) MSVCRT__close(fdStdHandle
);
801 if (fdStdErr
!= -1) MSVCRT__close(fdStdErr
);
802 MSVCRT__close(fds
[0]);
803 MSVCRT__close(fds
[1]);
807 /*********************************************************************
810 MSVCRT_FILE
* CDECL
MSVCRT__wpopen(const MSVCRT_wchar_t
* command
, const MSVCRT_wchar_t
* mode
)
812 FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command
), debugstr_w(mode
));
816 /*********************************************************************
819 int CDECL
MSVCRT__pclose(MSVCRT_FILE
* file
)
821 return MSVCRT_fclose(file
);
824 /*********************************************************************
827 int CDECL
MSVCRT_system(const char* cmd
)
832 /* Make a writable copy for CreateProcess */
833 cmdcopy
=_strdup(cmd
);
834 /* FIXME: should probably launch cmd interpreter in COMSPEC */
835 res
=msvcrt_spawn(MSVCRT__P_WAIT
, NULL
, cmdcopy
, NULL
);
836 MSVCRT_free(cmdcopy
);
840 /*********************************************************************
841 * _loaddll (MSVCRT.@)
843 MSVCRT_intptr_t CDECL
_loaddll(const char* dllname
)
845 return (MSVCRT_intptr_t
)LoadLibraryA(dllname
);
848 /*********************************************************************
849 * _unloaddll (MSVCRT.@)
851 int CDECL
_unloaddll(MSVCRT_intptr_t dll
)
853 if (FreeLibrary((HMODULE
)dll
))
857 int err
= GetLastError();
858 msvcrt_set_errno(err
);
863 /*********************************************************************
864 * _getdllprocaddr (MSVCRT.@)
866 void * CDECL
_getdllprocaddr(MSVCRT_intptr_t dll
, const char *name
, int ordinal
)
870 if (ordinal
!= -1) return NULL
;
871 return GetProcAddress( (HMODULE
)dll
, name
);
873 if (HIWORD(ordinal
)) return NULL
;
874 return GetProcAddress( (HMODULE
)dll
, (LPCSTR
)(ULONG_PTR
)ordinal
);