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 startDisplays( void );
59
static void exitDisplay( struct display *d, int endState, int serverCmd, int goodExit );
60
static void rStopDisplay( struct display *d, int endState );
61
static void mainLoop( void );
63
static int signalFds[2];
65
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
70
static int storePid( void );
73
SdRec sdRec = { 0, 0, 0, TO_INF, TO_INF, 0, 0, 0 };
77
char *prog, *progpath;
80
main( int argc, char **argv )
82
int oldpid, oldumask, fd, noDaemonMode;
83
char *pt, *errorLogFile, **opts;
85
/* make sure at least world write access is disabled */
86
if (((oldumask = umask( 022 )) & 002) == 002)
87
(void)umask( oldumask );
89
/* give /dev/null as stdin */
90
if ((fd = open( "/dev/null", O_RDONLY )) > 0) {
94
if (fcntl( 1, F_GETFD ) < 0)
96
if (fcntl( 2, F_GETFD ) < 0)
99
if (argv[0][0] == '/') {
100
if (!strDup( &progpath, argv[0] ))
101
panic( "Out of memory" );
105
/* note that this will resolve symlinks ... */
107
char fullpath[PATH_MAX];
108
if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0)
109
panic( "Invoke with full path specification or mount /proc" );
110
if (!strNDup( &progpath, fullpath, len ))
111
panic( "Out of memory" );
115
panic( "Must be invoked with full path specification" );
118
char directory[PATH_MAX+1];
119
if (!getcwd( directory, sizeof(directory) ))
120
panic( "Can't find myself (getcwd failed)" );
121
if (strchr( argv[0], '/' ))
122
strApp( &progpath, directory, "/", argv[0], (char *)0 );
125
char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
127
if (!(path = getenv( "PATH" )))
128
panic( "Can't find myself (no PATH)" );
129
len = strlen( argv[0] );
130
name = nambuf + PATH_MAX - len;
131
memcpy( name, argv[0], len + 1 );
134
if (!(pathe = strchr( path, ':' )))
135
pathe = path + strlen( path );
137
if (!len || (len == 1 && *path == '.')) {
138
len = strlen( directory );
142
if (thenam >= nambuf) {
143
memcpy( thenam, path, len );
144
if (!access( thenam, X_OK ))
148
} while (*path++ != '\0');
149
panic( "Can't find myself (not in PATH)" );
151
if (!strDup( &progpath, thenam ))
152
panic( "Out of memory" );
157
prog = strrchr( progpath, '/' ) + 1;
159
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
161
titleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - title;
165
* Parse command line options
167
noDaemonMode = getppid();
169
if (!(opts = Malloc( 2 * sizeof(char *) )))
171
opts[0] = (char *)"";
179
if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) {
180
printf( "Usage: %s [options] [tty]\n"
181
" -daemon\t - Daemonize even when started by init\n"
182
" -nodaemon\t - Don't daemonize even when started from command line\n"
183
" -config <file> - Use alternative master configuration file\n"
184
" -xrm <res>\t - Override frontend-specific resource\n"
185
" -error <file>\t - Use alternative log file\n"
186
" -debug <num>\t - Debug option bitfield:\n"
187
"\t\t\t0x1 - core log\n"
188
"\t\t\t0x2 - config reader log\n"
189
"\t\t\t0x4 - greeter log\n"
190
"\t\t\t0x8 - IPC log\n"
191
"\t\t\t0x10 - session sub-daemon post-fork delay\n"
192
"\t\t\t0x20 - config reader post-start delay\n"
193
"\t\t\t0x40 - greeter post-start delay\n"
194
"\t\t\t0x80 - don't use syslog\n"
195
"\t\t\t0x100 - core Xauth log\n"
196
"\t\t\t0x200 - debug greeter theming\n"
197
"\t\t\t0x400 - valgrind config reader and greeter\n"
198
"\t\t\t0x800 - strace config reader and greeter\n"
201
} else if (!strcmp( pt, "daemon" ))
203
else if (!strcmp( pt, "nodaemon" ))
205
else if (argv[1] && !strcmp( pt, "config" ))
206
strDup( opts, *++argv );
207
else if (argv[1] && !strcmp( pt, "xrm" ))
208
opts = addStrArr( opts, *++argv, -1 );
209
else if (argv[1] && !strcmp( pt, "debug" ))
210
sscanf( *++argv, "%i", &debugLevel );
211
else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" )))
212
errorLogFile = *++argv;
214
fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv );
220
* Only allow root to run in non-debug mode to avoid problems
222
if (!debugLevel && getuid()) {
223
fprintf( stderr, "Only root wants to run %s\n", prog );
227
initErrorLog( errorLogFile );
229
if (noDaemonMode != 1)
233
* Step 1 - load configuration parameters
235
if (!initResources( opts ) || scanConfigs( FALSE ) < 0)
236
logPanic( "Config reader failed. Aborting ...\n" );
239
if ((oldpid = storePid())) {
241
logError( "Can't create/lock pid file %s\n", pidFile );
243
logError( "Can't lock pid file %s, another xdm is running (pid %d)\n",
253
* We used to clean up old authorization files here. As authDir is
254
* supposed to be /var/run/xauth or /tmp, we needn't to care for it.
260
debug( "not compiled for XDMCP\n" );
262
if (pipe( signalFds ))
263
logPanic( "Unable to create signal notification pipe.\n" );
264
registerInput( signalFds[0] );
265
registerCloseOnFork( signalFds[0] );
266
registerCloseOnFork( signalFds[1] );
267
(void)Signal( SIGTERM, sigHandler );
268
(void)Signal( SIGINT, sigHandler );
269
(void)Signal( SIGHUP, sigHandler );
270
(void)Signal( SIGCHLD, sigHandler );
271
(void)Signal( SIGUSR1, sigHandler );
274
* Step 2 - run a sub-daemon for each entry
277
updateListenSockets();
285
if (Fork( &pid ) <= 0) {
286
char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot;
287
execute( parseArgs( (char **)0, cmd ), (char **)0 );
288
logError( "Failed to execute shutdown command %\"s\n", cmd );
292
sigemptyset( &mask );
293
sigaddset( &mask, SIGCHLD );
294
sigaddset( &mask, SIGHUP );
298
debug( "nothing left to do, exiting\n" );
305
TTYtoVT( const char *tty )
307
return memcmp( tty, "tty", 3 ) ? 0 : atoi( tty + 3 );
314
int con = open( "/dev/console", O_RDONLY );
316
if (!ioctl( con, VT_ACTIVATE, vt ))
325
wakeDisplay( struct display *d )
327
if (d->status == textMode)
328
d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
332
enum utState { UtDead, UtWait, UtActive };
345
#define TIME_RELOG 10
347
static struct utmps *utmpList;
348
static time_t utmpTimeout = TO_INF;
355
while ((utp = utmpList)) {
357
forEachDisplay( wakeDisplay );
359
utp->d->status = notRunning;
361
utmpList = utp->next;
369
static time_t modtim;
372
struct utmps *utp, **utpp;
383
if (stat( UTMP_FILE, &st )) {
384
logError( UTMP_FILE " not found - cannot use console mode\n" );
388
if (modtim != st.st_mtime) {
389
debug( "rescanning " UTMP_FILE "\n" );
390
for (utp = utmpList; utp; utp = utp->next)
393
if ((fd = open( UTMP_FILE, O_RDONLY )) < 0) {
394
logError( "Cannot open " UTMP_FILE " - cannot use console mode\n" );
398
while (reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0]))
401
while ((ut = GETUTENT()))
404
for (utp = utmpList; utp; utp = utp->next) {
407
for (line = consoleTTYs; *line; line++)
408
if (!strncmp( *line, ut->ut_line, sizeof(ut->ut_line) ))
413
if (strncmp( utp->d->console, ut->ut_line, sizeof(ut->ut_line) ))
419
if (ut->ut_type != USER_PROCESS) {
422
if (utp->state == UtActive)
428
utp->state = UtActive;
430
if (utp->time < ut->ut_time) /* theoretically superfluous */
431
utp->time = ut->ut_time;
440
modtim = st.st_mtime;
442
for (utpp = &utmpList; (utp = *utpp); ) {
443
if (utp->state != UtActive) {
444
if (utp->state == UtDead) /* shouldn't happen ... */
446
ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
449
forEachDisplay( wakeDisplay );
450
debug( "console login timed out\n" );
452
utp->d->status = notRunning;
453
debug( "console login for %s at %s timed out\n",
454
utp->d->name, utp->d->console );
462
nck = TIME_RELOG + now;
463
if (nck < utmpTimeout)
465
utpp = &(*utpp)->next;
473
switchToTTY( struct display *d )
481
if (!(utp = Malloc( sizeof(*utp) ))) {
483
forEachDisplay( wakeDisplay );
485
d->status = notRunning;
490
d->status = textMode;
495
utp->next = utmpList;
500
if ((vt = TTYtoVT( *consoleTTYs )))
504
/* XXX output something useful here */
509
stopToTTY( struct display *d )
511
if ((d->displayType & d_location) == dLocal)
514
rStopDisplay( d, DS_TEXTMODE | 0x100 );
526
for (d = displays; d; d = d->next)
527
if (d->status == zombie)
536
switchToX( struct display *d )
538
struct utmps *utp, **utpp;
540
for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
544
d->status = notRunning;
552
startRemoteLogin( struct display *d )
556
debug( "startRemoteLogin for %s\n", d->name );
557
/* HACK: omitting loadDisplayResources( d ) here! */
558
switch (Fork( &d->serverPid )) {
560
argv = prepareServerArgv( d, d->serverArgsRemote );
561
if (!(argv = addStrArr( argv, "-once", 5 )) ||
562
!(argv = addStrArr( argv, "-query", 6 )) ||
563
!(argv = addStrArr( argv, d->remoteHost, -1 )))
565
debug( "exec %\"[s\n", argv );
566
(void)execv( argv[0], argv );
567
logError( "X server %\"s cannot be executed\n", argv[0] );
570
logError( "Forking X server for remote login failed: %m" );
571
d->status = notRunning;
576
debug( "X server forked, pid %d\n", d->serverPid );
578
d->status = remoteLogin;
584
stopInactiveDisplay( struct display *d )
586
if (d->status != remoteLogin && d->userSess < 0)
595
updateListenSockets();
598
forEachDisplay( stopDisplay );
600
forEachDisplay( stopInactiveDisplay );
606
setNLogin( struct display *d,
607
const char *nuser, const char *npass, char *nargs, int rl )
609
struct disphist *he = d->hstent;
611
(reStr( &he->nuser, nuser ) &&
612
reStr( &he->npass, npass ) &&
613
reStr( &he->nargs, nargs )) ? rl : 0;
614
debug( "set next login for %s, level %d\n", nuser, rl );
618
processDPipe( struct display *d )
620
char *user, *pass, *args;
628
dpytalk.pipe = &d->pipe;
629
if (Setjmp( dpytalk.errjmp )) {
634
if (!gRecvCmd( &cmd )) {
635
/* process already exited */
636
unregisterInput( d->pipe.fd.r );
641
d->userSess = gRecvInt();
642
d->userName = gRecvStr();
643
d->sessName = gRecvStr();
649
setNLogin( d, user, pass, args, 1 );
656
ca.data = (unsigned char *)gRecvArr( &len );
657
ca.length = (CARD16)len;
659
ha.data = (unsigned char *)gRecvArr( &len );
660
ha.length = (CARD16)len;
661
registerindirectChoice( &ca, ct, &ha );
662
XdmcpDisposeARRAY8( &ha );
663
XdmcpDisposeARRAY8( &ca );
667
free( d->remoteHost );
668
d->remoteHost = gRecvStr();
675
logError( "Internal error: unknown D_* command %d\n", cmd );
682
emitXSessG( struct display *di, struct display *d, void *ctx ATTR_UNUSED )
684
gSendStr( di->name );
687
gSendInt( di->serverVT );
690
if (di->status == remoteLogin) {
692
gSendStr( di->remoteHost );
696
gSendStr( di->userName );
697
gSendStr( di->sessName );
699
gSendInt( di == d ? isSelf : 0 );
703
emitTTYSessG( STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED )
705
gSendStrN( ut->ut_line, sizeof(ut->ut_line) );
706
gSendStrN( ut->ut_host, sizeof(ut->ut_host) );
708
gSendInt( TTYtoVT( ut->ut_line ) );
711
gSendStrN( *ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user) );
713
gSendStrN( ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user) );
715
gSendStr( 0 ); /* session type unknown */
720
processGPipe( struct display *d )
722
char **opts, *option;
723
int cmd, ret, dflt, curr;
726
dpytalk.pipe = &d->gpipe;
727
if (Setjmp( dpytalk.errjmp )) {
732
if (!gRecvCmd( &cmd )) {
733
/* process already exited */
734
unregisterInput( d->gpipe.fd.r );
739
ret = getBootOptions( &opts, &dflt, &curr );
749
sdRec.how = gRecvInt();
750
sdRec.start = gRecvInt();
751
sdRec.timeout = gRecvInt();
752
sdRec.force = gRecvInt();
753
sdRec.uid = gRecvInt();
755
setBootOption( option, &sdRec );
759
case G_QueryShutdown:
760
gSendInt( sdRec.how );
761
gSendInt( sdRec.start );
762
gSendInt( sdRec.timeout );
763
gSendInt( sdRec.force );
764
gSendInt( sdRec.uid );
765
gSendStr( sdRec.osname );
768
listSessions( gRecvInt(), d, 0, emitXSessG, emitTTYSessG );
773
activateVT( gRecvInt() );
778
if (*consoleTTYs) { /* sanity check against greeter */
779
forEachDisplay( stopToTTY );
783
if (*d->console) /* sanity check against greeter */
784
rStopDisplay( d, DS_TEXTMODE );
788
logError( "Internal error: unknown G_* command %d\n", cmd );
796
scanConfigs( int force )
800
if ((ret = loadDMResources( force )) <= 0)
804
scanAccessDatabase( force );
810
markDisplay( struct display *d )
816
rescanConfigs( int force )
818
if (scanConfigs( force ) > 0) {
820
updateListenSockets();
827
cancelShutdown( void )
831
free( sdRec.osname );
835
rescanConfigs( TRUE );
846
while ((pid = waitpid( -1, &status, WNOHANG )) > 0)
848
debug( "manager wait returns pid %d sig %d core %d code %d\n",
849
pid, waitSig( status ), waitCore( status ), waitCode( status ) );
851
if ((d = findDisplayByPid( pid ))) {
853
unregisterInput( d->pipe.fd.r );
855
unregisterInput( d->gpipe.fd.r );
856
gClosen( &d->gpipe );
858
switch (wcFromWait( status )) {
861
debug( "display exited with EX_REMOTE\n" );
862
exitDisplay( d, DS_REMOTE, 0, 0 );
866
/* (any type of) session ended */
867
debug( "display exited with EX_NORMAL\n" );
868
if ((d->displayType & d_lifetime) == dReserve)
869
exitDisplay( d, DS_RESERVE, 0, 0 );
871
exitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
874
debug( "display exited with EX_RESERVE\n" );
875
exitDisplay( d, DS_RESERVE, 0, 0 );
878
case EX_REMANAGE_DPY:
879
/* user session ended */
880
debug( "display exited with EX_REMANAGE_DPY\n" );
881
exitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
884
case EX_OPENFAILED_DPY:
885
/* waitForServer() failed */
886
logError( "Display %s cannot be opened\n", d->name );
889
* no display connection was ever made, tell the
890
* terminal that the open attempt failed
892
if ((d->displayType & d_origin) == dFromXDMCP)
893
sendFailed( d, "cannot open display" );
895
exitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
897
case wcCompose( SIGTERM,0,0 ):
898
/* killed before/during waitForServer()
900
- display stopped (is zombie)
901
- "login now" and "suicide" pipe commands (is raiser)
903
debug( "display exited on SIGTERM\n" );
904
exitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
906
case EX_AL_RESERVER_DPY:
907
/* - killed after waitForServer()
908
- Xserver dead after remote session exit
910
debug( "display exited with EX_AL_RESERVER_DPY\n" );
911
exitDisplay( d, DS_RESTART, XS_RESTART, FALSE );
913
case EX_RESERVER_DPY:
914
/* induced by greeter:
915
- could not secure display
918
debug( "display exited with EX_RESERVER_DPY\n" );
919
exitDisplay( d, DS_RESTART, XS_RESTART, TRUE );
921
case EX_UNMANAGE_DPY:
922
/* some fatal error */
923
debug( "display exited with EX_UNMANAGE_DPY\n" );
924
exitDisplay( d, DS_REMOVE, 0, 0 );
928
logError( "Unknown session exit code %d (sig %d) from manager process\n",
929
waitCode( status ), waitSig( status ) );
930
exitDisplay( d, DS_REMOVE, 0, 0 );
933
} else if ((d = findDisplayByServerPid( pid ))) {
937
debug( "zombie X server for display %s reaped\n", d->name );
939
if (d->serverVT && d->zstatus != DS_REMOTE) {
941
d->follower->serverVT = d->serverVT;
944
int con = open( "/dev/console", O_RDONLY );
946
struct vt_stat vtstat;
947
ioctl( con, VT_GETSTATE, &vtstat );
948
if (vtstat.v_active == d->serverVT) {
951
for (di = displays; di; di = di->next)
952
if (di != d && di->serverVT)
954
for (di = displays; di; di = di->next)
955
if (di != d && di->serverVT &&
956
(di->userSess >= 0 ||
957
di->status == remoteLogin))
959
ioctl( con, VT_ACTIVATE, vt );
961
ioctl( con, VT_DISALLOCATE, d->serverVT );
968
rStopDisplay( d, d->zstatus );
971
debug( "phoenix X server arises, restarting display %s\n",
973
d->status = notRunning;
976
debug( "remote login X server for display %s exited\n",
978
d->status = ((d->displayType & d_lifetime) == dReserve) ?
979
reserve : notRunning;
982
logError( "X server for display %s terminated unexpectedly\n",
984
/* don't kill again */
987
if (startingServer == d && d->serverStatus != ignore) {
988
if (d->serverStatus == starting && waitCode( status ) != 47)
989
logError( "X server died during startup\n" );
993
logError( "X server for display %s terminated unexpectedly\n",
996
debug( "terminating session pid %d\n", d->pid );
997
terminateProcess( d->pid, SIGTERM );
1003
/* this cannot happen */
1004
debug( "X server exited for passive (%d) session on display %s\n",
1005
(int)d->status, d->name );
1009
debug( "unknown child termination\n" );
1017
wouldShutdown( void )
1021
if (sdRec.force != SHUT_CANCEL) {
1022
if (sdRec.force == SHUT_FORCEMY)
1023
for (d = displays; d; d = d->next)
1024
if (d->status == remoteLogin ||
1025
(d->userSess >= 0 && d->userSess != sdRec.uid))
1029
return !anyActiveDisplays();
1032
fd_set wellKnownSocketsMask;
1033
int wellKnownSocketsMax;
1034
int wellKnownSocketsCount;
1037
registerInput( int fd )
1039
/* can be omited, as it is always called right after opening a socket
1040
if (!FD_ISSET( fd, &wellKnownSocketsMask ))
1043
FD_SET( fd, &wellKnownSocketsMask );
1044
if (fd > wellKnownSocketsMax)
1045
wellKnownSocketsMax = fd;
1046
wellKnownSocketsCount++;
1051
unregisterInput( int fd )
1053
/* the check _is_ necessary, as some handles are unregistered before
1054
the regular close sequence.
1056
if (FD_ISSET( fd, &wellKnownSocketsMask )) {
1057
FD_CLR( fd, &wellKnownSocketsMask );
1058
wellKnownSocketsCount--;
1065
int olderrno = errno;
1067
/* debug( "caught signal %d\n", n ); this hangs in syslog() */
1068
write( signalFds[1], &buf, 1 );
1070
(void)Signal( n, sigHandler );
1079
struct timeval *tvp, tv;
1085
debug( "mainLoop\n" );
1089
anyListenSockets() ||
1091
(stopping ? anyRunningDisplays() : anyDisplaysLeft()))
1097
if (sdRec.start != TO_INF && now < sdRec.start) {
1098
/*if (sdRec.start < to)*/
1101
sdRec.start = TO_INF;
1102
if (now >= sdRec.timeout) {
1103
sdRec.timeout = TO_INF;
1104
if (wouldShutdown())
1110
/*if (sdRec.timeout < to)*/
1115
if (serverTimeout < to)
1117
if (utmpTimeout < to)
1129
reads = wellKnownSocketsMask;
1130
nready = select( wellKnownSocketsMax + 1, &reads, 0, 0, tvp );
1131
debug( "select returns %d\n", nready );
1136
if (now >= serverTimeout) {
1137
serverTimeout = TO_INF;
1138
startServerTimeout();
1140
if (now >= utmpTimeout) {
1141
utmpTimeout = TO_INF;
1146
* we restart after the first handled fd, as
1147
* a) it makes things simpler
1148
* b) the probability that multiple fds trigger at once is
1149
* ridiculously small. we handle it in the next iteration.
1151
/* XXX a cleaner solution would be a callback mechanism */
1152
if (FD_ISSET( signalFds[0], &reads )) {
1153
if (read( signalFds[0], &buf, 1 ) != 1)
1154
logPanic( "Signal notification pipe broken.\n" );
1158
debug( "shutting down entire manager\n" );
1162
logInfo( "Rescanning all config files\n" );
1163
forEachDisplay( markDisplay );
1164
rescanConfigs( TRUE );
1168
if (!stopping && autoRescan)
1169
rescanConfigs( FALSE );
1172
if (startingServer &&
1173
startingServer->serverStatus == starting)
1174
startServerSuccess();
1180
if (processListenSockets( &reads ))
1183
if (handleCtrl( &reads, 0 ))
1185
/* Must be last (because of the breaks)! */
1187
for (d = displays; d; d = d->next) {
1188
if (handleCtrl( &reads, d ))
1190
if (d->pipe.fd.r >= 0 && FD_ISSET( d->pipe.fd.r, &reads )) {
1194
if (d->gpipe.fd.r >= 0 && FD_ISSET( d->gpipe.fd.r, &reads )) {
1204
checkDisplayStatus( struct display *d )
1206
if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
1208
else if ((d->displayType & d_lifetime) == dReserve &&
1209
d->status == running && d->userSess < 0 && !d->idleTimeout)
1210
rStopDisplay( d, DS_RESERVE );
1211
else if (d->status == notRunning)
1212
if (loadDisplayResources( d ) < 0) {
1213
logError( "Unable to read configuration for display %s; "
1214
"stopping it.\n", d->name );
1221
kickDisplay( struct display *d )
1223
if (d->status == notRunning)
1225
if (d->serverStatus == awaiting && !startingServer)
1230
static int activeVTs;
1235
struct vt_stat vtstat;
1238
if (activeVTs == -1) {
1240
if ((con = open( "/dev/console", O_RDONLY )) >= 0) {
1241
ioctl( con, VT_GETSTATE, &vtstat );
1244
activeVTs = vtstat.v_state;
1250
allocateVT( struct display *d )
1255
if ((d->displayType & d_location) == dLocal &&
1256
d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
1258
if (d->reqSrvVT && d->reqSrvVT < 16)
1259
d->serverVT = d->reqSrvVT;
1261
for (i = tvt = 0;;) {
1263
tvt = atoi( serverVTs[i++] );
1269
if (!tvt || tvt >= 16)
1276
for (cd = displays; cd; cd = cd->next) {
1277
if (cd->reqSrvVT == tvt && /* protect from lusers */
1278
(cd->status != zombie || cd->zstatus != DS_REMOVE))
1280
if (cd->serverVT == tvt) {
1281
if (cd->status != zombie || cd->zstatus == DS_REMOTE)
1283
if (!cd->follower) {
1290
if (!volun || !((1 << tvt) & getBusyVTs())) {
1302
startDisplays( void )
1304
forEachDisplay( checkDisplayStatus );
1308
forEachDisplayRev( allocateVT );
1310
forEachDisplay( kickDisplay );
1314
startDisplay( struct display *d )
1317
debug( "stopping display %s because shutdown is scheduled\n", d->name );
1323
if (d->serverVT < 0)
1327
d->status = running;
1328
if ((d->displayType & d_location) == dLocal) {
1329
debug( "startDisplay %s\n", d->name );
1330
/* don't bother pinging local displays; we'll
1331
* certainly notice when they exit
1333
d->pingInterval = 0;
1335
setLocalAuthorization( d );
1337
* reset the server after writing the authorization information
1338
* to make it read the file (for compatibility with old
1339
* servers which read auth file only on reset instead of
1340
* at first connection)
1342
if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
1343
kill( d->serverPid, d->resetSignal );
1345
if (d->serverPid == -1) {
1346
d->serverStatus = awaiting;
1350
debug( "startDisplay %s, try %d\n", d->name, d->startTries + 1 );
1351
/* this will only happen when using XDMCP */
1352
if (d->authorizations)
1353
saveServerAuthorizations( d, d->authorizations, d->authNum );
1355
startDisplayP2( d );
1359
startDisplayP2( struct display *d )
1361
char *cname, *cgname;
1364
debug( "forking session\n" );
1365
ASPrintf( &cname, "sub-daemon for display %s", d->name );
1366
ASPrintf( &cgname, "greeter for display %s", d->name );
1367
switch (gFork( &d->pipe, "master daemon", cname,
1368
&d->gpipe, cgname, 0, &d->pid ))
1372
setproctitle( "%s", d->name );
1374
ASPrintf( &prog, "%s: %s", prog, d->name );
1376
if (debugLevel & DEBUG_WSESS)
1378
mstrtalk.pipe = &d->pipe;
1379
(void)Signal( SIGPIPE, SIG_IGN );
1380
setAuthorization( d );
1382
if ((d->displayType & d_location) == dLocal) {
1384
gSendInt( D_XConnOk );
1390
d->status = notRunning;
1393
debug( "forked session, pid %d\n", d->pid );
1395
/* (void) fcntl (d->pipe.fd.r, F_SETFL, O_NONBLOCK); */
1396
/* (void) fcntl (d->gpipe.fd.r, F_SETFL, O_NONBLOCK); */
1397
registerInput( d->pipe.fd.r );
1398
registerInput( d->gpipe.fd.r );
1400
d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
1401
d->hstent->sdRec.how = 0;
1408
* transition from running to zombie, textmode, reserve or deleted
1412
rStopDisplay( struct display *d, int endState )
1414
debug( "stopping display %s to state %d\n", d->name, endState );
1415
abortStartServer( d );
1417
if (d->serverPid != -1 || d->pid != -1) {
1419
terminateProcess( d->pid, SIGTERM );
1420
if (d->serverPid != -1)
1421
terminateProcess( d->serverPid, d->termSignal );
1423
d->zstatus = endState & 0xff;
1424
debug( " zombiefied\n" );
1425
} else if (endState == DS_TEXTMODE) {
1427
d->status = textMode;
1429
} else if (endState == (DS_TEXTMODE | 0x100)) {
1430
d->status = textMode;
1434
} else if (endState == DS_RESERVE)
1435
d->status = reserve;
1437
else if (endState == DS_REMOTE)
1438
startRemoteLogin( d );
1449
stopDisplay( struct display *d )
1451
rStopDisplay( d, DS_REMOVE );
1455
exitDisplay( struct display *d,
1460
struct disphist *he;
1462
if (d->status == raiser) {
1463
serverCmd = XS_KEEP;
1467
debug( "exitDisplay %s, "
1468
"endState = %d, serverCmd = %d, GoodExit = %d\n",
1469
d->name, endState, serverCmd, goodExit );
1473
free( d->userName );
1476
free( d->sessName );
1480
he->goodExit = goodExit;
1481
if (he->sdRec.how) {
1482
if (he->sdRec.force == SHUT_ASK &&
1483
(anyActiveDisplays() || d->allowShutdown == SHUT_ROOT))
1485
endState = DS_RESTART;
1487
if (!sdRec.how || sdRec.force != SHUT_FORCE ||
1488
!((d->allowNuke == SHUT_NONE && sdRec.uid != he->sdRec.uid) ||
1489
(d->allowNuke == SHUT_ROOT && he->sdRec.uid)))
1492
free( sdRec.osname );
1494
if (now < sdRec.timeout || wouldShutdown())
1495
endState = DS_REMOVE;
1496
} else if (he->sdRec.osname)
1497
free( he->sdRec.osname );
1499
he->sdRec.osname = 0;
1502
if (d->status == zombie)
1503
rStopDisplay( d, d->zstatus );
1509
if (endState != DS_RESTART ||
1510
(d->displayType & d_origin) != dFromFile)
1512
rStopDisplay( d, endState );
1514
if (serverCmd == XS_RETRY) {
1515
if ((d->displayType & d_location) == dLocal) {
1516
if (he->lastExit - d->lastStart < 120) {
1517
logError( "Unable to fire up local display %s;"
1518
" disabling.\n", d->name );
1523
if (++d->startTries > d->startAttempts) {
1524
logError( "Disabling foreign display %s"
1525
" (too many attempts)\n", d->name );
1532
if (d->serverPid != -1 &&
1533
(serverCmd != XS_KEEP || d->terminateServer))
1535
debug( "killing X server for %s\n", d->name );
1536
terminateProcess( d->serverPid, d->termSignal );
1537
d->status = phoenix;
1539
d->status = notRunning;
1546
static FILE *pidFilePtr;
1553
if (pidFile[0] != '\0') {
1554
pidFd = open( pidFile, O_RDWR );
1555
if (pidFd == -1 && errno == ENOENT)
1556
pidFd = open( pidFile, O_RDWR|O_CREAT, 0666 );
1557
if (pidFd == -1 || !(pidFilePtr = fdopen( pidFd, "r+" ))) {
1558
logError( "process-id file %s cannot be opened\n",
1562
if (fscanf( pidFilePtr, "%d\n", &oldpid ) != 1)
1564
fseek( pidFilePtr, 0l, 0 );
1570
struct flock lock_data;
1571
lock_data.l_type = F_WRLCK;
1572
lock_data.l_whence = SEEK_SET;
1573
lock_data.l_start = lock_data.l_len = 0;
1574
if (fcntl( pidFd, F_SETLK, &lock_data ) == -1) {
1575
if (errno == EAGAIN)
1582
if (flock( pidFd, LOCK_EX|LOCK_NB ) == -1) {
1583
if (errno == EWOULDBLOCK)
1589
if (lockf( pidFd, F_TLOCK, 0 ) == -1) {
1590
if (errno == EACCES)
1598
fprintf( pidFilePtr, "%ld\n", (long)getpid() );
1599
(void)fflush( pidFilePtr );
1600
registerCloseOnFork( pidFd );
1607
UnlockPidFile( void )
1612
struct flock lock_data;
1613
lock_data.l_type = F_UNLCK;
1614
lock_data.l_whence = SEEK_SET;
1615
lock_data.l_start = lock_data.l_len = 0;
1616
(void)fcntl( pidFd, F_SETLK, &lock_data );
1620
lockf( pidFd, F_ULOCK, 0 );
1622
flock( pidFd, LOCK_UN );
1626
fclose( pidFilePtr );
1630
#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
1632
setproctitle( const char *fmt, ... )
1637
int left = titleLen;
1640
va_start( args, fmt );
1641
VASPrintf( &oname, fmt, args );
1644
if ((name = oname)) {
1647
while (*name && left > 0) {