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

« back to all changes in this revision

Viewing changes to kdm/backend/dm.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 2000-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
 * display manager
 
35
 */
 
36
 
 
37
#include "dm.h"
 
38
#include "dm_auth.h"
 
39
#include "dm_error.h"
 
40
 
 
41
#include <stdio.h>
 
42
#include <string.h>
 
43
#include <unistd.h>
 
44
#include <stdarg.h>
 
45
#include <signal.h>
 
46
#include <sys/stat.h>
 
47
 
 
48
#ifdef HAVE_VTS
 
49
# include <sys/ioctl.h>
 
50
# include <sys/vt.h>
 
51
#endif
 
52
 
 
53
static void sigHandler( int n );
 
54
static int scanConfigs( int force );
 
55
static void startDisplays( void );
 
56
#define XS_KEEP 0
 
57
#define XS_RESTART 1
 
58
#define XS_RETRY 2
 
59
static void exitDisplay( struct display *d, int endState, int serverCmd, int goodExit );
 
60
static void rStopDisplay( struct display *d, int endState );
 
61
static void mainLoop( void );
 
62
 
 
63
static int signalFds[2];
 
64
 
 
65
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
 
66
static char *title;
 
67
static int titleLen;
 
68
#endif
 
69
 
 
70
static int storePid( void );
 
71
 
 
72
static int stopping;
 
73
SdRec sdRec = { 0, 0, 0, TO_INF, TO_INF, 0, 0, 0 };
 
74
 
 
75
time_t now;
 
76
 
 
77
char *prog, *progpath;
 
78
 
 
79
int
 
80
main( int argc, char **argv )
 
81
{
 
82
        int oldpid, oldumask, fd, noDaemonMode;
 
83
        char *pt, *errorLogFile, **opts;
 
84
 
 
85
        /* make sure at least world write access is disabled */
 
86
        if (((oldumask = umask( 022 )) & 002) == 002)
 
87
                (void)umask( oldumask );
 
88
 
 
89
        /* give /dev/null as stdin */
 
90
        if ((fd = open( "/dev/null", O_RDONLY )) > 0) {
 
91
                dup2( fd, 0 );
 
92
                close( fd );
 
93
        }
 
94
        if (fcntl( 1, F_GETFD ) < 0)
 
95
                dup2( 0, 1 );
 
96
        if (fcntl( 2, F_GETFD ) < 0)
 
97
                dup2( 0, 2 );
 
98
 
 
99
        if (argv[0][0] == '/') {
 
100
                if (!strDup( &progpath, argv[0] ))
 
101
                        panic( "Out of memory" );
 
102
        } else
 
103
#ifdef __linux__
 
104
        {
 
105
                /* note that this will resolve symlinks ... */
 
106
                int len;
 
107
                char fullpath[PATH_MAX];
 
108
                if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0)
 
109
                        panic( "Invoke with full path specification or mount /proc" );
 
110
                if (!strNDup( &progpath, fullpath, len ))
 
111
                        panic( "Out of memory" );
 
112
        }
 
113
#else
 
114
# if 0
 
115
                panic( "Must be invoked with full path specification" );
 
116
# else
 
117
        {
 
118
                char directory[PATH_MAX+1];
 
119
                if (!getcwd( directory, sizeof(directory) ))
 
120
                        panic( "Can't find myself (getcwd failed)" );
 
121
                if (strchr( argv[0], '/' ))
 
122
                        strApp( &progpath, directory, "/", argv[0], (char *)0 );
 
123
                else {
 
124
                        int len;
 
125
                        char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
 
126
 
 
127
                        if (!(path = getenv( "PATH" )))
 
128
                                panic( "Can't find myself (no PATH)" );
 
129
                        len = strlen( argv[0] );
 
130
                        name = nambuf + PATH_MAX - len;
 
131
                        memcpy( name, argv[0], len + 1 );
 
132
                        *--name = '/';
 
133
                        do {
 
134
                                if (!(pathe = strchr( path, ':' )))
 
135
                                        pathe = path + strlen( path );
 
136
                                len = pathe - path;
 
137
                                if (!len || (len == 1 && *path == '.')) {
 
138
                                        len = strlen( directory );
 
139
                                        path = directory;
 
140
                                }
 
141
                                thenam = name - len;
 
142
                                if (thenam >= nambuf) {
 
143
                                        memcpy( thenam, path, len );
 
144
                                        if (!access( thenam, X_OK ))
 
145
                                                goto found;
 
146
                                }
 
147
                                path = pathe;
 
148
                        } while (*path++ != '\0');
 
149
                        panic( "Can't find myself (not in PATH)" );
 
150
                  found:
 
151
                        if (!strDup( &progpath, thenam ))
 
152
                                panic( "Out of memory" );
 
153
                }
 
154
        }
 
155
# endif
 
156
#endif
 
157
        prog = strrchr( progpath, '/' ) + 1;
 
158
 
 
159
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
 
160
        title = argv[0];
 
161
        titleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - title;
 
162
#endif
 
163
 
 
164
        /*
 
165
         * Parse command line options
 
166
         */
 
167
        noDaemonMode = getppid();
 
168
        errorLogFile = 0;
 
169
        if (!(opts = Malloc( 2 * sizeof(char *) )))
 
170
                return 1;
 
171
        opts[0] = (char *)"";
 
172
        opts[1] = 0;
 
173
        while (*++argv) {
 
174
                if (**argv != '-')
 
175
                        break;
 
176
                pt = *argv + 1;
 
177
                if (*pt == '-')
 
178
                        pt++;
 
179
                if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) {
 
180
                        printf( "Usage: %s [options] [tty]\n"
 
181
"  -daemon\t  - Daemonize even when started by init\n"
 
182
"  -nodaemon\t  - Don't daemonize even when started from command line\n"
 
183
"  -config <file>  - Use alternative master configuration file\n"
 
184
"  -xrm <res>\t  - Override frontend-specific resource\n"
 
185
"  -error <file>\t  - Use alternative log file\n"
 
186
"  -debug <num>\t  - Debug option bitfield:\n"
 
187
"\t\t\t0x1 - core log\n"
 
188
"\t\t\t0x2 - config reader log\n"
 
189
"\t\t\t0x4 - greeter log\n"
 
190
"\t\t\t0x8 - IPC log\n"
 
191
"\t\t\t0x10 - session sub-daemon post-fork delay\n"
 
192
"\t\t\t0x20 - config reader post-start delay\n"
 
193
"\t\t\t0x40 - greeter post-start delay\n"
 
194
"\t\t\t0x80 - don't use syslog\n"
 
195
"\t\t\t0x100 - core Xauth log\n"
 
196
"\t\t\t0x200 - debug greeter theming\n"
 
197
"\t\t\t0x400 - valgrind config reader and greeter\n"
 
198
"\t\t\t0x800 - strace config reader and greeter\n"
 
199
                                , prog );
 
200
                        exit( 0 );
 
201
                } else if (!strcmp( pt, "daemon" ))
 
202
                        noDaemonMode = 0;
 
203
                else if (!strcmp( pt, "nodaemon" ))
 
204
                        noDaemonMode = 1;
 
205
                else if (argv[1] && !strcmp( pt, "config" ))
 
206
                        strDup( opts, *++argv );
 
207
                else if (argv[1] && !strcmp( pt, "xrm" ))
 
208
                        opts = addStrArr( opts, *++argv, -1 );
 
209
                else if (argv[1] && !strcmp( pt, "debug" ))
 
210
                        sscanf( *++argv, "%i", &debugLevel );
 
211
                else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" )))
 
212
                        errorLogFile = *++argv;
 
213
                else {
 
214
                        fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv );
 
215
                        exit( 1 );
 
216
                }
 
217
        }
 
218
 
 
219
        /*
 
220
         * Only allow root to run in non-debug mode to avoid problems
 
221
         */
 
222
        if (!debugLevel && getuid()) {
 
223
                fprintf( stderr, "Only root wants to run %s\n", prog );
 
224
                exit( 1 );
 
225
        }
 
