make echo -e "foo\nfoo" | passwd USER work
Suggested by Michael Zhu (linuxsir320 AT gmail.com)
function old new delta
bb_ask 333 340 +7
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
diff --git a/libbb/bb_askpass.c b/libbb/bb_askpass.c
index f9b918c..bdb7566 100644
--- a/libbb/bb_askpass.c
+++ b/libbb/bb_askpass.c
@@ -30,10 +30,6 @@
struct sigaction sa, oldsa;
struct termios tio, oldtio;
- if (!passwd)
- passwd = xmalloc(sizeof_passwd);
- memset(passwd, 0, sizeof_passwd);
-
tcgetattr(fd, &oldtio);
tcflush(fd, TCIFLUSH);
tio = oldtio;
@@ -46,7 +42,7 @@
memset(&sa, 0, sizeof(sa));
/* sa.sa_flags = 0; - no SA_RESTART! */
- /* SIGINT and SIGALRM will interrupt read below */
+ /* SIGINT and SIGALRM will interrupt reads below */
sa.sa_handler = askpass_timeout;
sigaction(SIGINT, &sa, &oldsa);
if (timeout) {
@@ -56,18 +52,26 @@
fputs(prompt, stdout);
fflush_all();
- ret = NULL;
- /* On timeout or Ctrl-C, read will hopefully be interrupted,
- * and we return NULL */
- if (read(fd, passwd, sizeof_passwd - 1) > 0) {
- ret = passwd;
- i = 0;
- /* Last byte is guaranteed to be 0
- (read did not overwrite it) */
- do {
- if (passwd[i] == '\r' || passwd[i] == '\n')
- passwd[i] = '\0';
- } while (passwd[i++]);
+
+ if (!passwd)
+ passwd = xmalloc(sizeof_passwd);
+ memset(passwd, 0, sizeof_passwd);
+ ret = passwd;
+ i = 0;
+ while (1) {
+ int r = read(fd, &ret[i], 1);
+ if (r < 0) {
+ /* read is interrupted by timeout or ^C */
+ ret = NULL;
+ break;
+ }
+ if (r == 0 /* EOF */
+ || ret[i] == '\r' || ret[i] == '\n' /* EOL */
+ || ++i == sizeof_passwd-1 /* line limit */
+ ) {
+ ret[i] = '\0';
+ break;
+ }
}
if (timeout) {