123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636 |
- /*
- * Configuration parameters shared between Wine server and clients
- *
- * Copyright 2002 Alexandre Julliard
- *
- * 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
- */
- #include "config.h"
- #include "wine/port.h"
- #include "wine/asm.h"
- #ifdef __ASM_OBSOLETE
- #include <stdio.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
- #include <errno.h>
- #include <sys/stat.h>
- #ifdef HAVE_UNISTD_H
- # include <unistd.h>
- #endif
- #ifdef HAVE_PWD_H
- #include <pwd.h>
- #endif
- #ifdef __APPLE__
- #include <crt_externs.h>
- #include <spawn.h>
- #ifndef _POSIX_SPAWN_DISABLE_ASLR
- #define _POSIX_SPAWN_DISABLE_ASLR 0x0100
- #endif
- #endif
- static char *bindir;
- static char *dlldir;
- static char *datadir;
- const char *build_dir;
- static char *argv0_name;
- static char *wineserver64;
- #ifdef __GNUC__
- static void fatal_error( const char *err, ... ) __attribute__((noreturn,format(printf,1,2)));
- #endif
- #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
- static const char exe_link[] = "/proc/self/exe";
- #elif defined (__FreeBSD__) || defined(__DragonFly__)
- static const char exe_link[] = "/proc/curproc/file";
- #else
- static const char exe_link[] = "";
- #endif
- /* die on a fatal error */
- static void fatal_error( const char *err, ... )
- {
- va_list args;
- va_start( args, err );
- fprintf( stderr, "wine: " );
- vfprintf( stderr, err, args );
- va_end( args );
- exit(1);
- }
- /* malloc wrapper */
- static void *xmalloc( size_t size )
- {
- void *res;
- if (!size) size = 1;
- if (!(res = malloc( size ))) fatal_error( "virtual memory exhausted\n");
- return res;
- }
- /* strdup wrapper */
- static char *xstrdup( const char *str )
- {
- size_t len = strlen(str) + 1;
- char *res = xmalloc( len );
- memcpy( res, str, len );
- return res;
- }
- /* build a path from the specified dir and name */
- static char *build_path( const char *dir, const char *name )
- {
- size_t len = strlen(dir);
- char *ret = xmalloc( len + strlen(name) + 2 );
- memcpy( ret, dir, len );
- if (len && ret[len-1] != '/') ret[len++] = '/';
- strcpy( ret + len, name );
- return ret;
- }
- /* return the directory that contains the library at run-time */
- static char *get_runtime_libdir(void)
- {
- #ifdef HAVE_DLADDR
- Dl_info info;
- char *libdir;
- if (dladdr( get_runtime_libdir, &info ) && info.dli_fname[0] == '/')
- {
- const char *p = strrchr( info.dli_fname, '/' );
- unsigned int len = p - info.dli_fname;
- if (!len) len++; /* include initial slash */
- libdir = xmalloc( len + 1 );
- memcpy( libdir, info.dli_fname, len );
- libdir[len] = 0;
- return libdir;
- }
- #endif /* HAVE_DLADDR */
- return NULL;
- }
- /* read a symlink and return its directory */
- static char *symlink_dirname( const char *name )
- {
- char *p, *fullpath = realpath( name, NULL );
- if (fullpath)
- {
- p = strrchr( fullpath, '/' );
- if (p == fullpath) p++;
- if (p) *p = 0;
- }
- return fullpath;
- }
- /* return the directory that contains the main exe at run-time */
- static char *get_runtime_exedir(void)
- {
- if (exe_link[0]) return symlink_dirname( exe_link );
- return NULL;
- }
- /* return the base directory from argv0 */
- static char *get_runtime_argvdir( const char *argv0 )
- {
- char *p, *bindir, *cwd;
- int len, size;
- if (!(p = strrchr( argv0, '/' ))) return NULL;
- len = p - argv0;
- if (!len) len++; /* include leading slash */
- if (argv0[0] == '/') /* absolute path */
- {
- bindir = xmalloc( len + 1 );
- memcpy( bindir, argv0, len );
- bindir[len] = 0;
- }
- else
- {
- /* relative path, make it absolute */
- for (size = 256 + len; ; size *= 2)
- {
- if (!(cwd = malloc( size ))) return NULL;
- if (getcwd( cwd, size - len ))
- {
- bindir = cwd;
- cwd += strlen(cwd);
- *cwd++ = '/';
- memcpy( cwd, argv0, len );
- cwd[len] = 0;
- break;
- }
- free( cwd );
- if (errno != ERANGE) return NULL;
- }
- }
- return bindir;
- }
- /* retrieve the default dll dir */
- const char *get_dlldir( const char **default_dlldir )
- {
- *default_dlldir = DLLDIR;
- return dlldir;
- }
- /* check if bindir is valid by checking for wineserver */
- static int is_valid_bindir( const char *bindir )
- {
- struct stat st;
- char *path = build_path( bindir, "wineserver" );
- int ret = (stat( path, &st ) != -1);
- free( path );
- return ret;
- }
- /* check if dlldir is valid by checking for ntdll */
- static int is_valid_dlldir( const char *dlldir )
- {
- struct stat st;
- char *path = build_path( dlldir, "ntdll.dll.so" );
- int ret = (stat( path, &st ) != -1);
- free( path );
- return ret;
- }
- /* check if basedir is a valid build dir by checking for wineserver and ntdll */
- /* helper for running_from_build_dir */
- static inline int is_valid_build_dir( char *basedir, int baselen )
- {
- struct stat st;
- strcpy( basedir + baselen, "/server/wineserver" );
- if (stat( basedir, &st ) == -1) return 0; /* no wineserver found */
- /* check for ntdll too to make sure */
- strcpy( basedir + baselen, "/dlls/ntdll/ntdll.dll.so" );
- if (stat( basedir, &st ) == -1) return 0; /* no ntdll found */
- basedir[baselen] = 0;
- return 1;
- }
- /* check if we are running from the build directory */
- static char *running_from_build_dir( const char *basedir )
- {
- const char *p;
- char *path;
- /* remove last component from basedir */
- p = basedir + strlen(basedir) - 1;
- while (p > basedir && *p == '/') p--;
- while (p > basedir && *p != '/') p--;
- if (p == basedir) return NULL;
- path = xmalloc( p - basedir + sizeof("/dlls/ntdll/ntdll.dll.so") );
- memcpy( path, basedir, p - basedir );
- if (!is_valid_build_dir( path, p - basedir ))
- {
- /* remove another component */
- while (p > basedir && *p == '/') p--;
- while (p > basedir && *p != '/') p--;
- if (p == basedir || !is_valid_build_dir( path, p - basedir ))
- {
- free( path );
- return NULL;
- }
- }
- return path;
- }
- /* try to set the specified directory as bindir, or set build_dir if it's inside the build directory */
- static int set_bindir( char *dir )
- {
- if (!dir) return 0;
- if (is_valid_bindir( dir ))
- {
- bindir = dir;
- dlldir = build_path( bindir, BIN_TO_DLLDIR );
- }
- else
- {
- build_dir = running_from_build_dir( dir );
- free( dir );
- }
- return bindir || build_dir;
- }
- /* try to set the specified directory as dlldir, or set build_dir if it's inside the build directory */
- static int set_dlldir( char *libdir )
- {
- char *path;
- if (!libdir) return 0;
- path = build_path( libdir, LIB_TO_DLLDIR );
- if (is_valid_dlldir( path ))
- {
- dlldir = path;
- bindir = build_path( libdir, LIB_TO_BINDIR );
- }
- else
- {
- build_dir = running_from_build_dir( libdir );
- free( path );
- }
- free( libdir );
- return dlldir || build_dir;
- }
- /* initialize the argv0 path */
- void wine_init_argv0_path_obsolete( const char *argv0 )
- {
- const char *basename, *wineloader;
- if (!(basename = strrchr( argv0, '/' ))) basename = argv0;
- else basename++;
- if (set_bindir( get_runtime_exedir() )) goto done;
- if (set_dlldir( get_runtime_libdir() )) goto done;
- if (set_bindir( get_runtime_argvdir( argv0 ))) goto done;
- if ((wineloader = getenv( "WINELOADER" ))) set_bindir( get_runtime_argvdir( wineloader ));
- done:
- if (build_dir)
- {
- argv0_name = build_path( "loader/", basename );
- if (sizeof(int) == sizeof(void *))
- {
- char *loader, *linkname = build_path( build_dir, "loader/wine64" );
- if ((loader = symlink_dirname( linkname )))
- {
- wineserver64 = build_path( loader, "../server/wineserver" );
- free( loader );
- }
- free( linkname );
- }
- }
- else
- {
- if (bindir) datadir = build_path( bindir, BIN_TO_DATADIR );
- argv0_name = xstrdup( basename );
- }
- }
- static const char server_config_dir[] = "/.wine"; /* config dir relative to $HOME */
- static const char server_root_prefix[] = "/tmp/.wine"; /* prefix for server root dir */
- static const char server_dir_prefix[] = "/server-"; /* prefix for server dir */
- static char *config_dir;
- static char *server_dir;
- static char *user_name;
- /* check if a string ends in a given substring */
- static inline int strendswith( const char* str, const char* end )
- {
- size_t len = strlen( str );
- size_t tail = strlen( end );
- return len >= tail && !strcmp( str + len - tail, end );
- }
- /* remove all trailing slashes from a path name */
- static inline void remove_trailing_slashes( char *path )
- {
- int len = strlen( path );
- while (len > 1 && path[len-1] == '/') path[--len] = 0;
- }
- /* die on a fatal error */
- static void fatal_perror( const char *err, ... )
- {
- va_list args;
- va_start( args, err );
- fprintf( stderr, "wine: " );
- vfprintf( stderr, err, args );
- perror( " " );
- va_end( args );
- exit(1);
- }
- /* initialize the server directory value */
- static void init_server_dir( dev_t dev, ino_t ino )
- {
- char *p, *root;
- #ifdef __ANDROID__ /* there's no /tmp dir on Android */
- root = build_path( config_dir, ".wineserver" );
- #else
- root = xmalloc( sizeof(server_root_prefix) + 12 );
- sprintf( root, "%s-%u", server_root_prefix, getuid() );
- #endif
- server_dir = xmalloc( strlen(root) + sizeof(server_dir_prefix) + 2*sizeof(dev) + 2*sizeof(ino) + 2 );
- strcpy( server_dir, root );
- strcat( server_dir, server_dir_prefix );
- p = server_dir + strlen(server_dir);
- if (dev != (unsigned long)dev)
- p += sprintf( p, "%lx%08lx-", (unsigned long)((unsigned long long)dev >> 32), (unsigned long)dev );
- else
- p += sprintf( p, "%lx-", (unsigned long)dev );
- if (ino != (unsigned long)ino)
- sprintf( p, "%lx%08lx", (unsigned long)((unsigned long long)ino >> 32), (unsigned long)ino );
- else
- sprintf( p, "%lx", (unsigned long)ino );
- free( root );
- }
- /* initialize all the paths values */
- static void init_paths(void)
- {
- struct stat st;
- const char *home = getenv( "HOME" );
- const char *user = NULL;
- const char *prefix = getenv( "WINEPREFIX" );
- char uid_str[32];
- struct passwd *pwd = getpwuid( getuid() );
- if (pwd)
- {
- user = pwd->pw_name;
- if (!home) home = pwd->pw_dir;
- }
- if (!user)
- {
- sprintf( uid_str, "%lu", (unsigned long)getuid() );
- user = uid_str;
- }
- user_name = xstrdup( user );
- /* build config_dir */
- if (prefix)
- {
- config_dir = xstrdup( prefix );
- remove_trailing_slashes( config_dir );
- if (config_dir[0] != '/')
- fatal_error( "invalid directory %s in WINEPREFIX: not an absolute path\n", prefix );
- if (stat( config_dir, &st ) == -1)
- {
- if (errno == ENOENT) return; /* will be created later on */
- fatal_perror( "cannot open %s as specified in WINEPREFIX", config_dir );
- }
- }
- else
- {
- if (!home) fatal_error( "could not determine your home directory\n" );
- if (home[0] != '/') fatal_error( "your home directory %s is not an absolute path\n", home );
- config_dir = xmalloc( strlen(home) + sizeof(server_config_dir) );
- strcpy( config_dir, home );
- remove_trailing_slashes( config_dir );
- strcat( config_dir, server_config_dir );
- if (stat( config_dir, &st ) == -1)
- {
- if (errno == ENOENT) return; /* will be created later on */
- fatal_perror( "cannot open %s", config_dir );
- }
- }
- if (!S_ISDIR(st.st_mode)) fatal_error( "%s is not a directory\n", config_dir );
- if (st.st_uid != getuid()) fatal_error( "%s is not owned by you\n", config_dir );
- init_server_dir( st.st_dev, st.st_ino );
- }
- /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
- const char *wine_get_config_dir_obsolete(void)
- {
- if (!config_dir) init_paths();
- return config_dir;
- }
- /* retrieve the wine data dir */
- const char *wine_get_data_dir_obsolete(void)
- {
- return datadir;
- }
- /* retrieve the wine build dir (if we are running from there) */
- const char *wine_get_build_dir_obsolete(void)
- {
- return build_dir;
- }
- /* return the full name of the server directory (the one containing the socket) */
- const char *wine_get_server_dir_obsolete(void)
- {
- if (!server_dir)
- {
- if (!config_dir) init_paths();
- else
- {
- struct stat st;
- if (stat( config_dir, &st ) == -1)
- {
- if (errno != ENOENT) fatal_error( "cannot stat %s\n", config_dir );
- return NULL; /* will have to try again once config_dir has been created */
- }
- init_server_dir( st.st_dev, st.st_ino );
- }
- }
- return server_dir;
- }
- /* return the current user name */
- const char *wine_get_user_name_obsolete(void)
- {
- if (!user_name) init_paths();
- return user_name;
- }
- /* return the standard version string */
- const char *wine_get_version_obsolete(void)
- {
- return PACKAGE_VERSION;
- }
- /* return the build id string */
- const char *wine_get_build_id_obsolete(void)
- {
- return PACKAGE_VERSION;
- }
- /* exec a binary using the preloader if requested; helper for wine_exec_wine_binary */
- static void preloader_exec( char **argv, int use_preloader )
- {
- if (use_preloader)
- {
- static const char preloader[] = "wine-preloader";
- static const char preloader64[] = "wine64-preloader";
- char *p, *full_name;
- char **last_arg = argv, **new_argv;
- if (!(p = strrchr( argv[0], '/' ))) p = argv[0];
- else p++;
- full_name = xmalloc( p - argv[0] + sizeof(preloader64) );
- memcpy( full_name, argv[0], p - argv[0] );
- if (strendswith( p, "64" ))
- memcpy( full_name + (p - argv[0]), preloader64, sizeof(preloader64) );
- else
- memcpy( full_name + (p - argv[0]), preloader, sizeof(preloader) );
- /* make a copy of argv */
- while (*last_arg) last_arg++;
- new_argv = xmalloc( (last_arg - argv + 2) * sizeof(*argv) );
- memcpy( new_argv + 1, argv, (last_arg - argv + 1) * sizeof(*argv) );
- new_argv[0] = full_name;
- #ifdef __APPLE__
- {
- posix_spawnattr_t attr;
- posix_spawnattr_init( &attr );
- posix_spawnattr_setflags( &attr, POSIX_SPAWN_SETEXEC | _POSIX_SPAWN_DISABLE_ASLR );
- posix_spawn( NULL, full_name, NULL, &attr, new_argv, *_NSGetEnviron() );
- posix_spawnattr_destroy( &attr );
- }
- #endif
- execv( full_name, new_argv );
- free( new_argv );
- free( full_name );
- }
- execv( argv[0], argv );
- }
- /* exec a wine internal binary (either the wine loader or the wine server) */
- void wine_exec_wine_binary_obsolete( const char *name, char **argv, const char *env_var )
- {
- const char *path, *pos, *ptr;
- int use_preloader;
- if (!name) name = argv0_name; /* no name means default loader */
- #if defined(linux) || defined(__APPLE__)
- use_preloader = !strendswith( name, "wineserver" );
- #else
- use_preloader = 0;
- #endif
- if ((ptr = strrchr( name, '/' )))
- {
- /* if we are in build dir and name contains a path, try that */
- if (build_dir)
- {
- if (wineserver64 && !strcmp( name, "server/wineserver" ))
- argv[0] = xstrdup( wineserver64 );
- else
- argv[0] = build_path( build_dir, name );
- preloader_exec( argv, use_preloader );
- free( argv[0] );
- }
- name = ptr + 1; /* get rid of path */
- }
- /* first, bin directory from the current libdir or argv0 */
- if (bindir)
- {
- argv[0] = build_path( bindir, name );
- preloader_exec( argv, use_preloader );
- free( argv[0] );
- }
- /* then specified environment variable */
- if (env_var)
- {
- argv[0] = (char *)env_var;
- preloader_exec( argv, use_preloader );
- }
- /* now search in the Unix path */
- if ((path = getenv( "PATH" )))
- {
- argv[0] = xmalloc( strlen(path) + strlen(name) + 2 );
- pos = path;
- for (;;)
- {
- while (*pos == ':') pos++;
- if (!*pos) break;
- if (!(ptr = strchr( pos, ':' ))) ptr = pos + strlen(pos);
- memcpy( argv[0], pos, ptr - pos );
- strcpy( argv[0] + (ptr - pos), "/" );
- strcat( argv[0] + (ptr - pos), name );
- preloader_exec( argv, use_preloader );
- pos = ptr;
- }
- free( argv[0] );
- }
- /* and finally try BINDIR */
- argv[0] = build_path( BINDIR, name );
- preloader_exec( argv, use_preloader );
- free( argv[0] );
- }
- __ASM_OBSOLETE(wine_init_argv0_path);
- __ASM_OBSOLETE(wine_get_build_dir);
- __ASM_OBSOLETE(wine_get_build_id);
- __ASM_OBSOLETE(wine_get_config_dir);
- __ASM_OBSOLETE(wine_get_data_dir);
- __ASM_OBSOLETE(wine_get_server_dir);
- __ASM_OBSOLETE(wine_get_user_name);
- __ASM_OBSOLETE(wine_get_version);
- __ASM_OBSOLETE(wine_exec_wine_binary);
- #endif /* __ASM_OBSOLETE */
|