[PATCH 5/8] Better support of virtual console

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Better support of virtual console due support of UTF-8 login names
provided by e.g. LDAP.  Set default size 24/80 on serial modem lines
if not found by the kernel.

Signed-off-by: Werner Fink <werner@xxxxxxx>
---
 term-utils/agetty.c |  199 ++++++++++++++++++++++++++++++++++-----------------
 1 files changed, 134 insertions(+), 65 deletions(-)

diff --git a/term-utils/agetty.c b/term-utils/agetty.c
index 3836ea1..2bee594 100644
--- a/term-utils/agetty.c
+++ b/term-utils/agetty.c
@@ -5,6 +5,8 @@
  * Venema, enhanced by John DiMarco, and further enhanced by Dennis Cronin.
  *
  * Ported to Linux by Peter Orbaek <poe@xxxxxxxxxxxx>
+ * Adopt the mingetty features for a better support
+ * of virtual consoles by Werner Fink <werner@xxxxxxx>
  *
  * This program is freely distributable.
  */
@@ -29,6 +31,9 @@
 #include <sys/socket.h>
 #include <netdb.h>
 #include <langinfo.h>
+#include <locale.h>
+#include <iconv.h>
+#include <wctype.h>
 #include <grp.h>
 
 #include "strutils.h"
@@ -347,7 +352,7 @@ int main(int argc, char **argv)
 	}
 
 	chardata = init_chardata;
