2 * CDE - Common Desktop Environment
4 * Copyright (c) 1993-2012, The Open Group. All rights reserved.
6 * These libraries and programs are free software; you can
7 * redistribute them and/or modify them under the terms of the GNU
8 * Lesser General Public License as published by the Free Software
9 * Foundation; either version 2 of the License, or (at your option)
12 * These libraries and programs are distributed in the hope that
13 * they will be useful, but WITHOUT ANY WARRANTY; without even the
14 * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15 * PURPOSE. See the GNU Lesser General Public License for more
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with these librararies and programs; if not, write
20 * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21 * Floor, Boston, MA 02110-1301 USA
24 * (c) Copyright 1993, 1994 Hewlett-Packard Company *
25 * (c) Copyright 1993, 1994 International Business Machines Corp. *
26 * (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
27 * (c) Copyright 1993, 1994 Novell, Inc. *
30 * xdm - display manager daemon
32 * $XConsortium: server.c /main/4 1995/10/27 16:14:56 rswiston $
34 * Copyright 1988 Massachusetts Institute of Technology
36 * Permission to use, copy, modify, and distribute this software and its
37 * documentation for any purpose and without fee is hereby granted, provided
38 * that the above copyright notice appear in all copies and that both that
39 * copyright notice and this permission notice appear in supporting
40 * documentation, and that the name of M.I.T. not be used in advertising or
41 * publicity pertaining to distribution of the software without specific,
42 * written prior permission. M.I.T. makes no representations about the
43 * suitability of this software for any purpose. It is provided "as is"
44 * without express or implied warranty.
46 * Author: Keith Packard, MIT X Consortium
49 # include <sys/types.h>
50 # include <sys/signal.h>
61 /***************************************************************************
63 * Local procedure declarations
65 ***************************************************************************/
67 static const char * _SysErrorMsg( int n) ;
68 static SIGVAL CatchUsr1( int arg ) ;
69 static void GetRemoteAddress( struct display *d, int fd) ;
70 static SIGVAL PingBlocked( int arg ) ;
71 static SIGVAL PingLost( int arg ) ;
72 static SIGVAL abortOpen( int arg ) ;
73 static int serverPause( unsigned t, int serverPid) ;
74 static SIGVAL serverPauseAbort( int arg ) ;
75 static SIGVAL serverPauseUsr1( int arg ) ;
81 /***************************************************************************
85 ***************************************************************************/
94 #if defined(SYSV) || defined(SVR4)
95 (void) signal (SIGUSR1, CatchUsr1);
97 Debug ("Display Manager caught SIGUSR1\n");
102 _SysErrorMsg( int n )
105 const char *s = strerror(n);
107 return (s ? s : "no such error");
111 StartServerOnce( struct display *d )
119 extern struct passwd puser; /* pseudo_user password entry */
121 Debug ("Starting server for %s\n", d->name);
123 signal (SIGUSR1, CatchUsr1);
125 switch (pid = fork ()) {
129 sprintf (arg, "-auth %s", d->authFile);
130 argv = parseArgs (argv, arg);
133 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_NO_ARGS,MC_DEF_LOG_NO_ARGS));
136 Debug("Server invoked as ");
137 for (f = argv; *f; f++)
142 * set the permissions on console devices to pseudo-user.
143 * run the server as a pseudo-user, not root...
146 if (solaris_setdevperm(d->gettyLine, puser.pw_uid, puser.pw_gid) == 0)
147 Debug ("Unable to set permissions on console devices ..\n");
150 if(-1 == setgid (puser.pw_gid)) {
151 Debug ("setgid() failed setting %d\n", puser.pw_gid);
153 if(-1 == setuid (puser.pw_uid)) {
154 Debug ("setuid() failed setting %d\n", puser.pw_uid);
161 * build the server environment (if any)...
164 if (d->environStr && strlen(d->environStr) > 0)
165 env = parseEnv(env, d->environStr);
167 if (getEnv (env, "OPENWINHOME") == NULL)
168 env = setEnv(env, "OPENWINHOME", "/usr/openwin");
171 if (getEnv (env, "ODMDIR") == NULL)
172 env = setEnv(env, "ODMDIR", "/etc/objrepos");
174 env = setEnv(env, "XTOEXEC", "true"); /* flag for xserverrc */
179 * give the server SIGUSR1 ignored,
180 * it will notice that and send SIGUSR1
183 signal (SIGUSR1, SIG_IGN);
184 (void) execve (argv[0], argv, env);
185 LogError(ReadCatalog(
186 MC_LOG_SET,MC_LOG_NO_EXESRV,MC_DEF_LOG_NO_EXESRV),argv[0]);
189 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_FAIL_FORK,MC_DEF_LOG_FAIL_FORK));
194 Debug ("Server started. Process ID = %d\n", pid);
196 if (serverPause ((unsigned) d->openDelay, pid))
203 StartServer( struct display *d )
209 while (d->serverAttempts == 0 || i < d->serverAttempts)
211 if ((ret = StartServerOnce (d)) == TRUE)
213 sleep (d->openDelay);
221 * sleep for t seconds, return 1 if the server is dead when
222 * the sleep finishes, 0 else
225 static jmp_buf pauseAbort;
226 static int serverPauseRet;
229 serverPauseAbort( int arg )
231 Debug ("Display Manager pause timed out\n");
232 longjmp (pauseAbort, 1);
236 serverPauseUsr1( int arg )
238 Debug ("Display Manager pause received SIGUSR1\n");
240 longjmp (pauseAbort, 1);
244 serverPause( unsigned t, int serverPid )
249 Debug ("Display Manager pausing until SIGUSR1 from server or timeout\n");
250 if (!setjmp (pauseAbort)) {
251 signal (SIGALRM, serverPauseAbort);
252 signal (SIGUSR1, serverPauseUsr1);
255 alarm ((unsigned) 1);
262 Debug ("ServerPause(): already received USR1\n");
266 pid = wait ((waitType *) 0);
269 pid = wait ((waitType *) 0);
274 pid = waitpid ((pid_t) 0,&dummy,WNOHANG);
277 pid = wait3 ((waitType *) 0, WNOHANG,
278 (struct rusage *) 0);
281 if (pid == serverPid ||
282 pid == -1 && errno == ECHILD)
284 Debug ("Server dead\n");
290 Debug ("Server alive and kicking\n");
296 alarm ((unsigned) 0);
297 signal (SIGALRM, SIG_DFL);
298 signal (SIGUSR1, CatchUsr1);
299 if (serverPauseRet) {
300 Debug ("Server died\n");
301 LogError(ReadCatalog(MC_LOG_SET,MC_LOG_SRV_DIED,MC_DEF_LOG_SRV_DIED));
303 return serverPauseRet;
308 * this code is complicated by some TCP failings. On
309 * many systems, the connect will occasionally hang forever,
310 * this trouble is avoided by setting up a timeout to longjmp
311 * out of the connect (possibly leaving piles of garbage around
312 * inside Xlib) and give up, terminating the server.
315 static jmp_buf openAbort;
320 longjmp (openAbort, 1);
324 GetRemoteAddress( struct display *d, int fd )
327 int len = sizeof (buf);
330 free ((char *) d->peer);
331 getpeername (fd, (struct sockaddr *) buf, &len);
335 d->peer = (struct sockaddr *) malloc (len);
338 bcopy (buf, (char *) d->peer, len);
342 Debug ("Got remote address %s %d\n", d->name, d->peerlen);
347 /****************************************************************************
351 * If d->startAttempts is a large number and a connection cannot be made to
352 * the server, the error log can fill up rapidly with error messages. This
353 * could be common in X-terminals that do not support XDMCP and are turned
354 * off over a weekend. This routine attempts to reduce the number of error
355 * messages logged in this scenario.
357 ****************************************************************************/
360 LogOpenError( int count )
363 if ( count <= 10 ) return 1;
364 if ( count <= 100 && (count % 10 == 0) ) return 1;
365 if ( count <= 500 && (count % 50 == 0) ) return 1;
366 if ( (count % 100 == 0) ) return 1;
373 WaitForServer( struct display *d )
377 for (i = 0; i < (d->openRepeat > 0 ? d->openRepeat : 1); i++) {
378 (void) signal (SIGALRM, abortOpen);
379 (void) alarm ((unsigned) d->openTimeout);
380 if (!setjmp (openAbort)) {
381 Debug ("Before XOpenDisplay(%s)\n", d->name);
383 dpy = XOpenDisplay (d->name);
384 (void) alarm ((unsigned) 0);
385 (void) signal (SIGALRM, SIG_DFL);
386 Debug ("After XOpenDisplay()\n");
388 if (d->displayType.location == Foreign)
389 GetRemoteAddress (d, ConnectionNumber (dpy));
390 RegisterCloseOnFork (ConnectionNumber (dpy));
391 (void) fcntl (ConnectionNumber (dpy), F_SETFD, 0);
394 Debug ("OpenDisplay failed %d (%s)\n",
395 errno, _SysErrorMsg (errno));
397 Debug ("Waiting for server to start %d\n", i);
398 sleep ((unsigned) d->openDelay);
400 Debug ("Hung in open, aborting\n");
401 if (LogOpenError(d->startTries))
402 LogError(ReadCatalog(
403 MC_LOG_SET,MC_LOG_HUNG_DPY,MC_DEF_LOG_HUNG_DPY),
404 d->name, d->startTries);
405 (void) signal (SIGALRM, SIG_DFL);
409 Debug ("Giving up on server\n");
410 if (LogOpenError(d->startTries))
411 LogError(ReadCatalog(
412 MC_LOG_SET,MC_LOG_FAIL_SRVOPEN,MC_DEF_LOG_FAIL_SRVOPEN),
413 d->startTries, d->name);
418 ResetServer( struct display *d )
420 if (dpy && d->displayType.origin != FromXDMCP)
425 /****************************************************************************
427 * Server pinging routines...
429 * These routines attempt to determine if the server is still alive.
430 * Periodically (d->pingInterval) an XSync is sent to the server. If an I/O
431 * error occurs, then the connection has been lost and the server needs to
432 * be reset. If the server is blocked for some reason (i.e. server grab) the
433 * XSync will block until a local timer expires. In this case, we just note
434 * the block and continue...
437 * The XSync was replaced by a socket-level ping. For some reason, an XSync
438 * to a grabbed server causes a subsequent pseudoReset (KillClients) to not
439 * kill all clients. The socket ping is not affected by a grabbed server,
440 * but it cannot detect a server shutdown and restart within one ping
443 ****************************************************************************/
445 static jmp_buf pingTime;
446 static int serverDead = FALSE;
452 longjmp (pingTime, 1);
457 PingBlocked( int arg )
460 longjmp (pingTime, 1);
465 PingServer( struct display *d, Display *alternateDpy )
473 oldError = XSetIOErrorHandler ((XIOErrorHandler)PingLost);
474 oldAlarm = alarm (0);
475 oldSig = signal (SIGALRM, PingBlocked);
476 alarm (d->pingTimeout * 60);
477 if (!setjmp (pingTime))
479 Debug ("Ping server\n");
480 XNoOp (alternateDpy);
481 XSync (alternateDpy, 0);
482 Debug ("Server alive\n");
484 while (XPending(alternateDpy)) {
486 XNextEvent(alternateDpy, &event);
492 Debug ("Server dead\n");
494 signal (SIGALRM, SIG_DFL);
495 XSetIOErrorHandler (oldError);
499 Debug ("Server blocked, continuing...\n");
502 signal (SIGALRM, oldSig);
504 XSetIOErrorHandler (oldError);