3
Copyright 1988, 1998 The Open Group
4
Copyright 2000-2005 Oswald Buddenhagen <ossi@kde.org>
6
Permission to use, copy, modify, distribute, and sell this software and its
7
documentation for any purpose is hereby granted without fee, provided that
8
the above copyright notice appear in all copies and that both that
9
copyright notice and this permission notice appear in supporting
12
The above copyright notice and this permission notice shall be included
13
in all copies or substantial portions of the Software.
15
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
16
OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18
IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
19
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
20
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
21
OTHER DEALINGS IN THE SOFTWARE.
23
Except as contained in this notice, the name of a copyright holder shall
24
not be used in advertising or otherwise to promote the sale, use or
25
other dealings in this Software without prior written authorization
26
from the copyright holder.
31
* xdm - display manager daemon
32
* Author: Keith Packard, MIT X Consortium
49
# include <sys/ioctl.h>
53
static void sigHandler(int n);
54
static int scanConfigs(int force);
55
static void startDisplay(struct display *d);
56
static void startDisplays(void);
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);
64
static int signalFds[2];
66
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
71
static int storePid(void);
74
SdRec sdRec = { 0, 0, 0, TO_INF, TO_INF, 0, 0, 0 };
81
#if KDM_LIBEXEC_STRIP != -1
90
main(int argc, char **argv)
92
int oldpid, oldumask, fd, parentPid;
93
char *pt, *errorLogFile, **opts;
95
/* make sure at least world write access is disabled */
96
if (((oldumask = umask(022)) & 002) == 002)
97
(void)umask(oldumask);
99
/* give /dev/null as stdin */
100
if ((fd = open("/dev/null", O_RDONLY)) > 0) {
104
if (fcntl(1, F_GETFD) < 0)
106
if (fcntl(2, F_GETFD) < 0)
110
nowMonotonic = sysconf(_SC_MONOTONIC_CLOCK) >= 200112L;
113
#if KDM_LIBEXEC_STRIP == -1
114
prog = strrchr(argv[0], '/');
115
progname = prog = prog ? prog + 1 : argv[0];
117
if (argv[0][0] == '/') {
118
if (!strDup(&progpath, argv[0]))
119
panic("Out of memory");
123
/* note that this will resolve symlinks ... */
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");
133
panic("Must be invoked with full path specification");
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);
143
char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
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);
152
if (!(pathe = strchr(path, ':')))
153
pathe = path + strlen(path);
155
if (!len || (len == 1 && *path == '.')) {
156
len = strlen(directory);
160
if (thenam >= nambuf) {
161
memcpy(thenam, path, len);
162
if (!access(thenam, X_OK))
166
} while (*path++ != '\0');
167
panic("Can't find myself (not in PATH)");
169
if (!strDup(&progpath, thenam))
170
panic("Out of memory");
175
prog = strrchr(progpath, '/') + 1;
176
# if KDM_LIBEXEC_STRIP
177
for (progname = pt = prog, fd = 0; fd < KDM_LIBEXEC_STRIP + 1; fd++) {
181
panic("Executable is obviously located outside BINDIR");
190
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
192
titleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - title;
196
* Parse command line options
198
parentPid = getppid();
200
if (!(opts = Malloc(2 * sizeof(char *))))
202
opts[0] = (char *)"";
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"
232
} else if (!strcmp(pt, "daemon")) {
234
} else if (!strcmp(pt, "nodaemon")) {
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;
245
fprintf(stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv);
251
* Only allow root to run in non-debug mode to avoid problems
253
if (!debugLevel && getuid()) {
254
fprintf(stderr, "Only root wants to run %s\n", prog);
258
initErrorLog(errorLogFile);
264
* Step 1 - load configuration parameters
266
if (!initResources(opts) || scanConfigs(False) < 0)
267
logPanic("Config reader failed. Aborting ...\n");
270
if ((oldpid = storePid())) {
272
logError("Cannot create/lock pid file %s\n", pidFile);
274
logError("Cannot lock pid file %s, another xdm is running (pid %d)\n",
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.
291
debug("not compiled for XDMCP\n");
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);
305
* Step 2 - run a sub-daemon for each entry
309
updateListenSockets();
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);
324
sigaddset(&mask, SIGCHLD);
325
sigaddset(&mask, SIGHUP);
329
debug("nothing left to do, exiting\n");
336
#if (_POSIX_MONOTONIC_CLOCK >= 0)
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;
350
TTYtoVT(const char *tty)
352
return memcmp(tty, "tty", 3) ? 0 : atoi(tty + 3);
359
int con = open("/dev/console", O_RDONLY);
361
if (!ioctl(con, VT_ACTIVATE, vt))
370
wakeDisplay(struct display *d)
372
if (d->status == textMode)
373
d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
378
UtDead, /* no such entry */
379
UtWait, /* waiting for user login */
380
UtActive /* user logged in */
394
#define TIME_RELOG 10
396
static struct utmps *utmpList;
397
static time_t utmpTimeout = TO_INF;
403
forEachDisplay(wakeDisplay);
408
while ((utp = utmpList)) {
409
utp->d->status = notRunning;
410
utmpList = utp->next;
419
static time_t modtim;
436
if (stat(UTMP_FILE, &st)) {
437
logError(UTMP_FILE " not found - cannot use console mode\n");
441
if (modtim != st.st_mtime) {
442
debug("rescanning " UTMP_FILE "\n");
446
for (utp = utmpList; utp; utp = utp->next)
450
if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) {
451
logError("Cannot open " UTMP_FILE " - cannot use console mode\n");
455
while (reader(fd, ut, sizeof(ut[0])) == sizeof(ut[0]))
458
while ((ut = GETUTENT()))
461
/* first, match the tty to a utemps */
464
for (line = consoleTTYs; *line; line++)
465
if (!strncmp(*line, ut->ut_line, sizeof(ut->ut_line)))
467
for (utp = utmpList; utp; utp = utp->next)
468
if (!strncmp(utp->d->console, ut->ut_line, sizeof(ut->ut_line)))
473
/* then, update the utemps accordingly */
477
if (ut->ut_type != USER_PROCESS) {
480
/* don't allow "downgrading" the singular utemps */
481
if (utp->state == UtActive)
487
utp->state = UtActive;
490
/* tty with latest activity wins */
491
if (utp->time < ut->ut_time)
493
utp->time = ut->ut_time;
500
modtim = st.st_mtime;
505
for (utpp = &utmpList; (utp = *utpp);) {
507
if (utp->state != UtActive) {
508
if (utp->state == UtDead) /* shouldn't happen ... */
510
ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
514
debug("console login timed out\n");
517
utp->d->status = notRunning;
518
debug("console login for %s at %s timed out\n",
519
utp->d->name, utp->d->console);
527
nck = TIME_RELOG + now;
528
if (nck < utmpTimeout)
531
utpp = &(*utpp)->next;
540
switchToTTY(struct display *d)
548
if (!(utp = Malloc(sizeof(*utp)))) {
552
d->status = notRunning;
557
d->status = textMode;
559
utp->next = utmpList;
562
utp->hadSess = False;
567
if ((vt = TTYtoVT(*consoleTTYs)))
574
stopToTTY(struct display *d)
576
if ((d->displayType & d_location) == dLocal)
579
rStopDisplay(d, DS_TEXTMODE | DS_SCHEDULE);
591
for (d = displays; d; d = d->next)
592
if (d->status == zombie)
601
switchToX(struct display *d)
603
struct utmps *utp, **utpp;
605
for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
609
d->status = notRunning;
617
startRemoteLogin(struct display *d)
621
debug("startRemoteLogin for %s\n", d->name);
622
/* HACK: omitting loadDisplayResources(d) here! */
623
switch (Fork(&d->serverPid)) {
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)))
630
debug("exec %\"[s\n", argv);
631
(void)execv(argv[0], argv);
632
logError("X server %\"s cannot be executed\n", argv[0]);
635
logError("Forking X server for remote login failed: %m");
636
d->status = notRunning;
641
debug("X server forked, pid %d\n", d->serverPid);
643
d->status = remoteLogin;
649
stopInactiveDisplay(struct display *d)
651
if (d->status != remoteLogin && d->userSess < 0)
660
updateListenSockets();
663
forEachDisplay(stopDisplay);
665
forEachDisplay(stopInactiveDisplay);
671
sessionDone(struct display *d)
676
d->userName = d->sessName = 0;
680
setNLogin(struct display *d,
681
const char *nuser, const char *npass, const char *nargs, int rl)
683
struct disphist *he = d->hstent;
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);
692
processDPipe(struct display *d)
694
char *user, *pass, *args;
702
dpytalk.pipe = &d->pipe;
703
if (Setjmp(dpytalk.errjmp)) {
708
if (!gRecvCmd(&cmd)) {
709
/* process already exited */
710
unregisterInput(d->pipe.fd.r);
715
d->userSess = gRecvInt();
716
d->userName = gRecvStr();
717
d->sessName = gRecvStr();
722
if (d->sdRec.force == SHUT_ASK &&
723
(anyUserLogins(-1) || d->allowShutdown == SHUT_ROOT))
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)))
734
free(d->sdRec.osname);
748
setNLogin(d, user, pass, args, 1);
755
ca.data = (unsigned char *)gRecvArr(&len);
756
ca.length = (CARD16)len;
757
cp.data = (unsigned char *)gRecvArr(&len);
758
cp.length = (CARD16)len;
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);
769
d->remoteHost = gRecvStr();
776
logError("Internal error: unknown D_* command %d\n", cmd);
783
emitXSessG(struct display *di, struct display *d, void *ctx ATTR_UNUSED)
788
gSendInt(di->serverVT);
791
if (di->status == remoteLogin) {
793
gSendStr(di->remoteHost);
797
gSendStr(di->userName);
798
gSendStr(di->sessName);
800
gSendInt(di == d ? isSelf : 0);
804
emitTTYSessG(STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED)
806
gSendStrN(ut->ut_line, sizeof(ut->ut_line));
807
gSendStrN(ut->ut_host, sizeof(ut->ut_host));
809
gSendInt(TTYtoVT(ut->ut_line));
812
gSendStrN(*ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user));
814
gSendStrN(ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user));
816
gSendStr(0); /* session type unknown */
821
processGPipe(struct display *d)
823
char **opts, *option;
824
int cmd, ret, dflt, curr;
827
dpytalk.pipe = &d->gpipe;
828
if (Setjmp(dpytalk.errjmp)) {
833
if (!gRecvCmd(&cmd)) {
834
/* process already exited */
835
unregisterInput(d->gpipe.fd.r);
840
ret = getBootOptions(&opts, &dflt, &curr);
850
sdRec.how = gRecvInt();
851
sdRec.start = gRecvInt();
852
sdRec.timeout = gRecvInt();
853
sdRec.force = gRecvInt();
854
sdRec.uid = gRecvInt();
856
setBootOption(option, &sdRec);
859
case G_QueryShutdown:
861
gSendInt(sdRec.start);
862
gSendInt(sdRec.timeout);
863
gSendInt(sdRec.force);
865
gSendStr(sdRec.osname);
867
case G_QryDpyShutdown:
868
gSendInt(d->sdRec.how);
869
gSendInt(d->sdRec.uid);
870
gSendStr(d->sdRec.osname);
873
listSessions(gRecvInt(), d, 0, emitXSessG, emitTTYSessG);
878
activateVT(gRecvInt());
883
if (*consoleTTYs) { /* sanity check against greeter */
884
forEachDisplay(stopToTTY);
888
if (*d->console) /* sanity check against greeter */
889
rStopDisplay(d, DS_TEXTMODE);
893
logError("Internal error: unknown G_* command %d\n", cmd);
901
scanConfigs(int force)
905
if ((ret = loadDMResources(force)) <= 0)
909
scanAccessDatabase(force);
915
markDisplay(struct display *d)
917
d->stillThere = False;
921
rescanConfigs(int force)
923
if (scanConfigs(force) > 0) {
925
updateListenSockets();
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));
953
if ((d = findDisplayByPid(pid))) {
955
unregisterInput(d->pipe.fd.r);
957
unregisterInput(d->gpipe.fd.r);
960
switch (wcFromWait(status)) {
963
debug("display exited with EX_REMOTE\n");
964
exitDisplay(d, DS_REMOTE, 0, False);
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);
973
exitDisplay(d, DS_RESTART, XS_KEEP, True);
976
debug("display exited with EX_RESERVE\n");
977
exitDisplay(d, DS_RESERVE, 0, False);
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);
986
case EX_OPENFAILED_DPY:
987
/* waitForServer() failed */
988
logError("Display %s cannot be opened\n", d->name);
991
* no display connection was ever made, tell the
992
* terminal that the open attempt failed
994
if ((d->displayType & d_origin) == dFromXDMCP)
995
sendFailed(d, "cannot open display");
997
exitDisplay(d, DS_RESTART, XS_RETRY, False);
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)
1005
debug("display exited on SIGTERM\n");
1006
exitDisplay(d, DS_RESTART, XS_RETRY, False);
1008
case EX_AL_RESERVER_DPY:
1009
/* - killed after waitForServer()
1010
- Xserver dead after remote session exit
1012
debug("display exited with EX_AL_RESERVER_DPY\n");
1013
exitDisplay(d, DS_RESTART, XS_RESTART, False);
1015
case EX_RESERVER_DPY:
1016
/* induced by greeter:
1017
- could not secure display
1020
debug("display exited with EX_RESERVER_DPY\n");
1021
exitDisplay(d, DS_RESTART, XS_RESTART, True);
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);
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);
1035
} else if ((d = findDisplayByServerPid(pid))) {
1037
switch (d->status) {
1039
debug("zombie X server for display %s reaped\n", d->name);
1041
if (d->serverVT && d->zstatus != DS_REMOTE) {
1043
d->follower->serverVT = d->serverVT;
1046
int con = open("/dev/console", O_RDONLY);
1048
struct vt_stat vtstat;
1049
ioctl(con, VT_GETSTATE, &vtstat);
1050
if (vtstat.v_active == d->serverVT) {
1053
for (di = displays; di; di = di->next)
1054
if (di != d && di->serverVT)
1056
for (di = displays; di; di = di->next)
1057
if (di != d && di->serverVT &&
1058
(di->userSess >= 0 ||
1059
di->status == remoteLogin))
1061
ioctl(con, VT_ACTIVATE, vt);
1063
ioctl(con, VT_DISALLOCATE, d->serverVT);
1070
rStopDisplay(d, d->zstatus);
1073
debug("phoenix X server arises, restarting display %s\n",
1075
d->status = notRunning;
1078
debug("remote login X server for display %s exited\n",
1080
d->status = ((d->displayType & d_lifetime) == dReserve) ?
1081
reserve : notRunning;
1084
logError("X server for display %s terminated unexpectedly\n",
1086
/* don't kill again */
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();
1095
logError("X server for display %s terminated unexpectedly\n",
1098
debug("terminating session pid %d\n", d->pid);
1099
terminateProcess(d->pid, SIGTERM);
1105
/* this cannot happen */
1106
debug("X server exited for passive (%d) session on display %s\n",
1107
(int)d->status, d->name);
1111
debug("unknown child termination\n");
1122
switch (sdRec.force) {
1126
return !anyUserLogins(sdRec.uid);
1129
return !anyUserLogins(-1);
1133
fd_set wellKnownSocketsMask;
1134
int wellKnownSocketsMax;
1135
int wellKnownSocketsCount;
1138
registerInput(int fd)
1140
/* can be omited, as it is always called right after opening a socket
1141
if (!FD_ISSET(fd, &wellKnownSocketsMask))
1144
FD_SET(fd, &wellKnownSocketsMask);
1145
if (fd > wellKnownSocketsMax)
1146
wellKnownSocketsMax = fd;
1147
wellKnownSocketsCount++;
1152
unregisterInput(int fd)
1154
/* the check _is_ necessary, as some handles are unregistered before
1155
the regular close sequence.
1157
if (FD_ISSET(fd, &wellKnownSocketsMask)) {
1158
FD_CLR(fd, &wellKnownSocketsMask);
1159
wellKnownSocketsCount--;
1166
int olderrno = errno;
1168
/* debug("caught signal %d\n", n); this hangs in syslog() */
1169
write(signalFds[1], &buf, 1);
1171
(void)Signal(n, sigHandler);
1180
struct timeval *tvp, tv;
1186
debug("mainLoop\n");
1190
anyListenSockets() ||
1192
(stopping ? anyRunningDisplays() : anyDisplaysLeft()))
1197
to = disposeIndirectHosts();
1202
if (sdRec.start != TO_INF && now < sdRec.start) {
1203
/*if (sdRec.start < to)*/
1206
sdRec.start = TO_INF;
1207
if (now >= sdRec.timeout) {
1208
sdRec.timeout = TO_INF;
1209
if (wouldShutdown())
1215
/*if (sdRec.timeout < to)*/
1220
if (serverTimeout < to)
1222
if (utmpTimeout < to)
1234
reads = wellKnownSocketsMask;
1235
nready = select(wellKnownSocketsMax + 1, &reads, 0, 0, tvp);
1236
debug("select returns %d\n", nready);
1241
if (now >= serverTimeout) {
1242
serverTimeout = TO_INF;
1243
startServerTimeout();
1245
if (now >= utmpTimeout) {
1246
utmpTimeout = TO_INF;
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.
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");
1263
debug("shutting down entire manager\n");
1267
logInfo("Rescanning all config files\n");
1268
forEachDisplay(markDisplay);
1269
rescanConfigs(True);
1273
if (!stopping && autoRescan)
1274
rescanConfigs(False);
1277
if (startingServer && startingServer->serverStatus == starting)
1278
startServerSuccess();
1284
if (processListenSockets(&reads))
1287
if (handleCtrl(&reads, 0))
1289
/* Must be last (because of the breaks)! */
1291
for (d = displays; d; d = d->next) {
1292
if (handleCtrl(&reads, d))
1294
if (d->pipe.fd.r >= 0 && FD_ISSET(d->pipe.fd.r, &reads)) {
1298
if (d->gpipe.fd.r >= 0 && FD_ISSET(d->gpipe.fd.r, &reads)) {
1308
checkDisplayStatus(struct display *d)
1310
if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
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);
1322
kickDisplay(struct display *d)
1324
if (d->status == notRunning)
1326
if (d->serverStatus == awaiting && !startingServer)
1331
static int activeVTs;
1336
struct vt_stat vtstat;
1339
if (activeVTs == -1) {
1341
if ((con = open("/dev/console", O_RDONLY)) >= 0) {
1342
ioctl(con, VT_GETSTATE, &vtstat);
1345
activeVTs = vtstat.v_state;
1351
allocateVT(struct display *d)
1356
if ((d->displayType & d_location) == dLocal &&
1357
d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
1359
if (d->reqSrvVT && d->reqSrvVT < 16) {
1360
d->serverVT = d->reqSrvVT;
1362
for (i = tvt = 0;;) {
1364
tvt = atoi(serverVTs[i++]);
1370
if (!tvt || tvt >= 16)
1377
for (cd = displays; cd; cd = cd->next) {
1378
if (cd->reqSrvVT == tvt && /* protect from lusers */
1379
(cd->status != zombie || cd->zstatus != DS_REMOVE))
1381
if (cd->serverVT == tvt) {
1382
if (cd->status != zombie || cd->zstatus == DS_REMOTE)
1384
if (!cd->follower) {
1391
if (!volun || !((1 << tvt) & getBusyVTs())) {
1405
forEachDisplay(checkDisplayStatus);
1409
forEachDisplayRev(allocateVT);
1411
forEachDisplay(kickDisplay);
1415
startDisplay(struct display *d)
1418
debug("stopping display %s because shutdown is scheduled\n", d->name);
1424
if (d->serverVT < 0)
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
1434
d->pingInterval = 0;
1436
setLocalAuthorization(d);
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)
1443
if (d->serverPid != -1 && d->resetForAuth)
1444
kill(d->serverPid, SIGHUP);
1446
if (d->serverPid == -1) {
1447
d->serverStatus = awaiting;
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);
1460
startDisplayP2(struct display *d)
1462
char *cname, *cgname;
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)) {
1473
setproctitle("%s", d->name);
1475
ASPrintf(&prog, "%s: %s", prog, d->name);
1477
if (debugLevel & DEBUG_WSESS)
1479
mstrtalk.pipe = &d->pipe;
1480
(void)Signal(SIGPIPE, SIG_IGN);
1481
setAuthorization(d);
1483
if ((d->displayType & d_location) == dLocal) {
1485
if (Setjmp(mstrtalk.errjmp))
1486
exit(EX_UNMANAGE_DPY);
1487
gSendInt(D_XConnOk);
1493
d->status = notRunning;
1496
debug("forked session, pid %d\n", d->pid);
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);
1503
d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
1511
* transition from running to zombie, textmode, reserve or deleted
1515
rStopDisplay(struct display *d, int endState)
1517
debug("stopping display %s to state %d\n", d->name, endState);
1518
abortStartServer(d);
1519
if (d->serverPid != -1 || d->pid != -1) {
1521
terminateProcess(d->pid, SIGTERM);
1522
if (d->serverPid != -1)
1523
terminateProcess(d->serverPid, SIGTERM);
1525
d->zstatus = endState & DS_MASK;
1526
debug(" zombiefied\n");
1527
} else if (endState == DS_TEXTMODE) {
1529
d->status = textMode;
1531
} else if (endState == (DS_TEXTMODE | DS_SCHEDULE)) {
1532
d->status = textMode;
1536
} else if (endState == DS_RESERVE) {
1537
d->status = reserve;
1538
d->hstent->lastExit = 0;
1540
} else if (endState == DS_REMOTE) {
1541
startRemoteLogin(d);
1552
stopDisplay(struct display *d)
1554
rStopDisplay(d, DS_REMOVE);
1558
exitDisplay(struct display *d, int endState, int serverCmd, int goodExit)
1560
struct disphist *he;
1562
if (d->status == raiser) {
1563
serverCmd = XS_KEEP;
1567
debug("exitDisplay %s, "
1568
"endState = %d, serverCmd = %d, GoodExit = %d\n",
1569
d->name, endState, serverCmd, goodExit);
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);
1584
if (endState != DS_RESTART ||
1585
(d->displayType & d_lifetime) == dTransient)
1587
rStopDisplay(d, endState);
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);
1598
if (++d->startTries > d->startAttempts) {
1599
logError("Disabling foreign display %s"
1600
" (too many attempts)\n", d->name);
1608
if (d->serverPid != -1 &&
1609
(serverCmd != XS_KEEP || d->terminateServer))
1611
debug("killing X server for %s\n", d->name);
1612
terminateProcess(d->serverPid, SIGTERM);
1613
d->status = phoenix;
1615
d->status = notRunning;
1623
static FILE *pidFilePtr;
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",
1639
if (fscanf(pidFilePtr, "%d\n", &oldpid) != 1)
1641
fseek(pidFilePtr, 0l, 0);
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)
1659
if (flock(pidFd, LOCK_EX | LOCK_NB) == -1) {
1660
if (errno == EWOULDBLOCK)
1666
if (lockf(pidFd, F_TLOCK, 0) == -1) {
1667
if (errno == EACCES)
1675
fprintf(pidFilePtr, "%ld\n", (long)getpid());
1676
if (fflush(pidFilePtr) == EOF)
1677
logError("Cannot write PID file %s: %m", pidFile);
1678
registerCloseOnFork(pidFd);
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);
1698
lockf(pidFd, F_ULOCK, 0);
1700
flock(pidFd, LOCK_UN);
1708
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
1710
setproctitle(const char *fmt, ...)
1715
int left = titleLen;
1718
va_start(args, fmt);
1719
VASPrintf(&oname, fmt, args);
1722
if ((name = oname)) {
1725
while (*name && left > 0) {