diff --git a/dlls/ntdll/server.c b/dlls/ntdll/server.c index 6654df1eec2..cb384583bc0 100644 --- a/dlls/ntdll/server.c +++ b/dlls/ntdll/server.c @@ -23,9 +23,11 @@ #include #include +#include #include #include #include +#include #include #include #include @@ -48,7 +50,6 @@ #ifdef HAVE_UNISTD_H # include #endif -#include #include "ntstatus.h" #include "thread.h" @@ -622,6 +623,116 @@ static int server_connect( const char *oldcwd, const char *serverdir ) } +/*********************************************************************** + * rm_rf + * + * Remove a directory and all its contents; helper for create_config_dir. + */ +static void rm_rf( const char *path ) +{ + int err = errno; /* preserve errno */ + DIR *dir; + char *buffer, *p; + struct stat st; + struct dirent *de; + + if (!(buffer = malloc( strlen(path) + 256 + 1 ))) goto done; + strcpy( buffer, path ); + p = buffer + strlen(buffer); + *p++ = '/'; + + if ((dir = opendir( path ))) + { + while ((de = readdir( dir ))) + { + if (!strcmp( de->d_name, "." ) || !strcmp( de->d_name, ".." )) continue; + strcpy( p, de->d_name ); + if (unlink( buffer ) != -1) continue; + if (errno == EISDIR || + (errno == EPERM && !lstat( buffer, &st ) && S_ISDIR(st.st_mode))) + { + /* recurse in the sub-directory */ + rm_rf( buffer ); + } + } + closedir( dir ); + } + free( buffer ); + rmdir( path ); +done: + errno = err; +} + + +/*********************************************************************** + * create_config_dir + * + * Create the wine configuration dir (~/.wine). + */ +static void create_config_dir(void) +{ + const char *config_dir = wine_get_config_dir(); + char *tmp_dir; + int fd; + pid_t pid, wret; + + if (!(tmp_dir = malloc( strlen(config_dir) + sizeof("-XXXXXX") ))) + fatal_error( "out of memory\n" ); + strcpy( tmp_dir, config_dir ); + strcat( tmp_dir, "-XXXXXX" ); + if ((fd = mkstemps( tmp_dir, 0 )) == -1) + fatal_perror( "can't get temp file name for %s", config_dir ); + close( fd ); + unlink( tmp_dir ); + if (mkdir( tmp_dir, 0777 ) == -1) + fatal_perror( "cannot create temp dir %s", tmp_dir ); + + MESSAGE( "wine: creating configuration directory '%s'...\n", config_dir ); + pid = fork(); + if (pid == -1) + { + rmdir( tmp_dir ); + fatal_perror( "fork" ); + } + if (!pid) + { + const char *argv[5]; + + argv[0] = "wineprefixcreate"; + argv[1] = "--quiet"; + argv[2] = "--prefix"; + argv[3] = tmp_dir; + argv[4] = NULL; + wine_exec_wine_binary( argv[0], (char **)argv, NULL ); + rmdir( tmp_dir ); + fatal_perror( "could not exec wineprefixcreate" ); + } + else + { + int status; + + while ((wret = waitpid( pid, &status, 0 )) != pid) + { + if (wret == -1 && errno != EINTR) fatal_perror( "wait4" ); + } + if (!WIFEXITED(status) || WEXITSTATUS(status)) + { + rm_rf( tmp_dir ); + fatal_error( "wineprefixcreate failed while creating '%s'.\n", config_dir ); + } + } + if (rename( tmp_dir, config_dir ) == -1) + { + rm_rf( tmp_dir ); + if (errno != EEXIST && errno != ENOTEMPTY) + fatal_perror( "rename '%s' to '%s'", tmp_dir, config_dir ); + /* else it was probably created by a concurrent wine process */ + } + free( tmp_dir ); + MESSAGE( "wine: '%s' created successfully.\n", config_dir ); +} + + /*********************************************************************** * server_init_process * @@ -632,6 +743,13 @@ void server_init_process(void) int size; char *oldcwd; obj_handle_t dummy_handle; + const char *server_dir = wine_get_server_dir(); + + if (!server_dir) /* this means the config dir doesn't exist */ + { + create_config_dir(); + server_dir = wine_get_server_dir(); + } /* retrieve the current directory */ for (size = 512; ; size *= 2) @@ -645,7 +763,7 @@ void server_init_process(void) } /* connect to the server */ - fd_socket = server_connect( oldcwd, wine_get_server_dir() ); + fd_socket = server_connect( oldcwd, server_dir ); /* switch back to the starting directory */ if (oldcwd) diff --git a/libs/wine/config.c b/libs/wine/config.c index 6ea0f8becee..cb4b00092f2 100644 --- a/libs/wine/config.c +++ b/libs/wine/config.c @@ -33,10 +33,11 @@ #ifdef HAVE_PWD_H #include #endif +#include "wine/library.h" -static const char * const server_config_dir = "/.wine"; /* config dir relative to $HOME */ -static const char * const server_root_prefix = "/tmp/.wine-"; /* prefix for server root dir */ -static const char * const server_dir_prefix = "/server-"; /* prefix for server dir */ +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; @@ -100,11 +101,40 @@ inline static void remove_trailing_slashes( char *path ) while (len > 1 && path[len-1] == '/') path[--len] = 0; } +/* initialize the server directory value */ +static void init_server_dir( dev_t dev, ino_t ino ) +{ + const char *user = wine_get_user_name(); + char *p; + + server_dir = xmalloc( sizeof(server_root_prefix) + strlen(user) + sizeof(server_dir_prefix) + + 2*sizeof(dev) + 2*sizeof(ino) ); + strcpy( server_dir, server_root_prefix ); + p = server_dir + sizeof(server_root_prefix) - 1; + strcpy( p, user ); + while (*p) + { + if (*p == '/') *p = '!'; + p++; + } + strcpy( p, server_dir_prefix ); + p += sizeof(server_dir_prefix) - 1; + + if (sizeof(dev) > sizeof(unsigned long) && dev > ~0UL) + sprintf( p, "%lx%08lx-", (unsigned long)(dev >> 32), (unsigned long)dev ); + else + sprintf( p, "%lx-", (unsigned long)dev ); + + if (sizeof(ino) > sizeof(unsigned long) && ino > ~0UL) + sprintf( p, "%lx%08lx", (unsigned long)(ino >> 32), (unsigned long)ino ); + else + sprintf( p, "%lx", (unsigned long)ino ); +} + /* initialize all the paths values */ static void init_paths(void) { struct stat st; - char *p; const char *home = getenv( "HOME" ); const char *user = NULL; @@ -139,46 +169,30 @@ static void init_paths(void) if (config_dir[0] != '/') fatal_error( "invalid directory %s in WINEPREFIX: not an absolute path\n", prefix ); if (stat( config_dir, &st ) == -1) - fatal_perror( "cannot open %s as specified in WINEPREFIX", config_dir ); + { + if (errno != ENOENT) + fatal_perror( "cannot open %s as specified in WINEPREFIX", config_dir ); + fatal_error( "the '%s' directory specified in WINEPREFIX doesn't exist.\n" + "You may want to create it by running 'wineprefixcreate'.\n", 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) + strlen(server_config_dir) + 1 ); + 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 ); - /* build server_dir */ - - server_dir = xmalloc( strlen(server_root_prefix) + strlen(user) + strlen( server_dir_prefix ) + - 2*sizeof(st.st_dev) + 2*sizeof(st.st_ino) + 2 ); - strcpy( server_dir, server_root_prefix ); - p = server_dir + strlen(server_dir); - strcpy( p, user ); - while (*p) - { - if (*p == '/') *p = '!'; - p++; - } - strcpy( p, server_dir_prefix ); - - if (sizeof(st.st_dev) > sizeof(unsigned long) && st.st_dev > ~0UL) - sprintf( server_dir + strlen(server_dir), "%lx%08lx-", - (unsigned long)(st.st_dev >> 32), (unsigned long)st.st_dev ); - else - sprintf( server_dir + strlen(server_dir), "%lx-", (unsigned long)st.st_dev ); - - if (sizeof(st.st_ino) > sizeof(unsigned long) && st.st_ino > ~0UL) - sprintf( server_dir + strlen(server_dir), "%lx%08lx", - (unsigned long)(st.st_ino >> 32), (unsigned long)st.st_ino ); - else - sprintf( server_dir + strlen(server_dir), "%lx", (unsigned long)st.st_ino ); + init_server_dir( st.st_dev, st.st_ino ); } /* initialize the argv0 path */ @@ -232,7 +246,21 @@ const char *wine_get_config_dir(void) /* return the full name of the server directory (the one containing the socket) */ const char *wine_get_server_dir(void) { - if (!server_dir) init_paths(); + 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; } diff --git a/tools/wineprefixcreate.in b/tools/wineprefixcreate.in index 3a3075ed6a0..bb887118f65 100644 --- a/tools/wineprefixcreate.in +++ b/tools/wineprefixcreate.in @@ -26,10 +26,11 @@ usage() echo "Usage: $0 [options]" echo "" echo "Options:" - echo " --help Display this message" - echo " --prefix Prefix directory to create (defaults to \$WINEPREFIX or ~/.wine)" - echo " --update Update the prefix directory if it already exists" - echo " --use-wine-tree Run from the Wine source tree " + echo " -h, --help Display this message" + echo " --prefix Directory to create (default: \$WINEPREFIX or ~/.wine)" + echo " -q, --quiet Don't print status messages" + echo " -u, --update Update the prefix directory if it already exists" + echo " --use-wine-tree Run from the Wine source tree " echo "" } @@ -39,11 +40,12 @@ dlldir="@dlldir@" datadir="@datadir@/wine" do_update=0 +quiet=0 while [ $# -gt 0 ] do case "$1" in - --help) + -h|--help) usage exit 0 ;; @@ -51,10 +53,14 @@ do WINEPREFIX="$2" shift 2 ;; - --update) + -u|--update) do_update=1 shift ;; + -q|--quiet) + quiet=1 + shift + ;; --use-wine-tree) topdir=`cd "$2" && pwd` if [ -x "$topdir/server/wineserver" ] @@ -69,6 +75,7 @@ do shift 2 ;; *) + echo "Unknown option $1" usage exit 1 ;; @@ -77,19 +84,10 @@ done WINEPREFIX="${WINEPREFIX:-$HOME/.wine}" -if [ -d "$WINEPREFIX" ] -then - if [ $do_update = 0 ] - then - echo "The $WINEPREFIX directory already exists, aborting" - exit 1 - fi +if [ -d "$WINEPREFIX" ] || mkdir "$WINEPREFIX"; then : else - if mkdir "$WINEPREFIX"; then : - else - echo "Could not create $WINEPREFIX, aborting" - exit 1 - fi + echo "Could not create $WINEPREFIX, aborting" + exit 1 fi WINEPREFIX=`cd "$WINEPREFIX" && pwd` @@ -160,7 +158,13 @@ ${WINELOADER:-wine} rundll32.exe setupapi.dll,InstallHinfSection DefaultInstall if [ $do_update = 0 ] then ${WINESERVER:-wineserver} -w - echo "$WINEPREFIX created successfully." + if [ $quiet = 0 ] + then + echo "$WINEPREFIX created successfully." + fi else - echo "$WINEPREFIX updated successfully." + if [ $quiet = 0 ] + then + echo "$WINEPREFIX updated successfully." + fi fi