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