~ubuntu-branches/ubuntu/wily/kdebase-workspace/wily

« back to all changes in this revision

Viewing changes to .pc/kdm_X_path.diff/kdm/backend/dm.c

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Thomas, Jonathan Thomas, Tarun Kumar Mall, Philip Muškovac, Stéphane Graber, James Hunt
  • Date: 2011-06-01 02:09:54 UTC
  • mfrom: (0.1.21 sid)
  • Revision ID: james.westby@ubuntu.com-20110601020954-id2t0x9rwxwrmjn2
Tags: 4:4.6.3-1ubuntu1
[ Jonathan Thomas ]
* Merge with Debian Unstable, remaining changes:
  - Add kdebase-workspace-wallpapers.{links, install}
  - Add kdebase-workspace-data.links
  - kdebase-workspace-data.install: don't add wallpapers that are in
    kdebase-workspace-wallpapers.install
  - Add kdm.{links, upstart}
  - kdm.logrotate: rotate 2 -> rotate 7
  - Make kdm work with upstart in kdm.prerm, kdm.postrm, kdm.postinst
  - debian/control:
    - don't build against libggadget-1.0-dev, libggadget-qt-1.0-dev
      (they are in Universe)
    - Build against libbost1.46-dev instead of libboost-dev
    - Add libxml2-dev, libpolkit-qt-1-dev to build-deps
    - Add python-kde4, python-sip, python-qt4 to build-dependencies
    - Keep bumped our replaces/breaks
    - plasma-netbook replaces plasma-widgets-workspace (<= 4:4.5.2-1ubuntu1)
    - kdebase-workspace-bin suggests plasma-scriptengines instead of
      recommend
    - kdebase-workspace-data depends on oxygen-cursor-theme instead of oxygencursors
    - Keep kdebase-workspace-wallpapers
    - plasma-dataengines-workspace replaces plasma-widget-workspace (<= 4:4.5.2-1ubuntu1)
    - plasma-widgets-workspace depends on akonadi-server and kdepim-runtime
    - plasma-scriptengines not depends on plasma-scriptengine-googlegadgets
    - plasma-scriptengine-ruby depends on libkde4-ruby
    - Don't build plasma-scriptengine-googlegadgets
    - freespacenotifier replaces kdebase-workspace-data (<= 4:4.5.2-1ubuntu1)
      and kdebase-workspace-bin (<= 4:4.5.2-1ubuntu1)
    - kinfocenter replaces kdebase-workspace-bin and systemsettings
    - libplasmagenericshell4 replaces plasma-widgets-workspace (<= 4:4.5.2-1ubuntu1)
  - debian/patches:
    - Use 07_kdmrc_defaults_kubuntu.diff instead of 07_kdmrc_defaults.diff
    - Don't add be_better_at_honouring_user_kdm_theming
    - Don't add use_dejavu_as_default_font
    - Don't add fix_target_link_libraries
    - Keep our patches
* Try a polkit-kde-1 | policykit-gnome-1 or-dependency again to see if policykit-1-gnome
  is a suitable policykit solution a year later.

[ Tarun Kumar Mall ]
* New uptream release
* Bumped kde-sc-dev-latest version to 4.6.3
* Removed patches kubuntu_120_ksysguard_sensors.diff and
  kubuntu_121_kdm_halt_cmd.diff, applied upstream
* Refreshed kubuntu_122_akonadi_calendar_dataengine.diff 

[ Philip Muškovac ]
* drop kubuntu_123_effectframe_glflush.diff, applied upstream
* Refresh symbol files 

[ Stéphane Graber ]
* Updated Vcs fields to point to kubuntu-uploaders instead of
  kubuntu-members

[ James Hunt ]
* Updated kdm.conf to fix kdm in single user mode (LP: #436936)

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