summaryrefslogtreecommitdiff
path: root/xdm/server.c
diff options
context:
space:
mode:
Diffstat (limited to 'xdm/server.c')
-rw-r--r--xdm/server.c337
1 files changed, 337 insertions, 0 deletions
diff --git a/xdm/server.c b/xdm/server.c
new file mode 100644
index 0000000..c645753
--- /dev/null
+++ b/xdm/server.c
@@ -0,0 +1,337 @@
+/*
+
+Copyright 1988, 1998 The Open Group
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of The Open Group shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from The Open Group.
+
+*/
+
+/*
+ * xdm - display manager daemon
+ * Author: Keith Packard, MIT X Consortium
+ *
+ * server.c - manage the X server
+ */
+
+#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, pid_t serverPid);
+
+/* ARGSUSED */
+static SIGVAL
+CatchUsr1 (int n)
+{
+ int olderrno = errno;
+
+ Debug ("display manager caught SIGUSR1\n");
+ ++receivedUsr1;
+ errno = olderrno;
+}
+
+const char *_SysErrorMsg (int n)
+{
+ const char *s = strerror(n);
+ return (s ? s : "unknown error");
+}
+
+static int
+StartServerOnce (struct display *d)
+{
+ char **f;
+ char **argv;
+ char arg[1024];
+ pid_t pid;
+
+ Debug ("StartServer for %s\n", d->name);
+ receivedUsr1 = 0;
+ (void) Signal (SIGUSR1, CatchUsr1);
+ argv = d->argv;
+ switch (pid = fork ()) {
+ case 0:
+ CleanUpChild ();
+ if (d->authFile) {
+ snprintf (arg, sizeof(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");
+ /*
+ * give the server SIGUSR1 ignored,
+ * it will notice that and send SIGUSR1
+ * when ready
+ */
+ (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;
+}
+
+/*
+ * sleep for t seconds, return 1 if the server is dead when
+ * the sleep finishes, 0 else
+ */
+
+static Jmp_buf pauseAbort;
+static int serverPauseRet;
+
+/* ARGSUSED */
+static SIGVAL
+serverPauseAbort (int n)
+{
+ Longjmp (pauseAbort, 1);
+}
+
+/* ARGSUSED */
+static SIGVAL
+serverPauseUsr1 (int n)
+{
+ Debug ("display manager paused til SIGUSR1\n");
+ ++receivedUsr1;
+ Longjmp (pauseAbort, 1);
+}
+
+static int
+serverPause (unsigned t, pid_t serverPid)
+{
+ pid_t pid;
+
+ serverPauseRet = 0;
+ if (!Setjmp (pauseAbort)) {
+ (void) Signal (SIGALRM, serverPauseAbort);
+ (void) Signal (SIGUSR1, serverPauseUsr1);
+ if (!receivedUsr1)
+ (void) alarm (t);
+ else
+ Debug ("Already received USR1\n");
+ for (;;) {
+ /*
+ * wait() is unsafe. Other Xserver or xdm processes may
+ * exit at this time and this will remove the wait status.
+ * This means the main loop will not restart the display.
+ */
+ if (!receivedUsr1)
+ pid = waitpid (serverPid, (int *) 0, 0);
+ else
+ pid = waitpid (serverPid, (int *) 0, WNOHANG);
+
+ if (pid == serverPid ||
+ (pid == -1 && errno == ECHILD))
+ {
+ Debug ("Server dead\n");
+ serverPauseRet = 1;
+ break;
+ }
+
+ if (pid == 0) {
+ Debug ("Server alive and kicking\n");
+ break;
+ }
+ }
+ }
+ (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;
+}
+
+
+/*
+ * this code is complicated by some TCP failings. On
+ * many systems, the connect will occasionally hang forever,
+ * this trouble is avoided by setting up a timeout to Longjmp
+ * out of the connect (possibly leaving piles of garbage around
+ * inside Xlib) and give up, terminating the server.
+ */
+
+static Jmp_buf openAbort;
+
+/* ARGSUSED */
+static SIGVAL
+abortOpen (int n)
+{
+ Longjmp (openAbort, 1);
+}
+
+
+static int
+openErrorHandler (Display *dpy)
+{
+ LogError ("IO Error in XOpenDisplay\n");
+ exit (OPENFAILED_DISPLAY);
+ /*NOTREACHED*/
+ 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);
+ d->dpy = XOpenDisplay (d->name);
+ (void) alarm ((unsigned) 0);
+ (void) Signal (SIGALRM, SIG_DFL);
+ (void) XSetIOErrorHandler ((int (*)(Display *)) 0);
+ Debug ("After XOpenDisplay(%s)\n", d->name);
+ if (d->dpy) {
+ RegisterCloseOnFork (ConnectionNumber (d->dpy));
+ (void) fcntl (ConnectionNumber (d->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 (d->dpy && d->displayType.origin != FromXDMCP)
+ pseudoReset (d->dpy);
+}
+
+static Jmp_buf pingTime;
+
+static void
+PingLost (void)
+{
+ Longjmp (pingTime, 1);
+}
+
+/* ARGSUSED */
+static int
+PingLostIOErr (Display *dpy)
+{
+ PingLost();
+ return 0;
+}
+
+/* ARGSUSED */
+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 : d->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;
+}