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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 #include "wine/port.h"
36 #include "wine/library.h"
38 static const char server_config_dir
[] = "/.wine"; /* config dir relative to $HOME */
39 static const char server_root_prefix
[] = "/tmp/.wine-"; /* prefix for server root dir */
40 static const char server_dir_prefix
[] = "/server-"; /* prefix for server dir */
45 static char *config_dir
;
46 static char *server_dir
;
47 static char *build_dir
;
48 static char *user_name
;
49 static char *argv0_name
;
52 static void fatal_error( const char *err
, ... ) __attribute__((noreturn
,format(printf
,1,2)));
53 static void fatal_perror( const char *err
, ... ) __attribute__((noreturn
,format(printf
,1,2)));
56 /* die on a fatal error */
57 static void fatal_error( const char *err
, ... )
61 va_start( args
, err
);
62 fprintf( stderr
, "wine: " );
63 vfprintf( stderr
, err
, args
);
68 /* die on a fatal error */
69 static void fatal_perror( const char *err
, ... )
73 va_start( args
, err
);
74 fprintf( stderr
, "wine: " );
75 vfprintf( stderr
, err
, args
);
82 static void *xmalloc( size_t size
)
87 if (!(res
= malloc( size
))) fatal_error( "virtual memory exhausted\n");
92 static char *xstrdup( const char *str
)
94 size_t len
= strlen(str
) + 1;
95 char *res
= xmalloc( len
);
96 memcpy( res
, str
, len
);
100 /* remove all trailing slashes from a path name */
101 inline static void remove_trailing_slashes( char *path
)
103 int len
= strlen( path
);
104 while (len
> 1 && path
[len
-1] == '/') path
[--len
] = 0;
107 /* build a path from the specified dir and name */
108 static char *build_path( const char *dir
, const char *name
)
110 size_t len
= strlen(dir
);
111 char *ret
= xmalloc( len
+ strlen(name
) + 2 );
113 memcpy( ret
, dir
, len
);
114 if (len
&& ret
[len
-1] != '/') ret
[len
++] = '/';
115 strcpy( ret
+ len
, name
);
119 /* return the directory that contains the library at run-time */
120 static const char *get_runtime_libdir(void)
126 if (dladdr( get_runtime_libdir
, &info
) && info
.dli_fname
[0] == '/')
128 const char *p
= strrchr( info
.dli_fname
, '/' );
129 unsigned int len
= p
- info
.dli_fname
;
130 if (!len
) len
++; /* include initial slash */
131 libdir
= xmalloc( len
+ 1 );
132 memcpy( libdir
, info
.dli_fname
, len
);
136 #endif /* HAVE_DLADDR */
140 /* initialize the server directory value */
141 static void init_server_dir( dev_t dev
, ino_t ino
)
145 const unsigned int uid
= getuid();
147 const unsigned int uid
= 0;
150 server_dir
= xmalloc( sizeof(server_root_prefix
) + 32 + sizeof(server_dir_prefix
) +
151 2*sizeof(dev
) + 2*sizeof(ino
) );
152 sprintf( server_dir
, "%s%u%s", server_root_prefix
, uid
, server_dir_prefix
);
153 p
= server_dir
+ strlen(server_dir
);
155 if (sizeof(dev
) > sizeof(unsigned long) && dev
> ~0UL)
156 p
+= sprintf( p
, "%lx%08lx-", (unsigned long)(dev
>> 32), (unsigned long)dev
);
158 p
+= sprintf( p
, "%lx-", (unsigned long)dev
);
160 if (sizeof(ino
) > sizeof(unsigned long) && ino
> ~0UL)
161 sprintf( p
, "%lx%08lx", (unsigned long)(ino
>> 32), (unsigned long)ino
);
163 sprintf( p
, "%lx", (unsigned long)ino
);
166 /* retrieve the default dll dir */
167 const char *get_dlldir( const char **default_dlldir
)
169 *default_dlldir
= DLLDIR
;
173 /* initialize all the paths values */
174 static void init_paths(void)
178 const char *home
= getenv( "HOME" );
179 const char *user
= NULL
;
180 const char *prefix
= getenv( "WINEPREFIX" );
184 struct passwd
*pwd
= getpwuid( getuid() );
189 if (!home
) home
= pwd
->pw_dir
;
193 sprintf( uid_str
, "%u", getuid() );
196 #else /* HAVE_GETPWUID */
197 if (!(user
= getenv( "USER" )))
198 fatal_error( "cannot determine your user name, set the USER environment variable\n" );
199 #endif /* HAVE_GETPWUID */
200 user_name
= xstrdup( user
);
202 /* build config_dir */
206 if (!(config_dir
= strdup( prefix
))) fatal_error( "virtual memory exhausted\n");
207 remove_trailing_slashes( config_dir
);
208 if (config_dir
[0] != '/')
209 fatal_error( "invalid directory %s in WINEPREFIX: not an absolute path\n", prefix
);
210 if (stat( config_dir
, &st
) == -1)
213 fatal_perror( "cannot open %s as specified in WINEPREFIX", config_dir
);
214 fatal_error( "the '%s' directory specified in WINEPREFIX doesn't exist.\n"
215 "You may want to create it by running 'wineprefixcreate'.\n", config_dir
);
220 if (!home
) fatal_error( "could not determine your home directory\n" );
221 if (home
[0] != '/') fatal_error( "your home directory %s is not an absolute path\n", home
);
222 config_dir
= xmalloc( strlen(home
) + sizeof(server_config_dir
) );
223 strcpy( config_dir
, home
);
224 remove_trailing_slashes( config_dir
);
225 strcat( config_dir
, server_config_dir
);
226 if (stat( config_dir
, &st
) == -1)
228 if (errno
== ENOENT
) return; /* will be created later on */
229 fatal_perror( "cannot open %s", config_dir
);
232 if (!S_ISDIR(st
.st_mode
)) fatal_error( "%s is not a directory\n", config_dir
);
234 init_server_dir( st
.st_dev
, st
.st_ino
);
237 /* check if we are running from the build directory */
238 static char *running_from_build_dir( const char *basedir
, const char *bindir
)
245 if (!(path
= build_path( bindir
, "wineserver" ))) return NULL
;
246 res
= stat( path
, &st
);
248 if (res
!= -1) return NULL
; /* the real bindir is valid */
250 /* remove last component from basedir */
251 p
= basedir
+ strlen(basedir
) - 1;
252 while (p
> basedir
&& *p
== '/') p
--;
253 while (p
> basedir
&& *p
!= '/') p
--;
254 if (p
== basedir
) return NULL
;
255 path
= xmalloc( p
- basedir
+ sizeof("/dlls/ntdll/ntdll.dll.so") );
256 memcpy( path
, basedir
, p
- basedir
);
257 end
= path
+ (p
- basedir
);
259 strcpy( end
, "/server/wineserver" );
260 if (stat( path
, &st
) == -1)
263 return NULL
; /* no wineserver found */
266 /* check for ntdll too to make sure */
267 strcpy( end
, "/dlls/ntdll/ntdll.dll.so" );
268 if (stat( path
, &st
) == -1)
271 return NULL
; /* no ntdll found */
278 /* initialize the argv0 path */
279 void wine_init_argv0_path( const char *argv0
)
282 const char *p
, *libdir
, *basename
;
285 if (!(p
= strrchr( argv0
, '/' )))
290 argv0_name
= xstrdup( basename
);
292 if ((libdir
= get_runtime_libdir()))
294 bindir
= build_path( libdir
, LIB_TO_BINDIR
);
295 if ((build_dir
= running_from_build_dir( libdir
, bindir
))) goto in_build_dir
;
297 dlldir
= build_path( libdir
, LIB_TO_DLLDIR
);
298 datadir
= build_path( libdir
, LIB_TO_DATADIR
);
302 if (!p
) return; /* if argv0 doesn't contain a path, don't store anything */
305 if (!len
) len
++; /* include leading slash */
307 if (argv0
[0] == '/') /* absolute path */
309 bindir
= xmalloc( len
+ 1 );
310 memcpy( bindir
, argv0
, len
);
315 /* relative path, make it absolute */
316 for (size
= 256 + len
; ; size
*= 2)
318 if (!(cwd
= malloc( size
))) return;
319 if (getcwd( cwd
, size
- len
))
324 memcpy( cwd
, argv0
, len
);
329 if (errno
!= ERANGE
) return;
333 if ((build_dir
= running_from_build_dir( bindir
, bindir
))) goto in_build_dir
;
335 dlldir
= build_path( bindir
, BIN_TO_DLLDIR
);
336 datadir
= build_path( bindir
, BIN_TO_DATADIR
);
343 argv0_name
= build_path( "loader/", basename
);
346 /* return the configuration directory ($WINEPREFIX or $HOME/.wine) */
347 const char *wine_get_config_dir(void)
349 if (!config_dir
) init_paths();
353 /* retrieve the wine data dir */
354 const char *wine_get_data_dir(void)
359 /* return the full name of the server directory (the one containing the socket) */
360 const char *wine_get_server_dir(void)
364 if (!config_dir
) init_paths();
369 if (stat( config_dir
, &st
) == -1)
371 if (errno
!= ENOENT
) fatal_error( "cannot stat %s\n", config_dir
);
372 return NULL
; /* will have to try again once config_dir has been created */
374 init_server_dir( st
.st_dev
, st
.st_ino
);
380 /* return the current user name */
381 const char *wine_get_user_name(void)
383 if (!user_name
) init_paths();
387 /* exec a binary using the preloader if requested; helper for wine_exec_wine_binary */
388 static void preloader_exec( char **argv
, int use_preloader
)
393 static const char preloader
[] = "wine-preloader";
395 char **last_arg
= argv
, **new_argv
;
397 if (!(p
= strrchr( argv
[0], '/' ))) p
= argv
[0];
400 full_name
= xmalloc( p
- argv
[0] + sizeof(preloader
) );
401 memcpy( full_name
, argv
[0], p
- argv
[0] );
402 memcpy( full_name
+ (p
- argv
[0]), preloader
, sizeof(preloader
) );
404 /* make a copy of argv */
405 while (*last_arg
) last_arg
++;
406 new_argv
= xmalloc( (last_arg
- argv
+ 2) * sizeof(*argv
) );
407 memcpy( new_argv
+ 1, argv
, (last_arg
- argv
+ 1) * sizeof(*argv
) );
408 new_argv
[0] = full_name
;
409 execv( full_name
, new_argv
);
415 execv( argv
[0], argv
);
418 /* exec a wine internal binary (either the wine loader or the wine server) */
419 void wine_exec_wine_binary( const char *name
, char **argv
, const char *env_var
)
421 const char *path
, *pos
, *ptr
;
422 int use_preloader
= 0;
424 if (!name
) /* no name means default loader */
430 /* first, bin directory from the current libdir or argv0 */
433 argv
[0] = build_path( bindir
, name
);
434 preloader_exec( argv
, use_preloader
);
438 /* then specified environment variable */
441 argv
[0] = (char *)env_var
;
442 preloader_exec( argv
, use_preloader
);
445 /* now search in the Unix path */
446 if ((path
= getenv( "PATH" )))
448 argv
[0] = xmalloc( strlen(path
) + strlen(name
) + 2 );
452 while (*pos
== ':') pos
++;
454 if (!(ptr
= strchr( pos
, ':' ))) ptr
= pos
+ strlen(pos
);
455 memcpy( argv
[0], pos
, ptr
- pos
);
456 strcpy( argv
[0] + (ptr
- pos
), "/" );
457 strcat( argv
[0] + (ptr
- pos
), name
);
458 preloader_exec( argv
, use_preloader
);
464 /* and finally try BINDIR */
465 argv
[0] = build_path( BINDIR
, name
);
466 preloader_exec( argv
, use_preloader
);