Merge pull request #2492 from derekschrock/randr-wait

Add xrdp-waitforx to wait for X to start with RandR outputs
This commit is contained in:
matt335672 2023-02-13 10:29:22 +00:00 committed by GitHub
commit a27440c237
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 195 additions and 71 deletions

View File

@ -58,6 +58,7 @@ SUBDIRS = \
xrdp \
fontutils \
keygen \
waitforx \
docs \
instfiles \
genkeymap \

View File

@ -2808,6 +2808,22 @@ g_execlp3(const char *a1, const char *a2, const char *a3)
#endif
}
/*****************************************************************************/
/* does not work in win32 */
unsigned int
g_set_alarm(void (*func)(int), unsigned int secs)
{
#if defined(_WIN32)
return 0;
#else
/* Cancel any previous alarm to prevent a race */
unsigned int rv = alarm(0);
signal(SIGALRM, func);
(void)alarm(secs);
return rv;
#endif
}
/*****************************************************************************/
/* does not work in win32 */
void

View File

@ -204,6 +204,7 @@ char *g_get_strerror(void);
int g_get_errno(void);
int g_execvp(const char *p1, char *args[]);
int g_execlp3(const char *a1, const char *a2, const char *a3);
unsigned int g_set_alarm(void (*func)(int), unsigned int secs);
void g_signal_child_stop(void (*func)(int));
void g_signal_segfault(void (*func)(int));
void g_signal_hang_up(void (*func)(int));

View File

