ntdll: Launch wineboot from the Unix side.
Signed-off-by: Alexandre Julliard <julliard@winehq.org>
This commit is contained in:
parent
d0a1bddea0
commit
0599347e96
181
dlls/ntdll/env.c
181
dlls/ntdll/env.c
|
@ -39,8 +39,6 @@ static const UNICODE_STRING null_str = { 0, 0, NULL };
|
|||
|
||||
static const BOOL is_win64 = (sizeof(void *) > sizeof(int));
|
||||
|
||||
static BOOL first_prefix_start; /* first ever process start in this prefix? */
|
||||
|
||||
static inline SIZE_T get_env_length( const WCHAR *env )
|
||||
{
|
||||
const WCHAR *end = env;
|
||||
|
@ -66,116 +64,6 @@ static void set_env_var( WCHAR **env, const WCHAR *name, const WCHAR *val )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* set_registry_variables
|
||||
*
|
||||
* Set environment variables by enumerating the values of a key;
|
||||
* helper for set_registry_environment().
|
||||
* Note that Windows happily truncates the value if it's too big.
|
||||
*/
|
||||
static void set_registry_variables( WCHAR **env, HANDLE hkey, ULONG type )
|
||||
{
|
||||
static const WCHAR pathW[] = {'P','A','T','H'};
|
||||
UNICODE_STRING env_name, env_value;
|
||||
NTSTATUS status;
|
||||
DWORD size;
|
||||
int index;
|
||||
char buffer[1024*sizeof(WCHAR) + sizeof(KEY_VALUE_FULL_INFORMATION)];
|
||||
WCHAR tmpbuf[1024];
|
||||
UNICODE_STRING tmp;
|
||||
KEY_VALUE_FULL_INFORMATION *info = (KEY_VALUE_FULL_INFORMATION *)buffer;
|
||||
|
||||
tmp.Buffer = tmpbuf;
|
||||
tmp.MaximumLength = sizeof(tmpbuf);
|
||||
|
||||
for (index = 0; ; index++)
|
||||
{
|
||||
status = NtEnumerateValueKey( hkey, index, KeyValueFullInformation,
|
||||
buffer, sizeof(buffer), &size );
|
||||
if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) break;
|
||||
if (info->Type != type) continue;
|
||||
env_name.Buffer = info->Name;
|
||||
env_name.Length = env_name.MaximumLength = info->NameLength;
|
||||
env_value.Buffer = (WCHAR *)(buffer + info->DataOffset);
|
||||
env_value.Length = info->DataLength;
|
||||
env_value.MaximumLength = sizeof(buffer) - info->DataOffset;
|
||||
if (env_value.Length && !env_value.Buffer[env_value.Length/sizeof(WCHAR)-1])
|
||||
env_value.Length -= sizeof(WCHAR); /* don't count terminating null if any */
|
||||
if (!env_value.Length) continue;
|
||||
if (info->Type == REG_EXPAND_SZ)
|
||||
{
|
||||
status = RtlExpandEnvironmentStrings_U( *env, &env_value, &tmp, NULL );
|
||||
if (status != STATUS_SUCCESS && status != STATUS_BUFFER_OVERFLOW) continue;
|
||||
RtlCopyUnicodeString( &env_value, &tmp );
|
||||
}
|
||||
/* PATH is magic */
|
||||
if (env_name.Length == sizeof(pathW) &&
|
||||
!wcsnicmp( env_name.Buffer, pathW, ARRAY_SIZE( pathW )) &&
|
||||
!RtlQueryEnvironmentVariable_U( *env, &env_name, &tmp ))
|
||||
{
|
||||
RtlAppendUnicodeToString( &tmp, L";" );
|
||||
if (RtlAppendUnicodeStringToString( &tmp, &env_value )) continue;
|
||||
RtlCopyUnicodeString( &env_value, &tmp );
|
||||
}
|
||||
RtlSetEnvironmentVariable( env, &env_name, &env_value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* set_registry_environment
|
||||
*
|
||||
* Set the environment variables specified in the registry.
|
||||
*
|
||||
* Note: Windows handles REG_SZ and REG_EXPAND_SZ in one pass with the
|
||||
* consequence that REG_EXPAND_SZ cannot be used reliably as it depends
|
||||
* on the order in which the variables are processed. But on Windows it
|
||||
* does not really matter since they only use %SystemDrive% and
|
||||
* %SystemRoot% which are predefined. But Wine defines these in the
|
||||
* registry, so we need two passes.
|
||||
*/
|
||||
static BOOL set_registry_environment( WCHAR **env, BOOL first_time )
|
||||
{
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
UNICODE_STRING nameW;
|
||||
HANDLE hkey;
|
||||
BOOL ret = FALSE;
|
||||
|
||||
/* first the system environment variables */
|
||||
InitializeObjectAttributes( &attr, &nameW, 0, 0, NULL );
|
||||
RtlInitUnicodeString( &nameW, L"\\Registry\\Machine\\System\\CurrentControlSet\\Control\\"
|
||||
"Session Manager\\Environment" );
|
||||
if (first_time && !NtOpenKey( &hkey, KEY_READ, &attr ))
|
||||
{
|
||||
set_registry_variables( env, hkey, REG_SZ );
|
||||
set_registry_variables( env, hkey, REG_EXPAND_SZ );
|
||||
NtClose( hkey );
|
||||
}
|
||||
else ret = TRUE;
|
||||
|
||||
/* then the ones for the current user */
|
||||
if (RtlOpenCurrentUser( KEY_READ, &attr.RootDirectory ) != STATUS_SUCCESS) return ret;
|
||||
RtlInitUnicodeString( &nameW, L"Environment" );
|
||||
if (first_time && !NtOpenKey( &hkey, KEY_READ, &attr ))
|
||||
{
|
||||
set_registry_variables( env, hkey, REG_SZ );
|
||||
set_registry_variables( env, hkey, REG_EXPAND_SZ );
|
||||
NtClose( hkey );
|
||||
}
|
||||
|
||||
RtlInitUnicodeString( &nameW, L"Volatile Environment" );
|
||||
if (!NtOpenKey( &hkey, KEY_READ, &attr ))
|
||||
{
|
||||
set_registry_variables( env, hkey, REG_SZ );
|
||||
set_registry_variables( env, hkey, REG_EXPAND_SZ );
|
||||
NtClose( hkey );
|
||||
}
|
||||
|
||||
NtClose( attr.RootDirectory );
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* get_registry_value
|
||||
*/
|
||||
|
@ -933,72 +821,6 @@ void WINAPI RtlDestroyProcessParameters( RTL_USER_PROCESS_PARAMETERS *params )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* run_wineboot
|
||||
*/
|
||||
static void run_wineboot( WCHAR **env )
|
||||
{
|
||||
UNICODE_STRING nameW, cmdlineW, dllpathW;
|
||||
RTL_USER_PROCESS_PARAMETERS *params;
|
||||
RTL_USER_PROCESS_INFORMATION info;
|
||||
WCHAR *load_path, *dummy;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER timeout;
|
||||
HANDLE handles[2];
|
||||
NTSTATUS status;
|
||||
ULONG redir = 0;
|
||||
int count = 1;
|
||||
|
||||
RtlInitUnicodeString( &nameW, L"\\KernelObjects\\__wineboot_event" );
|
||||
InitializeObjectAttributes( &attr, &nameW, OBJ_OPENIF, 0, NULL );
|
||||
|
||||
status = NtCreateEvent( &handles[0], EVENT_ALL_ACCESS, &attr, NotificationEvent, 0 );
|
||||
if (status == STATUS_OBJECT_NAME_EXISTS) goto wait;
|
||||
if (status)
|
||||
{
|
||||
ERR( "failed to create wineboot event, expect trouble\n" );
|
||||
return;
|
||||
}
|
||||
LdrGetDllPath( L"C:\\windows\\system32\\wineboot.exe", LOAD_WITH_ALTERED_SEARCH_PATH,
|
||||
&load_path, &dummy );
|
||||
RtlInitUnicodeString( &nameW, L"C:\\windows\\system32\\wineboot.exe" );
|
||||
RtlInitUnicodeString( &dllpathW, load_path );
|
||||
RtlInitUnicodeString( &cmdlineW, L"C:\\windows\\system32\\wineboot.exe --init" );
|
||||
RtlCreateProcessParametersEx( ¶ms, &nameW, &dllpathW, NULL, &cmdlineW, *env, NULL, NULL,
|
||||
NULL, NULL, PROCESS_PARAMS_FLAG_NORMALIZED );
|
||||
params->hStdInput = 0;
|
||||
params->hStdOutput = 0;
|
||||
params->hStdError = NtCurrentTeb()->Peb->ProcessParameters->hStdError;
|
||||
|
||||
RtlInitUnicodeString( &nameW, L"\\??\\C:\\windows\\system32\\wineboot.exe" );
|
||||
RtlWow64EnableFsRedirectionEx( TRUE, &redir );
|
||||
status = RtlCreateUserProcess( &nameW, OBJ_CASE_INSENSITIVE, params,
|
||||
NULL, NULL, 0, FALSE, 0, 0, &info );
|
||||
RtlWow64EnableFsRedirection( !redir );
|
||||
RtlReleasePath( load_path );
|
||||
RtlDestroyProcessParameters( params );
|
||||
if (status)
|
||||
{
|
||||
ERR( "failed to start wineboot %x\n", status );
|
||||
NtClose( handles[0] );
|
||||
return;
|
||||
}
|
||||
NtResumeThread( info.Thread, NULL );
|
||||
NtClose( info.Thread );
|
||||
handles[count++] = info.Process;
|
||||
|
||||
wait:
|
||||
timeout.QuadPart = (ULONGLONG)(first_prefix_start ? 5 : 2) * 60 * 1000 * -10000;
|
||||
if (NtWaitForMultipleObjects( count, handles, TRUE, FALSE, &timeout ) == WAIT_TIMEOUT)
|
||||
ERR( "boot event wait timed out\n" );
|
||||
while (count) NtClose( handles[--count] );
|
||||
|
||||
/* reload environment now that wineboot has run */
|
||||
set_registry_environment( env, first_prefix_start );
|
||||
set_additional_environment( env );
|
||||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* init_user_process_params
|
||||
*
|
||||
|
@ -1023,7 +845,6 @@ void init_user_process_params(void)
|
|||
|
||||
if (!params->DllPath.MaximumLength) /* not inherited from parent process */
|
||||
{
|
||||
first_prefix_start = !ENV_FindVariable( params->Environment, L"COMSPEC", 7 );
|
||||
set_additional_environment( ¶ms->Environment );
|
||||
|
||||
get_image_path( params->ImagePathName.Buffer, image, sizeof(image) );
|
||||
|
@ -1058,8 +879,6 @@ void init_user_process_params(void)
|
|||
|
||||
RtlFreeUnicodeString( &cmdline );
|
||||
RtlReleasePath( load_path );
|
||||
|
||||
run_wineboot( ¶ms->Environment );
|
||||
}
|
||||
|
||||
if (RtlSetCurrentDirectory_U( ¶ms->CurrentDirectory.DosPath ))
|
||||
|
|
|
@ -1597,6 +1597,93 @@ static WCHAR *build_command_line( WCHAR **wargv )
|
|||
}
|
||||
|
||||
|
||||
/***********************************************************************
|
||||
* run_wineboot
|
||||
*/
|
||||
static void run_wineboot( WCHAR *env, SIZE_T size )
|
||||
{
|
||||
static const WCHAR eventW[] = {'\\','K','e','r','n','e','l','O','b','j','e','c','t','s',
|
||||
'\\','_','_','w','i','n','e','b','o','o','t','_','e','v','e','n','t',0};
|
||||
static const WCHAR appnameW[] = {'\\','?','?','\\','C',':','\\','w','i','n','d','o','w','s',
|
||||
'\\','s','y','s','t','e','m','3','2','\\','w','i','n','e','b','o','o','t','.','e','x','e',0};
|
||||
static const WCHAR cmdlineW[] = {'"','C',':','\\','w','i','n','d','o','w','s','\\',
|
||||
's','y','s','t','e','m','3','2','\\','w','i','n','e','b','o','o','t','.','e','x','e','"',
|
||||
' ','-','-','i','n','i','t',0};
|
||||
static const WCHAR sysdirW[] = {'C',':','\\','w','i','n','d','o','w','s',
|
||||
'\\','s','y','s','t','e','m','3','2',0};
|
||||
RTL_USER_PROCESS_PARAMETERS params = { sizeof(params), sizeof(params) };
|
||||
PS_ATTRIBUTE_LIST ps_attr;
|
||||
PS_CREATE_INFO create_info;
|
||||
HANDLE process, thread, handles[2];
|
||||
UNICODE_STRING nameW;
|
||||
OBJECT_ATTRIBUTES attr;
|
||||
LARGE_INTEGER timeout;
|
||||
NTSTATUS status;
|
||||
int count = 1;
|
||||
|
||||
init_unicode_string( &nameW, eventW );
|
||||
InitializeObjectAttributes( &attr, &nameW, OBJ_OPENIF, 0, NULL );
|
||||
status = NtCreateEvent( &handles[0], EVENT_ALL_ACCESS, &attr, NotificationEvent, 0 );
|
||||
if (status == STATUS_OBJECT_NAME_EXISTS) goto wait;
|
||||
if (status)
|
||||
{
|
||||
ERR( "failed to create wineboot event, expect trouble\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
env[size] = 0;
|
||||
params.Flags = PROCESS_PARAMS_FLAG_NORMALIZED;
|
||||
params.Environment = env;
|
||||
params.EnvironmentSize = size;
|
||||
init_unicode_string( ¶ms.CurrentDirectory.DosPath, sysdirW );
|
||||
init_unicode_string( ¶ms.DllPath, sysdirW );
|
||||
init_unicode_string( ¶ms.ImagePathName, appnameW + 4 );
|
||||
init_unicode_string( ¶ms.CommandLine, cmdlineW );
|
||||
init_unicode_string( ¶ms.WindowTitle, appnameW + 4 );
|
||||
init_unicode_string( &nameW, appnameW );
|
||||
|
||||
ps_attr.TotalLength = sizeof(ps_attr);
|
||||
ps_attr.Attributes[0].Attribute = PS_ATTRIBUTE_IMAGE_NAME;
|
||||
ps_attr.Attributes[0].Size = sizeof(appnameW) - sizeof(WCHAR);
|
||||
ps_attr.Attributes[0].ValuePtr = (WCHAR *)appnameW;
|
||||
ps_attr.Attributes[0].ReturnLength = NULL;
|
||||
|
||||
wine_server_fd_to_handle( 2, GENERIC_WRITE | SYNCHRONIZE, OBJ_INHERIT, ¶ms.hStdError );
|
||||
|
||||
#ifndef _WIN64
|
||||
if (NtCurrentTeb64() && !NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR])
|
||||
{
|
||||
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = TRUE;
|
||||
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
||||
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
||||
&create_info, &ps_attr );
|
||||
NtCurrentTeb64()->TlsSlots[WOW64_TLS_FILESYSREDIR] = FALSE;
|
||||
}
|
||||
else
|
||||
#endif
|
||||
status = NtCreateUserProcess( &process, &thread, PROCESS_ALL_ACCESS, THREAD_ALL_ACCESS,
|
||||
NULL, NULL, 0, THREAD_CREATE_FLAGS_CREATE_SUSPENDED, ¶ms,
|
||||
&create_info, &ps_attr );
|
||||
NtClose( params.hStdError );
|
||||
|
||||
if (status)
|
||||
{
|
||||
ERR( "failed to start wineboot %x\n", status );
|
||||
NtClose( handles[0] );
|
||||
return;
|
||||
}
|
||||
NtResumeThread( thread, NULL );
|
||||
NtClose( thread );
|
||||
handles[count++] = process;
|
||||
|
||||
wait:
|
||||
timeout.QuadPart = (ULONGLONG)5 * 60 * 1000 * -10000;
|
||||
if (NtWaitForMultipleObjects( count, handles, TRUE, FALSE, &timeout ) == WAIT_TIMEOUT)
|
||||
ERR( "boot event wait timed out\n" );
|
||||
while (count) NtClose( handles[--count] );
|
||||
}
|
||||
|
||||
|
||||
static inline void copy_unicode_string( WCHAR **src, WCHAR **dst, UNICODE_STRING *str, UINT len )
|
||||
{
|
||||
str->Buffer = *dst;
|
||||
|
@ -1630,6 +1717,10 @@ static RTL_USER_PROCESS_PARAMETERS *build_initial_params(void)
|
|||
|
||||
add_dynamic_environment( &env, &env_pos, &env_size );
|
||||
add_registry_environment( &env, &env_pos, &env_size );
|
||||
env[env_pos] = 0;
|
||||
run_wineboot( env, env_pos );
|
||||
/* reload environment now that wineboot has run */
|
||||
add_registry_environment( &env, &env_pos, &env_size );
|
||||
env[env_pos++] = 0;
|
||||
|
||||
size = (sizeof(*params)
|
||||
|
|
Loading…
Reference in New Issue