ntdll: Add a helper to exec wineloader.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
68a425b19c
commit
9fd2330a96
|
@ -113,6 +113,7 @@ extern size_t dll_path_maxlen DECLSPEC_HIDDEN;
|
|||
extern timeout_t server_start_time DECLSPEC_HIDDEN;
|
||||
extern unsigned int server_cpus DECLSPEC_HIDDEN;
|
||||
extern BOOL is_wow64 DECLSPEC_HIDDEN;
|
||||
extern NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info ) DECLSPEC_HIDDEN;
|
||||
extern void server_init_process(void) DECLSPEC_HIDDEN;
|
||||
extern void server_init_process_done(void) DECLSPEC_HIDDEN;
|
||||
extern size_t server_init_thread( void *entry_point, BOOL *suspend ) DECLSPEC_HIDDEN;
|
||||
|
|
|
@ -51,7 +51,6 @@
|
|||
#include "winternl.h"
|
||||
#include "ntdll_misc.h"
|
||||
#include "wine/exception.h"
|
||||
#include "wine/library.h"
|
||||
#include "wine/server.h"
|
||||
|
||||
#ifdef HAVE_MACH_MACH_H
|
||||
|
@ -68,10 +67,6 @@ static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
|
|||
|
||||
static const char * const cpu_names[] = { "x86", "x86_64", "PowerPC", "ARM", "ARM64" };
|
||||
|
||||
static inline BOOL is_64bit_arch( client_cpu_t cpu )
|
||||
{
|
||||
return (cpu == CPU_x86_64 || cpu == CPU_ARM64);
|
||||
}
|
||||
|
||||
/*
|
||||
* Process object
|
||||
|
@ -995,51 +990,6 @@ static startup_info_t *create_startup_info( const RTL_USER_PROCESS_PARAMETERS *p
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_alternate_loader
|
||||
*
|
||||
* Get the name of the alternate (32 or 64 bit) Wine loader.
|
||||
*/
|
||||
static const char *get_alternate_loader( char **ret_env )
|
||||
{
|
||||
char *env;
|
||||
const char *loader = NULL;
|
||||
const char *loader_env = getenv( "WINELOADER" );
|
||||
|
||||
*ret_env = NULL;
|
||||
|
||||
if (build_dir) loader = is_win64 ? "loader/wine" : "loader/wine64";
|
||||
|
||||
if (loader_env)
|
||||
{
|
||||
int len = strlen( loader_env );
|
||||
if (!is_win64)
|
||||
{
|
||||
if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len + 2 ))) return NULL;
|
||||
strcpy( env, "WINELOADER=" );
|
||||
strcat( env, loader_env );
|
||||
strcat( env, "64" );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!(env = RtlAllocateHeap( GetProcessHeap(), 0, sizeof("WINELOADER=") + len ))) return NULL;
|
||||
strcpy( env, "WINELOADER=" );
|
||||
strcat( env, loader_env );
|
||||
len += sizeof("WINELOADER=") - 1;
|
||||
if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0;
|
||||
}
|
||||
if (!loader)
|
||||
{
|
||||
if ((loader = strrchr( env, '/' ))) loader++;
|
||||
else loader = env;
|
||||
}
|
||||
*ret_env = env;
|
||||
}
|
||||
if (!loader) loader = is_win64 ? "wine" : "wine64";
|
||||
return loader;
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
/***********************************************************************
|
||||
* terminate_main_thread
|
||||
|
@ -1117,15 +1067,10 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc
|
|||
{
|
||||
pid_t pid;
|
||||
int stdin_fd = -1, stdout_fd = -1;
|
||||
char *wineloader = NULL;
|
||||
const char *loader = NULL;
|
||||
char **argv;
|
||||
NTSTATUS status = STATUS_SUCCESS;
|
||||
|
||||
argv = build_argv( ¶ms->CommandLine, 1 );
|
||||
|
||||
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
|
||||
loader = get_alternate_loader( &wineloader );
|
||||
argv = build_argv( ¶ms->CommandLine, 2 );
|
||||
|
||||
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 );
|
||||
|
@ -1134,10 +1079,6 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc
|
|||
{
|
||||
if (!(pid = fork())) /* grandchild */
|
||||
{
|
||||
char preloader_reserve[64], socket_env[64];
|
||||
ULONGLONG res_start = pe_info->base;
|
||||
ULONGLONG res_end = pe_info->base + pe_info->map_size;
|
||||
|
||||
if (params->ConsoleFlags ||
|
||||
params->ConsoleHandle == (HANDLE)1 /* KERNEL32_CONSOLE_ALLOC */ ||
|
||||
(params->hStdInput == INVALID_HANDLE_VALUE && params->hStdOutput == INVALID_HANDLE_VALUE))
|
||||
|
@ -1150,20 +1091,10 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc
|
|||
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 );
|
||||
|
||||
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
|
||||
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
|
||||
(ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
|
||||
|
||||
putenv( preloader_reserve );
|
||||
putenv( socket_env );
|
||||
if (winedebug) putenv( winedebug );
|
||||
if (wineloader) putenv( wineloader );
|
||||
if (unixdir) chdir( unixdir );
|
||||
|
||||
if (argv) wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
|
||||
exec_wineloader( argv, socketfd, pe_info );
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
@ -1182,56 +1113,11 @@ static NTSTATUS spawn_loader( const RTL_USER_PROCESS_PARAMETERS *params, int soc
|
|||
|
||||
if (stdin_fd != -1) close( stdin_fd );
|
||||
if (stdout_fd != -1) close( stdout_fd );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, wineloader );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, argv );
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* exec_loader
|
||||
*/
|
||||
static NTSTATUS exec_loader( const UNICODE_STRING *cmdline, int socketfd, const pe_image_info_t *pe_info )
|
||||
{
|
||||
char *wineloader = NULL;
|
||||
const char *loader = NULL;
|
||||
char **argv;
|
||||
char preloader_reserve[64], socket_env[64];
|
||||
ULONGLONG res_start = pe_info->base;
|
||||
ULONGLONG res_end = pe_info->base + pe_info->map_size;
|
||||
|
||||
if (!(argv = build_argv( cmdline, 1 ))) return STATUS_NO_MEMORY;
|
||||
|
||||
if (!is_win64 ^ !is_64bit_arch( pe_info->cpu ))
|
||||
loader = get_alternate_loader( &wineloader );
|
||||
|
||||
/* Reset signals that we previously set to SIG_IGN */
|
||||
signal( SIGPIPE, SIG_DFL );
|
||||
|
||||
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
|
||||
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
|
||||
(ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
|
||||
|
||||
putenv( preloader_reserve );
|
||||
putenv( socket_env );
|
||||
if (wineloader) putenv( wineloader );
|
||||
|
||||
do
|
||||
{
|
||||
wine_exec_wine_binary( loader, argv, getenv("WINELOADER") );
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
while (errno == ENOTSUP && terminate_main_thread());
|
||||
#else
|
||||
while (0);
|
||||
#endif
|
||||
|
||||
RtlFreeHeap( GetProcessHeap(), 0, wineloader );
|
||||
RtlFreeHeap( GetProcessHeap(), 0, argv );
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
/***************************************************************************
|
||||
* is_builtin_path
|
||||
*/
|
||||
|
@ -1636,7 +1522,24 @@ NTSTATUS restart_process( RTL_USER_PROCESS_PARAMETERS *params, NTSTATUS status )
|
|||
}
|
||||
SERVER_END_REQ;
|
||||
|
||||
if (!status) status = exec_loader( &strW, socketfd[0], &pe_info );
|
||||
if (!status)
|
||||
{
|
||||
char **argv = build_argv( &strW, 2 );
|
||||
if (argv)
|
||||
{
|
||||
do
|
||||
{
|
||||
status = exec_wineloader( argv, socketfd[0], &pe_info );
|
||||
}
|
||||
#ifdef __APPLE__
|
||||
while (errno == ENOTSUP && terminate_main_thread());
|
||||
#else
|
||||
while (0);
|
||||
#endif
|
||||
RtlFreeHeap( GetProcessHeap(), 0, argv );
|
||||
}
|
||||
else status = STATUS_NO_MEMORY;
|
||||
}
|
||||
close( socketfd[0] );
|
||||
return status;
|
||||
}
|
||||
|
|
|
@ -75,6 +75,13 @@
|
|||
#ifdef HAVE_UNISTD_H
|
||||
# include <unistd.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <crt_externs.h>
|
||||
#include <spawn.h>
|
||||
#ifndef _POSIX_SPAWN_DISABLE_ASLR
|
||||
#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "ntstatus.h"
|
||||
#define WIN32_NO_STATUS
|
||||
|
@ -113,6 +120,12 @@ static const enum cpu_type client_cpu = CPU_ARM64;
|
|||
#error Unsupported CPU
|
||||
#endif
|
||||
|
||||
#if defined(linux) || defined(__APPLE__)
|
||||
static const BOOL use_preloader = TRUE;
|
||||
#else
|
||||
static const BOOL use_preloader = FALSE;
|
||||
#endif
|
||||
|
||||
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
|
||||
|
||||
const char *build_dir = NULL;
|
||||
|
@ -122,6 +135,7 @@ const char **dll_paths = NULL;
|
|||
size_t dll_path_maxlen = 0;
|
||||
static const char *server_dir;
|
||||
static const char *bin_dir;
|
||||
static const char *argv0;
|
||||
|
||||
unsigned int server_cpus = 0;
|
||||
BOOL is_wow64 = FALSE;
|
||||
|
@ -1218,6 +1232,119 @@ int server_pipe( int fd[2] )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* preloader_exec
|
||||
*/
|
||||
static void preloader_exec( char **argv )
|
||||
{
|
||||
if (use_preloader)
|
||||
{
|
||||
static const char *preloader = "wine-preloader";
|
||||
char *p;
|
||||
|
||||
if (!(p = strrchr( argv[1], '/' ))) p = argv[1];
|
||||
else p++;
|
||||
|
||||
if (strlen(p) > 2 && !strcmp( p + strlen(p) - 2, "64" )) preloader = "wine64-preloader";
|
||||
argv[0] = malloc( p - argv[1] + strlen(preloader) + 1 );
|
||||
memcpy( argv[0], argv[1], p - argv[1] );
|
||||
strcpy( argv[0] + (p - argv[1]), preloader );
|
||||
|
||||
#ifdef __APPLE__
|
||||
{
|
||||
posix_spawnattr_t attr;
|
||||
posix_spawnattr_init( &attr );
|
||||
posix_spawnattr_setflags( &attr, POSIX_SPAWN_SETEXEC | _POSIX_SPAWN_DISABLE_ASLR );
|
||||
posix_spawn( NULL, argv[0], NULL, &attr, argv, *_NSGetEnviron() );
|
||||
posix_spawnattr_destroy( &attr );
|
||||
}
|
||||
#endif
|
||||
execv( argv[0], argv );
|
||||
free( argv[0] );
|
||||
}
|
||||
execv( argv[1], argv + 1 );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* exec_wineloader
|
||||
*
|
||||
* argv[0] and argv[1] must be reserved for the preloader and loader respectively.
|
||||
*/
|
||||
NTSTATUS exec_wineloader( char **argv, int socketfd, const pe_image_info_t *pe_info )
|
||||
{
|
||||
const int is_child_64bit = (pe_info->cpu == CPU_x86_64 || pe_info->cpu == CPU_ARM64);
|
||||
const char *path, *loader = argv0;
|
||||
const char *loader_env = getenv( "WINELOADER" );
|
||||
char *p, preloader_reserve[64], socket_env[64];
|
||||
ULONGLONG res_start = pe_info->base;
|
||||
ULONGLONG res_end = pe_info->base + pe_info->map_size;
|
||||
|
||||
if (!is_win64 ^ !is_child_64bit)
|
||||
{
|
||||
/* remap WINELOADER to the alternate 32/64-bit version if necessary */
|
||||
if (loader_env)
|
||||
{
|
||||
int len = strlen( loader_env );
|
||||
char *env = malloc( sizeof("WINELOADER=") + len + 2 );
|
||||
|
||||
if (!env) return STATUS_NO_MEMORY;
|
||||
strcpy( env, "WINELOADER=" );
|
||||
strcat( env, loader_env );
|
||||
if (is_child_64bit)
|
||||
{
|
||||
strcat( env, "64" );
|
||||
}
|
||||
else
|
||||
{
|
||||
len += sizeof("WINELOADER=") - 1;
|
||||
if (!strcmp( env + len - 2, "64" )) env[len - 2] = 0;
|
||||
}
|
||||
loader = env;
|
||||
putenv( env );
|
||||
}
|
||||
else loader = is_child_64bit ? "wine64" : "wine";
|
||||
}
|
||||
|
||||
signal( SIGPIPE, SIG_DFL );
|
||||
|
||||
sprintf( socket_env, "WINESERVERSOCKET=%u", socketfd );
|
||||
sprintf( preloader_reserve, "WINEPRELOADRESERVE=%x%08x-%x%08x",
|
||||
(ULONG)(res_start >> 32), (ULONG)res_start, (ULONG)(res_end >> 32), (ULONG)res_end );
|
||||
|
||||
putenv( preloader_reserve );
|
||||
putenv( socket_env );
|
||||
|
||||
if (build_dir)
|
||||
{
|
||||
argv[1] = build_path( build_dir, is_child_64bit ? "loader/wine64" : "loader/wine" );
|
||||
preloader_exec( argv );
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
|
||||
if ((p = strrchr( loader, '/' ))) loader = p + 1;
|
||||
|
||||
argv[1] = build_path( bin_dir, loader );
|
||||
preloader_exec( argv );
|
||||
|
||||
argv[1] = getenv( "WINELOADER" );
|
||||
if (argv[1]) preloader_exec( argv );
|
||||
|
||||
if ((path = getenv( "PATH" )))
|
||||
{
|
||||
for (p = strtok( strdup( path ), ":" ); p; p = strtok( NULL, ":" ))
|
||||
{
|
||||
argv[1] = build_path( p, loader );
|
||||
preloader_exec( argv );
|
||||
}
|
||||
}
|
||||
|
||||
argv[1] = build_path( BINDIR, loader );
|
||||
preloader_exec( argv );
|
||||
return STATUS_INVALID_IMAGE_FORMAT;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* exec_wineserver
|
||||
*
|
||||
|
@ -1402,12 +1529,14 @@ void init_paths(void)
|
|||
dll_dir = realpath_dirname( info.dli_fname );
|
||||
#endif
|
||||
|
||||
argv0 = strdup( __wine_main_argv[0] );
|
||||
|
||||
#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
|
||||
bin_dir = realpath_dirname( "/proc/self/exe" );
|
||||
#elif defined (__FreeBSD__) || defined(__DragonFly__)
|
||||
bin_dir = realpath_dirname( "/proc/curproc/file" );
|
||||
#else
|
||||
bin_dir = realpath_dirname( __wine_main_argv[0] );
|
||||
bin_dir = realpath_dirname( argv0 );
|
||||
#endif
|
||||
|
||||
if (dll_dir) build_dir = remove_tail( dll_dir, "/dlls/ntdll" );
|
||||
|
|
Loading…
Reference in New Issue