Пример #1
0
/* create the server directory and chdir to it */
static void create_server_dir( const char *dir )
{
    char *p, *server_dir;
    struct stat st, st2;

    if (!(server_dir = strdup( dir ))) fatal_error( "out of memory\n" );

    /* first create the base directory if needed */

    p = strrchr( server_dir, '/' );
    *p = 0;
    create_dir( server_dir, &st );

    /* now create the server directory */

    *p = '/';
    create_dir( server_dir, &st );

    if (chdir( server_dir ) == -1) fatal_perror( "chdir %s", server_dir );
    if ((server_dir_fd = open( ".", O_RDONLY )) == -1) fatal_perror( "open %s", server_dir );
    if (fstat( server_dir_fd, &st2 ) == -1) fatal_perror( "stat %s", server_dir );
    if (st.st_dev != st2.st_dev || st.st_ino != st2.st_ino)
        fatal_error( "chdir did not end up in %s\n", server_dir );

    free( server_dir );
}
Пример #2
0
static void signal_setup(void)
{
	static struct event ev_sighup;
	static struct event ev_sigterm;
	static struct event ev_sigint;

	sigset_t set;
	int err;

	/* block SIGPIPE */
	sigemptyset(&set);
	sigaddset(&set, SIGPIPE);
	err = sigprocmask(SIG_BLOCK, &set, NULL);
	if (err < 0)
		fatal_perror("sigprocmask");

	/* catch signals */
	signal_set(&ev_sighup, SIGHUP, handle_sighup, NULL);
	err = signal_add(&ev_sighup, NULL);
	if (err < 0)
		fatal_perror("signal_add");

	signal_set(&ev_sigterm, SIGTERM, handle_sigterm, NULL);
	err = signal_add(&ev_sigterm, NULL);
	if (err < 0)
		fatal_perror("signal_add");

	signal_set(&ev_sigint, SIGINT, handle_sigint, NULL);
	err = signal_add(&ev_sigint, NULL);
	if (err < 0)
		fatal_perror("signal_add");
}
Пример #3
0
main (int argc, char *argv[])
{
  static char codexxx[] = "/tmp/codeXXXXXX";
  static char asxxx[] = "/tmp/asXXXXXX";
  char *codefile, *hookfile, hooksfile[40], hookofile[40];
  char *outfile = "a.out";
  char *arg, ldargs[1024], cmd[1024];
  FILE *inf, *outf;

  /* Make temp file names. */

  codefile = mktemp (codexxx);
  hookfile = mktemp (asxxx);
  sprintf (hooksfile, "%s.s", hookfile);
  sprintf (hookofile, "%s.o", hookfile);

  /* Parse arguments.  Remove output file spec, pass the rest to ld. */

  ldargs[0] = '\0';
  while (arg = *++argv)
    {
      if (! strcmp (arg, "-o"))
	outfile = *++argv;
      else
	{
	  strcat (ldargs, " ");
	  strcat (ldargs, arg);
	}
    }

  /* Load the program, searching all libraries.
     Use -r to save the output as a relocatable file.
     Examine the namelist with nm and search it for static constructors
     and destructors to call.
     Write the constructor and destructor tables to a .s file. */

  sprintf (cmd, "ld -r -o %s %s && nm -p %s", codefile, ldargs, codefile);

  if (! (inf = popen (cmd, "r")))
    fatal_perror ("Can't open pipe to ld");
  if (! (outf = fopen (hooksfile, "w")))
    fatal_perror ("Can't write %s", hooksfile);

  write_hooks (inf, outf);

  if (pclose (inf) || fclose (outf))
    fatal ("load failed");

  /* Assemble the constructor and destructor tables.
     Link the tables in with the rest of the program. */

  sprintf (cmd, "as -o %s %s && ld -o %s %s %s && rm %s %s %s",
	   hookofile, hooksfile, 
	   outfile, codefile, hookofile,
	   codefile, hooksfile, hookofile);
  exit (system (cmd));
}
Пример #4
0
void init_intset(struct intset *set, int size)
{
     set->size = size;
     set->fill_pointer = 0;
     set->items = malloc(size * sizeof(int));
     if (!set->items)
	  fatal_perror("malloc");
     set->positions = calloc(size, sizeof(int));
     if (!set->positions)
	  fatal_perror("calloc");
}
Пример #5
0
/* create a directory and check its permissions */
static void create_dir( const char *name, struct stat *st )
{
    if (lstat( name, st ) == -1)
    {
        if (errno != ENOENT) fatal_perror( "lstat %s", name );
        if (mkdir( name, 0700 ) == -1 && errno != EEXIST) fatal_perror( "mkdir %s", name );
        if (lstat( name, st ) == -1) fatal_perror( "lstat %s", name );
    }
    if (!S_ISDIR(st->st_mode)) fatal_error( "%s is not a directory\n", name );
    if (st->st_uid != getuid()) fatal_error( "%s is not owned by you\n", name );
    if (st->st_mode & 077) fatal_error( "%s must not be accessible by other users\n", name );
}
Пример #6
0
/*
 * Open connection to xenstore.
 *
 * @pollfds defines of signal-handling descriptors to be watched
 * if has to wait.
 *
 * Will not touch pollfds[NPFD_XS].
 */
