From ee5c842e5303c70e88a1c68390c46db1f1689f19 Mon Sep 17 00:00:00 2001 From: Alexandre Julliard Date: Thu, 11 Jun 2020 10:50:11 +0200 Subject: [PATCH] ntdll: Move the creation of the initial environment to the Unix library. Signed-off-by: Alexandre Julliard --- dlls/ntdll/Makefile.in | 1 + dlls/ntdll/env.c | 102 +----- dlls/ntdll/unix/env.c | 606 +++++++++++++++++++++++++++++++++ dlls/ntdll/unix/loader.c | 236 +------------ dlls/ntdll/unix/unix_private.h | 23 ++ dlls/ntdll/unixlib.h | 3 +- 6 files changed, 651 insertions(+), 320 deletions(-) create mode 100644 dlls/ntdll/unix/env.c diff --git a/dlls/ntdll/Makefile.in b/dlls/ntdll/Makefile.in index 36edde9388c..24e76236ad5 100644 --- a/dlls/ntdll/Makefile.in +++ b/dlls/ntdll/Makefile.in @@ -51,6 +51,7 @@ C_SRCS = \ threadpool.c \ time.c \ unix/debug.c \ + unix/env.c \ unix/loader.c \ unix/server.c \ unix/signal_arm.c \ diff --git a/dlls/ntdll/env.c b/dlls/ntdll/env.c index 6b32f4d57ea..992ec19fae5 100644 --- a/dlls/ntdll/env.c +++ b/dlls/ntdll/env.c @@ -483,41 +483,17 @@ static void set_wow64_environment( WCHAR **env ) * * Build the Win32 environment from the Unix environment */ -static WCHAR *build_initial_environment( char **env ) +static WCHAR *build_initial_environment( WCHAR **wargv[] ) { - SIZE_T size = 1; - char **e; - WCHAR *p, *ptr; + SIZE_T size = 1024; + WCHAR *ptr; - /* compute the total size of the Unix environment */ - - for (e = env; *e; e++) + for (;;) { - if (is_special_env_var( *e )) continue; - size += strlen(*e) + 1; + if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL; + if (!unix_funcs->get_initial_environment( wargv, ptr, &size )) break; + RtlFreeHeap( GetProcessHeap(), 0, ptr ); } - - if (!(ptr = RtlAllocateHeap( GetProcessHeap(), 0, size * sizeof(WCHAR) ))) return NULL; - p = ptr; - - /* and fill it with the Unix environment */ - - for (e = env; *e; e++) - { - char *str = *e; - - /* skip Unix special variables and use the Wine variants instead */ - if (!strncmp( str, "WINE", 4 )) - { - if (is_special_env_var( str + 4 )) str += 4; - else if (!strncmp( str, "WINEPRELOADRESERVE=", 19 )) continue; /* skip it */ - } - else if (is_special_env_var( str )) continue; /* skip it */ - - ntdll_umbstowcs( str, strlen(str) + 1, p, size - (p - ptr) ); - p += wcslen(p) + 1; - } - *p = 0; first_prefix_start = set_registry_environment( &ptr, TRUE ); set_additional_environment( &ptr ); return ptr; @@ -687,14 +663,11 @@ static inline BOOL is_path_prefix( const WCHAR *prefix, const WCHAR *path, const /*********************************************************************** * get_image_path */ -static void get_image_path( const char *argv0, UNICODE_STRING *path ) +static void get_image_path( const WCHAR *name, UNICODE_STRING *path ) { static const WCHAR exeW[] = {'.','e','x','e',0}; - WCHAR *load_path, *file_part, *name, full_name[MAX_PATH]; - DWORD len = strlen(argv0) + 1; - - if (!(name = RtlAllocateHeap( GetProcessHeap(), 0, len * sizeof(WCHAR) ))) goto failed; - ntdll_umbstowcs( argv0, len, name, len ); + WCHAR *load_path, *file_part, full_name[MAX_PATH]; + DWORD len; if (RtlDetermineDosPathNameType_U( name ) != RELATIVE_PATH || wcschr( name, '/' ) || wcschr( name, '\\' )) @@ -732,51 +705,14 @@ static void get_image_path( const char *argv0, UNICODE_STRING *path ) } done: RtlCreateUnicodeString( path, full_name ); - RtlFreeHeap( GetProcessHeap(), 0, name ); return; failed: - MESSAGE( "wine: cannot find '%s'\n", argv0 ); + MESSAGE( "wine: cannot find %s\n", debugstr_w(name) ); RtlExitUserProcess( GetLastError() ); } -/*********************************************************************** - * set_library_wargv - * - * Set the Wine library Unicode argv global variables. - */ -static void set_library_wargv( char **argv, const UNICODE_STRING *image ) -{ - int argc; - WCHAR *p, **wargv; - DWORD total = 0; - - if (image) total += 1 + image->Length / sizeof(WCHAR); - for (argc = (image != NULL); argv[argc]; argc++) total += strlen(argv[argc]) + 1; - - wargv = RtlAllocateHeap( GetProcessHeap(), 0, - total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) ); - p = (WCHAR *)(wargv + argc + 1); - if (image) - { - wcscpy( p, image->Buffer ); - wargv[0] = p; - p += 1 + image->Length / sizeof(WCHAR); - total -= 1 + image->Length / sizeof(WCHAR); - } - for (argc = (image != NULL); argv[argc]; argc++) - { - DWORD reslen = ntdll_umbstowcs( argv[argc], strlen(argv[argc]) + 1, p, total ); - wargv[argc] = p; - p += reslen; - total -= reslen; - } - wargv[argc] = NULL; - __wine_main_wargv = wargv; -} - - /*********************************************************************** * build_command_line * @@ -1504,10 +1440,7 @@ void init_user_process_params( SIZE_T data_size ) startup_info_t *info = NULL; RTL_USER_PROCESS_PARAMETERS *params = NULL; UNICODE_STRING curdir, dllpath, imagepath, cmdline, title, desktop, shellinfo, runtime; - int argc; - char **argv, **envp; - - unix_funcs->get_main_args( &argc, &argv, &envp ); + WCHAR **wargv; if (!data_size) { @@ -1515,14 +1448,14 @@ void init_user_process_params( SIZE_T data_size ) WCHAR *env, curdir_buffer[MAX_PATH]; NtCurrentTeb()->Peb->ProcessParameters = &initial_params; - initial_params.Environment = build_initial_environment( envp ); + initial_params.Environment = build_initial_environment( &wargv ); curdir.Buffer = curdir_buffer; curdir.MaximumLength = sizeof(curdir_buffer); get_current_directory( &curdir ); initial_params.CurrentDirectory.DosPath = curdir; - get_image_path( argv[0], &initial_params.ImagePathName ); - set_library_wargv( argv, &initial_params.ImagePathName ); - build_command_line( __wine_main_wargv, &cmdline ); + get_image_path( wargv[0], &initial_params.ImagePathName ); + wargv[0] = initial_params.ImagePathName.Buffer; + build_command_line( wargv, &cmdline ); LdrGetDllPath( initial_params.ImagePathName.Buffer, 0, &load_path, &dummy ); RtlInitUnicodeString( &dllpath, load_path ); @@ -1535,7 +1468,6 @@ void init_user_process_params( SIZE_T data_size ) params->Environment = env; NtCurrentTeb()->Peb->ProcessParameters = params; - RtlFreeUnicodeString( &initial_params.ImagePathName ); RtlFreeUnicodeString( &cmdline ); RtlReleasePath( load_path ); @@ -1609,8 +1541,6 @@ void init_user_process_params( SIZE_T data_size ) else params->Environment[0] = 0; } - set_library_wargv( argv, NULL ); - done: RtlFreeHeap( GetProcessHeap(), 0, info ); if (RtlSetCurrentDirectory_U( ¶ms->CurrentDirectory.DosPath )) diff --git a/dlls/ntdll/unix/env.c b/dlls/ntdll/unix/env.c new file mode 100644 index 00000000000..95d3c7679cb --- /dev/null +++ b/dlls/ntdll/unix/env.c @@ -0,0 +1,606 @@ +/* + * Ntdll environment functions + * + * Copyright 1996, 1998 Alexandre Julliard + * Copyright 2003 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_SYS_STAT_H +# include +#endif +#ifdef HAVE_SYS_PRCTL_H +# include +#endif +#ifdef HAVE_PWD_H +# include +#endif +#ifdef HAVE_UNISTD_H +# include +#endif + +#include "ntstatus.h" +#define WIN32_NO_STATUS +#include "windef.h" +#include "winternl.h" +#include "winbase.h" +#include "winnls.h" +#include "wine/debug.h" +#include "unix_private.h" + +WINE_DEFAULT_DEBUG_CHANNEL(environ); + +extern int __wine_main_argc; +extern char **__wine_main_argv; +extern char **__wine_main_environ; +extern WCHAR **__wine_main_wargv; + +static int main_argc; +static char **main_argv; +static char **main_envp; +static WCHAR **main_wargv; + +static CPTABLEINFO unix_table; + + +#ifdef __APPLE__ + +/* The Apple filesystem enforces NFD so we need the compose tables to put it back into NFC */ + +struct norm_table +{ + WCHAR name[13]; /* 00 file name */ + USHORT checksum[3]; /* 1a checksum? */ + USHORT version[4]; /* 20 Unicode version */ + USHORT form; /* 28 normalization form */ + USHORT len_factor; /* 2a factor for length estimates */ + USHORT unknown1; /* 2c */ + USHORT decomp_size; /* 2e decomposition hash size */ + USHORT comp_size; /* 30 composition hash size */ + USHORT unknown2; /* 32 */ + USHORT classes; /* 34 combining classes table offset */ + USHORT props_level1; /* 36 char properties table level 1 offset */ + USHORT props_level2; /* 38 char properties table level 2 offset */ + USHORT decomp_hash; /* 3a decomposition hash table offset */ + USHORT decomp_map; /* 3c decomposition character map table offset */ + USHORT decomp_seq; /* 3e decomposition character sequences offset */ + USHORT comp_hash; /* 40 composition hash table offset */ + USHORT comp_seq; /* 42 composition character sequences offset */ + /* BYTE[] combining class values */ + /* BYTE[0x2200] char properties index level 1 */ + /* BYTE[] char properties index level 2 */ + /* WORD[] decomposition hash table */ + /* WORD[] decomposition character map */ + /* WORD[] decomposition character sequences */ + /* WORD[] composition hash table */ + /* WORD[] composition character sequences */ +}; + +static struct norm_table *nfc_table; + +static void init_unix_codepage(void) +{ + const char *dir = build_dir ? build_dir : data_dir; + struct stat st; + char *name; + void *data; + int fd; + + if (!(name = malloc( strlen(dir) + 17 ))) return; + sprintf( name, "%s/nls/normnfc.nls", dir ); + if ((fd = open( name, O_RDONLY )) != -1) + { + fstat( fd, &st ); + if ((data = malloc( st.st_size )) && + st.st_size > 0x4000 && + read( fd, data, st.st_size ) == st.st_size) + { + nfc_table = data; + } + else + { + free( data ); + } + close( fd ); + } + else ERR( "failed to load %s\n", name ); + free( name ); +} + +static int get_utf16( const WCHAR *src, unsigned int srclen, unsigned int *ch ) +{ + if (IS_HIGH_SURROGATE( src[0] )) + { + if (srclen <= 1) return 0; + if (!IS_LOW_SURROGATE( src[1] )) return 0; + *ch = 0x10000 + ((src[0] & 0x3ff) << 10) + (src[1] & 0x3ff); + return 2; + } + if (IS_LOW_SURROGATE( src[0] )) return 0; + *ch = src[0]; + return 1; +} + +static void put_utf16( WCHAR *dst, unsigned int ch ) +{ + if (ch >= 0x10000) + { + ch -= 0x10000; + dst[0] = 0xd800 | (ch >> 10); + dst[1] = 0xdc00 | (ch & 0x3ff); + } + else dst[0] = ch; +} + +static BYTE rol( BYTE val, BYTE count ) +{ + return (val << count) | (val >> (8 - count)); +} + + +static BYTE get_char_props( const struct norm_table *info, unsigned int ch ) +{ + const BYTE *level1 = (const BYTE *)((const USHORT *)info + info->props_level1); + const BYTE *level2 = (const BYTE *)((const USHORT *)info + info->props_level2); + BYTE off = level1[ch / 128]; + + if (!off || off >= 0xfb) return rol( off, 5 ); + return level2[(off - 1) * 128 + ch % 128]; +} + +static BYTE get_combining_class( const struct norm_table *info, unsigned int c ) +{ + const BYTE *classes = (const BYTE *)((const USHORT *)info + info->classes); + BYTE class = get_char_props( info, c ) & 0x3f; + + if (class == 0x3f) return 0; + return classes[class]; +} + +#define HANGUL_SBASE 0xac00 +#define HANGUL_LBASE 0x1100 +#define HANGUL_VBASE 0x1161 +#define HANGUL_TBASE 0x11a7 +#define HANGUL_LCOUNT 19 +#define HANGUL_VCOUNT 21 +#define HANGUL_TCOUNT 28 +#define HANGUL_NCOUNT (HANGUL_VCOUNT * HANGUL_TCOUNT) +#define HANGUL_SCOUNT (HANGUL_LCOUNT * HANGUL_NCOUNT) + +static unsigned int compose_hangul( unsigned int ch1, unsigned int ch2 ) +{ + if (ch1 >= HANGUL_LBASE && ch1 < HANGUL_LBASE + HANGUL_LCOUNT) + { + int lindex = ch1 - HANGUL_LBASE; + int vindex = ch2 - HANGUL_VBASE; + if (vindex >= 0 && vindex < HANGUL_VCOUNT) + return HANGUL_SBASE + (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT; + } + if (ch1 >= HANGUL_SBASE && ch1 < HANGUL_SBASE + HANGUL_SCOUNT) + { + int sindex = ch1 - HANGUL_SBASE; + if (!(sindex % HANGUL_TCOUNT)) + { + int tindex = ch2 - HANGUL_TBASE; + if (tindex > 0 && tindex < HANGUL_TCOUNT) return ch1 + tindex; + } + } + return 0; +} + +static unsigned int compose_chars( const struct norm_table *info, unsigned int ch1, unsigned int ch2 ) +{ + const USHORT *table = (const USHORT *)info + info->comp_hash; + const WCHAR *chars = (const USHORT *)info + info->comp_seq; + unsigned int hash, start, end, i, len, ch[3]; + + hash = (ch1 + 95 * ch2) % info->comp_size; + start = table[hash]; + end = table[hash + 1]; + while (start < end) + { + for (i = 0; i < 3; i++, start += len) len = get_utf16( chars + start, end - start, ch + i ); + if (ch[0] == ch1 && ch[1] == ch2) return ch[2]; + } + return 0; +} + +static unsigned int compose_string( const struct norm_table *info, WCHAR *str, unsigned int srclen ) +{ + unsigned int i, ch, comp, len, start_ch = 0, last_starter = srclen; + BYTE class, prev_class = 0; + + for (i = 0; i < srclen; i += len) + { + if (!(len = get_utf16( str + i, srclen - i, &ch ))) return 0; + class = get_combining_class( info, ch ); + if (last_starter == srclen || (prev_class && prev_class >= class) || + (!(comp = compose_hangul( start_ch, ch )) && + !(comp = compose_chars( info, start_ch, ch )))) + { + if (!class) + { + last_starter = i; + start_ch = ch; + } + prev_class = class; + } + else + { + int comp_len = 1 + (comp >= 0x10000); + int start_len = 1 + (start_ch >= 0x10000); + + if (comp_len != start_len) + memmove( str + last_starter + comp_len, str + last_starter + start_len, + (i - (last_starter + start_len)) * sizeof(WCHAR) ); + memmove( str + i + comp_len - start_len, str + i + len, (srclen - i - len) * sizeof(WCHAR) ); + srclen += comp_len - start_len - len; + start_ch = comp; + i = last_starter; + len = comp_len; + prev_class = 0; + put_utf16( str + i, comp ); + } + } + return srclen; +} + +#elif defined(__ANDROID__) /* Android always uses UTF-8 */ + +static void init_unix_codepage(void) { } + +#else /* __APPLE__ || __ANDROID__ */ + +/* charset to codepage map, sorted by name */ +static const struct { const char *name; UINT cp; } charset_names[] = +{ + { "ANSIX341968", 20127 }, + { "BIG5", 950 }, + { "BIG5HKSCS", 950 }, + { "CP1250", 1250 }, + { "CP1251", 1251 }, + { "CP1252", 1252 }, + { "CP1253", 1253 }, + { "CP1254", 1254 }, + { "CP1255", 1255 }, + { "CP1256", 1256 }, + { "CP1257", 1257 }, + { "CP1258", 1258 }, + { "CP932", 932 }, + { "CP936", 936 }, + { "CP949", 949 }, + { "CP950", 950 }, + { "EUCJP", 20932 }, + { "EUCKR", 949 }, + { "GB18030", 936 /* 54936 */ }, + { "GB2312", 936 }, + { "GBK", 936 }, + { "IBM037", 37 }, + { "IBM1026", 1026 }, + { "IBM424", 20424 }, + { "IBM437", 437 }, + { "IBM500", 500 }, + { "IBM850", 850 }, + { "IBM852", 852 }, + { "IBM855", 855 }, + { "IBM857", 857 }, + { "IBM860", 860 }, + { "IBM861", 861 }, + { "IBM862", 862 }, + { "IBM863", 863 }, + { "IBM864", 864 }, + { "IBM865", 865 }, + { "IBM866", 866 }, + { "IBM869", 869 }, + { "IBM874", 874 }, + { "IBM875", 875 }, + { "ISO88591", 28591 }, + { "ISO885913", 28603 }, + { "ISO885915", 28605 }, + { "ISO88592", 28592 }, + { "ISO88593", 28593 }, + { "ISO88594", 28594 }, + { "ISO88595", 28595 }, + { "ISO88596", 28596 }, + { "ISO88597", 28597 }, + { "ISO88598", 28598 }, + { "ISO88599", 28599 }, + { "KOI8R", 20866 }, + { "KOI8U", 21866 }, + { "TIS620", 28601 }, + { "UTF8", CP_UTF8 } +}; + +static void load_unix_cptable( unsigned int cp ) +{ + const char *dir = build_dir ? build_dir : data_dir; + struct stat st; + char *name; + void *data; + int fd; + + if (!(name = malloc( strlen(dir) + 22 ))) return; + sprintf( name, "%s/nls/c_%03u.nls", dir, cp ); + if ((fd = open( name, O_RDONLY )) != -1) + { + fstat( fd, &st ); + if ((data = malloc( st.st_size )) && st.st_size > 0x10000 && + read( fd, data, st.st_size ) == st.st_size) + { + RtlInitCodePageTable( data, &unix_table ); + } + else + { + free( data ); + } + close( fd ); + } + else ERR( "failed to load %s\n", name ); + free( name ); +} + +static void init_unix_codepage(void) +{ + char charset_name[16]; + const char *name; + size_t i, j; + int min = 0, max = ARRAY_SIZE(charset_names) - 1; + + setlocale( LC_CTYPE, "" ); + if (!(name = nl_langinfo( CODESET ))) return; + + /* remove punctuation characters from charset name */ + for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++) + { + if (name[i] >= '0' && name[i] <= '9') charset_name[j++] = name[i]; + else if (name[i] >= 'A' && name[i] <= 'Z') charset_name[j++] = name[i]; + else if (name[i] >= 'a' && name[i] <= 'z') charset_name[j++] = name[i] + ('A' - 'a'); + } + charset_name[j] = 0; + + while (min <= max) + { + int pos = (min + max) / 2; + int res = strcmp( charset_names[pos].name, charset_name ); + if (!res) + { + if (charset_names[pos].cp != CP_UTF8) load_unix_cptable( charset_names[pos].cp ); + return; + } + if (res > 0) max = pos - 1; + else min = pos + 1; + } + ERR( "unrecognized charset '%s'\n", name ); +} + +#endif /* __APPLE__ || __ANDROID__ */ + + +/*********************************************************************** + * 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 )); +} + + +/****************************************************************** + * ntdll_umbstowcs + */ +DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) +{ + DWORD reslen; + + if (unix_table.CodePage) + RtlCustomCPToUnicodeN( &unix_table, dst, dstlen * sizeof(WCHAR), &reslen, src, srclen ); + else + RtlUTF8ToUnicodeN( dst, dstlen * sizeof(WCHAR), &reslen, src, srclen ); + + reslen /= sizeof(WCHAR); +#ifdef __APPLE__ /* work around broken Mac OS X filesystem that enforces NFD */ + if (reslen && nfc_table) reslen = compose_string( nfc_table, dst, reslen ); +#endif + return reslen; +} + + +/*********************************************************************** + * set_process_name + * + * Change the process name in the ps output. + */ +static void set_process_name( int argc, char *argv[] ) +{ + BOOL shift_strings; + char *p, *name; + int i; + +#ifdef HAVE_SETPROCTITLE + setproctitle("-%s", argv[1]); + shift_strings = FALSE; +#else + p = argv[0]; + + shift_strings = (argc >= 2); + for (i = 1; i < argc; i++) + { + p += strlen(p) + 1; + if (p != argv[i]) + { + shift_strings = FALSE; + break; + } + } +#endif + + if (shift_strings) + { + int offset = argv[1] - argv[0]; + char *end = argv[argc-1] + strlen(argv[argc-1]) + 1; + memmove( argv[0], argv[1], end - argv[1] ); + memset( end - offset, 0, offset ); + for (i = 1; i < argc; i++) + argv[i-1] = argv[i] - offset; + argv[i-1] = NULL; + } + else + { + /* remove argv[0] */ + memmove( argv, argv + 1, argc * sizeof(argv[0]) ); + } + + name = argv[0]; + if ((p = strrchr( name, '\\' ))) name = p + 1; + if ((p = strrchr( name, '/' ))) name = p + 1; + +#if defined(HAVE_SETPROGNAME) + setprogname( name ); +#endif + +#ifdef HAVE_PRCTL +#ifndef PR_SET_NAME +# define PR_SET_NAME 15 +#endif + prctl( PR_SET_NAME, name ); +#endif /* HAVE_PRCTL */ +} + + +/*********************************************************************** + * build_wargv + * + * Build the Unicode argv array. + */ +static WCHAR **build_wargv( char **argv ) +{ + int argc; + WCHAR *p, **wargv; + DWORD total = 0; + + for (argc = 0; argv[argc]; argc++) total += strlen(argv[argc]) + 1; + + wargv = malloc( total * sizeof(WCHAR) + (argc + 1) * sizeof(*wargv) ); + p = (WCHAR *)(wargv + argc + 1); + for (argc = 0; argv[argc]; argc++) + { + DWORD reslen = ntdll_umbstowcs( argv[argc], strlen(argv[argc]) + 1, p, total ); + wargv[argc] = p; + p += reslen; + total -= reslen; + } + wargv[argc] = NULL; + return wargv; +} + + +/*********************************************************************** + * init_environment + */ +void init_environment( int argc, char *argv[], char *envp[] ) +{ + init_unix_codepage(); + set_process_name( argc, argv ); + __wine_main_argc = main_argc = argc; + __wine_main_argv = main_argv = argv; + __wine_main_wargv = main_wargv = build_wargv( argv ); + __wine_main_environ = main_envp = envp; +} + + +/************************************************************************* + * get_main_args + * + * Return the initial arguments. + */ +void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) +{ + *argc = main_argc; + *argv = main_argv; + *envp = main_envp; +} + + +/************************************************************************* + * get_initial_environment + * + * Return the initial environment. + */ +NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) +{ + char **e; + WCHAR *ptr = env, *end = env + *size; + + *wargv = main_wargv; + for (e = main_envp; *e && ptr < end; e++) + { + char *str = *e; + + /* skip Unix special variables and use the Wine variants instead */ + if (!strncmp( str, "WINE", 4 )) + { + if (is_special_env_var( str + 4 )) str += 4; + else if (!strncmp( str, "WINEPRELOADRESERVE=", 19 )) continue; /* skip it */ + } + else if (is_special_env_var( str )) continue; /* skip it */ + + ptr += ntdll_umbstowcs( str, strlen(str) + 1, ptr, end - ptr ); + } + + if (ptr < end) + { + *ptr++ = 0; + *size = ptr - env; + return STATUS_SUCCESS; + } + + /* estimate needed size */ + for (e = main_envp, *size = 1; *e; e++) if (!is_special_env_var( *e )) *size += strlen(*e) + 1; + return STATUS_BUFFER_TOO_SMALL; +} + + +/************************************************************************* + * get_unix_codepage + * + * Return the Unix codepage data. + */ +void CDECL get_unix_codepage( CPTABLEINFO *table ) +{ + *table = unix_table; +} diff --git a/dlls/ntdll/unix/loader.c b/dlls/ntdll/unix/loader.c index da41805c6b6..50acd84139f 100644 --- a/dlls/ntdll/unix/loader.c +++ b/dlls/ntdll/unix/loader.c @@ -27,8 +27,6 @@ #include #include -#include -#include #include #include #include @@ -38,9 +36,6 @@ #ifdef HAVE_SYS_MMAN_H # include #endif -#ifdef HAVE_SYS_PRCTL_H -# include -#endif #ifdef HAVE_SYS_RESOURCE_H # include #endif @@ -100,9 +95,6 @@ static const BOOL use_preloader = FALSE; static const BOOL is_win64 = (sizeof(void *) > sizeof(int)); -static int main_argc; -static char **main_argv; -static char **main_envp; static char *argv0; static const char *bin_dir; static const char *dll_dir; @@ -113,8 +105,6 @@ const char *data_dir = NULL; const char *build_dir = NULL; const char *config_dir = NULL; -static CPTABLEINFO unix_table; - static inline void *get_rva( const IMAGE_NT_HEADERS *nt, ULONG_PTR addr ) { return (BYTE *)nt + addr; @@ -275,9 +265,6 @@ static void init_paths( int argc, char *argv[], char *envp[] ) { Dl_info info; - __wine_main_argc = main_argc = argc; - __wine_main_argv = main_argv = argv; - __wine_main_environ = main_envp = envp; argv0 = strdup( argv[0] ); if (!dladdr( init_paths, &info ) || !(dll_dir = realpath_dirname( info.dli_fname ))) @@ -300,136 +287,6 @@ static void init_paths( int argc, char *argv[], char *envp[] ) set_config_dir(); } -#if !defined(__APPLE__) && !defined(__ANDROID__) /* these platforms always use UTF-8 */ - -/* charset to codepage map, sorted by name */ -static const struct { const char *name; UINT cp; } charset_names[] = -{ - { "ANSIX341968", 20127 }, - { "BIG5", 950 }, - { "BIG5HKSCS", 950 }, - { "CP1250", 1250 }, - { "CP1251", 1251 }, - { "CP1252", 1252 }, - { "CP1253", 1253 }, - { "CP1254", 1254 }, - { "CP1255", 1255 }, - { "CP1256", 1256 }, - { "CP1257", 1257 }, - { "CP1258", 1258 }, - { "CP932", 932 }, - { "CP936", 936 }, - { "CP949", 949 }, - { "CP950", 950 }, - { "EUCJP", 20932 }, - { "EUCKR", 949 }, - { "GB18030", 936 /* 54936 */ }, - { "GB2312", 936 }, - { "GBK", 936 }, - { "IBM037", 37 }, - { "IBM1026", 1026 }, - { "IBM424", 20424 }, - { "IBM437", 437 }, - { "IBM500", 500 }, - { "IBM850", 850 }, - { "IBM852", 852 }, - { "IBM855", 855 }, - { "IBM857", 857 }, - { "IBM860", 860 }, - { "IBM861", 861 }, - { "IBM862", 862 }, - { "IBM863", 863 }, - { "IBM864", 864 }, - { "IBM865", 865 }, - { "IBM866", 866 }, - { "IBM869", 869 }, - { "IBM874", 874 }, - { "IBM875", 875 }, - { "ISO88591", 28591 }, - { "ISO885913", 28603 }, - { "ISO885915", 28605 }, - { "ISO88592", 28592 }, - { "ISO88593", 28593 }, - { "ISO88594", 28594 }, - { "ISO88595", 28595 }, - { "ISO88596", 28596 }, - { "ISO88597", 28597 }, - { "ISO88598", 28598 }, - { "ISO88599", 28599 }, - { "KOI8R", 20866 }, - { "KOI8U", 21866 }, - { "TIS620", 28601 }, - { "UTF8", CP_UTF8 } -}; - -static void load_unix_cptable( unsigned int cp ) -{ - const char *dir = build_dir ? build_dir : data_dir; - struct stat st; - char *name; - void *data; - int fd; - - if (!(name = malloc( strlen(dir) + 22 ))) return; - sprintf( name, "%s/nls/c_%03u.nls", dir, cp ); - if ((fd = open( name, O_RDONLY )) != -1) - { - fstat( fd, &st ); - if ((data = malloc( st.st_size )) && st.st_size > 0x10000 && - read( fd, data, st.st_size ) == st.st_size) - { - RtlInitCodePageTable( data, &unix_table ); - } - else - { - free( data ); - } - close( fd ); - } - else ERR( "failed to load %s\n", name ); - free( name ); -} - -static void init_unix_codepage(void) -{ - char charset_name[16]; - const char *name; - size_t i, j; - int min = 0, max = ARRAY_SIZE(charset_names) - 1; - - setlocale( LC_CTYPE, "" ); - if (!(name = nl_langinfo( CODESET ))) return; - - /* remove punctuation characters from charset name */ - for (i = j = 0; name[i] && j < sizeof(charset_name)-1; i++) - { - if (name[i] >= '0' && name[i] <= '9') charset_name[j++] = name[i]; - else if (name[i] >= 'A' && name[i] <= 'Z') charset_name[j++] = name[i]; - else if (name[i] >= 'a' && name[i] <= 'z') charset_name[j++] = name[i] + ('A' - 'a'); - } - charset_name[j] = 0; - - while (min <= max) - { - int pos = (min + max) / 2; - int res = strcmp( charset_names[pos].name, charset_name ); - if (!res) - { - if (charset_names[pos].cp != CP_UTF8) load_unix_cptable( charset_names[pos].cp ); - return; - } - if (res > 0) max = pos - 1; - else min = pos + 1; - } - ERR( "unrecognized charset '%s'\n", name ); -} - -#else /* __APPLE__ || __ANDROID__ */ - -static void init_unix_codepage(void) { } - -#endif /* __APPLE__ || __ANDROID__ */ - /********************************************************************* * get_version @@ -473,19 +330,6 @@ void CDECL get_host_version( const char **sysname, const char **release ) } -/************************************************************************* - * get_main_args - * - * Return the initial arguments. - */ -static void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) -{ - *argc = main_argc; - *argv = main_argv; - *envp = main_envp; -} - - /************************************************************************* * get_paths * @@ -511,17 +355,6 @@ static void CDECL get_dll_path( const char ***paths, SIZE_T *maxlen ) } -/************************************************************************* - * get_unix_codepage - * - * Return the Unix codepage data. - */ -static void CDECL get_unix_codepage( CPTABLEINFO *table ) -{ - *table = unix_table; -} - - static void preloader_exec( char **argv ) { if (use_preloader) @@ -1065,6 +898,7 @@ static struct unix_funcs unix_funcs = fast_RtlSleepConditionVariableCS, fast_RtlWakeConditionVariable, get_main_args, + get_initial_environment, get_paths, get_dll_path, get_unix_codepage, @@ -1295,68 +1129,6 @@ static int pre_exec(void) #endif -/*********************************************************************** - * set_process_name - * - * Change the process name in the ps output. - */ -static void set_process_name( int argc, char *argv[] ) -{ - BOOL shift_strings; - char *p, *name; - int i; - -#ifdef HAVE_SETPROCTITLE - setproctitle("-%s", argv[1]); - shift_strings = FALSE; -#else - p = argv[0]; - - shift_strings = (argc >= 2); - for (i = 1; i < argc; i++) - { - p += strlen(p) + 1; - if (p != argv[i]) - { - shift_strings = FALSE; - break; - } - } -#endif - - if (shift_strings) - { - int offset = argv[1] - argv[0]; - char *end = argv[argc-1] + strlen(argv[argc-1]) + 1; - memmove( argv[0], argv[1], end - argv[1] ); - memset( end - offset, 0, offset ); - for (i = 1; i < argc; i++) - argv[i-1] = argv[i] - offset; - argv[i-1] = NULL; - } - else - { - /* remove argv[0] */ - memmove( argv, argv + 1, argc * sizeof(argv[0]) ); - } - - name = argv[0]; - if ((p = strrchr( name, '\\' ))) name = p + 1; - if ((p = strrchr( name, '/' ))) name = p + 1; - -#if defined(HAVE_SETPROGNAME) - setprogname( name ); -#endif - -#ifdef HAVE_PRCTL -#ifndef PR_SET_NAME -# define PR_SET_NAME 15 -#endif - prctl( PR_SET_NAME, name ); -#endif /* HAVE_PRCTL */ -} - - /*********************************************************************** * check_command_line * @@ -1425,8 +1197,7 @@ void __wine_main( int argc, char *argv[], char *envp[] ) module = load_ntdll(); fixup_ntdll_imports( &__wine_spec_nt_header, module ); - set_process_name( argc, argv ); - init_unix_codepage(); + init_environment( argc, argv, envp ); #ifdef __APPLE__ apple_main_thread(); @@ -1460,8 +1231,7 @@ NTSTATUS __cdecl __wine_init_unix_lib( HMODULE module, const void *ptr_in, void map_so_dll( nt, module ); fixup_ntdll_imports( &__wine_spec_nt_header, module ); - set_process_name( __wine_main_argc, __wine_main_argv ); - init_unix_codepage(); + init_environment( __wine_main_argc, __wine_main_argv, envp ); *(struct unix_funcs **)ptr_out = &unix_funcs; wine_mmap_enum_reserved_areas( add_area, NULL, 0 ); return STATUS_SUCCESS; diff --git a/dlls/ntdll/unix/unix_private.h b/dlls/ntdll/unix/unix_private.h index f056cc5ed0f..6830ec2b63f 100644 --- a/dlls/ntdll/unix/unix_private.h +++ b/dlls/ntdll/unix/unix_private.h @@ -78,6 +78,9 @@ void CDECL mmap_remove_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN; int CDECL mmap_is_in_reserved_area( void *addr, SIZE_T size ) DECLSPEC_HIDDEN; int CDECL mmap_enum_reserved_areas( int (CDECL *enum_func)(void *base, SIZE_T size, void *arg), void *arg, int top_down ) DECLSPEC_HIDDEN; +extern void CDECL get_main_args( int *argc, char **argv[], char **envp[] ) DECLSPEC_HIDDEN; +extern NTSTATUS CDECL get_initial_environment( WCHAR **wargv[], WCHAR *env, SIZE_T *size ) DECLSPEC_HIDDEN; +extern void CDECL get_unix_codepage( CPTABLEINFO *table ) DECLSPEC_HIDDEN; extern NTSTATUS CDECL virtual_map_section( HANDLE handle, PVOID *addr_ptr, unsigned short zero_bits_64, SIZE_T commit_size, const LARGE_INTEGER *offset_ptr, SIZE_T *size_ptr, ULONG alloc_type, ULONG protect, pe_image_info_t *image_info ) DECLSPEC_HIDDEN; @@ -123,6 +126,9 @@ extern SIZE_T signal_stack_size DECLSPEC_HIDDEN; extern SIZE_T signal_stack_mask DECLSPEC_HIDDEN; extern struct _KUSER_SHARED_DATA *user_shared_data DECLSPEC_HIDDEN; +extern void init_environment( int argc, char *argv[], char *envp[] ) DECLSPEC_HIDDEN; +extern DWORD ntdll_umbstowcs( const char *src, DWORD srclen, WCHAR *dst, DWORD dstlen ) DECLSPEC_HIDDEN; + extern unsigned int server_call_unlocked( void *req_ptr ) DECLSPEC_HIDDEN; extern void server_enter_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; extern void server_leave_uninterrupted_section( RTL_CRITICAL_SECTION *cs, sigset_t *sigset ) DECLSPEC_HIDDEN; @@ -170,4 +176,21 @@ extern void DECLSPEC_NORETURN signal_exit_thread( int status, void (*func)(int) extern void dbg_init(void) DECLSPEC_HIDDEN; +static inline size_t ntdll_wcslen( const WCHAR *str ) +{ + const WCHAR *s = str; + while (*s) s++; + return s - str; +} + +static inline WCHAR *ntdll_wcscpy( WCHAR *dst, const WCHAR *src ) +{ + WCHAR *p = dst; + while ((*p++ = *src++)); + return dst; +} + +#define wcslen(str) ntdll_wcslen(str) +#define wcscpy(dst,src) ntdll_wcscpy(dst,src) + #endif /* __NTDLL_UNIX_PRIVATE_H */ diff --git a/dlls/ntdll/unixlib.h b/dlls/ntdll/unixlib.h index 07dc832635d..938c4ec9c97 100644 --- a/dlls/ntdll/unixlib.h +++ b/dlls/ntdll/unixlib.h @@ -28,7 +28,7 @@ struct ldt_copy; struct msghdr; /* increment this when you change the function table */ -#define NTDLL_UNIXLIB_VERSION 38 +#define NTDLL_UNIXLIB_VERSION 39 struct unix_funcs { @@ -171,6 +171,7 @@ struct unix_funcs /* environment functions */ void (CDECL *get_main_args)( int *argc, char **argv[], char **envp[] ); + NTSTATUS (CDECL *get_initial_environment)( WCHAR **wargv[], WCHAR *env, SIZE_T *size ); void (CDECL *get_paths)( const char **builddir, const char **datadir, const char **configdir ); void (CDECL *get_dll_path)( const char ***paths, SIZE_T *maxlen ); void (CDECL *get_unix_codepage)( CPTABLEINFO *table );