~ubuntu-branches/ubuntu/utopic/kde-workspace/utopic-proposed

« back to all changes in this revision

Viewing changes to kdm/backend/dm.c

  • Committer: Bazaar Package Importer
  • Author(s): Michał Zając
  • Date: 2011-07-09 08:31:15 UTC
  • Revision ID: james.westby@ubuntu.com-20110709083115-ohyxn6z93mily9fc
Tags: upstream-4.6.90
Import upstream version 4.6.90

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