226
 
 
227
        initErrorLog( errorLogFile );
 
228
 
 
229
        if (noDaemonMode != 1)
 
230
                becomeDaemon();
 
231
 
 
232
        /*
 
233
         * Step 1 - load configuration parameters
 
234
         */
 
235
        if (!initResources( opts ) || scanConfigs( FALSE ) < 0)
 
236
                logPanic( "Config reader failed. Aborting ...\n" );
 
237
 
 
238
        /* SUPPRESS 560 */
 
239
        if ((oldpid = storePid())) {
 
240
                if (oldpid == -1)
 
241
                        logError( "Can't create/lock pid file %s\n", pidFile );
 
242
                else
 
243
                        logError( "Can't lock pid file %s, another xdm is running (pid %d)\n",
 
244
                                  pidFile, oldpid );
 
245
                exit( 1 );
 
246
        }
 
247
 
 
248
#ifdef NEED_ENTROPY
 
249
        addOtherEntropy();
 
250
#endif
 
251
 
 
252
        /*
 
253
         * We used to clean up old authorization files here. As authDir is
 
254
         * supposed to be /var/run/xauth or /tmp, we needn't to care for it.
 
255
         */
 
256
 
 
257
#ifdef XDMCP
 
258
        init_session_id();
 
259
#else
 
260
        debug( "not compiled for XDMCP\n" );
 
261
#endif
 
262
        if (pipe( signalFds ))
 
263
                logPanic( "Unable to create signal notification pipe.\n" );
 
264
        registerInput( signalFds[0] );
 
265
        registerCloseOnFork( signalFds[0] );
 
266
        registerCloseOnFork( signalFds[1] );
 
267
        (void)Signal( SIGTERM, sigHandler );
 
268
        (void)Signal( SIGINT, sigHandler );
 
269
        (void)Signal( SIGHUP, sigHandler );
 
270
        (void)Signal( SIGCHLD, sigHandler );
 
271
        (void)Signal( SIGUSR1, sigHandler );
 
272
 
 
273
        /*
 
274
         * Step 2 - run a sub-daemon for each entry
 
275
         */
 
276
#ifdef XDMCP
 
277
        updateListenSockets();
 
278
#endif
 
279
        openCtrl( 0 );
 
280
        mainLoop();
 
281
        closeCtrl( 0 );
 
282
        if (sdRec.how) {
 
283
                int pid;
 
284
                commitBootOption();
 
285
                if (Fork( &pid ) <= 0) {
 
286
                        char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot;
 
287
                        execute( parseArgs( (char **)0, cmd ), (char **)0 );
 
288
                        logError( "Failed to execute shutdown command %\"s\n", cmd );
 
289
                        exit( 1 );
 
290
                } else {
 
291
                        sigset_t mask;
 
292
                        sigemptyset( &mask );
 
293
                        sigaddset( &mask, SIGCHLD );
 
294
                        sigaddset( &mask, SIGHUP );
 
295
                        sigsuspend( &mask );
 
296
                }
 
297
        }
 
298
        debug( "nothing left to do, exiting\n" );
 
299
        return 0;
 
300
}
 
301
 
 
302
 
 
303
#ifdef HAVE_VTS
 
304
int
 
305
TTYtoVT( const char *tty )
 
306
{
 
307
        return memcmp( tty, "tty", 3 ) ? 0 : atoi( tty + 3 );
 
308
}
 
309
 
 
310
int
 
311
activateVT( int vt )
 
312
{
 
313
        int ret = 0;
 
314
        int con = open( "/dev/console", O_RDONLY );
 
315
        if (con >= 0) {
 
316
                if (!ioctl( con, VT_ACTIVATE, vt ))
 
317
                        ret = 1;
 
318
                close( con );
 
319
        }
 
320
        return ret;
 
321
}
 
322
 
 
323
 
 
324
static void
 
325
wakeDisplay( struct display *d )
 
326
{
 
327
        if (d->status == textMode)
 
328
                d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
 
329
}
 
330
#endif
 
331
 
 
332
enum utState { UtDead, UtWait, UtActive };
 
333
 
 
334
struct utmps {
 
335
        struct utmps *next;
 
336
#ifndef HAVE_VTS
 
337
        struct display *d;
 
338
#endif
 
339
        time_t time;
 
340
        enum utState state;
 
341
        int hadSess;
 
342
};
 
343
 
 
344
#define TIME_LOG 40
 
345
#define TIME_RELOG 10
 
346
 
 
347
static struct utmps *utmpList;
 
348
static time_t utmpTimeout = TO_INF;
 
349
 
 
350
static void
 
351
bombUtmp( void )
 
352
{
 
353
        struct utmps *utp;
 
354
 
 
355
        while ((utp = utmpList)) {
 
356
#ifdef HAVE_VTS
 
357
                forEachDisplay( wakeDisplay );
 
358
#else
 
359
                utp->d->status = notRunning;
 
360
#endif
 
361
                utmpList = utp->next;
 
362
                free( utp );
 
363
        }
 
364
}
 
365
 
 
366
static void
 
367
checkUtmp( void )
 
368
{
 
369
        static time_t modtim;
 
370
        time_t nck;
 
371
        time_t ends;
 
372
        struct utmps *utp, **utpp;
 
373
        struct stat st;
 
374
#ifdef BSD_UTMP
 
375
        int fd;
 
376
        struct utmp ut[1];
 
377
#else
 
378
        STRUCTUTMP *ut;
 
379
#endif
 
380
 
 
381
        if (!utmpList)
 
382
                return;
 
383
        if (stat( UTMP_FILE, &st )) {
 
384
                logError( UTMP_FILE " not found - cannot use console mode\n" );
 
385
                bombUtmp();
 
386
                return;
 
387
        }
 
388
        if (modtim != st.st_mtime) {
 
389
                debug( "rescanning " UTMP_FILE "\n" );
 
390
                for (utp = utmpList; utp; utp = utp->next)
 
391
                        utp->state = UtDead;
 
392
#ifdef BSD_UTMP
 
393
                if ((fd = open( UTMP_FILE, O_RDONLY )) < 0) {
 
394
                        logError( "Cannot open " UTMP_FILE " - cannot use console mode\n" );
 
395
                        bombUtmp();
 
396
                        return;
 
397
                }
 
398
                while (reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0]))
 
399
#else
 
400
                SETUTENT();
 
401
                while ((ut = GETUTENT()))
 
402
#endif
 
403
                {
 
404
                        for (utp = utmpList; utp; utp = utp->next) {
 
405
#ifdef HAVE_VTS
 
406
                                char **line;
 
407
                                for (line = consoleTTYs; *line; line++)
 
408
                                        if (!strncmp( *line, ut->ut_line, sizeof(ut->ut_line) ))
 
409
                                                goto hitlin;
 
410
                                continue;
 
411
                          hitlin:
 
412
#else
 
413
                                if (strncmp( utp->d->console, ut->ut_line, sizeof(ut->ut_line) ))
 
414
                                        continue;
 
415
#endif
 
416
#ifdef BSD_UTMP
 
417
                                if (!*ut->ut_user) {
 
418
#else
 
419
                                if (ut->ut_type != USER_PROCESS) {
 
420
#endif
 
421
#ifdef HAVE_VTS
 
422
                                        if (utp->state == UtActive)
 
423
                                                break;
 
424
#endif
 
425
                                        utp->state = UtWait;
 
426
                                } else {
 
427
                                        utp->hadSess = 1;
 
428
                                        utp->state = UtActive;
 
429
                                }
 
430
                                if (utp->time < ut->ut_time) /* theoretically superfluous */
 
431
                                        utp->time = ut->ut_time;
 
432
                                break;
 
433
                        }
 
434
                }
 
435
#ifdef BSD_UTMP
 
436
                close( fd );
 
437
#else
 
438
                ENDUTENT();
 
439
#endif
 
440
                modtim = st.st_mtime;
 
441
        }
 
