mirror of
https://https.git.savannah.gnu.org/git/bash.git
synced 2026-07-03 02:10:50 +02:00
commit bash-20050127 snapshot
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
@@ -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
|
||||
|
||||
@@ -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
@@ -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
@@ -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"));
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -214,7 +214,6 @@ showtrap (i)
|
||||
char *t, *p, *sn;
|
||||
|
||||
p = trap_list[i];
|
||||
|
||||
if (p == (char *)DEFAULT_SIG)
|
||||
return;
|
||||
|
||||
|
||||
+7
-3
@@ -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
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+3614
File diff suppressed because it is too large
Load Diff
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
@@ -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. */
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
@@ -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 */
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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++)
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user