ntdll: Change master/slave to more neutral words.
[wine.git] / loader / main.c
blob0e6b6f66b50365981aefeda2d411ede10c01d876
1 /*
2 * Emulator initialisation code
4 * Copyright 2000 Alexandre Julliard
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
21 #include "config.h"
22 #include "wine/port.h"
24 #include <errno.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifdef HAVE_SYS_MMAN_H
28 # include <sys/mman.h>
29 #endif
30 #ifdef HAVE_SYS_RESOURCE_H
31 # include <sys/resource.h>
32 #endif
33 #ifdef HAVE_SYS_SYSCALL_H
34 # include <sys/syscall.h>
35 #endif
36 #ifdef HAVE_UNISTD_H
37 # include <unistd.h>
38 #endif
40 #include "wine/library.h"
41 #include "main.h"
43 extern char **environ;
45 /* the preloader will set this variable */
46 const struct wine_preload_info *wine_main_preload_info = NULL;
48 /***********************************************************************
49 * check_command_line
51 * Check if command line is one that needs to be handled specially.
53 static void check_command_line( int argc, char *argv[] )
55 static const char usage[] =
56 "Usage: wine PROGRAM [ARGUMENTS...] Run the specified program\n"
57 " wine --help Display this help and exit\n"
58 " wine --version Output version information and exit";
60 if (argc <= 1)
62 fprintf( stderr, "%s\n", usage );
63 exit(1);
65 if (!strcmp( argv[1], "--help" ))
67 printf( "%s\n", usage );
68 exit(0);
70 if (!strcmp( argv[1], "--version" ))
72 printf( "%s\n", wine_get_build_id() );
73 exit(0);
78 #ifdef __ANDROID__
80 static int pre_exec(void)
82 #if defined(__i386__) || defined(__x86_64__)
83 return 1; /* we have a preloader */
84 #else
85 return 0; /* no exec needed */
86 #endif
89 #elif defined(__linux__) && (defined(__i386__) || defined(__arm__))
91 static void check_vmsplit( void *stack )
93 if (stack < (void *)0x80000000)
95 /* if the stack is below 0x80000000, assume we can safely try a munmap there */
96 if (munmap( (void *)0x80000000, 1 ) == -1 && errno == EINVAL)
97 fprintf( stderr,
98 "Warning: memory above 0x80000000 doesn't seem to be accessible.\n"
99 "Wine requires a 3G/1G user/kernel memory split to work properly.\n" );
103 static void set_max_limit( int limit )
105 struct rlimit rlimit;
107 if (!getrlimit( limit, &rlimit ))
109 rlimit.rlim_cur = rlimit.rlim_max;
110 setrlimit( limit, &rlimit );
114 static int pre_exec(void)
116 int temp;
118 check_vmsplit( &temp );
119 set_max_limit( RLIMIT_AS );
120 #ifdef __i386__
121 return 1; /* we have a preloader on x86 */
122 #else
123 return 0;
124 #endif
127 #elif defined(__linux__) && (defined(__x86_64__) || defined(__aarch64__))
129 static int pre_exec(void)
131 return 1; /* we have a preloader on x86-64/arm64 */
134 #elif defined(__APPLE__) && (defined(__i386__) || defined(__x86_64__))
136 static int pre_exec(void)
138 return 1; /* we have a preloader */
141 #elif (defined(__FreeBSD__) || defined (__FreeBSD_kernel__) || defined(__DragonFly__))
143 static int pre_exec(void)
145 struct rlimit rl;
147 rl.rlim_cur = 0x02000000;
148 rl.rlim_max = 0x02000000;
149 setrlimit( RLIMIT_DATA, &rl );
150 return 1;
153 #else
155 static int pre_exec(void)
157 return 0; /* no exec needed */
160 #endif
163 /* canonicalize path and return its directory name */
164 static char *realpath_dirname( const char *name )
166 char *p, *fullpath = realpath( name, NULL );
168 if (fullpath)
170 p = strrchr( fullpath, '/' );
171 if (p == fullpath) p++;
172 if (p) *p = 0;
174 return fullpath;
177 /* if string ends with tail, remove it */
178 static char *remove_tail( const char *str, const char *tail )
180 size_t len = strlen( str );
181 size_t tail_len = strlen( tail );
182 char *ret;
184 if (len < tail_len) return NULL;
185 if (strcmp( str + len - tail_len, tail )) return NULL;
186 ret = malloc( len - tail_len + 1 );
187 memcpy( ret, str, len - tail_len );
188 ret[len - tail_len] = 0;
189 return ret;
192 /* build a path from the specified dir and name */
193 static char *build_path( const char *dir, const char *name )
195 size_t len = strlen( dir );
196 char *ret = malloc( len + strlen( name ) + 2 );
198 memcpy( ret, dir, len );
199 if (len && ret[len - 1] != '/') ret[len++] = '/';
200 strcpy( ret + len, name );
201 return ret;
204 static const char *get_self_exe( char *argv0 )
206 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
207 return "/proc/self/exe";
208 #elif defined (__FreeBSD__) || defined(__DragonFly__)
209 return "/proc/curproc/file";
210 #else
211 if (!strchr( argv0, '/' )) /* search in PATH */
213 char *p, *path = getenv( "PATH" );
215 if (!path || !(path = strdup(path))) return NULL;
216 for (p = strtok( path, ":" ); p; p = strtok( NULL, ":" ))
218 char *name = build_path( p, argv0 );
219 int found = !access( name, X_OK );
220 free( name );
221 if (found) break;
223 if (p) p = strdup( p );
224 free( path );
225 return p;
227 return argv0;
228 #endif
231 static void *try_dlopen( const char *dir, const char *name )
233 char *path = build_path( dir, name );
234 void *handle = dlopen( path, RTLD_NOW );
235 free( path );
236 return handle;
239 static void *load_ntdll( char *argv0 )
241 const char *self = get_self_exe( argv0 );
242 char *path, *p;
243 void *handle = NULL;
245 if (self && ((path = realpath_dirname( self ))))
247 if ((p = remove_tail( path, "/loader" )))
249 handle = try_dlopen( p, "dlls/ntdll/ntdll.so" );
250 free( p );
252 else handle = try_dlopen( path, BIN_TO_DLLDIR "/ntdll.so" );
253 free( path );
256 if (!handle && (path = getenv( "WINEDLLPATH" )))
258 path = strdup( path );
259 for (p = strtok( path, ":" ); p; p = strtok( NULL, ":" ))
261 handle = try_dlopen( p, "ntdll.so" );
262 if (handle) break;
264 free( path );
267 if (!handle && !self) handle = try_dlopen( DLLDIR, "ntdll.so" );
269 return handle;
273 /**********************************************************************
274 * main
276 int main( int argc, char *argv[] )
278 char error[1024];
279 int i;
280 void *handle;
282 if ((handle = load_ntdll( argv[0] )))
284 void (*init_func)(int, char **, char **) = dlsym( handle, "__wine_main" );
285 if (init_func) init_func( argc, argv, environ );
286 fprintf( stderr, "wine: __wine_main function not found in ntdll.so\n" );
287 exit(1);
290 if (!getenv( "WINELOADERNOEXEC" )) /* first time around */
292 static char noexec[] = "WINELOADERNOEXEC=1";
294 putenv( noexec );
295 check_command_line( argc, argv );
296 if (pre_exec())
298 wine_init_argv0_path( argv[0] );
299 wine_exec_wine_binary( NULL, argv, getenv( "WINELOADER" ));
300 fprintf( stderr, "wine: could not exec the wine loader\n" );
301 exit(1);
305 if (wine_main_preload_info)
307 for (i = 0; wine_main_preload_info[i].size; i++)
308 wine_mmap_add_reserved_area( wine_main_preload_info[i].addr, wine_main_preload_info[i].size );
311 wine_init( argc, argv, error, sizeof(error) );
312 fprintf( stderr, "wine: failed to initialize: %s\n", error );
313 exit(1);