442
        for (utpp = &utmpList; (utp = *utpp); ) {
 
443
                if (utp->state != UtActive) {
 
444
                        if (utp->state == UtDead) /* shouldn't happen ... */
 
445
                                utp->time = 0;
 
446
                        ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
 
447
                        if (ends <= now) {
 
448
#ifdef HAVE_VTS
 
449
                                forEachDisplay( wakeDisplay );
 
450
                                debug( "console login timed out\n" );
 
451
#else
 
452
                                utp->d->status = notRunning;
 
453
                                debug( "console login for %s at %s timed out\n",
 
454
                                       utp->d->name, utp->d->console );
 
455
#endif
 
456
                                *utpp = utp->next;
 
457
                                free( utp );
 
458
                                continue;
 
459
                        } else
 
460
                                nck = ends;
 
461
                } else
 
462
                        nck = TIME_RELOG + now;
 
463
                if (nck < utmpTimeout)
 
464
                        utmpTimeout = nck;
 
465
                utpp = &(*utpp)->next;
 
466
        }
 
467
}
 
468
 
 
469
static void
 
470
#ifdef HAVE_VTS
 
471
switchToTTY( void )
 
472
#else
 
473
switchToTTY( struct display *d )
 
474
#endif
 
475
{
 
476
        struct utmps *utp;
 
477
#ifdef HAVE_VTS
 
478
        int vt;
 
479
#endif
 
480
 
 
481
        if (!(utp = Malloc( sizeof(*utp) ))) {
 
482
#ifdef HAVE_VTS
 
483
                forEachDisplay( wakeDisplay );
 
484
#else
 
485
                d->status = notRunning;
 
486
#endif
 
487
                return;
 
488
        }
 
489
#ifndef HAVE_VTS
 
490
        d->status = textMode;
 
491
        utp->d = d;
 
492
#endif
 
493
        utp->time = now;
 
494
        utp->hadSess = 0;
 
495
        utp->next = utmpList;
 
496
        utmpList = utp;
 
497
        checkUtmp();
 
498
 
 
499
#ifdef HAVE_VTS
 
500
        if ((vt = TTYtoVT( *consoleTTYs )))
 
501
                activateVT( vt );
 
502
#endif
 
503
 
 
504
        /* XXX output something useful here */
 
505
}
 
506
 
 
507
#ifdef HAVE_VTS
 
508
static void
 
509
stopToTTY( struct display *d )
 
510
{
 
511
        if ((d->displayType & d_location) == dLocal)
 
512
                switch (d->status) {
 
513
                default:
 
514
                        rStopDisplay( d, DS_TEXTMODE | 0x100 );
 
515
                case reserve:
 
516
                case textMode:
 
517
                        break;
 
518
                }
 
519
}
 
520
 
 
521
static void
 
522
checkTTYMode( void )
 
523
{
 
524
        struct display *d;
 
525
 
 
526
        for (d = displays; d; d = d->next)
 
527
                if (d->status == zombie)
 
528
                        return;
 
529
 
 
530
        switchToTTY();
 
531
}
 
532
 
 
533
#else
 
534
 
 
535
void
 
536
switchToX( struct display *d )
 
537
{
 
538
        struct utmps *utp, **utpp;
 
539
 
 
540
        for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
 
541
                if (utp->d == d) {
 
542
                        *utpp = utp->next;
 
543
                        free( utp );
 
544
                        d->status = notRunning;
 
545
                        return;
 
546
                }
 
547
}
 
548
#endif
 
549
 
 
550
#ifdef XDMCP
 
551
static void
 
552
startRemoteLogin( struct display *d )
 
553
{
 
554
        char **argv;
 
555
 
 
556
        debug( "startRemoteLogin for %s\n", d->name );
 
557
        /* HACK: omitting loadDisplayResources( d ) here! */
 
558
        switch (Fork( &d->serverPid )) {
 
559
        case 0:
 
560
                argv = prepareServerArgv( d, d->serverArgsRemote );
 
561
                if (!(argv = addStrArr( argv, "-once", 5 )) ||
 
562
                    !(argv = addStrArr( argv, "-query", 6 )) ||
 
563
                    !(argv = addStrArr( argv, d->remoteHost, -1 )))
 
564
                        exit( 1 );
 
565
                debug( "exec %\"[s\n", argv );
 
566
                (void)execv( argv[0], argv );
 
567
                logError( "X server %\"s cannot be executed\n", argv[0] );
 
568
                exit( 1 );
 
569
        case -1:
 
570
                logError( "Forking X server for remote login failed: %m" );
 
571
                d->status = notRunning;
 
572
                return;
 
573
        default:
 
574
                break;
 
575
        }
 
576
        debug( "X server forked, pid %d\n", d->serverPid );
 
577
 
 
578
        d->status = remoteLogin;
 
579
}
 
580
#endif
 
581
 
 
582
 
 
583
static void
 
584
stopInactiveDisplay( struct display *d )
 
585
{
 
586
        if (d->status != remoteLogin && d->userSess < 0)
 
587
                stopDisplay( d );
 
588
}
 
589
 
 
590
static void
 
591
stoppen( int force )
 
592
{
 
593
#ifdef XDMCP
 
594
        requestPort = 0;
 
595
        updateListenSockets();
 
596
#endif
 
597
        if (force)
 
598
                forEachDisplay( stopDisplay );
 
599
        else
 
600
                forEachDisplay( stopInactiveDisplay );
 
601
        stopping = 1;
 
602
}
 
603
 
 
604
 
 
605
void
 
606
setNLogin( struct display *d,
 
607
           const char *nuser, const char *npass, char *nargs, int rl )
 
608
{
 
609
        struct disphist *he = d->hstent;
 
610
        he->rLogin =
 
611
                (reStr( &he->nuser, nuser ) &&
 
612
                 reStr( &he->npass, npass ) &&
 
613
                 reStr( &he->nargs, nargs )) ? rl : 0;
 
614
        debug( "set next login for %s, level %d\n", nuser, rl );
 
615
}
 
616
 
 
617
static void
 
618
processDPipe( struct display *d )
 
619
{
 
620
        char *user, *pass, *args;
 
621
        int cmd;
 
622
        GTalk dpytalk;
 
623
#ifdef XDMCP
 
624
        int ct, len;
 
625
        ARRAY8 ca, ha;
 
626
#endif
 
627
 
 
628
        dpytalk.pipe = &d->pipe;
 
629
        if (Setjmp( dpytalk.errjmp )) {
 
630
                stopDisplay( d );
 
631
                return;
 
632
        }
 
633
        gSet( &dpytalk );
 
634
        if (!gRecvCmd( &cmd )) {
 
635
                /* process already exited */
 
636
                unregisterInput( d->pipe.fd.r );
 
637
                return;
 
638
        }
 
639
        switch (cmd) {
 
640
        case D_User:
 
641
                d->userSess = gRecvInt();
 
642
                d->userName = gRecvStr();
 
643
                d->sessName = gRecvStr();
 
644
                break;
 
645
        case D_ReLogin:
 
646
                user = gRecvStr();
 
647
                pass = gRecvStr();
 
648
                args = gRecvStr();
 
649
                setNLogin( d, user, pass, args, 1 );
 
650
                free( args );
 
651
                free( pass );
 
652
                free( user );
 
653
                break;
 
654
#ifdef XDMCP
 
655
        case D_ChooseHost:
 
656
                ca.data = (unsigned char *)gRecvArr( &len );
 
657
                ca.length = (CARD16)len;
 
658
                ct = gRecvInt();
 
659
                ha.data = (unsigned char *)gRecvArr( &len );
 
660
                ha.length = (CARD16)len;
 
661
                registerindirectChoice( &ca, ct, &ha );
 
662
                XdmcpDisposeARRAY8( &ha );
 
663
                XdmcpDisposeARRAY8( &ca );
 
664
                break;
 
665
        case D_RemoteHost:
 
666
                if (d->remoteHost)
 
667
                        free( d->remoteHost );
 
668
                d->remoteHost = gRecvStr();
 
669
                break;
 
670
#endif
 
671
        case D_XConnOk:
 
672
                startingServer = 0;
 
673
                break;
 
674
        default:
 
675
                logError( "Internal error: unknown D_* command %d\n", cmd );
 
676
                stopDisplay( d );
 
677
                break;
 
678
        }
 
679
}
 