static void open_xs_connection(struct pollfd *pollfds)
{
	struct timespec ts0;
	int64_t wsec;
	bool displayed_msg = false;
	int k;

	/*
	 * If we are running as a daemon during system startup, there
	 * can be a race condition with continuing Xen initialization
	 * (/proc/xen including /proc/xen/privcmd may be unavailable yet,
	 * still to be created even though Xen service startup completion
	 * has already been signalled), so wait for a while if necessary.
	 */
	for (ts0 = getnow();;)
	{
		if (!xs)
			xs = xs_open(0);
		if (xs)
			break;

		/* time since the start */
		wsec = timespec_diff_ms(getnow(), ts0) / MSEC_PER_SEC;

		if (run_as_daemon && wsec < max_xen_init_retries)
		{
			if (wsec >= xen_init_retry_msg && !displayed_msg)
			{
				notice_msg("waiting for Xen to initialize");
				displayed_msg = true;
			}

			if (pollfds != NULL)
			{
				int npollfds = NPFD_COUNT - 1;
				for (k = 0;  k < npollfds;  k++)
					pollfds[k].revents = 0;
				if (poll(pollfds, npollfds, 1 * MSEC_PER_SEC) < 0)
					fatal_perror("poll");
				handle_signals(pollfds, NULL);
			}
			else
			{
				sleep(1);
			}
		}
		else
		{
			fatal_perror("unable to open connection to xenstore");
		}
	}
}
Пример #7
0
/***********************************************************************
 *           setup_config_dir
 *
 * Setup the wine configuration dir.
 */
static void setup_config_dir(void)
{
    const char *p, *config_dir = wine_get_config_dir();

    if (chdir( config_dir ) == -1)
    {
        if (errno != ENOENT) fatal_perror( "chdir to %s\n", config_dir );

        if ((p = strrchr( config_dir, '/' )) && p != config_dir)
        {
            struct stat st;
            char *tmp_dir;

            if (!(tmp_dir = malloc( p + 1 - config_dir ))) fatal_error( "out of memory\n" );
            memcpy( tmp_dir, config_dir, p - config_dir );
            tmp_dir[p - config_dir] = 0;
            if (!stat( tmp_dir, &st ) && st.st_uid != getuid())
                fatal_error( "'%s' is not owned by you, refusing to create a configuration directory there\n",
                             tmp_dir );
            free( tmp_dir );
        }

        mkdir( config_dir, 0777 );
        if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s\n", config_dir );

        if ((p = getenv( "WINEARCH" )) && !strcmp( p, "win32" ))
        {
            /* force creation of a 32-bit prefix */
            int fd = open( "system.reg", O_WRONLY | O_CREAT | O_EXCL, 0666 );
            if (fd != -1)
            {
                static const char regfile[] = "WINE REGISTRY Version 2\n\n#arch=win32\n";
                write( fd, regfile, sizeof(regfile) - 1 );
                close( fd );
            }
        }
        MESSAGE( "wine: created the configuration directory '%s'\n", config_dir );
    }

    if (mkdir( "dosdevices", 0777 ) == -1)
    {
        if (errno == EEXIST) return;
        fatal_perror( "cannot create %s/dosdevices\n", config_dir );
    }

    /* create the drive symlinks */

    mkdir( "drive_c", 0777 );
    symlink( "../drive_c", "dosdevices/c:" );
    symlink( "/", "dosdevices/z:" );
}
Пример #8
0
/*
 * Read in the whole content of file @path into the buffer pointed by *@ppbuf,
 * as nul-terminated string.
 * Reallocate *@ppbuf if necessary to be large enough.
 * The size of the buffer is kept in *@psize.
 * Initial size of the buffer to use on first allocation is given by @initial_size.
 * Abort on error.
 */
