# include "dm.h"
# include "dm_error.h"
# include "dm_socket.h"
# include <X11/Xlib.h>
# include <X11/Xos.h>
# include <stdio.h>
# include <signal.h>
# include <errno.h>
# include <sys/socket.h>
static int receivedUsr1;
static int serverPause (unsigned t, int serverPid);
static Display *dpy;
static SIGVAL
CatchUsr1 (int n)
{
int olderrno = errno;
#ifdef SIGNALS_RESET_WHEN_CAUGHT
(void) Signal (SIGUSR1, CatchUsr1);
#endif
Debug ("display manager caught SIGUSR1\n");
++receivedUsr1;
errno = olderrno;
}
char *_SysErrorMsg (int n)
{
char *s = strerror(n);
return (s ? s : "unknown error");
}
static int
StartServerOnce (struct display *d)
{
char **f;
char **argv;
char arg[1024];
int pid;
Debug ("StartServer for %s\n", d->name);
receivedUsr1 = 0;
(void) Signal (SIGUSR1, CatchUsr1);
argv = d->argv;
switch (pid = fork ()) {
case 0:
CleanUpChild ();
#ifdef XDMCP
DestroyWellKnownSockets();
#endif
if (d->authFile) {
sprintf (arg, "-auth %s", d->authFile);
argv = parseArgs (argv, arg);
}
if (!argv) {
LogError ("StartServer: no arguments\n");
sleep ((unsigned) d->openDelay);
exit (UNMANAGE_DISPLAY);
}
for (f = argv; *f; f++)
Debug ("'%s' ", *f);
Debug ("\n");
(void) Signal (SIGUSR1, SIG_IGN);
(void) execv (argv[0], argv);
LogError ("server %s cannot be executed\n",
argv[0]);
sleep ((unsigned) d->openDelay);
exit (REMANAGE_DISPLAY);
case -1:
LogError ("fork failed, sleeping\n");
return 0;
default:
break;
}
Debug ("Server Started %d\n", pid);
d->serverPid = pid;
if (serverPause ((unsigned) d->openDelay, pid))
return FALSE;
return TRUE;
}
int
StartServer (struct display *d)
{
int i;
int ret = FALSE;
i = 0;
while (d->serverAttempts == 0 || i < d->serverAttempts)
{
if ((ret = StartServerOnce (d)) == TRUE)
break;
sleep (d->openDelay);
i++;
}
return ret;
}
static Jmp_buf pauseAbort;
static int serverPauseRet;
static SIGVAL
serverPauseAbort (int n)
{
Longjmp (pauseAbort, 1);
}
static SIGVAL
serverPauseUsr1 (int n)
{
Debug ("display manager paused til SIGUSR1\n");
++receivedUsr1;
Longjmp (pauseAbort, 1);
}
static int
serverPause (unsigned t, int serverPid)
{
int pid;
serverPauseRet = 0;
if (!Setjmp (pauseAbort)) {
(void) Signal (SIGALRM, serverPauseAbort);
(void) Signal (SIGUSR1, serverPauseUsr1);
#ifdef SYSV
if (receivedUsr1)
(void) alarm ((unsigned) 1);
else
(void) alarm (t);
#else
if (!receivedUsr1)
(void) alarm (t);
else
Debug ("Already received USR1\n");
#endif
for (;;) {
#if defined(SYSV) && defined(X_NOT_POSIX)
pid = wait ((waitType *) 0);
#else
if (!receivedUsr1)
#ifndef X_NOT_POSIX
pid = waitpid (serverPid, (int *) 0, 0);
else
pid = waitpid (serverPid, (int *) 0, WNOHANG);
#else
pid = wait ((waitType *) 0);
else
pid = wait3 ((waitType *) 0, WNOHANG,
(struct rusage *) 0);
#endif
#endif
if (pid == serverPid ||
(pid == -1 && errno == ECHILD))
{
Debug ("Server dead\n");
serverPauseRet = 1;
break;
}
#if !defined(SYSV) || !defined(X_NOT_POSIX)
if (pid == 0) {
Debug ("Server alive and kicking\n");
break;
}
#endif
}
}
(void) alarm ((unsigned) 0);
(void) Signal (SIGALRM, SIG_DFL);
(void) Signal (SIGUSR1, CatchUsr1);
if (serverPauseRet) {
Debug ("Server died\n");
LogError ("server unexpectedly died\n");
}
return serverPauseRet;
}
static Jmp_buf openAbort;
static SIGVAL
abortOpen (int n)
{
Longjmp (openAbort, 1);
}
#ifdef XDMCP
#ifdef STREAMSCONN
#include <tiuser.h>
#endif
static void
GetRemoteAddress (struct display *d, int fd)
{
char buf[512];
int len = sizeof (buf);
#ifdef STREAMSCONN
struct netbuf netb;
#endif
if (d->peer)
free ((char *) d->peer);
#ifdef STREAMSCONN
netb.maxlen = sizeof(buf);
netb.buf = buf;
t_getname(fd, &netb, REMOTENAME);
len = 8;
#else
getpeername (fd, (struct sockaddr *) buf, (void *)&len);
#endif
d->peerlen = 0;
if (len)
{
d->peer = (XdmcpNetaddr) malloc (len);
if (d->peer)
{
memmove( (char *) d->peer, buf, len);
d->peerlen = len;
}
}
Debug ("Got remote address %s %d\n", d->name, d->peerlen);
}
#endif
static int
openErrorHandler (Display *dpy)
{
LogError ("IO Error in XOpenDisplay\n");
exit (OPENFAILED_DISPLAY);
return(0);
}
int
WaitForServer (struct display *d)
{
static int i;
for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
(void) Signal (SIGALRM, abortOpen);
(void) alarm ((unsigned) d->openTimeout);
if (!Setjmp (openAbort)) {
Debug ("Before XOpenDisplay(%s)\n", d->name);
errno = 0;
(void) XSetIOErrorHandler (openErrorHandler);
dpy = XOpenDisplay (d->name);
#ifdef STREAMSCONN
{
Display *bogusDpy = XOpenDisplay (d->name);
Debug ("bogus XOpenDisplay %s\n",
bogusDpy ? "succeeded" : "failed");
if (bogusDpy) XCloseDisplay(bogusDpy);
}
#endif
(void) alarm ((unsigned) 0);
(void) Signal (SIGALRM, SIG_DFL);
(void) XSetIOErrorHandler ((int (*)(Display *)) 0);
Debug ("After XOpenDisplay(%s)\n", d->name);
if (dpy) {
#ifdef XDMCP
if (d->displayType.location == Foreign)
GetRemoteAddress (d, ConnectionNumber (dpy));
#endif
RegisterCloseOnFork (ConnectionNumber (dpy));
(void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
return 1;
} else {
Debug ("OpenDisplay failed %d (%s) on \"%s\"\n",
errno, strerror (errno), d->name);
}
Debug ("waiting for server to start %d\n", i);
sleep ((unsigned) d->openDelay);
} else {
Debug ("hung in open, aborting\n");
LogError ("Hung in XOpenDisplay(%s), aborting\n", d->name);
(void) Signal (SIGALRM, SIG_DFL);
break;
}
}
Debug ("giving up on server\n");
LogError ("server open failed for %s, giving up\n", d->name);
return 0;
}
void
ResetServer (struct display *d)
{
if (dpy && d->displayType.origin != FromXDMCP)
pseudoReset (dpy);
}
static Jmp_buf pingTime;
static void
PingLost (void)
{
Longjmp (pingTime, 1);
}
static int
PingLostIOErr (Display *dpy)
{
PingLost();
return 0;
}
static SIGVAL
PingLostSig (int n)
{
PingLost();
}
int
PingServer (struct display *d, Display *alternateDpy)
{
int (*oldError)(Display *);
SIGVAL (*oldSig)(int);
int oldAlarm;
static Display *aDpy;
aDpy = (alternateDpy != NULL ? alternateDpy : dpy);
oldError = XSetIOErrorHandler (PingLostIOErr);
oldAlarm = alarm (0);
oldSig = Signal (SIGALRM, PingLostSig);
(void) alarm (d->pingTimeout * 60);
if (!Setjmp (pingTime))
{
Debug ("Ping server\n");
XSync (aDpy, 0);
}
else
{
Debug ("Server dead\n");
(void) alarm (0);
(void) Signal (SIGALRM, SIG_DFL);
XSetIOErrorHandler (oldError);
return 0;
}
(void) alarm (0);
(void) Signal (SIGALRM, oldSig);
(void) alarm (oldAlarm);
Debug ("Server alive\n");
XSetIOErrorHandler (oldError);
return 1;
}