Skip to content

Commit

Permalink
Add xrdp-waitforx to wait for X to start with RandR outputs
Browse files Browse the repository at this point in the history
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).
  • Loading branch information
derekschrock authored and jsorg71 committed Oct 20, 2023
1 parent 9150d69 commit 5875f39
Show file tree
Hide file tree
Showing 8 changed files with 186 additions and 73 deletions.
1 change: 1 addition & 0 deletions Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ SUBDIRS = \
xrdp \
fontutils \
keygen \
waitforx \
docs \
instfiles \
genkeymap \
Expand Down
1 change: 1 addition & 0 deletions configure.ac
Original file line number Diff line number Diff line change
Expand Up @@ -588,6 +588,7 @@ AC_CONFIG_FILES([
instfiles/pulse/Makefile
instfiles/rc.d/Makefile
keygen/Makefile
waitforx/Makefile
libipm/Makefile
libxrdp/Makefile
Makefile
Expand Down
16 changes: 15 additions & 1 deletion sesman/Makefile.am
Original file line number Diff line number Diff line change
Expand Up @@ -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}\" \
Expand Down Expand Up @@ -58,7 +59,20 @@ xrdp_sesman_SOURCES = \
sig.h \
xauth.c \
xauth.h \
$(AUTH_C)
xwait.c \
xwait.h

# Possible authentication modules
# See https://www.gnu.org/software/automake/manual/html_node/Conditional-Sources.html
EXTRA_xrdp_sesman_SOURCES = \
verify_user.c \
verify_user_bsd.c \
verify_user_kerberos.c \
verify_user_pam.c \
verify_user_pam_userpass.c

# Make sure the right authentication module is pulled in
xrdp_sesman_DEPENDENCIES = $(AUTHMOD_OBJ)

xrdp_sesman_LDADD = \
$(top_builddir)/libipm/libipm.la \
Expand Down
76 changes: 4 additions & 72 deletions sesman/session.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@

#include "sesman.h"
#include "xauth.h"
#include "xwait.h"
#include "xrdp_sockets.h"
#include "string_calls.h"

Expand Down Expand Up @@ -277,42 +278,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 */
Expand Down Expand Up @@ -367,37 +332,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(const char *username, int display)
{
Expand Down Expand Up @@ -607,13 +541,12 @@ session_start(struct auth_info *auth_info,
}
else if (window_manager_pid == 0)
{
wait_for_xserver(display);
env_set_user(s->username,
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)
Expand Down Expand Up @@ -891,8 +824,7 @@ 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->username, display);
chansrv_pid = session_start_chansrv(s->uid, display);

LOG(LOG_LEVEL_INFO,
"Session started successfully for user %s on display %d",
Expand Down
47 changes: 47 additions & 0 deletions sesman/xwait.c
Original file line number Diff line number Diff line change
@@ -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 changes: 12 additions & 0 deletions sesman/xwait.h
Original file line number Diff line number Diff line change
@@ -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 changes: 10 additions & 0 deletions waitforx/Makefile.am
Original file line number Diff line number Diff line change
@@ -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 changes: 96 additions & 0 deletions waitforx/waitforx.c
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 5875f39

Please sign in to comment.