@@ -64,6 +64,9 @@ typedef struct
6464 /* TRUE when received ready signal */
6565 gboolean got_signal ;
6666
67+ /* Poll source ID (fallback for signal if uids differ) */
68+ guint poll_for_socket_source ;
69+
6770 /* VT to run on */
6871 gint vt ;
6972 gboolean have_vt_ref ;
@@ -391,6 +394,44 @@ got_signal_cb (Process *process, int signum, XServerLocal *server)
391394 }
392395}
393396
397+ static gboolean
398+ poll_for_socket_cb (XServerLocal * server )
399+ {
400+ XServerLocalPrivate * priv = x_server_local_get_instance_private (server );
401+
402+ /* Check is X11 socket file exists as an alternative startup test to SIGUSR1 */
403+ GStatBuf statbuf ;
404+ g_autofree gchar * socketpath = g_strdup_printf ("/tmp/.X11-unix/X%d" , priv -> display_number );
405+
406+ if ( g_stat (socketpath , & statbuf ) == 0 )
407+ {
408+ uid_t uid = priv -> user ? user_get_uid (priv -> user ) : 0 ;
409+
410+ /* It has to be a valid socket file */
411+ if (!(statbuf .st_mode & S_IFSOCK ))
412+ l_debug (server , "X11 socket file is not a socket: %s" , socketpath );
413+
414+ /* It has to be owned by the correct user */
415+ else if (statbuf .st_uid != uid )
416+ l_debug (server , "X11 socket file is not owned by uid %d: %s" , uid , socketpath );
417+
418+ /* Consider SIGUSR1 to have been recieved */
419+ else {
420+ priv -> got_signal = TRUE;
421+ l_debug (server , "Detected valid X11 socket for X server :%d" , priv -> display_number );
422+
423+ // FIXME: Check return value
424+ DISPLAY_SERVER_CLASS (x_server_local_parent_class )-> start (DISPLAY_SERVER (server ));
425+ }
426+
427+ /* Cancel the timer as the file showed up */
428+ return FALSE;
429+ }
430+
431+ /* Wait another second and check again */
432+ return TRUE;
433+ }
434+
394435static void
395436stopped_cb (Process * process , XServerLocal * server )
396437{
@@ -468,7 +509,10 @@ x_server_local_start (DisplayServer *display_server)
468509 ProcessRunFunc run_cb = X_SERVER_LOCAL_GET_CLASS (server )-> get_run_function (server );
469510 priv -> x_server_process = process_new (run_cb , server );
470511 process_set_clear_environment (priv -> x_server_process , TRUE);
471- g_signal_connect (priv -> x_server_process , PROCESS_SIGNAL_GOT_SIGNAL , G_CALLBACK (got_signal_cb ), server );
512+ if (priv -> user == NULL || user_get_uid (priv -> user ) == getuid ())
513+ g_signal_connect (priv -> x_server_process , PROCESS_SIGNAL_GOT_SIGNAL , G_CALLBACK (got_signal_cb ), server );
514+ else if (!priv -> poll_for_socket_source )
515+ priv -> poll_for_socket_source = g_timeout_add_seconds (1 , (GSourceFunc )poll_for_socket_cb , server );
472516 g_signal_connect (priv -> x_server_process , PROCESS_SIGNAL_STOPPED , G_CALLBACK (stopped_cb ), server );
473517
474518 /* Setup logging */
@@ -594,6 +638,11 @@ x_server_local_finalize (GObject *object)
594638
595639 if (priv -> x_server_process )
596640 g_signal_handlers_disconnect_matched (priv -> x_server_process , G_SIGNAL_MATCH_DATA , 0 , 0 , NULL , NULL , self );
641+ if (priv -> poll_for_socket_source )
642+ {
643+ g_source_remove (priv -> poll_for_socket_source );
644+ priv -> poll_for_socket_source = 0 ;
645+ }
597646 g_clear_object (& priv -> x_server_process );
598647 g_clear_pointer (& priv -> command , g_free );
599648 g_clear_object (& priv -> user );
0 commit comments