static void read_whole_file(const char *path, char **ppbuf, size_t *psize, size_t initial_size)
{
	ssize_t rsz;
	ssize_t rd;
	ssize_t rem;
	int fd = -1;

	if (*psize == 0)
	{
		*psize = initial_size;
		*ppbuf = malloc(*psize);
		if (!*ppbuf)
			out_of_memory();
	}

	for (;;)
	{
		if (fd == -1)
			close (fd);
		fd = open(path, O_RDONLY);
		if (fd == -1)
			fatal_perror("unable to open file %s", path);
		rd = 0;

		for (;;)
		{
			rem = *psize - rd;
			if (rem <= 0) break;
			rsz = read(fd, *ppbuf, rem);
			if (rsz < 0)
				fatal_perror("unable to read file %s", path);
			if (rsz == 0)  break;
			rd += rsz;
		}

		if (rd <= *psize - 1)
		{
			(*ppbuf)[rd] = '\0';
			break;
		}

		*psize += *psize / 2;
		*ppbuf = realloc(*ppbuf, *psize);
		if (!*ppbuf)
			out_of_memory();
	}

	close(fd);
}
Пример #9
0
/*
 * Process expected signals
 */
static void handle_signals(struct pollfd *pollfds, bool *p_recheck_time)
{
	struct signalfd_siginfo fdsi;
	ssize_t sz;

	/* SIGTERM - exit gracefully */
	if (pollfds[NPFD_SIGTERM].revents & (POLLIN|POLLPRI))
	{
		shutdown_xs();
		notice_msg("terminating...");
		exit(EXIT_SUCCESS);
	}

	/* SIGHUP - reload configuration */
	if (pollfds[NPFD_SIGHUP].revents & (POLLIN|POLLPRI))
	{
		sz = read(fd_sighup, &fdsi, sizeof(fdsi));
		if (sz < 0)
			fatal_perror("read signalfd");
		if (sz != sizeof(fdsi))
			fatal_msg("read signalfd");
		/* reload configuration -- currently none for memprobed */
		if (p_recheck_time)
			*p_recheck_time = true;
	}
}
Пример #10
0
/***********************************************************************
 *           start_server
 *
 * Start a new wine server.
 */
static void start_server(void)
{
    static int started;  /* we only try once */
    char *argv[3];
    static char wineserver[] = "server/wineserver";
    static char debug[] = "-d";

    if (!started)
    {
        int status;
        int pid = fork();
        if (pid == -1) fatal_perror( "fork" );
        if (!pid)
        {
            argv[0] = wineserver;
            argv[1] = TRACE_ON(server) ? debug : NULL;
            argv[2] = NULL;
            wine_exec_wine_binary( argv[0], argv, getenv("WINESERVER") );
            fatal_error( "could not exec wineserver\n" );
        }
        waitpid( pid, &status, 0 );
        status = WIFEXITED(status) ? WEXITSTATUS(status) : 1;
        if (status == 2) return;  /* server lock held by someone else, will retry later */
        if (status) exit(status);  /* server failed */
        started = 1;
    }
}
Пример #11
0
int main(int argc, char *argv[])
{
	int i;
	unsigned char *ptrs[TOTAL_PAGES];

	parse_args(argc, argv);

	for (i = 0; i < TOTAL_PAGES; i++) {
		ptrs[i] = malloc(PAGE_SIZE);
		if (ptrs[i] == NULL)
			fatal_perror("simple_multi_malloc: malloc");

		/* Touch page. */
		ptrs[i][0] = 'x';
	}

	summarise(NULL);
	block();

	/* Not strictly necessary, but good habit to free regardless. */
	for (i = 0; i < TOTAL_PAGES; i++)
		free(ptrs[i]);

	return EXIT_SUCCESS;
}
Пример #12
0
static char *
xreadall(int fd)
{
  size_t nread = 0;
  size_t alloc = BUFSIZ;
  char *buf = xreallocarray(0, alloc, 1);

  for (;;) {
    ssize_t count = read(fd, buf + nread, alloc - nread);
    if (count == 0)
      break;
    if (count < 0)
      fatal_perror("read");

    nread += (size_t)count;
    while (nread >= alloc) {
      alloc *= 2;
      buf = xreallocarray(buf, alloc, 1);
    }
  }

  buf = xreallocarray(buf, nread+1, 1);
  buf[nread] = '\0';
  return buf;
}
Пример #13
0
/***********************************************************************
 *           server_init_process
 *
 * Start the server and create the initial socket pair.
 */
