]> rtime.felk.cvut.cz Git - sojka/lightdm.git/commitdiff
Be extra careful not to call any non thread safe function after a fork
authorRobert Ancell <robert.ancell@canonical.com>
Tue, 25 Feb 2014 22:12:22 +0000 (11:12 +1300)
committerRobert Ancell <robert.ancell@canonical.com>
Tue, 25 Feb 2014 22:12:22 +0000 (11:12 +1300)
src/process.c
src/process.h
src/seat.c
src/session-child.c
src/session.c
src/unity-system-compositor.c
src/x-server-local.c
src/x-server-xvnc.c

index 542492bc7c7044eb5325d9067073b799befde26a..3010eb0eb6ed80afc54b80dbd4c0de8c61e5101f 100644 (file)
@@ -23,7 +23,6 @@
 #include "process.h"
 
 enum {
-    RUN,
     GOT_DATA,
     GOT_SIGNAL,  
     STOPPED,
@@ -32,10 +31,18 @@ enum {
 static guint signals[LAST_SIGNAL] = { 0 };
 
 struct ProcessPrivate
-{  
+{
+    /* Function to run inside subprocess before exec */
+    ProcessRunFunc run_func;
+    gpointer run_func_data;
+
+    /* File to log to */
+    gchar *log_file;
+    gboolean log_stdout;
+
     /* Command to run */
     gchar *command;
-  
+
     /* TRUE to clear the environment in this process */
     gboolean clear_environment;
 
@@ -67,16 +74,28 @@ process_get_current (void)
     if (current_process)
         return current_process;
 
-    current_process = process_new ();
+    current_process = process_new (NULL, NULL);
     current_process->priv->pid = getpid ();
 
     return current_process;
 }
 
 Process *
-process_new (void)
+process_new (ProcessRunFunc run_func, gpointer run_func_data)
 {
-    return g_object_new (PROCESS_TYPE, NULL);
+    Process *process = g_object_new (PROCESS_TYPE, NULL);
+    process->priv->run_func = run_func;
+    process->priv->run_func_data = run_func_data;
+    return process;
+}
+
+void
+process_set_log_file (Process *process, const gchar *path, gboolean log_stdout)
+{
+    g_return_if_fail (process != NULL);
+    g_free (process->priv->log_file);
+    process->priv->log_file = g_strdup (path);
+    process->priv->log_stdout = log_stdout;
 }
 
 void
@@ -150,57 +169,88 @@ process_watch_cb (GPid pid, gint status, gpointer data)
     g_signal_emit (process, signals[STOPPED], 0);
 }
 
-static void
-process_run (Process *process)
+gboolean
+process_start (Process *process, gboolean block)
 {
     gint argc;
     gchar **argv;
-    GHashTableIter iter;
-    gpointer key, value;
+    gchar **env_keys, **env_values;
+    guint i, env_length;
+    pid_t pid;
+    int log_fd = -1;
     GError *error = NULL;
 
+    g_return_val_if_fail (process != NULL, FALSE);
+    g_return_val_if_fail (process->priv->command != NULL, FALSE);  
+    g_return_val_if_fail (process->priv->pid == 0, FALSE);
+
     if (!g_shell_parse_argv (process->priv->command, &argc, &argv, &error))
     {
         g_warning ("Error parsing command %s: %s", process->priv->command, error->message);
-        _exit (EXIT_FAILURE);
+        return FALSE;
+    }
+
+    if (process->priv->log_file)
+    {
+        gchar *old_filename;
+
+        /* Move old file out of the way */
+        old_filename = g_strdup_printf ("%s.old", process->priv->log_file);
+        rename (process->priv->log_file, old_filename);
+        g_free (old_filename);
+
+        /* Create new file and log to it */
+        log_fd = g_open (process->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
+        if (log_fd < 0)
+            g_warning ("Failed to open log file %s: %s", process->priv->log_file, g_strerror (errno));
     }
 
-    if (process->priv->clear_environment)
+    /* Work out variables to set */
+    env_keys = (gchar **) g_hash_table_get_keys_as_array (process->priv->env, &env_length);
+    env_values = g_malloc (sizeof (gchar *) * env_length);
+    for (i = 0; i < env_length; i++)
+        env_values[i] = g_hash_table_lookup (process->priv->env, env_keys[i]);
+
+    pid = fork ();
+    if (pid == 0)
+    {
+        /* Do custom setup */
+        if (process->priv->run_func)
+            process->priv->run_func (process, process->priv->run_func_data);
+
+        /* Redirect output to logfile */
+        if (log_fd >= 0)
+        {
+             if (process->priv->log_stdout)
+                 dup2 (log_fd, STDOUT_FILENO);
+             dup2 (log_fd, STDERR_FILENO);
+             close (log_fd);
+        }
+
+        /* Set environment */
+        if (process->priv->clear_environment)
 #ifdef HAVE_CLEARENV
-        clearenv ();
+            clearenv ();
 #else
-        environ = NULL;
+            environ = NULL;
 #endif
-
-    g_hash_table_iter_init (&iter, process->priv->env);
-    while (g_hash_table_iter_next (&iter, &key, &value))
-        g_setenv ((gchar *)key, (gchar *)value, TRUE);
+        for (i = 0; i < env_length; i++)
+            setenv (env_keys[i], env_values[i], TRUE);
   
-    execvp (argv[0], argv);
-
-    g_warning ("Error executing child process %s: %s", argv[0], g_strerror (errno));
-    _exit (EXIT_FAILURE);
-}
-
-gboolean
-process_start (Process *process, gboolean block)
-{
-    pid_t pid;
+        execvp (argv[0], argv);
+        _exit (EXIT_FAILURE);
+    }
 
-    g_return_val_if_fail (process != NULL, FALSE);
-    g_return_val_if_fail (process->priv->command != NULL, FALSE);  
-    g_return_val_if_fail (process->priv->pid == 0, FALSE);
+    close (log_fd);
+    g_free (env_keys);
+    g_free (env_values);
 
-    pid = fork ();
     if (pid < 0)
     {
         g_warning ("Failed to fork: %s", strerror (errno));
         return FALSE;
     }
 
-    if (pid == 0)
-        g_signal_emit (process, signals[RUN], 0);
-
     g_debug ("Launching process %d: %s", pid, process->priv->command);
 
     process->priv->pid = pid;
@@ -295,6 +345,7 @@ process_finalize (GObject *object)
     if (self->priv->pid > 0)
         g_hash_table_remove (processes, GINT_TO_POINTER (self->priv->pid));
 
+    g_free (self->priv->log_file);
     g_free (self->priv->command);
     g_hash_table_unref (self->priv->env);
     if (self->priv->quit_timeout)
@@ -349,20 +400,11 @@ process_class_init (ProcessClass *klass)
     GObjectClass *object_class = G_OBJECT_CLASS (klass);
     struct sigaction action;
 
-    klass->run = process_run;
     klass->stopped = process_stopped;
     object_class->finalize = process_finalize;  
 
     g_type_class_add_private (klass, sizeof (ProcessPrivate));
 
-    signals[RUN] =
-        g_signal_new ("run",
-                      G_TYPE_FROM_CLASS (klass),
-                      G_SIGNAL_RUN_LAST,
-                      G_STRUCT_OFFSET (ProcessClass, run),
-                      NULL, NULL,
-                      NULL,
-                      G_TYPE_NONE, 0); 
     signals[GOT_DATA] =
         g_signal_new ("got-data",
                       G_TYPE_FROM_CLASS (klass),
index 54c3776b1bd3258fb4d83385c2f03cf7935a1851..1fcde7a807705e14ed052a75d2382d26cf934452 100644 (file)
@@ -32,17 +32,20 @@ typedef struct
 typedef struct
 {
     GObjectClass parent_class;
-    void (*run)(Process *process);
     void (*got_data)(Process *process);
     void (*got_signal)(Process *process, int signum);
     void (*stopped)(Process *process);
 } ProcessClass;
 
+typedef void (*ProcessRunFunc)(Process *process, gpointer user_data);
+
 GType process_get_type (void);
 
 Process *process_get_current (void);
 
-Process *process_new (void);
+Process *process_new (ProcessRunFunc run_func, gpointer run_func_data);
+
+void process_set_log_file (Process *process, const gchar *path, gboolean log_stdout);
 
 void process_set_clear_environment (Process *process, gboolean clear_environment);
 
index 7347d1ce87b00b268374cb5e0cd04e6879a0717b..a78f32b7c34df9d9e3ccea2cd01386208be687d8 100644 (file)
@@ -269,7 +269,7 @@ run_script (Seat *seat, DisplayServer *display_server, const gchar *script_name,
     Process *script;
     gboolean result = FALSE;
   
-    script = process_new ();
+    script = process_new (NULL, NULL);
 
     process_set_command (script, script_name);
 
index 6d6d05e907516f4233e68cb509be22b4233cd8b0..c1c84e5d2f7edd976d6c1115d469b2fa9ba3e289 100644 (file)
@@ -234,6 +234,9 @@ session_child_run (int argc, char **argv)
         "LANG",
         NULL
     };
+    gid_t gid;
+    uid_t uid;
+    const gchar *home_directory;
     GError *error = NULL;
 
 #if !defined(GLIB_VERSION_2_36)
@@ -417,17 +420,21 @@ session_child_run (int argc, char **argv)
 
     /* Redirect stderr to a log file */
     if (log_filename)
-        log_backup_filename = g_strdup_printf ("%s.old", log_filename);
-    if (!log_filename)
     {
-        fd = open ("/dev/null", O_WRONLY);   
-        dup2 (fd, STDERR_FILENO);
-        close (fd);
+        log_backup_filename = g_strdup_printf ("%s.old", log_filename);
+        if (g_path_is_absolute (log_filename))
+        {
+            rename (log_filename, log_backup_filename);
+            fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
+            dup2 (fd, STDERR_FILENO);
+            close (fd);
+            g_free (log_filename);
+            log_filename = NULL;
+        }
     }
-    else if (g_path_is_absolute (log_filename))
+    else
     {
-        rename (log_filename, log_backup_filename);
-        fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
+        fd = open ("/dev/null", O_WRONLY);   
         dup2 (fd, STDERR_FILENO);
         close (fd);
     }
@@ -532,53 +539,46 @@ session_child_run (int argc, char **argv)
     signal (SIGTERM, signal_cb);
 
     /* Run the command as the authenticated user */
-    child_pid = fork (); 
+    uid = user_get_uid (user);
+    gid = user_get_gid (user);
+    home_directory = user_get_home_directory (user);
+    child_pid = fork ();
     if (child_pid == 0)
     {
-        // FIXME: This is not thread safe (particularly the printfs)
-
         /* Make this process its own session */
         if (setsid () < 0)
-            g_printerr ("Failed to make process a new session: %s\n", strerror (errno));
+            _exit (errno);
 
         /* Change to this user */
         if (getuid () == 0)
         {
-            if (setgid (user_get_gid (user)) != 0)
-            {
-                g_printerr ("Failed to set group ID to %d: %s\n", user_get_gid (user), strerror (errno));
-                _exit (EXIT_FAILURE);
-            }
+            if (setgid (gid) != 0)
+                _exit (errno);
 
-            if (setuid (user_get_uid (user)) != 0)
-            {
-                g_printerr ("Failed to set user ID to %d: %s\n", user_get_uid (user), strerror (errno));
-                _exit (EXIT_FAILURE);
-            }
+            if (setuid (uid) != 0)
+                _exit (errno);
         }
 
         /* Change working directory */
         /* NOTE: This must be done after the permissions are changed because NFS filesystems can
          * be setup so the local root user accesses the NFS files as 'nobody'.  If the home directories
          * are not system readable then the chdir can fail */
-        if (chdir (user_get_home_directory (user)) != 0)
-        {
-            g_printerr ("Failed to change to home directory %s: %s\n", user_get_home_directory (user), strerror (errno));
-            _exit (EXIT_FAILURE);
-        }
+        if (chdir (home_directory) != 0)
+            _exit (errno);
 
-        /* Redirect stderr to a log file */
-        if (log_filename && !g_path_is_absolute (log_filename))
+        if (log_filename)
         {
             rename (log_filename, log_backup_filename);
             fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
-            dup2 (fd, STDERR_FILENO);
-            close (fd);
+            if (fd >= 0)
+            {
+                dup2 (fd, STDERR_FILENO);
+                close (fd);
+            }
         }
 
         /* Run the command */
         execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
-        g_printerr ("Failed to run command: %s\n", strerror (errno));
         _exit (EXIT_FAILURE);
     }
 
index bc3928be49cfb9c65c371bf173e5efab89305e4f..88616f538886ba3c7c5ad29ac337f4b3887d2b1d 100644 (file)
@@ -549,6 +549,7 @@ session_real_start (Session *session)
     int version;
     int to_child_pipe[2], from_child_pipe[2];
     int to_child_output, from_child_input;
+    gchar *arg0, *arg1;
 
     g_return_val_if_fail (session->priv->pid == 0, FALSE);
 
@@ -581,24 +582,26 @@ session_real_start (Session *session)
     }
 
     /* Run the child */
+    arg0 = g_strdup_printf ("%d", to_child_output);
+    arg1 = g_strdup_printf ("%d", from_child_input);
     session->priv->pid = fork ();
-    if (session->priv->pid < 0)
-    {
-        g_debug ("Failed to fork session child process: %s", strerror (errno));
-        return FALSE;
-    }
-
     if (session->priv->pid == 0)
     {
         /* Run us again in session child mode */
         execlp ("lightdm",
                 "lightdm",
                 "--session-child",
-                g_strdup_printf ("%d", to_child_output),
-                g_strdup_printf ("%d", from_child_input),
-                NULL);
+                arg0, arg1, NULL);
         _exit (EXIT_FAILURE);
     }
+    g_free (arg0);
+    g_free (arg1);
+
+    if (session->priv->pid < 0)
+    {
+        g_debug ("Failed to fork session child process: %s", strerror (errno));
+        return FALSE;
+    }
 
     /* Hold a reference on this object until the child process terminates so we
      * can handle the watch callback even if it is no longer used. Otherwise a
index 13362095ceca1914841c6d944f7f56831a57f260..9624f450a00371b7563c16e1dd89d147305ba5e4 100644 (file)
@@ -28,9 +28,6 @@ struct UnitySystemCompositorPrivate
 {
     /* Compositor process */
     Process *process;
-  
-    /* File to log to */
-    gchar *log_file;    
 
     /* Command to run the compositor */
     gchar *command;
@@ -313,7 +310,7 @@ read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 }
 
 static void
-run_cb (Process *process, UnitySystemCompositor *compositor)
+run_cb (Process *process, gpointer user_data)
 {
     int fd;
 
@@ -321,29 +318,6 @@ run_cb (Process *process, UnitySystemCompositor *compositor)
     fd = open ("/dev/null", O_RDONLY);
     dup2 (fd, STDIN_FILENO);
     close (fd);
-
-    /* Redirect output to logfile */
-    if (compositor->priv->log_file)
-    {
-         int fd;
-         gchar *old_filename;
-
-         /* Move old file out of the way */
-         old_filename = g_strdup_printf ("%s.old", compositor->priv->log_file);
-         rename (compositor->priv->log_file, old_filename);
-         g_free (old_filename);
-
-         /* Create new file and log to it */
-         fd = g_open (compositor->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-         if (fd < 0)
-             l_warning (compositor, "Failed to open log file %s: %s", compositor->priv->log_file, g_strerror (errno));
-         else
-         {
-             dup2 (fd, STDOUT_FILENO);
-             dup2 (fd, STDERR_FILENO);
-             close (fd);
-         }
-    }
 }
 
 static gboolean
@@ -383,7 +357,7 @@ unity_system_compositor_start (DisplayServer *server)
 {
     UnitySystemCompositor *compositor = UNITY_SYSTEM_COMPOSITOR (server);
     gboolean result;
-    gchar *dir, *command, *absolute_command, *value;
+    gchar *dir, *log_file, *command, *absolute_command, *value;
 
     g_return_val_if_fail (compositor->priv->process == NULL, FALSE);
 
@@ -408,12 +382,14 @@ unity_system_compositor_start (DisplayServer *server)
 
     /* Setup logging */
     dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
-    compositor->priv->log_file = g_build_filename (dir, "unity-system-compositor.log", NULL);
-    l_debug (compositor, "Logging to %s", compositor->priv->log_file);
+    log_file = g_build_filename (dir, "unity-system-compositor.log", NULL);
+    l_debug (compositor, "Logging to %s", log_file);
     g_free (dir);
 
     /* Setup environment */
-    compositor->priv->process = process_new ();
+    compositor->priv->process = process_new (run_cb, compositor);
+    process_set_log_file (compositor->priv->process, log_file, TRUE);
+    g_free (log_file);
     process_set_clear_environment (compositor->priv->process, TRUE);
     process_set_env (compositor->priv->process, "XDG_SEAT", "seat0");
     value = g_strdup_printf ("%d", compositor->priv->vt);
@@ -435,7 +411,6 @@ unity_system_compositor_start (DisplayServer *server)
     process_set_command (compositor->priv->process, absolute_command);
     g_free (absolute_command);
     g_signal_connect (compositor->priv->process, "stopped", G_CALLBACK (stopped_cb), compositor);
-    g_signal_connect (compositor->priv->process, "run", G_CALLBACK (run_cb), compositor);
     result = process_start (compositor->priv->process, FALSE);
 
     /* Close compostor ends of the pipes */
@@ -485,7 +460,6 @@ unity_system_compositor_finalize (GObject *object)
         g_signal_handlers_disconnect_matched (self->priv->process, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
         g_object_unref (self->priv->process);
     }
-    g_free (self->priv->log_file);
     g_free (self->priv->command);
     g_free (self->priv->socket);
     if (self->priv->have_vt_ref)
index efe1227ea47a25411af52c1f17c45dc60310bf47..11d6fd1f939432b481768583244be230b1d77ea1 100644 (file)
@@ -27,9 +27,6 @@ struct XServerLocalPrivate
 {
     /* X server process */
     Process *x_server_process;
-  
-    /* File to log to */
-    gchar *log_file;    
 
     /* Command to run the X server */
     gchar *command;
@@ -326,7 +323,7 @@ get_absolute_command (const gchar *command)
 }
 
 static void
-run_cb (Process *process, XServerLocal *server)
+run_cb (Process *process, gpointer user_data)
 {
     int fd;
 
@@ -335,29 +332,6 @@ run_cb (Process *process, XServerLocal *server)
     dup2 (fd, STDIN_FILENO);
     close (fd);
 
-    /* Redirect output to logfile */
-    if (server->priv->log_file)
-    {
-         int fd;
-         gchar *old_filename;
-
-         /* Move old file out of the way */
-         old_filename = g_strdup_printf ("%s.old", server->priv->log_file);
-         rename (server->priv->log_file, old_filename);
-         g_free (old_filename);
-
-         /* Create new file and log to it */
-         fd = g_open (server->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-         if (fd < 0)
-             l_warning (server, "Failed to open log file %s: %s", server->priv->log_file, g_strerror (errno));
-         else
-         {
-             dup2 (fd, STDOUT_FILENO);
-             dup2 (fd, STDERR_FILENO);
-             close (fd);
-         }
-    }
-
     /* Set SIGUSR1 to ignore so the X server can indicate it when it is ready */
     signal (SIGUSR1, SIG_IGN);
 }
@@ -439,7 +413,7 @@ x_server_local_start (DisplayServer *display_server)
 {
     XServerLocal *server = X_SERVER_LOCAL (display_server);
     gboolean result;
-    gchar *filename, *dir, *absolute_command;
+    gchar *filename, *dir, *log_file, *absolute_command;
     GString *command;
 
     g_return_val_if_fail (server->priv->x_server_process == NULL, FALSE);
@@ -448,17 +422,18 @@ x_server_local_start (DisplayServer *display_server)
 
     g_return_val_if_fail (server->priv->command != NULL, FALSE);
 
-    server->priv->x_server_process = process_new ();
+    server->priv->x_server_process = process_new (run_cb, server);
     process_set_clear_environment (server->priv->x_server_process, TRUE);
-    g_signal_connect (server->priv->x_server_process, "run", G_CALLBACK (run_cb), server);
     g_signal_connect (server->priv->x_server_process, "got-signal", G_CALLBACK (got_signal_cb), server);
     g_signal_connect (server->priv->x_server_process, "stopped", G_CALLBACK (stopped_cb), server);
 
     /* Setup logging */
     filename = g_strdup_printf ("%s.log", display_server_get_name (display_server));
     dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
-    server->priv->log_file = g_build_filename (dir, filename, NULL);
-    l_debug (display_server, "Logging to %s", server->priv->log_file);
+    log_file = g_build_filename (dir, filename, NULL);
+    process_set_log_file (server->priv->x_server_process, log_file, TRUE);
+    l_debug (display_server, "Logging to %s", log_file);
+    g_free (log_file);
     g_free (filename);
     g_free (dir);
 
@@ -577,7 +552,6 @@ x_server_local_finalize (GObject *object)
         g_signal_handlers_disconnect_matched (self->priv->x_server_process, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
         g_object_unref (self->priv->x_server_process);
     }
-    g_free (self->priv->log_file);
     g_free (self->priv->command);
     g_free (self->priv->config_file);
     g_free (self->priv->layout);
index 0897725dd37f485bb620b8ea58c53f204349cecc..884489dd66a19fdde2fb4bc1382faabdff23a555 100644 (file)
@@ -26,9 +26,6 @@ struct XServerXVNCPrivate
 {
     /* X server process */
     Process *x_server_process;
-  
-    /* File to log to */
-    gchar *log_file;
 
     /* Command to run the X server */
     gchar *command;
@@ -130,28 +127,15 @@ get_absolute_command (const gchar *command)
 }
 
 static void
-run_cb (Process *process, XServerXVNC *server)
+run_cb (Process *process, gpointer user_data)
 {
+    XServerXVNC *server = user_data;
+
     /* Connect input */
     dup2 (server->priv->socket_fd, STDIN_FILENO);
     dup2 (server->priv->socket_fd, STDOUT_FILENO);
     close (server->priv->socket_fd);
 
-    /* Redirect output to logfile */
-    if (server->priv->log_file)
-    {
-         int fd;
-
-         fd = g_open (server->priv->log_file, O_WRONLY | O_CREAT | O_TRUNC, 0600);
-         if (fd < 0)
-             l_warning (server, "Failed to open log file %s: %s", server->priv->log_file, g_strerror (errno));
-         else
-         {
-             dup2 (fd, STDERR_FILENO);
-             close (fd);
-         }
-    }
-
     /* Set SIGUSR1 to ignore so the X server can indicate it when it is ready */
     signal (SIGUSR1, SIG_IGN);
 }
@@ -200,7 +184,7 @@ x_server_xvnc_start (DisplayServer *display_server)
     XServerXVNC *server = X_SERVER_XVNC (display_server);
     XAuthority *authority;
     gboolean result;
-    gchar *filename, *run_dir, *dir, *absolute_command;
+    gchar *filename, *run_dir, *dir, *log_file, *absolute_command;
     GString *command;
     gchar hostname[1024], *number;
     GError *error = NULL;
@@ -209,17 +193,18 @@ x_server_xvnc_start (DisplayServer *display_server)
 
     server->priv->got_signal = FALSE;
 
-    server->priv->x_server_process = process_new ();
+    server->priv->x_server_process = process_new (run_cb, server);
     process_set_clear_environment (server->priv->x_server_process, TRUE);
-    g_signal_connect (server->priv->x_server_process, "run", G_CALLBACK (run_cb), server);  
     g_signal_connect (server->priv->x_server_process, "got-signal", G_CALLBACK (got_signal_cb), server);
     g_signal_connect (server->priv->x_server_process, "stopped", G_CALLBACK (stopped_cb), server);
 
     /* Setup logging */
     filename = g_strdup_printf ("%s.log", display_server_get_name (display_server));
     dir = config_get_string (config_get_instance (), "LightDM", "log-directory");
-    server->priv->log_file = g_build_filename (dir, filename, NULL);
-    l_debug (display_server, "Logging to %s", server->priv->log_file);
+    log_file = g_build_filename (dir, filename, NULL);
+    process_set_log_file (server->priv->x_server_process, log_file, FALSE);
+    l_debug (display_server, "Logging to %s", log_file);
+    g_free (log_file);
     g_free (filename);
     g_free (dir);
 
@@ -314,7 +299,6 @@ x_server_xvnc_finalize (GObject *object)
         g_object_unref (self->priv->x_server_process);
     g_free (self->priv->command);
     g_free (self->priv->authority_file);
-    g_free (self->priv->log_file);
 
     G_OBJECT_CLASS (x_server_xvnc_parent_class)->finalize (object);
 }