From: Todd C. Miller Date: Mon, 1 Nov 1999 04:00:57 +0000 (+0000) Subject: Make this work again for things like "sudo echo hi | more" where the tty X-Git-Tag: SUDO_1_6_0~26 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=3f1581ae66f6a7701fa07216d72ecc127f47d2f6;p=sudo Make this work again for things like "sudo echo hi | more" where the tty gets put into character at a time mode. We read until we read end of line or we run out of space (similar to fgets(3)). --- diff --git a/tgetpass.c b/tgetpass.c index f7fcb4772..213c32ac2 100644 --- a/tgetpass.c +++ b/tgetpass.c @@ -81,6 +81,7 @@ static const char rcsid[] = "$Sudo$"; #endif /* lint */ +static char *tgetline __P((int, char *, size_t, int)); /* * Like getpass(3) but with timeout and echo flags. @@ -100,10 +101,8 @@ tgetpass(prompt, timeout, echo_off) struct sgttyb ttyb; #endif /* HAVE_TERMIO_H */ #endif /* HAVE_TERMIOS_H */ - int n, input, output; + int input, output; static char buf[SUDO_PASS_MAX + 1]; - fd_set *readfds; - struct timeval tv; /* Open /dev/tty for reading/writing if possible else use stdin/stderr. */ if ((input = output = open(_PATH_TTY, O_RDWR|O_NOCTTY)) == -1) { @@ -138,41 +137,8 @@ tgetpass(prompt, timeout, echo_off) #endif /* HAVE_TERMIOS_H */ } - /* - * Timeout of <= 0 means no timeout. - */ - if (timeout > 0) { - /* setup for select(2) */ - n = howmany(input + 1, NFDBITS) * sizeof(fd_mask); - readfds = (fd_set *) emalloc(n); - (void) memset((VOID *)readfds, 0, n); - FD_SET(input, readfds); - - /* set timeout for select */ - tv.tv_sec = timeout; - tv.tv_usec = 0; - - /* - * Get password or return empty string if nothing to read by timeout - */ - buf[0] = '\0'; - while ((n = select(input + 1, readfds, 0, 0, &tv)) == -1 && - errno == EINTR) - ; - if (n != 0 && (n = read(input, buf, sizeof(buf) - 1)) > 0) { - if (buf[n - 1] == '\n') - n--; - buf[n] = '\0'; - } - free(readfds); - } else { - buf[0] = '\0'; - if ((n = read(input, buf, sizeof(buf) - 1)) > 0) { - if (buf[n - 1] == '\n') - n--; - buf[n] = '\0'; - } - } + buf[0] = '\0'; + tgetline(input, buf, sizeof(buf), timeout); #ifdef HAVE_TERMIOS_H if (echo_off) { @@ -201,3 +167,59 @@ tgetpass(prompt, timeout, echo_off) return(buf); } + +/* + * Get a line of input (optionally timing out) and place it in buf. + */ +static char * +tgetline(fd, buf, bufsiz, timeout) + int fd; + char *buf; + size_t bufsiz; + int timeout; +{ + size_t left; + int n; + fd_set *readfds = NULL; + struct timeval tv; + char *cp; + + /* + * Timeout of <= 0 means no timeout. + */ + if (timeout > 0) { + /* Setup for select(2) */ + n = howmany(fd + 1, NFDBITS) * sizeof(fd_mask); + readfds = (fd_set *) emalloc(n); + (void) memset((VOID *)readfds, 0, n); + FD_SET(fd, readfds); + + /* Set timeout for select */ + tv.tv_sec = timeout; + tv.tv_usec = 0; + + /* + * Make sure there is something to read or timeout + */ + while ((n = select(fd + 1, readfds, 0, 0, &tv)) == -1 && + errno == EINTR) + ; + if (n == 0) + return(NULL); /* timeout */ + } + if (readfds) + free(readfds); + + /* Get a line of input */ + left = bufsiz; + cp = buf; + do { + if ((n = read(fd, cp, left)) > 0) { + cp += n; + left -= n; + } + } while (n > 0 && left != 0 && *(cp - 1) != '\n'); + *(cp - 1) = '\0'; + + return(left == bufsiz ? NULL : buf); +}