subst.c
- use W_COMPASSIGN flag in do_assignment_internal instead of deciding
lexically which assignments are compound array assignments
+
+ 10/6
+ ----
+support/shobj-conf
+ - additions for System V.5 from Boyd Gerber <gerberb@zenez.com>
+
+subst.c
+ - in command_substitute, if subshell_environment includes
+ SUBSHELL_ASYNC, call make_child with the `async_p' argument set to
+ non-zero. This keeps command substitutions for async commands or
+ pipelines from trying to give the terminal back to the shell's
+ pgrp. make sure to save and restore last_asynchronous_pid. Fix
+ suggested by <pierre.humblet@ieee.org>
+
+ 10/7
+ ----
+config.h.in
+ - add a placeholder definition for WCONTINUED_BROKEN
+
+ 10/9
+ ----
+aclocal.m4
+ - add BASH_CHECK_WCONTINUED, checks for glibc bug where WCONTINUED is
+ defined but rejected as invalid by waitpid(2)
+
+configure.in
+ - add call to BASH_CHECK_WCONTINUED, defines WCONTINUED_BROKEN
+
+redir.c
+ - experimental change to add_undo_redirect to save manipulations to
+ file descriptors >= SHELL_FD_BASE (10) on the list of redirections
+ to be undone even if `exec' causes the list to be discarded
+
+doc/{bash.1,bashref.texi}
+ - note that redirections using file descriptors > 9 should be used
+ carefully, because they might conflict with file descriptors the
+ shell uses internally
lib/readline/complete.c
- fixed rl_menu_complete so that a negative argument cycles backwards
through the list
+
+ 10/3
+ ----
+subst.c
+ - use W_COMPASSIGN flag in do_assignment_internal instead of deciding
+ lexically which assignments are compound array assignments
+
+ 10/6
+ ----
+support/shobj-conf
+ - additions for System V.5 from Boyd Gerber <gerberb@zenez.com>
+
+subst.c
+ - in command_substitute, if subshell_environment includes
+ SUBSHELL_ASYNC, call make_child with the `async_p' argument set to
+ non-zero. This keeps command substitutions for async commands or
+ pipelines from trying to give the terminal back to the shell's
+ pgrp. make sure to save and restore last_asynchronous_pid. Fix
+ suggested by <pierre.humblet@ieee.org>
+
+ 10/7
+ ----
+config.h.in
+ - add a placeholder definition for WCONTINUED_BROKEN
+
+ 10/9
+ ----
+aclocal.m4
+ - add BASH_CHECK_WCONTINUED, checks for glibc bug where WCONTINUED is
+ defined but rejected as invalid by waitpid(2)
+
+configure.in
+ - add call to BASH_CHECK_WCONTINUED, defines WCONTINUED_BROKEN
+
+redir.c
+ - experimental change to add_undo_redirect to save manipulations to
+ file descriptors >= SHELL_FD_BASE (10) on the list of redirections
+ to be undone even if `exec' causes the list to be discarded
tests/extglob.right f
tests/extglob2.tests f
tests/extglob2.right f
+tests/extglob3.tests f
+tests/extglob3.right f
tests/func.tests f
tests/func.right f
tests/func1.sub f
tests/run-exp-tests f
tests/run-extglob f
tests/run-extglob2 f
+tests/run-extglob3 f
tests/run-func f
tests/run-getopts f
tests/run-glob-test f
tests/run-strip f
tests/run-test f
tests/run-tilde f
+tests/run-tilde2 f
tests/run-trap f
tests/run-type f
tests/run-varenv f
tests/strip.right f
tests/test.tests f
tests/test.right f
-tests/tilde-tests f
+tests/tilde.tests f
tests/tilde.right f
+tests/tilde2.tests f
+tests/tilde2.right f
tests/trap.tests f
tests/trap.right f
tests/trap1.sub f 755
fi
])
+AC_DEFUN(BASH_CHECK_WCONTINUED,
+[
+AC_MSG_CHECKING(whether WCONTINUED flag to waitpid is unavailable or available but broken)
+AC_CACHE_VAL(bash_cv_wcontinued_broken,
+[AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+main()
+{
+ int x;
+
+ x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED);
+ if (x == -1 && errno == EINVAL)
+ exit (1);
+ else
+ exit (0);
+}
+], bash_cv_wcontinued_broken=no,bash_cv_wcontinued_broken=yes,
+ [AC_MSG_WARN(cannot check WCONTINUED if cross compiling -- defaulting to no)
+ bash_cv_wcontinued_broken=no]
+)])
+AC_MSG_RESULT($bash_cv_wcontinued_broken)
+if test $bash_cv_wcontinued_broken = yes; then
+AC_DEFINE(WCONTINUED_BROKEN)
+fi
+])
+
dnl
dnl tests added for bashdb
dnl
[AC_MSG_CHECKING(whether /dev/fd is available)
AC_CACHE_VAL(bash_cv_dev_fd,
[if test -d /dev/fd && test -r /dev/fd/0 < /dev/null; then
- bash_cv_dev_fd=standard
+# check for systems like FreeBSD 5 that only provide /dev/fd/[012]
+ exec 3<&0
+ if test -r /dev/fd/3; then
+ bash_cv_dev_fd=standard
+ else
+ bash_cv_dev_fd=absent
+ fi
+ exec 3<&-
elif test -d /proc/self/fd && test -r /proc/self/fd/0 < /dev/null; then
bash_cv_dev_fd=whacky
else
fi
])
+AC_DEFUN(BASH_CHECK_WCONTINUED,
+[
+AC_MSG_CHECKING(whether WCONTINUED flag to waitpid is unavailable or available but broken)
+AC_CACHE_VAL(bash_cv_wcontinued_broken,
+[AC_TRY_RUN([
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+main()
+{
+ int x;
+
+ x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED);
+ if (x == -1 && errno == EINVAL)
+ exit (1);
+ else
+ exit (0);
+}
+], bash_cv_wcontinued_broken=no,bash_cv_wcontined_broken=yes,
+ [AC_MSG_WARN(cannot check WCONTINUED if cross compiling -- defaulting to no)
+ bash_cv_wcontinued_broken=no]
+)])
+AC_MSG_RESULT($bash_cv_wcontinued_broken)
+if test $bash_cv_wcontinued_broken = yes; then
+AC_DEFINE(WCONTINUED_BROKEN)
+fi
+])
+
dnl
dnl tests added for bashdb
dnl
@%:@! /bin/sh
-@%:@ From configure.in for Bash 3.0, version 3.169, from autoconf version AC_ACVERSION.
+@%:@ From configure.in for Bash 3.0, version 3.170, from autoconf version AC_ACVERSION.
@%:@ Guess values for system-dependent variables and create Makefiles.
@%:@ Generated by GNU Autoconf 2.57 for bash 3.1-devel.
@%:@
fi
+
+echo "$as_me:$LINENO: checking whether WCONTINUED flag to waitpid is unavailable or available but broken" >&5
+echo $ECHO_N "checking whether WCONTINUED flag to waitpid is unavailable or available but broken... $ECHO_C" >&6
+if test "${bash_cv_wcontinued_broken+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "$as_me:$LINENO: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&5
+echo "$as_me: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&2;}
+ bash_cv_wcontinued_broken=no
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+main()
+{
+ int x;
+
+ x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED);
+ if (x == -1 && errno == EINVAL)
+ exit (1);
+ else
+ exit (0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ bash_cv_wcontinued_broken=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+bash_cv_wcontinued_broken=yes
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+
+echo "$as_me:$LINENO: result: $bash_cv_wcontinued_broken" >&5
+echo "${ECHO_T}$bash_cv_wcontinued_broken" >&6
+if test $bash_cv_wcontinued_broken = yes; then
+cat >>confdefs.h <<\_ACEOF
+@%:@define WCONTINUED_BROKEN 1
+_ACEOF
+
+fi
+
+
echo "$as_me:$LINENO: checking for speed_t in sys/types.h" >&5
echo $ECHO_N "checking for speed_t in sys/types.h... $ECHO_C" >&6
if test "${bash_cv_speed_t_in_sys_types+set}" = set; then
'configure.in'
],
{
- 'AC_HEADER_MAJOR' => 1,
- 'AC_FUNC_GETPGRP' => 1,
- 'AC_CONFIG_SUBDIRS' => 1,
- 'AC_HEADER_STAT' => 1,
+ 'AC_CONFIG_FILES' => 1,
+ 'AC_HEADER_TIME' => 1,
+ 'AC_PROG_CPP' => 1,
+ 'AC_FUNC_REALLOC' => 1,
+ 'AC_C_CONST' => 1,
+ 'AC_C_VOLATILE' => 1,
+ 'AC_STRUCT_TIMEZONE' => 1,
+ 'AC_SUBST' => 1,
+ 'AC_TYPE_SIGNAL' => 1,
+ 'AC_CHECK_MEMBERS' => 1,
+ 'AC_TYPE_SIZE_T' => 1,
+ 'AC_FUNC_SETPGRP' => 1,
+ 'AC_TYPE_OFF_T' => 1,
+ 'AC_FUNC_GETMNTENT' => 1,
'AC_FUNC_LSTAT' => 1,
- 'AC_HEADER_DIRENT' => 1,
- 'AC_FUNC_STAT' => 1,
- 'AC_FUNC_SELECT_ARGTYPES' => 1,
- 'AC_FUNC_CHOWN' => 1,
- 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
- 'AC_STRUCT_ST_BLOCKS' => 1,
- 'AC_TYPE_PID_T' => 1,
- 'AC_FUNC_STRERROR_R' => 1,
- 'AC_FUNC_VPRINTF' => 1,
- 'AH_OUTPUT' => 1,
- 'm4_pattern_allow' => 1,
+ 'AC_FUNC_GETGROUPS' => 1,
'AC_CONFIG_HEADERS' => 1,
+ 'AC_FUNC_SELECT_ARGTYPES' => 1,
+ 'AC_PROG_CC' => 1,
+ 'AM_CONDITIONAL' => 1,
+ 'AC_REPLACE_FNMATCH' => 1,
'AC_FUNC_MEMCMP' => 1,
- 'AC_HEADER_STDC' => 1,
- 'AC_CHECK_HEADERS' => 1,
- 'AC_FUNC_CLOSEDIR_VOID' => 1,
- 'm4_include' => 1,
+ 'AC_FUNC_STRTOD' => 1,
'AM_AUTOMAKE_VERSION' => 1,
+ 'AC_TYPE_UID_T' => 1,
+ 'AC_FUNC_STRERROR_R' => 1,
+ 'AC_PROG_YACC' => 1,
'AC_CONFIG_AUX_DIR' => 1,
- 'AC_FUNC_MALLOC' => 1,
- 'AC_DECL_SYS_SIGLIST' => 1,
- 'AC_C_CONST' => 1,
- 'AC_FUNC_SETPGRP' => 1,
- 'AC_CANONICAL_SYSTEM' => 1,
- 'AC_C_VOLATILE' => 1,
- 'AC_FUNC_FSEEKO' => 1,
- 'AC_FUNC_MBRTOWC' => 1,
+ 'AC_FUNC_OBSTACK' => 1,
+ 'AC_HEADER_STAT' => 1,
+ 'AC_FUNC_CLOSEDIR_VOID' => 1,
+ 'AC_PROG_CXX' => 1,
'AC_STRUCT_TM' => 1,
- 'AC_FUNC_STRCOLL' => 1,
- 'AC_HEADER_SYS_WAIT' => 1,
+ 'AC_FUNC_STRFTIME' => 1,
+ 'AC_FUNC_UTIME_NULL' => 1,
'AC_PROG_LIBTOOL' => 1,
- 'AC_CHECK_TYPES' => 1,
- 'AC_CONFIG_FILES' => 1,
- 'AC_CHECK_LIB' => 1,
- 'include' => 1,
- 'AC_FUNC_GETGROUPS' => 1,
- 'AC_PATH_X' => 1,
- 'AC_PROG_CC' => 1,
- 'AC_FUNC_GETLOADAVG' => 1,
- 'AC_HEADER_TIME' => 1,
- 'AC_REPLACE_FNMATCH' => 1,
- 'AC_LIBSOURCE' => 1,
- 'AC_PROG_LN_S' => 1,
- 'AC_FUNC_OBSTACK' => 1,
- 'AC_PROG_LEX' => 1,
- 'AC_FUNC_STRTOD' => 1,
- 'AC_TYPE_MODE_T' => 1,
- 'AC_CHECK_MEMBERS' => 1,
- 'AC_FUNC_ERROR_AT_LINE' => 1,
- 'AM_CONDITIONAL' => 1,
- 'AC_STRUCT_TIMEZONE' => 1,
- 'AC_FUNC_REALLOC' => 1,
- 'AM_PROG_CC_C_O' => 1,
+ 'AC_FUNC_FSEEKO' => 1,
'AM_GNU_GETTEXT' => 1,
- 'AC_PROG_MAKE_SET' => 1,
- 'AC_FUNC_UTIME_NULL' => 1,
- 'AC_PROG_CXX' => 1,
- 'AC_FUNC_MMAP' => 1,
- 'AC_PROG_GCC_TRADITIONAL' => 1,
- 'AC_DEFINE_TRACE_LITERAL' => 1,
- 'AC_PROG_AWK' => 1,
+ 'AC_PROG_RANLIB' => 1,
'AC_FUNC_FORK' => 1,
- 'AC_FUNC_ALLOCA' => 1,
+ 'AC_FUNC_MALLOC' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
- 'AC_TYPE_OFF_T' => 1,
- 'AC_PROG_RANLIB' => 1,
- 'AC_TYPE_SIGNAL' => 1,
- 'AC_PROG_CPP' => 1,
- 'AC_C_INLINE' => 1,
+ 'AC_TYPE_PID_T' => 1,
+ 'AC_PROG_GCC_TRADITIONAL' => 1,
+ 'AC_PROG_LEX' => 1,
+ 'AC_FUNC_STRCOLL' => 1,
+ 'AC_PATH_X' => 1,
'AM_INIT_AUTOMAKE' => 1,
- 'AC_TYPE_UID_T' => 1,
- 'AC_PROG_YACC' => 1,
- 'AC_FUNC_STRNLEN' => 1,
- 'AC_PROG_INSTALL' => 1,
- 'AC_FUNC_WAIT3' => 1,
+ 'AC_CHECK_TYPES' => 1,
+ 'AC_FUNC_GETLOADAVG' => 1,
+ 'include' => 1,
+ 'AC_LIBSOURCE' => 1,
'AC_CHECK_FUNCS' => 1,
- 'AM_MAINTAINER_MODE' => 1,
- 'AC_CANONICAL_HOST' => 1,
- 'AC_FUNC_STRFTIME' => 1,
+ 'm4_include' => 1,
'AC_FUNC_MKTIME' => 1,
- 'AC_SUBST' => 1,
- 'AC_TYPE_SIZE_T' => 1,
+ 'AC_FUNC_STAT' => 1,
+ 'AC_FUNC_CHOWN' => 1,
+ 'AC_HEADER_DIRENT' => 1,
+ 'AC_FUNC_STRNLEN' => 1,
+ 'AM_MAINTAINER_MODE' => 1,
+ 'AC_FUNC_WAIT3' => 1,
+ 'AC_PROG_LN_S' => 1,
+ 'AC_PROG_INSTALL' => 1,
+ 'm4_pattern_allow' => 1,
+ 'AC_FUNC_GETPGRP' => 1,
+ 'AC_PROG_AWK' => 1,
'AC_INIT' => 1,
- 'AC_FUNC_GETMNTENT' => 1,
- 'm4_pattern_forbid' => 1
+ 'AC_DEFINE_TRACE_LITERAL' => 1,
+ 'AC_CHECK_LIB' => 1,
+ 'AC_HEADER_MAJOR' => 1,
+ 'AC_FUNC_MBRTOWC' => 1,
+ 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
+ 'AC_FUNC_MMAP' => 1,
+ 'AC_CANONICAL_HOST' => 1,
+ 'AC_CONFIG_SUBDIRS' => 1,
+ 'AC_DECL_SYS_SIGLIST' => 1,
+ 'AC_HEADER_SYS_WAIT' => 1,
+ 'AC_C_INLINE' => 1,
+ 'AC_STRUCT_ST_BLOCKS' => 1,
+ 'AC_FUNC_ALLOCA' => 1,
+ 'AM_PROG_CC_C_O' => 1,
+ 'AC_CANONICAL_SYSTEM' => 1,
+ 'AC_FUNC_VPRINTF' => 1,
+ 'AC_FUNC_ERROR_AT_LINE' => 1,
+ 'AH_OUTPUT' => 1,
+ 'AC_TYPE_MODE_T' => 1,
+ 'AC_PROG_MAKE_SET' => 1,
+ 'm4_pattern_forbid' => 1,
+ 'AC_HEADER_STDC' => 1,
+ 'AC_CHECK_HEADERS' => 1
}
], 'Request' )
);
#undef GWINSZ_IN_SYS_IOCTL])
m4trace:configure.in:860: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL])
m4trace:configure.in:861: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL])
-m4trace:configure.in:864: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES])
-m4trace:configure.in:865: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS])
-m4trace:configure.in:866: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS])
-m4trace:configure.in:867: -1- AC_SUBST([SIGLIST_O])
-m4trace:configure.in:871: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL])
-m4trace:configure.in:879: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo,
+m4trace:configure.in:863: -1- AC_DEFINE_TRACE_LITERAL([WCONTINUED_BROKEN])
+m4trace:configure.in:866: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES])
+m4trace:configure.in:867: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS])
+m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS])
+m4trace:configure.in:869: -1- AC_SUBST([SIGLIST_O])
+m4trace:configure.in:873: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL])
+m4trace:configure.in:881: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo,
[AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])])
-m4trace:configure.in:879: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
+m4trace:configure.in:881: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses,
[AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])])
-m4trace:configure.in:879: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
+m4trace:configure.in:881: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses,
bash_cv_termcap_lib=gnutermcap)])
-m4trace:configure.in:879: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap])
-m4trace:configure.in:881: -1- AC_SUBST([TERMCAP_LIB])
-m4trace:configure.in:882: -1- AC_SUBST([TERMCAP_DEP])
-m4trace:configure.in:884: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
-m4trace:configure.in:884: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
-m4trace:configure.in:884: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
-m4trace:configure.in:884: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
-m4trace:configure.in:885: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN])
-m4trace:configure.in:886: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY])
-m4trace:configure.in:893: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL])
-m4trace:configure.in:899: -1- AC_SUBST([JOBS_O])
-m4trace:configure.in:912: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2])
-m4trace:configure.in:913: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
-m4trace:configure.in:914: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
-m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([SVR5])
-m4trace:configure.in:972: -1- AC_SUBST([SHOBJ_CC])
-m4trace:configure.in:973: -1- AC_SUBST([SHOBJ_CFLAGS])
-m4trace:configure.in:974: -1- AC_SUBST([SHOBJ_LD])
-m4trace:configure.in:975: -1- AC_SUBST([SHOBJ_LDFLAGS])
-m4trace:configure.in:976: -1- AC_SUBST([SHOBJ_XLDFLAGS])
-m4trace:configure.in:977: -1- AC_SUBST([SHOBJ_LIBS])
-m4trace:configure.in:978: -1- AC_SUBST([SHOBJ_STATUS])
-m4trace:configure.in:999: -1- AC_SUBST([PROFILE_FLAGS])
-m4trace:configure.in:1001: -1- AC_SUBST([incdir])
-m4trace:configure.in:1002: -1- AC_SUBST([BUILD_DIR])
-m4trace:configure.in:1004: -1- AC_SUBST([YACC])
-m4trace:configure.in:1005: -1- AC_SUBST([AR])
-m4trace:configure.in:1006: -1- AC_SUBST([ARFLAGS])
-m4trace:configure.in:1008: -1- AC_SUBST([BASHVERS])
-m4trace:configure.in:1009: -1- AC_SUBST([RELSTATUS])
-m4trace:configure.in:1010: -1- AC_SUBST([DEBUG])
-m4trace:configure.in:1011: -1- AC_SUBST([MALLOC_DEBUG])
-m4trace:configure.in:1013: -1- AC_SUBST([host_cpu])
-m4trace:configure.in:1014: -1- AC_SUBST([host_vendor])
-m4trace:configure.in:1015: -1- AC_SUBST([host_os])
-m4trace:configure.in:1017: -1- AC_SUBST([LOCAL_LIBS])
-m4trace:configure.in:1018: -1- AC_SUBST([LOCAL_CFLAGS])
-m4trace:configure.in:1019: -1- AC_SUBST([LOCAL_LDFLAGS])
-m4trace:configure.in:1020: -1- AC_SUBST([LOCAL_DEFS])
-m4trace:configure.in:1034: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \
+m4trace:configure.in:881: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap])
+m4trace:configure.in:883: -1- AC_SUBST([TERMCAP_LIB])
+m4trace:configure.in:884: -1- AC_SUBST([TERMCAP_DEP])
+m4trace:configure.in:886: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
+m4trace:configure.in:886: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
+m4trace:configure.in:886: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD])
+m4trace:configure.in:886: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX])
+m4trace:configure.in:887: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN])
+m4trace:configure.in:888: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY])
+m4trace:configure.in:895: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL])
+m4trace:configure.in:901: -1- AC_SUBST([JOBS_O])
+m4trace:configure.in:914: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2])
+m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
+m4trace:configure.in:916: -1- AC_DEFINE_TRACE_LITERAL([SVR4])
+m4trace:configure.in:917: -1- AC_DEFINE_TRACE_LITERAL([SVR5])
+m4trace:configure.in:974: -1- AC_SUBST([SHOBJ_CC])
+m4trace:configure.in:975: -1- AC_SUBST([SHOBJ_CFLAGS])
+m4trace:configure.in:976: -1- AC_SUBST([SHOBJ_LD])
+m4trace:configure.in:977: -1- AC_SUBST([SHOBJ_LDFLAGS])
+m4trace:configure.in:978: -1- AC_SUBST([SHOBJ_XLDFLAGS])
+m4trace:configure.in:979: -1- AC_SUBST([SHOBJ_LIBS])
+m4trace:configure.in:980: -1- AC_SUBST([SHOBJ_STATUS])
+m4trace:configure.in:1001: -1- AC_SUBST([PROFILE_FLAGS])
+m4trace:configure.in:1003: -1- AC_SUBST([incdir])
+m4trace:configure.in:1004: -1- AC_SUBST([BUILD_DIR])
+m4trace:configure.in:1006: -1- AC_SUBST([YACC])
+m4trace:configure.in:1007: -1- AC_SUBST([AR])
+m4trace:configure.in:1008: -1- AC_SUBST([ARFLAGS])
+m4trace:configure.in:1010: -1- AC_SUBST([BASHVERS])
+m4trace:configure.in:1011: -1- AC_SUBST([RELSTATUS])
+m4trace:configure.in:1012: -1- AC_SUBST([DEBUG])
+m4trace:configure.in:1013: -1- AC_SUBST([MALLOC_DEBUG])
+m4trace:configure.in:1015: -1- AC_SUBST([host_cpu])
+m4trace:configure.in:1016: -1- AC_SUBST([host_vendor])
+m4trace:configure.in:1017: -1- AC_SUBST([host_os])
+m4trace:configure.in:1019: -1- AC_SUBST([LOCAL_LIBS])
+m4trace:configure.in:1020: -1- AC_SUBST([LOCAL_CFLAGS])
+m4trace:configure.in:1021: -1- AC_SUBST([LOCAL_LDFLAGS])
+m4trace:configure.in:1022: -1- AC_SUBST([LOCAL_DEFS])
+m4trace:configure.in:1036: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \
lib/intl/Makefile \
lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \
lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \
examples/loadables/Makefile examples/loadables/perl/Makefile \
pathnames.h])
-m4trace:configure.in:1034: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
-m4trace:configure.in:1034: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
+m4trace:configure.in:1036: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs])
+m4trace:configure.in:1036: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs])
#undef HAVE_LIBC_FNM_EXTMATCH
-
#undef HAVE_DECL_CONFSTR
#undef HAVE_DECL_PRINTF
#undef HAVE_MBSTATE_T
+/* Define if WCONTINUED is defined in system headers, but rejected by waitpid */
+#undef WCONTINUED_BROKEN
+
/* These are checked with BASH_CHECK_DECL */
#undef HAVE_DECL_STRTOIMAX
#! /bin/sh
-# From configure.in for Bash 3.0, version 3.169, from autoconf version AC_ACVERSION.
+# From configure.in for Bash 3.0, version 3.170, from autoconf version AC_ACVERSION.
# Guess values for system-dependent variables and create Makefiles.
# Generated by GNU Autoconf 2.57 for bash 3.1-devel.
#
fi
+
+echo "$as_me:$LINENO: checking whether WCONTINUED flag to waitpid is unavailable or available but broken" >&5
+echo $ECHO_N "checking whether WCONTINUED flag to waitpid is unavailable or available but broken... $ECHO_C" >&6
+if test "${bash_cv_wcontinued_broken+set}" = set; then
+ echo $ECHO_N "(cached) $ECHO_C" >&6
+else
+ if test "$cross_compiling" = yes; then
+ { echo "$as_me:$LINENO: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&5
+echo "$as_me: WARNING: cannot check WCONTINUED if cross compiling -- defaulting to no" >&2;}
+ bash_cv_wcontinued_broken=no
+
+else
+ cat >conftest.$ac_ext <<_ACEOF
+#line $LINENO "configure"
+/* confdefs.h. */
+_ACEOF
+cat confdefs.h >>conftest.$ac_ext
+cat >>conftest.$ac_ext <<_ACEOF
+/* end confdefs.h. */
+
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <errno.h>
+
+#ifndef errno
+extern int errno;
+#endif
+main()
+{
+ int x;
+
+ x = waitpid(-1, (int *)0, WNOHANG|WCONTINUED);
+ if (x == -1 && errno == EINVAL)
+ exit (1);
+ else
+ exit (0);
+}
+
+_ACEOF
+rm -f conftest$ac_exeext
+if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && { ac_try='./conftest$ac_exeext'
+ { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5
+ (eval $ac_try) 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }; }; then
+ bash_cv_wcontinued_broken=no
+else
+ echo "$as_me: program exited with status $ac_status" >&5
+echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+( exit $ac_status )
+bash_cv_wcontinued_broken=yes
+fi
+rm -f core core.* *.core gmon.out bb.out conftest$ac_exeext conftest.$ac_objext conftest.$ac_ext
+fi
+fi
+
+echo "$as_me:$LINENO: result: $bash_cv_wcontinued_broken" >&5
+echo "${ECHO_T}$bash_cv_wcontinued_broken" >&6
+if test $bash_cv_wcontinued_broken = yes; then
+cat >>confdefs.h <<\_ACEOF
+#define WCONTINUED_BROKEN 1
+_ACEOF
+
+fi
+
+
echo "$as_me:$LINENO: checking for speed_t in sys/types.h" >&5
echo $ECHO_N "checking for speed_t in sys/types.h... $ECHO_C" >&6
if test "${bash_cv_speed_t_in_sys_types+set}" = set; then
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
-AC_REVISION([for Bash 3.0, version 3.169, from autoconf version] AC_ACVERSION)dnl
+AC_REVISION([for Bash 3.0, version 3.170, from autoconf version] AC_ACVERSION)dnl
define(bashvers, 3.1)
define(relstatus, devel)
BASH_HAVE_TIOCSTAT
BASH_HAVE_FIONREAD
+BASH_CHECK_WCONTINUED
+
dnl miscellaneous
BASH_CHECK_SPEED_T
BASH_CHECK_GETPW_FUNCS
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
# 02111-1307, USA.
-AC_REVISION([for Bash 3.0, version 3.168, from autoconf version] AC_ACVERSION)dnl
+AC_REVISION([for Bash 3.0, version 3.169, from autoconf version] AC_ACVERSION)dnl
-define(bashvers, 3.0)
-define(relstatus, release)
+define(bashvers, 3.1)
+define(relstatus, devel)
AC_INIT(bash, bashvers-relstatus, bug-bash@gnu.org)
getaddrinfo gethostbyname getservbyname getservent inet_aton \
vsnprintf snprintf vasprintf asprintf fnmatch regcomp regexec)
AC_CHECK_FUNCS(isascii isblank isgraph isprint isspace isxdigit)
-AC_REPLACE_FUNCS(getcwd strcasecmp strerror strftime strpbrk memset strstr)
+AC_REPLACE_FUNCS(getcwd strcasecmp strerror strftime strpbrk memset strstr strnlen)
AC_REPLACE_FUNCS(strtod strtol strtoul strtoll strtoull strtoimax strtoumax)
AC_CHECK_DECLS([confstr])
.RE
.PP
A failure to open or create a file causes the redirection to fail.
+.PP
+Redirections using file descriptors greater than 9 should be used with
+care, as they may conflict with file descriptors the shell uses
+internally.
.SS Redirecting Input
.PP
Redirection of input causes the file whose name results from
.\" Case Western Reserve University
.\" chet@po.CWRU.Edu
.\"
-.\" Last Change: Thu Sep 30 22:29:05 EDT 2004
+.\" Last Change: Sat Oct 2 18:05:57 EDT 2004
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
-.TH BASH 1 "2004 Sep 30" "GNU Bash-3.0"
+.TH BASH 1 "2004 Oct 2" "GNU Bash-3.1-devel"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
Matches one or more occurrences of the given patterns
.TP
\fB@(\fP\^\fIpattern-list\^\fP\fB)\fP
-Matches exactly one of the given patterns
+Matches one of the given patterns
.TP
\fB!(\fP\^\fIpattern-list\^\fP\fB)\fP
Matches anything except one of the given patterns
A failure to open or create a file causes the redirection to fail.
+Redirections using file descriptors greater than 9 should be used with
+care, as they may conflict with file descriptors the shell uses
+internally.
+
@subsection Redirecting Input
Redirection of input causes the file whose name results from
the expansion of @var{word}
Matches one or more occurrences of the given patterns.
@item @@(@var{pattern-list})
-Matches exactly one of the given patterns.
+Matches one of the given patterns.
@item !(@var{pattern-list})
Matches anything except one of the given patterns.
@set EDITION 3.1-devel
@set VERSION 3.1-devel
-@set UPDATED 2 October 2004
+@set UPDATED 9 October 2004
@set UPDATED-MONTH October 2004
-@set LASTCHANGE Sat Oct 2 18:05:41 EDT 2004
+@set LASTCHANGE Sat Oct 9 18:40:05 EDT 2004
Copyright (C) 1988-2004 Free Software Foundation, Inc.
@end ignore
-@set EDITION 3.0
-@set VERSION 3.0
-@set UPDATED 2 October 2004
+@set EDITION 3.1-devel
+@set VERSION 3.1-devel
+@set UPDATED 9 October 2004
@set UPDATED-MONTH October 2004
-@set LASTCHANGE Sat Oct 2 18:05:41 EDT 2004
+@set LASTCHANGE
static int execute_until_command __P((WHILE_COM *));
static int execute_while_or_until __P((WHILE_COM *, int));
static int execute_if_command __P((IF_COM *));
-static int execute_null_command __P((REDIRECT *, int, int, int, pid_t));
+static int execute_null_command __P((REDIRECT *, int, int, int));
static void fix_assignment_words __P((WORD_LIST *));
static int execute_simple_command __P((SIMPLE_COM *, int, int, int, struct fd_bitmap *));
static int execute_builtin __P((sh_builtin_func_t *, WORD_LIST *, int, int));
{
int exec_result, invert, ignore_return, was_error_trap;
REDIRECT *my_undo_list, *exec_undo_list;
- volatile pid_t last_pid;
volatile int save_line_number;
if (command == 0 || breaking || continuing || read_but_dont_execute)
/* We can't rely on variables retaining their values across a
call to execute_simple_command if a longjmp occurs as the
result of a `return' builtin. This is true for sure with gcc. */
- last_pid = last_made_pid;
+ last_made_pid = NO_PID;
was_error_trap = signal_is_trapped (ERROR_TRAP) && signal_is_ignored (ERROR_TRAP) == 0;
if (ignore_return && command->value.Simple)
/* XXX - this is something to watch out for if there are problems
when the shell is compiled without job control. */
if (already_making_children && pipe_out == NO_PIPE &&
- last_pid != last_made_pid)
+ last_made_pid != NO_PID)
{
stop_pipeline (asynchronous, (COMMAND *)NULL);
subshells forked to execute builtin commands (e.g., in
pipelines) to be waited for twice. */
exec_result = wait_for (last_made_pid);
-#if defined (RECYCLES_PIDS)
- /* LynxOS, for one, recycles pids very quickly -- so quickly
- that a new process may have the same pid as the last one
- created. This has been reported to fix the problem on that
- OS, and a similar problem on Cygwin. */
- if (exec_result == 0)
- last_made_pid = NO_PID;
-#endif
}
}
to be run asynchronously. This handles all the side effects that are
supposed to take place. */
static int
-execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subst_pid)
+execute_null_command (redirects, pipe_in, pipe_out, async)
REDIRECT *redirects;
int pipe_in, pipe_out, async;
- pid_t old_last_command_subst_pid;
{
int r;
if (r != 0)
return (EXECUTION_FAILURE);
- else if (old_last_command_subst_pid != last_command_subst_pid)
+ else if (last_command_subst_pid != NO_PID)
return (last_command_exit_value);
else
return (EXECUTION_SUCCESS);
WORD_LIST *words, *lastword;
char *command_line, *lastarg, *temp;
int first_word_quoted, result, builtin_is_special, already_forked, dofork;
- pid_t old_last_command_subst_pid, old_last_async_pid;
+ pid_t old_last_async_pid;
sh_builtin_func_t *builtin;
SHELL_VAR *func;
first_word_quoted =
simple_command->words ? (simple_command->words->word->flags & W_QUOTED): 0;
- old_last_command_subst_pid = last_command_subst_pid;
+ last_command_subst_pid = NO_PID;
old_last_async_pid = last_asynchronous_pid;
already_forked = dofork = 0;
this_command_name = 0;
result = execute_null_command (simple_command->redirects,
pipe_in, pipe_out,
- already_forked ? 0 : async,
- old_last_command_subst_pid);
+ already_forked ? 0 : async);
if (already_forked)
exit (result);
else
--- /dev/null
+/* input.c -- functions to perform buffered input with synchronization. */
+
+/* Copyright (C) 1992 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash 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 2, or (at your option) any later
+ version.
+
+ Bash 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 Bash; see the file COPYING. If not, write to the Free Software
+ Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+
+#include "config.h"
+
+#include "bashtypes.h"
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+#include "filecntl.h"
+#include "posixstat.h"
+#include <stdio.h>
+#include <errno.h>
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "command.h"
+#include "general.h"
+#include "input.h"
+#include "error.h"
+#include "externs.h"
+
+#if !defined (errno)
+extern int errno;
+#endif /* !errno */
+
+/* Functions to handle reading input on systems that don't restart read(2)
+ if a signal is received. */
+
+static char localbuf[128];
+static int local_index, local_bufused;
+
+/* Posix and USG systems do not guarantee to restart read () if it is
+ interrupted by a signal. We do the read ourselves, and restart it
+ if it returns EINTR. */
+int
+getc_with_restart (stream)
+ FILE *stream;
+{
+ unsigned char uc;
+
+ /* Try local buffering to reduce the number of read(2) calls. */
+ if (local_index == local_bufused || local_bufused == 0)
+ {
+ while (1)
+ {
+ local_bufused = read (fileno (stream), localbuf, sizeof(localbuf));
+ if (local_bufused > 0)
+ break;
+ else if (local_bufused == 0 || errno != EINTR)
+ {
+ local_index = 0;
+ return EOF;
+ }
+ }
+ local_index = 0;
+ }
+ uc = localbuf[local_index++];
+ return uc;
+}
+
+int
+ungetc_with_restart (c, stream)
+ int c;
+ FILE *stream;
+{
+ if (local_index == 0 || c == EOF)
+ return EOF;
+ localbuf[--local_index] = c;
+ return c;
+}
+
+#if defined (BUFFERED_INPUT)
+
+/* A facility similar to stdio, but input-only. */
+
+#if defined (USING_BASH_MALLOC)
+# define MAX_INPUT_BUFFER_SIZE 8176
+#else
+# define MAX_INPUT_BUFFER_SIZE 8192
+#endif
+
+#if !defined (SEEK_CUR)
+# define SEEK_CUR 1
+#endif /* !SEEK_CUR */
+
+#ifdef max
+# undef max
+#endif
+#define max(a, b) (((a) > (b)) ? (a) : (b))
+#ifdef min
+# undef min
+#endif
+#define min(a, b) ((a) > (b) ? (b) : (a))
+
+extern int interactive_shell;
+
+int bash_input_fd_changed;
+
+/* This provides a way to map from a file descriptor to the buffer
+ associated with that file descriptor, rather than just the other
+ way around. This is needed so that buffers are managed properly
+ in constructs like 3<&4. buffers[x]->b_fd == x -- that is how the
+ correspondence is maintained. */
+static BUFFERED_STREAM **buffers = (BUFFERED_STREAM **)NULL;
+static int nbuffers;
+
+#define ALLOCATE_BUFFERS(n) \
+ do { if ((n) >= nbuffers) allocate_buffers (n); } while (0)
+
+/* Make sure `buffers' has at least N elements. */
+static void
+allocate_buffers (n)
+ int n;
+{
+ register int i, orig_nbuffers;
+
+ orig_nbuffers = nbuffers;
+ nbuffers = n + 20;
+ buffers = (BUFFERED_STREAM **)xrealloc
+ (buffers, nbuffers * sizeof (BUFFERED_STREAM *));
+
+ /* Zero out the new buffers. */
+ for (i = orig_nbuffers; i < nbuffers; i++)
+ buffers[i] = (BUFFERED_STREAM *)NULL;
+}
+
+/* Construct and return a BUFFERED_STREAM corresponding to file descriptor
+ FD, using BUFFER. */
+static BUFFERED_STREAM *
+make_buffered_stream (fd, buffer, bufsize)
+ int fd;
+ char *buffer;
+ size_t bufsize;
+{
+ BUFFERED_STREAM *bp;
+
+ bp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
+ ALLOCATE_BUFFERS (fd);
+ buffers[fd] = bp;
+ bp->b_fd = fd;
+ bp->b_buffer = buffer;
+ bp->b_size = bufsize;
+ bp->b_used = bp->b_inputp = bp->b_flag = 0;
+ if (bufsize == 1)
+ bp->b_flag |= B_UNBUFF;
+ return (bp);
+}
+
+/* Allocate a new BUFFERED_STREAM, copy BP to it, and return the new copy. */
+static BUFFERED_STREAM *
+copy_buffered_stream (bp)
+ BUFFERED_STREAM *bp;
+{
+ BUFFERED_STREAM *nbp;
+
+ if (!bp)
+ return ((BUFFERED_STREAM *)NULL);
+
+ nbp = (BUFFERED_STREAM *)xmalloc (sizeof (BUFFERED_STREAM));
+ xbcopy ((char *)bp, (char *)nbp, sizeof (BUFFERED_STREAM));
+ return (nbp);
+}
+
+int
+set_bash_input_fd (fd)
+ int fd;
+{
+ if (bash_input.type == st_bstream)
+ bash_input.location.buffered_fd = fd;
+ else if (interactive_shell == 0)
+ default_buffered_input = fd;
+ return 0;
+}
+
+int
+fd_is_bash_input (fd)
+ int fd;
+{
+ if (bash_input.type == st_bstream && bash_input.location.buffered_fd == fd)
+ return 1;
+ else if (interactive_shell == 0 && default_buffered_input == fd)
+ return 1;
+ return 0;
+}
+
+/* Save the buffered stream corresponding to file descriptor FD (which bash
+ is using to read input) to a buffered stream associated with NEW_FD. If
+ NEW_FD is -1, a new file descriptor is allocated with fcntl. The new
+ file descriptor is returned on success, -1 on error. */
+int
+save_bash_input (fd, new_fd)
+ int fd, new_fd;
+{
+ int nfd;
+
+itrace("save_bash_input: %d -> %d", fd, new_fd);
+ /* Sync the stream so we can re-read from the new file descriptor. We
+ might be able to avoid this by copying the buffered stream verbatim
+ to the new file descriptor. */
+ if (buffers[fd])
+ sync_buffered_stream (fd);
+
+ /* Now take care of duplicating the file descriptor that bash is
+ using for input, so we can reinitialize it later. */
+ nfd = (new_fd == -1) ? fcntl (fd, F_DUPFD, 10) : new_fd;
+ if (nfd == -1)
+ {
+ if (fcntl (fd, F_GETFD, 0) == 0)
+ sys_error (_("cannot allocate new file descriptor for bash input from fd %d"), fd);
+ return -1;
+ }
+
+ if (buffers[nfd])
+ {
+ /* What's this? A stray buffer without an associated open file
+ descriptor? Free up the buffer and report the error. */
+ internal_error (_("save_bash_input: buffer already exists for new fd %d"), nfd);
+ free_buffered_stream (buffers[nfd]);
+ }
+
+ /* Reinitialize bash_input.location. */
+ if (bash_input.type == st_bstream)
+ {
+ bash_input.location.buffered_fd = nfd;
+ fd_to_buffered_stream (nfd);
+ close_buffered_fd (fd); /* XXX */
+ }
+ else
+ /* If the current input type is not a buffered stream, but the shell
+ is not interactive and therefore using a buffered stream to read
+ input (e.g. with an `eval exec 3>output' inside a script), note
+ that the input fd has been changed. pop_stream() looks at this
+ value and adjusts the input fd to the new value of
+ default_buffered_input accordingly. */
+ bash_input_fd_changed++;
+
+ if (default_buffered_input == fd)
+ default_buffered_input = nfd;
+
+ SET_CLOSE_ON_EXEC (nfd);
+ return nfd;
+}
+
+/* Check that file descriptor FD is not the one that bash is currently
+ using to read input from a script. FD is about to be duplicated onto,
+ which means that the kernel will close it for us. If FD is the bash
+ input file descriptor, we need to seek backwards in the script (if
+ possible and necessary -- scripts read from stdin are still unbuffered),
+ allocate a new file descriptor to use for bash input, and re-initialize
+ the buffered stream. Make sure the file descriptor used to save bash
+ input is set close-on-exec. Returns 0 on success, -1 on failure. This
+ works only if fd is > 0 -- if fd == 0 and bash is reading input from
+ fd 0, save_bash_input is used instead, to cooperate with input
+ redirection (look at redir.c:add_undo_redirect()). */
+int
+check_bash_input (fd)
+ int fd;
+{
+itrace("check_bash_input: %d", fd);
+ if (fd_is_bash_input (fd))
+ {
+ if (fd > 0)
+ return ((save_bash_input (fd, -1) == -1) ? -1 : 0);
+ else if (fd == 0)
+ return ((sync_buffered_stream (fd) == -1) ? -1 : 0);
+ }
+ return 0;
+}
+
+/* This is the buffered stream analogue of dup2(fd1, fd2). The
+ BUFFERED_STREAM corresponding to fd2 is deallocated, if one exists.
+ BUFFERS[fd1] is copied to BUFFERS[fd2]. This is called by the
+ redirect code for constructs like 4<&0 and 3</etc/rc.local. */
+int
+duplicate_buffered_stream (fd1, fd2)
+ int fd1, fd2;
+{
+ int is_bash_input, m;
+
+ if (fd1 == fd2)
+ return 0;
+
+ m = max (fd1, fd2);
+ ALLOCATE_BUFFERS (m);
+
+ /* If FD2 is the file descriptor bash is currently using for shell input,
+ we need to do some extra work to make sure that the buffered stream
+ actually exists (it might not if fd1 was not active, and the copy
+ didn't actually do anything). */
+ is_bash_input = (bash_input.type == st_bstream) &&
+ (bash_input.location.buffered_fd == fd2);
+
+ if (buffers[fd2])
+ free_buffered_stream (buffers[fd2]);
+ buffers[fd2] = copy_buffered_stream (buffers[fd1]);
+ if (buffers[fd2])
+ buffers[fd2]->b_fd = fd2;
+
+ if (is_bash_input)
+ {
+ if (!buffers[fd2])
+ fd_to_buffered_stream (fd2);
+ buffers[fd2]->b_flag |= B_WASBASHINPUT;
+ }
+
+ return (fd2);
+}
+
+/* Return 1 if a seek on FD will succeed. */
+#ifndef __CYGWIN__
+# define fd_is_seekable(fd) (lseek ((fd), 0L, SEEK_CUR) >= 0)
+#else
+# define fd_is_seekable(fd) 0
+#endif /* __CYGWIN__ */
+
+/* Take FD, a file descriptor, and create and return a buffered stream
+ corresponding to it. If something is wrong and the file descriptor
+ is invalid, return a NULL stream. */
+BUFFERED_STREAM *
+fd_to_buffered_stream (fd)
+ int fd;
+{
+ char *buffer;
+ size_t size;
+ struct stat sb;
+
+ if (fstat (fd, &sb) < 0)
+ {
+ close (fd);
+ return ((BUFFERED_STREAM *)NULL);
+ }
+
+ size = (fd_is_seekable (fd)) ? min (sb.st_size, MAX_INPUT_BUFFER_SIZE) : 1;
+ if (size == 0)
+ size = 1;
+ buffer = (char *)xmalloc (size);
+
+ return (make_buffered_stream (fd, buffer, size));
+}
+
+/* Return a buffered stream corresponding to FILE, a file name. */
+BUFFERED_STREAM *
+open_buffered_stream (file)
+ char *file;
+{
+ int fd;
+
+ fd = open (file, O_RDONLY);
+ return ((fd >= 0) ? fd_to_buffered_stream (fd) : (BUFFERED_STREAM *)NULL);
+}
+
+/* Deallocate a buffered stream and free up its resources. Make sure we
+ zero out the slot in BUFFERS that points to BP. */
+void
+free_buffered_stream (bp)
+ BUFFERED_STREAM *bp;
+{
+ int n;
+
+ if (!bp)
+ return;
+
+ n = bp->b_fd;
+ if (bp->b_buffer)
+ free (bp->b_buffer);
+ free (bp);
+ buffers[n] = (BUFFERED_STREAM *)NULL;
+}
+
+/* Close the file descriptor associated with BP, a buffered stream, and free
+ up the stream. Return the status of closing BP's file descriptor. */
+int
+close_buffered_stream (bp)
+ BUFFERED_STREAM *bp;
+{
+ int fd;
+
+ if (!bp)
+ return (0);
+ fd = bp->b_fd;
+ free_buffered_stream (bp);
+ return (close (fd));
+}
+
+/* Deallocate the buffered stream associated with file descriptor FD, and
+ close FD. Return the status of the close on FD. */
+int
+close_buffered_fd (fd)
+ int fd;
+{
+ if (fd < 0)
+ {
+ errno = EBADF;
+ return -1;
+ }
+ if (fd >= nbuffers || !buffers || !buffers[fd])
+ return (close (fd));
+ return (close_buffered_stream (buffers[fd]));
+}
+
+/* Make the BUFFERED_STREAM associcated with buffers[FD] be BP, and return
+ the old BUFFERED_STREAM. */
+BUFFERED_STREAM *
+set_buffered_stream (fd, bp)
+ int fd;
+ BUFFERED_STREAM *bp;
+{
+ BUFFERED_STREAM *ret;
+
+ ret = buffers[fd];
+ buffers[fd] = bp;
+ return ret;
+}
+
+/* Read a buffer full of characters from BP, a buffered stream. */
+static int
+b_fill_buffer (bp)
+ BUFFERED_STREAM *bp;
+{
+ ssize_t nr;
+
+ nr = zread (bp->b_fd, bp->b_buffer, bp->b_size);
+ if (nr <= 0)
+ {
+ bp->b_used = 0;
+ bp->b_buffer[0] = 0;
+ if (nr == 0)
+ bp->b_flag |= B_EOF;
+ else
+ bp->b_flag |= B_ERROR;
+ return (EOF);
+ }
+
+#if defined (__CYGWIN__)
+ /* If on cygwin, translate \r\n to \n. */
+ if (nr >= 2 && bp->b_buffer[nr - 2] == '\r' && bp->b_buffer[nr - 1] == '\n')
+ {
+ bp->b_buffer[nr - 2] = '\n';
+ nr--;
+ }
+#endif
+
+ bp->b_used = nr;
+ bp->b_inputp = 0;
+ return (bp->b_buffer[bp->b_inputp++] & 0xFF);
+}
+
+/* Get a character from buffered stream BP. */
+#define bufstream_getc(bp) \
+ (bp->b_inputp == bp->b_used || !bp->b_used) \
+ ? b_fill_buffer (bp) \
+ : bp->b_buffer[bp->b_inputp++] & 0xFF
+
+/* Push C back onto buffered stream BP. */
+static int
+bufstream_ungetc(c, bp)
+ int c;
+ BUFFERED_STREAM *bp;
+{
+ if (c == EOF || bp->b_inputp == 0)
+ return (EOF);
+
+ bp->b_buffer[--bp->b_inputp] = c;
+ return (c);
+}
+
+/* Seek backwards on file BFD to synchronize what we've read so far
+ with the underlying file pointer. */
+int
+sync_buffered_stream (bfd)
+ int bfd;
+{
+ BUFFERED_STREAM *bp;
+ off_t chars_left;
+
+ if (buffers == 0 || (bp = buffers[bfd]) == 0)
+ return (-1);
+
+ chars_left = bp->b_used - bp->b_inputp;
+ if (chars_left)
+ lseek (bp->b_fd, -chars_left, SEEK_CUR);
+ bp->b_used = bp->b_inputp = 0;
+ return (0);
+}
+
+int
+buffered_getchar ()
+{
+#if !defined (DJGPP)
+ return (bufstream_getc (buffers[bash_input.location.buffered_fd]));
+#else
+ /* On DJGPP, ignore \r. */
+ int ch;
+ while ((ch = bufstream_getc (buffers[bash_input.location.buffered_fd])) == '\r')
+ ;
+ return ch;
+#endif
+}
+
+int
+buffered_ungetchar (c)
+ int c;
+{
+ return (bufstream_ungetc (c, buffers[bash_input.location.buffered_fd]));
+}
+
+/* Make input come from file descriptor BFD through a buffered stream. */
+void
+with_input_from_buffered_stream (bfd, name)
+ int bfd;
+ char *name;
+{
+ INPUT_STREAM location;
+ BUFFERED_STREAM *bp;
+
+ location.buffered_fd = bfd;
+ /* Make sure the buffered stream exists. */
+ bp = fd_to_buffered_stream (bfd);
+ init_yy_io (bp == 0 ? return_EOF : buffered_getchar,
+ buffered_ungetchar, st_bstream, name, location);
+}
+
+#if defined (TEST)
+void *
+xmalloc(s)
+int s;
+{
+ return (malloc (s));
+}
+
+void *
+xrealloc(s, size)
+char *s;
+int size;
+{
+ if (!s)
+ return(malloc (size));
+ else
+ return(realloc (s, size));
+}
+
+void
+init_yy_io ()
+{
+}
+
+process(bp)
+BUFFERED_STREAM *bp;
+{
+ int c;
+
+ while ((c = bufstream_getc(bp)) != EOF)
+ putchar(c);
+}
+
+BASH_INPUT bash_input;
+
+struct stat dsb; /* can be used from gdb */
+
+/* imitate /bin/cat */
+main(argc, argv)
+int argc;
+char **argv;
+{
+ register int i;
+ BUFFERED_STREAM *bp;
+
+ if (argc == 1) {
+ bp = fd_to_buffered_stream (0);
+ process(bp);
+ exit(0);
+ }
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] == '-' && argv[i][1] == '\0') {
+ bp = fd_to_buffered_stream (0);
+ if (!bp)
+ continue;
+ process(bp);
+ free_buffered_stream (bp);
+ } else {
+ bp = open_buffered_stream (argv[i]);
+ if (!bp)
+ continue;
+ process(bp);
+ close_buffered_stream (bp);
+ }
+ }
+ exit(0);
+}
+#endif /* TEST */
+#endif /* BUFFERED_INPUT */
is thrown away by the `exec' builtin. */
add_exec_redirect (dummy_redirect);
+ /* experimental: if we're saving a redirection to undo for a file descriptor
+ above SHELL_FD_BASE, add a redirection to be undone if the exec builtin
+ causes redirections to be discarded. */
+ if (fd >= SHELL_FD_BASE)
+ {
+ rd.dest = new_fd;
+ new_redirect = make_redirection (fd, r_duplicating_output, rd);
+#if 0
+ closer = copy_redirects (new_redirect);
+ add_exec_redirect (closer);
+#else
+ add_exec_redirect (new_redirect);
+#endif
+ }
+
/* File descriptors used only for saving others should always be
marked close-on-exec. Unfortunately, we have to preserve the
close-on-exec state of the file descriptor we are saving, since
--- /dev/null
+/* redir.c -- Functions to perform input and output redirection. */
+
+/* Copyright (C) 1997-2002 Free Software Foundation, Inc.
+
+ This file is part of GNU Bash, the Bourne Again SHell.
+
+ Bash 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 2, or (at your option)
+ any later version.
+
+ Bash 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 Bash; see the file COPYING. If not, write to the Free
+ Software Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
+#include "config.h"
+
+#if !defined (__GNUC__) && !defined (HAVE_ALLOCA_H) && defined (_AIX)
+ #pragma alloca
+#endif /* _AIX && RISC6000 && !__GNUC__ */
+
+#include <stdio.h>
+#include "bashtypes.h"
+#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H)
+# include <sys/file.h>
+#endif
+#include "filecntl.h"
+#include "posixstat.h"
+
+#if defined (HAVE_UNISTD_H)
+# include <unistd.h>
+#endif
+
+#include <errno.h>
+
+#if !defined (errno)
+extern int errno;
+#endif
+
+#include "bashansi.h"
+#include "bashintl.h"
+
+#include "memalloc.h"
+#include "shell.h"
+#include "flags.h"
+#include "execute_cmd.h"
+#include "redir.h"
+
+#if defined (BUFFERED_INPUT)
+# include "input.h"
+#endif
+
+int expanding_redir;
+
+extern int posixly_correct;
+extern REDIRECT *redirection_undo_list;
+extern REDIRECT *exec_redirection_undo_list;
+
+/* Static functions defined and used in this file. */
+static void add_undo_close_redirect __P((int));
+static void add_exec_redirect __P((REDIRECT *));
+static int add_undo_redirect __P((int));
+static int expandable_redirection_filename __P((REDIRECT *));
+static int stdin_redirection __P((enum r_instruction, int));
+static int do_redirection_internal __P((REDIRECT *, int));
+
+static int write_here_document __P((int, WORD_DESC *));
+static int write_here_string __P((int, WORD_DESC *));
+static int here_document_to_fd __P((WORD_DESC *, enum r_instruction));
+
+static int redir_special_open __P((int, char *, int, int, enum r_instruction));
+static int noclobber_open __P((char *, int, int, enum r_instruction));
+static int redir_open __P((char *, int, int, enum r_instruction));
+
+/* Spare redirector used when translating [N]>&WORD[-] or [N]<&WORD[-] to
+ a new redirection and when creating the redirection undo list. */
+static REDIRECTEE rd;
+
+/* Set to errno when a here document cannot be created for some reason.
+ Used to print a reasonable error message. */
+static int heredoc_errno;
+
+void
+redirection_error (temp, error)
+ REDIRECT *temp;
+ int error;
+{
+ char *filename, *allocname;
+ int oflags;
+
+ allocname = 0;
+ if (temp->redirector < 0)
+ /* This can happen when read_token_word encounters overflow, like in
+ exec 4294967297>x */
+ filename = _("file descriptor out of range");
+#ifdef EBADF
+ else if (temp->redirector >= 0 && errno == EBADF)
+ {
+ /* If we're dealing with two file descriptors, we have to guess about
+ which one is invalid; in the cases of r_{duplicating,move}_input and
+ r_{duplicating,move}_output we're here because dup2() failed. */
+ switch (temp->instruction)
+ {
+ case r_duplicating_input:
+ case r_duplicating_output:
+ case r_move_input:
+ case r_move_output:
+ filename = allocname = itos (temp->redirectee.dest);
+ break;
+ default:
+ filename = allocname = itos (temp->redirector);
+ break;
+ }
+ }
+#endif
+ else if (expandable_redirection_filename (temp))
+ {
+ if (posixly_correct && interactive_shell == 0)
+ {
+ oflags = temp->redirectee.filename->flags;
+ temp->redirectee.filename->flags |= W_NOGLOB;
+ }
+ filename = allocname = redirection_expand (temp->redirectee.filename);
+ if (posixly_correct && interactive_shell == 0)
+ temp->redirectee.filename->flags = oflags;
+ if (filename == 0)
+ filename = temp->redirectee.filename->word;
+ }
+ else if (temp->redirectee.dest < 0)
+ filename = "file descriptor out of range";
+ else
+ filename = allocname = itos (temp->redirectee.dest);
+
+ switch (error)
+ {
+ case AMBIGUOUS_REDIRECT:
+ internal_error (_("%s: ambiguous redirect"), filename);
+ break;
+
+ case NOCLOBBER_REDIRECT:
+ internal_error (_("%s: cannot overwrite existing file"), filename);
+ break;
+
+#if defined (RESTRICTED_SHELL)
+ case RESTRICTED_REDIRECT:
+ internal_error (_("%s: restricted: cannot redirect output"), filename);
+ break;
+#endif /* RESTRICTED_SHELL */
+
+ case HEREDOC_REDIRECT:
+ internal_error (_("cannot create temp file for here document: %s"), strerror (heredoc_errno));
+ break;
+
+ default:
+ internal_error ("%s: %s", filename, strerror (error));
+ break;
+ }
+
+ FREE (allocname);
+}
+
+/* Perform the redirections on LIST. If flags & RX_ACTIVE, then actually
+ make input and output file descriptors, otherwise just do whatever is
+ neccessary for side effecting. flags & RX_UNDOABLE says to remember
+ how to undo the redirections later, if non-zero. If flags & RX_CLEXEC
+ is non-zero, file descriptors opened in do_redirection () have their
+ close-on-exec flag set. */
+int
+do_redirections (list, flags)
+ REDIRECT *list;
+ int flags;
+{
+ int error;
+ REDIRECT *temp;
+
+ if (flags & RX_UNDOABLE)
+ {
+ if (redirection_undo_list)
+ {
+ dispose_redirects (redirection_undo_list);
+ redirection_undo_list = (REDIRECT *)NULL;
+ }
+ if (exec_redirection_undo_list)
+ dispose_exec_redirects ();
+ }
+
+ for (temp = list; temp; temp = temp->next)
+ {
+ error = do_redirection_internal (temp, flags);
+ if (error)
+ {
+ redirection_error (temp, error);
+ return (error);
+ }
+ }
+ return (0);
+}
+
+/* Return non-zero if the redirection pointed to by REDIRECT has a
+ redirectee.filename that can be expanded. */
+static int
+expandable_redirection_filename (redirect)
+ REDIRECT *redirect;
+{
+ switch (redirect->instruction)
+ {
+ case r_output_direction:
+ case r_appending_to:
+ case r_input_direction:
+ case r_inputa_direction:
+ case r_err_and_out:
+ case r_input_output:
+ case r_output_force:
+ case r_duplicating_input_word:
+ case r_duplicating_output_word:
+ case r_move_input_word:
+ case r_move_output_word:
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+/* Expand the word in WORD returning a string. If WORD expands to
+ multiple words (or no words), then return NULL. */
+char *
+redirection_expand (word)
+ WORD_DESC *word;
+{
+ char *result;
+ WORD_LIST *tlist1, *tlist2;
+ WORD_DESC *w;
+
+ w = copy_word (word);
+ if (posixly_correct)
+ w->flags |= W_NOSPLIT;
+
+ tlist1 = make_word_list (w, (WORD_LIST *)NULL);
+ expanding_redir = 1;
+ tlist2 = expand_words_no_vars (tlist1);
+ expanding_redir = 0;
+ dispose_words (tlist1);
+
+ if (!tlist2 || tlist2->next)
+ {
+ /* We expanded to no words, or to more than a single word.
+ Dispose of the word list and return NULL. */
+ if (tlist2)
+ dispose_words (tlist2);
+ return ((char *)NULL);
+ }
+ result = string_list (tlist2); /* XXX savestring (tlist2->word->word)? */
+ dispose_words (tlist2);
+ return (result);
+}
+
+static int
+write_here_string (fd, redirectee)
+ int fd;
+ WORD_DESC *redirectee;
+{
+ char *herestr;
+ int herelen, n, e;
+
+ herestr = expand_string_to_string (redirectee->word, 0);
+ herelen = STRLEN (herestr);
+
+ n = write (fd, herestr, herelen);
+ if (n == herelen)
+ {
+ n = write (fd, "\n", 1);
+ herelen = 1;
+ }
+ e = errno;
+ FREE (herestr);
+ if (n != herelen)
+ {
+ if (e == 0)
+ e = ENOSPC;
+ return e;
+ }
+ return 0;
+}
+
+/* Write the text of the here document pointed to by REDIRECTEE to the file
+ descriptor FD, which is already open to a temp file. Return 0 if the
+ write is successful, otherwise return errno. */
+static int
+write_here_document (fd, redirectee)
+ int fd;
+ WORD_DESC *redirectee;
+{
+ char *document;
+ int document_len, fd2;
+ FILE *fp;
+ register WORD_LIST *t, *tlist;
+
+ /* Expand the text if the word that was specified had
+ no quoting. The text that we expand is treated
+ exactly as if it were surrounded by double quotes. */
+
+ if (redirectee->flags & W_QUOTED)
+ {
+ document = redirectee->word;
+ document_len = strlen (document);
+ /* Set errno to something reasonable if the write fails. */
+ if (write (fd, document, document_len) < document_len)
+ {
+ if (errno == 0)
+ errno = ENOSPC;
+ return (errno);
+ }
+ else
+ return 0;
+ }
+
+ tlist = expand_string (redirectee->word, Q_HERE_DOCUMENT);
+ if (tlist)
+ {
+ /* Try using buffered I/O (stdio) and writing a word
+ at a time, letting stdio do the work of buffering
+ for us rather than managing our own strings. Most
+ stdios are not particularly fast, however -- this
+ may need to be reconsidered later. */
+ if ((fd2 = dup (fd)) < 0 || (fp = fdopen (fd2, "w")) == NULL)
+ {
+ if (fd2 >= 0)
+ close (fd2);
+ return (errno);
+ }
+ errno = 0;
+ for (t = tlist; t; t = t->next)
+ {
+ /* This is essentially the body of
+ string_list_internal expanded inline. */
+ document = t->word->word;
+ document_len = strlen (document);
+ if (t != tlist)
+ putc (' ', fp); /* separator */
+ fwrite (document, document_len, 1, fp);
+ if (ferror (fp))
+ {
+ if (errno == 0)
+ errno = ENOSPC;
+ fd2 = errno;
+ fclose(fp);
+ dispose_words (tlist);
+ return (fd2);
+ }
+ }
+ dispose_words (tlist);
+ if (fclose (fp) != 0)
+ {
+ if (errno == 0)
+ errno = ENOSPC;
+ return (errno);
+ }
+ }
+ return 0;
+}
+
+/* Create a temporary file holding the text of the here document pointed to
+ by REDIRECTEE, and return a file descriptor open for reading to the temp
+ file. Return -1 on any error, and make sure errno is set appropriately. */
+static int
+here_document_to_fd (redirectee, ri)
+ WORD_DESC *redirectee;
+ enum r_instruction ri;
+{
+ char *filename;
+ int r, fd, fd2;
+
+ fd = sh_mktmpfd ("sh-thd", MT_USERANDOM, &filename);
+
+ /* If we failed for some reason other than the file existing, abort */
+ if (fd < 0)
+ {
+ FREE (filename);
+ return (fd);
+ }
+
+ errno = r = 0; /* XXX */
+ /* write_here_document returns 0 on success, errno on failure. */
+ if (redirectee->word)
+ r = (ri != r_reading_string) ? write_here_document (fd, redirectee)
+ : write_here_string (fd, redirectee);
+
+ if (r)
+ {
+ close (fd);
+ unlink (filename);
+ free (filename);
+ errno = r;
+ return (-1);
+ }
+
+ /* In an attempt to avoid races, we close the first fd only after opening
+ the second. */
+ /* Make the document really temporary. Also make it the input. */
+ fd2 = open (filename, O_RDONLY, 0600);
+
+ if (fd2 < 0)
+ {
+ r = errno;
+ unlink (filename);
+ free (filename);
+ close (fd);
+ errno = r;
+ return -1;
+ }
+
+ close (fd);
+ if (unlink (filename) < 0)
+ {
+ r = errno;
+#if defined (__CYGWIN__)
+ /* Under CygWin 1.1.0, the unlink will fail if the file is
+ open. This hack will allow the previous action of silently
+ ignoring the error, but will still leave the file there. This
+ needs some kind of magic. */
+ if (r == EACCES)
+ return (fd2);
+#endif /* __CYGWIN__ */
+ close (fd2);
+ free (filename);
+ errno = r;
+ return (-1);
+ }
+
+ free (filename);
+ return (fd2);
+}
+
+#define RF_DEVFD 1
+#define RF_DEVSTDERR 2
+#define RF_DEVSTDIN 3
+#define RF_DEVSTDOUT 4
+#define RF_DEVTCP 5
+#define RF_DEVUDP 6
+
+/* A list of pattern/value pairs for filenames that the redirection
+ code handles specially. */
+static STRING_INT_ALIST _redir_special_filenames[] = {
+#if !defined (HAVE_DEV_FD)
+ { "/dev/fd/[0-9]*", RF_DEVFD },
+#endif
+#if !defined (HAVE_DEV_STDIN)
+ { "/dev/stderr", RF_DEVSTDERR },
+ { "/dev/stdin", RF_DEVSTDIN },
+ { "/dev/stdout", RF_DEVSTDOUT },
+#endif
+#if defined (NETWORK_REDIRECTIONS)
+ { "/dev/tcp/*/*", RF_DEVTCP },
+ { "/dev/udp/*/*", RF_DEVUDP },
+#endif
+ { (char *)NULL, -1 }
+};
+
+static int
+redir_special_open (spec, filename, flags, mode, ri)
+ int spec;
+ char *filename;
+ int flags, mode;
+ enum r_instruction ri;
+{
+ int fd;
+#if !defined (HAVE_DEV_FD)
+ intmax_t lfd;
+#endif
+
+ fd = -1;
+ switch (spec)
+ {
+#if !defined (HAVE_DEV_FD)
+ case RF_DEVFD:
+ if (all_digits (filename+8) && legal_number (filename+8, &lfd) && lfd == (int)lfd)
+ {
+ fd = lfd;
+ fd = fcntl (fd, F_DUPFD, 10);
+ }
+ else
+ fd = AMBIGUOUS_REDIRECT;
+ break;
+#endif
+
+#if !defined (HAVE_DEV_STDIN)
+ case RF_DEVSTDIN:
+ fd = fcntl (0, F_DUPFD, 10);
+ break;
+ case RF_DEVSTDOUT:
+ fd = fcntl (1, F_DUPFD, 10);
+ break;
+ case RF_DEVSTDERR:
+ fd = fcntl (2, F_DUPFD, 10);
+ break;
+#endif
+
+#if defined (NETWORK_REDIRECTIONS)
+ case RF_DEVTCP:
+ case RF_DEVUDP:
+#if defined (HAVE_NETWORK)
+ fd = netopen (filename);
+#else
+ internal_warning (_("/dev/(tcp|udp)/host/port not supported without networking"));
+ fd = open (filename, flags, mode);
+#endif
+ break;
+#endif /* NETWORK_REDIRECTIONS */
+ }
+
+ return fd;
+}
+
+/* Open FILENAME with FLAGS in noclobber mode, hopefully avoiding most
+ race conditions and avoiding the problem where the file is replaced
+ between the stat(2) and open(2). */
+static int
+noclobber_open (filename, flags, mode, ri)
+ char *filename;
+ int flags, mode;
+ enum r_instruction ri;
+{
+ int r, fd;
+ struct stat finfo, finfo2;
+
+ /* If the file exists and is a regular file, return an error
+ immediately. */
+ r = stat (filename, &finfo);
+ if (r == 0 && (S_ISREG (finfo.st_mode)))
+ return (NOCLOBBER_REDIRECT);
+
+ /* If the file was not present (r != 0), make sure we open it
+ exclusively so that if it is created before we open it, our open
+ will fail. Make sure that we do not truncate an existing file.
+ Note that we don't turn on O_EXCL unless the stat failed -- if
+ the file was not a regular file, we leave O_EXCL off. */
+ flags &= ~O_TRUNC;
+ if (r != 0)
+ {
+ fd = open (filename, flags|O_EXCL, mode);
+ return ((fd < 0 && errno == EEXIST) ? NOCLOBBER_REDIRECT : fd);
+ }
+ fd = open (filename, flags, mode);
+
+ /* If the open failed, return the file descriptor right away. */
+ if (fd < 0)
+ return (errno == EEXIST ? NOCLOBBER_REDIRECT : fd);
+
+ /* OK, the open succeeded, but the file may have been changed from a
+ non-regular file to a regular file between the stat and the open.
+ We are assuming that the O_EXCL open handles the case where FILENAME
+ did not exist and is symlinked to an existing file between the stat
+ and open. */
+
+ /* If we can open it and fstat the file descriptor, and neither check
+ revealed that it was a regular file, and the file has not been replaced,
+ return the file descriptor. */
+ if ((fstat (fd, &finfo2) == 0) && (S_ISREG (finfo2.st_mode) == 0) &&
+ r == 0 && (S_ISREG (finfo.st_mode) == 0) &&
+ same_file (filename, filename, &finfo, &finfo2))
+ return fd;
+
+ /* The file has been replaced. badness. */
+ close (fd);
+ errno = EEXIST;
+ return (NOCLOBBER_REDIRECT);
+}
+
+static int
+redir_open (filename, flags, mode, ri)
+ char *filename;
+ int flags, mode;
+ enum r_instruction ri;
+{
+ int fd, r;
+
+ r = find_string_in_alist (filename, _redir_special_filenames, 1);
+ if (r >= 0)
+ return (redir_special_open (r, filename, flags, mode, ri));
+
+ /* If we are in noclobber mode, you are not allowed to overwrite
+ existing files. Check before opening. */
+ if (noclobber && CLOBBERING_REDIRECT (ri))
+ {
+ fd = noclobber_open (filename, flags, mode, ri);
+ if (fd == NOCLOBBER_REDIRECT)
+ return (NOCLOBBER_REDIRECT);
+ }
+ else
+ {
+ fd = open (filename, flags, mode);
+#if defined (AFS)
+ if ((fd < 0) && (errno == EACCES))
+ fd = open (filename, flags & ~O_CREAT, mode);
+#endif /* AFS */
+ }
+
+ return fd;
+}
+
+/* Do the specific redirection requested. Returns errno or one of the
+ special redirection errors (*_REDIRECT) in case of error, 0 on success.
+ If flags & RX_ACTIVE is zero, then just do whatever is neccessary to
+ produce the appropriate side effects. flags & RX_UNDOABLE, if non-zero,
+ says to remember how to undo each redirection. If flags & RX_CLEXEC is
+ non-zero, then we set all file descriptors > 2 that we open to be
+ close-on-exec. */
+static int
+do_redirection_internal (redirect, flags)
+ REDIRECT *redirect;
+ int flags;
+{
+ WORD_DESC *redirectee;
+ int redir_fd, fd, redirector, r, oflags;
+ intmax_t lfd;
+ char *redirectee_word;
+ enum r_instruction ri;
+ REDIRECT *new_redirect;
+
+ redirectee = redirect->redirectee.filename;
+ redir_fd = redirect->redirectee.dest;
+ redirector = redirect->redirector;
+ ri = redirect->instruction;
+
+ if (TRANSLATE_REDIRECT (ri))
+ {
+ /* We have [N]>&WORD[-] or [N]<&WORD[-]. Expand WORD, then translate
+ the redirection into a new one and continue. */
+ redirectee_word = redirection_expand (redirectee);
+
+ /* XXX - what to do with [N]<&$w- where w is unset or null? ksh93
+ closes N. */
+ if (redirectee_word == 0)
+ return (AMBIGUOUS_REDIRECT);
+ else if (redirectee_word[0] == '-' && redirectee_word[1] == '\0')
+ {
+ rd.dest = 0;
+ new_redirect = make_redirection (redirector, r_close_this, rd);
+ }
+ else if (all_digits (redirectee_word))
+ {
+ if (legal_number (redirectee_word, &lfd) && (int)lfd == lfd)
+ rd.dest = lfd;
+ else
+ rd.dest = -1; /* XXX */
+ switch (ri)
+ {
+ case r_duplicating_input_word:
+ new_redirect = make_redirection (redirector, r_duplicating_input, rd);
+ break;
+ case r_duplicating_output_word:
+ new_redirect = make_redirection (redirector, r_duplicating_output, rd);
+ break;
+ case r_move_input_word:
+ new_redirect = make_redirection (redirector, r_move_input, rd);
+ break;
+ case r_move_output_word:
+ new_redirect = make_redirection (redirector, r_move_output, rd);
+ break;
+ }
+ }
+ else if (ri == r_duplicating_output_word && redirector == 1)
+ {
+ rd.filename = make_bare_word (redirectee_word);
+ new_redirect = make_redirection (1, r_err_and_out, rd);
+ }
+ else
+ {
+ free (redirectee_word);
+ return (AMBIGUOUS_REDIRECT);
+ }
+
+ free (redirectee_word);
+
+ /* Set up the variables needed by the rest of the function from the
+ new redirection. */
+ if (new_redirect->instruction == r_err_and_out)
+ {
+ char *alloca_hack;
+
+ /* Copy the word without allocating any memory that must be
+ explicitly freed. */
+ redirectee = (WORD_DESC *)alloca (sizeof (WORD_DESC));
+ xbcopy ((char *)new_redirect->redirectee.filename,
+ (char *)redirectee, sizeof (WORD_DESC));
+
+ alloca_hack = (char *)
+ alloca (1 + strlen (new_redirect->redirectee.filename->word));
+ redirectee->word = alloca_hack;
+ strcpy (redirectee->word, new_redirect->redirectee.filename->word);
+ }
+ else
+ /* It's guaranteed to be an integer, and shouldn't be freed. */
+ redirectee = new_redirect->redirectee.filename;
+
+ redir_fd = new_redirect->redirectee.dest;
+ redirector = new_redirect->redirector;
+ ri = new_redirect->instruction;
+
+ /* Overwrite the flags element of the old redirect with the new value. */
+ redirect->flags = new_redirect->flags;
+ dispose_redirects (new_redirect);
+ }
+
+ switch (ri)
+ {
+ case r_output_direction:
+ case r_appending_to:
+ case r_input_direction:
+ case r_inputa_direction:
+ case r_err_and_out: /* command &>filename */
+ case r_input_output:
+ case r_output_force:
+ if (posixly_correct && interactive_shell == 0)
+ {
+ oflags = redirectee->flags;
+ redirectee->flags |= W_NOGLOB;
+ }
+ redirectee_word = redirection_expand (redirectee);
+ if (posixly_correct && interactive_shell == 0)
+ redirectee->flags = oflags;
+
+ if (redirectee_word == 0)
+ return (AMBIGUOUS_REDIRECT);
+
+#if defined (RESTRICTED_SHELL)
+ if (restricted && (WRITE_REDIRECT (ri)))
+ {
+ free (redirectee_word);
+ return (RESTRICTED_REDIRECT);
+ }
+#endif /* RESTRICTED_SHELL */
+
+ fd = redir_open (redirectee_word, redirect->flags, 0666, ri);
+ free (redirectee_word);
+
+ if (fd == NOCLOBBER_REDIRECT)
+ return (fd);
+
+ if (fd < 0)
+ return (errno);
+
+ if (flags & RX_ACTIVE)
+ {
+ if (flags & RX_UNDOABLE)
+ {
+ /* Only setup to undo it if the thing to undo is active. */
+ if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1))
+ add_undo_redirect (redirector);
+ else
+ add_undo_close_redirect (redirector);
+ }
+
+#if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+#endif
+
+ if ((fd != redirector) && (dup2 (fd, redirector) < 0))
+ return (errno);
+
+#if defined (BUFFERED_INPUT)
+ /* Do not change the buffered stream for an implicit redirection
+ of /dev/null to fd 0 for asynchronous commands without job
+ control (r_inputa_direction). */
+ if (ri == r_input_direction || ri == r_input_output)
+ duplicate_buffered_stream (fd, redirector);
+#endif /* BUFFERED_INPUT */
+
+ /*
+ * If we're remembering, then this is the result of a while, for
+ * or until loop with a loop redirection, or a function/builtin
+ * executing in the parent shell with a redirection. In the
+ * function/builtin case, we want to set all file descriptors > 2
+ * to be close-on-exec to duplicate the effect of the old
+ * for i = 3 to NOFILE close(i) loop. In the case of the loops,
+ * both sh and ksh leave the file descriptors open across execs.
+ * The Posix standard mentions only the exec builtin.
+ */
+ if ((flags & RX_CLEXEC) && (redirector > 2))
+ SET_CLOSE_ON_EXEC (redirector);
+ }
+
+ if (fd != redirector)
+ {
+#if defined (BUFFERED_INPUT)
+ if (INPUT_REDIRECT (ri))
+ close_buffered_fd (fd);
+ else
+#endif /* !BUFFERED_INPUT */
+ close (fd); /* Don't close what we just opened! */
+ }
+
+ /* If we are hacking both stdout and stderr, do the stderr
+ redirection here. */
+ if (ri == r_err_and_out)
+ {
+ if (flags & RX_ACTIVE)
+ {
+ if (flags & RX_UNDOABLE)
+ add_undo_redirect (2);
+ if (dup2 (1, 2) < 0)
+ return (errno);
+ }
+ }
+ break;
+
+ case r_reading_until:
+ case r_deblank_reading_until:
+ case r_reading_string:
+ /* REDIRECTEE is a pointer to a WORD_DESC containing the text of
+ the new input. Place it in a temporary file. */
+ if (redirectee)
+ {
+ fd = here_document_to_fd (redirectee, ri);
+
+ if (fd < 0)
+ {
+ heredoc_errno = errno;
+ return (HEREDOC_REDIRECT);
+ }
+
+ if (flags & RX_ACTIVE)
+ {
+ if (flags & RX_UNDOABLE)
+ {
+ /* Only setup to undo it if the thing to undo is active. */
+ if ((fd != redirector) && (fcntl (redirector, F_GETFD, 0) != -1))
+ add_undo_redirect (redirector);
+ else
+ add_undo_close_redirect (redirector);
+ }
+
+#if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+#endif
+ if (fd != redirector && dup2 (fd, redirector) < 0)
+ {
+ r = errno;
+ close (fd);
+ return (r);
+ }
+
+#if defined (BUFFERED_INPUT)
+ duplicate_buffered_stream (fd, redirector);
+#endif
+
+ if ((flags & RX_CLEXEC) && (redirector > 2))
+ SET_CLOSE_ON_EXEC (redirector);
+ }
+
+ if (fd != redirector)
+#if defined (BUFFERED_INPUT)
+ close_buffered_fd (fd);
+#else
+ close (fd);
+#endif
+ }
+ break;
+
+ case r_duplicating_input:
+ case r_duplicating_output:
+ case r_move_input:
+ case r_move_output:
+ if ((flags & RX_ACTIVE) && (redir_fd != redirector))
+ {
+ if (flags & RX_UNDOABLE)
+ {
+ /* Only setup to undo it if the thing to undo is active. */
+ if (fcntl (redirector, F_GETFD, 0) != -1)
+ add_undo_redirect (redirector);
+ else
+ add_undo_close_redirect (redirector);
+ }
+
+#if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+#endif
+ /* This is correct. 2>&1 means dup2 (1, 2); */
+ if (dup2 (redir_fd, redirector) < 0)
+ return (errno);
+
+#if defined (BUFFERED_INPUT)
+ if (ri == r_duplicating_input || ri == r_move_input)
+ duplicate_buffered_stream (redir_fd, redirector);
+#endif /* BUFFERED_INPUT */
+
+ /* First duplicate the close-on-exec state of redirectee. dup2
+ leaves the flag unset on the new descriptor, which means it
+ stays open. Only set the close-on-exec bit for file descriptors
+ greater than 2 in any case, since 0-2 should always be open
+ unless closed by something like `exec 2<&-'. */
+ /* if ((already_set || set_unconditionally) && (ok_to_set))
+ set_it () */
+ if (((fcntl (redir_fd, F_GETFD, 0) == 1) || (flags & RX_CLEXEC)) &&
+ (redirector > 2))
+ SET_CLOSE_ON_EXEC (redirector);
+
+ /* dup-and-close redirection */
+ if (ri == r_move_input || ri == r_move_output)
+ close (redir_fd);
+ }
+ break;
+
+ case r_close_this:
+ if (flags & RX_ACTIVE)
+ {
+ if ((flags & RX_UNDOABLE) && (fcntl (redirector, F_GETFD, 0) != -1))
+ add_undo_redirect (redirector);
+
+#if defined (BUFFERED_INPUT)
+ check_bash_input (redirector);
+ close_buffered_fd (redirector);
+#else /* !BUFFERED_INPUT */
+ close (redirector);
+#endif /* !BUFFERED_INPUT */
+ }
+ break;
+
+ case r_duplicating_input_word:
+ case r_duplicating_output_word:
+ break;
+ }
+ return (0);
+}
+
+#define SHELL_FD_BASE 10
+
+/* Remember the file descriptor associated with the slot FD,
+ on REDIRECTION_UNDO_LIST. Note that the list will be reversed
+ before it is executed. Any redirections that need to be undone
+ even if REDIRECTION_UNDO_LIST is discarded by the exec builtin
+ are also saved on EXEC_REDIRECTION_UNDO_LIST. */
+static int
+add_undo_redirect (fd)
+ int fd;
+{
+ int new_fd, clexec_flag;
+ REDIRECT *new_redirect, *closer, *dummy_redirect;
+
+ new_fd = fcntl (fd, F_DUPFD, SHELL_FD_BASE);
+ if (new_fd < 0)
+ {
+ sys_error (_("redirection error: cannot duplicate fd"));
+ return (-1);
+ }
+
+ clexec_flag = fcntl (fd, F_GETFD, 0);
+
+ rd.dest = 0;
+ closer = make_redirection (new_fd, r_close_this, rd);
+ dummy_redirect = copy_redirects (closer);
+
+ rd.dest = new_fd;
+ if (fd == 0)
+ new_redirect = make_redirection (fd, r_duplicating_input, rd);
+ else
+ new_redirect = make_redirection (fd, r_duplicating_output, rd);
+ new_redirect->next = closer;
+
+ closer->next = redirection_undo_list;
+ redirection_undo_list = new_redirect;
+
+ /* Save redirections that need to be undone even if the undo list
+ is thrown away by the `exec' builtin. */
+ add_exec_redirect (dummy_redirect);
+
+ /* experimental: if we're saving a redirection to undo for a file descriptor
+ above SHELL_FD_BASE, add a redirection to be undone if the exec builtin
+ causes redirections to be discarded. */
+ if (fd >= SHELL_FD_BASE)
+ {
+ rd.dest = new_fd;
+ new_redirect = make_redirection (fd, r_duplicating_output, rd);
+#if 0
+ closer = copy_redirects (new_redirect);
+ add_exec_redirect (closer);
+#else
+ add_exec_redirect (new_redirect);
+#endif
+ }
+
+ /* File descriptors used only for saving others should always be
+ marked close-on-exec. Unfortunately, we have to preserve the
+ close-on-exec state of the file descriptor we are saving, since
+ fcntl (F_DUPFD) sets the new file descriptor to remain open
+ across execs. If, however, the file descriptor whose state we
+ are saving is <= 2, we can just set the close-on-exec flag,
+ because file descriptors 0-2 should always be open-on-exec,
+ and the restore above in do_redirection() will take care of it. */
+ if (clexec_flag || fd < 3)
+ SET_CLOSE_ON_EXEC (new_fd);
+
+ return (0);
+}
+
+/* Set up to close FD when we are finished with the current command
+ and its redirections. */
+static void
+add_undo_close_redirect (fd)
+ int fd;
+{
+ REDIRECT *closer;
+
+ rd.dest = 0;
+ closer = make_redirection (fd, r_close_this, rd);
+ closer->next = redirection_undo_list;
+ redirection_undo_list = closer;
+}
+
+static void
+add_exec_redirect (dummy_redirect)
+ REDIRECT *dummy_redirect;
+{
+ dummy_redirect->next = exec_redirection_undo_list;
+ exec_redirection_undo_list = dummy_redirect;
+}
+
+/* Return 1 if the redirection specified by RI and REDIRECTOR alters the
+ standard input. */
+static int
+stdin_redirection (ri, redirector)
+ enum r_instruction ri;
+ int redirector;
+{
+ switch (ri)
+ {
+ case r_input_direction:
+ case r_inputa_direction:
+ case r_input_output:
+ case r_reading_until:
+ case r_deblank_reading_until:
+ case r_reading_string:
+ return (1);
+ case r_duplicating_input:
+ case r_duplicating_input_word:
+ case r_close_this:
+ return (redirector == 0);
+ case r_output_direction:
+ case r_appending_to:
+ case r_duplicating_output:
+ case r_err_and_out:
+ case r_output_force:
+ case r_duplicating_output_word:
+ return (0);
+ }
+ return (0);
+}
+
+/* Return non-zero if any of the redirections in REDIRS alter the standard
+ input. */
+int
+stdin_redirects (redirs)
+ REDIRECT *redirs;
+{
+ REDIRECT *rp;
+ int n;
+
+ for (n = 0, rp = redirs; rp; rp = rp->next)
+ n += stdin_redirection (rp->instruction, rp->redirector);
+ return n;
+}
char *string;
int quoted;
{
- pid_t pid, old_pid, old_pipeline_pgrp;
+ pid_t pid, old_pid, old_pipeline_pgrp, old_async_pid;
char *istring;
int result, fildes[2], function_value, pflags, rc;
cleanup_the_pipeline ();
#endif
+ old_async_pid = last_asynchronous_pid;
+#if 0
pid = make_child ((char *)NULL, 0);
+#else
+ pid = make_child ((char *)NULL, subshell_environment&SUBSHELL_ASYNC);
+#endif
+ last_asynchronous_pid = old_async_pid;
+
if (pid == 0)
/* Reset the signal handlers in the child, but don't free the
trap strings. */
SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
;;
-
+
+sysv5UnixWare*-*gcc*)
+ SHOBJ_CFLAGS=-fpic
+ SHOBJ_LD='${CC}'
+ SHOBJ_LDFLAGS='-shared'
+
+ SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
+ ;;
+
+sysv5UnixWare*)
+ SHOBJ_CFLAGS='-K PIC'
+ SHOBJ_LD=ld
+ SHOBJ_LDFLAGS='-G -dy -z text -h $@'
+
+ SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
+ ;;
+
+sysv5OpenUNIX*-*gcc*)
+ SHOBJ_CFLAGS=-fpic
+ SHOBJ_LD='${CC}'
+ SHOBJ_LDFLAGS='-shared'
+
+ SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
+ ;;
+
+sysv5OpenUNIX*)
+ SHOBJ_CFLAGS='-K PIC'
+ SHOBJ_LD=ld
+ SHOBJ_LDFLAGS='-G -dy -z text -h $@'
+
+ SHLIB_LIBVERSION='$(SHLIB_LIBSUFF).$(SHLIB_MAJOR)'
+ ;;
+
dgux*-*gcc*)
SHOBJ_CFLAGS=-fpic
SHOBJ_LD='${CC}'
-BUILD_DIR=/usr/local/build/bash/bash-current
+BUILD_DIR=/usr/local/build/chet/bash/bash-current
THIS_SH=$BUILD_DIR/bash
PATH=$PATH:$BUILD_DIR
-${THIS_SH} ./tilde-tests > /tmp/xx
+${THIS_SH} ./tilde.tests > /tmp/xx
diff /tmp/xx tilde.right && rm -f /tmp/xx