680
 
 
681
static void
 
682
emitXSessG( struct display *di, struct display *d, void *ctx ATTR_UNUSED )
 
683
{
 
684
        gSendStr( di->name );
 
685
        gSendStr( "" );
 
686
#ifdef HAVE_VTS
 
687
        gSendInt( di->serverVT );
 
688
#endif
 
689
#ifdef XDMCP
 
690
        if (di->status == remoteLogin) {
 
691
                gSendStr( "" );
 
692
                gSendStr( di->remoteHost );
 
693
        } else
 
694
#endif
 
695
        {
 
696
                gSendStr( di->userName );
 
697
                gSendStr( di->sessName );
 
698
        }
 
699
        gSendInt( di == d ? isSelf : 0 );
 
700
}
 
701
 
 
702
static void
 
703
emitTTYSessG( STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED )
 
704
{
 
705
        gSendStrN( ut->ut_line, sizeof(ut->ut_line) );
 
706
        gSendStrN( ut->ut_host, sizeof(ut->ut_host) );
 
707
#ifdef HAVE_VTS
 
708
        gSendInt( TTYtoVT( ut->ut_line ) );
 
709
#endif
 
710
#ifdef BSD_UTMP
 
711
        gSendStrN( *ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user) );
 
712
#else
 
713
        gSendStrN( ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user) );
 
714
#endif
 
715
        gSendStr( 0 ); /* session type unknown */
 
716
        gSendInt( isTTY );
 
717
}
 
718
 
 
719
static void
 
720
processGPipe( struct display *d )
 
721
{
 
722
        char **opts, *option;
 
723
        int cmd, ret, dflt, curr;
 
724
        GTalk dpytalk;
 
725
 
 
726
        dpytalk.pipe = &d->gpipe;
 
727
        if (Setjmp( dpytalk.errjmp )) {
 
728
                stopDisplay( d );
 
729
                return;
 
730
        }
 
731
        gSet( &dpytalk );
 
732
        if (!gRecvCmd( &cmd )) {
 
733
                /* process already exited */
 
734
                unregisterInput( d->gpipe.fd.r );
 
735
                return;
 
736
        }
 
737
        switch (cmd) {
 
738
        case G_ListBootOpts:
 
739
                ret = getBootOptions( &opts, &dflt, &curr );
 
740
                gSendInt( ret );
 
741
                if (ret == BO_OK) {
 
742
                        gSendArgv( opts );
 
743
                        freeStrArr( opts );
 
744
                        gSendInt( dflt );
 
745
                        gSendInt( curr );
 
746
                }
 
747
                break;
 
748
        case G_Shutdown:
 
749
                sdRec.how = gRecvInt();
 
750
                sdRec.start = gRecvInt();
 
751
                sdRec.timeout = gRecvInt();
 
752
                sdRec.force = gRecvInt();
 
753
                sdRec.uid = gRecvInt();
 
754
                option = gRecvStr();
 
755
                setBootOption( option, &sdRec );
 
756
                if (option)
 
757
                        free( option );
 
758
                break;
 
759
        case G_QueryShutdown:
 
760
                gSendInt( sdRec.how );
 
761
                gSendInt( sdRec.start );
 
762
                gSendInt( sdRec.timeout );
 
763
                gSendInt( sdRec.force );
 
764
                gSendInt( sdRec.uid );
 
765
                gSendStr( sdRec.osname );
 
766
                break;
 
767
        case G_List:
 
768
                listSessions( gRecvInt(), d, 0, emitXSessG, emitTTYSessG );
 
769
                gSendInt( 0 );
 
770
                break;
 
771
#ifdef HAVE_VTS
 
772
        case G_Activate:
 
773
                activateVT( gRecvInt() );
 
774
                break;
 
775
#endif
 
776
        case G_Console:
 
777
#ifdef HAVE_VTS
 
778
                if (*consoleTTYs) { /* sanity check against greeter */
 
779
                        forEachDisplay( stopToTTY );
 
780
                        checkTTYMode();
 
781
                }
 
782
#else
 
783
                if (*d->console) /* sanity check against greeter */
 
784
                        rStopDisplay( d, DS_TEXTMODE );
 
785
#endif
 
786
                break;
 
787
        default:
 
788
                logError( "Internal error: unknown G_* command %d\n", cmd );
 
789
                stopDisplay( d );
 
790
                break;
 
791
        }
 
792
}
 
793
 
 
794
 
 
795
static int
 
796
scanConfigs( int force )
 
797
{
 
798
        int ret;
 
799
 
 
800
        if ((ret = loadDMResources( force )) <= 0)
 
801
                return ret;
 
802
        scanServers();
 
803
#ifdef XDMCP
 
804
        scanAccessDatabase( force );
 
805
#endif
 
806
        return 1;
 
807
}
 
808
 
 
809
static void
 
810
markDisplay( struct display *d )
 
811
{
 
812
        d->stillThere = 0;
 
813
}
 
814
 
 
815
static void
 
816
rescanConfigs( int force )
 
817
{
 
818
        if (scanConfigs( force ) > 0) {
 
819
#ifdef XDMCP
 
820
                updateListenSockets();
 
821
#endif
 
822
                updateCtrl();
 
823
        }
 
824
}
 
825
 
 
826
void
 
827
cancelShutdown( void )
 
828
{
 
829
        sdRec.how = 0;
 
830
        if (sdRec.osname) {
 
831
                free( sdRec.osname );
 
832
                sdRec.osname = 0;
 
833
        }
 
834
        stopping = 0;
 
835
        rescanConfigs( TRUE );
 
836
}
 
837
 
 
838
 
 
839
static void
 
840
reapChildren( void )
 