void server_init_process(void)
{
    obj_handle_t dummy_handle;
    const char *env_socket = getenv( "WINESERVERSOCKET" );

    if (env_socket)
    {
        fd_socket = atoi( env_socket );
        if (fcntl( fd_socket, F_SETFD, 1 ) == -1)
            fatal_perror( "Bad server socket %d", fd_socket );
        unsetenv( "WINESERVERSOCKET" );
    }
    else fd_socket = server_connect();

    /* setup the signal mask */
    sigemptyset( &server_block_set );
    sigaddset( &server_block_set, SIGALRM );
    sigaddset( &server_block_set, SIGIO );
    sigaddset( &server_block_set, SIGINT );
    sigaddset( &server_block_set, SIGHUP );
    sigaddset( &server_block_set, SIGUSR1 );
    sigaddset( &server_block_set, SIGUSR2 );
    sigaddset( &server_block_set, SIGCHLD );
    pthread_functions.sigprocmask( SIG_BLOCK, &server_block_set, NULL );

    /* receive the first thread request fd on the main socket */
    ntdll_get_thread_data()->request_fd = receive_fd( &dummy_handle );

#ifdef __APPLE__
    send_server_task_port();
#endif
}
Пример #14
0
static void
runv_ignore_failure(const char *const *argv)
{
  pid_t pid = xspawnvp(argv);
  int status;
  if (waitpid(pid, &status, 0) != pid)
    fatal_perror("waitpid");
}
Пример #15
0
static void *
xreallocarray(void *optr, size_t nmemb, size_t size)
{
  /* s1*s2 <= SIZE_MAX if both s1 < K and s2 < K where K = sqrt(SIZE_MAX+1) */
  const size_t MUL_NO_OVERFLOW = ((size_t)1) << (sizeof(size_t) * 4);

  if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
      nmemb > 0 && SIZE_MAX / nmemb < size) {
    errno = ENOMEM;
    fatal_perror("malloc");
  }

  void *rv = realloc(optr, size * nmemb);
  if (!rv)
    fatal_perror("malloc");
  return rv;
}
Пример #16
0
static pid_t
spawn_with_redir(const char *const *argv, int child_stdin, int child_stdout)
{
  fflush(0);
  pid_t child = fork();
  if (child == -1)
    fatal_perror("fork");
  if (child != 0)
    return child; /* to the parent */

  /* We are the child.  The parent has arranged for it to be safe for
     us to write to stderr under error conditions, but the cleanup
     handler should not do anything. */
  controller_cleanups = false;
  up_script_cleanups = false;

  /* Child-side stdin and stdout redirections. */
  if (child_stdin != 0) {
    if (close(0))
      fatal_perror("close");

    if (child_stdin < 0) {
      if (open("/dev/null", O_RDONLY) != 0)
        fatal_perror("open");
    } else {
      if (dup(child_stdin) != 0)
        fatal_perror("dup");
    }
  }

  if (child_stdout != 1) {
    if (close(1))
      fatal_perror("close");
    if (child_stdout < 1) {
      if (open("/dev/null", O_WRONLY) != 1)
        fatal_perror("open");
    } else {
      if (dup(child_stdout) != 1)
        fatal_perror("dup");
    }
  }

  become_only_root();

  if (sigprocmask(SIG_SETMASK, &child_sigmask, 0))
    fatal_perror("sigprocmask");

  execvpe(argv[0], (char *const *)argv, (char *const *)child_env);
  fatal_perror("execvpe");
}
Пример #17
0
static void
runv(const char *const *argv)
{
  pid_t pid = xspawnvp(argv);
  int status;
  if (waitpid(pid, &status, 0) != pid)
    fatal_perror("waitpid");
  fatal_if_unsuccessful_child(argv[0], status);
}
Пример #18
0
static char * PRINTFLIKE
xasprintf(const char *fmt, ...)
{
  char *rv;
  va_list ap;
  va_start(ap, fmt);
  if (vasprintf(&rv, fmt, ap) == -1)
    fatal_perror("asprintf");
  return rv;
}
Пример #19
0
/*
 * Socket file with the same name already exists.
 * If another instance of membalanced is already running, abort.
 * Otherwise delete leftover file, and let the caller retry again.
 */