@ -575,6 +575,7 @@ AC_CONFIG_FILES([
instfiles/pulse/Makefile
instfiles/rc.d/Makefile
keygen/Makefile
waitforx/Makefile
libipm/Makefile
libxrdp/Makefile
Makefile

View File

@ -5,6 +5,7 @@ AM_CPPFLAGS = \
-DXRDP_SYSCONF_PATH=\"${sysconfdir}\" \
-DXRDP_CFG_PATH=\"${sysconfdir}/xrdp\" \
-DXRDP_SBIN_PATH=\"${sbindir}\" \
-DXRDP_BIN_PATH=\"${bindir}\" \
-DXRDP_SHARE_PATH=\"${datadir}/xrdp\" \
-DXRDP_PID_PATH=\"${localstatedir}/run\" \
-DXRDP_SOCKET_PATH=\"${socketdir}\" \
@ -34,7 +35,9 @@ xrdp_sesman_SOURCES = \
sig.c \
sig.h \
xauth.c \
xauth.h
xauth.h \
xwait.c \
xwait.h
# Possible authentication modules
# See https://www.gnu.org/software/automake/manual/html_node/Conditional-Sources.html

View File

@ -49,6 +49,7 @@
#include "sesman.h"
#include "string_calls.h"
#include "xauth.h"
#include "xwait.h"
#include "xrdp_sockets.h"
#ifndef PR_SET_NO_NEW_PRIVS
@ -285,42 +286,6 @@ x_server_running_check_ports(int display)
return x_running;
}
/******************************************************************************/
/**
*
* @brief checks if there's a server running on a display
* @param display the display to check
* @return 0 if there isn't a display running, nonzero otherwise
*
*/
static int
x_server_running(int display)
{
char text[256];
int x_running;
g_sprintf(text, "/tmp/.X11-unix/X%d", display);
x_running = g_file_exist(text);
if (!x_running)
{
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
g_sprintf(text, "/tmp/.X%d-lock", display);
x_running = g_file_exist(text);
}
if (x_running)
{
LOG(LOG_LEVEL_INFO, "Found X server running at %s", text);
}
else
{
LOG(LOG_LEVEL_DEBUG, "Did not find a running X server at %s", text);
}
return x_running;
}
/******************************************************************************/
/* called with the main thread
returns boolean */
@ -375,37 +340,6 @@ session_get_avail_display_from_chain(void)
return 0;
}
/******************************************************************************/
static int
wait_for_xserver(int display)
{
int i;
/* give X a bit to start */
/* wait up to 10 secs for x server to start */
i = 0;
LOG(LOG_LEVEL_DEBUG, "Waiting for X server to start on display %d", display);
while (!x_server_running(display))
{
i++;
if (i > 40)
{
LOG(LOG_LEVEL_WARNING,
"Timed out waiting for X server on display %d to startup",
display);
break;
}
g_sleep(250);
}
return 0;
}
/******************************************************************************/
static int
session_start_chansrv(int uid, int display)
{
@ -655,13 +589,12 @@ session_start(struct auth_info *auth_info,
}
else if (window_manager_pid == 0)
{
wait_for_xserver(display);
env_set_user(s->uid,
0,
display,
g_cfg->env_names,
g_cfg->env_values);
if (x_server_running(display))
if (wait_for_xserver(display))
{
auth_set_env(auth_info);
if (s->directory != 0)
@ -912,7 +845,6 @@ session_start(struct auth_info *auth_info,
struct exit_status xserver_exit_status;
struct exit_status chansrv_exit_status;
wait_for_xserver(display);
chansrv_pid = session_start_chansrv(s->uid, display);
LOG(LOG_LEVEL_INFO,

47
sesman/xwait.c Normal file
View File

@ -0,0 +1,47 @@
#if defined(HAVE_CONFIG_H)
#include "config_ac.h"
#endif
#include "log.h"
#include "os_calls.h"
#include "string_calls.h"
#include "xwait.h"
#include <stdio.h>
#include <string.h>
/******************************************************************************/
int
wait_for_xserver(int display)
{
FILE *dp = NULL;
int ret = 0;
char buffer[100];
char exe_cmd[262];
LOG(LOG_LEVEL_DEBUG, "Waiting for X server to start on display %d", display);
g_snprintf(exe_cmd, sizeof(exe_cmd), "%s/xrdp-waitforx", XRDP_BIN_PATH);
dp = popen(exe_cmd, "r");
if (dp == NULL)
{
LOG(LOG_LEVEL_ERROR, "Unable to launch xrdp-waitforx");
return 1;
}
while (fgets(buffer, 100, dp))
{
g_strtrim(buffer, 2);
LOG(LOG_LEVEL_DEBUG, "%s", buffer);
}
ret = pclose(dp);
if (ret != 0)
{
LOG(LOG_LEVEL_ERROR, "An error occurred while running xrdp-waitforx");
return 0;
}
return 1;
}

12
sesman/xwait.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef XWAIT_H
#define XWAIT_H
/**
*
* @brief waits for X to start
* @param display number
* @return 0 on error, 1 if X has outputs
*
*/
int
wait_for_xserver(int display);
#endif

10
waitforx/Makefile.am Normal file
View File

@ -0,0 +1,10 @@
bin_PROGRAMS = \
xrdp-waitforx
AM_LDFLAGS = -lX11 -lXrandr
AM_CFLAGS = -I$(top_srcdir)/common
xrdp_waitforx_SOURCES = waitforx.c
xrdp_waitforx_LDADD = \
$(top_builddir)/common/libcommon.la

101
waitforx/waitforx.c Normal file
View File

@ -0,0 +1,101 @@
#include <X11/extensions/Xrandr.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <unistd.h>
#include "config_ac.h"
#include "os_calls.h"
#include "string_calls.h"
#define ATTEMPTS 10
#define ALARM_WAIT 30
void
alarm_handler(int signal_num)
{
/* Avoid printf() in signal handler (see signal-safety(7)) */
const char msg[] = "Timed out waiting for RandR outputs\n";
g_file_write(1, msg, g_strlen(msg));
exit(1);
}
int
main(int argc, char **argv)
{
char *display = NULL;
int error_base = 0;
int event_base = 0;
int n = 0;
int outputs = 0;
int wait = ATTEMPTS;
Display *dpy = NULL;
XRRScreenResources *res = NULL;
display = getenv("DISPLAY");
g_set_alarm(alarm_handler, ALARM_WAIT);
if (!display)
{
printf("DISPLAY is null");
exit(1);
}
for (n = 1; n <= wait; ++n)
{
dpy = XOpenDisplay(display);
printf("Opening display %s. Attempt %d of %d\n", display, n, wait);
if (dpy != NULL)
{
printf("Opened display %s\n", display);
break;
}
g_sleep(1000);
}
if (!dpy)
{
printf("Unable to open display %s\n", display);
exit(1);
}
if (!XRRQueryExtension(dpy, &event_base, &error_base))
{
printf("RandR not supported on display %s", display);
}
else
{
for (n = 1; n <= wait; ++n)
{
res = XRRGetScreenResources(dpy, DefaultRootWindow(dpy));
printf("Waiting for outputs. Attempt %d of %d\n", n, wait);
if (res != NULL)
{
if (res->noutput > 0)
{
outputs = res->noutput;
XRRFreeScreenResources(res);
printf("Found %d output[s]\n", outputs);
break;
}
XRRFreeScreenResources(res);
}
g_sleep(1000);
}
if (outputs > 0)
{
printf("display %s ready with %d outputs\n", display, res->noutput);
}
else
{
printf("Unable to find any outputs\n");
exit(1);
}
}
exit(0);
}