commit bash-20050127 snapshot

This commit is contained in:
Chet Ramey
2011-12-03 13:42:58 -05:00
parent 3de8929be1
commit 10590446d1
43 changed files with 11636 additions and 1112 deletions
+75
View File
@@ -10901,3 +10901,78 @@ variables.c
generator only gets re-seeded once in a subshell environment, and
assigning a value to RANDOM counts as seeding the generator. This
makes the sequences a little more predictable
1/20
----
lib/readline/history.c
- fix replace_history_entry, remove_history to return NULL if
passed index is < 0
1/22
----
lib/sh/netconn.c
- fix isnetconn() to understand that getpeername can return ENOTCONN
to indicate that an fd is not a socket
configure.in
- set BUILD_DIR to contain backslashes to escape any spaces in the
directory name -- this is what make will accept in targets and
prerequisites, so it's better than trying to use double quotes
- set SIZE to the appropriate value if some cross-compiling tool
chain is being used; `size' by default (can be overridden by
SIZE environment variable)
Makefile.in
- use $(SIZE) instead of size; set SIZE from configure
2/1
---
jobs.h
- new struct to hold stats and counters for child processes and jobs
- change some uses of global and static variables to use members of
new struct (struct jobstats)
2/2
---
jobs.[ch]
- change PRUNNING to PALIVE
- new define INVALID_JOB
- new macro get_job_by_jid(ind), currently expands to jobs[ind]
- new define J_JOBSTATE, operates on a JOB * like JOBSTATE operates on
a job index
- new function, reset_job_indices, called from delete_job if
js.j_lastj or js.j_firstj are removed
pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- change global variables (e.g., job_slots) to struct members
(e.g., js.j_jobslots)
- use INVALID_JOB define where appropriate
- use get_job_by_jid and J_JOBSTATE where appropriate
trap.c
- change reset_or_restore_signal_handler to not free the trap
string if the function pointer is reset_signal, which is used when
the trap strings shouldn't be freed, like in command substitution
2/4
---
jobs.c
- new function, realloc_jobs_list, copies jobs array to newly-allocated
memory shrinking (or growing) size to have next multiple of JOB_SLOTS
greater than js.j_njobs
- change compact_jobs_list to just call reap_dead_jobs and then
realloc_jobs_list, simplifying it considerably
- discard_pipeline now returns `int': the number of processes freed
- slightly changed the logic deciding whether or not to call
compact_jobs_list: now non-interactive shells will compact the
list if it reaches MAX_JOBS_IN_ARRAY in size
parse.y
- move test for backslash-newline after pop_string in shell_getc so
that things like
((echo 5) \
(echo 6))
work right
+81
View File
@@ -10895,3 +10895,84 @@ tests/iquote.tests
dispose_cmd.c
- set w->word to 0 before putting a WORD_DESC * back in the cache in
dispose_word_desc; changed callers to delete those assignments
variables.c
- change assign_random and get_random_value so that the random number
generator only gets re-seeded once in a subshell environment, and
assigning a value to RANDOM counts as seeding the generator. This
makes the sequences a little more predictable
1/20
----
lib/readline/history.c
- fix replace_history_entry, remove_history to return NULL if
passed index is < 0
1/22
----
lib/sh/netconn.c
- fix isnetconn() to understand that getpeername can return ENOTCONN
to indicate that an fd is not a socket
configure.in
- set BUILD_DIR to contain backslashes to escape any spaces in the
directory name -- this is what make will accept in targets and
prerequisites, so it's better than trying to use double quotes
- set SIZE to the appropriate value if some cross-compiling tool
chain is being used; `size' by default (can be overridden by
SIZE environment variable)
Makefile.in
- use $(SIZE) instead of size; set SIZE from configure
2/1
---
jobs.h
- new struct to hold stats and counters for child processes and jobs
- change some uses of global and static variables to use members of
new struct (struct jobstats)
2/2
---
jobs.[ch]
- change PRUNNING to PALIVE
- new define INVALID_JOB
- new macro get_job_by_jid(ind), currently expands to jobs[ind]
- new define J_JOBSTATE, operates on a JOB * like JOBSTATE operates on
a job index
- new function, reset_job_indices, called from delete_job if
js.j_lastj or js.j_firstj are removed
pcomplete.c, builtins/common.c, builtins/{exit,fg_bg,jobs,kill,wait}.def
- change global variables (e.g., job_slots) to struct members
(e.g., js.j_jobslots)
- use INVALID_JOB define where appropriate
- use get_job_by_jid and J_JOBSTATE where appropriate
trap.c
- change reset_or_restore_signal_handler to not free the trap
string if the function pointer is reset_signal, which is used when
the trap strings shouldn't be freed, like in command substitution
2/4
---
jobs.c
- new function, realloc_jobs_list, copies jobs array to newly-allocated
memory shrinking (or growing) size to have next multiple of JOB_SLOTS
greater than js.j_njobs
- change compact_jobs_list to just call reap_dead_jobs and then
realloc_jobs_list, simplifying it considerably
- discard_pipeline now returns `int': the number of processes freed
- slightly changed the logic deciding whether or not to call
compact_jobs_list: now non-interactive shells will compact the
list if it reaches MAX_JOBS_IN_ARRAY in size
parse.y
- move test for backslash-newline after pop_string in read_token so
that things like
((echo 5) \
(echo 6))
work right
+5 -4
View File
@@ -1,6 +1,6 @@
# Makefile for bash-3.0, version 2.154
# Makefile for bash-3.0, version 2.155
#
# Copyright (C) 1996-2004 Free Software Foundation, Inc.
# Copyright (C) 1996-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -67,6 +67,7 @@ RM = rm -f
AR = @AR@
ARFLAGS = @ARFLAGS@
RANLIB = @RANLIB@
SIZE = @SIZE@
INSTALL = @INSTALL@
INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -514,7 +515,7 @@ $(Program): .build $(OBJECTS) $(BUILTINS_DEP) $(LIBDEP)
$(RM) $@
$(PURIFY) $(CC) $(BUILTINS_LDFLAGS) $(LIBRARY_LDFLAGS) $(LDFLAGS) -o $(Program) $(OBJECTS) $(LIBS)
ls -l $(Program)
-size $(Program)
-$(SIZE) $(Program)
.build: $(SOURCES) config.h Makefile version.h $(VERSPROG)
@echo
@@ -536,7 +537,7 @@ bashbug: $(SUPPORT_SRC)bashbug.sh config.h Makefile $(VERSPROG)
strip: $(Program) .made
strip $(Program)
ls -l $(Program)
-size $(Program)
-$(SIZE) $(Program)
lint:
${MAKE} ${MFLAGS} CFLAGS='${GCC_LINT_FLAGS}' .made
+1 -1
View File
@@ -708,7 +708,7 @@ array_value_internal (s, quoted, allow_all, rtype)
err_badarraysub (s);
return ((char *)NULL);
}
else if (var == 0)
else if (var == 0 || value_cell (var) == 0)
return ((char *)NULL);
else if (array_p (var) == 0)
l = add_string_to_list (value_cell (var), (WORD_LIST *)NULL);
+28 -2
View File
@@ -1,5 +1,5 @@
@%:@! /bin/sh
@%:@ From configure.in for Bash 3.0, version 3.172, from autoconf version AC_ACVERSION.
@%:@ From configure.in for Bash 3.1, version 3.173, 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.
@%:@
@@ -311,7 +311,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os EMACS lispdir DEBUGGER_START_FILE TESTSCRIPT PURIFY MALLOC_TARGET MALLOC_SRC MALLOC_LIB MALLOC_LIBRARY MALLOC_LDFLAGS MALLOC_DEP htmldir HELPDIR HELPDIRDEFINE HELPINSTALL HELPSTRINGS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP SIGNAMES_H CC_FOR_BUILD STATIC_LD CFLAGS_FOR_BUILD CPPFLAGS_FOR_BUILD LDFLAGS_FOR_BUILD RL_VERSION RL_MAJOR RL_MINOR READLINE_LIB READLINE_DEP RL_LIBDIR RL_INCLUDEDIR RL_INCLUDE HISTORY_LIB HISTORY_DEP HIST_LIBDIR INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR RANLIB ac_ct_RANLIB YACC SET_MAKE MAKE_SHELL MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE ALLOCA GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIB@&t@OBJS INTL_DEP INTL_INC LIBINTL_H SIGLIST_O TERMCAP_LIB TERMCAP_DEP JOBS_O SHOBJ_CC SHOBJ_CFLAGS SHOBJ_LD SHOBJ_LDFLAGS SHOBJ_XLDFLAGS SHOBJ_LIBS SHOBJ_STATUS PROFILE_FLAGS incdir BUILD_DIR ARFLAGS BASHVERS RELSTATUS DEBUG MALLOC_DEBUG LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os EMACS lispdir DEBUGGER_START_FILE TESTSCRIPT PURIFY MALLOC_TARGET MALLOC_SRC MALLOC_LIB MALLOC_LIBRARY MALLOC_LDFLAGS MALLOC_DEP htmldir HELPDIR HELPDIRDEFINE HELPINSTALL HELPSTRINGS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP SIGNAMES_H CC_FOR_BUILD STATIC_LD CFLAGS_FOR_BUILD CPPFLAGS_FOR_BUILD LDFLAGS_FOR_BUILD RL_VERSION RL_MAJOR RL_MINOR READLINE_LIB READLINE_DEP RL_LIBDIR RL_INCLUDEDIR RL_INCLUDE HISTORY_LIB HISTORY_DEP HIST_LIBDIR INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR RANLIB ac_ct_RANLIB YACC SET_MAKE MAKE_SHELL SIZE MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE ALLOCA GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIB@&t@OBJS INTL_DEP INTL_INC LIBINTL_H SIGLIST_O TERMCAP_LIB TERMCAP_DEP JOBS_O SHOBJ_CC SHOBJ_CFLAGS SHOBJ_LD SHOBJ_LDFLAGS SHOBJ_XLDFLAGS SHOBJ_LIBS SHOBJ_STATUS PROFILE_FLAGS incdir BUILD_DIR ARFLAGS BASHVERS RELSTATUS DEBUG MALLOC_DEBUG LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -4927,6 +4927,27 @@ opennt*|interix*) MAKE_SHELL="$INTERIX_ROOT/bin/sh" ;;
esac
if test x$SIZE = x; then
if test x$ac_tool_prefix = x; then
SIZE=size
else
SIZE=${ac_tool_prefix}size
save_IFS=$IFS ; IFS=:
size_found=0
for dir in $PATH; do
if test -x $dir/$SIZE ; then
size_found=1
break
fi
done
if test $size_found -eq 0; then
SIZE=size
fi
IFS=$save_IFS
fi
fi
cat >>confdefs.h <<\_ACEOF
@%:@define _GNU_SOURCE 1
_ACEOF
@@ -24146,6 +24167,10 @@ case "$srcdir" in
esac
BUILD_DIR=`pwd`
case "$BUILD_DIR" in
*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;;
*) ;;
esac
@@ -24877,6 +24902,7 @@ s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
s,@YACC@,$YACC,;t t
s,@SET_MAKE@,$SET_MAKE,;t t
s,@MAKE_SHELL@,$MAKE_SHELL,;t t
s,@SIZE@,$SIZE,;t t
s,@MKINSTALLDIRS@,$MKINSTALLDIRS,;t t
s,@USE_NLS@,$USE_NLS,;t t
s,@MSGFMT@,$MSGFMT,;t t
+79 -79
View File
@@ -15,96 +15,96 @@
'configure.in'
],
{
'AC_CHECK_LIB' => 1,
'AC_FUNC_MEMCMP' => 1,
'AC_C_VOLATILE' => 1,
'AC_HEADER_STDC' => 1,
'm4_pattern_forbid' => 1,
'AC_INIT' => 1,
'AC_FUNC_MALLOC' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
'AC_TYPE_MODE_T' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_CONFIG_FILES' => 1,
'include' => 1,
'AC_HEADER_MAJOR' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_CHECK_MEMBERS' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_PROG_AWK' => 1,
'AM_CONDITIONAL' => 1,
'AC_PROG_CC' => 1,
'AC_FUNC_SETPGRP' => 1,
'AC_TYPE_PID_T' => 1,
'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
'AC_FUNC_MKTIME' => 1,
'AC_FUNC_UTIME_NULL' => 1,
'AC_FUNC_WAIT3' => 1,
'AC_C_INLINE' => 1,
'AC_FUNC_STAT' => 1,
'AC_STRUCT_ST_BLOCKS' => 1,
'AC_CHECK_HEADERS' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_CONFIG_SUBDIRS' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_FUNC_MMAP' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AC_FUNC_CLOSEDIR_VOID' => 1,
'AC_LIBSOURCE' => 1,
'AC_SUBST' => 1,
'AC_FUNC_STRFTIME' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_FUNC_GETMNTENT' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AC_PROG_YACC' => 1,
'AC_FUNC_VPRINTF' => 1,
'AC_FUNC_REALLOC' => 1,
'AC_PROG_MAKE_SET' => 1,
'AC_CHECK_HEADERS' => 1,
'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1,
'AC_TYPE_UID_T' => 1,
'AC_FUNC_GETLOADAVG' => 1,
'AC_CHECK_FUNCS' => 1,
'AC_PROG_LN_S' => 1,
'AM_MAINTAINER_MODE' => 1,
'AC_TYPE_SIZE_T' => 1,
'AC_PROG_LIBTOOL' => 1,
'AC_FUNC_STRNLEN' => 1,
'AC_HEADER_SYS_WAIT' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AC_FUNC_MBRTOWC' => 1,
'AC_FUNC_OBSTACK' => 1,
'AC_HEADER_DIRENT' => 1,
'AC_FUNC_GETGROUPS' => 1,
'AC_REPLACE_FNMATCH' => 1,
'AC_FUNC_SELECT_ARGTYPES' => 1,
'AC_PROG_CPP' => 1,
'AC_PROG_GCC_TRADITIONAL' => 1,
'AC_PROG_CXX' => 1,
'AC_HEADER_TIME' => 1,
'AC_FUNC_GETPGRP' => 1,
'AC_PROG_LEX' => 1,
'm4_pattern_allow' => 1,
'AC_FUNC_FSEEKO' => 1,
'AC_PROG_MAKE_SET' => 1,
'AC_FUNC_ERROR_AT_LINE' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_STRUCT_TIMEZONE' => 1,
'AC_FUNC_FORK' => 1,
'AC_FUNC_GETGROUPS' => 1,
'AM_GNU_GETTEXT' => 1,
'AC_FUNC_STRERROR_R' => 1,
'AC_FUNC_LSTAT' => 1,
'AC_TYPE_SIZE_T' => 1,
'AC_FUNC_WAIT3' => 1,
'AC_PATH_X' => 1,
'AC_PROG_RANLIB' => 1,
'AC_HEADER_STAT' => 1,
'AC_CHECK_FUNCS' => 1,
'AC_PROG_AWK' => 1,
'AC_C_VOLATILE' => 1,
'AC_HEADER_STDC' => 1,
'AC_CHECK_TYPES' => 1,
'AC_STRUCT_TM' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_FUNC_CHOWN' => 1,
'AC_TYPE_OFF_T' => 1,
'AC_C_CONST' => 1,
'AC_FUNC_MKTIME' => 1,
'AM_AUTOMAKE_VERSION' => 1,
'AM_INIT_AUTOMAKE' => 1,
'AC_PROG_LEX' => 1,
'AC_PROG_CC' => 1,
'AC_FUNC_ALLOCA' => 1,
'm4_pattern_forbid' => 1,
'm4_pattern_allow' => 1,
'AC_PROG_GCC_TRADITIONAL' => 1,
'AC_C_CONST' => 1,
'AC_TYPE_OFF_T' => 1,
'AM_PROG_CC_C_O' => 1,
'AC_FUNC_CHOWN' => 1,
'AC_FUNC_MMAP' => 1,
'AM_GNU_GETTEXT' => 1,
'include' => 1,
'AC_LIBSOURCE' => 1,
'AC_HEADER_TIME' => 1,
'AC_FUNC_STRFTIME' => 1,
'AC_CHECK_MEMBERS' => 1,
'AC_FUNC_GETMNTENT' => 1,
'AC_HEADER_DIRENT' => 1,
'AC_FUNC_ERROR_AT_LINE' => 1,
'AC_HEADER_STAT' => 1,
'AC_DECL_SYS_SIGLIST' => 1,
'AC_FUNC_GETPGRP' => 1,
'AC_FUNC_SETVBUF_REVERSED' => 1,
'AC_PROG_CXX' => 1,
'AC_TYPE_MODE_T' => 1,
'AC_FUNC_SETPGRP' => 1,
'AC_FUNC_MALLOC' => 1,
'AC_FUNC_STAT' => 1,
'AC_FUNC_STRERROR_R' => 1,
'AC_STRUCT_TIMEZONE' => 1,
'AH_OUTPUT' => 1,
'AC_PROG_INSTALL' => 1,
'AC_PROG_CPP' => 1,
'AC_CONFIG_HEADERS' => 1,
'AC_PROG_RANLIB' => 1,
'AC_HEADER_SYS_WAIT' => 1,
'AC_C_INLINE' => 1,
'AC_CONFIG_AUX_DIR' => 1,
'AC_FUNC_LSTAT' => 1,
'AC_STRUCT_ST_BLOCKS' => 1,
'AC_FUNC_VPRINTF' => 1,
'AC_FUNC_CLOSEDIR_VOID' => 1,
'AC_FUNC_STRTOD' => 1,
'AC_CANONICAL_HOST' => 1,
'AC_INIT' => 1,
'AC_FUNC_GETLOADAVG' => 1,
'AC_HEADER_MAJOR' => 1,
'AC_FUNC_FSEEKO' => 1,
'AC_TYPE_PID_T' => 1,
'AC_FUNC_OBSTACK' => 1,
'AC_CANONICAL_SYSTEM' => 1,
'AC_FUNC_STRCOLL' => 1,
'AC_FUNC_REALLOC' => 1,
'AC_CONFIG_FILES' => 1,
'AM_CONDITIONAL' => 1,
'AC_PROG_LN_S' => 1,
'AC_FUNC_UTIME_NULL' => 1,
'AC_FUNC_MBRTOWC' => 1,
'AC_PROG_YACC' => 1,
'AC_TYPE_SIGNAL' => 1,
'm4_include' => 1
'AC_PROG_INSTALL' => 1,
'AC_FUNC_MEMCMP' => 1,
'AC_CHECK_LIB' => 1,
'AC_DEFINE_TRACE_LITERAL' => 1,
'AC_SUBST' => 1,
'm4_include' => 1,
'AC_STRUCT_TM' => 1,
'AC_FUNC_FORK' => 1
}
], 'Request' )
);
+620 -619
View File
File diff suppressed because it is too large Load Diff
+7 -3
View File
@@ -404,12 +404,12 @@ exec.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
exec.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/flags.h
exec.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exec.o: $(srcdir)/common.h $(topdir)/execute_cmd.h $(BASHINCDIR)/maxpath.h
exec.o: $(topdir)/findcmd.h
exec.o: $(topdir)/findcmd.h $(topdir)/jobs.h
exit.o: $(topdir)/bashtypes.h
exit.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
exit.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
exit.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
exit.o: $(topdir)/subst.h $(topdir)/externs.h
exit.o: $(topdir)/subst.h $(topdir)/externs.h $(topdir)/jobs.h
exit.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
exit.o: $(BASHINCDIR)/maxpath.h ./builtext.h
fc.o: $(topdir)/bashtypes.h $(BASHINCDIR)/posixstat.h
@@ -427,6 +427,7 @@ fg_bg.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
fg_bg.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
fg_bg.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
fg_bg.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
fg_bg.o: $(topdir)/jobs.h
getopts.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
getopts.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
getopts.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -458,7 +459,7 @@ inlib.o: $(BASHINCDIR)/maxpath.h $(topdir)/subst.h $(topdir)/externs.h
inlib.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
jobs.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
jobs.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/quit.h $(srcdir)/bashgetopt.h
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h
jobs.o: $(BASHINCDIR)/maxpath.h $(topdir)/externs.h $(topdir)/jobs.h
jobs.o: $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h $(topdir)/subst.h
jobs.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
kill.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h $(topdir)/error.h
@@ -466,6 +467,7 @@ kill.o: $(topdir)/general.h $(topdir)/xmalloc.h $(topdir)/subst.h $(topdir)/exte
kill.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
kill.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/trap.h $(topdir)/unwind_prot.h
kill.o: $(topdir)/variables.h $(topdir)/conftypes.h $(BASHINCDIR)/maxpath.h
kill.o: $(topdir)/jobs.h
let.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
let.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
let.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -525,6 +527,7 @@ suspend.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
suspend.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
suspend.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
suspend.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
suspend.o: $(topdir)/jobs.h
test.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
test.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
test.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
@@ -565,6 +568,7 @@ wait.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
wait.o: $(topdir)/quit.h $(topdir)/dispose_cmd.h $(topdir)/make_cmd.h
wait.o: $(topdir)/subst.h $(topdir)/externs.h $(BASHINCDIR)/maxpath.h
wait.o: $(topdir)/shell.h $(topdir)/syntax.h $(topdir)/unwind_prot.h $(topdir)/variables.h $(topdir)/conftypes.h
wait.o: $(topdir)/jobs.h
wait.o: $(BASHINCDIR)/chartypes.h
shopt.o: $(topdir)/command.h ../config.h $(BASHINCDIR)/memalloc.h
shopt.o: $(topdir)/error.h $(topdir)/general.h $(topdir)/xmalloc.h
+1 -1
View File
@@ -230,7 +230,7 @@ distclean maintainer-clean: clean
$(OFILES): $(MKBUILTINS) ../config.h
../version.h: ../config.h ../Makefile Makefile
-( cd "${BUILD_DIR}" && ${MAKE} ${MFLAGS} version.h )
-( cd ${BUILD_DIR} && ${MAKE} ${MFLAGS} version.h )
# maintainer special - for now
po: builtins.c
+10 -8
View File
@@ -514,15 +514,17 @@ get_job_by_name (name, flags)
{
register int i, wl, cl, match, job;
register PROCESS *p;
register JOB *j;
job = NO_JOB;
wl = strlen (name);
for (i = job_slots - 1; i >= 0; i--)
for (i = js.j_jobslots - 1; i >= 0; i--)
{
if (jobs[i] == 0 || ((flags & JM_STOPPED) && JOBSTATE(i) != JSTOPPED))
j = get_job_by_jid (i);
if (j == 0 || ((flags & JM_STOPPED) && J_JOBSTATE(j) != JSTOPPED))
continue;
p = jobs[i]->pipe;
p = j->pipe;
do
{
if (flags & JM_EXACT)
@@ -553,7 +555,7 @@ get_job_by_name (name, flags)
else
job = i;
}
while (p != jobs[i]->pipe);
while (p != j->pipe);
}
return (job);
@@ -568,7 +570,7 @@ get_job_spec (list)
int job, jflags;
if (list == 0)
return (current_job);
return (js.j_current);
word = list->word->word;
@@ -581,7 +583,7 @@ get_job_spec (list)
if (DIGIT (*word) && all_digits (word))
{
job = atoi (word);
return (job > job_slots ? NO_JOB : job - 1);
return (job > js.j_jobslots ? NO_JOB : job - 1);
}
jflags = 0;
@@ -590,10 +592,10 @@ get_job_spec (list)
case 0:
case '%':
case '+':
return (current_job);
return (js.j_current);
case '-':
return (previous_job);
return (js.j_previous);
case '?': /* Substring search requested. */
jflags |= JM_SUBSTRING;
+1 -1
View File
@@ -105,7 +105,7 @@ exit_or_logout (list)
if (!exit_immediate_okay)
{
register int i;
for (i = 0; i < job_slots; i++)
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && STOPPED (i))
{
fprintf (stderr, _("There are stopped jobs.\n"));
+152
View File
@@ -0,0 +1,152 @@
This file is exit.def, from which is created exit.c.
It implements the builtins "exit", and "logout" in Bash.
Copyright (C) 1987-2003 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.
$PRODUCES exit.c
$BUILTIN exit
$FUNCTION exit_builtin
$SHORT_DOC exit [n]
Exit the shell with a status of N. If N is omitted, the exit status
is that of the last command executed.
$END
#include <config.h>
#include "../bashtypes.h"
#include <stdio.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "common.h"
#include "builtext.h" /* for jobs_builtin */
extern int last_command_exit_value;
extern int running_trap, trap_saved_exit_value;
extern int subshell_environment;
extern sh_builtin_func_t *this_shell_builtin;
extern sh_builtin_func_t *last_shell_builtin;
static int exit_or_logout __P((WORD_LIST *));
static int sourced_logout;
int
exit_builtin (list)
WORD_LIST *list;
{
if (interactive)
{
fprintf (stderr, login_shell ? "logout\n" : "exit\n");
fflush (stderr);
}
return (exit_or_logout (list));
}
$BUILTIN logout
$FUNCTION logout_builtin
$SHORT_DOC logout
Logout of a login shell.
$END
/* How to logout. */
int
logout_builtin (list)
WORD_LIST *list;
{
if (login_shell == 0 /* && interactive */)
{
builtin_error (_("not login shell: use `exit'"));
return (EXECUTION_FAILURE);
}
else
return (exit_or_logout (list));
}
static int
exit_or_logout (list)
WORD_LIST *list;
{
int exit_value;
#if defined (JOB_CONTROL)
int exit_immediate_okay;
exit_immediate_okay = (interactive == 0 ||
last_shell_builtin == exit_builtin ||
last_shell_builtin == logout_builtin ||
last_shell_builtin == jobs_builtin);
/* Check for stopped jobs if the user wants to. */
if (!exit_immediate_okay)
{
register int i;
for (i = 0; i < job_slots; i++)
if (jobs[i] && STOPPED (i))
{
fprintf (stderr, _("There are stopped jobs.\n"));
/* This is NOT superfluous because EOF can get here without
going through the command parser. Set both last and this
so that either `exit', `logout', or ^D will work to exit
immediately if nothing intervenes. */
this_shell_builtin = last_shell_builtin = exit_builtin;
return (EXECUTION_FAILURE);
}
}
#endif /* JOB_CONTROL */
/* Get return value if present. This means that you can type
`logout 5' to a shell, and it returns 5. */
/* If we're running the exit trap (running_trap == 1, since running_trap
gets set to SIG+1), and we don't have a argument given to `exit'
(list == 0), use the exit status we saved before running the trap
commands (trap_saved_exit_value). */
exit_value = (running_trap == 1 && list == 0) ? trap_saved_exit_value : get_exitstat (list);
bash_logout ();
last_command_exit_value = exit_value;
/* Exit the program. */
jump_to_top_level (EXITPROG);
/*NOTREACHED*/
}
void
bash_logout ()
{
/* Run our `~/.bash_logout' file if it exists, and this is a login shell. */
if (login_shell && sourced_logout++ == 0 && subshell_environment == 0)
{
maybe_execute_file ("~/.bash_logout", 1);
#ifdef SYS_BASH_LOGOUT
maybe_execute_file (SYS_BASH_LOGOUT, 1);
#endif
}
}
+5 -3
View File
@@ -127,11 +127,12 @@ fg_bg (list, foreground)
{
sigset_t set, oset;
int job, status, old_async_pid;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (job < 0 || job >= job_slots || jobs[job] == 0)
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list ? list->word->word : "current");
@@ -139,7 +140,8 @@ fg_bg (list, foreground)
goto failure;
}
/* Or if jobs[job]->pgrp == shell_pgrp. */
j = get_job_by_jid (job);
/* Or if j->pgrp == shell_pgrp. */
if (IS_JOBCONTROL (job) == 0)
{
builtin_error (_("job %d started without job control"), job + 1);
@@ -149,7 +151,7 @@ fg_bg (list, foreground)
if (foreground == 0)
{
old_async_pid = last_asynchronous_pid;
last_asynchronous_pid = jobs[job]->pgrp; /* As per Posix.2 5.4.2 */
last_asynchronous_pid = j->pgrp; /* As per Posix.2 5.4.2 */
}
status = start_job (job, foreground);
+14 -2
View File
@@ -94,6 +94,8 @@ int
bg_builtin (list)
WORD_LIST *list;
{
int r;
if (job_control == 0)
{
sh_nojobs ((char *)NULL);
@@ -104,7 +106,17 @@ bg_builtin (list)
return (EX_USAGE);
list = loptend;
return (fg_bg (list, 0));
/* This relies on the fact that fg_bg() takes a WORD_LIST *, but only acts
on the first member (if any) of that list. */
do
{
r = fg_bg (list, 0);
if (list)
list = list->next;
}
while (list);
return r;
}
/* How to put a job into the foreground/background. */
@@ -119,7 +131,7 @@ fg_bg (list, foreground)
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (job < 0 || job >= job_slots || jobs[job] == 0)
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list ? list->word->word : "current");
+6 -4
View File
@@ -141,7 +141,7 @@ jobs_builtin (list)
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if ((job == NO_JOB) || !jobs || !jobs[job])
if ((job == NO_JOB) || jobs == 0 || get_job_by_jid (job) == 0)
{
sh_badjob (list->word->word);
any_failed++;
@@ -162,6 +162,7 @@ execute_list_with_replacements (list)
register WORD_LIST *l;
int job, result;
COMMAND *command;
JOB *j;
/* First do the replacement of job specifications with pids. */
for (l = list; l; l = l->next)
@@ -171,11 +172,12 @@ execute_list_with_replacements (list)
job = get_job_spec (l);
/* A bad job spec is not really a job spec! Pass it through. */
if (job < 0 || job >= job_slots || !jobs[job])
if (INVALID_JOB (job))
continue;
j = get_job_by_jid (job);
free (l->word->word);
l->word->word = itos (jobs[job]->pgrp);
l->word->word = itos (j->pgrp);
}
}
@@ -257,7 +259,7 @@ disown_builtin (list)
? get_job_by_pid ((pid_t) pid_value, 0)
: get_job_spec (list);
if (job == NO_JOB || jobs == 0 || job < 0 || job >= job_slots || jobs[job] == 0)
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
{
sh_badjob (list ? list->word->word : "current");
retval = EXECUTION_FAILURE;
+278
View File
@@ -0,0 +1,278 @@
This file is jobs.def, from which is created jobs.c.
It implements the builtins "jobs" and "disown" in Bash.
Copyright (C) 1987-2004 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.
$PRODUCES jobs.c
$BUILTIN jobs
$FUNCTION jobs_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC jobs [-lnprs] [jobspec ...] or jobs -x command [args]
Lists the active jobs. The -l option lists process id's in addition
to the normal information; the -p option lists process id's only.
If -n is given, only processes that have changed status since the last
notification are printed. JOBSPEC restricts output to that job. The
-r and -s options restrict output to running and stopped jobs only,
respectively. Without options, the status of all active jobs is
printed. If -x is given, COMMAND is run after all job specifications
that appear in ARGS have been replaced with the process ID of that job's
process group leader.
$END
#include <config.h>
#if defined (JOB_CONTROL)
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../jobs.h"
#include "../execute_cmd.h"
#include "bashgetopt.h"
#include "common.h"
#define JSTATE_ANY 0x0
#define JSTATE_RUNNING 0x1
#define JSTATE_STOPPED 0x2
static int execute_list_with_replacements __P((WORD_LIST *));
/* The `jobs' command. Prints outs a list of active jobs. If the
argument `-l' is given, then the process id's are printed also.
If the argument `-p' is given, print the process group leader's
pid only. If `-n' is given, only processes that have changed
status since the last notification are printed. If -x is given,
replace all job specs with the pid of the appropriate process
group leader and execute the command. The -r and -s options mean
to print info about running and stopped jobs only, respectively. */
int
jobs_builtin (list)
WORD_LIST *list;
{
int form, execute, state, opt, any_failed, job;
sigset_t set, oset;
execute = any_failed = 0;
form = JLIST_STANDARD;
state = JSTATE_ANY;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "lpnxrs")) != -1)
{
switch (opt)
{
case 'l':
form = JLIST_LONG;
break;
case 'p':
form = JLIST_PID_ONLY;
break;
case 'n':
form = JLIST_CHANGED_ONLY;
break;
case 'x':
if (form != JLIST_STANDARD)
{
builtin_error (_("no other options allowed with `-x'"));
return (EXECUTION_FAILURE);
}
execute++;
break;
case 'r':
state = JSTATE_RUNNING;
break;
case 's':
state = JSTATE_STOPPED;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
if (execute)
return (execute_list_with_replacements (list));
if (!list)
{
switch (state)
{
case JSTATE_ANY:
list_all_jobs (form);
break;
case JSTATE_RUNNING:
list_running_jobs (form);
break;
case JSTATE_STOPPED:
list_stopped_jobs (form);
break;
}
return (EXECUTION_SUCCESS);
}
while (list)
{
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if ((job == NO_JOB) || !jobs || !jobs[job])
{
sh_badjob (list->word->word);
any_failed++;
}
else if (job != DUP_JOB)
list_one_job ((JOB *)NULL, form, 0, job);
UNBLOCK_CHILD (oset);
list = list->next;
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
}
static int
execute_list_with_replacements (list)
WORD_LIST *list;
{
register WORD_LIST *l;
int job, result;
COMMAND *command;
/* First do the replacement of job specifications with pids. */
for (l = list; l; l = l->next)
{
if (l->word->word[0] == '%') /* we have a winner */
{
job = get_job_spec (l);
/* A bad job spec is not really a job spec! Pass it through. */
if (INVALID_JOB (job))
continue;
free (l->word->word);
l->word->word = itos (jobs[job]->pgrp);
}
}
/* Next make a new simple command and execute it. */
begin_unwind_frame ("jobs_builtin");
command = make_bare_simple_command ();
command->value.Simple->words = copy_word_list (list);
command->value.Simple->redirects = (REDIRECT *)NULL;
command->flags |= CMD_INHIBIT_EXPANSION;
command->value.Simple->flags |= CMD_INHIBIT_EXPANSION;
add_unwind_protect (dispose_command, command);
result = execute_command (command);
dispose_command (command);
discard_unwind_frame ("jobs_builtin");
return (result);
}
#endif /* JOB_CONTROL */
$BUILTIN disown
$FUNCTION disown_builtin
$DEPENDS_ON JOB_CONTROL
$SHORT_DOC disown [-h] [-ar] [jobspec ...]
By default, removes each JOBSPEC argument from the table of active jobs.
If the -h option is given, the job is not removed from the table, but is
marked so that SIGHUP is not sent to the job if the shell receives a
SIGHUP. The -a option, when JOBSPEC is not supplied, means to remove all
jobs from the job table; the -r option means to remove only running jobs.
$END
#if defined (JOB_CONTROL)
int
disown_builtin (list)
WORD_LIST *list;
{
int opt, job, retval, nohup_only, running_jobs, all_jobs;
sigset_t set, oset;
intmax_t pid_value;
nohup_only = running_jobs = all_jobs = 0;
reset_internal_getopt ();
while ((opt = internal_getopt (list, "ahr")) != -1)
{
switch (opt)
{
case 'a':
all_jobs = 1;
break;
case 'h':
nohup_only = 1;
break;
case 'r':
running_jobs = 1;
break;
default:
builtin_usage ();
return (EX_USAGE);
}
}
list = loptend;
retval = EXECUTION_SUCCESS;
/* `disown -a' or `disown -r' */
if (list == 0 && (all_jobs || running_jobs))
{
if (nohup_only)
nohup_all_jobs (running_jobs);
else
delete_all_jobs (running_jobs);
return (EXECUTION_SUCCESS);
}
do
{
BLOCK_CHILD (set, oset);
job = (list && legal_number (list->word->word, &pid_value) && pid_value == (pid_t) pid_value)
? get_job_by_pid ((pid_t) pid_value, 0)
: get_job_spec (list);
if (job == NO_JOB || jobs == 0 || INVALID_JOB (job))
{
sh_badjob (list ? list->word->word : "current");
retval = EXECUTION_FAILURE;
}
else if (nohup_only)
nohup_job (job);
else
delete_job (job, 1);
UNBLOCK_CHILD (oset);
if (list)
list = list->next;
}
while (list);
return (retval);
}
#endif /* JOB_CONTROL */
+4 -2
View File
@@ -192,11 +192,12 @@ kill_builtin (list)
{ /* Must be a job spec. Check it out. */
int job;
sigset_t set, oset;
JOB *j;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (job < 0 || job >= job_slots || !jobs[job])
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
@@ -204,11 +205,12 @@ kill_builtin (list)
CONTINUE_OR_FAIL;
}
j = get_job_by_jid (job);
/* Job spec used. Kill the process group. If the job was started
without job control, then its pgrp == shell_pgrp, so we have
to be careful. We take the pid of the first job in the pipeline
in that case. */
pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid;
pid = IS_JOBCONTROL (job) ? j->pgrp : j->pipe->pid;
UNBLOCK_CHILD (oset);
+250
View File
@@ -0,0 +1,250 @@
This file is kill.def, from which is created kill.c.
It implements the builtin "kill" in Bash.
Copyright (C) 1987-2004 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.
$PRODUCES kill.c
$BUILTIN kill
$FUNCTION kill_builtin
$SHORT_DOC kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
Send the processes named by PID (or JOBSPEC) the signal SIGSPEC. If
SIGSPEC is not present, then SIGTERM is assumed. An argument of `-l'
lists the signal names; if arguments follow `-l' they are assumed to
be signal numbers for which names should be listed. Kill is a shell
builtin for two reasons: it allows job IDs to be used instead of
process IDs, and, if you have reached the limit on processes that
you can create, you don't have to start a process to kill another one.
$END
#include <config.h>
#include <stdio.h>
#include <errno.h>
#if defined (HAVE_UNISTD_H)
# ifdef _MINIX
# include <sys/types.h>
# endif
# include <unistd.h>
#endif
#include "../bashansi.h"
#include "../bashintl.h"
#include "../shell.h"
#include "../trap.h"
#include "../jobs.h"
#include "common.h"
/* Not all systems declare ERRNO in errno.h... and some systems #define it! */
#if !defined (errno)
extern int errno;
#endif /* !errno */
extern int posixly_correct;
static void kill_error __P((pid_t, int));
#if !defined (CONTINUE_AFTER_KILL_ERROR)
# define CONTINUE_OR_FAIL return (EXECUTION_FAILURE)
#else
# define CONTINUE_OR_FAIL goto continue_killing
#endif /* CONTINUE_AFTER_KILL_ERROR */
/* Here is the kill builtin. We only have it so that people can type
kill -KILL %1? No, if you fill up the process table this way you
can still kill some. */
int
kill_builtin (list)
WORD_LIST *list;
{
int sig, any_succeeded, listing, saw_signal, dflags;
char *sigspec, *word;
pid_t pid;
intmax_t pid_value;
if (list == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
}
any_succeeded = listing = saw_signal = 0;
sig = SIGTERM;
sigspec = "TERM";
dflags = DSIG_NOCASE | ((posixly_correct == 0) ? DSIG_SIGPREFIX : 0);
/* Process options. */
while (list)
{
word = list->word->word;
if (ISOPTION (word, 'l'))
{
listing++;
list = list->next;
}
else if (ISOPTION (word, 's') || ISOPTION (word, 'n'))
{
list = list->next;
if (list)
{
sigspec = list->word->word;
if (sigspec[0] == '0' && sigspec[1] == '\0')
sig = 0;
else
sig = decode_signal (sigspec, dflags);
list = list->next;
}
else
{
sh_needarg (word);
return (EXECUTION_FAILURE);
}
}
else if (ISOPTION (word, '-'))
{
list = list->next;
break;
}
else if (ISOPTION (word, '?'))
{
builtin_usage ();
return (EXECUTION_SUCCESS);
}
/* If this is a signal specification then process it. We only process
the first one seen; other arguments may signify process groups (e.g,
-num == process group num). */
else if ((*word == '-') && !saw_signal)
{
sigspec = word + 1;
sig = decode_signal (sigspec, dflags);
saw_signal++;
list = list->next;
}
else
break;
}
if (listing)
return (display_signal_list (list, 0));
/* OK, we are killing processes. */
if (sig == NO_SIG)
{
sh_invalidsig (sigspec);
return (EXECUTION_FAILURE);
}
if (list == 0)
{
builtin_usage ();
return (EXECUTION_FAILURE);
}
while (list)
{
word = list->word->word;
if (*word == '-')
word++;
/* Use the entire argument in case of minus sign presence. */
if (*word && legal_number (list->word->word, &pid_value) && (pid_value == (pid_t)pid_value))
{
pid = (pid_t) pid_value;
if ((pid < -1 ? kill_pid (-pid, sig, 1) : kill_pid (pid, sig, 0)) < 0)
{
if (errno == EINVAL)
sh_invalidsig (sigspec);
else
kill_error (pid, errno);
CONTINUE_OR_FAIL;
}
else
any_succeeded++;
}
#if defined (JOB_CONTROL)
else if (*list->word->word && *list->word->word != '%')
{
builtin_error (_("%s: arguments must be process or job IDs"), list->word->word);
CONTINUE_OR_FAIL;
}
else if (*word)
/* Posix.2 says you can kill without job control active (4.32.4) */
{ /* Must be a job spec. Check it out. */
int job;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
UNBLOCK_CHILD (oset);
CONTINUE_OR_FAIL;
}
/* Job spec used. Kill the process group. If the job was started
without job control, then its pgrp == shell_pgrp, so we have
to be careful. We take the pid of the first job in the pipeline
in that case. */
pid = IS_JOBCONTROL (job) ? jobs[job]->pgrp : jobs[job]->pipe->pid;
UNBLOCK_CHILD (oset);
if (kill_pid (pid, sig, 1) < 0)
{
if (errno == EINVAL)
sh_invalidsig (sigspec);
else
kill_error (pid, errno);
CONTINUE_OR_FAIL;
}
else
any_succeeded++;
}
#endif /* !JOB_CONTROL */
else
{
sh_badpid (list->word->word);
CONTINUE_OR_FAIL;
}
continue_killing:
list = list->next;
}
return (any_succeeded ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
}
static void
kill_error (pid, e)
pid_t pid;
int e;
{
char *x;
x = strerror (e);
if (x == 0)
x = _("Unknown error");
builtin_error ("(%ld) - %s", (long)pid, x);
}
-1
View File
@@ -214,7 +214,6 @@ showtrap (i)
char *t, *p, *sn;
p = trap_list[i];
if (p == (char *)DEFAULT_SIG)
return;
+7 -3
View File
@@ -23,7 +23,7 @@ $PRODUCES trap.c
$BUILTIN trap
$FUNCTION trap_builtin
$SHORT_DOC trap [-lp] [[arg] signal_spec ...]
$SHORT_DOC trap [-lp] [arg signal_spec ...]
The command ARG is to be read and executed when the shell receives
signal(s) SIGNAL_SPEC. If ARG is absent (and a single SIGNAL_SPEC
is supplied) or `-', each specified signal is reset to its original
@@ -124,10 +124,13 @@ trap_builtin (list)
first_arg = list->word->word;
first_signal = first_arg && *first_arg && all_digits (first_arg) && signal_object_p (first_arg, opt);
/* Backwards compatibility */
if (first_signal)
operation = REVERT;
/* When in posix mode, the historical behavior of looking for a
missing first argument is disabled. To revert to the original
signal handling disposition, use `-' as the first argument. */
if (posixly_correct == 0 && first_arg && *first_arg &&
else if (posixly_correct == 0 && first_arg && *first_arg &&
(*first_arg != '-' || first_arg[1]) &&
signal_object_p (first_arg, opt) && list->next == 0)
operation = REVERT;
@@ -211,7 +214,7 @@ showtrap (i)
char *t, *p, *sn;
p = trap_list[i];
itrace("showtrap: %d", i);
if (p == (char *)DEFAULT_SIG)
return;
@@ -240,6 +243,7 @@ display_traps (list)
{
int result, i;
itrace("trap_builtin");
if (list == 0)
{
for (i = 0; i < BASH_NSIG; i++)
+1 -1
View File
@@ -150,7 +150,7 @@ wait_builtin (list)
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
if (job < 0 || job >= job_slots || !jobs[job])
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
+179
View File
@@ -0,0 +1,179 @@
This file is wait.def, from which is created wait.c.
It implements the builtin "wait" in Bash.
Copyright (C) 1987-2004 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.
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON JOB_CONTROL
$PRODUCES wait.c
$SHORT_DOC wait [n]
Wait for the specified process and report its termination status. If
N is not given, all currently active child processes are waited for,
and the return code is zero. N may be a process ID or a job
specification; if a job spec is given, all processes in the job's
pipeline are waited for.
$END
$BUILTIN wait
$FUNCTION wait_builtin
$DEPENDS_ON !JOB_CONTROL
$SHORT_DOC wait [n]
Wait for the specified process and report its termination status. If
N is not given, all currently active child processes are waited for,
and the return code is zero. N is a process ID; if it is not given,
all child processes of the shell are waited for.
$END
#include <config.h>
#include "../bashtypes.h"
#include <signal.h>
#if defined (HAVE_UNISTD_H)
# include <unistd.h>
#endif
#include <chartypes.h>
#include "../bashansi.h"
#include "../shell.h"
#include "../jobs.h"
#include "common.h"
#include "bashgetopt.h"
extern int interrupt_immediately;
extern int wait_signal_received;
procenv_t wait_intr_buf;
/* Wait for the pid in LIST to stop or die. If no arguments are given, then
wait for all of the active background processes of the shell and return
0. If a list of pids or job specs are given, return the exit status of
the last one waited for. */
#define WAIT_RETURN(s) \
do \
{ \
interrupt_immediately = old_interrupt_immediately;\
return (s);\
} \
while (0)
int
wait_builtin (list)
WORD_LIST *list;
{
int status, code;
volatile int old_interrupt_immediately;
USE_VAR(list);
if (no_options (list))
return (EX_USAGE);
list = loptend;
old_interrupt_immediately = interrupt_immediately;
interrupt_immediately++;
/* POSIX.2 says: When the shell is waiting (by means of the wait utility)
for asynchronous commands to complete, the reception of a signal for
which a trap has been set shall cause the wait utility to return
immediately with an exit status greater than 128, after which the trap
associated with the signal shall be taken.
We handle SIGINT here; it's the only one that needs to be treated
specially (I think), since it's handled specially in {no,}jobs.c. */
code = setjmp (wait_intr_buf);
if (code)
{
status = 128 + wait_signal_received;
WAIT_RETURN (status);
}
/* We support jobs or pids.
wait <pid-or-job> [pid-or-job ...] */
/* But wait without any arguments means to wait for all of the shell's
currently active background processes. */
if (list == 0)
{
wait_for_background_pids ();
WAIT_RETURN (EXECUTION_SUCCESS);
}
status = EXECUTION_SUCCESS;
while (list)
{
pid_t pid;
char *w;
intmax_t pid_value;
w = list->word->word;
if (DIGIT (*w))
{
if (legal_number (w, &pid_value) && pid_value == (pid_t)pid_value)
{
pid = (pid_t)pid_value;
status = wait_for_single_pid (pid);
}
else
{
sh_badpid (w);
WAIT_RETURN (EXECUTION_FAILURE);
}
}
#if defined (JOB_CONTROL)
else if (*w && *w == '%')
/* Must be a job spec. Check it out. */
{
int job;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
job = get_job_spec (list);
itrace("wait_builtin: get_job_spec returns %d, js.j_current = %d", job, js.j_current);
if (INVALID_JOB (job))
{
if (job != DUP_JOB)
sh_badjob (list->word->word);
UNBLOCK_CHILD (oset);
status = 127; /* As per Posix.2, section 4.70.2 */
list = list->next;
continue;
}
/* Job spec used. Wait for the last pid in the pipeline. */
UNBLOCK_CHILD (oset);
status = wait_for_job (job);
}
#endif /* JOB_CONTROL */
else
{
sh_badpid (w);
status = EXECUTION_FAILURE;
}
list = list->next;
}
WAIT_RETURN (status);
}
Vendored
+28 -2
View File
@@ -1,5 +1,5 @@
#! /bin/sh
# From configure.in for Bash 3.0, version 3.172, from autoconf version AC_ACVERSION.
# From configure.in for Bash 3.1, version 3.173, 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.
#
@@ -311,7 +311,7 @@ ac_includes_default="\
# include <unistd.h>
#endif"
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os EMACS lispdir DEBUGGER_START_FILE TESTSCRIPT PURIFY MALLOC_TARGET MALLOC_SRC MALLOC_LIB MALLOC_LIBRARY MALLOC_LDFLAGS MALLOC_DEP htmldir HELPDIR HELPDIRDEFINE HELPINSTALL HELPSTRINGS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP SIGNAMES_H CC_FOR_BUILD STATIC_LD CFLAGS_FOR_BUILD CPPFLAGS_FOR_BUILD LDFLAGS_FOR_BUILD RL_VERSION RL_MAJOR RL_MINOR READLINE_LIB READLINE_DEP RL_LIBDIR RL_INCLUDEDIR RL_INCLUDE HISTORY_LIB HISTORY_DEP HIST_LIBDIR INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR RANLIB ac_ct_RANLIB YACC SET_MAKE MAKE_SHELL MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE ALLOCA GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIBOBJS INTL_DEP INTL_INC LIBINTL_H SIGLIST_O TERMCAP_LIB TERMCAP_DEP JOBS_O SHOBJ_CC SHOBJ_CFLAGS SHOBJ_LD SHOBJ_LDFLAGS SHOBJ_XLDFLAGS SHOBJ_LIBS SHOBJ_STATUS PROFILE_FLAGS incdir BUILD_DIR ARFLAGS BASHVERS RELSTATUS DEBUG MALLOC_DEBUG LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS LTLIBOBJS'
ac_subst_vars='SHELL PATH_SEPARATOR PACKAGE_NAME PACKAGE_TARNAME PACKAGE_VERSION PACKAGE_STRING PACKAGE_BUGREPORT exec_prefix prefix program_transform_name bindir sbindir libexecdir datadir sysconfdir sharedstatedir localstatedir libdir includedir oldincludedir infodir mandir build_alias host_alias target_alias DEFS ECHO_C ECHO_N ECHO_T LIBS build build_cpu build_vendor build_os host host_cpu host_vendor host_os EMACS lispdir DEBUGGER_START_FILE TESTSCRIPT PURIFY MALLOC_TARGET MALLOC_SRC MALLOC_LIB MALLOC_LIBRARY MALLOC_LDFLAGS MALLOC_DEP htmldir HELPDIR HELPDIRDEFINE HELPINSTALL HELPSTRINGS CC CFLAGS LDFLAGS CPPFLAGS ac_ct_CC EXEEXT OBJEXT CPP EGREP SIGNAMES_H CC_FOR_BUILD STATIC_LD CFLAGS_FOR_BUILD CPPFLAGS_FOR_BUILD LDFLAGS_FOR_BUILD RL_VERSION RL_MAJOR RL_MINOR READLINE_LIB READLINE_DEP RL_LIBDIR RL_INCLUDEDIR RL_INCLUDE HISTORY_LIB HISTORY_DEP HIST_LIBDIR INSTALL_PROGRAM INSTALL_SCRIPT INSTALL_DATA AR RANLIB ac_ct_RANLIB YACC SET_MAKE MAKE_SHELL SIZE MKINSTALLDIRS USE_NLS MSGFMT GMSGFMT XGETTEXT MSGMERGE ALLOCA GLIBC21 LIBICONV LTLIBICONV INTLBISON BUILD_INCLUDED_LIBINTL USE_INCLUDED_LIBINTL CATOBJEXT DATADIRNAME INSTOBJEXT GENCAT INTLOBJS INTL_LIBTOOL_SUFFIX_PREFIX INTLLIBS LIBINTL LTLIBINTL POSUB LIBOBJS INTL_DEP INTL_INC LIBINTL_H SIGLIST_O TERMCAP_LIB TERMCAP_DEP JOBS_O SHOBJ_CC SHOBJ_CFLAGS SHOBJ_LD SHOBJ_LDFLAGS SHOBJ_XLDFLAGS SHOBJ_LIBS SHOBJ_STATUS PROFILE_FLAGS incdir BUILD_DIR ARFLAGS BASHVERS RELSTATUS DEBUG MALLOC_DEBUG LOCAL_LIBS LOCAL_CFLAGS LOCAL_LDFLAGS LOCAL_DEFS LTLIBOBJS'
ac_subst_files=''
# Initialize some variables set by options.
@@ -4927,6 +4927,27 @@ opennt*|interix*) MAKE_SHELL="$INTERIX_ROOT/bin/sh" ;;
esac
if test x$SIZE = x; then
if test x$ac_tool_prefix = x; then
SIZE=size
else
SIZE=${ac_tool_prefix}size
save_IFS=$IFS ; IFS=:
size_found=0
for dir in $PATH; do
if test -x $dir/$SIZE ; then
size_found=1
break
fi
done
if test $size_found -eq 0; then
SIZE=size
fi
IFS=$save_IFS
fi
fi
cat >>confdefs.h <<\_ACEOF
#define _GNU_SOURCE 1
_ACEOF
@@ -24146,6 +24167,10 @@ case "$srcdir" in
esac
BUILD_DIR=`pwd`
case "$BUILD_DIR" in
*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;;
*) ;;
esac
@@ -24877,6 +24902,7 @@ s,@ac_ct_RANLIB@,$ac_ct_RANLIB,;t t
s,@YACC@,$YACC,;t t
s,@SET_MAKE@,$SET_MAKE,;t t
s,@MAKE_SHELL@,$MAKE_SHELL,;t t
s,@SIZE@,$SIZE,;t t
s,@MKINSTALLDIRS@,$MKINSTALLDIRS,;t t
s,@USE_NLS@,$USE_NLS,;t t
s,@MSGFMT@,$MSGFMT,;t t
+29 -3
View File
@@ -1,11 +1,11 @@
dnl
dnl Configure script for bash-3.0
dnl Configure script for bash-3.1
dnl
dnl report bugs to chet@po.cwru.edu
dnl
dnl Process this file with autoconf to produce a configure script.
# Copyright (C) 1987-2004 Free Software Foundation, Inc.
# Copyright (C) 1987-2005 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -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.172, from autoconf version] AC_ACVERSION)dnl
AC_REVISION([for Bash 3.1, version 3.173, from autoconf version] AC_ACVERSION)dnl
define(bashvers, 3.1)
define(relstatus, devel)
@@ -557,6 +557,28 @@ opennt*|interix*) MAKE_SHELL="$INTERIX_ROOT/bin/sh" ;;
esac
AC_SUBST(MAKE_SHELL)
dnl this is similar to the expanded AC_PROG_RANLIB
if test x$SIZE = x; then
if test x$ac_tool_prefix = x; then
SIZE=size
else
SIZE=${ac_tool_prefix}size
save_IFS=$IFS ; IFS=:
size_found=0
for dir in $PATH; do
if test -x $dir/$SIZE ; then
size_found=1
break
fi
done
if test $size_found -eq 0; then
SIZE=size
fi
IFS=$save_IFS
fi
fi
AC_SUBST(SIZE)
dnl Turn on any extensions available in the GNU C library.
AC_DEFINE(_GNU_SOURCE, 1)
@@ -1004,6 +1026,10 @@ case "$srcdir" in
esac
BUILD_DIR=`pwd`
case "$BUILD_DIR" in
*\ *) BUILD_DIR=`echo "$BUILD_DIR" | sed 's: :\\\\ :g'` ;;
*) ;;
esac
AC_SUBST(PROFILE_FLAGS)
+1 -1
View File
@@ -1039,7 +1039,7 @@ static const struct conf_variable conf_table[] =
#ifdef _PC_MAX_INPUT
{ "MAX_INPUT", PATHCONF, _PC_MAX_INPUT },
#endif
#ifdef _PC_NAMW_MAX
#ifdef _PC_NAME_MAX
{ "NAME_MAX", PATHCONF, _PC_NAME_MAX },
#endif
#ifdef _PC_PATH_MAX
File diff suppressed because it is too large Load Diff
+320 -156
View File
@@ -160,11 +160,15 @@ extern procenv_t wait_intr_buf;
extern int wait_signal_received;
extern WORD_LIST *subst_assign_varlist;
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB };
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
#if 0
/* The number of slots currently allocated to JOBS. */
int job_slots = 0;
#endif
/* The controlling tty for this shell. */
int shell_tty = -1;
@@ -188,11 +192,13 @@ pid_t pipeline_pgrp = (pid_t)0;
int pgrp_pipe[2] = { -1, -1 };
#endif
#if 0
/* The job which is current; i.e. the one that `%+' stands for. */
int current_job = NO_JOB;
/* The previous job; i.e. the one that `%-' stands for. */
int previous_job = NO_JOB;
#endif
/* Last child made by the shell. */
pid_t last_made_pid = NO_PID;
@@ -252,9 +258,12 @@ static int set_job_status_and_cleanup __P((int));
static WAIT raw_job_exit_status __P((int));
static void notify_of_job_status __P((void));
static void reset_job_indices __P((void));
static void cleanup_dead_jobs __P((void));
static int processes_in_job __P((int));
static void realloc_jobs_list __P((void));
static int compact_jobs_list __P((int));
static void discard_pipeline __P((PROCESS *));
static int discard_pipeline __P((PROCESS *));
static void add_process __P((char *, pid_t));
static void print_pipeline __P((PROCESS *, int, int, FILE *));
static void pretty_print_job __P((int, int, FILE *));
@@ -308,8 +317,6 @@ static int jobs_list_frozen;
static char retcode_name_buffer[64];
static long child_max = -1L;
#if !defined (_POSIX_VERSION)
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
@@ -466,49 +473,61 @@ stop_pipeline (async, deferred)
cleanup_dead_jobs ();
if (job_slots == 0)
if (js.j_jobslots == 0)
{
job_slots = JOB_SLOTS;
jobs = (JOB **)xmalloc (job_slots * sizeof (JOB *));
js.j_jobslots = JOB_SLOTS;
jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *));
/* Now blank out these new entries. */
for (i = 0; i < job_slots; i++)
for (i = 0; i < js.j_jobslots; i++)
jobs[i] = (JOB *)NULL;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
/* Scan from the last slot backward, looking for the next free one. */
/* XXX - revisit this interactive assumption */
/* XXX - this way for now */
if (interactive)
{
for (i = job_slots; i; i--)
for (i = js.j_jobslots; i; i--)
if (jobs[i - 1])
break;
}
else
{
/* If we're not interactive, we don't need to monotonically increase
the job number (in fact, we don't care about the job number at all),
so we can simply scan for the first free slot. This helps to keep
us from continuously reallocating the jobs array when running
certain kinds of shell loops, and saves time spent searching. */
for (i = 0; i < job_slots; i++)
#if 0
/* This wraps around, but makes it inconvenient to extend the array */
for (i = js.j_lastj+1; i != js.j_lastj; i++)
{
if (i >= js.j_jobslots)
i = 0;
if (jobs[i] == 0)
break;
}
if (i == js.j_lastj)
i = js.j_jobslots;
#else
/* This doesn't wrap around yet. */
for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++)
if (jobs[i] == 0)
break;
#endif
}
/* Do we need more room? */
/* First try compaction */
if (subshell_environment && interactive_shell && i == job_slots && job_slots >= MAX_JOBS_IN_ARRAY)
if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY)
i = compact_jobs_list (0);
/* If we can't compact, reallocate */
if (i == job_slots)
if (i == js.j_jobslots)
{
job_slots += JOB_SLOTS;
jobs = (JOB **)xrealloc (jobs, ((1 + job_slots) * sizeof (JOB *)));
js.j_jobslots += JOB_SLOTS;
jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *)));
for (j = i; j < job_slots; j++)
for (j = i; j < js.j_jobslots; j++)
jobs[j] = (JOB *)NULL;
}
@@ -516,11 +535,11 @@ stop_pipeline (async, deferred)
if (the_pipeline)
{
register PROCESS *p;
int any_alive, any_stopped;
int any_alive, any_stopped, n;
newjob = (JOB *)xmalloc (sizeof (JOB));
for (p = the_pipeline; p->next != the_pipeline; p = p->next)
for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next)
;
p->next = (PROCESS *)NULL;
newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *);
@@ -559,6 +578,15 @@ stop_pipeline (async, deferred)
jobs[i] = newjob;
if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND))
setjstatus (i);
if (newjob->state == JDEAD)
{
js.c_reaped += n; /* wouldn't have been done since this was not part of a job */
js.j_ndead++;
}
js.c_injobs += n;
js.j_lastj = i;
js.j_njobs++;
}
else
newjob = (JOB *)NULL;
@@ -590,9 +618,47 @@ stop_pipeline (async, deferred)
stop_making_children ();
UNBLOCK_CHILD (oset);
return (current_job);
return (js.j_current);
}
/* Reset the values of js.j_lastj and js.j_firstj after one or both have
been deleted. The caller should check whether js.j_njobs is 0 before
calling this. */
static void
reset_job_indices ()
{
int old;
if (jobs[js.j_firstj] == 0)
{
old = js.j_firstj++;
while (js.j_firstj != old)
{
if (js.j_firstj >= js.j_jobslots)
js.j_firstj = 0;
if (jobs[js.j_firstj])
break;
js.j_firstj++;
}
if (js.j_firstj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
if (jobs[js.j_lastj] == 0)
{
old = js.j_lastj--;
while (js.j_lastj != old)
{
if (js.j_lastj < 0)
js.j_lastj = js.j_jobslots - 1;
if (jobs[js.j_lastj])
break;
js.j_lastj--;
}
if (js.j_lastj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
}
/* Delete all DEAD jobs that the user had received notification about. */
static void
cleanup_dead_jobs ()
@@ -600,84 +666,90 @@ cleanup_dead_jobs ()
register int i;
int os;
if (job_slots == 0 || jobs_list_frozen)
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
QUEUE_SIGCHLD(os);
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
delete_job (i, 0);
}
UNQUEUE_SIGCHLD(os);
}
static int
processes_in_job (job)
{
int nproc;
register PROCESS *p;
nproc = 0;
p = jobs[job]->pipe;
do
{
p = p->next;
nproc++;
}
while (p != jobs[job]->pipe);
return nproc;
}
/* Reallocate and compress the jobs list. This returns with a jobs array
whose size is a multiple of JOB_SLOTS and can hold the current number of
jobs. Heuristics are used to minimize the number of new reallocs. */
static void
realloc_jobs_list ()
{
sigset_t set, oset;
int nsize, i, j;
JOB **nlist;
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
nsize *= JOB_SLOTS;
i = js.j_njobs % JOB_SLOTS;
if (i == 0 || i > (JOB_SLOTS >> 1))
nsize += JOB_SLOTS;
BLOCK_CHILD (set, oset);
nlist = (JOB **) xmalloc (nsize * sizeof (JOB *));
for (i = j = 0; i < js.j_jobslots; i++)
if (jobs[i])
nlist[j++] = jobs[i];
js.j_firstj = 0;
js.j_lastj = (j > 0) ? j - 1: 0;
js.j_jobslots = nsize;
free (jobs);
jobs = nlist;
UNBLOCK_CHILD (oset);
}
/* Compact the jobs list by removing dead jobs. Assumed that we have filled
the jobs array to some predefined maximum. Called when the shell is not
the foreground process (subshell_environment != 0). Returns the first
available slot in the compacted list. If that value is job_slots, then
available slot in the compacted list. If that value is js.j_jobslots, then
the list needs to be reallocated. The jobs array is in new memory if
this returns > 0 and < job_slots. FLAGS is reserved for future use. */
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
static int
compact_jobs_list (flags)
int flags;
{
sigset_t set, oset;
register int i, j;
int nremove, ndel;
JOB **newlist;
if (js.j_jobslots == 0 || jobs_list_frozen)
return js.j_jobslots;
if (job_slots == 0 || jobs_list_frozen)
return job_slots;
reap_dead_jobs ();
realloc_jobs_list ();
if (child_max < 0)
child_max = getmaxchild ();
/* Take out at most a quarter of the jobs in the jobs array, but leave at
least child_max */
nremove = job_slots >> 2;
if ((job_slots - nremove) < child_max)
nremove = job_slots - child_max;
/* need to increase jobs list to at least CHILD_MAX entries */
if (nremove < 0)
return job_slots;
BLOCK_CHILD (set, oset);
for (ndel = i = 0; i < job_slots; i++)
if (jobs[i])
{
if (DEADJOB (i) && (find_last_pid (i, 0) != last_asynchronous_pid))
{
delete_job (i, 0);
ndel++;
if (ndel == nremove)
break;
}
}
if (ndel == 0)
{
UNBLOCK_CHILD (oset);
return job_slots;
}
newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *));
for (i = j = 0; i < job_slots; i++)
if (jobs[i])
newlist[j++] = jobs[i];
ndel = j;
for ( ; j < job_slots; j++)
newlist[j] = (JOB *)NULL;
free (jobs);
jobs = newlist;
UNBLOCK_CHILD (oset);
return ndel;
return (js.j_lastj);
}
/* Delete the job at INDEX from the job list. Must be called
@@ -687,26 +759,42 @@ delete_job (job_index, warn_stopped)
int job_index, warn_stopped;
{
register JOB *temp;
int ndel;
if (job_slots == 0 || jobs_list_frozen)
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
if (job_index == current_job || job_index == previous_job)
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
jobs[job_index] = (JOB *)NULL;
free (temp->wd);
discard_pipeline (temp->pipe);
ndel = discard_pipeline (temp->pipe);
js.c_injobs -= ndel;
if (temp->state == JDEAD)
{
js.c_reaped -= ndel;
if (js.c_reaped < 0)
itrace("delete_job (%d): js.c_reaped (%d) < 0 ndel = %d", job_index, js.c_reaped, ndel);
js.j_ndead--;
}
if (temp->deferred)
dispose_command (temp->deferred);
free (temp);
js.j_njobs--;
if (js.j_njobs == 0)
js.j_firstj = js.j_lastj = 0;
else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0)
reset_job_indices ();
}
/* Must be called with SIGCHLD blocked. */
@@ -716,7 +804,7 @@ nohup_job (job_index)
{
register JOB *temp;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
if (temp = jobs[job_index])
@@ -724,21 +812,26 @@ nohup_job (job_index)
}
/* Get rid of the data structure associated with a process chain. */
static void
static int
discard_pipeline (chain)
register PROCESS *chain;
{
register PROCESS *this, *next;
int n;
this = chain;
n = 0;
do
{
next = this->next;
FREE (this->command);
free (this);
n++;
this = next;
}
while (this != chain);
return n;
}
/* Add this process to the chain being built in the_pipeline.
@@ -821,13 +914,16 @@ map_over_jobs (func, arg1, arg2)
int result;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return 0;
BLOCK_CHILD (set, oset);
for (i = result = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = result = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i])
{
result = (*func)(jobs[i], arg1, arg2, i);
@@ -858,7 +954,8 @@ terminate_stopped_jobs ()
{
register int i;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && STOPPED (i))
{
@@ -875,7 +972,8 @@ hangup_all_jobs ()
{
register int i;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i])
{
@@ -916,7 +1014,7 @@ find_pipeline (pid, running_only, jobp)
/* Return it if we found it. */
if (p->pid == pid)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
if ((running_only && PALIVE(p)) || (running_only == 0))
return (p);
}
@@ -941,8 +1039,11 @@ find_job (pid, running_only)
register int i;
register PROCESS *p;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i])
{
p = jobs[i]->pipe;
@@ -951,7 +1052,7 @@ find_job (pid, running_only)
{
if (p->pid == pid)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
if ((running_only && PALIVE(p)) || (running_only == 0))
return (i);
}
@@ -1215,8 +1316,8 @@ pretty_print_job (job_index, format, stream)
if (format != JLIST_NONINTERACTIVE)
fprintf (stream, "[%d]%c ", job_index + 1,
(job_index == current_job) ? '+':
(job_index == previous_job) ? '-' : ' ');
(job_index == js.j_current) ? '+':
(job_index == js.j_previous) ? '-' : ' ');
if (format == JLIST_NONINTERACTIVE)
format = JLIST_LONG;
@@ -1434,6 +1535,10 @@ make_child (command, async_p)
last_made_pid = pid;
/* keep stats */
js.c_totforked++;
js.c_living++;
/* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case
SIGCHLD remains blocked until all commands in the pipeline have been
created. */
@@ -1663,11 +1768,15 @@ wait_for_background_pids ()
BLOCK_CHILD (set, oset);
/* find first running job; if none running in foreground, break */
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
break;
if (i == job_slots)
}
if (i == js.j_jobslots)
{
UNBLOCK_CHILD (oset);
break;
@@ -1924,7 +2033,10 @@ wait_for (pid)
child->running = PS_DONE;
child->status = 0; /* XXX -- can't find true status */
if (job != NO_JOB)
jobs[job]->state = JDEAD;
{
jobs[job]->state = JDEAD;
js.j_ndead++;
}
}
#endif /* WAITPID_BROKEN */
}
@@ -2009,7 +2121,7 @@ if (job == NO_JOB)
/* If the current job was stopped or killed by a signal, and
the user has requested it, get a possibly new window size */
if (check_window_size && (job == current_job || IS_FOREGROUND (job)))
if (check_window_size && (job == js.j_current || IS_FOREGROUND (job)))
get_new_window_size (0);
}
else
@@ -2166,29 +2278,29 @@ set_current_job (job)
{
int candidate;
if (current_job != job)
if (js.j_current != job)
{
previous_job = current_job;
current_job = job;
js.j_previous = js.j_current;
js.j_current = job;
}
/* First choice for previous_job is the old current_job. */
if (previous_job != current_job &&
previous_job != NO_JOB &&
jobs[previous_job] &&
STOPPED (previous_job))
/* First choice for previous job is the old current job. */
if (js.j_previous != js.j_current &&
js.j_previous != NO_JOB &&
jobs[js.j_previous] &&
STOPPED (js.j_previous))
return;
/* Second choice: Newest stopped job that is older than
the current job. */
candidate = NO_JOB;
if (STOPPED (current_job))
if (STOPPED (js.j_current))
{
candidate = job_last_stopped (current_job);
candidate = job_last_stopped (js.j_current);
if (candidate != NO_JOB)
{
previous_job = candidate;
js.j_previous = candidate;
return;
}
}
@@ -2197,27 +2309,27 @@ set_current_job (job)
the current job and the previous job should be set to the newest running
job, or there are only running jobs and the previous job should be set to
the newest running job older than the current job. We decide on which
alternative to use based on whether or not JOBSTATE(current_job) is
alternative to use based on whether or not JOBSTATE(js.j_current) is
JSTOPPED. */
candidate = RUNNING (current_job) ? job_last_running (current_job)
: job_last_running (job_slots);
candidate = RUNNING (js.j_current) ? job_last_running (js.j_current)
: job_last_running (js.j_jobslots);
if (candidate != NO_JOB)
{
previous_job = candidate;
js.j_previous = candidate;
return;
}
/* There is only a single job, and it is both `+' and `-'. */
previous_job = current_job;
js.j_previous = js.j_current;
}
/* Make current_job be something useful, if it isn't already. */
/* Here's the deal: The newest non-running job should be `+', and the
next-newest non-running job should be `-'. If there is only a single
stopped job, the previous_job is the newest non-running job. If there
stopped job, the js.j_previous is the newest non-running job. If there
are only running jobs, the newest running job is `+' and the
next-newest running job is `-'. Must be called with SIGCHLD blocked. */
@@ -2226,23 +2338,23 @@ reset_current ()
{
int candidate;
if (job_slots && current_job != NO_JOB && jobs[current_job] && STOPPED (current_job))
candidate = current_job;
if (js.j_jobslots && js.j_current != NO_JOB && jobs[js.j_current] && STOPPED (js.j_current))
candidate = js.j_current;
else
{
candidate = NO_JOB;
/* First choice: the previous job. */
if (previous_job != NO_JOB && jobs[previous_job] && STOPPED (previous_job))
candidate = previous_job;
if (js.j_previous != NO_JOB && jobs[js.j_previous] && STOPPED (js.j_previous))
candidate = js.j_previous;
/* Second choice: the most recently stopped job. */
if (candidate == NO_JOB)
candidate = job_last_stopped (job_slots);
candidate = job_last_stopped (js.j_jobslots);
/* Third choice: the newest running job. */
if (candidate == NO_JOB)
candidate = job_last_running (job_slots);
candidate = job_last_running (js.j_jobslots);
}
/* If we found a job to use, then use it. Otherwise, there
@@ -2250,7 +2362,7 @@ reset_current ()
if (candidate != NO_JOB)
set_current_job (candidate);
else
current_job = previous_job = NO_JOB;
js.j_current = js.j_previous = NO_JOB;
}
/* Set up the job structures so we know the job and its processes are
@@ -2324,7 +2436,7 @@ start_job (job, foreground)
if (foreground == 0)
printf ("[%d]%c ", job + 1,
(job == current_job) ? '+': ((job == previous_job) ? '-' : ' '));
(job == js.j_current) ? '+': ((job == js.j_previous) ? '-' : ' '));
do
{
@@ -2540,6 +2652,13 @@ waitchld (wpid, block)
child->status = status;
child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
if (child->running == PS_DONE)
{
js.c_totreaped++;
if (job != NO_JOB)
js.c_reaped++;
}
if (job == NO_JOB)
continue;
@@ -2643,6 +2762,7 @@ set_job_status_and_cleanup (job)
else
{
jobs[job]->state = JDEAD;
js.j_ndead++;
#if 0
if (IS_FOREGROUND (job))
@@ -2832,7 +2952,7 @@ notify_of_job_status ()
sigset_t set, oset;
WAIT s;
if (jobs == 0 || job_slots == 0)
if (jobs == 0 || js.j_jobslots == 0)
return;
if (old_ttou != 0)
@@ -2846,7 +2966,8 @@ notify_of_job_status ()
else
queue_sigchld++;
for (job = 0, dir = (char *)NULL; job < job_slots; job++)
/* XXX could use js.j_firstj here */
for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++)
{
if (jobs[job] && IS_NOTIFIED (job) == 0)
{
@@ -3288,18 +3409,24 @@ delete_all_jobs (running_only)
BLOCK_CHILD (set, oset);
if (job_slots)
/* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */
if (js.j_jobslots)
{
current_job = previous_job = NO_JOB;
js.j_current = js.j_previous = NO_JOB;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
delete_job (i, 1);
}
if (running_only == 0)
{
free ((char *)jobs);
job_slots = 0;
js.j_jobslots = 0;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
}
@@ -3317,9 +3444,10 @@ nohup_all_jobs (running_only)
BLOCK_CHILD (set, oset);
if (job_slots)
if (js.j_jobslots)
{
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
nohup_job (i);
}
@@ -3333,10 +3461,16 @@ count_all_jobs ()
int i, n;
sigset_t set, oset;
/* This really counts all non-dead jobs. */
BLOCK_CHILD (set, oset);
for (i = n = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = n = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB(i) == 0)
n++;
}
UNBLOCK_CHILD (oset);
return n;
}
@@ -3347,14 +3481,18 @@ mark_all_jobs_as_dead ()
register int i;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
BLOCK_CHILD (set, oset);
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i])
jobs[i]->state = JDEAD;
{
jobs[i]->state = JDEAD;
js.j_ndead++;
}
UNBLOCK_CHILD (oset);
}
@@ -3367,10 +3505,10 @@ static void
mark_dead_jobs_as_notified (force)
int force;
{
register int i, ndead;
register int i, ndead, ndeadproc;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
BLOCK_CHILD (set, oset);
@@ -3379,7 +3517,8 @@ mark_dead_jobs_as_notified (force)
around; just run through the array. */
if (force)
{
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
jobs[i]->flags |= J_NOTIFIED;
@@ -3388,24 +3527,35 @@ mark_dead_jobs_as_notified (force)
return;
}
/* Mark enough dead jobs as notified to keep CHILD_MAX jobs left in the
array not marked as notified. */
/* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the
array with the corresponding not marked as notified. */
/* Count the number of dead jobs */
for (i = ndead = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB (i))
ndead++;
{
ndead++;
ndeadproc += processes_in_job (i);
}
}
if (child_max < 0)
child_max = getmaxchild ();
if (child_max < 0)
child_max = DEFAULT_CHILD_MAX;
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
/* Don't do anything if the number of dead jobs is less than CHILD_MAX and
we're not forcing a cleanup. */
if (ndead <= child_max)
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
if (js.c_childmax < 0)
js.c_childmax = DEFAULT_CHILD_MAX;
/* Don't do anything if the number of dead processes is less than CHILD_MAX
and we're not forcing a cleanup. */
if (ndeadproc <= js.c_childmax)
{
UNBLOCK_CHILD (oset);
return;
@@ -3414,14 +3564,28 @@ mark_dead_jobs_as_notified (force)
/* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
the list. This isn't exactly right yet; changes need to be made
to stop_pipeline so we don't mark the newer jobs after we've
created CHILD_MAX slots in the jobs array. */
for (i = 0; i < job_slots; i++)
created CHILD_MAX slots in the jobs array. This needs to be
integrated with a way to keep the jobs array from growing without
bound. Maybe we wrap back around to 0 after we reach some max
limit, and there are sufficient job slots free (keep track of total
size of jobs array (js.j_jobslots) and running count of number of jobs
in jobs array. Then keep a job index corresponding to the `oldest job'
and start this loop there, wrapping around as necessary. In effect,
we turn the list into a circular buffer. */
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
{
jobs[i]->flags |= J_NOTIFIED;
if (--ndead <= child_max)
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
/* If marking this job as notified would drop us down below
child_max, don't mark it so we can keep at least child_max
statuses. XXX -- need to check what Posix actually says
about keeping statuses. */
if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax)
break;
jobs[i]->flags |= J_NOTIFIED;
}
}
+3699
View File
File diff suppressed because it is too large Load Diff
+3614
View File
File diff suppressed because it is too large Load Diff
+329 -160
View File
@@ -3,7 +3,7 @@
/* This file works with both POSIX and BSD systems. It implements job
control. */
/* Copyright (C) 1989-2003 Free Software Foundation, Inc.
/* Copyright (C) 1989-2005 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -160,11 +160,15 @@ extern procenv_t wait_intr_buf;
extern int wait_signal_received;
extern WORD_LIST *subst_assign_varlist;
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB };
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
#if 0
/* The number of slots currently allocated to JOBS. */
int job_slots = 0;
#endif
/* The controlling tty for this shell. */
int shell_tty = -1;
@@ -188,11 +192,13 @@ pid_t pipeline_pgrp = (pid_t)0;
int pgrp_pipe[2] = { -1, -1 };
#endif
#if 0
/* The job which is current; i.e. the one that `%+' stands for. */
int current_job = NO_JOB;
/* The previous job; i.e. the one that `%-' stands for. */
int previous_job = NO_JOB;
#endif
/* Last child made by the shell. */
pid_t last_made_pid = NO_PID;
@@ -252,9 +258,12 @@ static int set_job_status_and_cleanup __P((int));
static WAIT raw_job_exit_status __P((int));
static void notify_of_job_status __P((void));
static void reset_job_indices __P((void));
static void cleanup_dead_jobs __P((void));
static int processes_in_job __P((int));
static void realloc_jobs_list __P((void));
static int compact_jobs_list __P((int));
static void discard_pipeline __P((PROCESS *));
static int discard_pipeline __P((PROCESS *));
static void add_process __P((char *, pid_t));
static void print_pipeline __P((PROCESS *, int, int, FILE *));
static void pretty_print_job __P((int, int, FILE *));
@@ -308,8 +317,6 @@ static int jobs_list_frozen;
static char retcode_name_buffer[64];
static long child_max = -1L;
#if !defined (_POSIX_VERSION)
/* These are definitions to map POSIX 1003.1 functions onto existing BSD
@@ -466,49 +473,61 @@ stop_pipeline (async, deferred)
cleanup_dead_jobs ();
if (job_slots == 0)
if (js.j_jobslots == 0)
{
job_slots = JOB_SLOTS;
jobs = (JOB **)xmalloc (job_slots * sizeof (JOB *));
js.j_jobslots = JOB_SLOTS;
jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *));
/* Now blank out these new entries. */
for (i = 0; i < job_slots; i++)
for (i = 0; i < js.j_jobslots; i++)
jobs[i] = (JOB *)NULL;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
/* Scan from the last slot backward, looking for the next free one. */
/* XXX - revisit this interactive assumption */
/* XXX - this way for now */
if (interactive)
{
for (i = job_slots; i; i--)
for (i = js.j_jobslots; i; i--)
if (jobs[i - 1])
break;
}
else
{
/* If we're not interactive, we don't need to monotonically increase
the job number (in fact, we don't care about the job number at all),
so we can simply scan for the first free slot. This helps to keep
us from continuously reallocating the jobs array when running
certain kinds of shell loops, and saves time spent searching. */
for (i = 0; i < job_slots; i++)
#if 0
/* This wraps around, but makes it inconvenient to extend the array */
for (i = js.j_lastj+1; i != js.j_lastj; i++)
{
if (i >= js.j_jobslots)
i = 0;
if (jobs[i] == 0)
break;
}
if (i == js.j_lastj)
i = js.j_jobslots;
#else
/* This doesn't wrap around yet. */
for (i = js.j_lastj ? js.j_lastj + 1 : js.j_lastj; i < js.j_jobslots; i++)
if (jobs[i] == 0)
break;
#endif
}
/* Do we need more room? */
/* First try compaction */
if (subshell_environment && interactive_shell && i == job_slots && job_slots >= MAX_JOBS_IN_ARRAY)
if ((interactive_shell == 0 || subshell_environment) && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY)
i = compact_jobs_list (0);
/* If we can't compact, reallocate */
if (i == job_slots)
if (i == js.j_jobslots)
{
job_slots += JOB_SLOTS;
jobs = (JOB **)xrealloc (jobs, ((1 + job_slots) * sizeof (JOB *)));
js.j_jobslots += JOB_SLOTS;
jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *)));
for (j = i; j < job_slots; j++)
for (j = i; j < js.j_jobslots; j++)
jobs[j] = (JOB *)NULL;
}
@@ -516,11 +535,11 @@ stop_pipeline (async, deferred)
if (the_pipeline)
{
register PROCESS *p;
int any_alive, any_stopped;
int any_alive, any_stopped, n;
newjob = (JOB *)xmalloc (sizeof (JOB));
for (p = the_pipeline; p->next != the_pipeline; p = p->next)
for (n = 1, p = the_pipeline; p->next != the_pipeline; n++, p = p->next)
;
p->next = (PROCESS *)NULL;
newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *);
@@ -559,6 +578,16 @@ stop_pipeline (async, deferred)
jobs[i] = newjob;
if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND))
setjstatus (i);
if (newjob->state == JDEAD)
{
js.c_reaped += n; /* wouldn't have been done since this was not part of a job */
itrace("stop_pipeline: job %d: js.c_reaped (%d) just added (%d)", i, js.c_reaped, n);
js.j_ndead++;
}
js.c_injobs += n;
js.j_lastj = i;
js.j_njobs++;
}
else
newjob = (JOB *)NULL;
@@ -590,9 +619,47 @@ stop_pipeline (async, deferred)
stop_making_children ();
UNBLOCK_CHILD (oset);
return (current_job);
return (js.j_current);
}
/* Reset the values of js.j_lastj and js.j_firstj after one or both have
been deleted. The caller should check whether js.j_njobs is 0 before
calling this. */
static void
reset_job_indices ()
{
int old;
if (jobs[js.j_firstj] == 0)
{
old = js.j_firstj++;
while (js.j_firstj != old)
{
if (js.j_firstj >= js.j_jobslots)
js.j_firstj = 0;
if (jobs[js.j_firstj])
break;
js.j_firstj++;
}
if (js.j_firstj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
if (jobs[js.j_lastj] == 0)
{
old = js.j_lastj--;
while (js.j_lastj != old)
{
if (js.j_lastj < 0)
js.j_lastj = js.j_jobslots - 1;
if (jobs[js.j_lastj])
break;
js.j_lastj--;
}
if (js.j_lastj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
}
/* Delete all DEAD jobs that the user had received notification about. */
static void
cleanup_dead_jobs ()
@@ -600,84 +667,90 @@ cleanup_dead_jobs ()
register int i;
int os;
if (job_slots == 0 || jobs_list_frozen)
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
QUEUE_SIGCHLD(os);
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("cleanup_dead_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB (i) && IS_NOTIFIED (i))
delete_job (i, 0);
}
UNQUEUE_SIGCHLD(os);
}
static int
processes_in_job (job)
{
int nproc;
register PROCESS *p;
nproc = 0;
p = jobs[job]->pipe;
do
{
p = p->next;
nproc++;
}
while (p != jobs[job]->pipe);
return nproc;
}
/* Reallocate and compress the jobs list. This returns with a jobs array
whose size is a multiple of JOB_SLOTS and can hold the current number of
jobs. Heuristics are used to minimize the number of new reallocs. */
static void
realloc_jobs_list ()
{
sigset_t set, oset;
int nsize, i, j;
JOB **nlist;
nsize = ((js.j_njobs + JOB_SLOTS - 1) / JOB_SLOTS);
nsize *= JOB_SLOTS;
i = js.j_njobs % JOB_SLOTS;
if (i == 0 || i > (JOB_SLOTS >> 1))
nsize += JOB_SLOTS;
BLOCK_CHILD (set, oset);
nlist = (JOB **) xmalloc (nsize * sizeof (JOB *));
for (i = j = 0; i < js.j_jobslots; i++)
if (jobs[i])
nlist[j++] = jobs[i];
js.j_firstj = 0;
js.j_lastj = (j > 0) ? j - 1: 0;
js.j_jobslots = nsize;
free (jobs);
jobs = nlist;
UNBLOCK_CHILD (oset);
}
/* Compact the jobs list by removing dead jobs. Assumed that we have filled
the jobs array to some predefined maximum. Called when the shell is not
the foreground process (subshell_environment != 0). Returns the first
available slot in the compacted list. If that value is job_slots, then
available slot in the compacted list. If that value is js.j_jobslots, then
the list needs to be reallocated. The jobs array is in new memory if
this returns > 0 and < job_slots. FLAGS is reserved for future use. */
this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */
static int
compact_jobs_list (flags)
int flags;
{
sigset_t set, oset;
register int i, j;
int nremove, ndel;
JOB **newlist;
if (js.j_jobslots == 0 || jobs_list_frozen)
return js.j_jobslots;
if (job_slots == 0 || jobs_list_frozen)
return job_slots;
reap_dead_jobs ();
realloc_jobs_list ();
if (child_max < 0)
child_max = getmaxchild ();
/* Take out at most a quarter of the jobs in the jobs array, but leave at
least child_max */
nremove = job_slots >> 2;
if ((job_slots - nremove) < child_max)
nremove = job_slots - child_max;
/* need to increase jobs list to at least CHILD_MAX entries */
if (nremove < 0)
return job_slots;
BLOCK_CHILD (set, oset);
for (ndel = i = 0; i < job_slots; i++)
if (jobs[i])
{
if (DEADJOB (i) && (find_last_pid (i, 0) != last_asynchronous_pid))
{
delete_job (i, 0);
ndel++;
if (ndel == nremove)
break;
}
}
if (ndel == 0)
{
UNBLOCK_CHILD (oset);
return job_slots;
}
newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *));
for (i = j = 0; i < job_slots; i++)
if (jobs[i])
newlist[j++] = jobs[i];
ndel = j;
for ( ; j < job_slots; j++)
newlist[j] = (JOB *)NULL;
free (jobs);
jobs = newlist;
UNBLOCK_CHILD (oset);
return ndel;
return (js.j_lastj);
}
/* Delete the job at INDEX from the job list. Must be called
@@ -687,26 +760,42 @@ delete_job (job_index, warn_stopped)
int job_index, warn_stopped;
{
register JOB *temp;
int ndel;
if (job_slots == 0 || jobs_list_frozen)
if (js.j_jobslots == 0 || jobs_list_frozen)
return;
if (warn_stopped && subshell_environment == 0 && STOPPED (job_index))
internal_warning (_("deleting stopped job %d with process group %ld"), job_index+1, (long)jobs[job_index]->pgrp);
temp = jobs[job_index];
if (job_index == current_job || job_index == previous_job)
if (job_index == js.j_current || job_index == js.j_previous)
reset_current ();
jobs[job_index] = (JOB *)NULL;
free (temp->wd);
discard_pipeline (temp->pipe);
ndel = discard_pipeline (temp->pipe);
js.c_injobs -= ndel;
if (temp->state == JDEAD)
{
js.c_reaped -= ndel;
if (js.c_reaped < 0)
itrace("delete_job (%d): js.c_reaped (%d) < 0 ndel = %d", job_index, js.c_reaped, ndel);
js.j_ndead--;
}
if (temp->deferred)
dispose_command (temp->deferred);
free (temp);
js.j_njobs--;
if (js.j_njobs == 0)
js.j_firstj = js.j_lastj = 0;
else if (jobs[js.j_firstj] == 0 || jobs[js.j_lastj] == 0)
reset_job_indices ();
}
/* Must be called with SIGCHLD blocked. */
@@ -716,7 +805,7 @@ nohup_job (job_index)
{
register JOB *temp;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
if (temp = jobs[job_index])
@@ -724,21 +813,26 @@ nohup_job (job_index)
}
/* Get rid of the data structure associated with a process chain. */
static void
static int
discard_pipeline (chain)
register PROCESS *chain;
{
register PROCESS *this, *next;
int n;
this = chain;
n = 0;
do
{
next = this->next;
FREE (this->command);
free (this);
n++;
this = next;
}
while (this != chain);
return n;
}
/* Add this process to the chain being built in the_pipeline.
@@ -821,13 +915,16 @@ map_over_jobs (func, arg1, arg2)
int result;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return 0;
BLOCK_CHILD (set, oset);
for (i = result = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = result = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("map_over_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i])
{
result = (*func)(jobs[i], arg1, arg2, i);
@@ -858,7 +955,8 @@ terminate_stopped_jobs ()
{
register int i;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && STOPPED (i))
{
@@ -875,7 +973,8 @@ hangup_all_jobs ()
{
register int i;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i])
{
@@ -916,7 +1015,7 @@ find_pipeline (pid, running_only, jobp)
/* Return it if we found it. */
if (p->pid == pid)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
if ((running_only && PALIVE(p)) || (running_only == 0))
return (p);
}
@@ -941,8 +1040,11 @@ find_job (pid, running_only)
register int i;
register PROCESS *p;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("find_job: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i])
{
p = jobs[i]->pipe;
@@ -951,7 +1053,7 @@ find_job (pid, running_only)
{
if (p->pid == pid)
{
if ((running_only && PRUNNING(p)) || (running_only == 0))
if ((running_only && PALIVE(p)) || (running_only == 0))
return (i);
}
@@ -1215,8 +1317,8 @@ pretty_print_job (job_index, format, stream)
if (format != JLIST_NONINTERACTIVE)
fprintf (stream, "[%d]%c ", job_index + 1,
(job_index == current_job) ? '+':
(job_index == previous_job) ? '-' : ' ');
(job_index == js.j_current) ? '+':
(job_index == js.j_previous) ? '-' : ' ');
if (format == JLIST_NONINTERACTIVE)
format = JLIST_LONG;
@@ -1434,6 +1536,10 @@ make_child (command, async_p)
last_made_pid = pid;
/* keep stats */
js.c_totforked++;
js.c_living++;
/* Unblock SIGINT and SIGCHLD unless creating a pipeline, in which case
SIGCHLD remains blocked until all commands in the pipeline have been
created. */
@@ -1663,11 +1769,15 @@ wait_for_background_pids ()
BLOCK_CHILD (set, oset);
/* find first running job; if none running in foreground, break */
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("wait_for_background_pids: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
break;
if (i == job_slots)
}
if (i == js.j_jobslots)
{
UNBLOCK_CHILD (oset);
break;
@@ -1924,7 +2034,10 @@ wait_for (pid)
child->running = PS_DONE;
child->status = 0; /* XXX -- can't find true status */
if (job != NO_JOB)
jobs[job]->state = JDEAD;
{
jobs[job]->state = JDEAD;
js.j_ndead++;
}
}
#endif /* WAITPID_BROKEN */
}
@@ -1947,9 +2060,9 @@ wait_for (pid)
last_command_exit_signal = (job != NO_JOB) ? job_exit_signal (job)
: process_exit_signal (child->status);
/* XXX */
if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status))
termination_state = 128 + WSTOPSIG (child->status);
/* XXX */
if ((job != NO_JOB && JOBSTATE (job) == JSTOPPED) || WIFSTOPPED (child->status))
termination_state = 128 + WSTOPSIG (child->status);
if (job == NO_JOB || IS_JOBCONTROL (job))
{
@@ -2009,7 +2122,7 @@ if (job == NO_JOB)
/* If the current job was stopped or killed by a signal, and
the user has requested it, get a possibly new window size */
if (check_window_size && (job == current_job || IS_FOREGROUND (job)))
if (check_window_size && (job == js.j_current || IS_FOREGROUND (job)))
get_new_window_size (0);
}
else
@@ -2166,29 +2279,29 @@ set_current_job (job)
{
int candidate;
if (current_job != job)
if (js.j_current != job)
{
previous_job = current_job;
current_job = job;
js.j_previous = js.j_current;
js.j_current = job;
}
/* First choice for previous_job is the old current_job. */
if (previous_job != current_job &&
previous_job != NO_JOB &&
jobs[previous_job] &&
STOPPED (previous_job))
/* First choice for previous job is the old current job. */
if (js.j_previous != js.j_current &&
js.j_previous != NO_JOB &&
jobs[js.j_previous] &&
STOPPED (js.j_previous))
return;
/* Second choice: Newest stopped job that is older than
the current job. */
candidate = NO_JOB;
if (STOPPED (current_job))
if (STOPPED (js.j_current))
{
candidate = job_last_stopped (current_job);
candidate = job_last_stopped (js.j_current);
if (candidate != NO_JOB)
{
previous_job = candidate;
js.j_previous = candidate;
return;
}
}
@@ -2197,27 +2310,27 @@ set_current_job (job)
the current job and the previous job should be set to the newest running
job, or there are only running jobs and the previous job should be set to
the newest running job older than the current job. We decide on which
alternative to use based on whether or not JOBSTATE(current_job) is
alternative to use based on whether or not JOBSTATE(js.j_current) is
JSTOPPED. */
candidate = RUNNING (current_job) ? job_last_running (current_job)
: job_last_running (job_slots);
candidate = RUNNING (js.j_current) ? job_last_running (js.j_current)
: job_last_running (js.j_jobslots);
if (candidate != NO_JOB)
{
previous_job = candidate;
js.j_previous = candidate;
return;
}
/* There is only a single job, and it is both `+' and `-'. */
previous_job = current_job;
js.j_previous = js.j_current;
}
/* Make current_job be something useful, if it isn't already. */
/* Here's the deal: The newest non-running job should be `+', and the
next-newest non-running job should be `-'. If there is only a single
stopped job, the previous_job is the newest non-running job. If there
stopped job, the js.j_previous is the newest non-running job. If there
are only running jobs, the newest running job is `+' and the
next-newest running job is `-'. Must be called with SIGCHLD blocked. */
@@ -2226,23 +2339,23 @@ reset_current ()
{
int candidate;
if (job_slots && current_job != NO_JOB && jobs[current_job] && STOPPED (current_job))
candidate = current_job;
if (js.j_jobslots && js.j_current != NO_JOB && jobs[js.j_current] && STOPPED (js.j_current))
candidate = js.j_current;
else
{
candidate = NO_JOB;
/* First choice: the previous job. */
if (previous_job != NO_JOB && jobs[previous_job] && STOPPED (previous_job))
candidate = previous_job;
if (js.j_previous != NO_JOB && jobs[js.j_previous] && STOPPED (js.j_previous))
candidate = js.j_previous;
/* Second choice: the most recently stopped job. */
if (candidate == NO_JOB)
candidate = job_last_stopped (job_slots);
candidate = job_last_stopped (js.j_jobslots);
/* Third choice: the newest running job. */
if (candidate == NO_JOB)
candidate = job_last_running (job_slots);
candidate = job_last_running (js.j_jobslots);
}
/* If we found a job to use, then use it. Otherwise, there
@@ -2250,7 +2363,7 @@ reset_current ()
if (candidate != NO_JOB)
set_current_job (candidate);
else
current_job = previous_job = NO_JOB;
js.j_current = js.j_previous = NO_JOB;
}
/* Set up the job structures so we know the job and its processes are
@@ -2324,7 +2437,7 @@ start_job (job, foreground)
if (foreground == 0)
printf ("[%d]%c ", job + 1,
(job == current_job) ? '+': ((job == previous_job) ? '-' : ' '));
(job == js.j_current) ? '+': ((job == js.j_previous) ? '-' : ' '));
do
{
@@ -2540,6 +2653,16 @@ waitchld (wpid, block)
child->status = status;
child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE;
if (child->running == PS_DONE)
{
js.c_totreaped++;
if (job != NO_JOB)
{
js.c_reaped++;
itrace("waitchld: job %d js.c_reaped++ = %d", job, js.c_reaped);
}
}
if (job == NO_JOB)
continue;
@@ -2643,6 +2766,7 @@ set_job_status_and_cleanup (job)
else
{
jobs[job]->state = JDEAD;
js.j_ndead++;
#if 0
if (IS_FOREGROUND (job))
@@ -2832,7 +2956,7 @@ notify_of_job_status ()
sigset_t set, oset;
WAIT s;
if (jobs == 0 || job_slots == 0)
if (jobs == 0 || js.j_jobslots == 0)
return;
if (old_ttou != 0)
@@ -2846,7 +2970,8 @@ notify_of_job_status ()
else
queue_sigchld++;
for (job = 0, dir = (char *)NULL; job < job_slots; job++)
/* XXX could use js.j_firstj here */
for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++)
{
if (jobs[job] && IS_NOTIFIED (job) == 0)
{
@@ -3288,18 +3413,24 @@ delete_all_jobs (running_only)
BLOCK_CHILD (set, oset);
if (job_slots)
/* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */
if (js.j_jobslots)
{
current_job = previous_job = NO_JOB;
js.j_current = js.j_previous = NO_JOB;
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("delete_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
delete_job (i, 1);
}
if (running_only == 0)
{
free ((char *)jobs);
job_slots = 0;
js.j_jobslots = 0;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
}
@@ -3317,9 +3448,10 @@ nohup_all_jobs (running_only)
BLOCK_CHILD (set, oset);
if (job_slots)
if (js.j_jobslots)
{
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i))))
nohup_job (i);
}
@@ -3333,10 +3465,16 @@ count_all_jobs ()
int i, n;
sigset_t set, oset;
/* This really counts all non-dead jobs. */
BLOCK_CHILD (set, oset);
for (i = n = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = n = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("count_all_jobs: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB(i) == 0)
n++;
}
UNBLOCK_CHILD (oset);
return n;
}
@@ -3347,14 +3485,18 @@ mark_all_jobs_as_dead ()
register int i;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
BLOCK_CHILD (set, oset);
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i])
jobs[i]->state = JDEAD;
{
jobs[i]->state = JDEAD;
js.j_ndead++;
}
UNBLOCK_CHILD (oset);
}
@@ -3367,10 +3509,10 @@ static void
mark_dead_jobs_as_notified (force)
int force;
{
register int i, ndead;
register int i, ndead, ndeadproc;
sigset_t set, oset;
if (job_slots == 0)
if (js.j_jobslots == 0)
return;
BLOCK_CHILD (set, oset);
@@ -3379,7 +3521,8 @@ mark_dead_jobs_as_notified (force)
around; just run through the array. */
if (force)
{
for (i = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
jobs[i]->flags |= J_NOTIFIED;
@@ -3388,24 +3531,35 @@ mark_dead_jobs_as_notified (force)
return;
}
/* Mark enough dead jobs as notified to keep CHILD_MAX jobs left in the
array not marked as notified. */
/* Mark enough dead jobs as notified to keep CHILD_MAX processes left in the
array with the corresponding not marked as notified. */
/* Count the number of dead jobs */
for (i = ndead = 0; i < job_slots; i++)
/* XXX could use js.j_firstj here */
for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
{
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
if (jobs[i] && DEADJOB (i))
ndead++;
{
ndead++;
ndeadproc += processes_in_job (i);
}
}
if (child_max < 0)
child_max = getmaxchild ();
if (child_max < 0)
child_max = DEFAULT_CHILD_MAX;
if (ndeadproc != js.c_reaped)
itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped);
if (ndead != js.j_ndead)
itrace("mark_dead_jobs_as_notified: ndead (%d) != js.j_ndead (%d)", ndead, js.j_ndead);
if (js.c_childmax < 0)
js.c_childmax = getmaxchild ();
if (js.c_childmax < 0)
js.c_childmax = DEFAULT_CHILD_MAX;
/* Don't do anything if the number of dead jobs is less than CHILD_MAX and
we're not forcing a cleanup. */
if (ndead <= child_max)
itrace("mark_dead_jobs_as_notified: child_max = %d ndead = %d ndeadproc = %d", js.c_childmax, ndead, ndeadproc);
/* Don't do anything if the number of dead processes is less than CHILD_MAX
and we're not forcing a cleanup. */
if (ndeadproc <= js.c_childmax)
{
UNBLOCK_CHILD (oset);
return;
@@ -3414,14 +3568,29 @@ mark_dead_jobs_as_notified (force)
/* Mark enough dead jobs as notified that we keep CHILD_MAX jobs in
the list. This isn't exactly right yet; changes need to be made
to stop_pipeline so we don't mark the newer jobs after we've
created CHILD_MAX slots in the jobs array. */
for (i = 0; i < job_slots; i++)
created CHILD_MAX slots in the jobs array. This needs to be
integrated with a way to keep the jobs array from growing without
bound. Maybe we wrap back around to 0 after we reach some max
limit, and there are sufficient job slots free (keep track of total
size of jobs array (js.j_jobslots) and running count of number of jobs
in jobs array. Then keep a job index corresponding to the `oldest job'
and start this loop there, wrapping around as necessary. In effect,
we turn the list into a circular buffer. */
/* XXX could use js.j_firstj here */
for (i = 0; i < js.j_jobslots; i++)
{
if (jobs[i] && DEADJOB (i) && (interactive_shell || (find_last_pid (i, 0) != last_asynchronous_pid)))
{
jobs[i]->flags |= J_NOTIFIED;
if (--ndead <= child_max)
if (i < js.j_firstj && jobs[i])
itrace("mark_dead_jobs_as_notified: job %d non-null before js.j_firstj (%d)", i, js.j_firstj);
/* If marking this job as notified would drop us down below
child_max, don't mark it so we can keep at least child_max
statuses. XXX -- need to check what Posix actually says
about keeping statuses. */
if ((ndeadproc -= processes_in_job (i)) <= js.c_childmax)
break;
jobs[i]->flags |= J_NOTIFIED;
itrace("marking job %d as notified", i);
}
}
+31 -2
View File
@@ -58,23 +58,29 @@ typedef struct process {
} PROCESS;
/* PRUNNING really means `not exited' */
#define PRUNNING(p) ((p)->running || WIFSTOPPED((p)->status))
#define PALIVE(p) ((p)->running || WIFSTOPPED((p)->status))
#define PSTOPPED(p) (WIFSTOPPED((p)->status))
#define PDEADPROC(p) ((p)->running == PS_DONE)
#define get_job_by_jid(ind) (jobs[(ind)])
/* A description of a pipeline's state. */
typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define JOBSTATE(job) (jobs[(job)]->state)
#define JOBSTATE(job) (jobs[(job)]->state)
#define J_JOBSTATE(j) ((j)->state)
#define STOPPED(j) (jobs[(j)]->state == JSTOPPED)
#define RUNNING(j) (jobs[(j)]->state == JRUNNING)
#define DEADJOB(j) (jobs[(j)]->state == JDEAD)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || jobs[(j)] == 0)
/* Values for the FLAGS field in the JOB struct below. */
#define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */
#define J_NOTIFIED 0x02 /* Non-zero if already notified about job state. */
#define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */
#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */
#define J_STATSAVED 0x10 /* A process in this job had had status saved via $! */
#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0)
#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0)
@@ -93,6 +99,27 @@ typedef struct job {
#endif /* JOB_CONTROL */
} JOB;
struct jobstats {
/* limits */
long c_childmax;
/* child process statistics */
int c_living; /* running or stopped child processes */
int c_reaped; /* exited child processes still in jobs list */
int c_injobs; /* total number of child processes in jobs list */
/* child process totals */
int c_totforked; /* total number of children this shell has forked */
int c_totreaped; /* total number of children this shell has reaped */
/* job counters and indices */
int j_jobslots; /* total size of jobs array */
int j_lastj; /* last (newest) job allocated */
int j_firstj; /* first (oldest) job allocated */
int j_njobs; /* number of non-NULL jobs in jobs array */
int j_ndead; /* number of JDEAD jobs in jobs array */
/* */
int j_current; /* current job */
int j_previous; /* previous job */
};
#define NO_JOB -1 /* An impossible job array index. */
#define DUP_JOB -2 /* A possible return value for get_job_spec (). */
#define BAD_JOBSPEC -3 /* Bad syntax for job spec. */
@@ -106,6 +133,8 @@ extern pid_t fork (), getpid (), getpgrp ();
#endif /* !HAVE_UNISTD_H */
/* Stuff from the jobs.c file. */
extern struct jobstats js;
extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp;
extern pid_t last_made_pid, last_asynchronous_pid;
extern int current_job, previous_job;
+211
View File
@@ -0,0 +1,211 @@
/* jobs.h -- structures and stuff used by the jobs.c file. */
/* Copyright (C) 1993-2004 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. */
#if !defined (_JOBS_H_)
# define _JOBS_H_
#include "quit.h"
#include "siglist.h"
#include "stdc.h"
#include "posixwait.h"
/* Defines controlling the fashion in which jobs are listed. */
#define JLIST_STANDARD 0
#define JLIST_LONG 1
#define JLIST_PID_ONLY 2
#define JLIST_CHANGED_ONLY 3
#define JLIST_NONINTERACTIVE 4
/* I looked it up. For pretty_print_job (). The real answer is 24. */
#define LONGEST_SIGNAL_DESC 24
/* We keep an array of jobs. Each entry in the array is a linked list
of processes that are piped together. The first process encountered is
the group leader. */
/* Values for the `running' field of a struct process. */
#define PS_DONE 0
#define PS_RUNNING 1
#define PS_STOPPED 2
/* Each child of the shell is remembered in a STRUCT PROCESS. A chain of
such structures is a pipeline. The chain is circular. */
typedef struct process {
struct process *next; /* Next process in the pipeline. A circular chain. */
pid_t pid; /* Process ID. */
WAIT status; /* The status of this command as returned by wait. */
int running; /* Non-zero if this process is running. */
char *command; /* The particular program that is running. */
} PROCESS;
/* PRUNNING really means `not exited' */
#define PALIVE(p) ((p)->running || WIFSTOPPED((p)->status))
#define PSTOPPED(p) (WIFSTOPPED((p)->status))
#define PDEADPROC(p) ((p)->running == PS_DONE)
#define get_job_by_jid(ind) (jobs[(ind)])
/* A description of a pipeline's state. */
typedef enum { JRUNNING, JSTOPPED, JDEAD, JMIXED } JOB_STATE;
#define JOBSTATE(job) (jobs[(job)]->state)
#define J_JOBSTATE(j) ((j)->state)
#define STOPPED(j) (jobs[(j)]->state == JSTOPPED)
#define RUNNING(j) (jobs[(j)]->state == JRUNNING)
#define DEADJOB(j) (jobs[(j)]->state == JDEAD)
#define INVALID_JOB(j) ((j) < 0 || (j) >= js.j_jobslots || jobs[(j)] == 0)
/* Values for the FLAGS field in the JOB struct below. */
#define J_FOREGROUND 0x01 /* Non-zero if this is running in the foreground. */
#define J_NOTIFIED 0x02 /* Non-zero if already notified about job state. */
#define J_JOBCONTROL 0x04 /* Non-zero if this job started under job control. */
#define J_NOHUP 0x08 /* Don't send SIGHUP to job if shell gets SIGHUP. */
#define J_STATSAVED 0x10 /* A process in this job had had status saved via $! */
#define IS_FOREGROUND(j) ((jobs[j]->flags & J_FOREGROUND) != 0)
#define IS_NOTIFIED(j) ((jobs[j]->flags & J_NOTIFIED) != 0)
#define IS_JOBCONTROL(j) ((jobs[j]->flags & J_JOBCONTROL) != 0)
typedef struct job {
char *wd; /* The working directory at time of invocation. */
PROCESS *pipe; /* The pipeline of processes that make up this job. */
pid_t pgrp; /* The process ID of the process group (necessary). */
JOB_STATE state; /* The state that this job is in. */
int flags; /* Flags word: J_NOTIFIED, J_FOREGROUND, or J_JOBCONTROL. */
#if defined (JOB_CONTROL)
COMMAND *deferred; /* Commands that will execute when this job is done. */
sh_vptrfunc_t *j_cleanup; /* Cleanup function to call when job marked JDEAD */
PTR_T cleanarg; /* Argument passed to (*j_cleanup)() */
#endif /* JOB_CONTROL */
} JOB;
struct jobstats {
/* limits */
long c_childmax;
/* child process statistics */
int c_living; /* running or stopped child processes */
int c_reaped; /* exited child processes still in jobs list */
int c_injobs; /* total number of child processes in jobs list */
/* child process totals */
int c_totforked; /* total number of children this shell has forked */
int c_totreaped; /* total number of children this shell has reaped */
/* job counters and indices */
int j_jobslots; /* total size of jobs array */
int j_lastj; /* last (newest) job allocated */
int j_firstj; /* first (oldest) job allocated */
int j_njobs; /* number of non-NULL jobs in jobs array */
/* */
int j_current; /* current job */
int j_previous; /* previous job */
};
#define NO_JOB -1 /* An impossible job array index. */
#define DUP_JOB -2 /* A possible return value for get_job_spec (). */
#define BAD_JOBSPEC -3 /* Bad syntax for job spec. */
/* A value which cannot be a process ID. */
#define NO_PID (pid_t)-1
/* System calls. */
#if !defined (HAVE_UNISTD_H)
extern pid_t fork (), getpid (), getpgrp ();
#endif /* !HAVE_UNISTD_H */
/* Stuff from the jobs.c file. */
extern struct jobstats js;
extern pid_t original_pgrp, shell_pgrp, pipeline_pgrp;
extern pid_t last_made_pid, last_asynchronous_pid;
extern int current_job, previous_job;
extern int asynchronous_notification;
extern JOB **jobs;
extern int job_slots;
extern void making_children __P((void));
extern void stop_making_children __P((void));
extern void cleanup_the_pipeline __P((void));
extern void save_pipeline __P((int));
extern void restore_pipeline __P((int));
extern void start_pipeline __P((void));
extern int stop_pipeline __P((int, COMMAND *));
extern void delete_job __P((int, int));
extern void nohup_job __P((int));
extern void delete_all_jobs __P((int));
extern void nohup_all_jobs __P((int));
extern int count_all_jobs __P((void));
extern void terminate_current_pipeline __P((void));
extern void terminate_stopped_jobs __P((void));
extern void hangup_all_jobs __P((void));
extern void kill_current_pipeline __P((void));
#if defined (__STDC__) && defined (pid_t)
extern int get_job_by_pid __P((int, int));
extern void describe_pid __P((int));
#else
extern int get_job_by_pid __P((pid_t, int));
extern void describe_pid __P((pid_t));
#endif
extern void list_one_job __P((JOB *, int, int, int));
extern void list_all_jobs __P((int));
extern void list_stopped_jobs __P((int));
extern void list_running_jobs __P((int));
extern pid_t make_child __P((char *, int));
extern int get_tty_state __P((void));
extern int set_tty_state __P((void));
extern int wait_for_single_pid __P((pid_t));
extern void wait_for_background_pids __P((void));
extern int wait_for __P((pid_t));
extern int wait_for_job __P((int));
extern void notify_and_cleanup __P((void));
extern void reap_dead_jobs __P((void));
extern int start_job __P((int, int));
extern int kill_pid __P((pid_t, int, int));
extern int initialize_job_control __P((int));
extern void initialize_job_signals __P((void));
extern int give_terminal_to __P((pid_t, int));
extern void set_sigwinch_handler __P((void));
extern void unset_sigwinch_handler __P((void));
extern void unfreeze_jobs_list __P((void));
extern int set_job_control __P((int));
extern void without_job_control __P((void));
extern void end_job_control __P((void));
extern void restart_job_control __P((void));
extern void set_sigchld_handler __P((void));
extern void ignore_tty_job_signals __P((void));
extern void default_tty_job_signals __P((void));
#if defined (JOB_CONTROL)
extern int job_control;
#endif
#endif /* _JOBS_H_ */
+8 -10
View File
@@ -340,7 +340,7 @@ replace_history_entry (which, line, data)
{
HIST_ENTRY *temp, *old_value;
if (which >= history_length)
if (which < 0 || which >= history_length)
return ((HIST_ENTRY *)NULL);
temp = (HIST_ENTRY *)xmalloc (sizeof (HIST_ENTRY));
@@ -364,17 +364,15 @@ remove_history (which)
HIST_ENTRY *return_value;
register int i;
if (which >= history_length || !history_length)
return_value = (HIST_ENTRY *)NULL;
else
{
return_value = the_history[which];
if (which < 0 || which >= history_length || history_length == 0)
return ((HIST_ENTRY *)NULL);
for (i = which; i < history_length; i++)
the_history[i] = the_history[i + 1];
return_value = the_history[which];
history_length--;
}
for (i = which; i < history_length; i++)
the_history[i] = the_history[i + 1];
history_length--;
return (return_value);
}
+7 -4
View File
@@ -77,18 +77,20 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
char *string;
int seed, count, find_non_zero;
{
size_t tmp = 0;
size_t tmp;
mbstate_t ps;
int point = 0;
int point;
wchar_t wc;
tmp = 0;
memset(&ps, 0, sizeof (mbstate_t));
if (seed < 0)
seed = 0;
if (count <= 0)
return seed;
point = seed + _rl_adjust_point(string, seed, &ps);
point = seed + _rl_adjust_point (string, seed, &ps);
/* if this is true, means that seed was not pointed character
started byte. So correct the point and consume count */
if (seed < point)
@@ -134,7 +136,8 @@ _rl_find_next_mbchar_internal (string, seed, count, find_non_zero)
break;
}
}
return point;
return point;
}
static int
+2 -2
View File
@@ -52,8 +52,8 @@ isnetconn (fd)
l = sizeof(sa);
rv = getpeername(fd, &sa, &l);
/* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */
return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1);
/* Posix.2 says getpeername can return these errors. */
return ((rv < 0 && (errno == ENOTSOCK || errno == ENOTCONN || errno == EINVAL)) ? 0 : 1);
#else /* !HAVE_GETPEERNAME || SVR4_2 || __BEOS__ */
# if defined (SVR4) || defined (SVR4_2)
/* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */
+8 -8
View File
@@ -2066,14 +2066,6 @@ shell_getc (remove_quoted_newline)
if (uc)
shell_input_line_index++;
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
/* If UC is NULL, we have reached the end of the current input string. If
pushed_string_list is non-empty, it's time to pop to the previous string
@@ -2089,6 +2081,14 @@ shell_getc (remove_quoted_newline)
}
#endif /* ALIAS || DPAREN_ARITHMETIC */
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
if (!uc && shell_input_line_terminator == EOF)
return ((shell_input_line_index != 0) ? '\n' : EOF);
+25 -8
View File
@@ -1345,8 +1345,13 @@ yy_stream_get ()
result = EOF;
if (bash_input.location.file)
result = getc_with_restart (bash_input.location.file);
{
if (interactive)
interrupt_immediately++;
result = getc_with_restart (bash_input.location.file);
if (interactive)
interrupt_immediately--;
}
return (result);
}
@@ -1659,11 +1664,11 @@ read_a_line (remove_quoted_newline)
pass_next = 0;
while (1)
{
c = yy_getc ();
/* Allow immediate exit if interrupted during input. */
QUIT;
c = yy_getc ();
/* Ignore null bytes in input. */
if (c == 0)
{
@@ -2061,6 +2066,7 @@ shell_getc (remove_quoted_newline)
if (uc)
shell_input_line_index++;
#if 0
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
@@ -2068,6 +2074,7 @@ shell_getc (remove_quoted_newline)
line_number++;
goto restart_read;
}
#endif
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
/* If UC is NULL, we have reached the end of the current input string. If
@@ -2084,6 +2091,16 @@ shell_getc (remove_quoted_newline)
}
#endif /* ALIAS || DPAREN_ARITHMETIC */
#if 1
if MBTEST(uc == '\\' && remove_quoted_newline && shell_input_line[shell_input_line_index] == '\n')
{
if (SHOULD_PROMPT ())
prompt_again ();
line_number++;
goto restart_read;
}
#endif
if (!uc && shell_input_line_terminator == EOF)
return ((shell_input_line_index != 0) ? '\n' : EOF);
@@ -2913,9 +2930,10 @@ parse_dparen (c)
cmdtyp = parse_arith_cmd (&wval, 0);
if (cmdtyp == 1)
{
wd = alloc_word_desc ();
wd->word = wval;
wd = make_word (wval);
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
free (wval);
return (ARITH_FOR_EXPRS);
}
else
@@ -2931,10 +2949,10 @@ parse_dparen (c)
cmdtyp = parse_arith_cmd (&wval, 0);
if (cmdtyp == 1) /* arithmetic command */
{
wd = make_word (wval);
wd = alloc_word_desc ();
wd->word = wval;
wd->flags = W_QUOTED|W_NOSPLIT|W_NOGLOB;
yylval.word_list = make_word_list (wd, (WORD_LIST *)NULL);
free (wval); /* make_word copies it */
return (ARITH_CMD);
}
else if (cmdtyp == 0) /* nested subshell */
@@ -3524,7 +3542,6 @@ read_token_word (character)
goto next_character;
}
/* Identify possible compound array variable assignment. */
/* XXX - changes here for `+=' */
else if MBTEST(character == '=' && token_index > 0 && (assignment_acceptable (last_read_token) || (parser_state & PST_ASSIGNOK)) && token_is_assignment (token, token_index))
{
peek_char = shell_getc (1);
+10 -8
View File
@@ -513,20 +513,22 @@ it_init_joblist (itp, jstate)
register int i;
register PROCESS *p;
char *s, *t;
JOB_STATE js;
JOB *j;
JOB_STATE ws; /* wanted state */
if (jstate == 0)
js = JRUNNING;
ws = JRUNNING;
else if (jstate == 1)
js = JSTOPPED;
ws = JSTOPPED;
sl = strlist_create (job_slots);
for (i = job_slots - 1; i >= 0; i--)
sl = strlist_create (js.j_jobslots);
for (i = js.j_jobslots - 1; i >= 0; i--)
{
if (jobs[i] == 0)
j = get_job_by_jid (i);
if (j == 0)
continue;
p = jobs[i]->pipe;
if (jstate == -1 || JOBSTATE(i) == js)
p = j->pipe;
if (jstate == -1 || JOBSTATE(i) == ws)
{
s = savestring (p->command);
t = strpbrk (s, " \t\n");
+10 -7
View File
@@ -513,20 +513,20 @@ it_init_joblist (itp, jstate)
register int i;
register PROCESS *p;
char *s, *t;
JOB_STATE js;
JOB_STATE ws; /* wanted state */
if (jstate == 0)
js = JRUNNING;
ws = JRUNNING;
else if (jstate == 1)
js = JSTOPPED;
ws = JSTOPPED;
sl = strlist_create (job_slots);
for (i = job_slots - 1; i >= 0; i--)
sl = strlist_create (js.j_jobslots);
for (i = js.j_jobslots - 1; i >= 0; i--)
{
if (jobs[i] == 0)
continue;
p = jobs[i]->pipe;
if (jstate == -1 || JOBSTATE(i) == js)
if (jstate == -1 || JOBSTATE(i) == ws)
{
s = savestring (p->command);
t = strpbrk (s, " \t\n");
@@ -987,6 +987,7 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
SHELL_VAR *f, *v;
WORD_LIST *cmdlist;
int fval;
sh_parser_state_t ps;
#if defined (ARRAY_VARS)
ARRAY *a;
#endif
@@ -1010,8 +1011,10 @@ gen_shell_function_matches (cs, text, line, ind, lwords, nw, cw)
bind_compfunc_variables (line, ind, lwords, cw - 1, 0);
cmdlist = build_arg_list (funcname, text, lwords, cw);
save_parser_state (&ps);
fval = execute_shell_function (f, cmdlist);
restore_parser_state (&ps);
/* Now clean up and destroy everything. */
dispose_words (cmdlist);
+1 -1
View File
@@ -6931,7 +6931,7 @@ add_twochars:
cases: a quoted null character as above and when
CTLNUL is contained in the (non-null) expansion
of some variable. We use the had_quoted_null flag to
pass the value through this function to its return value. */
pass the value through this function to its caller. */
if ((tflag & W_HASQUOTEDNULL) && QUOTED_NULL (temp) == 0)
remove_quoted_nulls (temp); /* XXX */
}
-3
View File
@@ -4822,7 +4822,6 @@ parameter_brace_expand_indir (name, var_is_special, quoted, quoted_dollar_atp, c
w = parameter_brace_expand_word (name, var_is_special, quoted);
t = w->word;
w->word = 0;
/* Have to dequote here if necessary */
if (t)
{
@@ -5923,7 +5922,6 @@ parameter_brace_expand (string, indexp, quoted, quoted_dollar_atp, contains_doll
{
temp = tdesc->word;
tflag = tdesc->flags;
tdesc->word = 0;
dispose_word_desc (tdesc);
}
else
@@ -6751,7 +6749,6 @@ add_string:
had_quoted_null = 1;
temp = tword->word;
tword->word = 0;
dispose_word_desc (tword);
goto add_string;
+5 -2
View File
@@ -875,9 +875,12 @@ reset_or_restore_signal_handlers (reset)
/* Take care of the exit trap first */
if (sigmodes[EXIT_TRAP] & SIG_TRAPPED)
{
free_trap_command (EXIT_TRAP);
trap_list[EXIT_TRAP] = (char *)NULL;
sigmodes[EXIT_TRAP] &= ~SIG_TRAPPED;
if (reset != reset_signal)
{
free_trap_command (EXIT_TRAP);
trap_list[EXIT_TRAP] = (char *)NULL;
}
}
for (i = 1; i < NSIG; i++)
+6 -1
View File
@@ -807,6 +807,11 @@ run_return_trap ()
{
int old_exit_value;
#if 0
if ((sigmodes[DEBUG_TRAP] & SIG_TRAPPED) && (sigmodes[DEBUG_TRAP] & SIG_INPROGRESS))
return;
#endif
if ((sigmodes[RETURN_TRAP] & SIG_TRAPPED) && ((sigmodes[RETURN_TRAP] & SIG_IGNORED) == 0) && (sigmodes[RETURN_TRAP] & SIG_INPROGRESS) == 0)
{
old_exit_value = last_command_exit_value;
@@ -903,8 +908,8 @@ reset_or_restore_signal_handlers (reset)
sigmodes[ERROR_TRAP] &= ~SIG_TRAPPED;
#if defined (DEBUGGER)
if (debugging_mode == 0 || function_trace_mode == 0)
sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
#endif
sigmodes[RETURN_TRAP] &= ~SIG_TRAPPED;
}
/* Reset trapped signals to their original values, but don't free the