841
{
 
842
        int pid;
 
843
        struct display *d;
 
844
        int status;
 
845
 
 
846
        while ((pid = waitpid( -1, &status, WNOHANG )) > 0)
 
847
        {
 
848
                debug( "manager wait returns  pid %d  sig %d  core %d  code %d\n",
 
849
                       pid, waitSig( status ), waitCore( status ), waitCode( status ) );
 
850
                /* SUPPRESS 560 */
 
851
                if ((d = findDisplayByPid( pid ))) {
 
852
                        d->pid = -1;
 
853
                        unregisterInput( d->pipe.fd.r );
 
854
                        gClosen( &d->pipe );
 
855
                        unregisterInput( d->gpipe.fd.r );
 
856
                        gClosen( &d->gpipe );
 
857
                        closeCtrl( d );
 
858
                        switch (wcFromWait( status )) {
 
859
#ifdef XDMCP
 
860
                        case EX_REMOTE:
 
861
                                debug( "display exited with EX_REMOTE\n" );
 
862
                                exitDisplay( d, DS_REMOTE, 0, 0 );
 
863
                                break;
 
864
#endif
 
865
                        case EX_NORMAL:
 
866
                                /* (any type of) session ended */
 
867
                                debug( "display exited with EX_NORMAL\n" );
 
868
                                if ((d->displayType & d_lifetime) == dReserve)
 
869
                                        exitDisplay( d, DS_RESERVE, 0, 0 );
 
870
                                else
 
871
                                        exitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
 
872
                                break;
 
873
                        case EX_RESERVE:
 
874
                                debug( "display exited with EX_RESERVE\n" );
 
875
                                exitDisplay( d, DS_RESERVE, 0, 0 );
 
876
                                break;
 
877
#if 0
 
878
                        case EX_REMANAGE_DPY:
 
879
                                /* user session ended */
 
880
                                debug( "display exited with EX_REMANAGE_DPY\n" );
 
881
                                exitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
 
882
                                break;
 
883
#endif
 
884
                        case EX_OPENFAILED_DPY:
 
885
                                /* waitForServer() failed */
 
886
                                logError( "Display %s cannot be opened\n", d->name );
 
887
#ifdef XDMCP
 
888
                                /*
 
889
                                 * no display connection was ever made, tell the
 
890
                                 * terminal that the open attempt failed
 
891
                                 */
 
892
                                if ((d->displayType & d_origin) == dFromXDMCP)
 
893
                                        sendFailed( d, "cannot open display" );
 
894
#endif
 
895
                                exitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
 
896
                                break;
 
897
                        case wcCompose( SIGTERM,0,0 ):
 
898
                                /* killed before/during waitForServer()
 
899
                                   - local Xserver died
 
900
                                   - display stopped (is zombie)
 
901
                                   - "login now" and "suicide" pipe commands (is raiser)
 
902
                                */
 
903
                                debug( "display exited on SIGTERM\n" );
 
904
                                exitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
 
905
                                break;
 
906
                        case EX_AL_RESERVER_DPY:
 
907
                                /* - killed after waitForServer()
 
908
                                   - Xserver dead after remote session exit
 
909
                                */
 
910
                                debug( "display exited with EX_AL_RESERVER_DPY\n" );
 
911
                                exitDisplay( d, DS_RESTART, XS_RESTART, FALSE );
 
912
                                break;
 
913
                        case EX_RESERVER_DPY:
 
914
                                /* induced by greeter:
 
915
                                   - could not secure display
 
916
                                   - requested by user
 
917
                                */
 
918
                                debug( "display exited with EX_RESERVER_DPY\n" );
 
919
                                exitDisplay( d, DS_RESTART, XS_RESTART, TRUE );
 
920
                                break;
 
921
                        case EX_UNMANAGE_DPY:
 
922
                                /* some fatal error */
 
923
                                debug( "display exited with EX_UNMANAGE_DPY\n" );
 
924
                                exitDisplay( d, DS_REMOVE, 0, 0 );
 
925
                                break;
 
926
                        default:
 
927
                                /* prolly crash */
 
928
                                logError( "Unknown session exit code %d (sig %d) from manager process\n",
 
929
                                          waitCode( status ), waitSig( status ) );
 
930
                                exitDisplay( d, DS_REMOVE, 0, 0 );
 
931
                                break;
 
932
                        }
 
933
                } else if ((d = findDisplayByServerPid( pid ))) {
 
934
                        d->serverPid = -1;
 
935
                        switch (d->status) {
 
936
                        case zombie:
 
937
                                debug( "zombie X server for display %s reaped\n", d->name );
 
938
#ifdef HAVE_VTS
 
939
                                if (d->serverVT && d->zstatus != DS_REMOTE) {
 
940
                                        if (d->follower) {
 
941
                                                d->follower->serverVT = d->serverVT;
 
942
                                                d->follower = 0;
 
943
                                        } else {
 
944
                                                int con = open( "/dev/console", O_RDONLY );
 
945
                                                if (con >= 0) {
 
946
                                                        struct vt_stat vtstat;
 
947
                                                        ioctl( con, VT_GETSTATE, &vtstat );
 
948
                                                        if (vtstat.v_active == d->serverVT) {
 
949
                                                                int vt = 1;
 
950
                                                                struct display *di;
 
951
                                                                for (di = displays; di; di = di->next)
 
952
                                                                        if (di != d && di->serverVT)
 
953
                                                                                vt = di->serverVT;
 
954
                                                                for (di = displays; di; di = di->next)
 
955
                                                                        if (di != d && di->serverVT &&
 
956
                                                                            (di->userSess >= 0 ||
 
957
                                                                             di->status == remoteLogin))
 
958
                                                                                vt = di->serverVT;
 
959
                                                                ioctl( con, VT_ACTIVATE, vt );
 
960
                                                        }
 
961
                                                        ioctl( con, VT_DISALLOCATE, d->serverVT );
 
962
                                                        close( con );
 
963
                                                }
 
964
                                        }
 
965
                                        d->serverVT = 0;
 
966
                                }
 
967
#endif
 
968
                                rStopDisplay( d, d->zstatus );
 
969
                                break;
 
970
                        case phoenix:
 
971
                                debug( "phoenix X server arises, restarting display %s\n",
 
972
                                       d->name );
 
973
                                d->status = notRunning;
 
974
                                break;
 
975
                        case remoteLogin:
 
976
                                debug( "remote login X server for display %s exited\n",
 
977
                                       d->name );
 
978
                                d->status = ((d->displayType & d_lifetime) == dReserve) ?
 
979
                                            reserve : notRunning;
 
980
                                break;
 
981
                        case raiser:
 
982
                                logError( "X server for display %s terminated unexpectedly\n",
 
983
                                          d->name );
 
984
                                /* don't kill again */
 
985
                                break;
 
986
                        case running:
 
987
                                if (startingServer == d && d->serverStatus != ignore) {
 
988
                                        if (d->serverStatus == starting && waitCode( status ) != 47)
 
989
                                                logError( "X server died during startup\n" );
 
990
                                        startServerFailed();
 
991
                                        break;
 
992
                                }
 
993
                                logError( "X server for display %s terminated unexpectedly\n",
 
994
                                          d->name );
 
995
                                if (d->pid != -1) {
 
996
                                        debug( "terminating session pid %d\n", d->pid );
 
997
                                        terminateProcess( d->pid, SIGTERM );
 
998
                                }
 
999
                                break;
 
1000
                        case notRunning:
 
1001
                        case textMode:
 
1002
                        case reserve:
 
1003
                                /* this cannot happen */
 
1004
                                debug( "X server exited for passive (%d) session on display %s\n",
 
1005
                                       (int)d->status, d->name );
 
1006
                                break;
 
1007
                        }
 
1008
                } else
 
1009
                        debug( "unknown child termination\n" );
 
1010
        }
 
1011
#ifdef NEED_ENTROPY
 
1012
        addOtherEntropy();
 
1013
#endif
 
1014
}
 
1015
 
 
1016
static int
 
1017
wouldShutdown( void )
 
1018
{
 
1019
        struct display *d;
 
1020
 
 
1021
        if (sdRec.force != SHUT_CANCEL) {
 
1022
                if (sdRec.force == SHUT_FORCEMY)
 
1023
                        for (d = displays; d; d = d->next)
 
1024
                                if (d->status == remoteLogin ||
 
1025
                                    (d->userSess >= 0 && d->userSess != sdRec.uid))
 
1026
                                        return 0;
 
1027
                return 1;
 
1028
        }
 
1029
        return !anyActiveDisplays();
 
1030
}
 
1031
 
 
1032
fd_set wellKnownSocketsMask;
 
1033
int wellKnownSocketsMax;
 
1034
int wellKnownSocketsCount;
 
1035
 
 
1036
void
 
1037
registerInput( int fd )
 
1038
{
 
1039
        /* can be omited, as it is always called right after opening a socket
 
1040
        if (!FD_ISSET( fd, &wellKnownSocketsMask ))
 
1041
        */
 
1042
        {
 
1043
                FD_SET( fd, &wellKnownSocketsMask );
 
1044
                if (fd > wellKnownSocketsMax)
 
1045
                        wellKnownSocketsMax = fd;
 
1046
                wellKnownSocketsCount++;
 
1047
        }
 
1048
}
 
1049
 
 
1050
void
 
1051
unregisterInput( int fd )
 
1052
{
 
1053
        /* the check _is_ necessary, as some handles are unregistered before
 
1054
           the regular close sequence.
 
1055
        */
 
1056
        if (FD_ISSET( fd, &wellKnownSocketsMask )) {
 
1057
                FD_CLR( fd, &wellKnownSocketsMask );
 
1058
                wellKnownSocketsCount--;
 
1059
        }
 
1060
}
 
1061
 
 
1062
static void
 
1063
sigHandler( int n )
 
1064
{
 
1065
        int olderrno = errno;
 
1066
        char buf = (char)n;
 
1067
        /* debug( "caught signal %d\n", n ); this hangs in syslog() */
 
1068
        write( signalFds[1], &buf, 1 );
 
1069
#ifdef __EMX__
 
1070
        (void)Signal( n, sigHandler );
 
1071
#endif
 
1072
        errno = olderrno;
 
1073
}
 
