From cac4cdbf5eef54205da23ae1426f9ea3fc05aee6 Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Sat, 3 Dec 2011 13:37:49 -0500 Subject: [PATCH] commit bash-20041007 snapshot --- CWRU/CWRU.chlog | 37 ++ CWRU/CWRU.chlog~ | 38 ++ MANIFEST | 8 +- aclocal.m4 | 33 ++ aclocal.m4~ | 42 +- autom4te.cache/output.0 | 76 ++- autom4te.cache/requests | 152 +++--- autom4te.cache/traces.0 | 101 ++-- config.h.in | 4 +- configure | 76 ++- configure.in | 4 +- configure.in~ | 8 +- doc/bash.1 | 4 + doc/bash.1~ | 6 +- doc/bashref.texi | 4 + doc/bashref.texi~ | 2 +- doc/version.texi | 4 +- doc/version.texi~ | 8 +- execute_cmd.c~ | 27 +- input.c~ | 614 ++++++++++++++++++++++ redir.c | 15 + redir.c~ | 1066 +++++++++++++++++++++++++++++++++++++++ subst.c | 9 +- support/shobj-conf | 34 +- tests/RUN-ONE-TEST | 2 +- tests/run-tilde | 2 +- 26 files changed, 2207 insertions(+), 169 deletions(-) create mode 100644 input.c~ create mode 100644 redir.c~ diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 5f7aeddfd..566fd9f41 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -10281,3 +10281,40 @@ lib/readline/complete.c 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 + +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 + + 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 diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 17f6c575d..ed0deeef1 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -10275,3 +10275,41 @@ doc/{bash.1,bashref.texi} 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 + +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 + + 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 diff --git a/MANIFEST b/MANIFEST index 398d522df..2985f5402 100644 --- a/MANIFEST +++ b/MANIFEST @@ -731,6 +731,8 @@ tests/extglob.tests f 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 @@ -840,6 +842,7 @@ tests/run-execscript 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 @@ -873,6 +876,7 @@ tests/run-shopt 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 @@ -886,8 +890,10 @@ tests/strip.tests 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 diff --git a/aclocal.m4 b/aclocal.m4 index 30d9b8131..bfcd5970c 100644 --- a/aclocal.m4 +++ b/aclocal.m4 @@ -1859,6 +1859,39 @@ AC_DEFINE(CTYPE_NON_ASCII) 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 +#include +#include +#include + +#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 diff --git a/aclocal.m4~ b/aclocal.m4~ index 9d2ed5442..8ca532982 100644 --- a/aclocal.m4~ +++ b/aclocal.m4~ @@ -1541,7 +1541,14 @@ AC_DEFUN(BASH_CHECK_DEV_FD, [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 @@ -1852,6 +1859,39 @@ AC_DEFINE(CTYPE_NON_ASCII) 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 +#include +#include +#include + +#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 diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 index fa2b495fa..798e4cc07 100644 --- a/autom4te.cache/output.0 +++ b/autom4te.cache/output.0 @@ -1,5 +1,5 @@ @%:@! /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. @%:@ @@ -23202,6 +23202,80 @@ _ACEOF 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 +#include +#include +#include + +#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 diff --git a/autom4te.cache/requests b/autom4te.cache/requests index 6ac24b719..462f649d8 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -15,96 +15,96 @@ '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' ) ); diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 index 2aa1b3fab..9d125d4a9 100644 --- a/autom4te.cache/traces.0 +++ b/autom4te.cache/traces.0 @@ -1122,64 +1122,65 @@ m4trace:configure.in:859: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 i #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]) diff --git a/config.h.in b/config.h.in index 8e3e4569f..3bfc4624c 100644 --- a/config.h.in +++ b/config.h.in @@ -386,7 +386,6 @@ #undef HAVE_LIBC_FNM_EXTMATCH - #undef HAVE_DECL_CONFSTR #undef HAVE_DECL_PRINTF @@ -403,6 +402,9 @@ #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 diff --git a/configure b/configure index 5910defe6..6b689cd27 100755 --- a/configure +++ b/configure @@ -1,5 +1,5 @@ #! /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. # @@ -23202,6 +23202,80 @@ _ACEOF 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 +#include +#include +#include + +#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 diff --git a/configure.in b/configure.in index d1fc8048a..19dfe611c 100644 --- a/configure.in +++ b/configure.in @@ -22,7 +22,7 @@ dnl Process this file with autoconf to produce a configure script. # 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) @@ -860,6 +860,8 @@ AC_HEADER_TIOCGWINSZ BASH_HAVE_TIOCSTAT BASH_HAVE_FIONREAD +BASH_CHECK_WCONTINUED + dnl miscellaneous BASH_CHECK_SPEED_T BASH_CHECK_GETPW_FUNCS diff --git a/configure.in~ b/configure.in~ index 55c8a5c75..d1fc8048a 100644 --- a/configure.in~ +++ b/configure.in~ @@ -22,10 +22,10 @@ dnl Process this file with autoconf to produce a configure script. # 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) @@ -646,7 +646,7 @@ AC_CHECK_FUNCS(bcopy bzero confstr sysconf pathconf setenv putenv unsetenv \ 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]) diff --git a/doc/bash.1 b/doc/bash.1 index e0d7f797b..7eba6f08f 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -2950,6 +2950,10 @@ a UDP connection to the corresponding socket. .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 diff --git a/doc/bash.1~ b/doc/bash.1~ index e95567fa6..e0d7f797b 100644 --- a/doc/bash.1~ +++ b/doc/bash.1~ @@ -6,12 +6,12 @@ .\" 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. @@ -2853,7 +2853,7 @@ Matches zero or more occurrences of the given patterns 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 diff --git a/doc/bashref.texi b/doc/bashref.texi index 9df7ead7b..94814d676 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -2017,6 +2017,10 @@ connection to the corresponding socket. 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} diff --git a/doc/bashref.texi~ b/doc/bashref.texi~ index 1e0e446da..9df7ead7b 100644 --- a/doc/bashref.texi~ +++ b/doc/bashref.texi~ @@ -1931,7 +1931,7 @@ Matches zero or more occurrences of the given patterns. 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. diff --git a/doc/version.texi b/doc/version.texi index af20a424a..fe49140e2 100644 --- a/doc/version.texi +++ b/doc/version.texi @@ -4,7 +4,7 @@ Copyright (C) 1988-2004 Free Software Foundation, Inc. @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 diff --git a/doc/version.texi~ b/doc/version.texi~ index 9dd2c46a0..74cf713d6 100644 --- a/doc/version.texi~ +++ b/doc/version.texi~ @@ -2,9 +2,9 @@ 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 diff --git a/execute_cmd.c~ b/execute_cmd.c~ index cea110aba..968f23454 100644 --- a/execute_cmd.c~ +++ b/execute_cmd.c~ @@ -160,7 +160,7 @@ static int execute_while_command __P((WHILE_COM *)); 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)); @@ -491,7 +491,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, { 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) @@ -648,7 +647,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* 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) @@ -678,7 +677,7 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, /* 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); @@ -698,14 +697,6 @@ execute_command_internal (command, asynchronous, pipe_in, pipe_out, 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 } } @@ -2583,10 +2574,9 @@ bind_lastarg (arg) 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; @@ -2632,7 +2622,7 @@ execute_null_command (redirects, pipe_in, pipe_out, async, old_last_command_subs 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); @@ -2680,7 +2670,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) 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; @@ -2715,7 +2705,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) 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; @@ -2809,8 +2799,7 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close) 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 diff --git a/input.c~ b/input.c~ new file mode 100644 index 000000000..9ada733c5 --- /dev/null +++ b/input.c~ @@ -0,0 +1,614 @@ +/* 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 +#endif +#include "filecntl.h" +#include "posixstat.h" +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#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 3b_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 */ diff --git a/redir.c b/redir.c index 228d67ebb..3ee44ca96 100644 --- a/redir.c +++ b/redir.c @@ -970,6 +970,21 @@ add_undo_redirect (fd) 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 diff --git a/redir.c~ b/redir.c~ new file mode 100644 index 000000000..8b587767f --- /dev/null +++ b/redir.c~ @@ -0,0 +1,1066 @@ +/* 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 +#include "bashtypes.h" +#if !defined (_MINIX) && defined (HAVE_SYS_FILE_H) +# include +#endif +#include "filecntl.h" +#include "posixstat.h" + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#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; +} diff --git a/subst.c b/subst.c index 1372bf804..85393c653 100644 --- a/subst.c +++ b/subst.c @@ -4351,7 +4351,7 @@ command_substitute (string, quoted) 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; @@ -4399,7 +4399,14 @@ command_substitute (string, quoted) 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. */ diff --git a/support/shobj-conf b/support/shobj-conf index 4c1371708..5b5c81c38 100755 --- a/support/shobj-conf +++ b/support/shobj-conf @@ -408,7 +408,39 @@ sysv5uw7*) 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}' diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index 72ec06a2c..3efcf32d6 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -1,4 +1,4 @@ -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 diff --git a/tests/run-tilde b/tests/run-tilde index ecb7e9a25..b8569c11c 100644 --- a/tests/run-tilde +++ b/tests/run-tilde @@ -1,2 +1,2 @@ -${THIS_SH} ./tilde-tests > /tmp/xx +${THIS_SH} ./tilde.tests > /tmp/xx diff /tmp/xx tilde.right && rm -f /tmp/xx -- 2.47.3