~ubuntu-branches/ubuntu/gutsy/kdebase-workspace/gutsy-backports

« back to all changes in this revision

Viewing changes to kdm/backend/server.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2007-09-05 20:45:14 UTC
  • Revision ID: james.westby@ubuntu.com-20070905204514-632hhspl0nvrc84i
Tags: upstream-3.93.0
ImportĀ upstreamĀ versionĀ 3.93.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 
 
3
Copyright 1988, 1998  The Open Group
 
4
Copyright 2001,2003,2005 Oswald Buddenhagen <ossi@kde.org>
 
5
 
 
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.
 
11
 
 
12
The above copyright notice and this permission notice shall be included
 
13
in all copies or substantial portions of the Software.
 
14
 
 
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.
 
22
 
 
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.
 
27
 
 
28
*/
 
29
 
 
30
/*
 
31
 * xdm - display manager daemon
 
32
 * Author: Keith Packard, MIT X Consortium
 
33
 *
 
34
 * server.c - manage the X server
 
35
 */
 
36
 
 
37
#include "dm.h"
 
38
#include "dm_error.h"
 
39
#include "dm_socket.h"
 
40
 
 
41
#include <X11/Xlib.h>
 
42
 
 
43
#include <stdio.h>
 
44
#include <signal.h>
 
45
 
 
46
 
 
47
struct display *startingServer;
 
48
time_t serverTimeout = TO_INF;
 
49
 
 
50
char **
 
51
prepareServerArgv( struct display *d, const char *args )
 
52
{
 
53
        char **argv;
 
54
#ifdef HAVE_VTS
 
55
        char vtstr[8];
 
56
#endif
 
57
 
 
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;
 
69
}
 
70
 
 
71
static void
 
72
startServerOnce( void )
 
73
{
 
74
        struct display *d = startingServer;
 
75
        char **argv;
 
76
 
 
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 );
 
86
                }
 
87
                debug( "exec %\"[s\n", argv );
 
88
                /*
 
89
                 * give the server SIGUSR1 ignored,
 
90
                 * it will notice that and send SIGUSR1
 
91
                 * when ready
 
92
                 */
 
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;
 
105
        }
 
106
}
 
107
 
 
108
void
 
109
startServer( struct display *d )
 
110
{
 
111
        startingServer = d;
 
112
        d->startTries = 0;
 
113
        startServerOnce();
 
114
}
 
115
 
 
116
void
 
117
abortStartServer( struct display *d )
 
118
{
 
119
        if (startingServer == d)
 
120
        {
 
121
                if (d->serverStatus != ignore)
 
122
                {
 
123
                        d->serverStatus = ignore;
 
124
                        serverTimeout = TO_INF;
 
125
                        debug( "aborting X server start\n" );
 
126
                }
 
127
                startingServer = 0;
 
128
        }
 
129
}
 
130
 
 
131
void
 
132
startServerSuccess()
 
133
{
 
134
        struct display *d = startingServer;
 
135
        d->serverStatus = ignore;
 
136
        serverTimeout = TO_INF;
 
137
        debug( "X server ready, starting session\n" );
 
138
        startDisplayP2( d );
 
139
}
 
140
 
 
141
void
 
142
startServerFailed()
 
143
{
 
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 can't be started,"
 
153
                          " session disabled\n", d->name );
 
154
                stopDisplay( d );
 
155
        }
 
156
}
 
157
 
 
158
void
 
159
startServerTimeout()
 
160
{
 
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;
 
185
        }
 
186
}
 
187
 
 
188
 
 
189
Display *dpy;
 
190
 
 
191
/*
 
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.
 
197
 */
 
198
 
 
199
static Jmp_buf openAbort;
 
200
 
 
201
/* ARGSUSED */
 
202
static void
 
203
abortOpen( int n ATTR_UNUSED )
 
204
{
 
205
        Longjmp( openAbort, 1 );
 
206
}
 
207
 
 
208
#ifdef XDMCP
 
209
 
 
210
#ifdef STREAMSCONN
 
211
# include <tiuser.h>
 
212
#endif
 
213
 
 
214
static void
 
215
getRemoteAddress( struct display *d, int fd )
 
216
{
 
217
        char buf[512];
 
218
        int len = sizeof(buf);
 
219
#ifdef STREAMSCONN
 
220
        struct netbuf netb;
 
221
#endif
 
222
 
 
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 );
 
236
}
 
237
 
 
238
#endif /* XDMCP */
 
239
 
 
240
static int
 
241
openErrorHandler( Display *dspl ATTR_UNUSED )
 
242
{
 
243
        logError( "IO Error in XOpenDisplay\n" );
 
244
        exit( EX_OPENFAILED_DPY );
 
245
        /*NOTREACHED*/
 
246
        return (0);
 
247
}
 
248
 
 
249
void
 
250
waitForServer( struct display *d )
 
251
{
 
252
        volatile int i;
 
253
        /* static int i; */
 
254
 
 
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
 
265
                        {
 
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 */
 
273
                        }
 
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;
 
286
                        }
 
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;
 
293
                }
 
294
        } while (++i < d->openRepeat);
 
295
        logError( "Cannot connect to %s, giving up\n", d->name );
 
296
        exit( EX_OPENFAILED_DPY );
 
297
}
 
298
 
 
299
 
 
300
void
 
301
resetServer( struct display *d )
 
302
{
 
303
        if (dpy && (d->displayType & d_origin) != dFromXDMCP)
 
304
                pseudoReset();
 
305
}
 
306
 
 
307
 
 
308
static Jmp_buf pingTime;
 
309
 
 
310
static void
 
311
pingLost( void )
 
312
{
 
313
        Longjmp( pingTime, 1 );
 
314
}
 
315
 
 
316
/* ARGSUSED */
 
317
static int
 
318
pingLostIOErr( Display *dspl ATTR_UNUSED )
 
319
{
 
320
        pingLost();
 
321
        return 0;
 
322
}
 
323
 
 
324
/* ARGSUSED */
 
325
static void
 
326
pingLostSig( int n ATTR_UNUSED )
 
327
{
 
328
        pingLost();
 
329
}
 
330
 
 
331
int
 
332
pingServer( struct display *d )
 
333
{
 
334
        int (*oldError)( Display * );
 
335
        void (*oldSig)( int );
 
336
        int oldAlarm;
 
337
 
 
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 0;
 
351
        }
 
352
        (void)alarm( 0 );
 
353
        (void)Signal( SIGALRM, oldSig );
 
354
        (void)alarm( oldAlarm );
 
355
        debug( "X server alive\n" );
 
356
        XSetIOErrorHandler( oldError );
 
357
        return 1;
 
358
}