@@ -64,6 +64,9 @@ typedef struct
64
64
/* TRUE when received ready signal */
65
65
gboolean got_signal ;
66
66
67
+ /* Poll source ID (fallback for signal if uids differ) */
68
+ guint poll_for_socket_source ;
69
+
67
70
/* VT to run on */
68
71
gint vt ;
69
72
gboolean have_vt_ref ;
@@ -391,6 +394,46 @@ got_signal_cb (Process *process, int signum, XServerLocal *server)
391
394
}
392
395
}
393
396
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
+ if ( g_stat (socketpath , & statbuf ) == 0 )
406
+ {
407
+ uid_t uid = priv -> user ? user_get_uid (priv -> user ) : 0 ;
408
+
409
+ /* It has to be a valid socket file */
410
+ if (!(statbuf .st_mode & S_IFSOCK ))
411
+ {
412
+ l_debug (server , "X11 socket file is not a socket: %s" , socketpath );
413
+ return G_SOURCE_REMOVE ;
414
+ }
415
+
416
+ /* It has to be owned by the correct user */
417
+ if (statbuf .st_uid != uid )
418
+ {
419
+ l_debug (server , "X11 socket file is not owned by uid %d: %s" , uid , socketpath );
420
+ return G_SOURCE_REMOVE ;
421
+ }
422
+
423
+ /* Consider SIGUSR1 to have been recieved */
424
+ priv -> got_signal = TRUE;
425
+ l_debug (server , "Detected valid X11 socket for X server :%d" , priv -> display_number );
426
+
427
+ // FIXME: Check return value
428
+ DISPLAY_SERVER_CLASS (x_server_local_parent_class )-> start (DISPLAY_SERVER (server ));
429
+
430
+ return G_SOURCE_REMOVE ;
431
+ }
432
+
433
+ /* Wait another second and check again */
434
+ return G_SOURCE_CONTINUE ;
435
+ }
436
+
394
437
static void
395
438
stopped_cb (Process * process , XServerLocal * server )
396
439
{
@@ -468,7 +511,10 @@ x_server_local_start (DisplayServer *display_server)
468
511
ProcessRunFunc run_cb = X_SERVER_LOCAL_GET_CLASS (server )-> get_run_function (server );
469
512
priv -> x_server_process = process_new (run_cb , server );
470
513
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 );
514
+ if (priv -> user == NULL || user_get_uid (priv -> user ) == getuid ())
515
+ g_signal_connect (priv -> x_server_process , PROCESS_SIGNAL_GOT_SIGNAL , G_CALLBACK (got_signal_cb ), server );
516
+ else if (!priv -> poll_for_socket_source )
517
+ priv -> poll_for_socket_source = g_timeout_add_seconds (1 , (GSourceFunc )poll_for_socket_cb , server );
472
518
g_signal_connect (priv -> x_server_process , PROCESS_SIGNAL_STOPPED , G_CALLBACK (stopped_cb ), server );
473
519
474
520
/* Setup logging */
@@ -594,6 +640,11 @@ x_server_local_finalize (GObject *object)
594
640
595
641
if (priv -> x_server_process )
596
642
g_signal_handlers_disconnect_matched (priv -> x_server_process , G_SIGNAL_MATCH_DATA , 0 , 0 , NULL , NULL , self );
643
+ if (priv -> poll_for_socket_source )
644
+ {
645
+ g_source_remove (priv -> poll_for_socket_source );
646
+ priv -> poll_for_socket_source = 0 ;
647
+ }
597
648
g_clear_object (& priv -> x_server_process );
598
649
g_clear_pointer (& priv -> command , g_free );
599
650
g_clear_object (& priv -> user );
0 commit comments