From 1fb3e6c2bbcb782830c7fbc531a699b852dd84e0 Mon Sep 17 00:00:00 2001 From: jilles Date: Sun, 30 Aug 2015 17:24:22 +0000 Subject: sh: Fix read with escaped IFS characters at the end. Characters escaped with a backslash must be treated as if they were not in IFS. This includes stripping trailing IFS characters. --- bin/sh/miscbltin.c | 29 +++++++++++++++++------------ bin/sh/tests/builtins/Makefile | 1 + bin/sh/tests/builtins/read9.0 | 10 ++++++++++ 3 files changed, 28 insertions(+), 12 deletions(-) create mode 100644 bin/sh/tests/builtins/read9.0 (limited to 'bin') diff --git a/bin/sh/miscbltin.c b/bin/sh/miscbltin.c index 4575e96..4de1276 100644 --- a/bin/sh/miscbltin.c +++ b/bin/sh/miscbltin.c @@ -100,6 +100,7 @@ readcmd(int argc __unused, char **argv __unused) int i; int is_ifs; int saveall = 0; + ptrdiff_t lastnonifs, lastnonifsws; struct timeval tv; char *tvptr; fd_set ifds; @@ -169,6 +170,7 @@ readcmd(int argc __unused, char **argv __unused) startword = 2; backslash = 0; STARTSTACKSTR(p); + lastnonifs = lastnonifsws = -1; for (;;) { nread = read(STDIN_FILENO, &c, 1); if (nread == -1) { @@ -193,6 +195,7 @@ readcmd(int argc __unused, char **argv __unused) backslash = 0; if (c != '\n') { startword = 0; + lastnonifs = lastnonifsws = p - stackblock(); USTPUTC(c, p); } continue; @@ -218,8 +221,10 @@ readcmd(int argc __unused, char **argv __unused) if (is_ifs == 2 && startword == 1) { /* Only one non-whitespace IFS per word */ startword = 2; - if (saveall) + if (saveall) { + lastnonifsws = p - stackblock(); USTPUTC(c, p); + } continue; } } @@ -230,6 +235,7 @@ readcmd(int argc __unused, char **argv __unused) if (saveall) /* Not just a spare terminator */ saveall++; + lastnonifs = lastnonifsws = p - stackblock(); USTPUTC(c, p); continue; } @@ -240,6 +246,8 @@ readcmd(int argc __unused, char **argv __unused) if (ap[1] == NULL) { /* Last variable needs all IFS chars */ saveall++; + if (is_ifs == 2) + lastnonifsws = p - stackblock(); USTPUTC(c, p); continue; } @@ -248,20 +256,17 @@ readcmd(int argc __unused, char **argv __unused) setvar(*ap, stackblock(), 0); ap++; STARTSTACKSTR(p); + lastnonifs = lastnonifsws = -1; } STACKSTRNUL(p); - /* Remove trailing IFS chars */ - for (; stackblock() <= --p; *p = 0) { - if (!strchr(ifs, *p)) - break; - if (strchr(" \t\n", *p)) - /* Always remove whitespace */ - continue; - if (saveall > 1) - /* Don't remove non-whitespace unless it was naked */ - break; - } + /* + * Remove trailing IFS chars: always remove whitespace, don't remove + * non-whitespace unless it was naked + */ + if (saveall <= 1) + lastnonifsws = lastnonifs; + stackblock()[lastnonifsws + 1] = '\0'; setvar(*ap, stackblock(), 0); /* Set any remaining args to "" */ diff --git a/bin/sh/tests/builtins/Makefile b/bin/sh/tests/builtins/Makefile index c1e7b64..46a0b41 100644 --- a/bin/sh/tests/builtins/Makefile +++ b/bin/sh/tests/builtins/Makefile @@ -123,6 +123,7 @@ FILES+= read5.0 FILES+= read6.0 FILES+= read7.0 FILES+= read8.0 +FILES+= read9.0 FILES+= return1.0 FILES+= return2.1 FILES+= return3.1 diff --git a/bin/sh/tests/builtins/read9.0 b/bin/sh/tests/builtins/read9.0 new file mode 100644 index 0000000..0805498 --- /dev/null +++ b/bin/sh/tests/builtins/read9.0 @@ -0,0 +1,10 @@ +# $FreeBSD$ + +empty='' +read a b c <