From 9acd63c92cbc4bd0a3ddbb6a61e512eadc29239d Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 28 Mar 2018 18:35:07 +0200 Subject: ash,hush: fix "saved" redirected fds still visible in children Based on a patch by Mark Marshall function old new delta dup_CLOEXEC - 49 +49 fcntl_F_DUPFD 46 - -46 Signed-off-by: Denys Vlasenko --- shell/ash.c | 16 ++++++++++----- .../redir_children_should_not_see_saved_fd_1.right | 5 +++++ .../redir_children_should_not_see_saved_fd_1.tests | 6 ++++++ .../redir_children_should_not_see_saved_fd_2.right | 5 +++++ .../redir_children_should_not_see_saved_fd_2.tests | 6 ++++++ .../redir_children_should_not_see_saved_fd_3.right | 5 +++++ .../redir_children_should_not_see_saved_fd_3.tests | 6 ++++++ shell/hush.c | 23 ++++++++++++++-------- .../redir_children_should_not_see_saved_fd_1.right | 5 +++++ .../redir_children_should_not_see_saved_fd_1.tests | 6 ++++++ .../redir_children_should_not_see_saved_fd_2.right | 5 +++++ .../redir_children_should_not_see_saved_fd_2.tests | 6 ++++++ .../redir_children_should_not_see_saved_fd_3.right | 5 +++++ .../redir_children_should_not_see_saved_fd_3.tests | 6 ++++++ 14 files changed, 92 insertions(+), 13 deletions(-) create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests create mode 100644 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right create mode 100755 shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests create mode 100644 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right create mode 100755 shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 5e281b5ce..85690e555 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -255,6 +255,9 @@ typedef long arith_t; # define IF_NOT_FEATURE_SH_STANDALONE(...) __VA_ARGS__ #endif +#ifndef F_DUPFD_CLOEXEC +# define F_DUPFD_CLOEXEC F_DUPFD +#endif #ifndef PIPE_BUF # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif @@ -5448,12 +5451,15 @@ dup2_or_raise(int from, int to) return newfd; } static int -fcntl_F_DUPFD(int fd, int avoid_fd) +dup_CLOEXEC(int fd, int avoid_fd) { int newfd; repeat: - newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); - if (newfd < 0) { + newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); + if (newfd >= 0) { + if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ + fcntl(newfd, F_SETFD, FD_CLOEXEC); + } else { /* newfd < 0 */ if (errno == EBUSY) goto repeat; if (errno == EINTR) @@ -5569,7 +5575,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) for (i = 0; sq->two_fd[i].orig_fd != EMPTY; i++) { /* If we collide with an already moved fd... */ if (fd == sq->two_fd[i].moved_to) { - new_fd = fcntl_F_DUPFD(fd, avoid_fd); + new_fd = dup_CLOEXEC(fd, avoid_fd); sq->two_fd[i].moved_to = new_fd; TRACE(("redirect_fd %d: already busy, moving to %d\n", fd, new_fd)); if (new_fd < 0) /* what? */ @@ -5584,7 +5590,7 @@ save_fd_on_redirect(int fd, int avoid_fd, struct redirtab *sq) } /* If this fd is open, we move and remember it; if it's closed, new_fd = CLOSED (-1) */ - new_fd = fcntl_F_DUPFD(fd, avoid_fd); + new_fd = dup_CLOEXEC(fd, avoid_fd); TRACE(("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, new_fd)); if (new_fd < 0) { if (errno != EBADF) diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests new file mode 100755 index 000000000..544c810e3 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_1.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +busybox find /proc/self/fd >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests new file mode 100755 index 000000000..43777cade --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_2.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +{ busybox find /proc/self/fd; } >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests new file mode 100755 index 000000000..0a21173bd --- /dev/null +++ b/shell/ash_test/ash-redir/redir_children_should_not_see_saved_fd_3.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +{ busybox find /proc/self/fd; true; } >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out diff --git a/shell/hush.c b/shell/hush.c index 6e64efb70..012ec219f 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -1501,12 +1501,15 @@ static void free_strings(char **strings) free(strings); } -static int fcntl_F_DUPFD(int fd, int avoid_fd) +static int dup_CLOEXEC(int fd, int avoid_fd) { int newfd; repeat: - newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); - if (newfd < 0) { + newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); + if (newfd >= 0) { + if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ + fcntl(newfd, F_SETFD, FD_CLOEXEC); + } else { /* newfd < 0 */ if (errno == EBUSY) goto repeat; if (errno == EINTR) @@ -6890,7 +6893,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) if (sq) for (; sq[i].orig_fd >= 0; i++) { /* If we collide with an already moved fd... */ if (fd == sq[i].moved_to) { - sq[i].moved_to = fcntl_F_DUPFD(sq[i].moved_to, avoid_fd); + sq[i].moved_to = dup_CLOEXEC(sq[i].moved_to, avoid_fd); debug_printf_redir("redirect_fd %d: already busy, moving to %d\n", fd, sq[i].moved_to); if (sq[i].moved_to < 0) /* what? */ xfunc_die(); @@ -6904,7 +6907,7 @@ static struct squirrel *add_squirrel(struct squirrel *sq, int fd, int avoid_fd) } /* If this fd is open, we move and remember it; if it's closed, moved_to = -1 */ - moved_to = fcntl_F_DUPFD(fd, avoid_fd); + moved_to = dup_CLOEXEC(fd, avoid_fd); debug_printf_redir("redirect_fd %d: previous fd is moved to %d (-1 if it was closed)\n", fd, moved_to); if (moved_to < 0 && errno != EBADF) xfunc_die(); @@ -7622,6 +7625,10 @@ static NOINLINE void pseudo_exec_argv(nommu_save_t *nommu_save, */ close_saved_fds_and_FILE_fds(); //FIXME: should also close saved redir fds +//This casuses test failures in +//redir_children_should_not_see_saved_fd_2.tests +//redir_children_should_not_see_saved_fd_3.tests +//if you replace "busybox find" with just "find" in them /* Without this, "rm -i FILE" can't be ^C'ed: */ switch_off_special_sigs(G.special_sig_mask); debug_printf_exec("running applet '%s'\n", argv[0]); @@ -9347,7 +9354,7 @@ int hush_main(int argc, char **argv) G_saved_tty_pgrp = 0; /* try to dup stdin to high fd#, >= 255 */ - G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); + G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); if (G_interactive_fd < 0) { /* try to dup to any fd */ G_interactive_fd = dup(STDIN_FILENO); @@ -9420,10 +9427,10 @@ int hush_main(int argc, char **argv) #elif ENABLE_HUSH_INTERACTIVE /* No job control compiled in, only prompt/line editing */ if (isatty(STDIN_FILENO) && isatty(STDOUT_FILENO)) { - G_interactive_fd = fcntl_F_DUPFD(STDIN_FILENO, 254); + G_interactive_fd = dup_CLOEXEC(STDIN_FILENO, 254); if (G_interactive_fd < 0) { /* try to dup to any fd */ - G_interactive_fd = dup(STDIN_FILENO); + G_interactive_fd = dup_CLOEXEC(STDIN_FILENO); if (G_interactive_fd < 0) /* give up */ G_interactive_fd = 0; diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests new file mode 100755 index 000000000..544c810e3 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_1.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +busybox find /proc/self/fd >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests new file mode 100755 index 000000000..43777cade --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_2.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +{ busybox find /proc/self/fd; } >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right new file mode 100644 index 000000000..46ab7f5d1 --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.right @@ -0,0 +1,5 @@ +/proc/self/fd +/proc/self/fd/0 +/proc/self/fd/1 +/proc/self/fd/2 +/proc/self/fd/3 diff --git a/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests new file mode 100755 index 000000000..0a21173bd --- /dev/null +++ b/shell/hush_test/hush-redir/redir_children_should_not_see_saved_fd_3.tests @@ -0,0 +1,6 @@ +# The "find" should not see "saved" (duplicated) fd #1 +# Explicitly use bbox find, since other implementations of "find" +# may open other descriptors as well. +{ busybox find /proc/self/fd; true; } >tmp_$$.out +cat tmp_$$.out +rm -f tmp_$$.out -- cgit v1.2.3-55-g6feb From d1b845706df2aa819babe74cb0b9b15c13da6b16 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Wed, 28 Mar 2018 18:42:54 +0200 Subject: hush: add a FIXME comment Signed-off-by: Denys Vlasenko --- shell/hush.c | 6 ++++++ 1 file changed, 6 insertions(+) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 012ec219f..e6dd1bc3d 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -8173,6 +8173,12 @@ static NOINLINE int run_pipe(struct pipe *pi) rcode = 1; /* exitcode if redir failed */ if (setup_redirects(command, &squirrel) == 0) { debug_printf_exec(": run_list\n"); +//FIXME: we need to pass squirrel down into run_list() +//for SH_STANDALONE case, or else this construct: +// { find /proc/self/fd; true; } >FILE; cmd2 +//has no way of closing saved fd#1 for "find", +//and in SH_STANDALONE mode, "find" is not execed, +//therefore CLOEXEC on saved fd does not help. rcode = run_list(command->group) & 0xff; } restore_redirects(squirrel); -- cgit v1.2.3-55-g6feb From 60fb98e51d11ed45bbc836eb28a2539ba3ab76f7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 30 Mar 2018 22:15:14 +0200 Subject: ash: use F_DUPFD_CLOEXEC and O_CLOEXEC function old new delta setjobctl 371 367 -4 setinputfile 226 220 -6 ------------------------------------------------------------------------------ (add/remove: 0/0 grow/shrink: 0/2 up/down: 0/-10) Total: -10 bytes Based on patch by Mark Marshall Signed-off-by: Denys Vlasenko --- shell/ash.c | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 85690e555..c957b001e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -258,6 +258,9 @@ typedef long arith_t; #ifndef F_DUPFD_CLOEXEC # define F_DUPFD_CLOEXEC F_DUPFD #endif +#ifndef O_CLOEXEC +# define O_CLOEXEC 0 +#endif #ifndef PIPE_BUF # define PIPE_BUF 4096 /* amount of buffering in a pipe */ #endif @@ -3972,12 +3975,13 @@ setjobctl(int on) goto out; } /* fd is a tty at this point */ - fd = fcntl(fd, F_DUPFD, 10); + fd = fcntl(fd, F_DUPFD_CLOEXEC, 10); if (ofd >= 0) /* if it is "/dev/tty", close. If 0/1/2, don't */ close(ofd); if (fd < 0) goto out; /* F_DUPFD failed */ - close_on_exec_on(fd); + if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ + close_on_exec_on(fd); while (1) { /* while we are in the background */ pgrp = tcgetpgrp(fd); if (pgrp < 0) { @@ -5427,13 +5431,14 @@ savefd(int from) int newfd; int err; - newfd = fcntl(from, F_DUPFD, 10); + newfd = fcntl(from, F_DUPFD_CLOEXEC, 10); err = newfd < 0 ? errno : 0; if (err != EBADF) { if (err) ash_msg_and_raise_perror("%d", from); close(from); - fcntl(newfd, F_SETFD, FD_CLOEXEC); + if (F_DUPFD_CLOEXEC == F_DUPFD) + close_on_exec_on(newfd); } return newfd; @@ -5458,7 +5463,7 @@ dup_CLOEXEC(int fd, int avoid_fd) newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); if (newfd >= 0) { if (F_DUPFD_CLOEXEC == F_DUPFD) /* if old libc (w/o F_DUPFD_CLOEXEC) */ - fcntl(newfd, F_SETFD, FD_CLOEXEC); + close_on_exec_on(newfd); } else { /* newfd < 0 */ if (errno == EBUSY) goto repeat; @@ -5472,7 +5477,7 @@ xdup_CLOEXEC_and_close(int fd, int avoid_fd) { int newfd; repeat: - newfd = fcntl(fd, F_DUPFD, avoid_fd + 1); + newfd = fcntl(fd, F_DUPFD_CLOEXEC, avoid_fd + 1); if (newfd < 0) { if (errno == EBUSY) goto repeat; @@ -5483,7 +5488,8 @@ xdup_CLOEXEC_and_close(int fd, int avoid_fd) return fd; ash_msg_and_raise_perror("%d", newfd); } - fcntl(newfd, F_SETFD, FD_CLOEXEC); + if (F_DUPFD_CLOEXEC == F_DUPFD) + close_on_exec_on(newfd); close(fd); return newfd; } @@ -10753,7 +10759,7 @@ setinputfile(const char *fname, int flags) int fd; INT_OFF; - fd = open(fname, O_RDONLY); + fd = open(fname, O_RDONLY | O_CLOEXEC); if (fd < 0) { if (flags & INPUT_NOFILE_OK) goto out; @@ -10762,8 +10768,9 @@ setinputfile(const char *fname, int flags) } if (fd < 10) fd = savefd(fd); - else + else if (O_CLOEXEC == 0) /* old libc */ close_on_exec_on(fd); + setinputfd(fd, flags & INPUT_PUSH_FILE); out: INT_ON; -- cgit v1.2.3-55-g6feb From ac61f447040479f7a852ae2c1262915274496f49 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 30 Mar 2018 23:03:29 +0200 Subject: ash: fix "char == CTLfoo" comparison signedness bug It usually does not bite since bbox forces -funsigned-char build. But for some reason void linux people disabled that. Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index c957b001e..8fb32c1ae 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7439,13 +7439,13 @@ hasmeta(const char *p) p = strpbrk(p, chars); if (!p) break; - switch ((unsigned char) *p) { + switch ((unsigned char)*p) { case CTLQUOTEMARK: for (;;) { p++; - if (*p == CTLQUOTEMARK) + if ((unsigned char)*p == CTLQUOTEMARK) break; - if (*p == CTLESC) + if ((unsigned char)*p == CTLESC) p++; if (*p == '\0') /* huh? */ return 0; -- cgit v1.2.3-55-g6feb From 73523079a2c5f1cf370095a3166bace1d01fcba5 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Fri, 30 Mar 2018 23:25:24 +0200 Subject: ash,hush: new test dollar_repl_slash_bash2.tests This fails for ash. hush works. Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right | 1 + shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests | 2 ++ shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right | 1 + shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests | 2 ++ 4 files changed, 6 insertions(+) create mode 100644 shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right create mode 100755 shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests create mode 100644 shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right create mode 100755 shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests (limited to 'shell') diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right new file mode 100644 index 000000000..2aead7129 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.right @@ -0,0 +1 @@ +\/a\/bc\/def\/file diff --git a/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests new file mode 100755 index 000000000..64ca0c170 --- /dev/null +++ b/shell/ash_test/ash-quoting/dollar_repl_slash_bash2.tests @@ -0,0 +1,2 @@ +var="/a/bc/def/file" +echo "${var//\//\\/}" diff --git a/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right new file mode 100644 index 000000000..2aead7129 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.right @@ -0,0 +1 @@ +\/a\/bc\/def\/file diff --git a/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests new file mode 100755 index 000000000..64ca0c170 --- /dev/null +++ b/shell/hush_test/hush-quoting/dollar_repl_slash_bash2.tests @@ -0,0 +1,2 @@ +var="/a/bc/def/file" +echo "${var//\//\\/}" -- cgit v1.2.3-55-g6feb From 6ffaa00338a9dc5f9e798c30aa9f96e51ab2ef36 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 31 Mar 2018 00:46:07 +0200 Subject: hush: fix a signedness bug Testcase: set -- a ""; space=" "; printf "<%s>\n" "$@"$space Before: After: <> It usually does not bite since bbox forces -funsigned-char build. Signed-off-by: Denys Vlasenko --- shell/hush.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index e6dd1bc3d..01d8f5935 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -6126,7 +6126,7 @@ static NOINLINE int expand_vars_to_list(o_string *output, int n, char *arg) } else /* If EXP_FLAG_SINGLEWORD, we handle assignment 'a=....$@.....' * and in this case should treat it like '$*' - see 'else...' below */ - if (first_ch == ('@'|0x80) /* quoted $@ */ + if (first_ch == (char)('@'|0x80) /* quoted $@ */ && !(output->o_expflags & EXP_FLAG_SINGLEWORD) /* not v="$@" case */ ) { while (1) { -- cgit v1.2.3-55-g6feb From ad4e961352f04ba88019c4c2bb36c652ce9c51fa Mon Sep 17 00:00:00 2001 From: Martijn Dekker Date: Sat, 31 Mar 2018 18:15:59 +0200 Subject: ash: 'nolog' and 'debug' options cause "$-" to wreak havoc Upstream commit: Date: Tue Mar 6 17:40:37 2018 +0000 expand: 'nolog' and 'debug' options cause "$-" to wreak havoc Op 29-03-17 om 20:02 schreef Martijn Dekker: > Bug: if either the 'nolog' or the 'debug' option is set, trying to > expand "$-" silently aborts parsing of an entire argument. > > $ dash -o nolog -c 'set -fuC; echo "|$- are the options|"; set +o nolog; echo "|$- are the options|"' > | > |uCf are the options| > $ dash -o debug -c 'set -fuC; echo "|$- are the options|"; set +o debug; echo "|$- are the options|"' > | > |uCf are the options| This turned out to be easy to fix. The routine producing the "$-" expansion failed to skip options for which there is no option letter, but only a long-form name. In dash, 'nolog' and 'debug' are currently the only two such options. Patch below. - Martijn Signed-off-by: Herbert Xu In bbox ash, pipefail is the option which exhibited this. Signed-off-by: Martijn Dekker Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 8fb32c1ae..2ed802d2e 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -7192,7 +7192,7 @@ varvalue(char *name, int varflags, int flags, int *quotedp) case '-': expdest = makestrspace(NOPTS, expdest); for (i = NOPTS - 1; i >= 0; i--) { - if (optlist[i]) { + if (optlist[i] && optletters(i)) { USTPUTC(optletters(i), expdest); len++; } -- cgit v1.2.3-55-g6feb From 220be537a03f029e1e619003d6f7def10103a156 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 31 Mar 2018 19:21:31 +0200 Subject: ash: use pgetc_eatbnl() in more places Part of upstream commit: Date: Thu Mar 8 08:37:11 2018 +0100 Author: Harald van Dijk parser: use pgetc_eatbnl() in more places dash has a pgetc_eatbnl function in parser.c which skips any backslash-newline combinations. It's not used everywhere it could be. There is also some duplicated backslash-newline handling elsewhere in parser.c. Replace most of the calls to pgetc() with calls to pgetc_eatbnl() and remove the duplicated backslash-newline handling. Signed-off-by: Herbert Xu Not adding "readtoken1(pgetc_eatbnl(), DQSYNTAX..." changes, since readtoken1() handles the "starts with backslash + newline" case itself. Signed-off-by: Denys Vlasenko --- shell/ash.c | 47 ++++----------- .../ash_test/ash-heredoc/heredoc_backslash1.right | 43 +++++++++++++ .../ash_test/ash-heredoc/heredoc_backslash1.tests | 70 ++++++++++++++++++++++ .../ash-heredoc/heredoc_bkslash_newline1.right | 8 +++ .../ash-heredoc/heredoc_bkslash_newline1.tests | 25 ++++++++ .../hush-heredoc/heredoc_bkslash_newline1.right | 8 +++ .../hush-heredoc/heredoc_bkslash_newline1.tests | 25 ++++++++ 7 files changed, 191 insertions(+), 35 deletions(-) create mode 100644 shell/ash_test/ash-heredoc/heredoc_backslash1.right create mode 100755 shell/ash_test/ash-heredoc/heredoc_backslash1.tests create mode 100644 shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.right create mode 100755 shell/ash_test/ash-heredoc/heredoc_bkslash_newline1.tests create mode 100644 shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.right create mode 100755 shell/hush_test/hush-heredoc/heredoc_bkslash_newline1.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 2ed802d2e..a7767b4f8 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12225,7 +12225,7 @@ parseredir: { np = stzalloc(sizeof(struct nfile)); if (c == '>') { np->nfile.fd = 1; - c = pgetc(); + c = pgetc_eatbnl(); if (c == '>') np->type = NAPPEND; else if (c == '|') @@ -12247,7 +12247,7 @@ parseredir: { #endif else { /* c == '<' */ /*np->nfile.fd = 0; - stzalloc did it */ - c = pgetc(); + c = pgetc_eatbnl(); switch (c) { case '<': if (sizeof(struct nfile) != sizeof(struct nhere)) { @@ -12257,7 +12257,7 @@ parseredir: { np->type = NHERE; heredoc = stzalloc(sizeof(struct heredoc)); heredoc->here = np; - c = pgetc(); + c = pgetc_eatbnl(); if (c == '-') { heredoc->striptabs = 1; } else { @@ -12487,23 +12487,13 @@ parsebackq: { int pc; setprompt_if(needprompt, 2); - pc = pgetc(); + pc = pgetc_eatbnl(); switch (pc) { case '`': goto done; case '\\': - pc = pgetc(); - if (pc == '\n') { - nlprompt(); - /* - * If eating a newline, avoid putting - * the newline into the new character - * stream (via the STPUTC after the - * switch). - */ - continue; - } + pc = pgetc(); /* or pgetc_eatbnl()? why (example)? */ if (pc != '\\' && pc != '`' && pc != '$' && (!dblquote || pc != '"') ) { @@ -12635,7 +12625,7 @@ xxreadtoken(void) } setprompt_if(needprompt, 2); for (;;) { /* until token or start of word found */ - c = pgetc(); + c = pgetc_eatbnl(); if (c == ' ' || c == '\t' IF_ASH_ALIAS( || c == PEOA)) continue; @@ -12644,11 +12634,7 @@ xxreadtoken(void) continue; pungetc(); } else if (c == '\\') { - if (pgetc() != '\n') { - pungetc(); - break; /* return readtoken1(...) */ - } - nlprompt(); + break; /* return readtoken1(...) */ } else { const char *p; @@ -12695,7 +12681,7 @@ xxreadtoken(void) } setprompt_if(needprompt, 2); for (;;) { /* until token or start of word found */ - c = pgetc(); + c = pgetc_eatbnl(); switch (c) { case ' ': case '\t': IF_ASH_ALIAS(case PEOA:) @@ -12705,30 +12691,23 @@ xxreadtoken(void) continue; pungetc(); continue; - case '\\': - if (pgetc() == '\n') { - nlprompt(); - continue; - } - pungetc(); - goto breakloop; case '\n': nlnoprompt(); RETURN(TNL); case PEOF: RETURN(TEOF); case '&': - if (pgetc() == '&') + if (pgetc_eatbnl() == '&') RETURN(TAND); pungetc(); RETURN(TBACKGND); case '|': - if (pgetc() == '|') + if (pgetc_eatbnl() == '|') RETURN(TOR); pungetc(); RETURN(TPIPE); case ';': - if (pgetc() == ';') + if (pgetc_eatbnl() == ';') RETURN(TENDCASE); pungetc(); RETURN(TSEMI); @@ -12736,11 +12715,9 @@ xxreadtoken(void) RETURN(TLP); case ')': RETURN(TRP); - default: - goto breakloop; } + break; } - breakloop: return readtoken1(c, BASESYNTAX, (char *)NULL, 0); #undef RETURN } diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.right b/shell/ash_test/ash-heredoc/heredoc_backslash1.right new file mode 100644 index 000000000..6a6114821 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.right @@ -0,0 +1,43 @@ +Quoted heredoc: +a\ + b +a\\ + b + 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?- + -$a-\t-\\-\"-\'-\`-\--\z-\*-\?- + 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'` + 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-') +c\ + +Unquoted heredoc: +a b +a\ + b + 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?- + -qwerty-\t-\-\"-\'-`-\--\z-\*-\?- + 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?- + 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?- +cEOF2 + +Quoted -heredoc: +a\ +b +a\\ +b + 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?- +-$a-\t-\\-\"-\'-\`-\--\z-\*-\?- + 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'` + 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-') +c\ + +Unquoted -heredoc: +a b +a\ +b + 123456 -qwerty-\t-\-\"-\'-`-\--\z-\*-\?- +-qwerty-\t-\-\"-\'-`-\--\z-\*-\?- + 123456 v-$a-\t-\-\"-\x-`-\--\z-\*-\?- + 123456 v-$a-\t-\\-\"-\x-\`-\--\z-\*-\?- +cEOF4 + +Done: 0 diff --git a/shell/ash_test/ash-heredoc/heredoc_backslash1.tests b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests new file mode 100755 index 000000000..501af5490 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_backslash1.tests @@ -0,0 +1,70 @@ +# Test for correct handling of backslashes. +# Note that some lines in each heredoc start with a tab. + +a=qwerty + +echo Quoted heredoc: +cat <<"EOF1" +a\ + b +a\\ + b + 123456 -$a-\t-\\-\"-\'-\`-\--\z-\*-\?- + -$a-\t-\\-\"-\'-\`-\--\z-\*-\?- + 123456 `echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-'` + 123456 $(echo v'-$a-\t-\\-\"-\'-\`-\--\z-\*-\?-') +c\ +EOF1 +echo + +echo Unquoted heredoc: +cat < Date: Sat, 31 Mar 2018 20:16:31 +0200 Subject: hush: fix heredoc_bkslash_newline1.tests failure function old new delta parse_stream 2787 2827 +40 builtin_type 117 115 -2 Signed-off-by: Denys Vlasenko --- shell/hush.c | 77 +++++++++++++++++++++++++++++++++--------------------------- 1 file changed, 42 insertions(+), 35 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 01d8f5935..533d45ac3 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -2694,6 +2694,42 @@ static int i_peek2(struct in_str *i) return ch; } +static int i_getch_and_eat_bkslash_nl(struct in_str *input) +{ + for (;;) { + int ch, ch2; + + ch = i_getch(input); + if (ch != '\\') + return ch; + ch2 = i_peek(input); + if (ch2 != '\n') + return ch; + /* backslash+newline, skip it */ + i_getch(input); + } +} + +/* Note: this function _eats_ \ pairs, safe to use plain + * i_getch() after it instead of i_getch_and_eat_bkslash_nl(). + */ +static int i_peek_and_eat_bkslash_nl(struct in_str *input) +{ + for (;;) { + int ch, ch2; + + ch = i_peek(input); + if (ch != '\\') + return ch; + ch2 = i_peek2(input); + if (ch2 != '\n') + return ch; + /* backslash+newline, skip it */ + i_getch(input); + i_getch(input); + } +} + static void setup_file_in_str(struct in_str *i, FILE *f) { memset(i, 0, sizeof(*i)); @@ -4014,7 +4050,7 @@ static int parse_redirect(struct parse_context *ctx, if (dup_num == REDIRFD_SYNTAX_ERR) return 1; } else { - int ch = i_peek(input); + int ch = i_peek_and_eat_bkslash_nl(input); dup_num = (ch == '-'); /* HEREDOC_SKIPTABS bit is 1 */ if (dup_num) { /* <<-... */ ch = i_getch(input); @@ -4024,7 +4060,7 @@ static int parse_redirect(struct parse_context *ctx, } if (style == REDIRECT_OVERWRITE && dup_num == REDIRFD_TO_FILE) { - int ch = i_peek(input); + int ch = i_peek_and_eat_bkslash_nl(input); if (ch == '|') { /* >|FILE redirect ("clobbering" >). * Since we do not support "set -o noclobber" yet, @@ -4343,39 +4379,6 @@ static int parse_group(o_string *dest, struct parse_context *ctx, /* command remains "open", available for possible redirects */ } -static int i_getch_and_eat_bkslash_nl(struct in_str *input) -{ - for (;;) { - int ch, ch2; - - ch = i_getch(input); - if (ch != '\\') - return ch; - ch2 = i_peek(input); - if (ch2 != '\n') - return ch; - /* backslash+newline, skip it */ - i_getch(input); - } -} - -static int i_peek_and_eat_bkslash_nl(struct in_str *input) -{ - for (;;) { - int ch, ch2; - - ch = i_peek(input); - if (ch != '\\') - return ch; - ch2 = i_peek2(input); - if (ch2 != '\n') - return ch; - /* backslash+newline, skip it */ - i_getch(input); - i_getch(input); - } -} - #if ENABLE_HUSH_TICK || ENABLE_FEATURE_SH_MATH || ENABLE_HUSH_DOLLAR_OPS /* Subroutines for copying $(...) and `...` things */ static int add_till_backquote(o_string *dest, struct in_str *input, int in_dquote); @@ -5181,6 +5184,8 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; } redir_style = REDIRECT_OVERWRITE; + if (next == '\\') + next = i_peek_and_eat_bkslash_nl(input); if (next == '>') { redir_style = REDIRECT_APPEND; ch = i_getch(input); @@ -5201,6 +5206,8 @@ static struct pipe *parse_stream(char **pstring, goto parse_error; } redir_style = REDIRECT_INPUT; + if (next == '\\') + next = i_peek_and_eat_bkslash_nl(input); if (next == '<') { redir_style = REDIRECT_HEREDOC; heredoc_cnt++; -- cgit v1.2.3-55-g6feb From 32e183e63ecb46595a480ab66120795ed9c9e0df Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sat, 31 Mar 2018 20:31:13 +0200 Subject: shells: fix var_LINENO1.tests false positive, add it to ash tests too Signed-off-by: Denys Vlasenko --- shell/ash_test/ash-vars/var_LINENO1.right | 8 ++++++++ shell/ash_test/ash-vars/var_LINENO1.tests | 6 ++++++ shell/hush_test/hush-vars/var_LINENO1.tests | 2 +- 3 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 shell/ash_test/ash-vars/var_LINENO1.right create mode 100755 shell/ash_test/ash-vars/var_LINENO1.tests (limited to 'shell') diff --git a/shell/ash_test/ash-vars/var_LINENO1.right b/shell/ash_test/ash-vars/var_LINENO1.right new file mode 100644 index 000000000..31e1a4478 --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO1.right @@ -0,0 +1,8 @@ +2:2 +3:3 +4:4 +5:5 +2:2 +3:3 +4:4 +5:5 diff --git a/shell/ash_test/ash-vars/var_LINENO1.tests b/shell/ash_test/ash-vars/var_LINENO1.tests new file mode 100755 index 000000000..775861e64 --- /dev/null +++ b/shell/ash_test/ash-vars/var_LINENO1.tests @@ -0,0 +1,6 @@ +env | grep ^LINENO +echo 2:$LINENO +echo 3:$LINENO >&2 \ +| { sleep 0.1; echo 4:$LINENO; } +echo 5:$LINENO +test "$1" || . ./var_LINENO1.tests norepeat diff --git a/shell/hush_test/hush-vars/var_LINENO1.tests b/shell/hush_test/hush-vars/var_LINENO1.tests index 851b52cf5..775861e64 100755 --- a/shell/hush_test/hush-vars/var_LINENO1.tests +++ b/shell/hush_test/hush-vars/var_LINENO1.tests @@ -1,4 +1,4 @@ -env | grep LINENO +env | grep ^LINENO echo 2:$LINENO echo 3:$LINENO >&2 \ | { sleep 0.1; echo 4:$LINENO; } -- cgit v1.2.3-55-g6feb From 1e5111b0f80b1f3d7f2fc8254cb70de067317403 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 1 Apr 2018 03:04:55 +0200 Subject: ash,hush: handle a few more bkslash-newline cases Signed-off-by: Denys Vlasenko --- shell/ash.c | 2 +- shell/ash_test/ash-parsing/bkslash_newline1.right | 4 ++++ shell/ash_test/ash-parsing/bkslash_newline1.tests | 8 ++++++++ shell/ash_test/ash-parsing/bkslash_newline2.right | 4 ++++ shell/ash_test/ash-parsing/bkslash_newline2.tests | 4 ++++ shell/hush.c | 14 ++++++++++++-- shell/hush_test/hush-parsing/bkslash_newline1.right | 4 ++++ shell/hush_test/hush-parsing/bkslash_newline1.tests | 8 ++++++++ shell/hush_test/hush-parsing/bkslash_newline2.right | 4 ++++ shell/hush_test/hush-parsing/bkslash_newline2.tests | 4 ++++ 10 files changed, 53 insertions(+), 3 deletions(-) create mode 100644 shell/ash_test/ash-parsing/bkslash_newline1.right create mode 100755 shell/ash_test/ash-parsing/bkslash_newline1.tests create mode 100644 shell/ash_test/ash-parsing/bkslash_newline2.right create mode 100755 shell/ash_test/ash-parsing/bkslash_newline2.tests create mode 100644 shell/hush_test/hush-parsing/bkslash_newline1.right create mode 100755 shell/hush_test/hush-parsing/bkslash_newline1.tests create mode 100644 shell/hush_test/hush-parsing/bkslash_newline2.right create mode 100755 shell/hush_test/hush-parsing/bkslash_newline2.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index a7767b4f8..454bc3317 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12649,7 +12649,7 @@ xxreadtoken(void) break; /* return readtoken1(...) */ if ((int)(p - xxreadtoken_chars) >= xxreadtoken_singles) { - int cc = pgetc(); + int cc = pgetc_eatbnl(); if (cc == c) { /* double occurrence? */ p += xxreadtoken_doubles + 1; } else { diff --git a/shell/ash_test/ash-parsing/bkslash_newline1.right b/shell/ash_test/ash-parsing/bkslash_newline1.right new file mode 100644 index 000000000..97ea0c197 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline1.right @@ -0,0 +1,4 @@ +and1 +and2 +or1 +ok diff --git a/shell/ash_test/ash-parsing/bkslash_newline1.tests b/shell/ash_test/ash-parsing/bkslash_newline1.tests new file mode 100755 index 000000000..6e374c4fb --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline1.tests @@ -0,0 +1,8 @@ +echo and1 &\ +& echo and2 + +echo or1 |\ +| echo NOT SHOWN + +case w in a) echo SKIP;\ +; w) echo ok;; esac; diff --git a/shell/ash_test/ash-parsing/bkslash_newline2.right b/shell/ash_test/ash-parsing/bkslash_newline2.right new file mode 100644 index 000000000..c863c5453 --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline2.right @@ -0,0 +1,4 @@ +Line with one backslash: +\ + +Ok:0 diff --git a/shell/ash_test/ash-parsing/bkslash_newline2.tests b/shell/ash_test/ash-parsing/bkslash_newline2.tests new file mode 100755 index 000000000..47d63042d --- /dev/null +++ b/shell/ash_test/ash-parsing/bkslash_newline2.tests @@ -0,0 +1,4 @@ +echo Line with one backslash: +echo '\ +' +echo Ok:$? diff --git a/shell/hush.c b/shell/hush.c index 533d45ac3..4b8641d19 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -4980,8 +4980,14 @@ static struct pipe *parse_stream(char **pstring, nommu_addchr(&ctx.as_string, ch); next = '\0'; - if (ch != '\n') + if (ch != '\n') { next = i_peek(input); + /* Can't use i_peek_and_eat_bkslash_nl(input) here: + * echo '\ + * ' + * will break. + */ + } is_special = "{}<>;&|()#'" /* special outside of "str" */ "\\$\"" IF_HUSH_TICK("`") /* always special */ @@ -5375,7 +5381,7 @@ static struct pipe *parse_stream(char **pstring, /* Eat multiple semicolons, detect * whether it means something special */ while (1) { - ch = i_peek(input); + ch = i_peek_and_eat_bkslash_nl(input); if (ch != ';') break; ch = i_getch(input); @@ -5397,6 +5403,8 @@ static struct pipe *parse_stream(char **pstring, if (done_word(&dest, &ctx)) { goto parse_error; } + if (next == '\\') + next = i_peek_and_eat_bkslash_nl(input); if (next == '&') { ch = i_getch(input); nommu_addchr(&ctx.as_string, ch); @@ -5413,6 +5421,8 @@ static struct pipe *parse_stream(char **pstring, if (ctx.ctx_res_w == RES_MATCH) break; /* we are in case's "word | word)" */ #endif + if (next == '\\') + next = i_peek_and_eat_bkslash_nl(input); if (next == '|') { /* || */ ch = i_getch(input); nommu_addchr(&ctx.as_string, ch); diff --git a/shell/hush_test/hush-parsing/bkslash_newline1.right b/shell/hush_test/hush-parsing/bkslash_newline1.right new file mode 100644 index 000000000..97ea0c197 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline1.right @@ -0,0 +1,4 @@ +and1 +and2 +or1 +ok diff --git a/shell/hush_test/hush-parsing/bkslash_newline1.tests b/shell/hush_test/hush-parsing/bkslash_newline1.tests new file mode 100755 index 000000000..6e374c4fb --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline1.tests @@ -0,0 +1,8 @@ +echo and1 &\ +& echo and2 + +echo or1 |\ +| echo NOT SHOWN + +case w in a) echo SKIP;\ +; w) echo ok;; esac; diff --git a/shell/hush_test/hush-parsing/bkslash_newline2.right b/shell/hush_test/hush-parsing/bkslash_newline2.right new file mode 100644 index 000000000..c863c5453 --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline2.right @@ -0,0 +1,4 @@ +Line with one backslash: +\ + +Ok:0 diff --git a/shell/hush_test/hush-parsing/bkslash_newline2.tests b/shell/hush_test/hush-parsing/bkslash_newline2.tests new file mode 100755 index 000000000..47d63042d --- /dev/null +++ b/shell/hush_test/hush-parsing/bkslash_newline2.tests @@ -0,0 +1,4 @@ +echo Line with one backslash: +echo '\ +' +echo Ok:$? -- cgit v1.2.3-55-g6feb From 41fddb43729373740bfba82da83373ec5ba49fc8 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 1 Apr 2018 16:38:32 +0200 Subject: parser: Fix backquote support in here-document EOF mark Upstream commit: Author: Herbert Xu Date: Thu Mar 15 18:27:30 2018 +0800 parser: Fix backquote support in here-document EOF mark Currently using backquotes in a here-document EOF mark is broken because dash tries to do command substitution on it. This patch fixes it by checking whether we're looking for an EOF mark during tokenisation. Reported-by: Harald van Dijk Signed-off-by: Herbert Xu With added fix for quoted-ness of the EOF mark. Signed-off-by: Denys Vlasenko --- shell/ash.c | 6 ++++++ shell/ash_test/ash-heredoc/heredoc_backquote1.right | 5 +++++ shell/ash_test/ash-heredoc/heredoc_backquote1.tests | 10 ++++++++++ shell/hush_test/hush-heredoc/heredoc_backquote1.right | 5 +++++ shell/hush_test/hush-heredoc/heredoc_backquote1.tests | 10 ++++++++++ 5 files changed, 36 insertions(+) create mode 100644 shell/ash_test/ash-heredoc/heredoc_backquote1.right create mode 100755 shell/ash_test/ash-heredoc/heredoc_backquote1.tests create mode 100644 shell/hush_test/hush-heredoc/heredoc_backquote1.right create mode 100755 shell/hush_test/hush-heredoc/heredoc_backquote1.tests (limited to 'shell') diff --git a/shell/ash.c b/shell/ash.c index 454bc3317..cf1d062fb 100644 --- a/shell/ash.c +++ b/shell/ash.c @@ -12093,6 +12093,12 @@ readtoken1(int c, int syntax, char *eofmark, int striptabs) break; #endif case CBQUOTE: /* '`' */ + if (checkkwd & CHKEOFMARK) { + quotef = 1; + USTPUTC('`', out); + break; + } + PARSEBACKQOLD(); break; case CENDFILE: diff --git a/shell/ash_test/ash-heredoc/heredoc_backquote1.right b/shell/ash_test/ash-heredoc/heredoc_backquote1.right new file mode 100644 index 000000000..0be2a3296 --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_backquote1.right @@ -0,0 +1,5 @@ +heredoc1 +Ok1:0 +heredoc2 +EO`false`F +Ok2:0 diff --git a/shell/ash_test/ash-heredoc/heredoc_backquote1.tests b/shell/ash_test/ash-heredoc/heredoc_backquote1.tests new file mode 100755 index 000000000..ec3d8fe1d --- /dev/null +++ b/shell/ash_test/ash-heredoc/heredoc_backquote1.tests @@ -0,0 +1,10 @@ +cat < Date: Sun, 1 Apr 2018 18:55:00 +0200 Subject: hush: add a comment where we differ from bash wrt heredoc EOF mark handling Signed-off-by: Denys Vlasenko --- shell/hush.c | 8 ++++++++ shell/hush_test/hush-heredoc/heredoc_backquote1.right | 5 ----- shell/hush_test/hush-heredoc/heredoc_backquote1.tests | 10 ---------- 3 files changed, 8 insertions(+), 15 deletions(-) delete mode 100644 shell/hush_test/hush-heredoc/heredoc_backquote1.right delete mode 100755 shell/hush_test/hush-heredoc/heredoc_backquote1.tests (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 4b8641d19..1921932d1 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3861,6 +3861,13 @@ static int done_word(o_string *word, struct parse_context *ctx) * shell may perform it, but shall do so only when * the expansion would result in one word." */ +//bash does not do parameter/command substitution or arithmetic expansion +//for _heredoc_ redirection word: these constructs look for exact eof marker +// as written: +// <pending_redirect->rd_filename = xstrdup(word->data); /* Cater for >\file case: * >\a creates file a; >\\a, >"\a", >"\\a" create file \a @@ -4228,6 +4235,7 @@ static int fetch_heredocs(int heredoc_cnt, struct parse_context *ctx, struct in_ redir->rd_type = REDIRECT_HEREDOC2; /* redir->rd_dup is (ab)used to indicate <<- */ +bb_error_msg("redir->rd_filename:'%s'", redir->rd_filename); p = fetch_till_str(&ctx->as_string, input, redir->rd_filename, redir->rd_dup); if (!p) { diff --git a/shell/hush_test/hush-heredoc/heredoc_backquote1.right b/shell/hush_test/hush-heredoc/heredoc_backquote1.right deleted file mode 100644 index 0be2a3296..000000000 --- a/shell/hush_test/hush-heredoc/heredoc_backquote1.right +++ /dev/null @@ -1,5 +0,0 @@ -heredoc1 -Ok1:0 -heredoc2 -EO`false`F -Ok2:0 diff --git a/shell/hush_test/hush-heredoc/heredoc_backquote1.tests b/shell/hush_test/hush-heredoc/heredoc_backquote1.tests deleted file mode 100755 index ec3d8fe1d..000000000 --- a/shell/hush_test/hush-heredoc/heredoc_backquote1.tests +++ /dev/null @@ -1,10 +0,0 @@ -cat < Date: Sun, 1 Apr 2018 19:59:37 +0200 Subject: libbb: new function bb_die_memory_exhausted function old new delta bb_die_memory_exhausted - 10 +10 xstrdup 28 23 -5 xsetenv 27 22 -5 xrealloc 32 27 -5 xputenv 22 17 -5 xmalloc 30 25 -5 xfdopen_helper 40 35 -5 xasprintf 44 39 -5 wget_main 2387 2382 -5 open_socket 54 49 -5 glob_brace 419 414 -5 bb_get_chunk_from_file 146 141 -5 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 0/11 up/down: 10/-55) Total: -45 bytes Signed-off-by: Denys Vlasenko --- archival/libarchive/data_extract_to_command.c | 2 +- include/libbb.h | 29 ++++++++++++++------------- libbb/get_line_from_file.c | 2 +- libbb/wfopen.c | 2 +- libbb/xfuncs_printf.c | 15 +++++++++----- networking/wget.c | 4 ++-- shell/hush.c | 4 ++-- 7 files changed, 32 insertions(+), 26 deletions(-) (limited to 'shell') diff --git a/archival/libarchive/data_extract_to_command.c b/archival/libarchive/data_extract_to_command.c index 1114a95cb..0fcabb4a9 100644 --- a/archival/libarchive/data_extract_to_command.c +++ b/archival/libarchive/data_extract_to_command.c @@ -37,7 +37,7 @@ static const char *const tar_var[] = { static void xputenv(char *str) { if (putenv(str)) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); } static void str2env(char *env[], int idx, const char *str) diff --git a/include/libbb.h b/include/libbb.h index 309c58734..ad1c7346f 100644 --- a/include/libbb.h +++ b/include/libbb.h @@ -1277,20 +1277,21 @@ extern smallint syslog_level; extern smallint logmode; extern uint8_t xfunc_error_retval; extern void (*die_func)(void); -extern void xfunc_die(void) NORETURN FAST_FUNC; -extern void bb_show_usage(void) NORETURN FAST_FUNC; -extern void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; -extern void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; -extern void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; -extern void bb_simple_perror_msg(const char *s) FAST_FUNC; -extern void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; -extern void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; -extern void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; -extern void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; -extern void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; -extern void bb_perror_nomsg(void) FAST_FUNC; -extern void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC; -extern void bb_logenv_override(void) FAST_FUNC; +void xfunc_die(void) NORETURN FAST_FUNC; +void bb_show_usage(void) NORETURN FAST_FUNC; +void bb_error_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; +void bb_error_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; +void bb_perror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; +void bb_simple_perror_msg(const char *s) FAST_FUNC; +void bb_perror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; +void bb_simple_perror_msg_and_die(const char *s) NORETURN FAST_FUNC; +void bb_herror_msg(const char *s, ...) __attribute__ ((format (printf, 1, 2))) FAST_FUNC; +void bb_herror_msg_and_die(const char *s, ...) __attribute__ ((noreturn, format (printf, 1, 2))) FAST_FUNC; +void bb_perror_nomsg_and_die(void) NORETURN FAST_FUNC; +void bb_perror_nomsg(void) FAST_FUNC; +void bb_verror_msg(const char *s, va_list p, const char *strerr) FAST_FUNC; +void bb_die_memory_exhausted(void) NORETURN FAST_FUNC; +void bb_logenv_override(void) FAST_FUNC; /* We need to export XXX_main from libbusybox * only if we build "individual" binaries diff --git a/libbb/get_line_from_file.c b/libbb/get_line_from_file.c index d10066937..f3d6c6203 100644 --- a/libbb/get_line_from_file.c +++ b/libbb/get_line_from_file.c @@ -20,7 +20,7 @@ char* FAST_FUNC bb_get_chunk_from_file(FILE *file, size_t *end) /* grow the line buffer as necessary */ if (!(idx & 0xff)) { if (idx == ((size_t)-1) - 0xff) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); linebuf = xrealloc(linebuf, idx + 0x100); } linebuf[idx++] = (char) ch; diff --git a/libbb/wfopen.c b/libbb/wfopen.c index 20fe18b23..1c7f7f3d7 100644 --- a/libbb/wfopen.c +++ b/libbb/wfopen.c @@ -42,7 +42,7 @@ static FILE* xfdopen_helper(unsigned fd_and_rw_bit) { FILE* fp = fdopen(fd_and_rw_bit >> 1, fd_and_rw_bit & 1 ? "w" : "r"); if (!fp) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return fp; } FILE* FAST_FUNC xfdopen_for_read(int fd) diff --git a/libbb/xfuncs_printf.c b/libbb/xfuncs_printf.c index 2bc01ad10..7247c915b 100644 --- a/libbb/xfuncs_printf.c +++ b/libbb/xfuncs_printf.c @@ -25,6 +25,11 @@ * fail, so callers never need to check for errors. If it returned, it * succeeded. */ +void FAST_FUNC bb_die_memory_exhausted(void) +{ + bb_error_msg_and_die(bb_msg_memory_exhausted); +} + #ifndef DMALLOC /* dmalloc provides variants of these that do abort() on failure. * Since dmalloc's prototypes overwrite the impls here as they are @@ -44,7 +49,7 @@ void* FAST_FUNC xmalloc(size_t size) { void *ptr = malloc(size); if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return ptr; } @@ -55,7 +60,7 @@ void* FAST_FUNC xrealloc(void *ptr, size_t size) { ptr = realloc(ptr, size); if (ptr == NULL && size != 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return ptr; } #endif /* DMALLOC */ @@ -79,7 +84,7 @@ char* FAST_FUNC xstrdup(const char *s) t = strdup(s); if (t == NULL) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return t; } @@ -327,14 +332,14 @@ char* FAST_FUNC xasprintf(const char *format, ...) va_end(p); if (r < 0) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return string_ptr; } void FAST_FUNC xsetenv(const char *key, const char *value) { if (setenv(key, value, 1)) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); } /* Handles "VAR=VAL" strings, even those which are part of environ diff --git a/networking/wget.c b/networking/wget.c index 8969310a4..12ee29a6f 100644 --- a/networking/wget.c +++ b/networking/wget.c @@ -409,7 +409,7 @@ static FILE *open_socket(len_and_sockaddr *lsa) /* hopefully it understands what ESPIPE means... */ fp = fdopen(fd, "r+"); if (!fp) - bb_perror_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); return fp; } @@ -1114,7 +1114,7 @@ static void download_one_url(const char *url) # endif sfp = fdopen(fd, "r+"); if (!sfp) - bb_perror_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); goto socket_opened; } sfp = open_socket(lsa); diff --git a/shell/hush.c b/shell/hush.c index 1921932d1..8246b5fd8 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3158,7 +3158,7 @@ static int glob_brace(char *pattern, o_string *o, int n) return o_save_ptr_helper(o, n); } if (gr == GLOB_NOSPACE) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); /* GLOB_ABORTED? Only happens with GLOB_ERR flag, * but we didn't specify it. Paranoia again. */ bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); @@ -3260,7 +3260,7 @@ static int perform_glob(o_string *o, int n) goto literal; } if (gr == GLOB_NOSPACE) - bb_error_msg_and_die(bb_msg_memory_exhausted); + bb_die_memory_exhausted(); /* GLOB_ABORTED? Only happens with GLOB_ERR flag, * but we didn't specify it. Paranoia again. */ bb_error_msg_and_die("glob error %d on '%s'", gr, pattern); -- cgit v1.2.3-55-g6feb From e84212f8346741a2d4a04b40639c44fe519cf5a7 Mon Sep 17 00:00:00 2001 From: Denys Vlasenko Date: Sun, 1 Apr 2018 20:11:23 +0200 Subject: hush: update information comment about heredoc discrepancy Signed-off-by: Denys Vlasenko --- shell/hush.c | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) (limited to 'shell') diff --git a/shell/hush.c b/shell/hush.c index 8246b5fd8..06fe0e405 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -3851,12 +3851,17 @@ static int done_word(o_string *word, struct parse_context *ctx) if (ctx->pending_redirect) { /* We do not glob in e.g. >*.tmp case. bash seems to glob here * only if run as "bash", not "sh" */ - /* http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html + /* http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html * "2.7 Redirection - * ...the word that follows the redirection operator - * shall be subjected to tilde expansion, parameter expansion, - * command substitution, arithmetic expansion, and quote - * removal. Pathname expansion shall not be performed + * If the redirection operator is "<<" or "<<-", the word + * that follows the redirection operator shall be + * subjected to quote removal; it is unspecified whether + * any of the other expansions occur. For the other + * redirection operators, the word that follows the + * redirection operator shall be subjected to tilde + * expansion, parameter expansion, command substitution, + * arithmetic expansion, and quote removal. + * Pathname expansion shall not be performed * on the word by a non-interactive shell; an interactive * shell may perform it, but shall do so only when * the expansion would result in one word." @@ -3866,8 +3871,8 @@ static int done_word(o_string *word, struct parse_context *ctx) // as written: // <pending_redirect->rd_filename = xstrdup(word->data); /* Cater for >\file case: * >\a creates file a; >\\a, >"\a", >"\\a" create file \a -- cgit v1.2.3-55-g6feb