1074
 
 
1075
static void
 
1076
mainLoop( void )
 
1077
{
 
1078
        struct display *d;
 
1079
        struct timeval *tvp, tv;
 
1080
        time_t to;
 
1081
        int nready;
 
1082
        char buf;
 
1083
        fd_set reads;
 
1084
 
 
1085
        debug( "mainLoop\n" );
 
1086
        time( &now );
 
1087
        while (
 
1088
#ifdef XDMCP
 
1089
               anyListenSockets() ||
 
1090
#endif
 
1091
                   (stopping ? anyRunningDisplays() : anyDisplaysLeft()))
 
1092
        {
 
1093
                if (!stopping)
 
1094
                        startDisplays();
 
1095
                to = TO_INF;
 
1096
                if (sdRec.how) {
 
1097
                        if (sdRec.start != TO_INF && now < sdRec.start) {
 
1098
                                /*if (sdRec.start < to)*/
 
1099
                                        to = sdRec.start;
 
1100
                        } else {
 
1101
                                sdRec.start = TO_INF;
 
1102
                                if (now >= sdRec.timeout) {
 
1103
                                        sdRec.timeout = TO_INF;
 
1104
                                        if (wouldShutdown())
 
1105
                                                stoppen( TRUE );
 
1106
                                        else
 
1107
                                                cancelShutdown();
 
1108
                                } else {
 
1109
                                        stoppen( FALSE );
 
1110
                                        /*if (sdRec.timeout < to)*/
 
1111
                                                to = sdRec.timeout;
 
1112
                                }
 
1113
                        }
 
1114
                }
 
1115
                if (serverTimeout < to)
 
1116
                        to = serverTimeout;
 
1117
                if (utmpTimeout < to)
 
1118
                        to = utmpTimeout;
 
1119
                if (to == TO_INF)
 
1120
                        tvp = 0;
 
1121
                else {
 
1122
                        to -= now;
 
1123
                        if (to < 0)
 
1124
                                to = 0;
 
1125
                        tv.tv_sec = to;
 
1126
                        tv.tv_usec = 0;
 
1127
                        tvp = &tv;
 
1128
                }
 
1129
                reads = wellKnownSocketsMask;
 
1130
                nready = select( wellKnownSocketsMax + 1, &reads, 0, 0, tvp );
 
1131
                debug( "select returns %d\n", nready );
 
1132
                time( &now );
 
1133
#ifdef NEED_ENTROPY
 
1134
                addTimerEntropy();
 
1135
#endif
 
1136
                if (now >= serverTimeout) {
 
1137
                        serverTimeout = TO_INF;
 
1138
                        startServerTimeout();
 
1139
                }
 
1140
                if (now >= utmpTimeout) {
 
1141
                        utmpTimeout = TO_INF;
 
1142
                        checkUtmp();
 
1143
                }
 
1144
                if (nready > 0) {
 
1145
                        /*
 
1146
                         * we restart after the first handled fd, as
 
1147
                         * a) it makes things simpler
 
1148
                         * b) the probability that multiple fds trigger at once is
 
1149
                         *    ridiculously small. we handle it in the next iteration.
 
1150
                         */
 
1151
                        /* XXX a cleaner solution would be a callback mechanism */
 
1152
                        if (FD_ISSET( signalFds[0], &reads )) {
 
1153
                                if (read( signalFds[0], &buf, 1 ) != 1)
 
1154
                                        logPanic( "Signal notification pipe broken.\n" );
 
1155
                                switch (buf) {
 
1156
                                case SIGTERM:
 
1157
                                case SIGINT:
 
1158
                                        debug( "shutting down entire manager\n" );
 
1159
                                        stoppen( TRUE );
 
1160
                                        break;
 
1161
                                case SIGHUP:
 
1162
                                        logInfo( "Rescanning all config files\n" );
 
1163
                                        forEachDisplay( markDisplay );
 
1164
                                        rescanConfigs( TRUE );
 
1165
                                        break;
 
1166
                                case SIGCHLD:
 
1167
                                        reapChildren();
 
1168
                                        if (!stopping && autoRescan)
 
1169
                                                rescanConfigs( FALSE );
 
1170
                                        break;
 
1171
                                case SIGUSR1:
 
1172
                                        if (startingServer &&
 
1173
                                            startingServer->serverStatus == starting)
 
1174
                                                startServerSuccess();
 
1175
                                        break;
 
1176
                                }
 
1177
                                continue;
 
1178
                        }
 
1179
#ifdef XDMCP
 
1180
                        if (processListenSockets( &reads ))
 
1181
                                continue;
 
1182
#endif  /* XDMCP */
 
1183
                        if (handleCtrl( &reads, 0 ))
 
1184
                                continue;
 
1185
                        /* Must be last (because of the breaks)! */
 
1186
                  again:
 
1187
                        for (d = displays; d; d = d->next) {
 
1188
                                if (handleCtrl( &reads, d ))
 
1189
                                        goto again;
 
1190
                                if (d->pipe.fd.r >= 0 && FD_ISSET( d->pipe.fd.r, &reads )) {
 
1191
                                        processDPipe( d );
 
1192
                                        break;
 
1193
                                }
 
1194
                                if (d->gpipe.fd.r >= 0 && FD_ISSET( d->gpipe.fd.r, &reads )) {
 
1195
                                        processGPipe( d );
 
1196
                                        break;
 
1197
                                }
 
1198
                        }
 
1199
                }
 
1200
        }
 
1201
}
 
1202
 
 
1203
static void
 
1204
checkDisplayStatus( struct display *d )
 
1205
{
 
1206
        if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
 
1207
                stopDisplay( d );
 
1208
        else if ((d->displayType & d_lifetime) == dReserve &&
 
1209
                 d->status == running && d->userSess < 0 && !d->idleTimeout)
 
1210
                rStopDisplay( d, DS_RESERVE );
 
1211
        else if (d->status == notRunning)
 
1212
                if (loadDisplayResources( d ) < 0) {
 
1213
                        logError( "Unable to read configuration for display %s; "
 
1214
                                  "stopping it.\n", d->name );
 
1215
                        stopDisplay( d );
 
1216
                        return;
 
1217
                }
 
1218
}
 
1219
 
 
1220
static void
 
1221
kickDisplay( struct display *d )
 
1222
{
 
1223
        if (d->status == notRunning)
 
1224
                startDisplay( d );
 
1225
        if (d->serverStatus == awaiting && !startingServer)
 
1226
                startServer( d );
 
1227
}
 
1228
 
 
1229
#ifdef HAVE_VTS
 
1230
static int activeVTs;
 
1231
 
 
1232
static int
 
1233
getBusyVTs( void )
 
1234
{
 
1235
        struct vt_stat vtstat;
 
1236
        int con;
 
1237
 
 
1238
        if (activeVTs == -1) {
 
1239
                vtstat.v_state = 0;
 
1240
                if ((con = open( "/dev/console", O_RDONLY )) >= 0) {
 
1241
                        ioctl( con, VT_GETSTATE, &vtstat );
 
1242
                        close( con );
 
1243
                }
 
1244
                activeVTs = vtstat.v_state;
 
1245
        }
 
1246
        return activeVTs;
 
1247
}
 
1248
 
 
1249
static void
 
1250
allocateVT( struct display *d )
 