-	if (!(options.flags & F_NOPROMPT)) {
+	if ((options.flags & F_NOPROMPT) == 0) {
 		/* Read the login name. */
 		debug("reading login name\n");
 		while ((logname =
@@ -777,7 +782,7 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
 	 * In case of a virtual console the ioctl TIOCMGET fails and
 	 * the error number will be set to EINVAL.
 	 */
-	if (ioctl(0, TIOCMGET, &serial) < 0 && (errno = EINVAL)) {
+	if (ioctl(STDIN_FILENO, TIOCMGET, &serial) < 0 && (errno = EINVAL)) {
 		op->flags |= F_VCONSOLE;
 		if (!op->term)
 			op->term = DEFAULT_VCTERM;
@@ -791,13 +796,14 @@ static void open_tty(char *tty, struct termios *tp, struct options *op)
 static void termio_init(struct options *op, struct termios *tp)
 {
 	speed_t ispeed, ospeed;
+	struct winsize ws;
 
 	if (op->flags & F_VCONSOLE) {
-#ifdef IUTF8
+#if defined(IUTF8) && defined(KDGKBMODE)
 		int mode;
 
 		/* Detect mode of current keyboard setup, e.g. for UTF-8 */
-		if (ioctl(0, KDGKBMODE, &mode) < 0)
+		if (ioctl(STDIN_FILENO, KDGKBMODE, &mode) < 0)
 			mode = K_RAW;
 		switch(mode) {
 		case K_UNICODE:
@@ -817,6 +823,7 @@ static void termio_init(struct options *op, struct termios *tp)
 		op->flags &= ~F_UTF8;
 #endif
 		reset_vc(op);
+		op->flags |= F_EIGHTBITS;
 		return;
 	}
 
@@ -824,6 +831,10 @@ static void termio_init(struct options *op, struct termios *tp)
 		/* Save the original setting. */
 		ispeed = cfgetispeed(tp);
 		ospeed = cfgetospeed(tp);
+
+		if (!ispeed) ispeed = TTYDEF_SPEED;
+		if (!ospeed) ospeed = TTYDEF_SPEED;
+
 	} else {
 		ospeed = ispeed = op->speeds[FIRST_SPEED];
 	}
@@ -840,7 +851,7 @@ static void termio_init(struct options *op, struct termios *tp)
 
 	tp->c_iflag = tp->c_lflag = tp->c_oflag = 0;
 
-	if (!(op->flags & F_KEEPCFLAGS))
+	if ((op->flags & F_KEEPCFLAGS) == 0)
 		tp->c_cflag = CS8 | HUPCL | CREAD | (tp->c_cflag & CLOCAL);
 
 	/*
@@ -858,6 +869,20 @@ static void termio_init(struct options *op, struct termios *tp)
 	tp->c_cc[VMIN] = 1;
 	tp->c_cc[VTIME] = 0;
 
+	/* Check for terminal size and if not found set default */
+	if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
+		int set = 0;
+		if (ws.ws_row == 0) {
+			ws.ws_row = 24;
+			set++;
+		}
+		if (ws.ws_col == 0) {
+			ws.ws_col = 80;
+			set++;
+		}
+		(void)ioctl(STDIN_FILENO, TIOCSWINSZ, &ws);
+	}
+
 	/* Optionally enable hardware flow control. */
 #ifdef	CRTSCTS
 	if (op->flags & F_RTSCTS)
@@ -910,8 +935,9 @@ static void reset_vc(const struct options *op)
 	if (op->flags & F_UTF8)
 		termios.c_iflag |= IUTF8;	    /* Set UTF-8 input flag */
 	else
-		termios.c_iflag &= ~IUTF8;
 #endif
+		termios.c_iflag &= ~IUTF8;
+
 	/* VTIME and VMIN can overlap with VEOF and VEOL since they are
 	 * only used for non-canonical mode. We just set the at the
 	 * beginning, so nothing bad should happen.
@@ -1013,13 +1039,13 @@ static void do_prompt(struct options *op, struct termios *tp)
 
 #ifdef	ISSUE
 	if ((op->flags & F_ISSUE) && (fd = fopen(op->issue, "r"))) {
-		int c, oflag;
+		int c, oflag = tp->c_oflag;	    /* Save current setting. */
 
-		/* Save current setting. */
-		oflag = tp->c_oflag;
-		/* Map new line in output to carriage return & new line. */
-		tp->c_oflag |= (ONLCR | OPOST);
-		tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+		if ((op->flags & F_VCONSOLE) == 0) {
+			/* Map new line in output to carriage return & new line. */
+			tp->c_oflag |= (ONLCR | OPOST);
+			tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+		}
 
 		while ((c = getc(fd)) != EOF) {
 			if (c == '\\')
@@ -1029,10 +1055,12 @@ static void do_prompt(struct options *op, struct termios *tp)
 		}
 		fflush(stdout);
 
-		/* Restore settings. */
-		tp->c_oflag = oflag;
-		/* Wait till output is gone. */
-		tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+		if ((op->flags & F_VCONSOLE) == 0) {
+			/* Restore settings. */
+			tp->c_oflag = oflag;
+			/* Wait till output is gone. */
+			tcsetattr(STDIN_FILENO, TCSADRAIN, tp);
+		}
 		fclose(fd);
 	}
 #endif				/* ISSUE */
@@ -1072,8 +1100,8 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
 	char *bp;
 	char c;			/* input character, full eight bits */
 	char ascval;		/* low 7 bits of input character */
-	int bits;		/* # of "1" bits per character */
-	int mask;		/* mask with 1 bit up */
+	int eightbit;
+	iconv_t ic;
 	static char *erase[] = {	/* backspace-space-backspace */
 		"\010\040\010",		/* space parity */
 		"\010\040\010",		/* odd parity */
@@ -1088,92 +1116,133 @@ static char *get_logname(struct options *op, struct termios *tp, struct chardata
 	 * Flush pending input (especially important after parsing or switching
 	 * the baud rate).
 	 */
-	sleep(1);
+	if ((op->flags & F_VCONSOLE) == 0)
+		sleep(1);
 	tcflush(STDIN_FILENO, TCIFLUSH);
 
-	/* Prompt for and read a login name. */
-	for (*logname = 0; *logname == 0; /* void */ ) {
-		/* Write issue file and prompt, with "parity" bit == 0. */
+	eightbit = (op->flags & F_EIGHTBITS);
+	bp = logname;
+	*bp = '\0';
+
+	while (*logname == '\0') {
+    
+		/* Write issue file and prompt */
 		do_prompt(op, tp);
 
-		/*
-		 * Read name, watch for break, parity, erase, kill,
-		 * end-of-line.
-		 */
-		for (bp = logname, cp->eol = 0; cp->eol == 0; /* void */ ) {
-			/* Do not report trivial EINTR/EIO errors. */
-			if (read(STDIN_FILENO, &c, 1) < 1) {
-				if (errno == EINTR || errno == EIO)
-					exit(EXIT_SUCCESS);
-				error(_("%s: read: %m"), op->tty);
+		cp->eol = '\0';
+
+		/* Read name, watch for break and end-of-line. */
+		while (cp->eol == '\0') {
+
+			if (read (STDIN_FILENO, &c, 1) < 1) {
+
+				/* Do not report trivial like EINTR/EIO errors. */
+				if (errno == EINTR || errno == EAGAIN) {
+					usleep(1000);
+					continue;
+				}
+				switch (errno) {
+				case 0:
+				case EIO:
+				case ESRCH:
+				case EINVAL:
+				case ENOENT:
+					break;
+				default:
+					error(_("%s: read: %m"), op->tty);
+				}
 			}
-			/* Do BREAK handling elsewhere. */
-			if ((c == 0) && op->numspeed > 1)
-				return EXIT_SUCCESS;
+
 			/* Do parity bit handling. */
-			if (op->flags & F_EIGHTBITS) {
+			if (eightbit)
 				ascval = c;
-			} else if (c != (ascval = (c & 0177))) {
-				/* Set "parity" bit on. */
-				for (bits = 1, mask = 1; mask & 0177;
-				     mask <<= 1)
+			else if (c != (ascval = (c & 0177))) {
+				uint32_t bits;			/* # of "1" bits per character */
+				uint32_t mask;			/* mask with 1 bit up */
+				for (bits = 1, mask = 1; mask & 0177; mask <<= 1) {
 					if (mask & ascval)
-						/* Count "1" bits. */
 						bits++;
+				}
 				cp->parity |= ((bits & 1) ? 1 : 2);
 			}
+
 			/* Do erase, kill and end-of-line processing. */
 			switch (ascval) {
+			case 0:
+				*bp = 0;
+				if (op->numspeed > 1)
+					return logname;
+				break;
 			case CR:
 			case NL:
-				/* Terminate logname. */
-				*bp = 0;
-				/* Set end-of-line char. */
-				cp->eol = ascval;
+				*bp = 0;			/* terminate logname */
+				cp->eol = ascval;		/* set end-of-line char */
 				break;
 			case BS:
 			case DEL:
 			case '#':
-				/* Set erase character. */
-				cp->erase = ascval;
+				cp->erase = ascval; /* set erase character */
 				if (bp > logname) {
-					safe_write(STDIN_FILENO,
-						   erase[cp->parity], 3);
+					if ((tp->c_cflag & (ECHO)) == 0)
+						safe_write(1, erase[cp->parity], 3);
 					bp--;
 				}
 				break;
 			case CTL('U'):
 			case '@':
-				/* Set kill character. */
-				cp->kill = ascval;
+				cp->kill = ascval;		/* set kill character */
 				while (bp > logname) {
-					safe_write(STDIN_FILENO,
-						   erase[cp->parity], 3);
+					if ((tp->c_cflag & (ECHO)) == 0)
+						safe_write(1, erase[cp->parity], 3);
 					bp--;
 				}
 				break;
 			case CTL('D'):
 				exit(EXIT_SUCCESS);
 			default:
-				if (!isascii(ascval) || !isprint(ascval)) {
-					/* Ignore garbage characters. */ ;
-				} else if ((size_t)(bp - logname) >= sizeof(logname) - 1) {
+				if (!isascii(ascval) || !isprint(ascval))
+					break;
+				if ((size_t)(bp - logname) >= sizeof(logname) - 1)
 					error(_("%s: input overrun"), op->tty);
-				} else {
-					/* Echo the character... */
-					safe_write(STDIN_FILENO, &c, 1);
-					/* ...and store it. */
-					*bp++ = ascval;
-				}
+				if ((tp->c_cflag & (ECHO)) == 0)
+					safe_write(1, &c, 1);	/* echo the character */
+				*bp++ = ascval;			/* and store it */
 				break;
 			}
 		}
 	}
-	/* Handle names with upper case and no lower case. */
-	if ((op->flags & F_LCUC) && (cp->capslock = caps_lock(logname)))
+
+
+	if ((op->flags & F_UTF8) && (ic = iconv_open("WCHAR_T", "UTF-8"))) {
+		char tmpbuf[4*sizeof(logname)], *optr, *lptr;
+		size_t len = bp - logname;
+		size_t out = sizeof(tmpbuf) - 1;
+		size_t wcl;
+		wint_t *wcp;
+
+		/* Handle UTF-8 multibyte characters */
+		optr = tmpbuf;
+		lptr = logname;
+		if ((wcl = iconv(ic , &lptr, &len, &optr, &out)) == (size_t)-1)
+			error ("%s: invalid character conversion for login name", op->tty);
+		iconv_close(ic);
+
+		wcp = (wint_t*)tmpbuf;
+		wcp[wcl] = (wint_t)0;
+		while (*wcp) {
+			const wint_t wc = *wcp++;
+			if (!iswprint(wc))
+				error ("%s: invalid character 0x%x in login name", op->tty, wc);
+		}
+
+	} else if ((op->flags & F_LCUC) && (cp->capslock = caps_lock(logname))) {
+
+		/* Handle names with upper case and no lower case. */
 		for (bp = logname; *bp; bp++)
 			if (isupper(*bp))
-				*bp = tolower(*bp);
+				*bp = tolower(*bp);		/* map name to lower case */
+	}
+
 	return logname;
 }
 
-- 
1.6.0.2

--
To unsubscribe from this list: send the line "unsubscribe util-linux" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [Netdev]     [Ethernet Bridging]     [Linux Wireless]     [Kernel Newbies]     [Security]     [Linux for Hams]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux RAID]     [Linux Admin]     [Samba]

  Powered by Linux