not quite so much needs to be delayed to the init() function
[personal-kdebase.git] / workspace / kdm / backend / server.c
blob81754838749f56c8b43b98a1f6f1e56aa303bf30
1 /*
3 Copyright 1988, 1998 The Open Group
4 Copyright 2001,2003,2005 Oswald Buddenhagen <ossi@kde.org>
6 Permission to use, copy, modify, distribute, and sell this software and its
7 documentation for any purpose is hereby granted without fee, provided that
8 the above copyright notice appear in all copies and that both that
9 copyright notice and this permission notice appear in supporting
10 documentation.
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21 OTHER DEALINGS IN THE SOFTWARE.
23 Except as contained in this notice, the name of a copyright holder shall
24 not be used in advertising or otherwise to promote the sale, use or
25 other dealings in this Software without prior written authorization
26 from the copyright holder.
31 * xdm - display manager daemon
32 * Author: Keith Packard, MIT X Consortium
34 * server.c - manage the X server
37 #include "dm.h"
38 #include "dm_error.h"
39 #include "dm_socket.h"
41 #include <X11/Xlib.h>
43 #include <stdio.h>
44 #include <signal.h>
47 struct display *startingServer;
48 time_t serverTimeout = TO_INF;
50 char **
51 prepareServerArgv( struct display *d, const char *args )
53 char **argv;
54 #ifdef HAVE_VTS
55 char vtstr[8];
56 #endif
58 if (!(argv = parseArgs( 0, d->serverCmd )) ||
59 !(argv = parseArgs( argv, args )) ||
60 !(argv = addStrArr( argv, d->name, -1 )))
61 exit( 47 );
62 #ifdef HAVE_VTS
63 if (d->serverVT &&
64 !(argv = addStrArr( argv, vtstr,
65 sprintf( vtstr, "vt%d", d->serverVT ) )))
66 exit( 47 );
67 #endif
68 return argv;
71 static void
72 startServerOnce( void )
74 struct display *d = startingServer;
75 char **argv;
77 debug( "startServerOnce for %s, try %d\n", d->name, ++d->startTries );
78 d->serverStatus = starting;
79 switch (Fork( &d->serverPid )) {
80 case 0:
81 argv = prepareServerArgv( d, d->serverArgsLocal );
82 if (d->authFile) {
83 if (!(argv = addStrArr( argv, "-auth", 5 )) ||
84 !(argv = addStrArr( argv, d->authFile, -1 )))
85 exit( 47 );
87 debug( "exec %\"[s\n", argv );
89 * give the server SIGUSR1 ignored,
90 * it will notice that and send SIGUSR1
91 * when ready
93 (void)Signal( SIGUSR1, SIG_IGN );
94 (void)execv( argv[0], argv );
95 logError( "X server %\"s cannot be executed\n", argv[0] );
96 exit( 47 );
97 case -1:
98 logError( "X server fork failed\n" );
99 startServerFailed();
100 break;
101 default:
102 debug( "X server forked, pid %d\n", d->serverPid );
103 serverTimeout = d->serverTimeout + now;
104 break;
108 void
109 startServer( struct display *d )
111 startingServer = d;
112 d->startTries = 0;
113 startServerOnce();
116 void
117 abortStartServer( struct display *d )
119 if (startingServer == d)
121 if (d->serverStatus != ignore)
123 d->serverStatus = ignore;
124 serverTimeout = TO_INF;
125 debug( "aborting X server start\n" );
127 startingServer = 0;
131 void
132 startServerSuccess()
134 struct display *d = startingServer;
135 d->serverStatus = ignore;
136 serverTimeout = TO_INF;
137 debug( "X server ready, starting session\n" );
138 startDisplayP2( d );
141 void
142 startServerFailed()
144 struct display *d = startingServer;
145 if (!d->serverAttempts || d->startTries < d->serverAttempts) {
146 d->serverStatus = pausing;
147 serverTimeout = d->openDelay + now;
148 } else {
149 d->serverStatus = ignore;
150 serverTimeout = TO_INF;
151 startingServer = 0;
152 logError( "X server for display %s cannot be started,"
153 " session disabled\n", d->name );
154 stopDisplay( d );
158 void
159 startServerTimeout()
161 struct display *d = startingServer;
162 switch (d->serverStatus) {
163 case ignore:
164 case awaiting:
165 break; /* cannot happen */
166 case starting:
167 logError( "X server startup timeout, terminating\n" );
168 kill( d->serverPid, d->termSignal );
169 d->serverStatus = d->termSignal == SIGKILL ? killed : terminated;
170 serverTimeout = d->serverTimeout + now;
171 break;
172 case terminated:
173 logInfo( "X server termination timeout, killing\n" );
174 kill( d->serverPid, SIGKILL );
175 d->serverStatus = killed;
176 serverTimeout = 10 + now;
177 break;
178 case killed:
179 logInfo( "X server is stuck in D state; leaving it alone\n" );
180 startServerFailed();
181 break;
182 case pausing:
183 startServerOnce();
184 break;
189 Display *dpy;
192 * this code is complicated by some TCP failings. On
193 * many systems, the connect will occasionally hang forever,
194 * this trouble is avoided by setting up a timeout to Longjmp
195 * out of the connect (possibly leaving piles of garbage around
196 * inside Xlib) and give up, terminating the server.
199 static Jmp_buf openAbort;
201 /* ARGSUSED */
202 static void
203 abortOpen( int n ATTR_UNUSED )
205 Longjmp( openAbort, 1 );
208 #ifdef XDMCP
210 #ifdef STREAMSCONN
211 # include <tiuser.h>
212 #endif
214 static void
215 getRemoteAddress( struct display *d, int fd )
217 char buf[512];
218 int len = sizeof(buf);
219 #ifdef STREAMSCONN
220 struct netbuf netb;
221 #endif
223 XdmcpDisposeARRAY8( &d->peer );
224 #ifdef STREAMSCONN
225 netb.maxlen = sizeof(buf);
226 netb.buf = buf;
227 t_getname( fd, &netb, REMOTENAME );
228 len = 8;
229 /* lucky for us, t_getname returns something that looks like a sockaddr */
230 #else
231 getpeername( fd, (struct sockaddr *)buf, (void *)&len );
232 #endif
233 if (len && XdmcpAllocARRAY8( &d->peer, len ))
234 memmove( (char *)d->peer.data, buf, len );
235 debug( "got remote address %s %d\n", d->name, d->peer.length );
238 #endif /* XDMCP */
240 static int
241 openErrorHandler( Display *dspl ATTR_UNUSED )
243 logError( "IO Error in XOpenDisplay\n" );
244 exit( EX_OPENFAILED_DPY );
245 /*NOTREACHED*/
246 return (0);
249 void
250 waitForServer( struct display *d )
252 volatile int i;
253 /* static int i; */
255 i = 0;
256 do {
257 (void)Signal( SIGALRM, abortOpen );
258 (void)alarm( (unsigned)d->openTimeout );
259 if (!Setjmp( openAbort )) {
260 debug( "before XOpenDisplay(%s)\n", d->name );
261 errno = 0;
262 (void)XSetIOErrorHandler( openErrorHandler );
263 dpy = XOpenDisplay( d->name );
264 #ifdef STREAMSCONN
266 /* For some reason, the next XOpenDisplay we do is
267 going to fail, so we might as well get that out
268 of the way. There is something broken here. */
269 Display *bogusDpy = XOpenDisplay( d->name );
270 debug( "bogus XOpenDisplay %s\n",
271 bogusDpy ? "succeeded" : "failed" );
272 if (bogusDpy) XCloseDisplay( bogusDpy ); /* just in case */
274 #endif
275 (void)alarm( (unsigned)0 );
276 (void)Signal( SIGALRM, SIG_DFL );
277 (void)XSetIOErrorHandler( (int (*)( Display * )) 0 );
278 debug( "after XOpenDisplay(%s)\n", d->name );
279 if (dpy) {
280 #ifdef XDMCP
281 if ((d->displayType & d_location) == dForeign)
282 getRemoteAddress( d, ConnectionNumber( dpy ) );
283 #endif
284 registerCloseOnFork( ConnectionNumber( dpy ) );
285 return;
287 debug( "OpenDisplay(%s) attempt %d failed: %m\n", d->name, i + 1 );
288 sleep( (unsigned)d->openDelay );
289 } else {
290 logError( "Hung in XOpenDisplay(%s), aborting\n", d->name );
291 (void)Signal( SIGALRM, SIG_DFL );
292 break;
294 } while (++i < d->openRepeat);
295 logError( "Cannot connect to %s, giving up\n", d->name );
296 exit( EX_OPENFAILED_DPY );
300 void
301 resetServer( struct display *d )
303 if (dpy && (d->displayType & d_origin) != dFromXDMCP)
304 pseudoReset();
308 static Jmp_buf pingTime;
310 static void
311 pingLost( void )
313 Longjmp( pingTime, 1 );
316 /* ARGSUSED */
317 static int
318 pingLostIOErr( Display *dspl ATTR_UNUSED )
320 pingLost();
321 return 0;
324 /* ARGSUSED */
325 static void
326 pingLostSig( int n ATTR_UNUSED )
328 pingLost();
332 pingServer( struct display *d )
334 int (*oldError)( Display * );
335 void (*oldSig)( int );
336 int oldAlarm;
338 oldError = XSetIOErrorHandler( pingLostIOErr );
339 oldAlarm = alarm( 0 );
340 oldSig = Signal( SIGALRM, pingLostSig );
341 (void)alarm( d->pingTimeout * 60 );
342 if (!Setjmp( pingTime )) {
343 debug( "ping X server\n" );
344 XSync( dpy, 0 );
345 } else {
346 debug( "X server dead\n" );
347 (void)alarm( 0 );
348 (void)Signal( SIGALRM, SIG_DFL );
349 XSetIOErrorHandler( oldError );
350 return False;
352 (void)alarm( 0 );
353 (void)Signal( SIGALRM, oldSig );
354 (void)alarm( oldAlarm );
355 debug( "X server alive\n" );
356 XSetIOErrorHandler( oldError );
357 return True;