Binary relocatability part 2

Mike Hearn mike at navi.cx
Sat Aug 28 06:50:07 CDT 2004


It might be worth putting read_symlink into libwine, rather than
duplicate the code.

On systems that don't use the standard FHS layout this will lead to a
useless dll path entry, but it should be harmless and for everybody who
does use the default layout it means you can place the wine binaries
anywhere at runtime.

I think these two patches do it a lot more cleanly than my previous
attempt back before WineConf, but let me know if it's got any more
problems.

thanks -mike

Mike Hearn <mike at navi.cx>
Allow relocatability on systems that support /proc/self/exe when using
the default directory layout.


-------------- next part --------------

--- libs/wine/loader.c.~1.21.~	2004-06-14 18:07:30.000000000 +0100
+++ libs/wine/loader.c	2004-08-22 22:46:03.778222560 +0100
@@ -80,12 +80,44 @@
 
 extern void mmap_init(void);
 
+static char *read_symlink( char *path )
+{
+    int size = 256;
+    char *buffer = NULL;
+
+    while (TRUE)
+    {
+        int nchars;
+        
+        buffer = (char *) realloc( buffer, size );
+        nchars = readlink( path, buffer, size );
+        
+        if (nchars < 0)
+        {
+            free( buffer );
+            return NULL;
+        }
+
+        if (nchars < size) return buffer;
+        size *= 2;
+    }
+}
+
+static int isdir( char *path )
+{
+    struct stat buf;
+    if (stat( path, &buf ) == 0) return S_ISDIR( buf );
+    
+    return 0;
+}
+
 /* build the dll load path from the WINEDLLPATH variable */
 static void build_dll_path(void)
 {
     static const char * const dlldir = DLLDIR;
     int len, count = 0;
     char *p, *path = getenv( "WINEDLLPATH" );
+    char *selfpath = read_symlink( "/proc/self/exe" );
 
     if (path)
     {
@@ -101,7 +133,10 @@
         }
     }
 
-    dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
+    if (selfpath)
+        dll_paths = malloc( (count+2) * sizeof(*dll_paths) );
+    else
+        dll_paths = malloc( (count+1) * sizeof(*dll_paths) );
 
     if (count)
     {
@@ -125,6 +160,33 @@
         if (len > dll_path_maxlen) dll_path_maxlen = len;
         dll_paths[nb_dll_paths++] = dlldir;
     }
+
+    /* on Linux we can dynamically discover our own DLL path  */
+    if (selfpath)
+    {
+        /* strip /bin/wine from our executable path */
+        char *marker = strrchr( selfpath, '/' );
+        static const char *libwinepath = "/lib/wine";
+        
+        if (!marker) goto end;
+        
+        marker = strrchr( marker, '/' );
+        if (!marker) goto end;
+
+        *marker = '\0';
+
+        selfpath = realloc( selfpath, strlen(selfpath) + strlen(libwinepath) + 1 );
+        strcat( selfpath, libwinepath );
+
+        if (!isdir( selfpath )) goto end;
+        
+        len = strlen( selfpath );
+        if (len > dll_path_maxlen) dll_path_maxlen = len;
+        dllpaths[nb_dll_paths++] = selfpath;
+    }
+    
+end:
+    if (selfpath) free( selfpath );
 }
 
 /* check if a given file can be opened */
--- dlls/ntdll/server.c.~1.17.~	2004-08-22 13:57:22.000000000 +0100
+++ dlls/ntdll/server.c	2004-08-22 23:51:56.136372792 +0100
@@ -709,6 +709,29 @@
     errno = err;
 }
 
+static char *read_symlink( char *path )
+{
+    int size = 256;
+    char *buffer = NULL;
+
+    while (TRUE)
+    {
+        int nchars;
+
+        buffer = (char *) realloc( buffer, size );
+        nchars = readlink( path, buffer, size );
+
+        if (nchars < 0)
+        {
+            free( buffer );
+            return NULL;
+        }
+
+        if (nchars < size) return buffer;
+        size *= 2;
+    }
+}
+
 
 /***********************************************************************
  *           create_config_dir
@@ -743,12 +766,26 @@
     if (!pid)
     {
         const char *argv[5];
+        char *selfpath = read_symlink( "/proc/self/exe" );
 
         argv[0] = "wineprefixcreate";
         argv[1] = "--quiet";
         argv[2] = "--prefix";
         argv[3] = tmp_dir;
         argv[4] = NULL;
+
+        /* set WINELOADER/WINESERVER to absolute path if not already in environment */
+        if (selfpath)
+        {
+            char *marker = strrchr( selfpath, '/' );
+            if (!strcmp( marker, "/wine-preloader" )) *strrchr( selfpath, '-' ) = '\0';
+            setenv( "WINELOADER", selfpath, 0 );
+
+            /* wine-preloader/wine-[pk]thread are long enough that we can just overwrite here  */
+            strcpy( marker, "/wineserver" );
+            setenv( "WINESERVER", selfpath, 0 );
+        }
+
         wine_exec_wine_binary( argv[0], (char **)argv, NULL, FALSE );
         rmdir( tmp_dir );
         fatal_perror( "could not exec wineprefixcreate" );


More information about the wine-patches mailing list