summaryrefslogtreecommitdiffstats
path: root/kdm/backend/dm.c
diff options
context:
space:
mode:
Diffstat (limited to 'kdm/backend/dm.c')
-rw-r--r--kdm/backend/dm.c1652
1 files changed, 1652 insertions, 0 deletions
diff --git a/kdm/backend/dm.c b/kdm/backend/dm.c
new file mode 100644
index 000000000..e696a1a5e
--- /dev/null
+++ b/kdm/backend/dm.c
@@ -0,0 +1,1652 @@
+/*
+
+Copyright 1988, 1998 The Open Group
+Copyright 2000-2005 Oswald Buddenhagen <ossi@kde.org>
+
+Permission to use, copy, modify, distribute, and sell this software and its
+documentation for any purpose is hereby granted without fee, provided that
+the above copyright notice appear in all copies and that both that
+copyright notice and this permission notice appear in supporting
+documentation.
+
+The above copyright notice and this permission notice shall be included
+in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+Except as contained in this notice, the name of a copyright holder shall
+not be used in advertising or otherwise to promote the sale, use or
+other dealings in this Software without prior written authorization
+from the copyright holder.
+
+*/
+
+/*
+ * xdm - display manager daemon
+ * Author: Keith Packard, MIT X Consortium
+ *
+ * display manager
+ */
+
+#include "dm.h"
+#include "dm_auth.h"
+#include "dm_error.h"
+
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <stdarg.h>
+#include <signal.h>
+#include <sys/stat.h>
+
+#ifdef HAVE_VTS
+# include <sys/ioctl.h>
+# include <sys/vt.h>
+#endif
+
+static void SigHandler( int n );
+static int ScanConfigs( int force );
+static void StartDisplays( void );
+#define XS_KEEP 0
+#define XS_RESTART 1
+#define XS_RETRY 2
+static void ExitDisplay( struct display *d, int endState, int serverCmd, int goodExit );
+static void rStopDisplay( struct display *d, int endState );
+static void MainLoop( void );
+
+static int signalFds[2];
+
+#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
+static char *Title;
+static int TitleLen;
+#endif
+
+static int StorePid( void );
+
+static int Stopping;
+SdRec sdRec = { 0, 0, 0, TO_INF, TO_INF, 0, 0, 0 };
+
+time_t now;
+
+char *prog, *progpath;
+
+int
+main( int argc, char **argv )
+{
+ int oldpid, oldumask, fd, noDaemonMode;
+ char *pt, *errorLogFile, **opts;
+
+ /* make sure at least world write access is disabled */
+ if (((oldumask = umask( 022 )) & 002) == 002)
+ (void)umask( oldumask );
+
+ /* give /dev/null as stdin */
+ if ((fd = open( "/dev/null", O_RDONLY )) > 0) {
+ dup2( fd, 0 );
+ close( fd );
+ }
+ if (fcntl( 1, F_GETFD ) < 0)
+ dup2( 0, 1 );
+ if (fcntl( 2, F_GETFD ) < 0)
+ dup2( 0, 2 );
+
+ if (argv[0][0] == '/') {
+ if (!StrDup( &progpath, argv[0] ))
+ Panic( "Out of memory" );
+ } else
+#ifdef __linux__
+ {
+ /* note that this will resolve symlinks ... */
+ int len;
+ char fullpath[PATH_MAX];
+ if ((len = readlink( "/proc/self/exe", fullpath, sizeof(fullpath) )) < 0)
+ Panic( "Invoke with full path specification or mount /proc" );
+ if (!StrNDup( &progpath, fullpath, len ))
+ Panic( "Out of memory" );
+ }
+#else
+# if 0
+ Panic( "Must be invoked with full path specification" );
+# else
+ {
+ char directory[PATH_MAX+1];
+ if (!getcwd( directory, sizeof(directory) ))
+ Panic( "Can't find myself (getcwd failed)" );
+ if (strchr( argv[0], '/' ))
+ StrApp( &progpath, directory, "/", argv[0], (char *)0 );
+ else {
+ int len;
+ char *path, *pathe, *name, *thenam, nambuf[PATH_MAX+1];
+
+ if (!(path = getenv( "PATH" )))
+ Panic( "Can't find myself (no PATH)" );
+ len = strlen( argv[0] );
+ name = nambuf + PATH_MAX - len;
+ memcpy( name, argv[0], len + 1 );
+ *--name = '/';
+ do {
+ if (!(pathe = strchr( path, ':' )))
+ pathe = path + strlen( path );
+ len = pathe - path;
+ if (!len || (len == 1 && *path == '.')) {
+ len = strlen( directory );
+ path = directory;
+ }
+ thenam = name - len;
+ if (thenam >= nambuf) {
+ memcpy( thenam, path, len );
+ if (!access( thenam, X_OK ))
+ goto found;
+ }
+ path = pathe;
+ } while (*path++ != '\0');
+ Panic( "Can't find myself (not in PATH)" );
+ found:
+ if (!StrDup( &progpath, thenam ))
+ Panic( "Out of memory" );
+ }
+ }
+# endif
+#endif
+ prog = strrchr( progpath, '/' ) + 1;
+
+#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
+ Title = argv[0];
+ TitleLen = (argv[argc - 1] + strlen( argv[argc - 1] )) - Title;
+#endif
+
+ /*
+ * Parse command line options
+ */
+ noDaemonMode = getppid();
+ errorLogFile = 0;
+ if (!(opts = Malloc( 2 * sizeof(char *) )))
+ return 1;
+ opts[0] = (char *)"";
+ opts[1] = 0;
+ while (*++argv) {
+ if (**argv != '-')
+ break;
+ pt = *argv + 1;
+ if (*pt == '-')
+ pt++;
+ if (!strcmp( pt, "help" ) || !strcmp( pt, "h" )) {
+ printf( "Usage: %s [options] [tty]\n"
+" -daemon\t - Daemonize even when started by init\n"
+" -nodaemon\t - Don't daemonize even when started from command line\n"
+" -config <file> - Use alternative master configuration file\n"
+" -xrm <res>\t - Override frontend-specific resource\n"
+" -error <file>\t - Use alternative log file\n"
+" -debug <num>\t - Debug option bitfield:\n"
+"\t\t\t0x1 - core log\n"
+"\t\t\t0x2 - config reader log\n"
+"\t\t\t0x4 - greeter log\n"
+"\t\t\t0x8 - IPC log\n"
+"\t\t\t0x10 - session sub-daemon post-fork delay\n"
+"\t\t\t0x20 - config reader post-start delay\n"
+"\t\t\t0x40 - greeter post-start delay\n"
+"\t\t\t0x80 - don't use syslog\n"
+"\t\t\t0x100 - core Xauth log\n"
+"\t\t\t0x400 - valgrind config reader and greeter\n"
+"\t\t\t0x800 - strace config reader and greeter\n"
+ , prog );
+ exit( 0 );
+ } else if (!strcmp( pt, "daemon" ))
+ noDaemonMode = 0;
+ else if (!strcmp( pt, "nodaemon" ))
+ noDaemonMode = 1;
+ else if (argv[1] && !strcmp( pt, "config" ))
+ StrDup( opts, *++argv );
+ else if (argv[1] && !strcmp( pt, "xrm" ))
+ opts = addStrArr( opts, *++argv, -1 );
+ else if (argv[1] && !strcmp( pt, "debug" ))
+ sscanf( *++argv, "%i", &debugLevel );
+ else if (argv[1] && (!strcmp( pt, "error" ) || !strcmp( pt, "logfile" )))
+ errorLogFile = *++argv;
+ else {
+ fprintf( stderr, "\"%s\" is an unknown option or is missing a parameter\n", *argv );
+ exit( 1 );
+ }
+ }
+
+ /*
+ * Only allow root to run in non-debug mode to avoid problems
+ */
+ if (!debugLevel && getuid()) {
+ fprintf( stderr, "Only root wants to run %s\n", prog );
+ exit( 1 );
+ }
+
+ InitErrorLog( errorLogFile );
+
+ if (noDaemonMode != 1)
+ BecomeDaemon();
+
+ /*
+ * Step 1 - load configuration parameters
+ */
+ if (!InitResources( opts ) || ScanConfigs( FALSE ) < 0)
+ LogPanic( "Config reader failed. Aborting ...\n" );
+
+ /* SUPPRESS 560 */
+ if ((oldpid = StorePid())) {
+ if (oldpid == -1)
+ LogError( "Can't create/lock pid file %s\n", pidFile );
+ else
+ LogError( "Can't lock pid file %s, another xdm is running (pid %d)\n",
+ pidFile, oldpid );
+ exit( 1 );
+ }
+
+#ifdef NEED_ENTROPY
+ AddOtherEntropy();
+#endif
+
+ /*
+ * We used to clean up old authorization files here. As authDir is
+ * supposed to be /var/run/xauth or /tmp, we needn't to care for it.
+ */
+
+#ifdef XDMCP
+ init_session_id();
+#else
+ Debug( "not compiled for XDMCP\n" );
+#endif
+ if (pipe( signalFds ))
+ LogPanic( "Unable to create signal notification pipe.\n" );
+ RegisterInput( signalFds[0] );
+ RegisterCloseOnFork( signalFds[0] );
+ RegisterCloseOnFork( signalFds[1] );
+ (void)Signal( SIGTERM, SigHandler );
+ (void)Signal( SIGINT, SigHandler );
+ (void)Signal( SIGHUP, SigHandler );
+ (void)Signal( SIGCHLD, SigHandler );
+ (void)Signal( SIGUSR1, SigHandler );
+
+ /*
+ * Step 2 - run a sub-daemon for each entry
+ */
+#ifdef XDMCP
+ UpdateListenSockets();
+#endif
+ openCtrl( 0 );
+ MainLoop();
+ closeCtrl( 0 );
+ if (sdRec.how) {
+ commitBootOption();
+ if (Fork() <= 0) {
+ char *cmd = sdRec.how == SHUT_HALT ? cmdHalt : cmdReboot;
+ execute( parseArgs( (char **)0, cmd ), (char **)0 );
+ LogError( "Failed to execute shutdown command %\"s\n", cmd );
+ exit( 1 );
+ } else {
+ sigset_t mask;
+ sigemptyset( &mask );
+ sigaddset( &mask, SIGCHLD );
+ sigaddset( &mask, SIGHUP );
+ sigsuspend( &mask );
+ }
+ }
+ Debug( "nothing left to do, exiting\n" );
+ return 0;
+}
+
+
+#ifdef HAVE_VTS
+int
+TTYtoVT( const char *tty )
+{
+ return memcmp( tty, "tty", 3 ) ? 0 : atoi( tty + 3 );
+}
+
+int
+activateVT( int vt )
+{
+ int ret = 0;
+ int con = open( "/dev/console", O_RDONLY );
+ if (con >= 0) {
+ if (!ioctl( con, VT_ACTIVATE, vt ))
+ ret = 1;
+ close( con );
+ }
+ return ret;
+}
+
+
+static void
+WakeDisplay( struct display *d )
+{
+ if (d->status == textMode)
+ d->status = (d->displayType & d_lifetime) == dReserve ? reserve : notRunning;
+}
+#endif
+
+enum utState { UtDead, UtWait, UtActive };
+
+struct utmps {
+ struct utmps *next;
+#ifndef HAVE_VTS
+ struct display *d;
+#endif
+ time_t time;
+ enum utState state;
+ int hadSess;
+};
+
+#define TIME_LOG 40
+#define TIME_RELOG 10
+
+static struct utmps *utmpList;
+static time_t utmpTimeout = TO_INF;
+
+static void
+bombUtmp( void )
+{
+ struct utmps *utp;
+
+ while ((utp = utmpList)) {
+#ifdef HAVE_VTS
+ ForEachDisplay( WakeDisplay );
+#else
+ utp->d->status = notRunning;
+#endif
+ utmpList = utp->next;
+ free( utp );
+ }
+}
+
+static void
+CheckUtmp( void )
+{
+ static time_t modtim;
+ time_t nck;
+ time_t ends;
+ struct utmps *utp, **utpp;
+ struct stat st;
+#ifdef BSD_UTMP
+ int fd;
+ struct utmp ut[1];
+#else
+ STRUCTUTMP *ut;
+#endif
+
+ if (!utmpList)
+ return;
+ if (stat( UTMP_FILE, &st )) {
+ LogError( UTMP_FILE " not found - cannot use console mode\n" );
+ bombUtmp();
+ return;
+ }
+ if (modtim != st.st_mtime) {
+ Debug( "rescanning " UTMP_FILE "\n" );
+ for (utp = utmpList; utp; utp = utp->next)
+ utp->state = UtDead;
+#ifdef BSD_UTMP
+ if ((fd = open( UTMP_FILE, O_RDONLY )) < 0) {
+ LogError( "Cannot open " UTMP_FILE " - cannot use console mode\n" );
+ bombUtmp();
+ return;
+ }
+ while (Reader( fd, ut, sizeof(ut[0]) ) == sizeof(ut[0]))
+#else
+ SETUTENT();
+ while ((ut = GETUTENT()))
+#endif
+ {
+ for (utp = utmpList; utp; utp = utp->next) {
+#ifdef HAVE_VTS
+ char **line;
+ for (line = consoleTTYs; *line; line++)
+ if (!strncmp( *line, ut->ut_line, sizeof(ut->ut_line) ))
+ goto hitlin;
+ continue;
+ hitlin:
+#else
+ if (strncmp( utp->d->console, ut->ut_line, sizeof(ut->ut_line) ))
+ continue;
+#endif
+#ifdef BSD_UTMP
+ if (!*ut->ut_user) {
+#else
+ if (ut->ut_type != USER_PROCESS) {
+#endif
+#ifdef HAVE_VTS
+ if (utp->state == UtActive)
+ break;
+#endif
+ utp->state = UtWait;
+ } else {
+ utp->hadSess = 1;
+ utp->state = UtActive;
+ }
+ if (utp->time < ut->ut_time) /* theoretically superfluous */
+ utp->time = ut->ut_time;
+ break;
+ }
+ }
+#ifdef BSD_UTMP
+ close( fd );
+#else
+ ENDUTENT();
+#endif
+ modtim = st.st_mtime;
+ }
+ for (utpp = &utmpList; (utp = *utpp); ) {
+ if (utp->state != UtActive) {
+ if (utp->state == UtDead) /* shouldn't happen ... */
+ utp->time = 0;
+ ends = utp->time + (utp->hadSess ? TIME_RELOG : TIME_LOG);
+ if (ends <= now) {
+#ifdef HAVE_VTS
+ ForEachDisplay( WakeDisplay );
+ Debug( "console login timed out\n" );
+#else
+ utp->d->status = notRunning;
+ Debug( "console login for %s at %s timed out\n",
+ utp->d->name, utp->d->console );
+#endif
+ *utpp = utp->next;
+ free( utp );
+ continue;
+ } else
+ nck = ends;
+ } else
+ nck = TIME_RELOG + now;
+ if (nck < utmpTimeout)
+ utmpTimeout = nck;
+ utpp = &(*utpp)->next;
+ }
+}
+
+static void
+#ifdef HAVE_VTS
+SwitchToTty( void )
+#else
+SwitchToTty( struct display *d )
+#endif
+{
+ struct utmps *utp;
+#ifdef HAVE_VTS
+ int vt;
+#endif
+
+ if (!(utp = Malloc( sizeof(*utp) ))) {
+#ifdef HAVE_VTS
+ ForEachDisplay( WakeDisplay );
+#else
+ d->status = notRunning;
+#endif
+ return;
+ }
+#ifndef HAVE_VTS
+ d->status = textMode;
+ utp->d = d;
+#endif
+ utp->time = now;
+ utp->hadSess = 0;
+ utp->next = utmpList;
+ utmpList = utp;
+ CheckUtmp();
+
+#ifdef HAVE_VTS
+ if ((vt = TTYtoVT( *consoleTTYs )))
+ activateVT( vt );
+#endif
+
+ /* XXX output something useful here */
+}
+
+#ifdef HAVE_VTS
+static void
+StopToTTY( struct display *d )
+{
+ if ((d->displayType & d_location) == dLocal)
+ switch (d->status) {
+ default:
+ rStopDisplay( d, DS_TEXTMODE | 0x100 );
+ case reserve:
+ case textMode:
+ break;
+ }
+}
+
+static void
+CheckTTYMode( void )
+{
+ struct display *d;
+
+ for (d = displays; d; d = d->next)
+ if (d->status == zombie)
+ return;
+
+ SwitchToTty();
+}
+
+#else
+
+void
+SwitchToX( struct display *d )
+{
+ struct utmps *utp, **utpp;
+
+ for (utpp = &utmpList; (utp = *utpp); utpp = &(*utpp)->next)
+ if (utp->d == d) {
+ *utpp = utp->next;
+ free( utp );
+ d->status = notRunning;
+ return;
+ }
+}
+#endif
+
+#ifdef XDMCP
+static void
+StartRemoteLogin( struct display *d )
+{
+ char **argv;
+ int pid;
+
+ Debug( "StartRemoteLogin for %s\n", d->name );
+ /* HACK: omitting LoadDisplayResources( d ) here! */
+ switch (pid = Fork()) {
+ case 0:
+ argv = PrepServerArgv( d, d->serverArgsRemote );
+ if (!(argv = addStrArr( argv, "-once", 5 )) ||
+ !(argv = addStrArr( argv, "-query", 6 )) ||
+ !(argv = addStrArr( argv, d->remoteHost, -1 )))
+ exit( 1 );
+ Debug( "exec %\"[s\n", argv );
+ (void)execv( argv[0], argv );
+ LogError( "X server %\"s cannot be executed\n", argv[0] );
+ exit( 1 );
+ case -1:
+ LogError( "Forking X server for remote login failed: %m" );
+ d->status = notRunning;
+ return;
+ default:
+ break;
+ }
+ Debug( "X server forked, pid %d\n", pid );
+ d->serverPid = pid;
+
+ d->status = remoteLogin;
+}
+#endif
+
+
+static void
+StopInactiveDisplay( struct display *d )
+{
+ if (d->status != remoteLogin && d->userSess < 0)
+ StopDisplay( d );
+}
+
+static void
+stoppen( int force )
+{
+#ifdef XDMCP
+ request_port = 0;
+ UpdateListenSockets();
+#endif
+ if (force)
+ ForEachDisplay( StopDisplay );
+ else
+ ForEachDisplay( StopInactiveDisplay );
+ Stopping = 1;
+}
+
+
+void
+setNLogin( struct display *d,
+ const char *nuser, const char *npass, char *nargs, int rl )
+{
+ struct disphist *he = d->hstent;
+ he->rLogin =
+ (ReStr( &he->nuser, nuser ) &&
+ ReStr( &he->npass, npass ) &&
+ ReStr( &he->nargs, nargs )) ? rl : 0;
+ Debug( "set next login for %s, level %d\n", nuser, rl );
+}
+
+static void
+processDPipe( struct display *d )
+{
+ char *user, *pass, *args;
+ int cmd;
+ GTalk dpytalk;
+#ifdef XDMCP
+ int ct, len;
+ ARRAY8 ca, ha;
+#endif
+
+ dpytalk.pipe = &d->pipe;
+ if (Setjmp( dpytalk.errjmp )) {
+ StopDisplay( d );
+ return;
+ }
+ GSet( &dpytalk );
+ if (!GRecvCmd( &cmd )) {
+ /* process already exited */
+ UnregisterInput( d->pipe.rfd );
+ return;
+ }
+ switch (cmd) {
+ case D_User:
+ d->userSess = GRecvInt();
+ d->userName = GRecvStr();
+ d->sessName = GRecvStr();
+ break;
+ case D_ReLogin:
+ user = GRecvStr();
+ pass = GRecvStr();
+ args = GRecvStr();
+ setNLogin( d, user, pass, args, 1 );
+ free( args );
+ free( pass );
+ free( user );
+ break;
+#ifdef XDMCP
+ case D_ChooseHost:
+ ca.data = (unsigned char *)GRecvArr( &len );
+ ca.length = (CARD16)len;
+ ct = GRecvInt();
+ ha.data = (unsigned char *)GRecvArr( &len );
+ ha.length = (CARD16)len;
+ RegisterIndirectChoice( &ca, ct, &ha );
+ XdmcpDisposeARRAY8( &ha );
+ XdmcpDisposeARRAY8( &ca );
+ break;
+ case D_RemoteHost:
+ if (d->remoteHost)
+ free( d->remoteHost );
+ d->remoteHost = GRecvStr();
+ break;
+#endif
+ case D_XConnOk:
+ startingServer = 0;
+ break;
+ default:
+ LogError( "Internal error: unknown D_* command %d\n", cmd );
+ StopDisplay( d );
+ break;
+ }
+}
+
+static void
+emitXSessG( struct display *di, struct display *d, void *ctx ATTR_UNUSED )
+{
+ GSendStr( di->name );
+ GSendStr( "" );
+#ifdef HAVE_VTS
+ GSendInt( di->serverVT );
+#endif
+#ifdef XDMCP
+ if (di->status == remoteLogin) {
+ GSendStr( "" );
+ GSendStr( di->remoteHost );
+ } else
+#endif
+ {
+ GSendStr( di->userName );
+ GSendStr( di->sessName );
+ }
+ GSendInt( di == d ? isSelf : 0 );
+}
+
+static void
+emitTTYSessG( STRUCTUTMP *ut, struct display *d ATTR_UNUSED, void *ctx ATTR_UNUSED )
+{
+ GSendStrN( ut->ut_line, sizeof(ut->ut_line) );
+ GSendStrN( ut->ut_host, sizeof(ut->ut_host) );
+#ifdef HAVE_VTS
+ GSendInt( TTYtoVT( ut->ut_line ) );
+#endif
+#ifdef BSD_UTMP
+ GSendStrN( *ut->ut_user ? ut->ut_user : 0, sizeof(ut->ut_user) );
+#else
+ GSendStrN( ut->ut_type == USER_PROCESS ? ut->ut_user : 0, sizeof(ut->ut_user) );
+#endif
+ GSendStr( 0 ); /* session type unknown */
+ GSendInt( isTTY );
+}
+
+static void
+processGPipe( struct display *d )
+{
+ char **opts, *option;
+ int cmd, ret, dflt, curr;
+ GTalk dpytalk;
+
+ dpytalk.pipe = &d->gpipe;
+ if (Setjmp( dpytalk.errjmp )) {
+ StopDisplay( d );
+ return;
+ }
+ GSet( &dpytalk );
+ if (!GRecvCmd( &cmd )) {
+ /* process already exited */
+ UnregisterInput( d->gpipe.rfd );
+ return;
+ }
+ switch (cmd) {
+ case G_ListBootOpts:
+ ret = getBootOptions( &opts, &dflt, &curr );
+ GSendInt( ret );
+ if (ret == BO_OK) {
+ GSendArgv( opts );
+ freeStrArr( opts );
+ GSendInt( dflt );
+ GSendInt( curr );
+ }
+ break;
+ case G_Shutdown:
+ sdRec.how = GRecvInt();
+ sdRec.start = GRecvInt();
+ sdRec.timeout = GRecvInt();
+ sdRec.force = GRecvInt();
+ sdRec.uid = GRecvInt();
+ option = GRecvStr();
+ setBootOption( option, &sdRec );
+ if (option)
+ free( option );
+ break;
+ case G_QueryShutdown:
+ GSendInt( sdRec.how );
+ GSendInt( sdRec.start );
+ GSendInt( sdRec.timeout );
+ GSendInt( sdRec.force );
+ GSendInt( sdRec.uid );
+ GSendStr( sdRec.osname );
+ break;
+ case G_List:
+ ListSessions( GRecvInt(), d, 0, emitXSessG, emitTTYSessG );
+ GSendInt( 0 );
+ break;
+#ifdef HAVE_VTS
+ case G_Activate:
+ activateVT( GRecvInt() );
+ break;
+#endif
+ case G_Console:
+#ifdef HAVE_VTS
+ if (*consoleTTYs) { /* sanity check against greeter */
+ ForEachDisplay( StopToTTY );
+ CheckTTYMode();
+ }
+#else
+ if (*d->console) /* sanity check against greeter */
+ rStopDisplay( d, DS_TEXTMODE );
+#endif
+ break;
+ default:
+ LogError( "Internal error: unknown G_* command %d\n", cmd );
+ StopDisplay( d );
+ break;
+ }
+}
+
+
+static int
+ScanConfigs( int force )
+{
+ int ret;
+
+ if ((ret = LoadDMResources( force )) <= 0)
+ return ret;
+ ScanServers();
+#ifdef XDMCP
+ ScanAccessDatabase( force );
+#endif
+ return 1;
+}
+
+static void
+MarkDisplay( struct display *d )
+{
+ d->stillThere = 0;
+}
+
+static void
+RescanConfigs( int force )
+{
+ if (ScanConfigs( force ) > 0) {
+#ifdef XDMCP
+ UpdateListenSockets();
+#endif
+ updateCtrl();
+ }
+}
+
+void
+cancelShutdown( void )
+{
+ sdRec.how = 0;
+ if (sdRec.osname) {
+ free( sdRec.osname );
+ sdRec.osname = 0;
+ }
+ Stopping = 0;
+ RescanConfigs( TRUE );
+}
+
+
+static void
+ReapChildren( void )
+{
+ int pid;
+ struct display *d;
+ waitType status;
+
+ while ((pid = waitpid( -1, &status, WNOHANG )) > 0)
+ {
+ Debug( "manager wait returns pid %d sig %d core %d code %d\n",
+ pid, waitSig( status ), waitCore( status ), waitCode( status ) );
+ /* SUPPRESS 560 */
+ if ((d = FindDisplayByPid( pid ))) {
+ d->pid = -1;
+ UnregisterInput( d->pipe.rfd );
+ GClosen (&d->pipe);
+ UnregisterInput( d->gpipe.rfd );
+ GClosen (&d->gpipe);
+ closeCtrl( d );
+ switch (waitVal( status )) {
+#ifdef XDMCP
+ case EX_REMOTE:
+ Debug( "display exited with EX_REMOTE\n" );
+ ExitDisplay( d, DS_REMOTE, 0, 0 );
+ break;
+#endif
+ case EX_NORMAL:
+ /* (any type of) session ended */
+ Debug( "display exited with EX_NORMAL\n" );
+ if ((d->displayType & d_lifetime) == dReserve)
+ ExitDisplay( d, DS_RESERVE, 0, 0 );
+ else
+ ExitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
+ break;
+#if 0
+ case EX_REMANAGE_DPY:
+ /* user session ended */
+ Debug( "display exited with EX_REMANAGE_DPY\n" );
+ ExitDisplay( d, DS_RESTART, XS_KEEP, TRUE );
+ break;
+#endif
+ case EX_OPENFAILED_DPY:
+ /* WaitForServer() failed */
+ LogError( "Display %s cannot be opened\n", d->name );
+#ifdef XDMCP
+ /*
+ * no display connection was ever made, tell the
+ * terminal that the open attempt failed
+ */
+ if ((d->displayType & d_origin) == dFromXDMCP)
+ SendFailed( d, "cannot open display" );
+#endif
+ ExitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
+ break;
+ case waitCompose( SIGTERM,0,0 ):
+ /* killed before/during WaitForServer()
+ - local Xserver died
+ - display stopped (is zombie)
+ - "login now" and "suicide" pipe commands (is raiser)
+ */
+ Debug( "display exited on SIGTERM\n" );
+ ExitDisplay( d, DS_RESTART, XS_RETRY, FALSE );
+ break;
+ case EX_AL_RESERVER_DPY:
+ /* - killed after WaitForServer()
+ - Xserver dead after remote session exit
+ */
+ Debug( "display exited with EX_AL_RESERVER_DPY\n" );
+ ExitDisplay( d, DS_RESTART, XS_RESTART, FALSE );
+ break;
+ case EX_RESERVER_DPY:
+ /* induced by greeter:
+ - could not secure display
+ - requested by user
+ */
+ Debug( "display exited with EX_RESERVER_DPY\n" );
+ ExitDisplay( d, DS_RESTART, XS_RESTART, TRUE );
+ break;
+ case EX_UNMANAGE_DPY:
+ /* some fatal error */
+ Debug( "display exited with EX_UNMANAGE_DPY\n" );
+ ExitDisplay( d, DS_REMOVE, 0, 0 );
+ break;
+ default:
+ /* prolly crash */
+ LogError( "Unknown session exit code %d (sig %d) from manager process\n",
+ waitCode( status ), waitSig( status ) );
+ ExitDisplay( d, DS_REMOVE, 0, 0 );
+ break;
+ }
+ } else if ((d = FindDisplayByServerPid( pid ))) {
+ d->serverPid = -1;
+ switch (d->status) {
+ case zombie:
+ Debug( "zombie X server for display %s reaped\n", d->name );
+#ifdef HAVE_VTS
+ if (d->serverVT && d->zstatus != DS_REMOTE) {
+ if (d->follower) {
+ d->follower->serverVT = d->serverVT;
+ d->follower = 0;
+ } else {
+ int con = open( "/dev/console", O_RDONLY );
+ if (con >= 0) {
+ struct vt_stat vtstat;
+ ioctl( con, VT_GETSTATE, &vtstat );
+ if (vtstat.v_active == d->serverVT) {
+ int vt = 1;
+ struct display *di;
+ for (di = displays; di; di = di->next)
+ if (di != d && di->serverVT)
+ vt = di->serverVT;
+ for (di = displays; di; di = di->next)
+ if (di != d && di->serverVT &&
+ (di->userSess >= 0 ||
+ di->status == remoteLogin))
+ vt = di->serverVT;
+ ioctl( con, VT_ACTIVATE, vt );
+ }
+ ioctl( con, VT_DISALLOCATE, d->serverVT );
+ close( con );
+ }
+ }
+ d->serverVT = 0;
+ }
+#endif
+ rStopDisplay( d, d->zstatus );
+ break;
+ case phoenix:
+ Debug( "phoenix X server arises, restarting display %s\n",
+ d->name );
+ d->status = notRunning;
+ break;
+ case remoteLogin:
+ Debug( "remote login X server for display %s exited\n",
+ d->name );
+ d->status = ((d->displayType & d_lifetime) == dReserve) ?
+ reserve : notRunning;
+ break;
+ case raiser:
+ LogError( "X server for display %s terminated unexpectedly\n",
+ d->name );
+ /* don't kill again */
+ break;
+ case running:
+ if (startingServer == d && d->serverStatus != ignore) {
+ if (d->serverStatus == starting && waitCode( status ) != 47)
+ LogError( "X server died during startup\n" );
+ StartServerFailed();
+ break;
+ }
+ LogError( "X server for display %s terminated unexpectedly\n",
+ d->name );
+ if (d->pid != -1) {
+ Debug( "terminating session pid %d\n", d->pid );
+ TerminateProcess( d->pid, SIGTERM );
+ }
+ break;
+ case notRunning:
+ case textMode:
+ case reserve:
+ /* this cannot happen */
+ Debug( "X server exited for passive (%d) session on display %s\n",
+ (int)d->status, d->name );
+ break;
+ }
+ } else
+ Debug( "unknown child termination\n" );
+ }
+#ifdef NEED_ENTROPY
+ AddOtherEntropy();
+#endif
+}
+
+static int
+wouldShutdown( void )
+{
+ struct display *d;
+
+ if (sdRec.force != SHUT_CANCEL) {
+ if (sdRec.force == SHUT_FORCEMY)
+ for (d = displays; d; d = d->next)
+ if (d->status == remoteLogin ||
+ (d->userSess >= 0 && d->userSess != sdRec.uid))
+ return 0;
+ return 1;
+ }
+ return !AnyActiveDisplays();
+}
+
+FD_TYPE WellKnownSocketsMask;
+int WellKnownSocketsMax;
+int WellKnownSocketsCount;
+
+void
+RegisterInput( int fd )
+{
+ /* can be omited, as it is always called right after opening a socket
+ if (!FD_ISSET (fd, &WellKnownSocketsMask))
+ */
+ {
+ FD_SET( fd, &WellKnownSocketsMask );
+ if (fd > WellKnownSocketsMax)
+ WellKnownSocketsMax = fd;
+ WellKnownSocketsCount++;
+ }
+}
+
+void
+UnregisterInput( int fd )
+{
+ /* the check _is_ necessary, as some handles are unregistered before
+ the regular close sequence.
+ */
+ if (FD_ISSET( fd, &WellKnownSocketsMask )) {
+ FD_CLR( fd, &WellKnownSocketsMask );
+ WellKnownSocketsCount--;
+ }
+}
+
+static void
+SigHandler( int n )
+{
+ int olderrno = errno;
+ char buf = (char)n;
+ /* Debug( "caught signal %d\n", n ); this hangs in syslog() */
+ write( signalFds[1], &buf, 1 );
+#ifdef __EMX__
+ (void)Signal( n, SigHandler );
+#endif
+ errno = olderrno;
+}
+
+static void
+MainLoop( void )
+{
+ struct display *d;
+ struct timeval *tvp, tv;
+ time_t to;
+ int nready;
+ char buf;
+ FD_TYPE reads;
+
+ Debug( "MainLoop\n" );
+ time( &now );
+ while (
+#ifdef XDMCP
+ AnyListenSockets() ||
+#endif
+ (Stopping ? AnyRunningDisplays() : AnyDisplaysLeft()))
+ {
+ if (!Stopping)
+ StartDisplays();
+ to = TO_INF;
+ if (sdRec.how) {
+ if (sdRec.start != TO_INF && now < sdRec.start) {
+ /*if (sdRec.start < to)*/
+ to = sdRec.start;
+ } else {
+ sdRec.start = TO_INF;
+ if (now >= sdRec.timeout) {
+ sdRec.timeout = TO_INF;
+ if (wouldShutdown())
+ stoppen( TRUE );
+ else
+ cancelShutdown();
+ } else {
+ stoppen( FALSE );
+ /*if (sdRec.timeout < to)*/
+ to = sdRec.timeout;
+ }
+ }
+ }
+ if (serverTimeout < to)
+ to = serverTimeout;
+ if (utmpTimeout < to)
+ to = utmpTimeout;
+ if (to == TO_INF)
+ tvp = 0;
+ else {
+ to -= now;
+ if (to < 0)
+ to = 0;
+ tv.tv_sec = to;
+ tv.tv_usec = 0;
+ tvp = &tv;
+ }
+ reads = WellKnownSocketsMask;
+ nready = select( WellKnownSocketsMax + 1, &reads, 0, 0, tvp );
+ Debug( "select returns %d\n", nready );
+ time( &now );
+#ifdef NEED_ENTROPY
+ AddTimerEntropy();
+#endif
+ if (now >= serverTimeout) {
+ serverTimeout = TO_INF;
+ StartServerTimeout();
+ }
+ if (now >= utmpTimeout) {
+ utmpTimeout = TO_INF;
+ CheckUtmp();
+ }
+ if (nready > 0) {
+ /*
+ * we restart after the first handled fd, as
+ * a) it makes things simpler
+ * b) the probability that multiple fds trigger at once is
+ * ridiculously small. we handle it in the next iteration.
+ */
+ /* XXX a cleaner solution would be a callback mechanism */
+ if (FD_ISSET( signalFds[0], &reads )) {
+ if (read( signalFds[0], &buf, 1 ) != 1)
+ LogPanic( "Signal notification pipe broken.\n" );
+ switch (buf) {
+ case SIGTERM:
+ case SIGINT:
+ Debug( "shutting down entire manager\n" );
+ stoppen( TRUE );
+ break;
+ case SIGHUP:
+ LogInfo( "Rescanning all config files\n" );
+ ForEachDisplay( MarkDisplay );
+ RescanConfigs( TRUE );
+ break;
+ case SIGCHLD:
+ ReapChildren();
+ if (!Stopping && autoRescan)
+ RescanConfigs( FALSE );
+ break;
+ case SIGUSR1:
+ if (startingServer &&
+ startingServer->serverStatus == starting)
+ StartServerSuccess();
+ break;
+ }
+ continue;
+ }
+#ifdef XDMCP
+ if (ProcessListenSockets( &reads ))
+ continue;
+#endif /* XDMCP */
+ if (handleCtrl( &reads, 0 ))
+ continue;
+ /* Must be last (because of the breaks)! */
+ again:
+ for (d = displays; d; d = d->next) {
+ if (handleCtrl( &reads, d ))
+ goto again;
+ if (d->pipe.rfd >= 0 && FD_ISSET( d->pipe.rfd, &reads )) {
+ processDPipe( d );
+ break;
+ }
+ if (d->gpipe.rfd >= 0 && FD_ISSET( d->gpipe.rfd, &reads )) {
+ processGPipe( d );
+ break;
+ }
+ }
+ }
+ }
+}
+
+static void
+CheckDisplayStatus( struct display *d )
+{
+ if ((d->displayType & d_origin) == dFromFile && !d->stillThere)
+ StopDisplay( d );
+ else if ((d->displayType & d_lifetime) == dReserve &&
+ d->status == running && d->userSess < 0 && !d->idleTimeout)
+ rStopDisplay( d, DS_RESERVE );
+ else if (d->status == notRunning)
+ if (LoadDisplayResources( d ) < 0) {
+ LogError( "Unable to read configuration for display %s; "
+ "stopping it.\n", d->name );
+ StopDisplay( d );
+ return;
+ }
+}
+
+static void
+KickDisplay( struct display *d )
+{
+ if (d->status == notRunning)
+ StartDisplay( d );
+ if (d->serverStatus == awaiting && !startingServer)
+ StartServer( d );
+}
+
+#ifdef HAVE_VTS
+static int active_vts;
+
+static int
+GetBusyVTs( void )
+{
+ struct vt_stat vtstat;
+ int con;
+
+ if (active_vts == -1) {
+ vtstat.v_state = 0;
+ if ((con = open( "/dev/console", O_RDONLY )) >= 0) {
+ ioctl( con, VT_GETSTATE, &vtstat );
+ close( con );
+ }
+ active_vts = vtstat.v_state;
+ }
+ return active_vts;
+}
+
+static void
+AllocateVT( struct display *d )
+{
+ struct display *cd;
+ int i, tvt, volun;
+
+ if ((d->displayType & d_location) == dLocal &&
+ d->status == notRunning && !d->serverVT && d->reqSrvVT >= 0)
+ {
+ if (d->reqSrvVT && d->reqSrvVT < 16)
+ d->serverVT = d->reqSrvVT;
+ else {
+ for (i = tvt = 0;;) {
+ if (serverVTs[i]) {
+ tvt = atoi( serverVTs[i++] );
+ volun = 0;
+ if (tvt < 0) {
+ tvt = -tvt;
+ volun = 1;
+ }
+ if (!tvt || tvt >= 16)
+ continue;
+ } else {
+ if (++tvt >= 16)
+ break;
+ volun = 1;
+ }
+ for (cd = displays; cd; cd = cd->next) {
+ if (cd->reqSrvVT == tvt && /* protect from lusers */
+ (cd->status != zombie || cd->zstatus != DS_REMOVE))
+ goto next;
+ if (cd->serverVT == tvt) {
+ if (cd->status != zombie || cd->zstatus == DS_REMOTE)
+ goto next;
+ if (!cd->follower) {
+ d->serverVT = -1;
+ cd->follower = d;
+ return;
+ }
+ }
+ }
+ if (!volun || !((1 << tvt) & GetBusyVTs())) {
+ d->serverVT = tvt;
+ return;
+ }
+ next: ;
+ }
+ }
+ }
+}
+#endif
+
+static void
+StartDisplays( void )
+{
+ ForEachDisplay( CheckDisplayStatus );
+ CloseGetter();
+#ifdef HAVE_VTS
+ active_vts = -1;
+ ForEachDisplayRev( AllocateVT );
+#endif
+ ForEachDisplay( KickDisplay );
+}
+
+void
+StartDisplay( struct display *d )
+{
+ if (Stopping) {
+ Debug( "stopping display %s because shutdown is scheduled\n", d->name );
+ StopDisplay( d );
+ return;
+ }
+
+#ifdef HAVE_VTS
+ if (d->serverVT < 0)
+ return;
+#endif
+
+ d->status = running;
+ if ((d->displayType & d_location) == dLocal) {
+ Debug( "StartDisplay %s\n", d->name );
+ /* don't bother pinging local displays; we'll
+ * certainly notice when they exit
+ */
+ d->pingInterval = 0;
+ if (d->authorize) {
+ SetLocalAuthorization( d );
+ /*
+ * reset the server after writing the authorization information
+ * to make it read the file (for compatibility with old
+ * servers which read auth file only on reset instead of
+ * at first connection)
+ */
+ if (d->serverPid != -1 && d->resetForAuth && d->resetSignal)
+ kill( d->serverPid, d->resetSignal );
+ }
+ if (d->serverPid == -1) {
+ d->serverStatus = awaiting;
+ return;
+ }
+ } else {
+ Debug( "StartDisplay %s, try %d\n", d->name, d->startTries + 1 );
+ /* this will only happen when using XDMCP */
+ if (d->authorizations)
+ SaveServerAuthorizations( d, d->authorizations, d->authNum );
+ }
+ StartDisplayP2( d );
+}
+
+void
+StartDisplayP2( struct display *d )
+{
+ char *cname, *cgname;
+ int pid;
+
+ openCtrl( d );
+ Debug( "forking session\n" );
+ ASPrintf( &cname, "sub-daemon for display %s", d->name );
+ ASPrintf( &cgname, "greeter for display %s", d->name );
+ pid = GFork( &d->pipe, "master daemon", cname,
+ &d->gpipe, cgname );
+ switch (pid) {
+ case 0:
+ SetTitle( d->name );
+ if (debugLevel & DEBUG_WSESS)
+ sleep( 100 );
+ mstrtalk.pipe = &d->pipe;
+ (void)Signal( SIGPIPE, SIG_IGN );
+ SetAuthorization( d );
+ WaitForServer( d );
+ if ((d->displayType & d_location) == dLocal) {
+ GSet( &mstrtalk );
+ GSendInt( D_XConnOk );
+ }
+ ManageSession( d );
+ /* NOTREACHED */
+ case -1:
+ closeCtrl( d );
+ d->status = notRunning;
+ break;
+ default:
+ Debug( "forked session, pid %d\n", pid );
+
+ /* (void) fcntl (d->pipe.rfd, F_SETFL, O_NONBLOCK); */
+ /* (void) fcntl (d->gpipe.rfd, F_SETFL, O_NONBLOCK); */
+ RegisterInput( d->pipe.rfd );
+ RegisterInput( d->gpipe.rfd );
+
+ d->pid = pid;
+ d->hstent->lock = d->hstent->rLogin = d->hstent->goodExit =
+ d->hstent->sdRec.how = 0;
+ d->lastStart = now;
+ break;
+ }
+}
+
+/*
+ * transition from running to zombie, textmode, reserve or deleted
+ */
+
+static void
+rStopDisplay( struct display *d, int endState )
+{
+ Debug( "stopping display %s to state %d\n", d->name, endState );
+ AbortStartServer( d );
+ d->idleTimeout = 0;
+ if (d->serverPid != -1 || d->pid != -1) {
+ if (d->pid != -1)
+ TerminateProcess( d->pid, SIGTERM );
+ if (d->serverPid != -1)
+ TerminateProcess( d->serverPid, d->termSignal );
+ d->status = zombie;
+ d->zstatus = endState & 0xff;
+ Debug( " zombiefied\n" );
+ } else if (endState == DS_TEXTMODE) {
+#ifdef HAVE_VTS
+ d->status = textMode;
+ CheckTTYMode();
+ } else if (endState == (DS_TEXTMODE | 0x100)) {
+ d->status = textMode;
+#else
+ SwitchToTty( d );
+#endif
+ } else if (endState == DS_RESERVE)
+ d->status = reserve;
+#ifdef XDMCP
+ else if (endState == DS_REMOTE)
+ StartRemoteLogin( d );
+#endif
+ else {
+#ifndef HAVE_VTS
+ SwitchToX( d );
+#endif
+ RemoveDisplay( d );
+ }
+}
+
+void
+StopDisplay( struct display *d )
+{
+ rStopDisplay( d, DS_REMOVE );
+}
+
+static void
+ExitDisplay(
+ struct display *d,
+ int endState,
+ int serverCmd,
+ int goodExit )
+{
+ struct disphist *he;
+
+ if (d->status == raiser) {
+ serverCmd = XS_KEEP;
+ goodExit = TRUE;
+ }
+
+ Debug( "ExitDisplay %s, "
+ "endState = %d, serverCmd = %d, GoodExit = %d\n",
+ d->name, endState, serverCmd, goodExit );
+
+ d->userSess = -1;
+ if (d->userName)
+ free( d->userName );
+ d->userName = 0;
+ if (d->sessName)
+ free( d->sessName );
+ d->sessName = 0;
+ he = d->hstent;
+ he->lastExit = now;
+ he->goodExit = goodExit;
+ if (he->sdRec.how) {
+ if (he->sdRec.force == SHUT_ASK &&
+ (AnyActiveDisplays() || d->allowShutdown == SHUT_ROOT))
+ {
+ endState = DS_RESTART;
+ } else {
+ if (!sdRec.how || sdRec.force != SHUT_FORCE ||
+ !((d->allowNuke == SHUT_NONE && sdRec.uid != he->sdRec.uid) ||
+ (d->allowNuke == SHUT_ROOT && he->sdRec.uid)))
+ {
+ if (sdRec.osname)
+ free( sdRec.osname );
+ sdRec = he->sdRec;
+ if (now < sdRec.timeout || wouldShutdown())
+ endState = DS_REMOVE;
+ } else if (he->sdRec.osname)
+ free( he->sdRec.osname );
+ he->sdRec.how = 0;
+ he->sdRec.osname = 0;
+ }
+ }
+ if (d->status == zombie)
+ rStopDisplay( d, d->zstatus );
+ else {
+ if (Stopping) {
+ StopDisplay( d );
+ return;
+ }
+ if (endState != DS_RESTART ||
+ (d->displayType & d_origin) != dFromFile)
+ {
+ rStopDisplay( d, endState );
+ } else {
+ if (serverCmd == XS_RETRY) {
+ if ((d->displayType & d_location) == dLocal) {
+ if (he->lastExit - d->lastStart < 120) {
+ LogError( "Unable to fire up local display %s;"
+ " disabling.\n", d->name );
+ StopDisplay( d );
+ return;
+ }
+ } else {
+ if (++d->startTries > d->startAttempts) {
+ LogError( "Disabling foreign display %s"
+ " (too many attempts)\n", d->name );
+ StopDisplay( d );
+ return;
+ }
+ }
+ } else
+ d->startTries = 0;
+ if (d->serverPid != -1 &&
+ (serverCmd != XS_KEEP || d->terminateServer))
+ {
+ Debug( "killing X server for %s\n", d->name );
+ TerminateProcess( d->serverPid, d->termSignal );
+ d->status = phoenix;
+ } else
+ d->status = notRunning;
+ }
+ }
+}
+
+
+static int pidFd;
+static FILE *pidFilePtr;
+
+static int
+StorePid( void )
+{
+ int oldpid;
+
+ if (pidFile[0] != '\0') {
+ pidFd = open( pidFile, O_RDWR );
+ if (pidFd == -1 && errno == ENOENT)
+ pidFd = open( pidFile, O_RDWR|O_CREAT, 0666 );
+ if (pidFd == -1 || !(pidFilePtr = fdopen( pidFd, "r+" ))) {
+ LogError( "process-id file %s cannot be opened\n",
+ pidFile );
+ return -1;
+ }
+ if (fscanf( pidFilePtr, "%d\n", &oldpid ) != 1)
+ oldpid = -1;
+ fseek( pidFilePtr, 0l, 0 );
+ if (lockPidFile) {
+#ifdef F_SETLK
+# ifndef SEEK_SET
+# define SEEK_SET 0
+# endif
+ struct flock lock_data;
+ lock_data.l_type = F_WRLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = lock_data.l_len = 0;
+ if (fcntl( pidFd, F_SETLK, &lock_data ) == -1) {
+ if (errno == EAGAIN)
+ return oldpid;
+ else
+ return -1;
+ }
+#else
+# ifdef LOCK_EX
+ if (flock( pidFd, LOCK_EX|LOCK_NB ) == -1) {
+ if (errno == EWOULDBLOCK)
+ return oldpid;
+ else
+ return -1;
+ }
+# else
+ if (lockf( pidFd, F_TLOCK, 0 ) == -1) {
+ if (errno == EACCES)
+ return oldpid;
+ else
+ return -1;
+ }
+# endif
+#endif
+ }
+ fprintf( pidFilePtr, "%ld\n", (long)getpid() );
+ (void)fflush( pidFilePtr );
+ RegisterCloseOnFork( pidFd );
+ }
+ return 0;
+}
+
+#if 0
+void
+UnlockPidFile( void )
+{
+ if (lockPidFile)
+# ifdef F_SETLK
+ {
+ struct flock lock_data;
+ lock_data.l_type = F_UNLCK;
+ lock_data.l_whence = SEEK_SET;
+ lock_data.l_start = lock_data.l_len = 0;
+ (void)fcntl( pidFd, F_SETLK, &lock_data );
+ }
+# else
+# ifdef F_ULOCK
+ lockf( pidFd, F_ULOCK, 0 );
+# else
+ flock( pidFd, LOCK_UN );
+# endif
+# endif
+ close( pidFd );
+ fclose( pidFilePtr );
+}
+#endif
+
+void
+SetTitle( const char *name )
+{
+#if !defined(HAVE_SETPROCTITLE) && !defined(NOXDMTITLE)
+ char *p;
+ int left;
+#endif
+
+ ASPrintf( &prog, "%s: %s", prog, name );
+ ReInitErrorLog();
+#ifdef HAVE_SETPROCTITLE
+ setproctitle( "%s", name );
+#elif !defined(NOXDMTITLE)
+ p = Title;
+ left = TitleLen;
+
+ *p++ = '-';
+ --left;
+ while (*name && left > 0) {
+ *p++ = *name++;
+ --left;
+ }
+ while (left > 0) {
+ *p++ = '\0';
+ --left;
+ }
+#endif
+}