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 };
78
#if KDM_LIBEXEC_STRIP != -1
87
main(int argc, char **argv)
89
int oldpid, oldumask, fd, parentPid;
90
char *pt, *errorLogFile, **opts;
92
/* make sure at least world write access is disabled */
93
if (((oldumask = umask(022)) & 002) == 002)
94
(void)umask(oldumask);
96
/* give /dev/null as stdin */
97
if ((fd = open("/dev/null", O_RDONLY)) > 0) {
101
if (fcntl(1, F_GETFD) < 0)
103
if (fcntl(2, F_GETFD) < 0)
106
#if KDM_LIBEXEC_STRIP == -1
107
prog = strrchr(argv[0], '/');
108
progname = prog = prog ? prog + 1 : argv[0];
110
if (argv[0][0] == '/') {
111
if (!strDup(&progpath, argv[0]))
112
panic("Out of memory");
116
/* note that this will resolve symlinks ... */
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");
126
panic("Must be invoked with full path specification");
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);
136
char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
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);
145
if (!(pathe = strchr(path, ':')))
146
pathe = path + strlen(path);
148
if (!len || (len == 1 && *path == '.')) {
149
len = strlen(directory);
153
if (thenam >= nambuf) {
154
memcpy(thenam, path, len);
155
if (!access(thenam, X_OK))
159
} while (*path++ != '\0');
160
panic("Can't find myself (not in PATH)");
162
if (!strDup(&progpath, thenam))
163
panic("Out of memory");
168
prog = strrchr(progpath, '/') + 1;
169
# if KDM_LIBEXEC_STRIP
170
for (progname = pt = prog, fd = 0; fd < KDM_LIBEXEC_STRIP + 1; fd++) {
174
panic("Executable is obviously located outside BINDIR");
183
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
185
titleLen = (argv[argc - 1] + strlen(argv[argc - 1])) - title;
189
* Parse command line options
191
parentPid = getppid();
193
if (!(opts = Malloc(2 * sizeof(char *))))
195
opts[0] = (char *)"";
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"
225
} else if (!strcmp(pt, "daemon")) {
227
} else if (!strcmp(pt, "nodaemon")) {
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;
238
fprintf(stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv);
244
* Only allow root to run in non-debug mode to avoid problems
246
if (!debugLevel && getuid()) {
247
fprintf(stderr, "Only root wants to run %s\n", prog);
251
initErrorLog(errorLogFile);
257
* Step 1 - load configuration parameters
259
if (!initResources(opts) || scanConfigs(False) < 0)
260
logPanic("Config reader failed. Aborting ...\n");
263
if ((oldpid = storePid())) {
265
logError("Cannot create/lock pid file %s\n", pidFile);
267
logError("Cannot lock pid file %s, another xdm is running (pid %d)\n",
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.
284
debug("not compiled for XDMCP\n");
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);
298
* Step 2 - run a sub-daemon for each entry
302
updateListenSockets();
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);
317
sigaddset(&mask, SIGCHLD);
318
sigaddset(&mask, SIGHUP);
322
debug("nothing left to do, exiting\n");
329
TTYtoVT(const char *tty)
331
return memcmp(tty, "tty", 3) ? 0 : atoi(tty + 3);
338
int con = open("/dev/console", O_RDONLY);
340
if (!ioctl(con, VT_ACTIVATE, vt))
349
wakeDisplay(struct display *d)
351
if (d->status == textMode)
352
d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
357
UtDead, /* no such entry */
358
UtWait, /* waiting for user login */
359
UtActive /* user logged in */
373
#define TIME_RELOG 10
375
static struct utmps *utmpList;
376
static time_t utmpTimeout = TO_INF;
382
forEachDisplay(wakeDisplay);
387
while ((utp = utmpList)) {
388
utp->d->status = notRunning;
389
utmpList = utp->next;
398
static time_t modtim;
415
if (stat(UTMP_FILE, &st)) {
416
logError(UTMP_FILE " not found - cannot use console mode\n");
420
if (modtim != st.st_mtime) {
421
debug("rescanning " UTMP_FILE "\n");
425
for (utp = utmpList; utp; utp = utp->next)
429
if ((fd = open(UTMP_FILE, O_RDONLY)) < 0) {
430
logError("Cannot open " UTMP_FILE " - cannot use console mode\n");
434
while (reader(fd, ut, sizeof(ut[0])) == sizeof(ut[0]))
437
while ((ut = GETUTENT()))
440
/* first, match the tty to a utemps */
443
for (line = consoleTTYs; *line; line++)
444
if (!strncmp(*line, ut->ut_line, sizeof(ut->ut_line)))
446
for (utp = utmpList; utp; utp = utp->next)
447
if (!strncmp(utp->d->console, ut->ut_line, sizeof(ut->ut_line)))
452
/* then, update the utemps accordingly */
456
if (ut->ut_type != USER_PROCESS) {
459
/* don't allow "downgrading" the singular utemps */
460
if (utp->state == UtActive)
466
utp->state = UtActive;
469
/* tty with latest activity wins */
470
if (utp->time < ut->ut_time)
472
utp->time = ut->ut_time;
479
modtim = st.st_mtime;
484
for (utpp = &utmpList; (utp = *utpp);) {
486
if (utp->state != UtActive) {
487
if (utp->state == UtDead) /* shouldn't happen ... */
489
ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
493
debug("console login timed out\n");
496
utp->d->status = notRunning;
497
debug("console login for %s at %s timed out\n",
498
utp->d->name, utp->d->console);
506
nck = TIME_RELOG + now;
507
if (nck < utmpTimeout)
510
utpp = &(*utpp)->next;
519
switchToTTY(struct display *d)
527
if (!(utp = Malloc(sizeof(*utp)))) {
531
d->status = notRunning;
536
d->status = textMode;
538
utp->next = utmpList;
541
utp->hadSess = False;
546
if ((vt = TTYtoVT(*consoleTTYs)))
553
stopToTTY(struct display *d)
555
if ((d->displayType & d_location) == dLocal)
558
rStopDisplay(d, DS_TEXTMODE | DS_SCHEDULE);
570
for (d = displays; d; d = d->next)
571
if (d->status == zombie)
580
switchToX(struct display *d)
582
struct utmps *utp, **utpp;
584
for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
588
d->status = notRunning;
596
startRemoteLogin(struct display *d)
600
debug("startRemoteLogin for %s\n", d->name);
601
/* HACK: omitting loadDisplayResources(d) here! */
602
switch (Fork(&d->serverPid)) {
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)))
609
debug("exec %\"[s\n", argv);
610
(void)execv(argv[0], argv);
611
logError("X server %\"s cannot be executed\n", argv[0]);
614
logError("Forking X server for remote login failed: %m");
615
d->status = notRunning;
620
debug("X server forked, pid %d\n", d->serverPid);
622
d->status = remoteLogin;
628
stopInactiveDisplay(struct display *d)
630
if (d->status != remoteLogin && d->userSess < 0)
639
updateListenSockets();
642
forEachDisplay(stopDisplay);
644
forEachDisplay(stopInactiveDisplay);
650
sessionDone(struct display *d)
655
d->userName = d->sessName = 0;
659
setNLogin(struct display *d,
660
const char *nuser, const char *npass, const char *nargs, int rl)
662
struct disphist *he = d->hstent;
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);
671
processDPipe(struct display *d)
673
char *user, *pass, *args;
681
dpytalk.pipe = &d->pipe;
682
if (Setjmp(dpytalk.errjmp)) {
687
if (!gRecvCmd(&cmd)) {
688
/* process already exited */
689
unregisterInput(d->pipe.fd.r);
694
d->userSess = gRecvInt();
695
d->userName = gRecvStr();
696
d->sessName = gRecvStr();
701
if (d->sdRec.force == SHUT_ASK &&
702
(anyUserLogins(-1) || d->allowShutdown == SHUT_ROOT))
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)))
713
free(d->sdRec.osname);
727
setNLogin(d, user, pass, args, 1);
734
ca.data = (unsigned char *)gRecvArr(&len);
735
ca.length = (CARD16)len;
736
cp.data = (unsigned char *)gRecvArr(&len);
737
cp.length = (CARD16)len;
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);
748
d->remoteHost = gRecvStr();
755
logError("Internal error: unknown D_* command %d\n", cmd);
762
emitXSessG(struct display *di, struct display *d, void *ctx ATTR_UNUSED)
767
gSendInt(di->serverVT);
770
if (di->status == remoteLogin) {
772
gSendStr(di->remoteHost);
776
gSendStr(di->userName);
777
gSendStr(di->sessName);
779
gSendInt(di == d ? isSelf : 0);
783
emitTTYSessG(STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED)
785
gSendStrN(ut->ut_line, sizeof(ut->ut_line));
786
gSendStrN(ut->ut_host, sizeof(ut->ut_host));
788
gSendInt(TTYtoVT(ut->ut_line));
791
gSendStrN(*ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user));
793
gSendStrN(ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user));
795
gSendStr(0); /* session type unknown */
800
processGPipe(struct display *d)
802
char **opts, *option;
803
int cmd, ret, dflt, curr;
806
dpytalk.pipe = &d->gpipe;
807
if (Setjmp(dpytalk.errjmp)) {
812
if (!gRecvCmd(&cmd)) {
813
/* process already exited */
814
unregisterInput(d->gpipe.fd.r);
819
ret = getBootOptions(&opts, &dflt, &curr);
829
sdRec.how = gRecvInt();
830
sdRec.start = gRecvInt();
831
sdRec.timeout = gRecvInt();
832
sdRec.force = gRecvInt();
833
sdRec.uid = gRecvInt();
835
setBootOption(option, &sdRec);
838
case G_QueryShutdown:
840
gSendInt(sdRec.start);
841
gSendInt(sdRec.timeout);
842
gSendInt(sdRec.force);
844
gSendStr(sdRec.osname);
846
case G_QryDpyShutdown:
847
gSendInt(d->sdRec.how);
848
gSendInt(d->sdRec.uid);
849
gSendStr(d->sdRec.osname);
852
listSessions(gRecvInt(), d, 0, emitXSessG, emitTTYSessG);
857
activateVT(gRecvInt());
862
if (*consoleTTYs) { /* sanity check against greeter */
863
forEachDisplay(stopToTTY);
867
if (*d->console) /* sanity check against greeter */
868
rStopDisplay(d, DS_TEXTMODE);
872
logError("Internal error: unknown G_* command %d\n", cmd);
880
scanConfigs(int force)
884
if ((ret = loadDMResources(force)) <= 0)
888
scanAccessDatabase(force);
894
markDisplay(struct display *d)
896
d->stillThere = False;
900
rescanConfigs(int force)
902
if (scanConfigs(force) > 0) {
904
updateListenSockets();
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));
932
if ((d = findDisplayByPid(pid))) {
934
unregisterInput(d->pipe.fd.r);
936
unregisterInput(d->gpipe.fd.r);
939
switch (wcFromWait(status)) {
942
debug("display exited with EX_REMOTE\n");
943
exitDisplay(d, DS_REMOTE, 0, False);
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);
952
exitDisplay(d, DS_RESTART, XS_KEEP, True);
955
debug("display exited with EX_RESERVE\n");
956
exitDisplay(d, DS_RESERVE, 0, False);
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);
965
case EX_OPENFAILED_DPY:
966
/* waitForServer() failed */
967
logError("Display %s cannot be opened\n", d->name);
970
* no display connection was ever made, tell the
971
* terminal that the open attempt failed
973
if ((d->displayType & d_origin) == dFromXDMCP)
974
sendFailed(d, "cannot open display");
976
exitDisplay(d, DS_RESTART, XS_RETRY, False);
978
case wcCompose(SIGTERM, 0, 0):
979
/* killed before/during waitForServer()
981
- display stopped (is zombie)
982
- "login now" and "suicide" pipe commands (is raiser)
984
debug("display exited on SIGTERM\n");
985
exitDisplay(d, DS_RESTART, XS_RETRY, False);
987
case EX_AL_RESERVER_DPY:
988
/* - killed after waitForServer()
989
- Xserver dead after remote session exit
991
debug("display exited with EX_AL_RESERVER_DPY\n");
992
exitDisplay(d, DS_RESTART, XS_RESTART, False);
994
case EX_RESERVER_DPY:
995
/* induced by greeter:
996
- could not secure display
999
debug("display exited with EX_RESERVER_DPY\n");
1000
exitDisplay(d, DS_RESTART, XS_RESTART, True);
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);
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);
1014
} else if ((d = findDisplayByServerPid(pid))) {
1016
switch (d->status) {
1018
debug("zombie X server for display %s reaped\n", d->name);
1020
if (d->serverVT && d->zstatus != DS_REMOTE) {
1022
d->follower->serverVT = d->serverVT;
1025
int con = open("/dev/console", O_RDONLY);
1027
struct vt_stat vtstat;
1028
ioctl(con, VT_GETSTATE, &vtstat);
1029
if (vtstat.v_active == d->serverVT) {
1032
for (di = displays; di; di = di->next)
1033
if (di != d && di->serverVT)
1035
for (di = displays; di; di = di->next)
1036
if (di != d && di->serverVT &&
1037
(di->userSess >= 0 ||
1038
di->status == remoteLogin))
1040
ioctl(con, VT_ACTIVATE, vt);
1042
ioctl(con, VT_DISALLOCATE, d->serverVT);
1049
rStopDisplay(d, d->zstatus);
1052
debug("phoenix X server arises, restarting display %s\n",
1054
d->status = notRunning;
1057
debug("remote login X server for display %s exited\n",
1059
d->status = ((d->displayType & d_lifetime) == dReserve) ?
1060
reserve : notRunning;
1063
logError("X server for display %s terminated unexpectedly\n",
1065
/* don't kill again */
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();
1074
logError("X server for display %s terminated unexpectedly\n",
1077
debug("terminating session pid %d\n", d->pid);
1078
terminateProcess(d->pid, SIGTERM);
1084
/* this cannot happen */
1085
debug("X server exited for passive (%d) session on display %s\n",
1086
(int)d->status, d->name);
1090
debug("unknown child termination\n");
1101
switch (sdRec.force) {
1105
return !anyUserLogins(sdRec.uid);
1108
return !anyUserLogins(-1);
1112
fd_set wellKnownSocketsMask;
1113
int wellKnownSocketsMax;
1114
int wellKnownSocketsCount;
1117
registerInput(int fd)
1119
/* can be omited, as it is always called right after opening a socket
1120
if (!FD_ISSET(fd, &wellKnownSocketsMask))
1123
FD_SET(fd, &wellKnownSocketsMask);
1124
if (fd > wellKnownSocketsMax)
1125
wellKnownSocketsMax = fd;
1126
wellKnownSocketsCount++;
1131
unregisterInput(int fd)
1133
/* the check _is_ necessary, as some handles are unregistered before
1134
the regular close sequence.
1136
if (FD_ISSET(fd, &wellKnownSocketsMask)) {
1137
FD_CLR(fd, &wellKnownSocketsMask);
1138
wellKnownSocketsCount--;
1145
int olderrno = errno;
1147
/* debug("caught signal %d\n", n); this hangs in syslog() */
1148
write(signalFds[1], &buf, 1);
1150
(void)Signal(n, sigHandler);
1159
struct timeval *tvp, tv;
1165
debug("mainLoop\n");
1169
anyListenSockets() ||
1171
(stopping ? anyRunningDisplays() : anyDisplaysLeft()))
1176
to = disposeIndirectHosts();
1181
if (sdRec.start != TO_INF && now < sdRec.start) {
1182
/*if (sdRec.start < to)*/
1185
sdRec.start = TO_INF;
1186
if (now >= sdRec.timeout) {
1187
sdRec.timeout = TO_INF;
1188
if (wouldShutdown())
1194
/*if (sdRec.timeout < to)*/
1199
if (serverTimeout < to)
1201
if (utmpTimeout < to)
1213
reads = wellKnownSocketsMask;
1214
nready = select(wellKnownSocketsMax + 1, &reads, 0, 0, tvp);
1215
debug("select returns %d\n", nready);
1220
if (now >= serverTimeout) {
1221
serverTimeout = TO_INF;
1222
startServerTimeout();
1224
if (now >= utmpTimeout) {
1225
utmpTimeout = TO_INF;
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.
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");
1242
debug("shutting down entire manager\n");
1246
logInfo("Rescanning all config files\n");
1247
forEachDisplay(markDisplay);
1248
rescanConfigs(True);
1252
if (!stopping && autoRescan)
1253
rescanConfigs(False);
1256
if (startingServer && startingServer->serverStatus == starting)
1257
startServerSuccess();
1263
if (processListenSockets(&reads))
1266
if (handleCtrl(&reads, 0))
1268
/* Must be last (because of the breaks)! */
1270
for (d = displays; d; d = d->next) {
1271
if (handleCtrl(&reads, d))
1273
if (d->pipe.fd.r >= 0 && FD_ISSET(d->pipe.fd.r, &reads)) {
1277
if (d->gpipe.fd.r >= 0 && FD_ISSET(d->gpipe.fd.r, &reads)) {
1287
checkDisplayStatus(struct display *d)
1289
if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
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);
1301
kickDisplay(struct display *d)
1303
if (d->status == notRunning)
1305
if (d->serverStatus == awaiting && !startingServer)
1310
static int activeVTs;
1315
struct vt_stat vtstat;
1318
if (activeVTs == -1) {
1320
if ((con = open("/dev/console", O_RDONLY)) >= 0) {
1321
ioctl(con, VT_GETSTATE, &vtstat);
1324
activeVTs = vtstat.v_state;
1330
allocateVT(struct display *d)
1335
if ((d->displayType & d_location) == dLocal &&
1336
d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
1338
if (d->reqSrvVT && d->reqSrvVT < 16) {
1339
d->serverVT = d->reqSrvVT;
1341
for (i = tvt = 0;;) {
1343
tvt = atoi(serverVTs[i++]);
1349
if (!tvt || tvt >= 16)
1356
for (cd = displays; cd; cd = cd->next) {
1357
if (cd->reqSrvVT == tvt && /* protect from lusers */
1358
(cd->status != zombie || cd->zstatus != DS_REMOVE))
1360
if (cd->serverVT == tvt) {
1361
if (cd->status != zombie || cd->zstatus == DS_REMOTE)
1363
if (!cd->follower) {
1370
if (!volun || !((1 << tvt) & getBusyVTs())) {
1384
forEachDisplay(checkDisplayStatus);
1388
forEachDisplayRev(allocateVT);
1390
forEachDisplay(kickDisplay);
1394
startDisplay(struct display *d)
1397
debug("stopping display %s because shutdown is scheduled\n", d->name);
1403
if (d->serverVT < 0)
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
1413
d->pingInterval = 0;
1415
setLocalAuthorization(d);
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)
1422
if (d->serverPid != -1 && d->resetForAuth)
1423
kill(d->serverPid, SIGHUP);
1425
if (d->serverPid == -1) {
1426
d->serverStatus = awaiting;
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);
1439
startDisplayP2(struct display *d)
1441
char *cname, *cgname;
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)) {
1452
setproctitle("%s", d->name);
1454
ASPrintf(&prog, "%s: %s", prog, d->name);
1456
if (debugLevel & DEBUG_WSESS)
1458
mstrtalk.pipe = &d->pipe;
1459
(void)Signal(SIGPIPE, SIG_IGN);
1460
setAuthorization(d);
1462
if ((d->displayType & d_location) == dLocal) {
1464
if (Setjmp(mstrtalk.errjmp))
1465
exit(EX_UNMANAGE_DPY);
1466
gSendInt(D_XConnOk);
1472
d->status = notRunning;
1475
debug("forked session, pid %d\n", d->pid);
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);
1482
d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
1490
* transition from running to zombie, textmode, reserve or deleted
1494
rStopDisplay(struct display *d, int endState)
1496
debug("stopping display %s to state %d\n", d->name, endState);
1497
abortStartServer(d);
1498
if (d->serverPid != -1 || d->pid != -1) {
1500
terminateProcess(d->pid, SIGTERM);
1501
if (d->serverPid != -1)
1502
terminateProcess(d->serverPid, SIGTERM);
1504
d->zstatus = endState & DS_MASK;
1505
debug(" zombiefied\n");
1506
} else if (endState == DS_TEXTMODE) {
1508
d->status = textMode;
1510
} else if (endState == (DS_TEXTMODE | DS_SCHEDULE)) {
1511
d->status = textMode;
1515
} else if (endState == DS_RESERVE) {
1516
d->status = reserve;
1517
d->hstent->lastExit = 0;
1519
} else if (endState == DS_REMOTE) {
1520
startRemoteLogin(d);
1531
stopDisplay(struct display *d)
1533
rStopDisplay(d, DS_REMOVE);
1537
exitDisplay(struct display *d, int endState, int serverCmd, int goodExit)
1539
struct disphist *he;
1541
if (d->status == raiser) {
1542
serverCmd = XS_KEEP;
1546
debug("exitDisplay %s, "
1547
"endState = %d, serverCmd = %d, GoodExit = %d\n",
1548
d->name, endState, serverCmd, goodExit);
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);
1563
if (endState != DS_RESTART ||
1564
(d->displayType & d_lifetime) == dTransient)
1566
rStopDisplay(d, endState);
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);
1577
if (++d->startTries > d->startAttempts) {
1578
logError("Disabling foreign display %s"
1579
" (too many attempts)\n", d->name);
1587
if (d->serverPid != -1 &&
1588
(serverCmd != XS_KEEP || d->terminateServer))
1590
debug("killing X server for %s\n", d->name);
1591
terminateProcess(d->serverPid, SIGTERM);
1592
d->status = phoenix;
1594
d->status = notRunning;
1602
static FILE *pidFilePtr;
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",
1618
if (fscanf(pidFilePtr, "%d\n", &oldpid) != 1)
1620
fseek(pidFilePtr, 0l, 0);
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)
1638
if (flock(pidFd, LOCK_EX | LOCK_NB) == -1) {
1639
if (errno == EWOULDBLOCK)
1645
if (lockf(pidFd, F_TLOCK, 0) == -1) {
1646
if (errno == EACCES)
1654
fprintf(pidFilePtr, "%ld\n", (long)getpid());
1655
if (fflush(pidFilePtr) == EOF)
1656
logError("Cannot write PID file %s: %m", pidFile);
1657
registerCloseOnFork(pidFd);
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);
1677
lockf(pidFd, F_ULOCK, 0);
1679
flock(pidFd, LOCK_UN);
1687
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
1689
setproctitle(const char *fmt, ...)
1694
int left = titleLen;
1697
va_start(args, fmt);
1698
VASPrintf(&oname, fmt, args);
1701
if ((name = oname)) {
1704
while (*name && left > 0) {