kernel32: Move support for starting Unix processes to ntdll.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
1deefb84ee
commit
eee3a4e84a
|
@ -99,24 +99,6 @@ static WCHAR winevdm[] = {'C',':','\\','w','i','n','d','o','w','s',
|
||||||
'\\','w','i','n','e','v','d','m','.','e','x','e',0};
|
'\\','w','i','n','e','v','d','m','.','e','x','e',0};
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* is_special_env_var
|
|
||||||
*
|
|
||||||
* Check if an environment variable needs to be handled specially when
|
|
||||||
* passed through the Unix environment (i.e. prefixed with "WINE").
|
|
||||||
*/
|
|
||||||
static inline BOOL is_special_env_var( const char *var )
|
|
||||||
{
|
|
||||||
return (!strncmp( var, "PATH=", sizeof("PATH=")-1 ) ||
|
|
||||||
!strncmp( var, "PWD=", sizeof("PWD=")-1 ) ||
|
|
||||||
!strncmp( var, "HOME=", sizeof("HOME=")-1 ) ||
|
|
||||||
!strncmp( var, "TEMP=", sizeof("TEMP=")-1 ) ||
|
|
||||||
!strncmp( var, "TMP=", sizeof("TMP=")-1 ) ||
|
|
||||||
!strncmp( var, "QT_", sizeof("QT_")-1 ) ||
|
|
||||||
!strncmp( var, "VK_", sizeof("VK_")-1 ));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* find_exe_file
|
* find_exe_file
|
||||||
*
|
*
|
||||||
|
@ -295,317 +277,6 @@ void * CDECL __wine_kernel_init(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* build_argv
|
|
||||||
*
|
|
||||||
* Build an argv array from a command-line.
|
|
||||||
* 'reserved' is the number of args to reserve before the first one.
|
|
||||||
*/
|
|
||||||
static char **build_argv( const UNICODE_STRING *cmdlineW, int reserved )
|
|
||||||
{
|
|
||||||
int argc;
|
|
||||||
char** argv;
|
|
||||||
char *arg,*s,*d,*cmdline;
|
|
||||||
int in_quotes,bcount,len;
|
|
||||||
|
|
||||||
len = WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW->Buffer, cmdlineW->Length / sizeof(WCHAR),
|
|
||||||
NULL, 0, NULL, NULL );
|
|
||||||
if (!(cmdline = HeapAlloc( GetProcessHeap(), 0, len + 1 ))) return NULL;
|
|
||||||
WideCharToMultiByte( CP_UNIXCP, 0, cmdlineW->Buffer, cmdlineW->Length / sizeof(WCHAR),
|
|
||||||
cmdline, len, NULL, NULL );
|
|
||||||
cmdline[len++] = 0;
|
|
||||||
|
|
||||||
argc=reserved+1;
|
|
||||||
bcount=0;
|
|
||||||
in_quotes=0;
|
|
||||||
s=cmdline;
|
|
||||||
while (1) {
|
|
||||||
if (*s=='\0' || ((*s==' ' || *s=='\t') && !in_quotes)) {
|
|
||||||
/* space */
|
|
||||||
argc++;
|
|
||||||
/* skip the remaining spaces */
|
|
||||||
while (*s==' ' || *s=='\t') {
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
if (*s=='\0')
|
|
||||||
break;
|
|
||||||
bcount=0;
|
|
||||||
continue;
|
|
||||||
} else if (*s=='\\') {
|
|
||||||
/* '\', count them */
|
|
||||||
bcount++;
|
|
||||||
} else if ((*s=='"') && ((bcount & 1)==0)) {
|
|
||||||
if (in_quotes && s[1] == '"') {
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
/* unescaped '"' */
|
|
||||||
in_quotes=!in_quotes;
|
|
||||||
bcount=0;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* a regular character */
|
|
||||||
bcount=0;
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
if (!(argv = HeapAlloc( GetProcessHeap(), 0, argc*sizeof(*argv) + len )))
|
|
||||||
{
|
|
||||||
HeapFree( GetProcessHeap(), 0, cmdline );
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
arg = d = s = (char *)(argv + argc);
|
|
||||||
memcpy( d, cmdline, len );
|
|
||||||
bcount=0;
|
|
||||||
in_quotes=0;
|
|
||||||
argc=reserved;
|
|
||||||
while (*s) {
|
|
||||||
if ((*s==' ' || *s=='\t') && !in_quotes) {
|
|
||||||
/* Close the argument and copy it */
|
|
||||||
*d=0;
|
|
||||||
argv[argc++]=arg;
|
|
||||||
|
|
||||||
/* skip the remaining spaces */
|
|
||||||
do {
|
|
||||||
s++;
|
|
||||||
} while (*s==' ' || *s=='\t');
|
|
||||||
|
|
||||||
/* Start with a new argument */
|
|
||||||
arg=d=s;
|
|
||||||
bcount=0;
|
|
||||||
} else if (*s=='\\') {
|
|
||||||
/* '\\' */
|
|
||||||
*d++=*s++;
|
|
||||||
bcount++;
|
|
||||||
} else if (*s=='"') {
|
|
||||||
/* '"' */
|
|
||||||
if ((bcount & 1)==0) {
|
|
||||||
/* Preceded by an even number of '\', this is half that
|
|
||||||
* number of '\', plus a '"' which we discard.
|
|
||||||
*/
|
|
||||||
d-=bcount/2;
|
|
||||||
s++;
|
|
||||||
if(in_quotes && *s == '"') {
|
|
||||||
*d++='"';
|
|
||||||
s++;
|
|
||||||
} else {
|
|
||||||
in_quotes=!in_quotes;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
/* Preceded by an odd number of '\', this is half that
|
|
||||||
* number of '\' followed by a '"'
|
|
||||||
*/
|
|
||||||
d=d-bcount/2-1;
|
|
||||||
*d++='"';
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
bcount=0;
|
|
||||||
} else {
|
|
||||||
/* a regular character */
|
|
||||||
*d++=*s++;
|
|
||||||
bcount=0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (*arg) {
|
|
||||||
*d='\0';
|
|
||||||
argv[argc++]=arg;
|
|
||||||
}
|
|
||||||
argv[argc]=NULL;
|
|
||||||
|
|
||||||
HeapFree( GetProcessHeap(), 0, cmdline );
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* build_envp
|
|
||||||
*
|
|
||||||
* Build the environment of a new child process.
|
|
||||||
*/
|
|
||||||
static char **build_envp( const WCHAR *envW )
|
|
||||||
{
|
|
||||||
static const char * const unix_vars[] = { "PATH", "TEMP", "TMP", "HOME" };
|
|
||||||
|
|
||||||
const WCHAR *end;
|
|
||||||
char **envp;
|
|
||||||
char *env, *p;
|
|
||||||
int count = 1, length;
|
|
||||||
unsigned int i;
|
|
||||||
|
|
||||||
for (end = envW; *end; count++) end += strlenW(end) + 1;
|
|
||||||
end++;
|
|
||||||
length = WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, NULL, 0, NULL, NULL );
|
|
||||||
if (!(env = HeapAlloc( GetProcessHeap(), 0, length ))) return NULL;
|
|
||||||
WideCharToMultiByte( CP_UNIXCP, 0, envW, end - envW, env, length, NULL, NULL );
|
|
||||||
|
|
||||||
for (p = env; *p; p += strlen(p) + 1)
|
|
||||||
if (is_special_env_var( p )) length += 4; /* prefix it with "WINE" */
|
|
||||||
|
|
||||||
for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
|
|
||||||
{
|
|
||||||
if (!(p = getenv(unix_vars[i]))) continue;
|
|
||||||
length += strlen(unix_vars[i]) + strlen(p) + 2;
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((envp = HeapAlloc( GetProcessHeap(), 0, count * sizeof(*envp) + length )))
|
|
||||||
{
|
|
||||||
char **envptr = envp;
|
|
||||||
char *dst = (char *)(envp + count);
|
|
||||||
|
|
||||||
/* some variables must not be modified, so we get them directly from the unix env */
|
|
||||||
for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
|
|
||||||
{
|
|
||||||
if (!(p = getenv(unix_vars[i]))) continue;
|
|
||||||
*envptr++ = strcpy( dst, unix_vars[i] );
|
|
||||||
strcat( dst, "=" );
|
|
||||||
strcat( dst, p );
|
|
||||||
dst += strlen(dst) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* now put the Windows environment strings */
|
|
||||||
for (p = env; *p; p += strlen(p) + 1)
|
|
||||||
{
|
|
||||||
if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */
|
|
||||||
if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
|
|
||||||
if (!strncmp( p, "WINELOADERNOEXEC=", sizeof("WINELOADERNOEXEC=")-1 )) continue;
|
|
||||||
if (!strncmp( p, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
|
|
||||||
if (is_special_env_var( p )) /* prefix it with "WINE" */
|
|
||||||
{
|
|
||||||
*envptr++ = strcpy( dst, "WINE" );
|
|
||||||
strcat( dst, p );
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
*envptr++ = strcpy( dst, p );
|
|
||||||
}
|
|
||||||
dst += strlen(dst) + 1;
|
|
||||||
}
|
|
||||||
*envptr = 0;
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, env );
|
|
||||||
return envp;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
|
||||||
* fork_and_exec
|
|
||||||
*
|
|
||||||
* Fork and exec a new Unix binary, checking for errors.
|
|
||||||
*/
|
|
||||||
static NTSTATUS fork_and_exec( const RTL_USER_PROCESS_PARAMETERS *params, const char *newdir )
|
|
||||||
{
|
|
||||||
int fd[2], stdin_fd = -1, stdout_fd = -1, stderr_fd = -1;
|
|
||||||
int pid, err;
|
|
||||||
char **argv, **envp;
|
|
||||||
UNICODE_STRING nt_name;
|
|
||||||
ANSI_STRING unix_name;
|
|
||||||
NTSTATUS status;
|
|
||||||
|
|
||||||
status = RtlDosPathNameToNtPathName_U_WithStatus( params->ImagePathName.Buffer, &nt_name, NULL, NULL );
|
|
||||||
if (!status)
|
|
||||||
{
|
|
||||||
status = wine_nt_to_unix_file_name( &nt_name, &unix_name, FILE_OPEN, FALSE );
|
|
||||||
RtlFreeUnicodeString( &nt_name );
|
|
||||||
}
|
|
||||||
if (status) return status;
|
|
||||||
|
|
||||||
#ifdef HAVE_PIPE2
|
|
||||||
if (pipe2( fd, O_CLOEXEC ) == -1)
|
|
||||||
#endif
|
|
||||||
{
|
|
||||||
if (pipe(fd) == -1)
|
|
||||||
{
|
|
||||||
RtlFreeAnsiString( &unix_name );
|
|
||||||
return STATUS_TOO_MANY_OPENED_FILES;
|
|
||||||
}
|
|
||||||
fcntl( fd[0], F_SETFD, FD_CLOEXEC );
|
|
||||||
fcntl( fd[1], F_SETFD, FD_CLOEXEC );
|
|
||||||
}
|
|
||||||
|
|
||||||
wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
|
|
||||||
wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
|
|
||||||
wine_server_handle_to_fd( params->hStdError, FILE_WRITE_DATA, &stderr_fd, NULL );
|
|
||||||
|
|
||||||
argv = build_argv( ¶ms->CommandLine, 0 );
|
|
||||||
envp = build_envp( params->Environment );
|
|
||||||
|
|
||||||
if (!(pid = fork())) /* child */
|
|
||||||
{
|
|
||||||
if (!(pid = fork())) /* grandchild */
|
|
||||||
{
|
|
||||||
close( fd[0] );
|
|
||||||
|
|
||||||
if (params->ConsoleFlags || params->ConsoleHandle == KERNEL32_CONSOLE_ALLOC ||
|
|
||||||
(params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
|
|
||||||
{
|
|
||||||
int nullfd = open( "/dev/null", O_RDWR );
|
|
||||||
setsid();
|
|
||||||
/* close stdin and stdout */
|
|
||||||
if (nullfd != -1)
|
|
||||||
{
|
|
||||||
dup2( nullfd, 0 );
|
|
||||||
dup2( nullfd, 1 );
|
|
||||||
close( nullfd );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (stdin_fd != -1)
|
|
||||||
{
|
|
||||||
dup2( stdin_fd, 0 );
|
|
||||||
close( stdin_fd );
|
|
||||||
}
|
|
||||||
if (stdout_fd != -1)
|
|
||||||
{
|
|
||||||
dup2( stdout_fd, 1 );
|
|
||||||
close( stdout_fd );
|
|
||||||
}
|
|
||||||
if (stderr_fd != -1)
|
|
||||||
{
|
|
||||||
dup2( stderr_fd, 2 );
|
|
||||||
close( stderr_fd );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Reset signals that we previously set to SIG_IGN */
|
|
||||||
signal( SIGPIPE, SIG_DFL );
|
|
||||||
|
|
||||||
if (newdir) chdir(newdir);
|
|
||||||
|
|
||||||
if (argv && envp) execve( unix_name.Buffer, argv, envp );
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pid <= 0) /* grandchild if exec failed or child if fork failed */
|
|
||||||
{
|
|
||||||
status = pid ? STATUS_NO_MEMORY : STATUS_ACCESS_DENIED; /* FIXME: FILE_GetNtStatus() */
|
|
||||||
write( fd[1], &status, sizeof(status) );
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
_exit(0); /* child if fork succeeded */
|
|
||||||
}
|
|
||||||
HeapFree( GetProcessHeap(), 0, argv );
|
|
||||||
HeapFree( GetProcessHeap(), 0, envp );
|
|
||||||
RtlFreeAnsiString( &unix_name );
|
|
||||||
if (stdin_fd != -1) close( stdin_fd );
|
|
||||||
if (stdout_fd != -1) close( stdout_fd );
|
|
||||||
if (stderr_fd != -1) close( stderr_fd );
|
|
||||||
close( fd[1] );
|
|
||||||
if (pid != -1)
|
|
||||||
{
|
|
||||||
/* reap child */
|
|
||||||
do {
|
|
||||||
err = waitpid(pid, NULL, 0);
|
|
||||||
} while (err < 0 && errno == EINTR);
|
|
||||||
read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
|
|
||||||
}
|
|
||||||
else status = STATUS_NO_MEMORY;
|
|
||||||
close( fd[0] );
|
|
||||||
return status;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* create_process_params
|
* create_process_params
|
||||||
*/
|
*/
|
||||||
|
@ -876,7 +547,6 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||||
LPSTARTUPINFOW startup_info, LPPROCESS_INFORMATION info,
|
LPSTARTUPINFOW startup_info, LPPROCESS_INFORMATION info,
|
||||||
HANDLE *new_token )
|
HANDLE *new_token )
|
||||||
{
|
{
|
||||||
char *unixdir = NULL;
|
|
||||||
WCHAR name[MAX_PATH];
|
WCHAR name[MAX_PATH];
|
||||||
WCHAR *p, *tidy_cmdline = cmd_line;
|
WCHAR *p, *tidy_cmdline = cmd_line;
|
||||||
RTL_USER_PROCESS_PARAMETERS *params = NULL;
|
RTL_USER_PROCESS_PARAMETERS *params = NULL;
|
||||||
|
@ -915,17 +585,13 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||||
|
|
||||||
if (cur_dir)
|
if (cur_dir)
|
||||||
{
|
{
|
||||||
if (!(unixdir = wine_get_unix_file_name( cur_dir )))
|
DWORD attr = GetFileAttributesW( cur_dir );
|
||||||
|
if (attr == INVALID_FILE_ATTRIBUTES || !(attr & FILE_ATTRIBUTE_DIRECTORY))
|
||||||
{
|
{
|
||||||
status = STATUS_NOT_A_DIRECTORY;
|
status = STATUS_NOT_A_DIRECTORY;
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
|
||||||
{
|
|
||||||
WCHAR buf[MAX_PATH];
|
|
||||||
if (GetCurrentDirectoryW(MAX_PATH, buf)) unixdir = wine_get_unix_file_name( buf );
|
|
||||||
}
|
|
||||||
|
|
||||||
info->hThread = info->hProcess = 0;
|
info->hThread = info->hProcess = 0;
|
||||||
info->dwProcessId = info->dwThreadId = 0;
|
info->dwProcessId = info->dwThreadId = 0;
|
||||||
|
@ -949,24 +615,17 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||||
break;
|
break;
|
||||||
case STATUS_INVALID_IMAGE_NOT_MZ:
|
case STATUS_INVALID_IMAGE_NOT_MZ:
|
||||||
/* check for .com or .bat extension */
|
/* check for .com or .bat extension */
|
||||||
if ((p = strrchrW( app_name, '.' )))
|
if (!(p = strrchrW( app_name, '.' ))) break;
|
||||||
|
if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW ))
|
||||||
{
|
{
|
||||||
if (!strcmpiW( p, comW ) || !strcmpiW( p, pifW ))
|
TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) );
|
||||||
{
|
status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
|
||||||
TRACE( "starting %s as DOS binary\n", debugstr_w(app_name) );
|
}
|
||||||
status = create_vdm_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
|
else if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ))
|
||||||
break;
|
{
|
||||||
}
|
TRACE( "starting %s as batch binary\n", debugstr_w(app_name) );
|
||||||
if (!strcmpiW( p, batW ) || !strcmpiW( p, cmdW ))
|
status = create_cmd_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
|
||||||
{
|
|
||||||
TRACE( "starting %s as batch binary\n", debugstr_w(app_name) );
|
|
||||||
status = create_cmd_process( process_attr, thread_attr, inherit, flags, params, &rtl_info );
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
/* unknown file, try as unix executable */
|
|
||||||
TRACE( "starting %s as Unix binary\n", debugstr_w(app_name) );
|
|
||||||
status = fork_and_exec( params, unixdir );
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -983,7 +642,6 @@ BOOL WINAPI CreateProcessInternalW( HANDLE token, LPCWSTR app_name, LPWSTR cmd_l
|
||||||
done:
|
done:
|
||||||
RtlDestroyProcessParameters( params );
|
RtlDestroyProcessParameters( params );
|
||||||
if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
|
if (tidy_cmdline != cmd_line) HeapFree( GetProcessHeap(), 0, tidy_cmdline );
|
||||||
HeapFree( GetProcessHeap(), 0, unixdir );
|
|
||||||
return set_ntstatus( status );
|
return set_ntstatus( status );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -508,6 +508,74 @@ static WCHAR *build_initial_environment( char **env )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* build_envp
|
||||||
|
*
|
||||||
|
* Build the environment of a new child process.
|
||||||
|
*/
|
||||||
|
char **build_envp( const WCHAR *envW )
|
||||||
|
{
|
||||||
|
static const char * const unix_vars[] = { "PATH", "TEMP", "TMP", "HOME" };
|
||||||
|
char **envp;
|
||||||
|
char *env, *p;
|
||||||
|
int count = 1, length, lenW;
|
||||||
|
unsigned int i;
|
||||||
|
|
||||||
|
lenW = get_env_length( envW );
|
||||||
|
length = ntdll_wcstoumbs( 0, envW, lenW, NULL, 0, NULL, NULL );
|
||||||
|
if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, length ))) return NULL;
|
||||||
|
ntdll_wcstoumbs( 0, envW, lenW, env, length, NULL, NULL );
|
||||||
|
|
||||||
|
for (p = env; *p; p += strlen(p) + 1)
|
||||||
|
if (is_special_env_var( p )) length += 4; /* prefix it with "WINE" */
|
||||||
|
|
||||||
|
for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
|
||||||
|
{
|
||||||
|
if (!(p = getenv(unix_vars[i]))) continue;
|
||||||
|
length += strlen(unix_vars[i]) + strlen(p) + 2;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((envp = RtlAllocateHeap( GetProcessHeap(), 0, count * sizeof(*envp) + length )))
|
||||||
|
{
|
||||||
|
char **envptr = envp;
|
||||||
|
char *dst = (char *)(envp + count);
|
||||||
|
|
||||||
|
/* some variables must not be modified, so we get them directly from the unix env */
|
||||||
|
for (i = 0; i < ARRAY_SIZE( unix_vars ); i++)
|
||||||
|
{
|
||||||
|
if (!(p = getenv( unix_vars[i] ))) continue;
|
||||||
|
*envptr++ = strcpy( dst, unix_vars[i] );
|
||||||
|
strcat( dst, "=" );
|
||||||
|
strcat( dst, p );
|
||||||
|
dst += strlen(dst) + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* now put the Windows environment strings */
|
||||||
|
for (p = env; *p; p += strlen(p) + 1)
|
||||||
|
{
|
||||||
|
if (*p == '=') continue; /* skip drive curdirs, this crashes some unix apps */
|
||||||
|
if (!strncmp( p, "WINEPRELOADRESERVE=", sizeof("WINEPRELOADRESERVE=")-1 )) continue;
|
||||||
|
if (!strncmp( p, "WINELOADERNOEXEC=", sizeof("WINELOADERNOEXEC=")-1 )) continue;
|
||||||
|
if (!strncmp( p, "WINESERVERSOCKET=", sizeof("WINESERVERSOCKET=")-1 )) continue;
|
||||||
|
if (is_special_env_var( p )) /* prefix it with "WINE" */
|
||||||
|
{
|
||||||
|
*envptr++ = strcpy( dst, "WINE" );
|
||||||
|
strcat( dst, p );
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*envptr++ = strcpy( dst, p );
|
||||||
|
}
|
||||||
|
dst += strlen(dst) + 1;
|
||||||
|
}
|
||||||
|
*envptr = 0;
|
||||||
|
}
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, env );
|
||||||
|
return envp;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* get_current_directory
|
* get_current_directory
|
||||||
*
|
*
|
||||||
|
|
|
@ -86,6 +86,7 @@ extern void virtual_init_threading(void) DECLSPEC_HIDDEN;
|
||||||
extern void fill_cpu_info(void) DECLSPEC_HIDDEN;
|
extern void fill_cpu_info(void) DECLSPEC_HIDDEN;
|
||||||
extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN;
|
extern void heap_set_debug_flags( HANDLE handle ) DECLSPEC_HIDDEN;
|
||||||
extern void init_user_process_params( SIZE_T data_size ) DECLSPEC_HIDDEN;
|
extern void init_user_process_params( SIZE_T data_size ) DECLSPEC_HIDDEN;
|
||||||
|
extern char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
|
||||||
extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
|
extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
|
||||||
|
|
||||||
/* server support */
|
/* server support */
|
||||||
|
|
|
@ -1465,6 +1465,101 @@ static char *get_unix_curdir( const RTL_USER_PROCESS_PARAMETERS *params )
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************
|
||||||
|
* fork_and_exec
|
||||||
|
*
|
||||||
|
* Fork and exec a new Unix binary, checking for errors.
|
||||||
|
*/
|
||||||
|
static NTSTATUS fork_and_exec( UNICODE_STRING *path, const RTL_USER_PROCESS_PARAMETERS *params )
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
int fd[2], stdin_fd = -1, stdout_fd = -1;
|
||||||
|
char **argv, **envp;
|
||||||
|
char *unixdir;
|
||||||
|
ANSI_STRING unix_name;
|
||||||
|
NTSTATUS status;
|
||||||
|
|
||||||
|
status = wine_nt_to_unix_file_name( path, &unix_name, FILE_OPEN, FALSE );
|
||||||
|
if (status) return status;
|
||||||
|
|
||||||
|
#ifdef HAVE_PIPE2
|
||||||
|
if (pipe2( fd, O_CLOEXEC ) == -1)
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
if (pipe(fd) == -1)
|
||||||
|
{
|
||||||
|
RtlFreeAnsiString( &unix_name );
|
||||||
|
return STATUS_TOO_MANY_OPENED_FILES;
|
||||||
|
}
|
||||||
|
fcntl( fd[0], F_SETFD, FD_CLOEXEC );
|
||||||
|
fcntl( fd[1], F_SETFD, FD_CLOEXEC );
|
||||||
|
}
|
||||||
|
|
||||||
|
wine_server_handle_to_fd( params->hStdInput, FILE_READ_DATA, &stdin_fd, NULL );
|
||||||
|
wine_server_handle_to_fd( params->hStdOutput, FILE_WRITE_DATA, &stdout_fd, NULL );
|
||||||
|
|
||||||
|
argv = build_argv( ¶ms->CommandLine, 0 );
|
||||||
|
envp = build_envp( params->Environment );
|
||||||
|
unixdir = get_unix_curdir( params );
|
||||||
|
|
||||||
|
if (!(pid = fork())) /* child */
|
||||||
|
{
|
||||||
|
if (!(pid = fork())) /* grandchild */
|
||||||
|
{
|
||||||
|
close( fd[0] );
|
||||||
|
|
||||||
|
if (params->ConsoleFlags ||
|
||||||
|
params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
|
||||||
|
(params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
|
||||||
|
{
|
||||||
|
setsid();
|
||||||
|
set_stdio_fd( -1, -1 ); /* close stdin and stdout */
|
||||||
|
}
|
||||||
|
else set_stdio_fd( stdin_fd, stdout_fd );
|
||||||
|
|
||||||
|
if (stdin_fd != -1) close( stdin_fd );
|
||||||
|
if (stdout_fd != -1) close( stdout_fd );
|
||||||
|
|
||||||
|
/* Reset signals that we previously set to SIG_IGN */
|
||||||
|
signal( SIGPIPE, SIG_DFL );
|
||||||
|
|
||||||
|
if (unixdir) chdir( unixdir );
|
||||||
|
|
||||||
|
if (argv && envp) execve( unix_name.Buffer, argv, envp );
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pid <= 0) /* grandchild if exec failed or child if fork failed */
|
||||||
|
{
|
||||||
|
status = FILE_GetNtStatus();
|
||||||
|
write( fd[1], &status, sizeof(status) );
|
||||||
|
_exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
_exit(0); /* child if fork succeeded */
|
||||||
|
}
|
||||||
|
close( fd[1] );
|
||||||
|
|
||||||
|
if (pid != -1)
|
||||||
|
{
|
||||||
|
/* reap child */
|
||||||
|
pid_t wret;
|
||||||
|
do {
|
||||||
|
wret = waitpid(pid, NULL, 0);
|
||||||
|
} while (wret < 0 && errno == EINTR);
|
||||||
|
read( fd[0], &status, sizeof(status) ); /* if we read something, exec or second fork failed */
|
||||||
|
}
|
||||||
|
else status = FILE_GetNtStatus();
|
||||||
|
|
||||||
|
close( fd[0] );
|
||||||
|
if (stdin_fd != -1) close( stdin_fd );
|
||||||
|
if (stdout_fd != -1) close( stdout_fd );
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, argv );
|
||||||
|
RtlFreeHeap( GetProcessHeap(), 0, envp );
|
||||||
|
RtlFreeAnsiString( &unix_name );
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************
|
/***********************************************************************
|
||||||
* restart_process
|
* restart_process
|
||||||
*/
|
*/
|
||||||
|
@ -1575,7 +1670,15 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
|
||||||
TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
|
TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
|
||||||
debugstr_us( ¶ms->ImagePathName ), debugstr_us( ¶ms->CommandLine ));
|
debugstr_us( ¶ms->ImagePathName ), debugstr_us( ¶ms->CommandLine ));
|
||||||
|
|
||||||
if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info ))) goto done;
|
if ((status = get_pe_file_info( path, attributes, &file_handle, &pe_info )))
|
||||||
|
{
|
||||||
|
if (status == STATUS_INVALID_IMAGE_NOT_MZ && !fork_and_exec( path, params ))
|
||||||
|
{
|
||||||
|
memset( info, 0, sizeof(*info) );
|
||||||
|
return STATUS_SUCCESS;
|
||||||
|
}
|
||||||
|
goto done;
|
||||||
|
}
|
||||||
if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
|
if (!(startup_info = create_startup_info( params, &startup_info_size ))) goto done;
|
||||||
env_size = get_env_size( params, &winedebug );
|
env_size = get_env_size( params, &winedebug );
|
||||||
unixdir = get_unix_curdir( params );
|
unixdir = get_unix_curdir( params );
|
||||||
|
|
Loading…
Reference in New Issue