2 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
3 * (c) Copyright 1993, 1994 International Business Machines Corp. *
4 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
5 * (c) Copyright 1993, 1994 Novell, Inc. *
8 * xdm - display manager daemon
10 * $XConsortium: server.c /main/4 1995/10/27 16:14:56 rswiston $
12 * Copyright 1988 Massachusetts Institute of Technology
14 * Permission to use, copy, modify, and distribute this software and its
15 * documentation for any purpose and without fee is hereby granted, provided
16 * that the above copyright notice appear in all copies and that both that
17 * copyright notice and this permission notice appear in supporting
18 * documentation, and that the name of M.I.T. not be used in advertising or
19 * publicity pertaining to distribution of the software without specific,
20 * written prior permission. M.I.T. makes no representations about the
21 * suitability of this software for any purpose. It is provided "as is"
22 * without express or implied warranty.
24 * Author: Keith Packard, MIT X Consortium
27 # include <sys/signal.h>
37 /***************************************************************************
39 * Local procedure declarations
41 ***************************************************************************/
43 static char * _SysErrorMsg( int n) ;
44 static SIGVAL CatchUsr1( int arg ) ;
45 static void GetRemoteAddress( struct display *d, int fd) ;
46 static SIGVAL PingBlocked( int arg ) ;
47 static SIGVAL PingLost( int arg ) ;
48 static SIGVAL abortOpen( int arg ) ;
49 static int serverPause( unsigned t, int serverPid) ;
50 static SIGVAL serverPauseAbort( int arg ) ;
51 static SIGVAL serverPauseUsr1( int arg ) ;
57 /***************************************************************************
61 ***************************************************************************/
70 #if defined(SYSV) || defined(SVR4)
71 (void) signal (SIGUSR1, CatchUsr1);
73 Debug ("Display Manager caught SIGUSR1\n");
81 char *s = ((n >= 0 && n < sys_nerr) ? sys_errlist[n] : "unknown error");
83 return (s ? s : "no such error");
87 StartServerOnce( struct display *d )
95 extern struct passwd puser; /* pseudo_user password entry */
97 Debug ("Starting server for %s\n", d->name);
99 signal (SIGUSR1, CatchUsr1);
101 switch (pid = fork ()) {
105 sprintf (arg, "-auth %s", d->authFile);
106 argv = parseArgs (argv, arg);
109 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_ARGS,MC_DEF_LOG_NO_ARGS));
112 Debug("Server invoked as ");
113 for (f = argv; *f; f++)
118 * set the permissions on console devices to pseudo-user.
119 * run the server as a pseudo-user, not root...
122 if (solaris_setdevperm(d->gettyLine, puser.pw_uid, puser.pw_gid) == 0)
123 Debug ("Unable to set permissions on console devices ..\n");
126 setgid (puser.pw_gid);
127 setuid (puser.pw_uid);
133 * build the server environment (if any)...
136 if (d->environStr && strlen(d->environStr) > 0)
137 env = parseEnv(env, d->environStr);
139 if (getEnv (env, "OPENWINHOME") == NULL)
140 env = setEnv(env, "OPENWINHOME", "/usr/openwin");
143 if (getEnv (env, "ODMDIR") == NULL)
144 env = setEnv(env, "ODMDIR", "/etc/objrepos");
146 env = setEnv(env, "XTOEXEC", "true"); /* flag for xserverrc */
151 * give the server SIGUSR1 ignored,
152 * it will notice that and send SIGUSR1
155 signal (SIGUSR1, SIG_IGN);
156 (void) execve (argv[0], argv, env);
157 LogError(ReadCatalog(
158 MC_LOG_SET,MC_LOG_NO_EXESRV,MC_DEF_LOG_NO_EXESRV),argv[0]);
161 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_FAIL_FORK,MC_DEF_LOG_FAIL_FORK));
166 Debug ("Server started. Process ID = %d\n", pid);
168 if (serverPause ((unsigned) d->openDelay, pid))
175 StartServer( struct display *d )
181 while (d->serverAttempts == 0 || i < d->serverAttempts)
183 if ((ret = StartServerOnce (d)) == TRUE)
185 sleep (d->openDelay);
193 * sleep for t seconds, return 1 if the server is dead when
194 * the sleep finishes, 0 else
197 static jmp_buf pauseAbort;
198 static int serverPauseRet;
201 serverPauseAbort( int arg )
203 Debug ("Display Manager pause timed out\n");
204 longjmp (pauseAbort, 1);
208 serverPauseUsr1( int arg )
210 Debug ("Display Manager pause received SIGUSR1\n");
212 longjmp (pauseAbort, 1);
216 serverPause( unsigned t, int serverPid )
221 Debug ("Display Manager pausing until SIGUSR1 from server or timeout\n");
222 if (!setjmp (pauseAbort)) {
223 signal (SIGALRM, serverPauseAbort);
224 signal (SIGUSR1, serverPauseUsr1);
227 alarm ((unsigned) 1);
234 Debug ("ServerPause(): already received USR1\n");
238 pid = wait ((waitType *) 0);
241 pid = wait ((waitType *) 0);
246 pid = waitpid ((pid_t) 0,&dummy,WNOHANG);
249 pid = wait3 ((waitType *) 0, WNOHANG,
250 (struct rusage *) 0);
253 if (pid == serverPid ||
254 pid == -1 && errno == ECHILD)
256 Debug ("Server dead\n");
262 Debug ("Server alive and kicking\n");
268 alarm ((unsigned) 0);
269 signal (SIGALRM, SIG_DFL);
270 signal (SIGUSR1, CatchUsr1);
271 if (serverPauseRet) {
272 Debug ("Server died\n");
273 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_SRV_DIED,MC_DEF_LOG_SRV_DIED));
275 return serverPauseRet;
280 * this code is complicated by some TCP failings. On
281 * many systems, the connect will occasionally hang forever,
282 * this trouble is avoided by setting up a timeout to longjmp
283 * out of the connect (possibly leaving piles of garbage around
284 * inside Xlib) and give up, terminating the server.
287 static jmp_buf openAbort;
292 longjmp (openAbort, 1);
296 GetRemoteAddress( struct display *d, int fd )
299 int len = sizeof (buf);
302 free ((char *) d->peer);
303 getpeername (fd, (struct sockaddr *) buf, &len);
307 d->peer = (struct sockaddr *) malloc (len);
310 bcopy (buf, (char *) d->peer, len);
314 Debug ("Got remote address %s %d\n", d->name, d->peerlen);
319 /****************************************************************************
323 * If d->startAttempts is a large number and a connection cannot be made to
324 * the server, the error log can fill up rapidly with error messages. This
325 * could be common in X-terminals that do not support XDMCP and are turned
326 * off over a weekend. This routine attempts to reduce the number of error
327 * messages logged in this scenario.
329 ****************************************************************************/
332 LogOpenError( int count )
335 if ( count <= 10 ) return 1;
336 if ( count <= 100 && (count % 10 == 0) ) return 1;
337 if ( count <= 500 && (count % 50 == 0) ) return 1;
338 if ( (count % 100 == 0) ) return 1;
345 WaitForServer( struct display *d )
349 for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
350 (void) signal (SIGALRM, abortOpen);
351 (void) alarm ((unsigned) d->openTimeout);
352 if (!setjmp (openAbort)) {
353 Debug ("Before XOpenDisplay(%s)\n", d->name);
355 dpy = XOpenDisplay (d->name);
356 (void) alarm ((unsigned) 0);
357 (void) signal (SIGALRM, SIG_DFL);
358 Debug ("After XOpenDisplay()\n");
360 if (d->displayType.location == Foreign)
361 GetRemoteAddress (d, ConnectionNumber (dpy));
362 RegisterCloseOnFork (ConnectionNumber (dpy));
363 (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
366 Debug ("OpenDisplay failed %d (%s)\n",
367 errno, _SysErrorMsg (errno));
369 Debug ("Waiting for server to start %d\n", i);
370 sleep ((unsigned) d->openDelay);
372 Debug ("Hung in open, aborting\n");
373 if (LogOpenError(d->startTries))
374 LogError(ReadCatalog(
375 MC_LOG_SET,MC_LOG_HUNG_DPY,MC_DEF_LOG_HUNG_DPY),
376 d->name, d->startTries);
377 (void) signal (SIGALRM, SIG_DFL);
381 Debug ("Giving up on server\n");
382 if (LogOpenError(d->startTries))
383 LogError(ReadCatalog(
384 MC_LOG_SET,MC_LOG_FAIL_SRVOPEN,MC_DEF_LOG_FAIL_SRVOPEN),
385 d->startTries, d->name);
390 ResetServer( struct display *d )
392 if (dpy && d->displayType.origin != FromXDMCP)
397 /****************************************************************************
399 * Server pinging routines...
401 * These routines attempt to determine if the server is still alive.
402 * Periodically (d->pingInterval) an XSync is sent to the server. If an I/O
403 * error occurs, then the connection has been lost and the server needs to
404 * be reset. If the server is blocked for some reason (i.e. server grab) the
405 * XSync will block until a local timer expires. In this case, we just note
406 * the block and continue...
409 * The XSync was replaced by a socket-level ping. For some reason, an XSync
410 * to a grabbed server causes a subsequent pseudoReset (KillClients) to not
411 * kill all clients. The socket ping is not affected by a grabbed server,
412 * but it cannot detect a server shutdown and restart within one ping
415 ****************************************************************************/
417 static jmp_buf pingTime;
418 static int serverDead = FALSE;
424 longjmp (pingTime, 1);
429 PingBlocked( int arg )
432 longjmp (pingTime, 1);
437 PingServer( struct display *d, Display *alternateDpy )
445 oldError = XSetIOErrorHandler ((XIOErrorHandler)PingLost);
446 oldAlarm = alarm (0);
447 oldSig = signal (SIGALRM, PingBlocked);
448 alarm (d->pingTimeout * 60);
449 if (!setjmp (pingTime))
451 Debug ("Ping server\n");
452 XNoOp (alternateDpy);
453 XSync (alternateDpy, 0);
454 Debug ("Server alive\n");
456 while (XPending(alternateDpy)) {
458 XNextEvent(alternateDpy, &event);
464 Debug ("Server dead\n");
466 signal (SIGALRM, SIG_DFL);
467 XSetIOErrorHandler (oldError);
471 Debug ("Server blocked, continuing...\n");
474 signal (SIGALRM, oldSig);
476 XSetIOErrorHandler (oldError);