static void on_addrinuse(const struct sockaddr_un& addr)
{
	int fd;
	int rc;

	DO_RESTARTABLE(fd, socket(AF_UNIX, SOCK_STREAM, 0));
	if (fd == -1)
		fatal_perror("unable to create RPC socket");

	DO_RESTARTABLE(rc, connect(fd, (struct sockaddr*)&addr, sizeof addr));
	if (rc == 0)
		fatal_msg("membalanced is already running and owns RPC socket");
	if (errno != ECONNREFUSED)
		fatal_perror("socket file %s in a bad state", socket_path);

	/* socket exists, but no one is lisening on it */
	if (unlink(socket_path) && errno != ENOENT)
		fatal_perror("unable to delete socket file %s", socket_path);
}
Пример #20
0
struct intset *make_intset(int size)
{
     struct intset *set;

     set = malloc(sizeof(struct intset));
     if (!set)
	  fatal_perror("malloc");
     init_intset(set, size);
     return set;
}
Пример #21
0
static int start_ptraced_child(void)
{
	int pid, n, status;

	pid = fork();
	if (pid == 0)
		ptrace_child();
	else if (pid < 0)
		fatal_perror("start_ptraced_child : fork failed");

	CATCH_EINTR(n = waitpid(pid, &status, WUNTRACED));
	if (n < 0)
		fatal_perror("check_ptrace : waitpid failed");
	if (!WIFSTOPPED(status) || (WSTOPSIG(status) != SIGSTOP))
		fatal("check_ptrace : expected SIGSTOP, got status = %d",
		      status);

	return pid;
}
Пример #22
0
/***********************************************************************
 *           server_init_process
 *
 * Start the server and create the initial socket pair.
 */
