Add xrdp-waitforx to wait for X to start with RandR outputs

For some window managers (fvwm2 and fvwm3) if the X server isn't
running and has output it's possible for the window manager to fail or
reconfigure randr incorrectly.

With xrdp-waitfox:
 - Install xrdp-waitfox to the BIN dir.
 - sesman will run xrdp-waitfox as the logged in user.
 - Set an alarm to exit after 30 seconds.
 - Try to open env DISPLAY value's display (10 seconds).
 - Test for RandR extension.
 - Wait for outputs to appear (10 seconds).
This commit is contained in:
Derek Schrock 2022-11-19 21:43:00 -05:00
parent 9bab8e0da5
commit 829378bba8
8 changed files with 173 additions and 71 deletions

View File

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

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

96
waitforx/waitforx.c Normal file
View File

@ -0,0 +1,96 @@
#include <X11/extensions/Xrandr.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/signal.h>
#include <unistd.h>
#define ATTEMPTS 10
#define ALARM_WAIT 30
void
alarm_handler(int signal_num)
{
printf("Unable to find RandR outputs after %d seconds\n", ALARM_WAIT);
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");
signal(SIGALRM, alarm_handler);
alarm(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;
}
sleep(1);
}
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);
}
sleep(1);
}
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);
}