main.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * Emulator initialisation code
  3. *
  4. * Copyright 2000 Alexandre Julliard
  5. *
  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.
  10. *
  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.
  15. *
  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
  19. */
  20. #include "config.h"
  21. #include <fcntl.h>
  22. #include <pthread.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. #include <sys/stat.h>
  28. #include <unistd.h>
  29. #include <dlfcn.h>
  30. #include <limits.h>
  31. #ifdef HAVE_SYS_SYSCTL_H
  32. # include <sys/sysctl.h>
  33. #endif
  34. #include "main.h"
  35. extern char **environ;
  36. /* the preloader will set this variable */
  37. const struct wine_preload_info *wine_main_preload_info = NULL;
  38. /* canonicalize path and return its directory name */
  39. static char *realpath_dirname( const char *name )
  40. {
  41. char *p, *fullpath = realpath( name, NULL );
  42. if (fullpath)
  43. {
  44. p = strrchr( fullpath, '/' );
  45. if (p == fullpath) p++;
  46. if (p) *p = 0;
  47. }
  48. return fullpath;
  49. }
  50. /* if string ends with tail, remove it */
  51. static char *remove_tail( const char *str, const char *tail )
  52. {
  53. size_t len = strlen( str );
  54. size_t tail_len = strlen( tail );
  55. char *ret;
  56. if (len < tail_len) return NULL;
  57. if (strcmp( str + len - tail_len, tail )) return NULL;
  58. ret = malloc( len - tail_len + 1 );
  59. memcpy( ret, str, len - tail_len );
  60. ret[len - tail_len] = 0;
  61. return ret;
  62. }
  63. /* build a path from the specified dir and name */
  64. static char *build_path( const char *dir, const char *name )
  65. {
  66. size_t len = strlen( dir );
  67. char *ret = malloc( len + strlen( name ) + 2 );
  68. memcpy( ret, dir, len );
  69. if (len && ret[len - 1] != '/') ret[len++] = '/';
  70. strcpy( ret + len, name );
  71. return ret;
  72. }
  73. static const char *get_self_exe( char *argv0 )
  74. {
  75. #if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
  76. return "/proc/self/exe";
  77. #elif defined (__FreeBSD__) || defined(__DragonFly__)
  78. static int pathname[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
  79. size_t path_size = PATH_MAX;
  80. char *path = malloc( path_size );
  81. if (path && !sysctl( pathname, sizeof(pathname)/sizeof(pathname[0]), path, &path_size, NULL, 0 ))
  82. return path;
  83. free( path );
  84. #endif
  85. if (!strchr( argv0, '/' )) /* search in PATH */
  86. {
  87. char *p, *path = getenv( "PATH" );
  88. if (!path || !(path = strdup(path))) return NULL;
  89. for (p = strtok( path, ":" ); p; p = strtok( NULL, ":" ))
  90. {
  91. char *name = build_path( p, argv0 );
  92. if (!access( name, X_OK ))
  93. {
  94. free( path );
  95. return name;
  96. }
  97. free( name );
  98. }
  99. free( path );
  100. return NULL;
  101. }
  102. return argv0;
  103. }
  104. static void *try_dlopen( const char *dir, const char *name )
  105. {
  106. char *path = build_path( dir, name );
  107. void *handle = dlopen( path, RTLD_NOW );
  108. free( path );
  109. return handle;
  110. }
  111. static void *load_ntdll( char *argv0 )
  112. {
  113. #ifdef __i386__
  114. #define SO_DIR "i386-unix/"
  115. #elif defined(__x86_64__)
  116. #define SO_DIR "x86_64-unix/"
  117. #elif defined(__arm__)
  118. #define SO_DIR "arm-unix/"
  119. #elif defined(__aarch64__)
  120. #define SO_DIR "aarch64-unix/"
  121. #else
  122. #define SO_DIR ""
  123. #endif
  124. const char *self = get_self_exe( argv0 );
  125. char *path, *p;
  126. void *handle = NULL;
  127. if (self && ((path = realpath_dirname( self ))))
  128. {
  129. if ((p = remove_tail( path, "/loader" )))
  130. {
  131. handle = try_dlopen( p, "dlls/ntdll/ntdll.so" );
  132. free( p );
  133. }
  134. else handle = try_dlopen( path, BIN_TO_DLLDIR "/" SO_DIR "ntdll.so" );
  135. free( path );
  136. }
  137. if (!handle && (path = getenv( "WINEDLLPATH" )))
  138. {
  139. path = strdup( path );
  140. for (p = strtok( path, ":" ); p; p = strtok( NULL, ":" ))
  141. {
  142. handle = try_dlopen( p, SO_DIR "ntdll.so" );
  143. if (!handle) handle = try_dlopen( p, "ntdll.so" );
  144. if (handle) break;
  145. }
  146. free( path );
  147. }
  148. if (!handle && !self) handle = try_dlopen( DLLDIR, SO_DIR "ntdll.so" );
  149. return handle;
  150. }
  151. /**********************************************************************
  152. * main
  153. */
  154. int main( int argc, char *argv[] )
  155. {
  156. void *handle;
  157. if ((handle = load_ntdll( argv[0] )))
  158. {
  159. void (*init_func)(int, char **, char **) = dlsym( handle, "__wine_main" );
  160. if (init_func) init_func( argc, argv, environ );
  161. fprintf( stderr, "wine: __wine_main function not found in ntdll.so\n" );
  162. exit(1);
  163. }
  164. fprintf( stderr, "wine: could not load ntdll.so: %s\n", dlerror() );
  165. pthread_detach( pthread_self() ); /* force importing libpthread for OpenGL */
  166. exit(1);
  167. }