2 * Configuration parameters shared between Wine server and clients
4 * Copyright 2002 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
32 #include <sys/types.h>
34 #ifdef HAVE_SYS_SYSCTL_H
35 # include <sys/sysctl.h>
43 #include <crt_externs.h>
45 #ifndef _POSIX_SPAWN_DISABLE_ASLR
46 #define _POSIX_SPAWN_DISABLE_ASLR 0x0100
53 const char *build_dir
;
54 static char *argv0_name
;
55 static char *wineserver64
;
58 static void fatal_error( const char *err
, ... ) __attribute__((noreturn
,format(printf
,1,2)));
61 #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
62 static const char exe_link
[] = "/proc/self/exe";
63 #elif ! defined (__FreeBSD__) && ! defined(__DragonFly__)
64 static const char exe_link
[] = "";
67 /* die on a fatal error */
68 static void fatal_error( const char *err
, ... )
72 va_start( args
, err
);
73 fprintf( stderr
, "wine: " );
74 vfprintf( stderr
, err
, args
);
80 static void *xmalloc( size_t size
)
85 if (!(res
= malloc( size
))) fatal_error( "virtual memory exhausted\n");
90 static char *xstrdup( const char *str
)
92 size_t len
= strlen(str
) + 1;
93 char *res
= xmalloc( len
);
94 memcpy( res
, str
, len
);
98 /* build a path from the specified dir and name */
99 static char *build_path( const char *dir
, const char *name
)
101 size_t len
= strlen(dir
);
102 char *ret
= xmalloc( len
+ strlen(name
) + 2 );
104 memcpy( ret
, dir
, len
);
105 if (len
&& ret
[len
-1] != '/') ret
[len
++] = '/';
106 strcpy( ret
+ len
, name
);
110 /* return the directory that contains the library at run-time */
111 static char *get_runtime_libdir(void)
116 if (dladdr( get_runtime_libdir
, &info
) && info
.dli_fname
[0] == '/')
118 const char *p
= strrchr( info
.dli_fname
, '/' );
119 unsigned int len
= p
- info
.dli_fname
;
120 if (!len
) len
++; /* include initial slash */
121 libdir
= xmalloc( len
+ 1 );
122 memcpy( libdir
, info
.dli_fname
, len
);
129 /* read a symlink and return its directory */
130 static char *symlink_dirname( const char *name
)
132 char *p
, *fullpath
= realpath( name
, NULL
);
136 p
= strrchr( fullpath
, '/' );
137 if (p
== fullpath
) p
++;
143 /* return the directory that contains the main exe at run-time */
144 static char *get_runtime_exedir(void)
146 #if defined(__FreeBSD__) || defined(__DragonFly__)
147 static int pathname
[] = { CTL_KERN
, KERN_PROC
, KERN_PROC_PATHNAME
, -1 };
148 size_t dir_size
= PATH_MAX
;
149 char *dir
= malloc( dir_size
);
150 if (dir
&& !sysctl( pathname
, ARRAY_SIZE( pathname
), dir
, &dir_size
, NULL
, 0 ))
155 if (exe_link
[0]) return symlink_dirname( exe_link
);
160 /* return the base directory from argv0 */
161 static char *get_runtime_argvdir( const char *argv0
)
163 char *p
, *bindir
, *cwd
;
166 if (!(p
= strrchr( argv0
, '/' ))) return NULL
;
169 if (!len
) len
++; /* include leading slash */
171 if (argv0
[0] == '/') /* absolute path */
173 bindir
= xmalloc( len
+ 1 );
174 memcpy( bindir
, argv0
, len
);
179 /* relative path, make it absolute */
180 for (size
= 256 + len
; ; size
*= 2)
182 if (!(cwd
= malloc( size
))) return NULL
;
183 if (getcwd( cwd
, size
- len
))
188 memcpy( cwd
, argv0
, len
);
193 if (errno
!= ERANGE
) return NULL
;
199 /* retrieve the default dll dir */
200 const char *get_dlldir( const char **default_dlldir
)
202 *default_dlldir
= DLLDIR
;
206 /* check if bindir is valid by checking for wineserver */
207 static int is_valid_bindir( const char *bindir
)
210 char *path
= build_path( bindir
, "wineserver" );
211 int ret
= (stat( path
, &st
) != -1);
216 /* check if dlldir is valid by checking for ntdll */
217 static int is_valid_dlldir( const char *dlldir
)
220 char *path
= build_path( dlldir
, "ntdll.dll.so" );
221 int ret
= (stat( path
, &st
) != -1);
226 /* check if basedir is a valid build dir by checking for wineserver and ntdll */
227 /* helper for running_from_build_dir */
228 static inline int is_valid_build_dir( char *basedir
, int baselen
)
232 strcpy( basedir
+ baselen
, "/server/wineserver" );
233 if (stat( basedir
, &st
) == -1) return 0; /* no wineserver found */
234 /* check for ntdll too to make sure */
235 strcpy( basedir
+ baselen
, "/dlls/ntdll/ntdll.dll.so" );
236 if (stat( basedir
, &st
) == -1) return 0; /* no ntdll found */
238 basedir
[baselen
] = 0;
242 /* check if we are running from the build directory */
243 static char *running_from_build_dir( const char *basedir
)
248 /* remove last component from basedir */
249 p
= basedir
+ strlen(basedir
) - 1;
250 while (p
> basedir
&& *p
== '/') p
--;
251 while (p
> basedir
&& *p
!= '/') p
--;
252 if (p
== basedir
) return NULL
;
253 path
= xmalloc( p
- basedir
+ sizeof("/dlls/ntdll/ntdll.dll.so") );
254 memcpy( path
, basedir
, p
- basedir
);
256 if (!is_valid_build_dir( path
, p
- basedir
))
258 /* remove another component */
259 while (p
> basedir
&& *p
== '/') p
--;
260 while (p
> basedir
&& *p
!= '/') p
--;
261 if (p
== basedir
|| !is_valid_build_dir( path
, p
- basedir
))
270 /* try to set the specified directory as bindir, or set build_dir if it's inside the build directory */
271 static int set_bindir( char *dir
)
274 if (is_valid_bindir( dir
))
277 dlldir
= build_path( bindir
, BIN_TO_DLLDIR
);
281 build_dir
= running_from_build_dir( dir
);
284 return bindir
|| build_dir
;
287 /* try to set the specified directory as dlldir, or set build_dir if it's inside the build directory */
288 static int set_dlldir( char *libdir
)
292 if (!libdir
) return 0;
294 path
= build_path( libdir
, LIB_TO_DLLDIR
);
295 if (is_valid_dlldir( path
))
298 bindir
= build_path( libdir
, LIB_TO_BINDIR
);
302 build_dir
= running_from_build_dir( libdir
);
306 return dlldir
|| build_dir
;
309 /* initialize the argv0 path */
310 void wine_init_argv0_path_obsolete( const char *argv0
)
312 const char *basename
, *wineloader
;
314 if (!(basename
= strrchr( argv0
, '/' ))) basename
= argv0
;
317 if (set_bindir( get_runtime_exedir() )) goto done
;
318 if (set_dlldir( get_runtime_libdir() )) goto done
;
319 if (set_bindir( get_runtime_argvdir( argv0
))) goto done
;
320 if ((wineloader
= getenv( "WINELOADER" ))) set_bindir( get_runtime_argvdir( wineloader
));
325 argv0_name
= build_path( "loader/", basename
);
326 if (sizeof(int) == sizeof(void *))
328 char *loader
, *linkname
= build_path( build_dir
, "loader/wine64" );
329 if ((loader
= symlink_dirname( linkname
)))
331 wineserver64
= build_path( loader
, "../server/wineserver" );
339 if (bindir
) datadir
= build_path( bindir
, BIN_TO_DATADIR
);
340 argv0_name
= xstrdup( basename
);
344 static const char server_config_dir
[] = "/.wine"; /* config dir relative to $HOME */
345 static const char server_root_prefix
[] = "/tmp/.wine"; /* prefix for server root dir */
346 static const char server_dir_prefix
[] = "/server-"; /* prefix for server dir */
348 static char *config_dir
;
349 static char *server_dir
;
350 static char *user_name
;
352 /* check if a string ends in a given substring */
353 static inline int strendswith( const char* str
, const char* end
)
355 size_t len
= strlen( str
);
356 size_t tail
= strlen( end
);
357 return len
>= tail
&& !strcmp( str
+ len
- tail
, end
);
360 /* remove all trailing slashes from a path name */
361 static inline void remove_trailing_slashes( char *path
)
363 int len
= strlen( path
);
364 while (len
> 1 && path
[len
-1] == '/') path
[--len
] = 0;
367 /* die on a fatal error */
368 static void fatal_perror( const char *err
, ... )
372 va_start( args
, err
);
373 fprintf( stderr
, "wine: " );
374 vfprintf( stderr
, err
, args
);
380 /* initialize the server directory value */
381 static void init_server_dir( dev_t dev
, ino_t ino
)
385 #ifdef __ANDROID__ /* there's no /tmp dir on Android */
386 root
= build_path( config_dir
, ".wineserver" );
388 root
= xmalloc( sizeof(server_root_prefix
) + 12 );
389 sprintf( root
, "%s-%u", server_root_prefix
, getuid() );
392 server_dir
= xmalloc( strlen(root
) + sizeof(server_dir_prefix
) + 2*sizeof(dev
) + 2*sizeof(ino
) + 2 );
393 strcpy( server_dir
, root
);
394 strcat( server_dir
, server_dir_prefix
);
395 p
= server_dir
+ strlen(server_dir
);
397 if (dev
!= (unsigned long)dev
)
398 p
+= sprintf( p
, "%lx%08lx-", (unsigned long)((unsigned long long)dev
>> 32), (unsigned long)dev
);
400 p
+= sprintf( p
, "%lx-", (unsigned long)dev
);
402 if (ino
!= (unsigned long)ino
)
403 sprintf( p
, "%lx%08lx", (unsigned long)((unsigned long long)ino
>> 32), (unsigned long)ino
);
405 sprintf( p
, "%lx", (unsigned long)ino
);
409 /* initialize all the paths values */
410 static void init_paths(void)
414 const char *home
= getenv( "HOME" );
415 const char *user
= NULL
;
416 const char *prefix
= getenv( "WINEPREFIX" );
418 struct passwd
*pwd
= getpwuid( getuid() );
423 if (!home
) home
= pwd
->pw_dir
;
427 sprintf( uid_str
, "%lu", (unsigned long)getuid() );
430 user_name
= xstrdup( user
);
432 /* build config_dir */
436 config_dir
= xstrdup( prefix
);
437 remove_trailing_slashes( config_dir
);
438 if (config_dir
[0] != '/')
439 fatal_error( "invalid directory %s in WINEPREFIX: not an absolute path\n", prefix
);
440 if (stat( config_dir
, &st
) == -1)
442 if (errno
== ENOENT
) return; /* will be created later on */
443 fatal_perror( "cannot open %s as specified in WINEPREFIX", config_dir
);
448 if (!home
) fatal_error( "could not determine your home directory\n" );
449 if (home
[0] != '/') fatal_error( "your home directory %s is not an absolute path\n", home
);
450 config_dir
= xmalloc( strlen(home
) + sizeof(server_config_dir
) );
451 strcpy( config_dir
, home
);
452 remove_trailing_slashes( config_dir
);
453 strcat( config_dir
, server_config_dir
);
454 if (stat( config_dir
, &st
) == -1)
456 if (errno
== ENOENT
) return; /* will be created later on */
457 fatal_perror( "cannot open %s", config_dir
);
460 if (!S_ISDIR(st
.st_mode
)) fatal_error( "%s is not a directory\n", config_dir
);
461 if (st
.st_uid
!= getuid()) fatal_error( "%s is not owned by you\n", config_dir
);
462 init_server_dir( st
.st_dev
, st
.st_ino
);
465 /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
466 const char *wine_get_config_dir_obsolete(void)
468 if (!config_dir
) init_paths();
472 /* retrieve the wine data dir */
473 const char *wine_get_data_dir_obsolete(void)
478 /* retrieve the wine build dir (if we are running from there) */
479 const char *wine_get_build_dir_obsolete(void)
484 /* return the full name of the server directory (the one containing the socket) */
485 const char *wine_get_server_dir_obsolete(void)
489 if (!config_dir
) init_paths();
494 if (stat( config_dir
, &st
) == -1)
496 if (errno
!= ENOENT
) fatal_error( "cannot stat %s\n", config_dir
);
497 return NULL
; /* will have to try again once config_dir has been created */
499 init_server_dir( st
.st_dev
, st
.st_ino
);
505 /* return the current user name */
506 const char *wine_get_user_name_obsolete(void)
508 if (!user_name
) init_paths();
512 /* return the standard version string */
513 const char *wine_get_version_obsolete(void)
515 return PACKAGE_VERSION
;
518 /* return the build id string */
519 const char *wine_get_build_id_obsolete(void)
521 return PACKAGE_VERSION
;
524 /* exec a binary using the preloader if requested; helper for wine_exec_wine_binary */
525 static void preloader_exec( char **argv
, int use_preloader
)
529 static const char preloader
[] = "wine-preloader";
530 static const char preloader64
[] = "wine64-preloader";
532 char **last_arg
= argv
, **new_argv
;
534 if (!(p
= strrchr( argv
[0], '/' ))) p
= argv
[0];
537 full_name
= xmalloc( p
- argv
[0] + sizeof(preloader64
) );
538 memcpy( full_name
, argv
[0], p
- argv
[0] );
539 if (strendswith( p
, "64" ))
540 memcpy( full_name
+ (p
- argv
[0]), preloader64
, sizeof(preloader64
) );
542 memcpy( full_name
+ (p
- argv
[0]), preloader
, sizeof(preloader
) );
544 /* make a copy of argv */
545 while (*last_arg
) last_arg
++;
546 new_argv
= xmalloc( (last_arg
- argv
+ 2) * sizeof(*argv
) );
547 memcpy( new_argv
+ 1, argv
, (last_arg
- argv
+ 1) * sizeof(*argv
) );
548 new_argv
[0] = full_name
;
551 posix_spawnattr_t attr
;
552 posix_spawnattr_init( &attr
);
553 posix_spawnattr_setflags( &attr
, POSIX_SPAWN_SETEXEC
| _POSIX_SPAWN_DISABLE_ASLR
);
554 posix_spawn( NULL
, full_name
, NULL
, &attr
, new_argv
, *_NSGetEnviron() );
555 posix_spawnattr_destroy( &attr
);
558 execv( full_name
, new_argv
);
562 execv( argv
[0], argv
);
565 /* exec a wine internal binary (either the wine loader or the wine server) */
566 void wine_exec_wine_binary_obsolete( const char *name
, char **argv
, const char *env_var
)
568 const char *path
, *pos
, *ptr
;
571 if (!name
) name
= argv0_name
; /* no name means default loader */
573 #if defined(linux) || defined(__APPLE__)
574 use_preloader
= !strendswith( name
, "wineserver" );
579 if ((ptr
= strrchr( name
, '/' )))
581 /* if we are in build dir and name contains a path, try that */
584 if (wineserver64
&& !strcmp( name
, "server/wineserver" ))
585 argv
[0] = xstrdup( wineserver64
);
587 argv
[0] = build_path( build_dir
, name
);
588 preloader_exec( argv
, use_preloader
);
591 name
= ptr
+ 1; /* get rid of path */
594 /* first, bin directory from the current libdir or argv0 */
597 argv
[0] = build_path( bindir
, name
);
598 preloader_exec( argv
, use_preloader
);
602 /* then specified environment variable */
605 argv
[0] = (char *)env_var
;
606 preloader_exec( argv
, use_preloader
);
609 /* now search in the Unix path */
610 if ((path
= getenv( "PATH" )))
612 argv
[0] = xmalloc( strlen(path
) + strlen(name
) + 2 );
616 while (*pos
== ':') pos
++;
618 if (!(ptr
= strchr( pos
, ':' ))) ptr
= pos
+ strlen(pos
);
619 memcpy( argv
[0], pos
, ptr
- pos
);
620 strcpy( argv
[0] + (ptr
- pos
), "/" );
621 strcat( argv
[0] + (ptr
- pos
), name
);
622 preloader_exec( argv
, use_preloader
);
628 /* and finally try BINDIR */
629 argv
[0] = build_path( BINDIR
, name
);
630 preloader_exec( argv
, use_preloader
);
634 __ASM_OBSOLETE(wine_init_argv0_path
);
635 __ASM_OBSOLETE(wine_get_build_dir
);
636 __ASM_OBSOLETE(wine_get_build_id
);
637 __ASM_OBSOLETE(wine_get_config_dir
);
638 __ASM_OBSOLETE(wine_get_data_dir
);
639 __ASM_OBSOLETE(wine_get_server_dir
);
640 __ASM_OBSOLETE(wine_get_user_name
);
641 __ASM_OBSOLETE(wine_get_version
);
642 __ASM_OBSOLETE(wine_exec_wine_binary
);
644 #endif /* __ASM_OBSOLETE */