backspace at login prompt shown as 2 backspace
Gert Doering (gert@greenie.muc.de)
Sun, 12 Nov 1995 18:38:16 +0100
Hi,
Gert Doering wrote:
> Jan Richert wrote:
> > mgetty 0.97
> > linux 1.2.11
> >
> > Problem: If some characters are typed at login prompt and backspace
> > is pressed TWO characters are erased for each time bs is pressed.
> >
> > This problem didn't exist with mgetty 0.22 in the same environment.
>
> Hmmm. I changed something in there, that's right. I *know* that I still
> didn't get the backspacing on Linux completely right, but I'm afraid that
> to *get* it right, I'll have to rewrite the terminal handling of login.c
> *sigh*.
Done. A test version with reworked "logname.c" can be found on ftp.leo.org
as mgetty099-Nov12, and I'll attach the new "logname.c" below. This
version should *finally* work with every variant of Backspace/<DEL>, Echoe
or not, ...
gert
-----------------
#ident "@(#)logname.c 3.5 95/11/12 Copyright (c) Gert Doering"
#include <stdio.h>
#include "syslibs.h"
#include <unistd.h>
#include <string.h>
#include <signal.h>
#include <sys/types.h>
#include <time.h>
#include <ctype.h>
#ifndef sunos4
#include <sys/ioctl.h>
#endif
#ifndef ENOENT
#include <errno.h>
#endif
#include "mgetty.h"
#include "policy.h"
#include "tio.h"
#include "mg_utmp.h"
#ifndef SYSTEM
#include <sys/utsname.h>
#endif
/* ln_escape_prompt()
*
* substitute all "known" escapes, e.g. "\n" and "\t", plus some
* private extentions (@, \D and \T for system name, date, and time)
*
* The caller has to free() the string returned
*
* If the resulting string would be too long, it's silently truncated.
*/
int strappnd _P2((s1,s2), char * s1, char * s2 )
{
strcpy( s1, s2 );
return strlen( s1 );
}
char * ln_escape_prompt _P1( (ep), char * ep )
{
#define MAX_PROMPT_LENGTH 140
static char * p = NULL;
int i;
extern char * Device; /* mgetty.c */
if ( p == NULL ) p = malloc( MAX_PROMPT_LENGTH );
if ( p == NULL ) return ep;
i = 0;
while ( *ep != 0 && i < MAX_PROMPT_LENGTH-4 )
{
if ( *ep == '@' ) /* system name */
{
#ifdef SYSTEM
if ( sizeof( SYSTEM ) + i > MAX_PROMPT_LENGTH ) break;
i += strappnd( &p[i], SYSTEM );
#else
struct utsname un;
uname( &un );
if ( strlen( un.nodename ) +1 +i > MAX_PROMPT_LENGTH ) break;
i += strappnd( &p[i], un.nodename );
#endif
}
else if ( *ep != '\\' ) p[i++] = *ep;
else /* *ep == '\\' */
{
ep++;
switch ( *ep )
{
case 'n': p[i++] = '\n'; break;
case 'r': p[i++] = '\r'; break;
case 'g': p[i++] = '\007'; break;
case 'b': p[i++] = '\010'; break;
case 'v': p[i++] = '\013'; break;
case 'f': p[i++] = '\f'; break;
case 't': p[i++] = '\t'; break;
case 'P': /* port name */
case 'L': /* tty line */
{
if ( i + strlen(Device) +1 > MAX_PROMPT_LENGTH ) break;
i += strappnd( &p[i], Device );
break;
}
case 'C': /* ctime */
{
time_t ti = time(NULL);
char * h = ctime( &ti );
if ( strlen(h) +1 +i > MAX_PROMPT_LENGTH ) break;
i += strappnd( &p[i], h ) -1;
break;
}
case 'I':
{
if ( strlen(Connect) +1 +i > MAX_PROMPT_LENGTH ) break;
i += strappnd( &p[i], Connect);
break;
}
case 'N': /* numer of */
case 'U': /* users */
{
sprintf( &p[i], "%d", get_current_users() );
i = strlen(p);
break;
}
case 'S': /* port speed */
{ /* ugly, I know. */
TIO temp_t;
tio_get( 0, &temp_t );
sprintf( &p[i], "%d", tio_get_speed( &temp_t ) );
i = strlen(p);
}
break;
case 'D': /* fallthrough */
case 'T':
if ( i + 30 > MAX_PROMPT_LENGTH )
{
i += strappnd( &p[i], "(x)" ); break;
}
else
{
time_t ti = time( NULL );
struct tm * tm = localtime( &ti );
if ( tm == NULL ) break;
if ( *ep == 'D' )
sprintf( &p[i], "%d/%d/%d", tm->tm_mon+1,
tm->tm_mday, tm->tm_year + 1900 );
else
sprintf( &p[i], "%02d:%02d:%02d", tm->tm_hour,
tm->tm_min, tm->tm_sec );
i = strlen(p);
}
break;
default: /* not a recognized string */
if ( isdigit( *ep ) ) /* "\01234" */
{
char * help;
p[i++] = strtol( ep, &help, 0 );
ep = help-1;
}
else p[i++] = *ep;
} /* end switch( char after '\\' ) */
} /* end if ( char is '\\' ) */
ep++;
} /* end while ( char to copy, p not full ) */
p[i] = 0; /* terminate string */
if ( *ep != 0 )
{
lprintf( L_WARN, "buffer overrun - input prompt too long" );
}
return p;
}
/* return TRUE if all letters found in the string are uppercase
*/
boolean ln_all_upper _P1( (string), char * string )
{
int i;
boolean uc = FALSE;
for ( i=0; string[i] != 0; i++ )
{
if ( string[i] == '\377' ) return FALSE; /* **EMSI_INQ */
if ( islower( string[i] ) ) return FALSE;
if ( isupper( string[i] ) ) uc = TRUE;
}
if ( ! uc ) /* no letters at all */
return FALSE; /* -> counted as lowercase */
return TRUE;
}
/* set_env_var( var, string )
*
* create an environment entry "VAR=string"
*/
void set_env_var _P2( (var,string), char * var, char * string )
{
char * v;
v = malloc( strlen(var) + strlen(string) + 2 );
if ( v == NULL )
lprintf( L_ERROR, "set_env_var: cannot malloc" );
else
{
sprintf( v, "%s=%s", var, string );
lprintf( L_NOISE, "setenv: '%s'", v );
if ( putenv( v ) != 0 )
lprintf( L_ERROR, "putenv failed" );
}
}
static int timeouts = 0;
#ifdef MAX_LOGIN_TIME
static RETSIGTYPE getlog_timeout()
{
signal( SIGALRM, getlog_timeout );
lprintf( L_WARN, "getlogname: timeout\n" );
timeouts++;
}
#endif
/* getlogname()
*
* read the login name into "char buf[]", maximum length "maxsize".
* depending on the key that the input was finished (\r vs. \n), mapping
* of cr->nl is set in "TIO * tio" (with tio_set_cr())
*
* If ENV_TTYPROMPT is set, do not read anything
*/
int getlogname _P5( (prompt, tio, buf, maxsize, do_timeout),
char * prompt, TIO * tio, char * buf,
int maxsize, boolean do_timeout )
{
int i, r;
char ch;
TIO tio_save;
char * final_prompt;
static int ppp_level = 0;
static boolean was_all_uc = FALSE;
/* read character by character! */
tio_save = *tio;
tio_mode_raw( tio );
tio_set( STDIN, tio );
final_prompt = ln_escape_prompt( prompt );
#ifdef ENV_TTYPROMPT
printf( "\r\n%s", final_prompt );
tio_mode_sane( tio, FALSE );
tio_map_cr( tio, TRUE );
tio_set( STDIN, tio );
buf[0] = 0;
set_env_var( "TTYPROMPT", final_prompt );
return 0;
#else /* !ENV_TTYPROMPT */
#ifdef MAX_LOGIN_TIME
if ( do_timeout )
{
signal( SIGALRM, getlog_timeout );
alarm( MAX_LOGIN_TIME );
}
#endif
newlogin:
#ifdef FIDO
printf( "**EMSI_REQA77E\r\021 \r" );
newlogin_noemsi:
#endif
printf( "\r\n%s", final_prompt );
if ( ferror( stdin ) )
{
lprintf( L_ERROR, "getlogname: error writing prompt" );
}
i = 0;
lprintf( L_NOISE, "getlogname, read:" );
do
{
if ( ( r = read( STDIN, &ch, 1 ) ) != 1 )
{
if ( r == 0 ) /* EOF/HUP/^D */
{
lprintf( L_MESG, "getlogname: got EOF, exiting" );
exit(0);
}
if ( errno != EINTR ) exit(0); /* HUP/^D/timeout */
#ifdef MAX_LOGIN_TIME
if ( timeouts <= 1 ) /* first timeout */
{
printf( "\r\n\07\r\nHey! Please login now. You have one minute left\r\n" );
alarm(60);
}
else /* second */
{
printf( "\r\n\07\r\nYour login time (%d minutes) ran out. Goodbye.\r\n",
MAX_LOGIN_TIME / 60 );
sleep(3); /* give message time to xmit */
exit(0); /* bye bye... */
}
#endif
ch = CKILL; /* timeout #1 -> clear input */
}
lputc( L_NOISE, ch ); /* logging */
#ifdef FIDO
if ( ch == (char) TSYNC )
{
strcpy( buf, "\377tsync" ); i=6; ch='\r';
}
else if ( ch == (char) YOOHOO )
{
strcpy( buf, "\377yoohoo" ); i=7; ch='\r';
}
#endif
#ifdef AUTO_PPP
/* Accept the following sequences as start of PPP packet:
PPP_FRAME, PPP_STATION, PPP_ESCAPE, PPP_CONTROL_ESCAPED (normal)
PPP_FRAME, PPP_STATION, PPP_CONTROL (deviant from RFC)
Odds are pretty low of hitting this by accident.
See RFC1662 for more information.
Contributed by Erik 'PPP' Olson, <eriko@wrq.com>.
*/
if (ch == (char) PPP_FRAME) {
ppp_level = 1;
} else if (ch == (char) PPP_STATION && ppp_level == 1) {
ppp_level = 2;
} else if (ch == (char) PPP_ESCAPE && ppp_level == 2) {
ppp_level = 3;
} else if ((ch == (char) PPP_CONTROL && ppp_level == 2)
|| (ch == (char) PPP_CONTROL_ESCAPED && ppp_level == 3)) {
ppp_level = 4;
} else if (ch == (char) PPP_LCP_HI && ppp_level == 4) {
ppp_level = 5;
} else if (ch == (char) PPP_LCP_LOW && ppp_level == 5)
{
strcpy (buf, "/AutoPPP/");
i=9;
ch = '\r';
} else {
ppp_level = 0;
}
#endif
#ifdef JANUS
/* ignore ^X as first character, some JANUS programs send it first
to skip the usual bbs banner
oli@rhein-main.de, 941217 */
if ( i == 0 && ch == 0x18 )
continue;
#endif
ch = ch & 0x7f; /* strip to 7 bit */
if ( ch == CQUIT ) exit(0);
if ( ch == CEOF )
{
if ( i == 0 ) exit(0); else continue;
}
if ( ch == CKILL || ch == 03 /*^C*/ ) goto newlogin;
/* ignore XON/XOFF characters */
if ( ch == CSTART || ch == CSTOP ) continue;
/* since some OSes use backspace and others DEL -> accept both */
if ( ch == 0x7f /*DEL*/ || ch == 0x08 /*BS*/ || ch == CERASE )
{
if ( i > 0 )
{
fputs( "\b \b", stdout );
i--;
}
}
else
if ( ch != 27 ) /* not <ESC> */
{
putc( ch, stdout );
if ( i >= maxsize || /* buffer full, */
( ch == ' ' && i == 0 ) || /* leading ' ' */
( ch == '-' && i == 0 ) ) /* or '-' */
fputs( "\b \b", stdout ); /* -> ignore */
else
buf[i++] = ch;
#ifdef FIDO
if ( i >= 7 && strncmp( &buf[i-7], "**EMSI_", 7 ) == 0 )
{
strcpy( buf, "\377**EMSI_" ); i=8; break;
}
#endif
}
}
while ( ch != '\n' && ch != '\r' );
#ifdef FIDO
if ( strncmp( buf, "\377**EMSI_", 8 ) == 0 )
{ /* read up to final \r */
while ( ch != '\r' )
{
if ( read( STDIN, &ch, 1 ) != 1 )
{
lprintf( L_ERROR, "logname/FIDO: read error" );
exit(0);
}
if ( i < maxsize) buf[i++] = ch;
if ( i >= 15 &&
strncmp( buf, "\377**EMSI_INQC816", 15 ) == 0 )
{
ch = buf[i++] = '\r';
}
}
/* log EMSI packets that are not EMSI_INQ (e.g. EMSI_DAT) */
if ( strncmp( buf, "\377**EMSI_INQ", 11 ) != 0 )
{
buf[i-1] = 0;
lprintf( L_MESG, "non-INQ EMSI packet: '%.15s...', length %d",
buf+1, i-1 );
if ( strncmp( buf, "\377**EMSI_CLI", 11 ) == 0 )
{
lprintf( L_MESG, "got EMSI_CLI packet, re-read login name" );
goto newlogin_noemsi;
}
}
}
#endif
alarm(0);
buf[--i] = 0;
*tio = tio_save;
#ifdef JANUS
/* change JANUS to janus */
if( strcmp(buf,"JANUS") == 0 )
strcpy(buf,"janus");
#endif
/* check whether all letters entered were uppercase, if yes, tell
user to try again with l/c, if it's all uppercase again on the
second try, enable UC<->LC mapping
*/
if ( ln_all_upper( buf ) )
{
if ( !was_all_uc ) /* first time */
{
printf("\r\n\nIf your terminal supports lower case letter, please\r\n");
printf("use them. Login again, using lower case if possible\r\n\n");
was_all_uc = TRUE;
return -1;
}
else /* second time */
{
for ( i=0; buf[i] != 0; i++ )
if ( isupper( buf[i] ) ) buf[i] = tolower(buf[i]);
tio_map_uclc( tio, TRUE );
lprintf( L_MESG, "login name all uppercase, set IUCLC OLCUC" );
}
}
/* set CR/LF mapping according to the caracter the input was
ended with
*/
if ( ch == '\n' )
{
tio_map_cr( tio, FALSE );
fputc( '\r', stdout );
}
else
{
tio_map_cr( tio, TRUE );
fputc( '\n', stdout );
lprintf( L_NOISE, "input finished with '\\r', setting ICRNL ONLCR" );
}
tio_set( STDIN, tio );
if ( i == 0 ) return -1;
else return 0;
#endif /* !ENV_TTYPROMPT */
}
-----------------
--
//www.muc.de/~gert
Gert Doering - Munich, Germany gert@greenie.muc.de
fax: +49-89-3545980 <---new!!! gert.doering@physik.tu-muenchen.de