]> git.ipfire.org Git - thirdparty/bash.git/commitdiff
posix conformance fixes
authorChet Ramey <chet.ramey@case.edu>
Fri, 10 Mar 2023 20:45:52 +0000 (15:45 -0500)
committerChet Ramey <chet.ramey@case.edu>
Fri, 10 Mar 2023 20:45:52 +0000 (15:45 -0500)
13 files changed:
CWRU/CWRU.chlog
MANIFEST
builtins/alias.def
builtins/cd.def
builtins/command.def
builtins/trap.def
jobs.c
subst.c
tests/printf.right
tests/printf.tests
tests/printf5.sub [new file with mode: 0644]
tests/read.tests
tests/read9.sub [new file with mode: 0644]

index ca666338807717f0b19a84ed78f349bc9638d4a3..b3ea96aa7630f59be0395ce2025981a9b0d5228e 100644 (file)
@@ -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
index 0e83b0d0a7040b2cc9be3b28688e78e180975e69..24cd4eeb48b32df1b8f74915e343633caec49a28 100644 (file)
--- 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
index fa186d7ea765ef514e88b14dac7a26e3bb33f2da..b75262c52dc0ef431780e932c1f50e25c6aa5905 100644 (file)
@@ -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 */
index 7481000d4984e94cdbf85ef5ace2779ad615c5e5..08f18da9ea73f57e12baf96e9e16b1f303ba9627 100644 (file)
@@ -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)
index 9689e95585dae85c94ef6b7deeb313a92556196d..e695fdd1b70ea48e6c317d99f7c0522f8e53c1ca 100644 (file)
@@ -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 ();
index bd63e47c27658b4905bff8e9619878b01f5df4b0..f28bde8e87c8dd23886da3f5edb518dc4d16078d 100644 (file)
@@ -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 1c225aa6c544bd0afcfd884a8c8ae4ce784f78f5..00f9485c1d2e5b1f8cd96875df0bcc2c964d9044 100644 (file)
--- 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 c2ccc6fd2308732cf63dca6a2d4b3e1911ab8e48..4b2e316c30f0a2bf2cfc5226397530a01c9e01b2 100644 (file)
--- 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';
index b032dcbfd4a1e0d9063ec3f4e81428f6cd4e77d3..e99d04a769c1275d5978d98773f60830fef3a970 100644 (file)
@@ -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 --
index 3947e7d6de73c7a0dc15722752c3f5de03edfb4e..04a1e481c07ea03e3c417acd6d57ddece70899bb 100644 (file)
@@ -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 (file)
index 0000000..2ba6c73
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+#
+
+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
index 6132b6fe81e6c995bd530891c58aa0817a4d2114..e5c9bc5a69d0b6c7c9e190f90091351c55b024f7 100644 (file)
@@ -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 (file)
index 0000000..3f56fcb
--- /dev/null
@@ -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 <http://www.gnu.org/licenses/>.
+#
+: ${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