1251
{
 
1252
        struct display *cd;
 
1253
        int i, tvt, volun;
 
1254
 
 
1255
        if ((d->displayType & d_location) == dLocal &&
 
1256
            d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
 
1257
        {
 
1258
                if (d->reqSrvVT && d->reqSrvVT < 16)
 
1259
                        d->serverVT = d->reqSrvVT;
 
1260
                else {
 
1261
                        for (i = tvt = 0;;) {
 
1262
                                if (serverVTs[i]) {
 
1263
                                        tvt = atoi( serverVTs[i++] );
 
1264
                                        volun = 0;
 
1265
                                        if (tvt < 0) {
 
1266
                                                tvt = -tvt;
 
1267
                                                volun = 1;
 
1268
                                        }
 
1269
                                        if (!tvt || tvt >= 16)
 
1270
                                                continue;
 
1271
                                } else {
 
1272
                                        if (++tvt >= 16)
 
1273
                                                break;
 
1274
                                        volun = 1;
 
1275
                                }
 
1276
                                for (cd = displays; cd; cd = cd->next) {
 
1277
                                        if (cd->reqSrvVT == tvt && /* protect from lusers */
 
1278
                                            (cd->status != zombie || cd->zstatus != DS_REMOVE))
 
1279
                                                goto next;
 
1280
                                        if (cd->serverVT == tvt) {
 
1281
                                                if (cd->status != zombie || cd->zstatus == DS_REMOTE)
 
1282
                                                        goto next;
 
1283
                                                if (!cd->follower) {
 
1284
                                                        d->serverVT = -1;
 
1285
                                                        cd->follower = d;
 
1286
                                                        return;
 
1287
                                                }
 
1288
                                        }
 
1289
                                }
 
1290
                                if (!volun || !((1 << tvt) & getBusyVTs())) {
 
1291
                                        d->serverVT = tvt;
 
1292
                                        return;
 
1293
                                }
 
1294
                  next: ;
 
1295
                        }
 
1296
                }
 
1297
        }
 
1298
}
 
1299
#endif
 
1300
 
 
1301
static void
 
1302
startDisplays( void )
 
1303
{
 
1304
        forEachDisplay( checkDisplayStatus );
 
1305
        closeGetter();
 
1306
#ifdef HAVE_VTS
 
1307
        activeVTs = -1;
 
1308
        forEachDisplayRev( allocateVT );
 
1309
#endif
 
1310
        forEachDisplay( kickDisplay );
 
1311
}
 
1312
 
 
1313
void
 
1314
startDisplay( struct display *d )
 
1315
{
 
1316
        if (stopping) {
 
1317
                debug( "stopping display %s because shutdown is scheduled\n", d->name );
 
1318
                stopDisplay( d );
 
1319
                return;
 
1320
        }
 
1321
 
 
1322
#ifdef HAVE_VTS
 
1323
        if (d->serverVT < 0)
 
1324
                return;
 
1325
#endif
 
1326
 
 
1327
        d->status = running;
 
1328
        if ((d->displayType & d_location) == dLocal) {
 
1329
                debug( "startDisplay %s\n", d->name );
 
1330
                /* don't bother pinging local displays; we'll
 
1331
                 * certainly notice when they exit
 
1332
                 */
 
1333
                d->pingInterval = 0;
 
1334
                if (d->authorize) {
 
1335
                        setLocalAuthorization( d );
 
1336
                        /*
 
1337
                         * reset the server after writing the authorization information
 
1338
                         * to make it read the file (for compatibility with old
 
1339
                         * servers which read auth file only on reset instead of
 
1340
                         * at first connection)
 
1341
                         */
 
1342
                        if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
 
1343
                                kill( d->serverPid, d->resetSignal );
 
1344
                }
 
1345
                if (d->serverPid == -1) {
 
1346
                        d->serverStatus = awaiting;
 
1347
                        return;
 
1348
                }
 
1349
        } else {
 
1350
                debug( "startDisplay %s, try %d\n", d->name, d->startTries + 1 );
 
1351
                /* this will only happen when using XDMCP */
 
1352
                if (d->authorizations)
 
1353
                        saveServerAuthorizations( d, d->authorizations, d->authNum );
 
1354
        }
 
1355
        startDisplayP2( d );
 
1356
}
 
1357
 
 
1358
void
 
1359
startDisplayP2( struct display *d )
 
1360
{
 
1361
        char *cname, *cgname;
 
1362
 
 
1363
        openCtrl( d );
 
1364
        debug( "forking session\n" );
 
1365
        ASPrintf( &cname, "sub-daemon for display %s", d->name );
 
1366
        ASPrintf( &cgname, "greeter for display %s", d->name );
 
1367
        switch (gFork( &d->pipe, "master daemon", cname,
 
1368
                       &d->gpipe, cgname, 0, &d->pid ))
 
1369
        {
 
1370
        case 0:
 
1371
#ifndef NOXDMTITLE
 
1372
                setproctitle( "%s", d->name );
 
1373
#endif
 
1374
                ASPrintf( &prog, "%s: %s", prog, d->name );
 
1375
                reInitErrorLog();
 
1376
                if (debugLevel & DEBUG_WSESS)
 
1377
                        sleep( 100 );
 
1378
                mstrtalk.pipe = &d->pipe;
 
1379
                (void)Signal( SIGPIPE, SIG_IGN );
 
1380
                setAuthorization( d );
 
1381
                waitForServer( d );
 
1382
                if ((d->displayType & d_location) == dLocal) {
 
1383
                        gSet( &mstrtalk );
 
1384
                        gSendInt( D_XConnOk );
 
1385
                }
 
1386
                manageSession( d );
 
1387
                /* NOTREACHED */
 
1388
        case -1:
 
1389
                closeCtrl( d );
 
1390
                d->status = notRunning;
 
1391
                break;
 
1392
        default:
 
1393
                debug( "forked session, pid %d\n", d->pid );
 
1394
 
 
1395
                /* (void) fcntl (d->pipe.fd.r, F_SETFL, O_NONBLOCK); */
 
1396
                /* (void) fcntl (d->gpipe.fd.r, F_SETFL, O_NONBLOCK); */
 
1397
                registerInput( d->pipe.fd.r );
 
1398
                registerInput( d->gpipe.fd.r );
 
1399
 
 
1400
                d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
 
1401
                        d->hstent->sdRec.how = 0;
 
1402
                d->lastStart = now;
 
1403
                break;
 
1404
        }
 
1405
}
 
1406
 
 
1407
/*
 
1408
 * transition from running to zombie, textmode, reserve or deleted
 
1409
 */
 
1410
 
 
1411
static void
 
1412
rStopDisplay( struct display *d, int endState )
 
1413
{
 
1414
        debug( "stopping display %s to state %d\n", d->name, endState );
 
1415
        abortStartServer( d );
 
1416
        d->idleTimeout = 0;
 
1417
        if (d->serverPid != -1 || d->pid != -1) {
 
1418
                if (d->pid != -1)
 
1419
                        terminateProcess( d->pid, SIGTERM );
 
1420
                if (d->serverPid != -1)
 
1421
                        terminateProcess( d->serverPid, d->termSignal );
 
1422
                d->status = zombie;
 
1423
                d->zstatus = endState & 0xff;
 
1424
                debug( " zombiefied\n" );
 
1425
        } else if (endState == DS_TEXTMODE) {
 
1426
#ifdef HAVE_VTS
 
1427
                d->status = textMode;
 
1428
                checkTTYMode();
 
1429
        } else if (endState == (DS_TEXTMODE | 0x100)) {
 
1430
                d->status = textMode;
 
1431
#else
 
1432
                switchToTTY( d );
 
1433
#endif
 
1434
        } else if (endState == DS_RESERVE)
 
1435
                d->status = reserve;
 
1436
#ifdef XDMCP
 
1437
        else if (endState == DS_REMOTE)
 
1438
                startRemoteLogin( d );
 
1439
#endif
 
1440
        else {
 
1441
#ifndef HAVE_VTS
 
1442
                switchToX( d );
 
1443
#endif
 
1444
                removeDisplay( d );
 
1445
        }
 
1446
}
 
1447
 
 
1448
void
 
1449
stopDisplay( struct display *d )
 
1450
{
 
1451
        rStopDisplay( d, DS_REMOVE );
 
1452
}
 
1453
 
 
1454
static void
 
1455
exitDisplay( struct display *d,
 
1456
             int endState,
 
1457
             int serverCmd,
 
1458
             int goodExit )
 
1459
{
 
1460
        struct disphist *he;
 
1461
 
 
1462
        if (d->status == raiser) {
 
1463
                serverCmd = XS_KEEP;
 
1464
                goodExit = TRUE;
 
1465
        }
 
1466
 
 
1467
        debug( "exitDisplay %s, "
 
1468
               "endState = %d, serverCmd = %d, GoodExit = %d\n",
 
1469
               d->name, endState, serverCmd, goodExit );
 
1470
 
 
1471
        d->userSess = -1;
 
1472
        if (d->userName)
 
1473
                free( d->userName );
 
1474
        d->userName = 0;
 
1475
        if (d->sessName)
 
1476
                free( d->sessName );
 
1477
        d->sessName = 0;
 
1478
        he = d->hstent;
 
1479
        he->lastExit = now;
 
1480
        he->goodExit = goodExit;
 
1481
        if (he->sdRec.how) {
 
1482
                if (he->sdRec.force == SHUT_ASK &&
 
1483
                    (anyActiveDisplays() || d->allowShutdown == SHUT_ROOT))
 
1484
                {
 
1485
                        endState = DS_RESTART;
 
1486
                } else {
 
1487
                        if (!sdRec.how || sdRec.force != SHUT_FORCE ||
 
1488
                            !((d->allowNuke == SHUT_NONE && sdRec.uid != he->sdRec.uid) ||
 
1489
                              (d->allowNuke == SHUT_ROOT && he->sdRec.uid)))
 
1490
                        {
 
1491
                                if (sdRec.osname)
 
1492
                                        free( sdRec.osname );
 
1493
                                sdRec = he->sdRec;
 
1494
                                if (now < sdRec.timeout || wouldShutdown())
 
1495
                                        endState = DS_REMOVE;
 
1496
                        } else if (he->sdRec.osname)
 
1497
                                free( he->sdRec.osname );
 
1498
                        he->sdRec.how = 0;
 
1499
                        he->sdRec.osname = 0;
 
1500
                }
 
1501
        }
 
1502
        if (d->status == zombie)
 
1503
                rStopDisplay( d, d->zstatus );
 
1504
        else {
 
1505
                if (stopping) {
 
1506
                        stopDisplay( d );
 
1507
                        return;
 
1508
                }
 
1509
                if (endState != DS_RESTART ||
 
1510
                    (d->displayType & d_origin) != dFromFile)
 
1511
                {
 
1512
                        rStopDisplay( d, endState );
 
1513
                } else {
 
1514
                        if (serverCmd == XS_RETRY) {
 
1515
                                if ((d->displayType & d_location) == dLocal) {
 
1516
                                        if (he->lastExit - d->lastStart < 120) {
 
1517
                                                logError( "Unable to fire up local display %s;"
 
1518
                                                          " disabling.\n", d->name );
 
1519
                                                stopDisplay( d );
 
1520
                                                return;
 
1521
                                        }
 
1522
                                } else {
 
1523
                                        if (++d->startTries > d->startAttempts) {
 
1524
                                                logError( "Disabling foreign display %s"
 
1525
                                                          " (too many attempts)\n", d->name );
 
1526
                                                stopDisplay( d );
 
1527
                                                return;
 
1528
                                        }
 
1529
                                }
 
1530
                        } else
 
1531
                                d->startTries = 0;
 
1532
                        if (d->serverPid != -1 &&
 
1533
                            (serverCmd != XS_KEEP || d->terminateServer))
 
1534
                        {
 
1535
                                debug( "killing X server for %s\n", d->name );
 
1536
                                terminateProcess( d->serverPid, d->termSignal );
 
1537
                                d->status = phoenix;
 
1538
                        } else
 
1539
                                d->status = notRunning;
 
1540
                }
 
1541
        }
 
1542
}
 
1543
 
 
1544
 
 
1545
static int pidFd;
 
1546
static FILE *pidFilePtr;
 
1547
 
 
1548
static int
 
1549
storePid( void )
 
1550
{
 
1551
        int oldpid;
 
1552
 
 
1553
        if (pidFile[0] != '\0') {
 
1554
                pidFd = open( pidFile, O_RDWR );
 
1555
                if (pidFd == -1 && errno == ENOENT)
 
1556
                        pidFd = open( pidFile, O_RDWR|O_CREAT, 0666 );
 
1557
                if (pidFd == -1 || !(pidFilePtr = fdopen( pidFd, "r+" ))) {
 
1558
                        logError( "process-id file %s cannot be opened\n",
 
1559
                                  pidFile );
 
1560
                        return -1;
 
1561
                }
 
1562
                if (fscanf( pidFilePtr, "%d\n", &oldpid ) != 1)
 
1563
                        oldpid = -1;
 
1564
                fseek( pidFilePtr, 0l, 0 );
 
1565
                if (lockPidFile) {
 
1566
#ifdef F_SETLK
 
1567
# ifndef SEEK_SET
 
1568
#  define SEEK_SET 0
 
1569
# endif
 
1570
                        struct flock lock_data;
 
1571
                        lock_data.l_type = F_WRLCK;
 
1572
                        lock_data.l_whence = SEEK_SET;
 
1573
                        lock_data.l_start = lock_data.l_len = 0;
 
1574
                        if (fcntl( pidFd, F_SETLK, &lock_data ) == -1) {
 
1575
                                if (errno == EAGAIN)
 
1576
                                        return oldpid;
 
1577
                                else
 
1578
                                        return -1;
 
1579
                        }
 
1580
#else
 
1581
# ifdef LOCK_EX
 
1582
                        if (flock( pidFd, LOCK_EX|LOCK_NB ) == -1) {
 
1583
                                if (errno == EWOULDBLOCK)
 
1584
                                        return oldpid;
 
1585
                                else
 
1586
                                        return -1;
 
1587
                        }
 
1588
# else
 
1589
                        if (lockf( pidFd, F_TLOCK, 0 ) == -1) {
 
1590
                                if (errno == EACCES)
 
1591
                                        return oldpid;
 
1592
                                else
 
1593
                                        return -1;
 
1594
                        }
 
1595
# endif
 
1596
#endif
 
1597
                }
 
1598
                fprintf( pidFilePtr, "%ld\n", (long)getpid() );
 
1599
                (void)fflush( pidFilePtr );
 
1600
                registerCloseOnFork( pidFd );
 
1601
        }
 
1602
        return 0;
 
1603
}
 
1604
 
 
1605
#if 0
 
1606
void
 
1607
UnlockPidFile( void )
 
1608
{
 
1609
        if (lockPidFile)
 
1610
# ifdef F_SETLK
 
1611
        {
 
1612
                struct flock lock_data;
 
1613
                lock_data.l_type = F_UNLCK;
 
1614
                lock_data.l_whence = SEEK_SET;
 
1615
                lock_data.l_start = lock_data.l_len = 0;
 
1616
                (void)fcntl( pidFd, F_SETLK, &lock_data );
 
1617
        }
 
1618
# else
 
1619
#  ifdef F_ULOCK
 
1620
                lockf( pidFd, F_ULOCK, 0 );
 
1621
#  else
 
1622
                flock( pidFd, LOCK_UN );
 
1623
#  endif
 
1624
# endif
 
1625
        close( pidFd );
 
1626
        fclose( pidFilePtr );
 
1627
}
 
1628
#endif
 
1629
 
 
1630
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
 
1631
void
 
1632
setproctitle( const char *fmt, ... )
 
1633
{
 
1634
        const char *name;
 
1635
        char *oname;
 
1636
        char *p = title;
 
1637
        int left = titleLen;
 
1638
        va_list args;
 
1639
 
 
1640
        va_start( args, fmt );
 
1641
        VASPrintf( &oname, fmt, args );
 
1642
        va_end( args );
 
1643
 
 
1644
        if ((name = oname)) {
 
1645
                *p++ = '-';
 
1646
                --left;
 
1647
                while (*name && left > 0) {
 
1648
                        *p++ = *name++;
 
1649
                        --left;
 
1650
                }
 
1651
                while (left > 0) {
 
1652
                        *p++ = '\0';
 
1653
                        --left;
 
1654
                }
 
1655
 
 
1656
                free( oname );
 
1657
        }
 
1658
}
 
1659
#endif