summaryrefslogtreecommitdiffstats
path: root/kdm/backend/dm.c
diff options
context:
space:
mode:
authorTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-01-22 01:02:36 -0600
committerTimothy Pearson <kb9vqf@pearsoncomputing.net>2012-01-22 01:02:36 -0600
commitb81e43465b14836b17e4fe2dea91c78a2bdd29b3 (patch)
tree7815d61ce59a6ccb6e655ed44f5fea786f520985 /kdm/backend/dm.c
parent7021f40c13f949b7cb5ded32d0241d648a43bf6c (diff)
downloadtdebase-b81e43465b14836b17e4fe2dea91c78a2bdd29b3.tar.gz
tdebase-b81e43465b14836b17e4fe2dea91c78a2bdd29b3.zip
Part 2 of prior commit
Diffstat (limited to 'kdm/backend/dm.c')
-rw-r--r--kdm/backend/dm.c1669
1 files changed, 0 insertions, 1669 deletions
diff --git a/kdm/backend/dm.c b/kdm/backend/dm.c
deleted file mode 100644
index d372dd472..000000000
--- a/kdm/backend/dm.c
+++ /dev/null
@@ -1,1669 +0,0 @@
-/*
-
-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 <stdlib.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, *name, *thenam, nambuf[PATH_MAX+1];
- char *pathe;
-
- 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] );
-
- /* Let's try again with some standard paths */
- argv[0] = (char *)realloc(argv[0], strlen("/usr/X11R6/bin/X") + 1);
- if (argv[0] != NULL) {
- argv[0] = "/usr/X11R6/bin/X";
- Debug( "exec %\"[s\n", argv );
- (void)execv( argv[0], argv );
- LogError( "X server %\"s cannot be executed\n", argv[0] );
-
- argv[0] = "/usr/bin/X"; /* Shorter than the previous file name */
- 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
-}