diff --git a/libs/wine/Makefile.in b/libs/wine/Makefile.in index b9ddf42b971..34b64007148 100644 --- a/libs/wine/Makefile.in +++ b/libs/wine/Makefile.in @@ -5,7 +5,7 @@ VPATH = @srcdir@ LIBRARY = wine SOVERSION = 1 VERSCRIPT = $(SRCDIR)/wine.map -EXTRADEFS = -D__WINESRC__ -DBINDIR="\"$(bindir)\"" -DDLLDIR="\"$(dlldir)\"" +EXTRADEFS = -D__WINESRC__ -DBINDIR="\"$(bindir)\"" -DLIBDIR="\"$(libdir)\"" -DDLLDIR="\"$(dlldir)\"" EXTRALIBS = $(LIBPORT) @DLLIBS@ @CRTLIBS@ @LDLIBWINEFLAGS@ C_SRCS = \ diff --git a/libs/wine/config.c b/libs/wine/config.c index b2b039c7f1e..33aa87a8ea4 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c @@ -101,6 +101,103 @@ inline static void remove_trailing_slashes( char *path ) while (len > 1 && path[len-1] == '/') path[--len] = 0; } +/* determine where the destination path is located relative to the 'from' path */ +inline static const char *get_relative_path( const char *from, const char *dest, unsigned int *dotdots ) +{ +#define DIR_END(p) (*(p) == 0 || *(p) == '/') + const char *start; + + *dotdots = 0; + for (;;) + { + while (*from == '/') from++; + while (*dest == '/') dest++; + start = dest; /* save start of next path element */ + if (!*from) break; + + while (!DIR_END(from) && *from == *dest) { from++; dest++; } + if (DIR_END(from) && DIR_END(dest)) continue; + + /* count remaining elements in 'from' */ + do + { + (*dotdots)++; + while (!DIR_END(from)) from++; + while (*from == '/') from++; + } + while (*from); + break; + } + return start; +#undef DIR_END +} + +/* return the directory that contains the library at run-time */ +static const char *get_runtime_libdir(void) +{ + static char *libdir; + +#ifdef HAVE_DLADDR + Dl_info info; + char *p; + + if (!libdir && dladdr( get_runtime_libdir, &info ) && (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; + } +#endif /* HAVE_DLADDR */ + return libdir; +} + +/* determine the proper location of the given path based on the current libdir */ +static char *get_path_from_libdir( const char *path, const char *filename ) +{ + char *p, *ret; + const char *libdir = get_runtime_libdir(); + + /* retrieve the library load path */ + + if (libdir) + { + unsigned int dotdots = 0; + const char *start = get_relative_path( LIBDIR, path, &dotdots ); + + ret = xmalloc( strlen(libdir) + 3 * dotdots + strlen(start) + strlen(filename) + 3 ); + strcpy( ret, libdir ); + p = ret + strlen(libdir); + if (p[-1] != '/') *p++ = '/'; + + while (dotdots--) + { + p[0] = '.'; + p[1] = '.'; + p[2] = '/'; + p += 3; + } + + strcpy( p, start ); + p += strlen(p); + } + else + { + ret = xmalloc( strlen(path) + strlen(filename) + 2 ); + strcpy( ret, path ); + p = ret + strlen(ret); + } + + if (*filename) + { + if (p[-1] != '/') *p++ = '/'; + strcpy( p, filename ); + } + else if (p[-1] == '/') p[-1] = 0; + return ret; +} + /* initialize the server directory value */ static void init_server_dir( dev_t dev, ino_t ino ) { @@ -127,6 +224,15 @@ static void init_server_dir( dev_t dev, ino_t ino ) sprintf( p, "%lx", (unsigned long)ino ); } +/* retrieve the default dll dir */ +const char *get_default_dlldir(void) +{ + static const char *dlldir; + + if (!dlldir) dlldir = get_path_from_libdir( DLLDIR, "" ); + return dlldir; +} + /* initialize all the paths values */ static void init_paths(void) { @@ -314,9 +420,7 @@ void wine_exec_wine_binary( const char *name, char **argv, char **envp, int use_ else if (!name) name = argv0_name; /* first, try bin directory */ - argv[0] = xmalloc( sizeof(BINDIR "/") + strlen(name) ); - strcpy( argv[0], BINDIR "/" ); - strcat( argv[0], name ); + argv[0] = get_path_from_libdir( BINDIR, name ); preloader_exec( argv, envp, use_preloader ); free( argv[0] ); diff --git a/libs/wine/loader.c b/libs/wine/loader.c index 50ab544d6c1..e58ab7c0e41 100644 --- a/libs/wine/loader.c +++ b/libs/wine/loader.c @@ -74,13 +74,14 @@ static const IMAGE_NT_HEADERS *main_exe; static load_dll_callback_t load_dll_callback; -static const char default_dlldir[] = DLLDIR; +static const char *default_dlldir; static const char **dll_paths; static int nb_dll_paths; static int dll_path_maxlen; extern void mmap_init(void); extern void debug_init(void); +extern const char *get_default_dlldir(void); /* build the dll load path from the WINEDLLPATH variable */ static void build_dll_path(void) @@ -121,7 +122,8 @@ static void build_dll_path(void) } /* append default dll dir (if not empty) to path */ - if ((len = sizeof(default_dlldir)-1)) + default_dlldir = get_default_dlldir(); + if ((len = strlen(default_dlldir)) > 0) { if (len > dll_path_maxlen) dll_path_maxlen = len; dll_paths[nb_dll_paths++] = default_dlldir;