void server_init_process(void)
{
    obj_handle_t version;
    const char *env_socket = getenv( "WINESERVERSOCKET" );

    server_pid = -1;
    if (env_socket)
    {
        fd_socket = atoi( env_socket );
        if (fcntl( fd_socket, F_SETFD, 1 ) == -1)
            fatal_perror( "Bad server socket %d", fd_socket );
        unsetenv( "WINESERVERSOCKET" );
    }
    else fd_socket = server_connect();

    /* setup the signal mask */
    sigemptyset( &server_block_set );
    sigaddset( &server_block_set, SIGALRM );
    sigaddset( &server_block_set, SIGIO );
    sigaddset( &server_block_set, SIGINT );
    sigaddset( &server_block_set, SIGHUP );
    sigaddset( &server_block_set, SIGUSR1 );
    sigaddset( &server_block_set, SIGUSR2 );
    sigaddset( &server_block_set, SIGCHLD );
    pthread_sigmask( SIG_BLOCK, &server_block_set, NULL );

    /* receive the first thread request fd on the main socket */
#ifdef SO_PASSCRED
    if (server_pid == -1)
    {
        int enable = 1;
        setsockopt( fd_socket, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
        ntdll_get_thread_data()->request_fd = receive_fd( &version );
        enable = 0;
        setsockopt( fd_socket, SOL_SOCKET, SO_PASSCRED, &enable, sizeof(enable) );
    }
    else
#endif
    ntdll_get_thread_data()->request_fd = receive_fd( &version );

    if (version != SERVER_PROTOCOL_VERSION)
        server_protocol_error( "version mismatch %d/%d.\n"
                               "Your %s binary was not upgraded correctly,\n"
                               "or you have an older one somewhere in your PATH.\n"
                               "Or maybe the wrong wineserver is still running?\n",
                               version, SERVER_PROTOCOL_VERSION,
                               (version > SERVER_PROTOCOL_VERSION) ? "wine" : "wineserver" );
#ifdef __APPLE__
    send_server_task_port();
#endif
#if defined(__linux__) && defined(HAVE_PRCTL)
    /* work around Ubuntu's ptrace breakage */
    if (server_pid != -1) prctl( 0x59616d61 /* PR_SET_PTRACER */, server_pid );
#endif
}
Пример #23
0
/*
 * Get current timestamp.
 * Preserves previous value of errno.
 */
static struct timespec getnow(void)
{
	int sv_errno = errno;
	struct timespec ts;

	if (clock_gettime(clk_id, &ts))
		fatal_perror("clock_gettime");

	errno = sv_errno;
	return ts;
}
Пример #24
0
/* create the lock file and return its file descriptor */
static int create_server_lock(void)
{
    struct stat st;
    int fd;

    if (lstat( server_lock_name, &st ) == -1)
    {
        if (errno != ENOENT)
            fatal_perror( "lstat %s/%s", wine_get_server_dir(), server_lock_name );
    }
    else
    {
        if (!S_ISREG(st.st_mode))
            fatal_error( "%s/%s is not a regular file\n", wine_get_server_dir(), server_lock_name );
    }

    if ((fd = open( server_lock_name, O_CREAT|O_TRUNC|O_WRONLY, 0600 )) == -1)
        fatal_perror( "error creating %s/%s", wine_get_server_dir(), server_lock_name );
    return fd;
}
Пример #25
0
void socket_set_nonblocking(int fd, int val)
{
	int flags, res;

	/* get old flags */
	flags = fcntl(fd, F_GETFL, 0);
	if (flags < 0)
		fatal_perror("fcntl(F_GETFL)");

	/* flip O_NONBLOCK */
	if (val)
		flags |= O_NONBLOCK;
	else
		flags &= ~O_NONBLOCK;

	/* set new flags */
	res = fcntl(fd, F_SETFL, flags);
	if (res < 0)
		fatal_perror("fcntl(F_SETFL)");
}
Пример #26
0
static char *
runv_get_output(const char *const *argv)
{
  int pipefds[2];
  if (pipe2(pipefds, O_CLOEXEC))
    fatal_perror("pipe");

  pid_t pid = spawn_with_redir(argv, -1, pipefds[1]);
  close(pipefds[1]);

  char *output = xreadall(pipefds[0]);
  close(pipefds[0]);

  int status;
  if (waitpid(pid, &status, 0) != pid)
    fatal_perror("waitpid");
  fatal_if_unsuccessful_child(argv[0], status);

  return output;
}
Пример #27
0
int output( const char *format, ... )
{
    int ret;
    va_list valist;

    va_start( valist, format );
    ret = vfprintf( output_file, format, valist );
    va_end( valist );
    if (ret < 0) fatal_perror( "Output error" );
    return ret;
}
Пример #28
0
static NORETURN
fatal_regerror(const char *msg, int errcode, const regex_t *offender)
{
  size_t req = regerror(errcode, offender, 0, 0);
  char *errbuf = malloc(req);
  if (!errbuf)
    fatal_perror("malloc");
  regerror(errcode, offender, errbuf, req);
  fprintf(stderr, "%s: %s: %s\n", progname, msg, errbuf);
  exit(1);
}
Пример #29
0
static int
configuration_file_exists(const char *fname)
{
    struct stat tmpbuf;
    int status = stat(fname, &tmpbuf);
    int result = status ? 0 : 1; /* must invert result: 0 => true, !0 => false */

    if (status < 0)
        fatal_perror(fname);

    return result;
}
Пример #30
0
/***********************************************************************
 *           setup_config_dir
 *
 * Setup the wine configuration dir.
 */
static void setup_config_dir(void)
{
    const char *p, *config_dir = wine_get_config_dir();

    if (chdir( config_dir ) == -1)
    {
        if (errno != ENOENT) fatal_perror( "chdir to %s\n", config_dir );

        if ((p = strrchr( config_dir, '/' )) && p != config_dir)
        {
            struct stat st;
            char *tmp_dir;

            if (!(tmp_dir = malloc( p + 1 - config_dir ))) fatal_error( "out of memory\n" );
            memcpy( tmp_dir, config_dir, p - config_dir );
            tmp_dir[p - config_dir] = 0;
            if (!stat( tmp_dir, &st ) && st.st_uid != getuid())
                fatal_error( "'%s' is not owned by you, refusing to create a configuration directory there\n",
                             tmp_dir );
            free( tmp_dir );
        }

        mkdir( config_dir, 0777 );
        if (chdir( config_dir ) == -1) fatal_perror( "chdir to %s\n", config_dir );
        MESSAGE( "wine: created the configuration directory '%s'\n", config_dir );
    }

    if (mkdir( "dosdevices", 0777 ) == -1)
    {
        if (errno == EEXIST) return;
        fatal_perror( "cannot create %s/dosdevices\n", config_dir );
    }

    /* create the drive symlinks */

    mkdir( "drive_c", 0777 );
    symlink( "../drive_c", "dosdevices/c:" );
    symlink( "/", "dosdevices/z:" );
}