From 22cdf92bee16d1cef4124a0a3257b4a024865632 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Fri, 10 Mar 2023 15:45:52 -0500 Subject: [PATCH] posix conformance fixes --- CWRU/CWRU.chlog | 37 +++++++++++++++++++++++++++++++++++++ MANIFEST | 2 ++ builtins/alias.def | 18 +++++++++++------- builtins/cd.def | 14 +++++++++++--- builtins/command.def | 2 -- builtins/trap.def | 9 +++++++-- jobs.c | 8 +++++--- subst.c | 2 +- tests/printf.right | 20 ++++++++++++++++++++ tests/printf.tests | 1 + tests/printf5.sub | 36 ++++++++++++++++++++++++++++++++++++ tests/read.tests | 3 +++ tests/read9.sub | 41 +++++++++++++++++++++++++++++++++++++++++ 13 files changed, 175 insertions(+), 18 deletions(-) create mode 100644 tests/printf5.sub create mode 100644 tests/read9.sub diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index ca666338..b3ea96aa 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -5534,3 +5534,40 @@ parse.y examples/loadables/kv.c - kv: new loadable builtin, reads key-value pairs from stdin and assigns them to an associative array + + 3/7 + --- +builtins/trap.def + - trap_builtin: if trying to restore SIGQUIT to its default disposition, + and the shell is in posix mode, set to SIG_DFL if the shell is + running as an async command and signal_is_async_ignored (SIGQUIT) is + true. Posix conformance issue 751 + + 3/8 + --- +builtins/alias.def + - print_alias: now returns int. Check for write errors using sh_chkwrite + and return EXECUTION_FAILURE if it fails + - alias_builtin: if print_alias returns EXECUTION_FAILURE, return + EXECUTION_FAILURE immediately (write error). POSIX test conformance + + 3/9 + --- +builtins/cd.def + - change_to_directory: if we're not in physical mode and are in posix + mode, add step 9 of the posix cd algorithm, which essentially tries + the pathname the user supplied if it's shorter than PATH_MAX and the + length of the canonicalized pathname is longer than PATH_MAX. This + is basically what default bash mode does without the length checks. + POSIX test conformance. + +subst.c + - strip_trailing_ifs_whitespace: use ifs_whitespace(*s) instead of + spctabnl(*s) like word splitting and get_word_from_string. POSIX + test conformance + +jobs.c + - wait_for: tweak change from 1/18 to make sure a J_ASYNC job isn't in + the foreground (J_FOREGROUND) as it would be if it had been continued + in the foreground with `fg'; if it is, we want to give the terminal + back to shell_pgrp diff --git a/MANIFEST b/MANIFEST index 0e83b0d0..24cd4eeb 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1339,6 +1339,7 @@ tests/printf1.sub f tests/printf2.sub f tests/printf3.sub f tests/printf4.sub f +tests/printf5.sub f tests/procsub.tests f tests/procsub.right f tests/procsub1.sub f @@ -1366,6 +1367,7 @@ tests/read5.sub f tests/read6.sub f tests/read7.sub f tests/read8.sub f +tests/read9.sub f tests/redir.tests f tests/redir.right f tests/redir1.sub f diff --git a/builtins/alias.def b/builtins/alias.def index fa186d7e..b75262c5 100644 --- a/builtins/alias.def +++ b/builtins/alias.def @@ -63,7 +63,7 @@ $END /* Flags for print_alias */ #define AL_REUSABLE 0x01 -static void print_alias (alias_t *, int); +static int print_alias (alias_t *, int); /* Hack the alias command in a Korn shell way. */ int @@ -103,13 +103,14 @@ alias_builtin (WORD_LIST *list) if (alias_list == 0) return (EXECUTION_SUCCESS); + any_failed = EXECUTION_SUCCESS; for (offset = 0; alias_list[offset]; offset++) - print_alias (alias_list[offset], dflags); + if (any_failed = print_alias (alias_list[offset], dflags) != EXECUTION_SUCCESS) + break; free (alias_list); /* XXX - Do not free the strings. */ - if (list == 0) - return (sh_chkwrite (EXECUTION_SUCCESS)); + return (any_failed != EXECUTION_SUCCESS ? EXECUTION_FAILURE : sh_chkwrite (EXECUTION_SUCCESS)); } any_failed = 0; @@ -137,7 +138,10 @@ alias_builtin (WORD_LIST *list) { t = find_alias (name); if (t) - print_alias (t, dflags); + { + if (print_alias (t, dflags) != EXECUTION_SUCCESS) + return (EXECUTION_FAILURE); + } else { sh_notfound (name); @@ -221,7 +225,7 @@ unalias_builtin (WORD_LIST *list) } /* Output ALIAS in such a way as to allow it to be read back in. */ -static void +static int print_alias (alias_t *alias, int flags) { char *value; @@ -232,6 +236,6 @@ print_alias (alias_t *alias, int flags) printf ("%s=%s\n", alias->name, value); free (value); - fflush (stdout); + return (sh_chkwrite (EXECUTION_SUCCESS)); } #endif /* ALIAS */ diff --git a/builtins/cd.def b/builtins/cd.def index 7481000d..08f18da9 100644 --- a/builtins/cd.def +++ b/builtins/cd.def @@ -654,9 +654,17 @@ change_to_directory (char *newdir, int nolinks, int xattr) /* We're not in physical mode (nolinks == 0), but we failed to change to the canonicalized directory name (TDIR). Try what the user passed - verbatim. If we succeed, reinitialize the_current_working_directory. - POSIX requires that we just fail here, so we do in posix mode. */ - if (posixly_correct == 0 && chdir (newdir) == 0) + verbatim. If we succeed, reinitialize the_current_working_directory. */ + + /* The first block is step 9 in the POSIX cd algorithm. */ + if (posixly_correct && ndlen < PATH_MAX && strlen (tdir) >= PATH_MAX) + r = chdir (newdir); + else if (posixly_correct == 0) + r = chdir (newdir); + else + r = -1; + + if (r == 0) { t = resetpwd ("cd"); if (t == 0) diff --git a/builtins/command.def b/builtins/command.def index 9689e955..e695fdd1 100644 --- a/builtins/command.def +++ b/builtins/command.def @@ -123,8 +123,6 @@ command_builtin (WORD_LIST *list) #define COMMAND_BUILTIN_FLAGS (CMD_NO_FUNCTIONS | CMD_INHIBIT_EXPANSION | CMD_COMMAND_BUILTIN | (use_standard_path ? CMD_STDPATH : 0)) - INTERNAL_DEBUG (("command_builtin: running execute_command for `%s'", list->word->word)); - /* We don't want this to be reparsed (consider command echo 'foo &'), so just make a simple_command structure and call execute_command with it. */ command = make_bare_simple_command (); diff --git a/builtins/trap.def b/builtins/trap.def index bd63e47c..f28bde8e 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -251,8 +251,13 @@ trap_builtin (WORD_LIST *list) break; case SIGQUIT: - /* Always ignore SIGQUIT. */ - set_signal_handler (SIGQUIT, SIG_IGN); + /* Always ignore SIGQUIT, but allow a posix-mode shell + that is running asynchronously and has ignored + SIGQUIT to reset it to the default. POSIX interp 751. */ + if (posixly_correct && signal_is_async_ignored (SIGQUIT)) + set_signal_handler (SIGQUIT, termsig_sighandler); + else + set_signal_handler (SIGQUIT, SIG_IGN); break; case SIGTERM: #if defined (JOB_CONTROL) diff --git a/jobs.c b/jobs.c index 1c225aa6..00f9485c 100644 --- a/jobs.c +++ b/jobs.c @@ -3011,10 +3011,12 @@ if (job == NO_JOB) subshell. Make sure subst.c:command_substitute uses the same conditions to determine whether or not it should undo this and give the terminal to pipeline_pgrp. We don't give the terminal - back to shell_pgrp if an async job exits because we never gave it - to that job in the first place. */ + back to shell_pgrp if an async job in the background exits because + we never gave it to that job in the first place. An async job in + the foreground is one we started in the background and foregrounded + with `fg', and gave it the terminal. */ if ((flags & JWAIT_NOTERM) == 0 && running_in_background == 0 && - (job == NO_JOB || IS_ASYNC (job) == 0) && + (job == NO_JOB || IS_ASYNC (job) == 0 || IS_FOREGROUND (job)) && (subshell_environment & (SUBSHELL_ASYNC|SUBSHELL_PIPE)) == 0) give_terminal_to (shell_pgrp, 0); } diff --git a/subst.c b/subst.c index c2ccc6fd..4b2e316c 100644 --- a/subst.c +++ b/subst.c @@ -3299,7 +3299,7 @@ strip_trailing_ifs_whitespace (char *string, char *separators, int saw_escape) char *s; s = string + STRLEN (string) - 1; - while (s > string && ((spctabnl (*s) && isifs (*s)) || + while (s > string && ((ifs_whitespace (*s) && isifs (*s)) || (saw_escape && *s == CTLESC && spctabnl (s[1])))) s--; *++s = '\0'; diff --git a/tests/printf.right b/tests/printf.right index b032dcbf..e99d04a7 100644 --- a/tests/printf.right +++ b/tests/printf.right @@ -296,3 +296,23 @@ x +123x x +123x x +123x x +123x +abcd +ab + 123 + 123 + 173 + 7b + 7B + hello + hello + 123 + 6 +123 -- +123 -- +173 -- +7b -- +7B -- +hello -- +hello -- +123 -- +6 -- diff --git a/tests/printf.tests b/tests/printf.tests index 3947e7d6..04a1e481 100644 --- a/tests/printf.tests +++ b/tests/printf.tests @@ -329,3 +329,4 @@ ${THIS_SH} ./printf1.sub ${THIS_SH} ./printf2.sub ${THIS_SH} ./printf3.sub ${THIS_SH} ./printf4.sub +${THIS_SH} ./printf5.sub diff --git a/tests/printf5.sub b/tests/printf5.sub new file mode 100644 index 00000000..2ba6c73a --- /dev/null +++ b/tests/printf5.sub @@ -0,0 +1,36 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# + +printf "%.4s\n" abcde +printf "%.2b\n" abcde + +printf "%4d\n" 123 +printf "%5i\n" 123 +printf "%4o\n" 123 +printf "%4x\n" 123 +printf "%4X\n" 123 +printf "%7b\n" hello +printf "%6s\n" hello +printf "%4u\n" 123 +printf "%2c\n" 65 + +printf "%-4d--\n" 123 +printf "%-5i--\n" 123 +printf "%-4o--\n" 123 +printf "%-4x--\n" 123 +printf "%-4X--\n" 123 +printf "%-7b--\n" hello +printf "%-6s--\n" hello +printf "%-4u--\n" 123 +printf "%-2c--\n" 65 diff --git a/tests/read.tests b/tests/read.tests index 6132b6fe..e5c9bc5a 100644 --- a/tests/read.tests +++ b/tests/read.tests @@ -115,3 +115,6 @@ ${THIS_SH} ./read7.sub # test behavior of read -n and read -d on regular files ${THIS_SH} ./read8.sub + +# test behavior of trailing IFS whitespace - POSIX conformance +${THIS_SH} ./read9.sub diff --git a/tests/read9.sub b/tests/read9.sub new file mode 100644 index 00000000..3f56fcbe --- /dev/null +++ b/tests/read9.sub @@ -0,0 +1,41 @@ +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . +# +: ${TMPDIR:=/var/tmp} + +TESTDIR=${TMPDIR}/read9-test-$$ +mkdir ${TESTDIR} +cd $TESTDIR || { + echo "$TESTDIR: cannot cd" >&2 + exit 1 +} + +printf ' line\tb \t\r\f\v\n' > read9.stdin || exit 1 +printf 'var1=" line", var2="b "\n' > read9.expout || exit 1 + +IFS=$'\t\r\f\v' + +{ + # line 2 + unset var1 var2 + read var1 var2 && + printf 'var1="%s", var2="%s"\n' "$var1" "$var2" +} < read9.stdin > read9.stdout 2>&1 + +cmp read9.expout read9.stdout || { + echo "read9.sub: expected output and actual output differ" + diff read9.expout read9.stdout +} + +cd $OLDPWD +rm -rf $TESTDIR