Commit eee3a4e8 authored by Alexandre Julliard's avatar Alexandre Julliard

kernel32: Move support for starting Unix processes to ntdll.

parent 1deefb84
......@@ -509,6 +509,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
*
* Initialize the current directory from the Unix cwd.
......
......@@ -86,6 +86,7 @@ extern void virtual_init_threading(void) DECLSPEC_HIDDEN;
extern void fill_cpu_info(void) 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 char **build_envp( const WCHAR *envW ) DECLSPEC_HIDDEN;
extern NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status ) DECLSPEC_HIDDEN;
/* server support */
......
......@@ -1466,6 +1466,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( &params->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
*/
NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status )
......@@ -1575,7 +1670,15 @@ NTSTATUS WINAPI RtlCreateUserProcess( UNICODE_STRING *path, ULONG attributes,
TRACE( "%s image %s cmdline %s\n", debugstr_us( path ),
debugstr_us( &params->ImagePathName ), debugstr_us( &params->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;
env_size = get_env_size( params, &winedebug );
unixdir = get_unix_curdir( params );
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment