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 #if KDM_LIBEXEC_STRIP != -1
86 main( int argc
, char **argv
)
88 int oldpid
, oldumask
, fd
, parentPid
;
89 char *pt
, *errorLogFile
, **opts
;
91 /* make sure at least world write access is disabled */
92 if (((oldumask
= umask( 022 )) & 002) == 002)
93 (void)umask( oldumask
);
95 /* give /dev/null as stdin */
96 if ((fd
= open( "/dev/null", O_RDONLY
)) > 0) {
100 if (fcntl( 1, F_GETFD
) < 0)
102 if (fcntl( 2, F_GETFD
) < 0)
105 #if KDM_LIBEXEC_STRIP == -1
106 prog
= strrchr( argv
[0], '/' );
107 progname
= prog
= prog
? prog
+ 1 : argv
[0];
109 if (argv
[0][0] == '/') {
110 if (!strDup( &progpath
, argv
[0] ))
111 panic( "Out of memory" );
115 /* note that this will resolve symlinks ... */
117 char fullpath
[PATH_MAX
];
118 if ((len
= readlink( "/proc/self/exe", fullpath
, sizeof(fullpath
) )) < 0)
119 panic( "Invoke with full path specification or mount /proc" );
120 if (!strNDup( &progpath
, fullpath
, len
))
121 panic( "Out of memory" );
125 panic( "Must be invoked with full path specification" );
128 char directory
[PATH_MAX
+1];
129 if (!getcwd( directory
, sizeof(directory
) ))
130 panic( "Can't find myself (getcwd failed)" );
131 if (strchr( argv
[0], '/' ))
132 strApp( &progpath
, directory
, "/", argv
[0], (char *)0 );
135 char *path
, *pathe
, *name
, *thenam
, nambuf
[PATH_MAX
+1];
137 if (!(path
= getenv( "PATH" )))
138 panic( "Can't find myself (no PATH)" );
139 len
= strlen( argv
[0] );
140 name
= nambuf
+ PATH_MAX
- len
;
141 memcpy( name
, argv
[0], len
+ 1 );
144 if (!(pathe
= strchr( path
, ':' )))
145 pathe
= path
+ strlen( path
);
147 if (!len
|| (len
== 1 && *path
== '.')) {
148 len
= strlen( directory
);
152 if (thenam
>= nambuf
) {
153 memcpy( thenam
, path
, len
);
154 if (!access( thenam
, X_OK
))
158 } while (*path
++ != '\0');
159 panic( "Can't find myself (not in PATH)" );
161 if (!strDup( &progpath
, thenam
))
162 panic( "Out of memory" );
167 prog
= strrchr( progpath
, '/' ) + 1;
168 # if KDM_LIBEXEC_STRIP
169 for (progname
= pt
= prog
, fd
= 0; fd
< KDM_LIBEXEC_STRIP
+ 1; fd
++) {
173 panic( "Executable is obviously located outside BINDIR" );
182 #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
184 titleLen
= (argv
[argc
- 1] + strlen( argv
[argc
- 1] )) - title
;
188 * Parse command line options
190 parentPid
= getppid();
192 if (!(opts
= Malloc( 2 * sizeof(char *) )))
194 opts
[0] = (char *)"";
202 if (!strcmp( pt
, "help" ) || !strcmp( pt
, "h" )) {
203 printf( "Usage: %s [options] [tty]\n"
204 " -daemon\t - Daemonize even when started by init\n"
205 " -nodaemon\t - Do not daemonize even when started from command line\n"
206 " -config <file> - Use alternative master configuration file\n"
207 " -xrm <res>\t - Override frontend-specific resource\n"
208 " -error <file>\t - Use alternative log file\n"
209 " -debug <num>\t - Debug option bitfield:\n"
210 "\t\t\t0x1 - core log\n"
211 "\t\t\t0x2 - config reader log\n"
212 "\t\t\t0x4 - greeter log\n"
213 "\t\t\t0x8 - IPC log\n"
214 "\t\t\t0x10 - session sub-daemon post-fork delay\n"
215 "\t\t\t0x20 - config reader post-start delay\n"
216 "\t\t\t0x40 - greeter post-start delay\n"
217 "\t\t\t0x80 - do not use syslog\n"
218 "\t\t\t0x100 - core Xauth log\n"
219 "\t\t\t0x200 - debug greeter theming\n"
220 "\t\t\t0x400 - valgrind config reader and greeter\n"
221 "\t\t\t0x800 - strace config reader and greeter\n"
224 } else if (!strcmp( pt
, "daemon" ))
226 else if (!strcmp( pt
, "nodaemon" ))
228 else if (argv
[1] && !strcmp( pt
, "config" ))
229 strDup( opts
, *++argv
);
230 else if (argv
[1] && !strcmp( pt
, "xrm" ))
231 opts
= addStrArr( opts
, *++argv
, -1 );
232 else if (argv
[1] && !strcmp( pt
, "debug" ))
233 sscanf( *++argv
, "%i", &debugLevel
);
234 else if (argv
[1] && (!strcmp( pt
, "error" ) || !strcmp( pt
, "logfile" )))
235 errorLogFile
= *++argv
;
237 fprintf( stderr
, "\"%s\" is an unknown option or is missing a parameter\n", *argv
);
243 * Only allow root to run in non-debug mode to avoid problems
245 if (!debugLevel
&& getuid()) {
246 fprintf( stderr
, "Only root wants to run %s\n", prog
);
250 initErrorLog( errorLogFile
);
256 * Step 1 - load configuration parameters
258 if (!initResources( opts
) || scanConfigs( False
) < 0)
259 logPanic( "Config reader failed. Aborting ...\n" );
262 if ((oldpid
= storePid())) {
264 logError( "Cannot create/lock pid file %s\n", pidFile
);
266 logError( "Cannot lock pid file %s, another xdm is running (pid %d)\n",
276 * We used to clean up old authorization files here. As authDir is
277 * supposed to be /var/run/xauth or /tmp, we needn't to care for it.
283 debug( "not compiled for XDMCP\n" );
285 if (pipe( signalFds
))
286 logPanic( "Unable to create signal notification pipe.\n" );
287 registerInput( signalFds
[0] );
288 registerCloseOnFork( signalFds
[0] );
289 registerCloseOnFork( signalFds
[1] );
290 (void)Signal( SIGTERM
, sigHandler
);
291 (void)Signal( SIGINT
, sigHandler
);
292 (void)Signal( SIGHUP
, sigHandler
);
293 (void)Signal( SIGCHLD
, sigHandler
);
294 (void)Signal( SIGUSR1
, sigHandler
);
297 * Step 2 - run a sub-daemon for each entry
301 updateListenSockets();
308 if (Fork( &pid
) <= 0) {
309 char *cmd
= sdRec
.how
== SHUT_HALT
? cmdHalt
: cmdReboot
;
310 execute( parseArgs( (char **)0, cmd
), (char **)0 );
311 logError( "Failed to execute shutdown command %\"s\n", cmd
);
315 sigemptyset( &mask
);
316 sigaddset( &mask
, SIGCHLD
);
317 sigaddset( &mask
, SIGHUP
);
321 debug( "nothing left to do, exiting\n" );
328 TTYtoVT( const char *tty
)
330 return memcmp( tty
, "tty", 3 ) ? 0 : atoi( tty
+ 3 );
337 int con
= open( "/dev/console", O_RDONLY
);
339 if (!ioctl( con
, VT_ACTIVATE
, vt
))
348 wakeDisplay( struct display
*d
)
350 if (d
->status
== textMode
)
351 d
->status
= (d
->displayType
& d_lifetime
) == dReserve
? reserve
: notRunning
;
355 enum utState
{ UtDead
, UtWait
, UtActive
};
368 #define TIME_RELOG 10
370 static struct utmps
*utmpList
;
371 static time_t utmpTimeout
= TO_INF
;
378 while ((utp
= utmpList
)) {
380 forEachDisplay( wakeDisplay
);
382 utp
->d
->status
= notRunning
;
384 utmpList
= utp
->next
;
392 static time_t modtim
;
395 struct utmps
*utp
, **utpp
;
406 if (stat( UTMP_FILE
, &st
)) {
407 logError( UTMP_FILE
" not found - cannot use console mode\n" );
411 if (modtim
!= st
.st_mtime
) {
412 debug( "rescanning " UTMP_FILE
"\n" );
413 for (utp
= utmpList
; utp
; utp
= utp
->next
)
416 if ((fd
= open( UTMP_FILE
, O_RDONLY
)) < 0) {
417 logError( "Cannot open " UTMP_FILE
" - cannot use console mode\n" );
421 while (reader( fd
, ut
, sizeof(ut
[0]) ) == sizeof(ut
[0]))
424 while ((ut
= GETUTENT()))
427 for (utp
= utmpList
; utp
; utp
= utp
->next
) {
430 for (line
= consoleTTYs
; *line
; line
++)
431 if (!strncmp( *line
, ut
->ut_line
, sizeof(ut
->ut_line
) ))
436 if (strncmp( utp
->d
->console
, ut
->ut_line
, sizeof(ut
->ut_line
) ))
442 if (ut
->ut_type
!= USER_PROCESS
) {
445 if (utp
->state
== UtActive
)
451 utp
->state
= UtActive
;
453 if (utp
->time
< ut
->ut_time
) /* theoretically superfluous */
454 utp
->time
= ut
->ut_time
;
463 modtim
= st
.st_mtime
;
465 for (utpp
= &utmpList
; (utp
= *utpp
); ) {
466 if (utp
->state
!= UtActive
) {
467 if (utp
->state
== UtDead
) /* shouldn't happen ... */
469 ends
= utp
->time
+ (utp
->hadSess
? TIME_RELOG
: TIME_LOG
);
472 forEachDisplay( wakeDisplay
);
473 debug( "console login timed out\n" );
475 utp
->d
->status
= notRunning
;
476 debug( "console login for %s at %s timed out\n",
477 utp
->d
->name
, utp
->d
->console
);
485 nck
= TIME_RELOG
+ now
;
486 if (nck
< utmpTimeout
)
488 utpp
= &(*utpp
)->next
;
496 switchToTTY( struct display
*d
)
504 if (!(utp
= Malloc( sizeof(*utp
) ))) {
506 forEachDisplay( wakeDisplay
);
508 d
->status
= notRunning
;
513 d
->status
= textMode
;
517 utp
->hadSess
= False
;
518 utp
->next
= utmpList
;
523 if ((vt
= TTYtoVT( *consoleTTYs
)))
527 /* XXX output something useful here */
532 stopToTTY( struct display
*d
)
534 if ((d
->displayType
& d_location
) == dLocal
)
537 rStopDisplay( d
, DS_TEXTMODE
| DS_SCHEDULE
);
549 for (d
= displays
; d
; d
= d
->next
)
550 if (d
->status
== zombie
)
559 switchToX( struct display
*d
)
561 struct utmps
*utp
, **utpp
;
563 for (utpp
= &utmpList
; (utp
= *utpp
); utpp
= &(*utpp
)->next
)
567 d
->status
= notRunning
;
575 startRemoteLogin( struct display
*d
)
579 debug( "startRemoteLogin for %s\n", d
->name
);
580 /* HACK: omitting loadDisplayResources( d ) here! */
581 switch (Fork( &d
->serverPid
)) {
583 argv
= prepareServerArgv( d
, d
->serverArgsRemote
);
584 if (!(argv
= addStrArr( argv
, "-once", 5 )) ||
585 !(argv
= addStrArr( argv
, "-query", 6 )) ||
586 !(argv
= addStrArr( argv
, d
->remoteHost
, -1 )))
588 debug( "exec %\"[s\n", argv
);
589 (void)execv( argv
[0], argv
);
590 logError( "X server %\"s cannot be executed\n", argv
[0] );
593 logError( "Forking X server for remote login failed: %m" );
594 d
->status
= notRunning
;
599 debug( "X server forked, pid %d\n", d
->serverPid
);
601 d
->status
= remoteLogin
;
607 stopInactiveDisplay( struct display
*d
)
609 if (d
->status
!= remoteLogin
&& d
->userSess
< 0)
618 updateListenSockets();
621 forEachDisplay( stopDisplay
);
623 forEachDisplay( stopInactiveDisplay
);
629 sessionDone( struct display
*d
)
641 setNLogin( struct display
*d
,
642 const char *nuser
, const char *npass
, const char *nargs
, int rl
)
644 struct disphist
*he
= d
->hstent
;
646 (reStr( &he
->nuser
, nuser
) &&
647 reStr( &he
->npass
, npass
) &&
648 reStr( &he
->nargs
, nargs
)) ? rl
: 0;
649 debug( "set next login for %s, level %d\n", nuser
, rl
);
653 processDPipe( struct display
*d
)
655 char *user
, *pass
, *args
;
663 dpytalk
.pipe
= &d
->pipe
;
664 if (Setjmp( dpytalk
.errjmp
)) {
669 if (!gRecvCmd( &cmd
)) {
670 /* process already exited */
671 unregisterInput( d
->pipe
.fd
.r
);
676 d
->userSess
= gRecvInt();
677 d
->userName
= gRecvStr();
678 d
->sessName
= gRecvStr();
683 if (d
->sdRec
.force
== SHUT_ASK
&&
684 (anyUserLogins( -1 ) || d
->allowShutdown
== SHUT_ROOT
))
688 if (!sdRec
.how
|| sdRec
.force
!= SHUT_FORCE
||
689 !((d
->allowNuke
== SHUT_NONE
&& sdRec
.uid
!= d
->sdRec
.uid
) ||
690 (d
->allowNuke
== SHUT_ROOT
&& d
->sdRec
.uid
)))
693 free( sdRec
.osname
);
695 } else if (d
->sdRec
.osname
)
696 free( d
->sdRec
.osname
);
708 setNLogin( d
, user
, pass
, args
, 1 );
715 ca
.data
= (unsigned char *)gRecvArr( &len
);
716 ca
.length
= (CARD16
)len
;
717 cp
.data
= (unsigned char *)gRecvArr( &len
);
718 cp
.length
= (CARD16
)len
;
720 ha
.data
= (unsigned char *)gRecvArr( &len
);
721 ha
.length
= (CARD16
)len
;
722 registerIndirectChoice( &ca
, &cp
, ct
, &ha
);
723 XdmcpDisposeARRAY8( &ha
);
724 XdmcpDisposeARRAY8( &cp
);
725 XdmcpDisposeARRAY8( &ca
);
729 free( d
->remoteHost
);
730 d
->remoteHost
= gRecvStr();
737 logError( "Internal error: unknown D_* command %d\n", cmd
);
744 emitXSessG( struct display
*di
, struct display
*d
, void *ctx ATTR_UNUSED
)
746 gSendStr( di
->name
);
749 gSendInt( di
->serverVT
);
752 if (di
->status
== remoteLogin
) {
754 gSendStr( di
->remoteHost
);
758 gSendStr( di
->userName
);
759 gSendStr( di
->sessName
);
761 gSendInt( di
== d
? isSelf
: 0 );
765 emitTTYSessG( STRUCTUTMP
*ut
, struct display
*d ATTR_UNUSED
, void *ctx ATTR_UNUSED
)
767 gSendStrN( ut
->ut_line
, sizeof(ut
->ut_line
) );
768 gSendStrN( ut
->ut_host
, sizeof(ut
->ut_host
) );
770 gSendInt( TTYtoVT( ut
->ut_line
) );
773 gSendStrN( *ut
->ut_user
? ut
->ut_user
: 0, sizeof(ut
->ut_user
) );
775 gSendStrN( ut
->ut_type
== USER_PROCESS
? ut
->ut_user
: 0, sizeof(ut
->ut_user
) );
777 gSendStr( 0 ); /* session type unknown */
782 processGPipe( struct display
*d
)
784 char **opts
, *option
;
785 int cmd
, ret
, dflt
, curr
;
788 dpytalk
.pipe
= &d
->gpipe
;
789 if (Setjmp( dpytalk
.errjmp
)) {
794 if (!gRecvCmd( &cmd
)) {
795 /* process already exited */
796 unregisterInput( d
->gpipe
.fd
.r
);
801 ret
= getBootOptions( &opts
, &dflt
, &curr
);
811 sdRec
.how
= gRecvInt();
812 sdRec
.start
= gRecvInt();
813 sdRec
.timeout
= gRecvInt();
814 sdRec
.force
= gRecvInt();
815 sdRec
.uid
= gRecvInt();
817 setBootOption( option
, &sdRec
);
821 case G_QueryShutdown
:
822 gSendInt( sdRec
.how
);
823 gSendInt( sdRec
.start
);
824 gSendInt( sdRec
.timeout
);
825 gSendInt( sdRec
.force
);
826 gSendInt( sdRec
.uid
);
827 gSendStr( sdRec
.osname
);
829 case G_QryDpyShutdown
:
830 gSendInt( d
->sdRec
.how
);
831 gSendInt( d
->sdRec
.uid
);
832 gSendStr( d
->sdRec
.osname
);
835 listSessions( gRecvInt(), d
, 0, emitXSessG
, emitTTYSessG
);
840 activateVT( gRecvInt() );
845 if (*consoleTTYs
) { /* sanity check against greeter */
846 forEachDisplay( stopToTTY
);
850 if (*d
->console
) /* sanity check against greeter */
851 rStopDisplay( d
, DS_TEXTMODE
);
855 logError( "Internal error: unknown G_* command %d\n", cmd
);
863 scanConfigs( int force
)
867 if ((ret
= loadDMResources( force
)) <= 0)
871 scanAccessDatabase( force
);
877 markDisplay( struct display
*d
)
879 d
->stillThere
= False
;
883 rescanConfigs( int force
)
885 if (scanConfigs( force
) > 0) {
887 updateListenSockets();
894 cancelShutdown( void )
898 free( sdRec
.osname
);
902 rescanConfigs( True
);
913 while ((pid
= waitpid( -1, &status
, WNOHANG
)) > 0)
915 debug( "manager wait returns pid %d sig %d core %d code %d\n",
916 pid
, waitSig( status
), waitCore( status
), waitCode( status
) );
918 if ((d
= findDisplayByPid( pid
))) {
920 unregisterInput( d
->pipe
.fd
.r
);
922 unregisterInput( d
->gpipe
.fd
.r
);
923 gClosen( &d
->gpipe
);
925 switch (wcFromWait( status
)) {
928 debug( "display exited with EX_REMOTE\n" );
929 exitDisplay( d
, DS_REMOTE
, 0, False
);
933 /* (any type of) session ended */
934 debug( "display exited with EX_NORMAL\n" );
935 if ((d
->displayType
& d_lifetime
) == dReserve
)
936 exitDisplay( d
, DS_RESERVE
, 0, False
);
938 exitDisplay( d
, DS_RESTART
, XS_KEEP
, True
);
941 debug( "display exited with EX_RESERVE\n" );
942 exitDisplay( d
, DS_RESERVE
, 0, False
);
945 case EX_REMANAGE_DPY
:
946 /* user session ended */
947 debug( "display exited with EX_REMANAGE_DPY\n" );
948 exitDisplay( d
, DS_RESTART
, XS_KEEP
, True
);
951 case EX_OPENFAILED_DPY
:
952 /* waitForServer() failed */
953 logError( "Display %s cannot be opened\n", d
->name
);
956 * no display connection was ever made, tell the
957 * terminal that the open attempt failed
959 if ((d
->displayType
& d_origin
) == dFromXDMCP
)
960 sendFailed( d
, "cannot open display" );
962 exitDisplay( d
, DS_RESTART
, XS_RETRY
, False
);
964 case wcCompose( SIGTERM
,0,0 ):
965 /* killed before/during waitForServer()
967 - display stopped (is zombie)
968 - "login now" and "suicide" pipe commands (is raiser)
970 debug( "display exited on SIGTERM\n" );
971 exitDisplay( d
, DS_RESTART
, XS_RETRY
, False
);
973 case EX_AL_RESERVER_DPY
:
974 /* - killed after waitForServer()
975 - Xserver dead after remote session exit
977 debug( "display exited with EX_AL_RESERVER_DPY\n" );
978 exitDisplay( d
, DS_RESTART
, XS_RESTART
, False
);
980 case EX_RESERVER_DPY
:
981 /* induced by greeter:
982 - could not secure display
985 debug( "display exited with EX_RESERVER_DPY\n" );
986 exitDisplay( d
, DS_RESTART
, XS_RESTART
, True
);
988 case EX_UNMANAGE_DPY
:
989 /* some fatal error */
990 debug( "display exited with EX_UNMANAGE_DPY\n" );
991 exitDisplay( d
, DS_REMOVE
, 0, False
);
995 logError( "Unknown session exit code %d (sig %d) from manager process\n",
996 waitCode( status
), waitSig( status
) );
997 exitDisplay( d
, DS_REMOVE
, 0, False
);
1000 } else if ((d
= findDisplayByServerPid( pid
))) {
1002 switch (d
->status
) {
1004 debug( "zombie X server for display %s reaped\n", d
->name
);
1006 if (d
->serverVT
&& d
->zstatus
!= DS_REMOTE
) {
1008 d
->follower
->serverVT
= d
->serverVT
;
1011 int con
= open( "/dev/console", O_RDONLY
);
1013 struct vt_stat vtstat
;
1014 ioctl( con
, VT_GETSTATE
, &vtstat
);
1015 if (vtstat
.v_active
== d
->serverVT
) {
1018 for (di
= displays
; di
; di
= di
->next
)
1019 if (di
!= d
&& di
->serverVT
)
1021 for (di
= displays
; di
; di
= di
->next
)
1022 if (di
!= d
&& di
->serverVT
&&
1023 (di
->userSess
>= 0 ||
1024 di
->status
== remoteLogin
))
1026 ioctl( con
, VT_ACTIVATE
, vt
);
1028 ioctl( con
, VT_DISALLOCATE
, d
->serverVT
);
1035 rStopDisplay( d
, d
->zstatus
);
1038 debug( "phoenix X server arises, restarting display %s\n",
1040 d
->status
= notRunning
;
1043 debug( "remote login X server for display %s exited\n",
1045 d
->status
= ((d
->displayType
& d_lifetime
) == dReserve
) ?
1046 reserve
: notRunning
;
1049 logError( "X server for display %s terminated unexpectedly\n",
1051 /* don't kill again */
1054 if (startingServer
== d
&& d
->serverStatus
!= ignore
) {
1055 if (d
->serverStatus
== starting
&& waitCode( status
) != 47)
1056 logError( "X server died during startup\n" );
1057 startServerFailed();
1060 logError( "X server for display %s terminated unexpectedly\n",
1063 debug( "terminating session pid %d\n", d
->pid
);
1064 terminateProcess( d
->pid
, SIGTERM
);
1070 /* this cannot happen */
1071 debug( "X server exited for passive (%d) session on display %s\n",
1072 (int)d
->status
, d
->name
);
1076 debug( "unknown child termination\n" );
1084 wouldShutdown( void )
1086 switch (sdRec
.force
) {
1090 return !anyUserLogins( sdRec
.uid
);
1093 return !anyUserLogins( -1 );
1097 fd_set wellKnownSocketsMask
;
1098 int wellKnownSocketsMax
;
1099 int wellKnownSocketsCount
;
1102 registerInput( int fd
)
1104 /* can be omited, as it is always called right after opening a socket
1105 if (!FD_ISSET( fd, &wellKnownSocketsMask ))
1108 FD_SET( fd
, &wellKnownSocketsMask
);
1109 if (fd
> wellKnownSocketsMax
)
1110 wellKnownSocketsMax
= fd
;
1111 wellKnownSocketsCount
++;
1116 unregisterInput( int fd
)
1118 /* the check _is_ necessary, as some handles are unregistered before
1119 the regular close sequence.
1121 if (FD_ISSET( fd
, &wellKnownSocketsMask
)) {
1122 FD_CLR( fd
, &wellKnownSocketsMask
);
1123 wellKnownSocketsCount
--;
1130 int olderrno
= errno
;
1132 /* debug( "caught signal %d\n", n ); this hangs in syslog() */
1133 write( signalFds
[1], &buf
, 1 );
1135 (void)Signal( n
, sigHandler
);
1144 struct timeval
*tvp
, tv
;
1150 debug( "mainLoop\n" );
1154 anyListenSockets() ||
1156 (stopping
? anyRunningDisplays() : anyDisplaysLeft()))
1161 to
= disposeIndirectHosts();
1166 if (sdRec
.start
!= TO_INF
&& now
< sdRec
.start
) {
1167 /*if (sdRec.start < to)*/
1170 sdRec
.start
= TO_INF
;
1171 if (now
>= sdRec
.timeout
) {
1172 sdRec
.timeout
= TO_INF
;
1173 if (wouldShutdown())
1179 /*if (sdRec.timeout < to)*/
1184 if (serverTimeout
< to
)
1186 if (utmpTimeout
< to
)
1198 reads
= wellKnownSocketsMask
;
1199 nready
= select( wellKnownSocketsMax
+ 1, &reads
, 0, 0, tvp
);
1200 debug( "select returns %d\n", nready
);
1205 if (now
>= serverTimeout
) {
1206 serverTimeout
= TO_INF
;
1207 startServerTimeout();
1209 if (now
>= utmpTimeout
) {
1210 utmpTimeout
= TO_INF
;
1215 * we restart after the first handled fd, as
1216 * a) it makes things simpler
1217 * b) the probability that multiple fds trigger at once is
1218 * ridiculously small. we handle it in the next iteration.
1220 /* XXX a cleaner solution would be a callback mechanism */
1221 if (FD_ISSET( signalFds
[0], &reads
)) {
1222 if (read( signalFds
[0], &buf
, 1 ) != 1)
1223 logPanic( "Signal notification pipe broken.\n" );
1227 debug( "shutting down entire manager\n" );
1231 logInfo( "Rescanning all config files\n" );
1232 forEachDisplay( markDisplay
);
1233 rescanConfigs( True
);
1237 if (!stopping
&& autoRescan
)
1238 rescanConfigs( False
);
1241 if (startingServer
&&
1242 startingServer
->serverStatus
== starting
)
1243 startServerSuccess();
1249 if (processListenSockets( &reads
))
1252 if (handleCtrl( &reads
, 0 ))
1254 /* Must be last (because of the breaks)! */
1256 for (d
= displays
; d
; d
= d
->next
) {
1257 if (handleCtrl( &reads
, d
))
1259 if (d
->pipe
.fd
.r
>= 0 && FD_ISSET( d
->pipe
.fd
.r
, &reads
)) {
1263 if (d
->gpipe
.fd
.r
>= 0 && FD_ISSET( d
->gpipe
.fd
.r
, &reads
)) {
1273 checkDisplayStatus( struct display
*d
)
1275 if ((d
->displayType
& d_origin
) == dFromFile
&& !d
->stillThere
)
1277 else if ((d
->displayType
& d_lifetime
) == dReserve
&&
1278 d
->status
== running
&& d
->userSess
< 0 && !d
->idleTimeout
)
1279 rStopDisplay( d
, DS_RESERVE
);
1280 else if (d
->status
== notRunning
)
1281 if (loadDisplayResources( d
) < 0) {
1282 logError( "Unable to read configuration for display %s; "
1283 "stopping it.\n", d
->name
);
1290 kickDisplay( struct display
*d
)
1292 if (d
->status
== notRunning
)
1294 if (d
->serverStatus
== awaiting
&& !startingServer
)
1299 static int activeVTs
;
1304 struct vt_stat vtstat
;
1307 if (activeVTs
== -1) {
1309 if ((con
= open( "/dev/console", O_RDONLY
)) >= 0) {
1310 ioctl( con
, VT_GETSTATE
, &vtstat
);
1313 activeVTs
= vtstat
.v_state
;
1319 allocateVT( struct display
*d
)
1324 if ((d
->displayType
& d_location
) == dLocal
&&
1325 d
->status
== notRunning
&& !d
->serverVT
&& d
->reqSrvVT
>= 0)
1327 if (d
->reqSrvVT
&& d
->reqSrvVT
< 16)
1328 d
->serverVT
= d
->reqSrvVT
;
1330 for (i
= tvt
= 0;;) {
1332 tvt
= atoi( serverVTs
[i
++] );
1338 if (!tvt
|| tvt
>= 16)
1345 for (cd
= displays
; cd
; cd
= cd
->next
) {
1346 if (cd
->reqSrvVT
== tvt
&& /* protect from lusers */
1347 (cd
->status
!= zombie
|| cd
->zstatus
!= DS_REMOVE
))
1349 if (cd
->serverVT
== tvt
) {
1350 if (cd
->status
!= zombie
|| cd
->zstatus
== DS_REMOTE
)
1352 if (!cd
->follower
) {
1359 if (!volun
|| !((1 << tvt
) & getBusyVTs())) {
1371 startDisplays( void )
1373 forEachDisplay( checkDisplayStatus
);
1377 forEachDisplayRev( allocateVT
);
1379 forEachDisplay( kickDisplay
);
1383 startDisplay( struct display
*d
)
1386 debug( "stopping display %s because shutdown is scheduled\n", d
->name
);
1392 if (d
->serverVT
< 0)
1396 d
->status
= running
;
1397 if ((d
->displayType
& d_location
) == dLocal
) {
1398 debug( "startDisplay %s\n", d
->name
);
1399 /* don't bother pinging local displays; we'll
1400 * certainly notice when they exit
1402 d
->pingInterval
= 0;
1404 setLocalAuthorization( d
);
1406 * reset the server after writing the authorization information
1407 * to make it read the file (for compatibility with old
1408 * servers which read auth file only on reset instead of
1409 * at first connection)
1411 if (d
->serverPid
!= -1 && d
->resetForAuth
&& d
->resetSignal
)
1412 kill( d
->serverPid
, d
->resetSignal
);
1414 if (d
->serverPid
== -1) {
1415 d
->serverStatus
= awaiting
;
1419 debug( "startDisplay %s, try %d\n", d
->name
, d
->startTries
+ 1 );
1420 /* this will only happen when using XDMCP */
1421 if (d
->authorizations
)
1422 saveServerAuthorizations( d
, d
->authorizations
, d
->authNum
);
1424 startDisplayP2( d
);
1428 startDisplayP2( struct display
*d
)
1430 char *cname
, *cgname
;
1433 debug( "forking session\n" );
1434 ASPrintf( &cname
, "sub-daemon for display %s", d
->name
);
1435 ASPrintf( &cgname
, "greeter for display %s", d
->name
);
1436 switch (gFork( &d
->pipe
, "master daemon", cname
,
1437 &d
->gpipe
, cgname
, 0, &d
->pid
))
1442 setproctitle( "%s", d
->name
);
1444 ASPrintf( &prog
, "%s: %s", prog
, d
->name
);
1446 if (debugLevel
& DEBUG_WSESS
)
1448 mstrtalk
.pipe
= &d
->pipe
;
1449 (void)Signal( SIGPIPE
, SIG_IGN
);
1450 setAuthorization( d
);
1452 if ((d
->displayType
& d_location
) == dLocal
) {
1454 gSendInt( D_XConnOk
);
1460 d
->status
= notRunning
;
1463 debug( "forked session, pid %d\n", d
->pid
);
1465 /* (void) fcntl (d->pipe.fd.r, F_SETFL, O_NONBLOCK); */
1466 /* (void) fcntl (d->gpipe.fd.r, F_SETFL, O_NONBLOCK); */
1467 registerInput( d
->pipe
.fd
.r
);
1468 registerInput( d
->gpipe
.fd
.r
);
1470 d
->hstent
->lock
= d
->hstent
->rLogin
= d
->hstent
->goodExit
=
1478 * transition from running to zombie, textmode, reserve or deleted
1482 rStopDisplay( struct display
*d
, int endState
)
1484 debug( "stopping display %s to state %d\n", d
->name
, endState
);
1485 abortStartServer( d
);
1487 if (d
->serverPid
!= -1 || d
->pid
!= -1) {
1489 terminateProcess( d
->pid
, SIGTERM
);
1490 if (d
->serverPid
!= -1)
1491 terminateProcess( d
->serverPid
, d
->termSignal
);
1493 d
->zstatus
= endState
& DS_MASK
;
1494 debug( " zombiefied\n" );
1495 } else if (endState
== DS_TEXTMODE
) {
1497 d
->status
= textMode
;
1499 } else if (endState
== (DS_TEXTMODE
| DS_SCHEDULE
)) {
1500 d
->status
= textMode
;
1504 } else if (endState
== DS_RESERVE
)
1505 d
->status
= reserve
;
1507 else if (endState
== DS_REMOTE
)
1508 startRemoteLogin( d
);
1519 stopDisplay( struct display
*d
)
1521 rStopDisplay( d
, DS_REMOVE
);
1525 exitDisplay( struct display
*d
,
1530 struct disphist
*he
;
1532 if (d
->status
== raiser
) {
1533 serverCmd
= XS_KEEP
;
1537 debug( "exitDisplay %s, "
1538 "endState = %d, serverCmd = %d, GoodExit = %d\n",
1539 d
->name
, endState
, serverCmd
, goodExit
);
1544 he
->goodExit
= goodExit
;
1545 if (sdRec
.how
&& sdRec
.start
== TO_INF
)
1546 endState
= DS_REMOVE
;
1547 if (d
->status
== zombie
)
1548 rStopDisplay( d
, d
->zstatus
);
1554 if (endState
!= DS_RESTART
||
1555 (d
->displayType
& d_origin
) != dFromFile
)
1557 rStopDisplay( d
, endState
);
1559 if (serverCmd
== XS_RETRY
) {
1560 if ((d
->displayType
& d_location
) == dLocal
) {
1561 if (he
->lastExit
- d
->lastStart
< 120) {
1562 logError( "Unable to fire up local display %s;"
1563 " disabling.\n", d
->name
);
1568 if (++d
->startTries
> d
->startAttempts
) {
1569 logError( "Disabling foreign display %s"
1570 " (too many attempts)\n", d
->name
);
1577 if (d
->serverPid
!= -1 &&
1578 (serverCmd
!= XS_KEEP
|| d
->terminateServer
))
1580 debug( "killing X server for %s\n", d
->name
);
1581 terminateProcess( d
->serverPid
, d
->termSignal
);
1582 d
->status
= phoenix
;
1584 d
->status
= notRunning
;
1591 static FILE *pidFilePtr
;
1598 if (pidFile
[0] != '\0') {
1599 pidFd
= open( pidFile
, O_RDWR
);
1600 if (pidFd
== -1 && errno
== ENOENT
)
1601 pidFd
= open( pidFile
, O_RDWR
|O_CREAT
, 0666 );
1602 if (pidFd
== -1 || !(pidFilePtr
= fdopen( pidFd
, "r+" ))) {
1603 logError( "process-id file %s cannot be opened\n",
1607 if (fscanf( pidFilePtr
, "%d\n", &oldpid
) != 1)
1609 fseek( pidFilePtr
, 0l, 0 );
1615 struct flock lock_data
;
1616 lock_data
.l_type
= F_WRLCK
;
1617 lock_data
.l_whence
= SEEK_SET
;
1618 lock_data
.l_start
= lock_data
.l_len
= 0;
1619 if (fcntl( pidFd
, F_SETLK
, &lock_data
) == -1) {
1620 if (errno
== EAGAIN
)
1627 if (flock( pidFd
, LOCK_EX
|LOCK_NB
) == -1) {
1628 if (errno
== EWOULDBLOCK
)
1634 if (lockf( pidFd
, F_TLOCK
, 0 ) == -1) {
1635 if (errno
== EACCES
)
1643 fprintf( pidFilePtr
, "%ld\n", (long)getpid() );
1644 (void)fflush( pidFilePtr
);
1645 registerCloseOnFork( pidFd
);
1652 UnlockPidFile( void )
1657 struct flock lock_data
;
1658 lock_data
.l_type
= F_UNLCK
;
1659 lock_data
.l_whence
= SEEK_SET
;
1660 lock_data
.l_start
= lock_data
.l_len
= 0;
1661 (void)fcntl( pidFd
, F_SETLK
, &lock_data
);
1665 lockf( pidFd
, F_ULOCK
, 0 );
1667 flock( pidFd
, LOCK_UN
);
1671 fclose( pidFilePtr
);
1675 #if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
1677 setproctitle( const char *fmt
, ... )
1682 int left
= titleLen
;
1685 va_start( args
, fmt
);
1686 VASPrintf( &oname
, fmt
, args
);
1689 if ((name
= oname
)) {
1692 while (*name
&& left
> 0) {