From: Chet Ramey Date: Sat, 3 Dec 2011 18:42:58 +0000 (-0500) Subject: commit bash-20050127 snapshot X-Git-Tag: bash-3.1-alpha~22 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=10590446d192a7f8ddf60123dab298f2748c9c41;p=platform%2Fupstream%2Fbash.git commit bash-20050127 snapshot --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 3caa405..1075ef3 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -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 diff --git a/CWRU/CWRU.chlog~ b/CWRU/CWRU.chlog~ index 424aefb..fc75173 100644 --- a/CWRU/CWRU.chlog~ +++ b/CWRU/CWRU.chlog~ @@ -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 diff --git a/Makefile.in b/Makefile.in index b4683b8..c68b6d5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 diff --git a/arrayfunc.c b/arrayfunc.c index 48c59d7..c1b589f 100644 --- a/arrayfunc.c +++ b/arrayfunc.c @@ -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); diff --git a/autom4te.cache/output.0 b/autom4te.cache/output.0 index 114843f..58c418b 100644 --- a/autom4te.cache/output.0 +++ b/autom4te.cache/output.0 @@ -1,5 +1,5 @@ @%:@! /bin/sh -@%:@ From configure.in for Bash 3.0, version 3.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 #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 diff --git a/autom4te.cache/requests b/autom4te.cache/requests index 5acfeb3..6402393 100644 --- a/autom4te.cache/requests +++ b/autom4te.cache/requests @@ -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_CONFIG_SUBDIRS' => 1, + 'AC_PROG_MAKE_SET' => 1, + 'AC_CHECK_HEADERS' => 1, + 'AC_FUNC_LSTAT_FOLLOWS_SLASHED_SYMLINK' => 1, + 'AC_TYPE_UID_T' => 1, + 'AM_MAINTAINER_MODE' => 1, + 'AC_TYPE_SIZE_T' => 1, 'AC_PROG_LIBTOOL' => 1, + 'AC_FUNC_STRNLEN' => 1, + 'AC_FUNC_GETGROUPS' => 1, + 'AC_REPLACE_FNMATCH' => 1, + 'AC_FUNC_SELECT_ARGTYPES' => 1, + 'AC_FUNC_WAIT3' => 1, + 'AC_PATH_X' => 1, + 'AC_CHECK_FUNCS' => 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_C_VOLATILE' => 1, + 'AC_HEADER_STDC' => 1, + 'AC_CHECK_TYPES' => 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_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, - 'AC_CONFIG_AUX_DIR' => 1, - 'AC_FUNC_CLOSEDIR_VOID' => 1, + 'AM_GNU_GETTEXT' => 1, + 'include' => 1, 'AC_LIBSOURCE' => 1, - 'AC_SUBST' => 1, + 'AC_HEADER_TIME' => 1, 'AC_FUNC_STRFTIME' => 1, - 'AC_CONFIG_HEADERS' => 1, - 'AC_DEFINE_TRACE_LITERAL' => 1, + 'AC_CHECK_MEMBERS' => 1, 'AC_FUNC_GETMNTENT' => 1, - 'AM_AUTOMAKE_VERSION' => 1, - 'AC_PROG_YACC' => 1, - 'AC_FUNC_VPRINTF' => 1, - 'AC_FUNC_REALLOC' => 1, - 'AC_TYPE_UID_T' => 1, - 'AC_FUNC_GETLOADAVG' => 1, - 'AC_CHECK_FUNCS' => 1, - 'AC_PROG_LN_S' => 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_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_PATH_X' => 1, - 'AC_PROG_RANLIB' => 1, 'AC_HEADER_STAT' => 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_ALLOCA' => 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' ) ); diff --git a/autom4te.cache/traces.0 b/autom4te.cache/traces.0 index 68cfe7d..2253d40 100644 --- a/autom4te.cache/traces.0 +++ b/autom4te.cache/traces.0 @@ -221,969 +221,970 @@ m4trace:configure.in:551: -1- AC_SUBST([YACC]) m4trace:configure.in:552: -1- AC_PROG_MAKE_SET m4trace:configure.in:552: -1- AC_SUBST([SET_MAKE]) m4trace:configure.in:558: -1- AC_SUBST([MAKE_SHELL]) -m4trace:configure.in:561: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) -m4trace:configure.in:564: -1- AC_C_CONST -m4trace:configure.in:564: -1- AC_DEFINE_TRACE_LITERAL([const]) -m4trace:configure.in:564: -1- AH_OUTPUT([const], [/* Define to empty if `const\' does not conform to ANSI C. */ +m4trace:configure.in:580: -1- AC_SUBST([SIZE]) +m4trace:configure.in:583: -1- AC_DEFINE_TRACE_LITERAL([_GNU_SOURCE]) +m4trace:configure.in:586: -1- AC_C_CONST +m4trace:configure.in:586: -1- AC_DEFINE_TRACE_LITERAL([const]) +m4trace:configure.in:586: -1- AH_OUTPUT([const], [/* Define to empty if `const\' does not conform to ANSI C. */ #undef const]) -m4trace:configure.in:565: -1- AC_C_INLINE -m4trace:configure.in:565: -1- AC_DEFINE_TRACE_LITERAL([inline]) -m4trace:configure.in:565: -1- AH_OUTPUT([inline], [/* Define as `__inline\' if that\'s what the C compiler calls it, or to nothing +m4trace:configure.in:587: -1- AC_C_INLINE +m4trace:configure.in:587: -1- AC_DEFINE_TRACE_LITERAL([inline]) +m4trace:configure.in:587: -1- AH_OUTPUT([inline], [/* Define as `__inline\' if that\'s what the C compiler calls it, or to nothing if it is not supported. */ #undef inline]) -m4trace:configure.in:565: -1- AC_DEFINE_TRACE_LITERAL([inline]) -m4trace:configure.in:566: -1- AC_DEFINE_TRACE_LITERAL([WORDS_BIGENDIAN]) -m4trace:configure.in:566: -1- AH_OUTPUT([WORDS_BIGENDIAN], [/* Define to 1 if your processor stores words with the most significant byte +m4trace:configure.in:587: -1- AC_DEFINE_TRACE_LITERAL([inline]) +m4trace:configure.in:588: -1- AC_DEFINE_TRACE_LITERAL([WORDS_BIGENDIAN]) +m4trace:configure.in:588: -1- AH_OUTPUT([WORDS_BIGENDIAN], [/* Define to 1 if your processor stores words with the most significant byte first (like Motorola and SPARC, unlike Intel and VAX). */ #undef WORDS_BIGENDIAN]) -m4trace:configure.in:567: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRINGIZE]) -m4trace:configure.in:567: -1- AH_OUTPUT([HAVE_STRINGIZE], [/* Define to 1 if cpp supports the ANSI @%:@ stringizing operator. */ +m4trace:configure.in:589: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRINGIZE]) +m4trace:configure.in:589: -1- AH_OUTPUT([HAVE_STRINGIZE], [/* Define to 1 if cpp supports the ANSI @%:@ stringizing operator. */ #undef HAVE_STRINGIZE]) -m4trace:configure.in:568: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_DOUBLE]) -m4trace:configure.in:568: -1- AH_OUTPUT([HAVE_LONG_DOUBLE], [/* Define to 1 if long double works and has more range or precision than +m4trace:configure.in:590: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_DOUBLE]) +m4trace:configure.in:590: -1- AH_OUTPUT([HAVE_LONG_DOUBLE], [/* Define to 1 if long double works and has more range or precision than double. */ #undef HAVE_LONG_DOUBLE]) -m4trace:configure.in:569: -1- AC_DEFINE_TRACE_LITERAL([PROTOTYPES]) -m4trace:configure.in:569: -1- AH_OUTPUT([PROTOTYPES], [/* Define to 1 if the C compiler supports function prototypes. */ +m4trace:configure.in:591: -1- AC_DEFINE_TRACE_LITERAL([PROTOTYPES]) +m4trace:configure.in:591: -1- AH_OUTPUT([PROTOTYPES], [/* Define to 1 if the C compiler supports function prototypes. */ #undef PROTOTYPES]) -m4trace:configure.in:569: -1- AC_DEFINE_TRACE_LITERAL([__PROTOTYPES]) -m4trace:configure.in:569: -1- AH_OUTPUT([__PROTOTYPES], [/* Define like PROTOTYPES; this can be used by system headers. */ +m4trace:configure.in:591: -1- AC_DEFINE_TRACE_LITERAL([__PROTOTYPES]) +m4trace:configure.in:591: -1- AH_OUTPUT([__PROTOTYPES], [/* Define like PROTOTYPES; this can be used by system headers. */ #undef __PROTOTYPES]) -m4trace:configure.in:570: -1- AH_OUTPUT([__CHAR_UNSIGNED__], [/* Define to 1 if type `char\' is unsigned and you are not using gcc. */ +m4trace:configure.in:592: -1- AH_OUTPUT([__CHAR_UNSIGNED__], [/* Define to 1 if type `char\' is unsigned and you are not using gcc. */ #ifndef __CHAR_UNSIGNED__ # undef __CHAR_UNSIGNED__ #endif]) -m4trace:configure.in:570: -1- AC_DEFINE_TRACE_LITERAL([__CHAR_UNSIGNED__]) -m4trace:configure.in:573: -1- AM_GNU_GETTEXT([no-libtool], [need-ngettext], [lib/intl]) -m4trace:configure.in:573: -1- AC_SUBST([MKINSTALLDIRS]) -m4trace:configure.in:573: -1- AC_SUBST([USE_NLS]) -m4trace:configure.in:573: -1- AC_SUBST([MSGFMT]) -m4trace:configure.in:573: -1- AC_SUBST([GMSGFMT], [$ac_cv_path_GMSGFMT]) -m4trace:configure.in:573: -1- AC_SUBST([XGETTEXT]) -m4trace:configure.in:573: -1- AC_SUBST([MSGMERGE]) -m4trace:configure.in:573: -1- AC_TYPE_OFF_T -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([off_t]) -m4trace:configure.in:573: -1- AH_OUTPUT([off_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:592: -1- AC_DEFINE_TRACE_LITERAL([__CHAR_UNSIGNED__]) +m4trace:configure.in:595: -1- AM_GNU_GETTEXT([no-libtool], [need-ngettext], [lib/intl]) +m4trace:configure.in:595: -1- AC_SUBST([MKINSTALLDIRS]) +m4trace:configure.in:595: -1- AC_SUBST([USE_NLS]) +m4trace:configure.in:595: -1- AC_SUBST([MSGFMT]) +m4trace:configure.in:595: -1- AC_SUBST([GMSGFMT], [$ac_cv_path_GMSGFMT]) +m4trace:configure.in:595: -1- AC_SUBST([XGETTEXT]) +m4trace:configure.in:595: -1- AC_SUBST([MSGMERGE]) +m4trace:configure.in:595: -1- AC_TYPE_OFF_T +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([off_t]) +m4trace:configure.in:595: -1- AH_OUTPUT([off_t], [/* Define to `long\' if does not define. */ #undef off_t]) -m4trace:configure.in:573: -1- AC_TYPE_SIZE_T -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([size_t]) -m4trace:configure.in:573: -1- AH_OUTPUT([size_t], [/* Define to `unsigned\' if does not define. */ +m4trace:configure.in:595: -1- AC_TYPE_SIZE_T +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([size_t]) +m4trace:configure.in:595: -1- AH_OUTPUT([size_t], [/* Define to `unsigned\' if does not define. */ #undef size_t]) -m4trace:configure.in:573: -1- AC_FUNC_ALLOCA -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). +m4trace:configure.in:595: -1- AC_FUNC_ALLOCA +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ #undef HAVE_ALLOCA]) -m4trace:configure.in:573: -1- AC_LIBSOURCE([alloca.c]) -m4trace:configure.in:573: -1- AC_SUBST([ALLOCA], [alloca.$ac_objext]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) -m4trace:configure.in:573: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ +m4trace:configure.in:595: -1- AC_LIBSOURCE([alloca.c]) +m4trace:configure.in:595: -1- AC_SUBST([ALLOCA], [alloca.$ac_objext]) +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) +m4trace:configure.in:595: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ #undef C_ALLOCA]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) -m4trace:configure.in:573: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) +m4trace:configure.in:595: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c\' support on those systems. */ #undef CRAY_STACKSEG_END]) -m4trace:configure.in:573: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the +m4trace:configure.in:595: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ @%:@undef STACK_DIRECTION]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) -m4trace:configure.in:573: -1- AC_FUNC_MMAP -m4trace:configure.in:573: -1- AC_CHECK_HEADERS([stdlib.h unistd.h]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) +m4trace:configure.in:595: -1- AC_FUNC_MMAP +m4trace:configure.in:595: -1- AC_CHECK_HEADERS([stdlib.h unistd.h]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H]) -m4trace:configure.in:573: -1- AC_CHECK_FUNCS([getpagesize]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ +m4trace:configure.in:595: -1- AC_CHECK_FUNCS([getpagesize]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ #undef HAVE_GETPAGESIZE]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ #undef HAVE_MMAP]) -m4trace:configure.in:573: -1- AC_SUBST([GLIBC21]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([INTDIV0_RAISES_SIGFPE]) -m4trace:configure.in:573: -1- AH_OUTPUT([INTDIV0_RAISES_SIGFPE], [/* Define if integer division by zero raises signal SIGFPE. */ +m4trace:configure.in:595: -1- AC_SUBST([GLIBC21]) +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([INTDIV0_RAISES_SIGFPE]) +m4trace:configure.in:595: -1- AH_OUTPUT([INTDIV0_RAISES_SIGFPE], [/* Define if integer division by zero raises signal SIGFPE. */ #undef INTDIV0_RAISES_SIGFPE]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H_WITH_UINTMAX]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_INTTYPES_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H_WITH_UINTMAX]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_INTTYPES_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and declares uintmax_t. */ #undef HAVE_INTTYPES_H_WITH_UINTMAX]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDINT_H_WITH_UINTMAX]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STDINT_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and declares +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STDINT_H_WITH_UINTMAX]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STDINT_H_WITH_UINTMAX], [/* Define if exists, doesn\'t clash with , and declares uintmax_t. */ #undef HAVE_STDINT_H_WITH_UINTMAX]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_UNSIGNED_LONG_LONG], [/* Define if you have the unsigned long long type. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_UNSIGNED_LONG_LONG], [/* Define if you have the unsigned long long type. */ #undef HAVE_UNSIGNED_LONG_LONG]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) -m4trace:configure.in:573: -1- AH_OUTPUT([uintmax_t], [/* Define to unsigned long or unsigned long long if and +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) +m4trace:configure.in:595: -1- AH_OUTPUT([uintmax_t], [/* Define to unsigned long or unsigned long long if and don\'t define. */ #undef uintmax_t]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINTMAX_T]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_UINTMAX_T], [/* Define if you have the \'uintmax_t\' type in or . */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UINTMAX_T]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_UINTMAX_T], [/* Define if you have the \'uintmax_t\' type in or . */ #undef HAVE_UINTMAX_T]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define if exists and doesn\'t clash with . */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INTTYPES_H]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define if exists and doesn\'t clash with . */ #undef HAVE_INTTYPES_H]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([PRI_MACROS_BROKEN]) -m4trace:configure.in:573: -1- AH_OUTPUT([PRI_MACROS_BROKEN], [/* Define if exists and defines unusable PRI* macros. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([PRI_MACROS_BROKEN]) +m4trace:configure.in:595: -1- AH_OUTPUT([PRI_MACROS_BROKEN], [/* Define if exists and defines unusable PRI* macros. */ #undef PRI_MACROS_BROKEN]) -m4trace:configure.in:573: -1- AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ +m4trace:configure.in:595: -1- AC_CHECK_HEADERS([argz.h limits.h locale.h nl_types.h malloc.h stddef.h \ stdlib.h string.h unistd.h sys/param.h]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ #undef HAVE_ARGZ_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_LOCALE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_LOCALE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_NL_TYPES_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_NL_TYPES_H], [/* Define to 1 if you have the header file. */ #undef HAVE_NL_TYPES_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_MALLOC_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_MALLOC_H], [/* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STRING_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H]) -m4trace:configure.in:573: -1- AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ +m4trace:configure.in:595: -1- AC_CHECK_FUNCS([feof_unlocked fgets_unlocked getc_unlocked getcwd getegid \ geteuid getgid getuid mempcpy munmap putenv setenv setlocale stpcpy \ strcasecmp strdup strtoul tsearch __argz_count __argz_stringify __argz_next \ __fsetlocking]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_FEOF_UNLOCKED], [/* Define to 1 if you have the `feof_unlocked\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_FEOF_UNLOCKED], [/* Define to 1 if you have the `feof_unlocked\' function. */ #undef HAVE_FEOF_UNLOCKED]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_FGETS_UNLOCKED], [/* Define to 1 if you have the `fgets_unlocked\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_FGETS_UNLOCKED], [/* Define to 1 if you have the `fgets_unlocked\' function. */ #undef HAVE_FGETS_UNLOCKED]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETC_UNLOCKED], [/* Define to 1 if you have the `getc_unlocked\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETC_UNLOCKED], [/* Define to 1 if you have the `getc_unlocked\' function. */ #undef HAVE_GETC_UNLOCKED]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ #undef HAVE_GETCWD]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETEGID], [/* Define to 1 if you have the `getegid\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETEGID], [/* Define to 1 if you have the `getegid\' function. */ #undef HAVE_GETEGID]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETEUID], [/* Define to 1 if you have the `geteuid\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETEUID], [/* Define to 1 if you have the `geteuid\' function. */ #undef HAVE_GETEUID]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETGID], [/* Define to 1 if you have the `getgid\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETGID], [/* Define to 1 if you have the `getgid\' function. */ #undef HAVE_GETGID]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETUID], [/* Define to 1 if you have the `getuid\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETUID], [/* Define to 1 if you have the `getuid\' function. */ #undef HAVE_GETUID]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ #undef HAVE_MEMPCPY]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ #undef HAVE_MUNMAP]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ #undef HAVE_PUTENV]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ #undef HAVE_SETENV]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ #undef HAVE_SETLOCALE]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ #undef HAVE_STPCPY]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ #undef HAVE_STRCASECMP]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ #undef HAVE_STRDUP]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ #undef HAVE_STRTOUL]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_TSEARCH], [/* Define to 1 if you have the `tsearch\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_TSEARCH], [/* Define to 1 if you have the `tsearch\' function. */ #undef HAVE_TSEARCH]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE___ARGZ_COUNT], [/* Define to 1 if you have the `__argz_count\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE___ARGZ_COUNT], [/* Define to 1 if you have the `__argz_count\' function. */ #undef HAVE___ARGZ_COUNT]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE___ARGZ_STRINGIFY], [/* Define to 1 if you have the `__argz_stringify\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE___ARGZ_STRINGIFY], [/* Define to 1 if you have the `__argz_stringify\' function. */ #undef HAVE___ARGZ_STRINGIFY]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE___ARGZ_NEXT], [/* Define to 1 if you have the `__argz_next\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE___ARGZ_NEXT], [/* Define to 1 if you have the `__argz_next\' function. */ #undef HAVE___ARGZ_NEXT]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE___FSETLOCKING], [/* Define to 1 if you have the `__fsetlocking\' function. */ +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE___FSETLOCKING], [/* Define to 1 if you have the `__fsetlocking\' function. */ #undef HAVE___FSETLOCKING]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ICONV]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_ICONV], [/* Define if you have the iconv() function. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ICONV]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_ICONV], [/* Define if you have the iconv() function. */ #undef HAVE_ICONV]) -m4trace:configure.in:573: -1- AC_SUBST([LIBICONV]) -m4trace:configure.in:573: -1- AC_SUBST([LTLIBICONV]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([ICONV_CONST]) -m4trace:configure.in:573: -1- AH_OUTPUT([ICONV_CONST], [/* Define as const if the declaration of iconv() needs const. */ +m4trace:configure.in:595: -1- AC_SUBST([LIBICONV]) +m4trace:configure.in:595: -1- AC_SUBST([LTLIBICONV]) +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([ICONV_CONST]) +m4trace:configure.in:595: -1- AH_OUTPUT([ICONV_CONST], [/* Define as const if the declaration of iconv() needs const. */ #undef ICONV_CONST]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_LANGINFO_CODESET], [/* Define if you have and nl_langinfo(CODESET). */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_LANGINFO_CODESET], [/* Define if you have and nl_langinfo(CODESET). */ #undef HAVE_LANGINFO_CODESET]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LC_MESSAGES]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_LC_MESSAGES], [/* Define if your file defines LC_MESSAGES. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LC_MESSAGES]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_LC_MESSAGES], [/* Define if your file defines LC_MESSAGES. */ #undef HAVE_LC_MESSAGES]) -m4trace:configure.in:573: -1- AC_SUBST([INTLBISON]) -m4trace:configure.in:573: -1- AC_SUBST([USE_NLS]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([ENABLE_NLS]) -m4trace:configure.in:573: -1- AH_OUTPUT([ENABLE_NLS], [/* Define to 1 if translation of program messages to the user\'s native +m4trace:configure.in:595: -1- AC_SUBST([INTLBISON]) +m4trace:configure.in:595: -1- AC_SUBST([USE_NLS]) +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([ENABLE_NLS]) +m4trace:configure.in:595: -1- AH_OUTPUT([ENABLE_NLS], [/* Define to 1 if translation of program messages to the user\'s native language is requested. */ #undef ENABLE_NLS]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETTEXT]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_GETTEXT], [/* Define if the GNU gettext() function is already present or preinstalled. */ +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETTEXT]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_GETTEXT], [/* Define if the GNU gettext() function is already present or preinstalled. */ #undef HAVE_GETTEXT]) -m4trace:configure.in:573: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DCGETTEXT]) -m4trace:configure.in:573: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define if the GNU dcgettext() function is already present or preinstalled. +m4trace:configure.in:595: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DCGETTEXT]) +m4trace:configure.in:595: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define if the GNU dcgettext() function is already present or preinstalled. */ #undef HAVE_DCGETTEXT]) -m4trace:configure.in:573: -1- AC_SUBST([BUILD_INCLUDED_LIBINTL]) -m4trace:configure.in:573: -1- AC_SUBST([USE_INCLUDED_LIBINTL]) -m4trace:configure.in:573: -1- AC_SUBST([CATOBJEXT]) -m4trace:configure.in:573: -1- AC_SUBST([DATADIRNAME]) -m4trace:configure.in:573: -1- AC_SUBST([INSTOBJEXT]) -m4trace:configure.in:573: -1- AC_SUBST([GENCAT]) -m4trace:configure.in:573: -1- AC_SUBST([INTLOBJS]) -m4trace:configure.in:573: -1- AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) -m4trace:configure.in:573: -1- AC_SUBST([INTLLIBS]) -m4trace:configure.in:573: -1- AC_SUBST([LIBINTL]) -m4trace:configure.in:573: -1- AC_SUBST([LTLIBINTL]) -m4trace:configure.in:573: -1- AC_SUBST([POSUB]) -m4trace:configure.in:576: -1- AC_HEADER_DIRENT -m4trace:configure.in:576: -1- AH_OUTPUT([HAVE_DIRENT_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. +m4trace:configure.in:595: -1- AC_SUBST([BUILD_INCLUDED_LIBINTL]) +m4trace:configure.in:595: -1- AC_SUBST([USE_INCLUDED_LIBINTL]) +m4trace:configure.in:595: -1- AC_SUBST([CATOBJEXT]) +m4trace:configure.in:595: -1- AC_SUBST([DATADIRNAME]) +m4trace:configure.in:595: -1- AC_SUBST([INSTOBJEXT]) +m4trace:configure.in:595: -1- AC_SUBST([GENCAT]) +m4trace:configure.in:595: -1- AC_SUBST([INTLOBJS]) +m4trace:configure.in:595: -1- AC_SUBST([INTL_LIBTOOL_SUFFIX_PREFIX]) +m4trace:configure.in:595: -1- AC_SUBST([INTLLIBS]) +m4trace:configure.in:595: -1- AC_SUBST([LIBINTL]) +m4trace:configure.in:595: -1- AC_SUBST([LTLIBINTL]) +m4trace:configure.in:595: -1- AC_SUBST([POSUB]) +m4trace:configure.in:598: -1- AC_HEADER_DIRENT +m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_DIRENT_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ #undef HAVE_DIRENT_H]) -m4trace:configure.in:576: -1- AH_OUTPUT([HAVE_SYS_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. +m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_SYS_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ #undef HAVE_SYS_NDIR_H]) -m4trace:configure.in:576: -1- AH_OUTPUT([HAVE_SYS_DIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. +m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_SYS_DIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ #undef HAVE_SYS_DIR_H]) -m4trace:configure.in:576: -1- AH_OUTPUT([HAVE_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ +m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_NDIR_H], [/* Define to 1 if you have the header file, and it defines `DIR\'. */ #undef HAVE_NDIR_H]) -m4trace:configure.in:577: -1- AC_HEADER_TIME -m4trace:configure.in:577: -1- AC_DEFINE_TRACE_LITERAL([TIME_WITH_SYS_TIME]) -m4trace:configure.in:577: -1- AH_OUTPUT([TIME_WITH_SYS_TIME], [/* Define to 1 if you can safely include both and . */ +m4trace:configure.in:599: -1- AC_HEADER_TIME +m4trace:configure.in:599: -1- AC_DEFINE_TRACE_LITERAL([TIME_WITH_SYS_TIME]) +m4trace:configure.in:599: -1- AH_OUTPUT([TIME_WITH_SYS_TIME], [/* Define to 1 if you can safely include both and . */ #undef TIME_WITH_SYS_TIME]) -m4trace:configure.in:579: -1- AC_CHECK_HEADERS([inttypes.h]) -m4trace:configure.in:579: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:601: -1- AC_CHECK_HEADERS([inttypes.h]) +m4trace:configure.in:601: -1- AH_OUTPUT([HAVE_INTTYPES_H], [/* Define to 1 if you have the header file. */ #undef HAVE_INTTYPES_H]) -m4trace:configure.in:583: -1- AC_CHECK_HEADERS([unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ +m4trace:configure.in:605: -1- AC_CHECK_HEADERS([unistd.h stdlib.h stdarg.h varargs.h limits.h string.h \ memory.h locale.h termcap.h termio.h termios.h dlfcn.h \ stddef.h stdint.h netdb.h grp.h strings.h regex.h]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STDARG_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STDARG_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDARG_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_VARARGS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_VARARGS_H], [/* Define to 1 if you have the header file. */ #undef HAVE_VARARGS_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_LIMITS_H], [/* Define to 1 if you have the header file. */ #undef HAVE_LIMITS_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STRING_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STRING_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_MEMORY_H], [/* Define to 1 if you have the header file. */ #undef HAVE_MEMORY_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_LOCALE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_LOCALE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_LOCALE_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_TERMCAP_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_TERMCAP_H], [/* Define to 1 if you have the header file. */ #undef HAVE_TERMCAP_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_TERMIO_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_TERMIO_H], [/* Define to 1 if you have the header file. */ #undef HAVE_TERMIO_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_TERMIOS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_TERMIOS_H], [/* Define to 1 if you have the header file. */ #undef HAVE_TERMIOS_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_DLFCN_H], [/* Define to 1 if you have the header file. */ #undef HAVE_DLFCN_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STDDEF_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDDEF_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STDINT_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDINT_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_NETDB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_NETDB_H], [/* Define to 1 if you have the header file. */ #undef HAVE_NETDB_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_GRP_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_GRP_H], [/* Define to 1 if you have the header file. */ #undef HAVE_GRP_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_STRINGS_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STRINGS_H]) -m4trace:configure.in:583: -1- AH_OUTPUT([HAVE_REGEX_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:605: -1- AH_OUTPUT([HAVE_REGEX_H], [/* Define to 1 if you have the header file. */ #undef HAVE_REGEX_H]) -m4trace:configure.in:586: -1- AC_CHECK_HEADERS([sys/pte.h sys/stream.h sys/select.h sys/file.h \ +m4trace:configure.in:608: -1- AC_CHECK_HEADERS([sys/pte.h sys/stream.h sys/select.h sys/file.h \ sys/resource.h sys/param.h sys/socket.h sys/stat.h \ sys/time.h sys/times.h sys/types.h sys/wait.h]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_PTE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_PTE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_PTE_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_STREAM_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_STREAM_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_STREAM_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_SELECT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_SELECT_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_SELECT_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_FILE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_FILE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_FILE_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_RESOURCE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_RESOURCE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_RESOURCE_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_PARAM_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_PARAM_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_SOCKET_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_SOCKET_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_SOCKET_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_STAT_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_STAT_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_TIMES_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_TIMES_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIMES_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_TYPES_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_TYPES_H]) -m4trace:configure.in:586: -1- AH_OUTPUT([HAVE_SYS_WAIT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:608: -1- AH_OUTPUT([HAVE_SYS_WAIT_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_WAIT_H]) -m4trace:configure.in:587: -1- AC_CHECK_HEADERS([netinet/in.h arpa/inet.h]) -m4trace:configure.in:587: -1- AH_OUTPUT([HAVE_NETINET_IN_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:609: -1- AC_CHECK_HEADERS([netinet/in.h arpa/inet.h]) +m4trace:configure.in:609: -1- AH_OUTPUT([HAVE_NETINET_IN_H], [/* Define to 1 if you have the header file. */ #undef HAVE_NETINET_IN_H]) -m4trace:configure.in:587: -1- AH_OUTPUT([HAVE_ARPA_INET_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:609: -1- AH_OUTPUT([HAVE_ARPA_INET_H], [/* Define to 1 if you have the header file. */ #undef HAVE_ARPA_INET_H]) -m4trace:configure.in:598: -1- AC_FUNC_ALLOCA -m4trace:configure.in:598: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) -m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). +m4trace:configure.in:620: -1- AC_FUNC_ALLOCA +m4trace:configure.in:620: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA_H]) +m4trace:configure.in:620: -1- AH_OUTPUT([HAVE_ALLOCA_H], [/* Define to 1 if you have and it should be used (not on Ultrix). */ #undef HAVE_ALLOCA_H]) -m4trace:configure.in:598: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) -m4trace:configure.in:598: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ +m4trace:configure.in:620: -1- AC_DEFINE_TRACE_LITERAL([HAVE_ALLOCA]) +m4trace:configure.in:620: -1- AH_OUTPUT([HAVE_ALLOCA], [/* Define to 1 if you have `alloca\', as a function or macro. */ #undef HAVE_ALLOCA]) -m4trace:configure.in:598: -1- AC_LIBSOURCE([alloca.c]) -m4trace:configure.in:598: -1- AC_SUBST([ALLOCA], [alloca.$ac_objext]) -m4trace:configure.in:598: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) -m4trace:configure.in:598: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ +m4trace:configure.in:620: -1- AC_LIBSOURCE([alloca.c]) +m4trace:configure.in:620: -1- AC_SUBST([ALLOCA], [alloca.$ac_objext]) +m4trace:configure.in:620: -1- AC_DEFINE_TRACE_LITERAL([C_ALLOCA]) +m4trace:configure.in:620: -1- AH_OUTPUT([C_ALLOCA], [/* Define to 1 if using `alloca.c\'. */ #undef C_ALLOCA]) -m4trace:configure.in:598: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) -m4trace:configure.in:598: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP +m4trace:configure.in:620: -1- AC_DEFINE_TRACE_LITERAL([CRAY_STACKSEG_END]) +m4trace:configure.in:620: -1- AH_OUTPUT([CRAY_STACKSEG_END], [/* Define to one of `_getb67\', `GETB67\', `getb67\' for Cray-2 and Cray-YMP systems. This function is required for `alloca.c\' support on those systems. */ #undef CRAY_STACKSEG_END]) -m4trace:configure.in:598: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the +m4trace:configure.in:620: -1- AH_OUTPUT([STACK_DIRECTION], [/* If using the C implementation of alloca, define if you know the direction of stack growth for your system; otherwise it will be automatically deduced at run-time. STACK_DIRECTION > 0 => grows toward higher addresses STACK_DIRECTION < 0 => grows toward lower addresses STACK_DIRECTION = 0 => direction of growth unknown */ @%:@undef STACK_DIRECTION]) -m4trace:configure.in:598: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) -m4trace:configure.in:599: -1- AC_FUNC_GETPGRP -m4trace:configure.in:599: -1- AC_DEFINE_TRACE_LITERAL([GETPGRP_VOID]) -m4trace:configure.in:599: -1- AH_OUTPUT([GETPGRP_VOID], [/* Define to 1 if the `getpgrp\' function requires zero arguments. */ +m4trace:configure.in:620: -1- AC_DEFINE_TRACE_LITERAL([STACK_DIRECTION]) +m4trace:configure.in:621: -1- AC_FUNC_GETPGRP +m4trace:configure.in:621: -1- AC_DEFINE_TRACE_LITERAL([GETPGRP_VOID]) +m4trace:configure.in:621: -1- AH_OUTPUT([GETPGRP_VOID], [/* Define to 1 if the `getpgrp\' function requires zero arguments. */ #undef GETPGRP_VOID]) -m4trace:configure.in:600: -1- AC_FUNC_SETVBUF_REVERSED -m4trace:configure.in:600: -1- AC_DEFINE_TRACE_LITERAL([SETVBUF_REVERSED]) -m4trace:configure.in:600: -1- AH_OUTPUT([SETVBUF_REVERSED], [/* Define to 1 if the `setvbuf\' function takes the buffering type as its +m4trace:configure.in:622: -1- AC_FUNC_SETVBUF_REVERSED +m4trace:configure.in:622: -1- AC_DEFINE_TRACE_LITERAL([SETVBUF_REVERSED]) +m4trace:configure.in:622: -1- AH_OUTPUT([SETVBUF_REVERSED], [/* Define to 1 if the `setvbuf\' function takes the buffering type as its second argument and the buffer pointer as the third, as on System V before release 3. */ #undef SETVBUF_REVERSED]) -m4trace:configure.in:601: -1- AC_FUNC_VPRINTF -m4trace:configure.in:601: -1- AC_CHECK_FUNCS([vprintf], [ +m4trace:configure.in:623: -1- AC_FUNC_VPRINTF +m4trace:configure.in:623: -1- AC_CHECK_FUNCS([vprintf], [ AC_CHECK_FUNC(_doprnt, [AC_DEFINE(HAVE_DOPRNT, 1, [Define to 1 if you don't have `vprintf' but do have `_doprnt.'])])]) -m4trace:configure.in:601: -1- AH_OUTPUT([HAVE_VPRINTF], [/* Define to 1 if you have the `vprintf\' function. */ +m4trace:configure.in:623: -1- AH_OUTPUT([HAVE_VPRINTF], [/* Define to 1 if you have the `vprintf\' function. */ #undef HAVE_VPRINTF]) -m4trace:configure.in:601: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DOPRNT]) -m4trace:configure.in:601: -1- AH_OUTPUT([HAVE_DOPRNT], [/* Define to 1 if you don\'t have `vprintf\' but do have `_doprnt.\' */ +m4trace:configure.in:623: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DOPRNT]) +m4trace:configure.in:623: -1- AH_OUTPUT([HAVE_DOPRNT], [/* Define to 1 if you don\'t have `vprintf\' but do have `_doprnt.\' */ #undef HAVE_DOPRNT]) -m4trace:configure.in:602: -1- AC_FUNC_STRCOLL -m4trace:configure.in:602: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCOLL]) -m4trace:configure.in:602: -1- AH_OUTPUT([HAVE_STRCOLL], [/* Define to 1 if you have the `strcoll\' function and it is properly defined. +m4trace:configure.in:624: -1- AC_FUNC_STRCOLL +m4trace:configure.in:624: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRCOLL]) +m4trace:configure.in:624: -1- AH_OUTPUT([HAVE_STRCOLL], [/* Define to 1 if you have the `strcoll\' function and it is properly defined. */ #undef HAVE_STRCOLL]) -m4trace:configure.in:623: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VPRINTF]) -m4trace:configure.in:628: -1- AC_LIBSOURCE([vprint.c]) -m4trace:configure.in:628: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:632: -1- AC_TYPE_SIGNAL -m4trace:configure.in:632: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) -m4trace:configure.in:632: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ +m4trace:configure.in:645: -1- AC_DEFINE_TRACE_LITERAL([HAVE_VPRINTF]) +m4trace:configure.in:650: -1- AC_LIBSOURCE([vprint.c]) +m4trace:configure.in:650: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:654: -1- AC_TYPE_SIGNAL +m4trace:configure.in:654: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) +m4trace:configure.in:654: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ #undef RETSIGTYPE]) -m4trace:configure.in:635: -2- AC_DEFINE_TRACE_LITERAL([HAVE_SETOSTYPE]) -m4trace:configure.in:636: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WAIT3]) -m4trace:configure.in:637: -2- AC_DEFINE_TRACE_LITERAL([HAVE_ISINF_IN_LIBC]) -m4trace:configure.in:640: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MKFIFO]) -m4trace:configure.in:640: -2- AC_DEFINE_TRACE_LITERAL([MKFIFO_MISSING]) -m4trace:configure.in:646: -1- AC_CHECK_FUNCS([dup2 select getdtablesize getgroups gethostname \ +m4trace:configure.in:657: -2- AC_DEFINE_TRACE_LITERAL([HAVE_SETOSTYPE]) +m4trace:configure.in:658: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WAIT3]) +m4trace:configure.in:659: -2- AC_DEFINE_TRACE_LITERAL([HAVE_ISINF_IN_LIBC]) +m4trace:configure.in:662: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MKFIFO]) +m4trace:configure.in:662: -2- AC_DEFINE_TRACE_LITERAL([MKFIFO_MISSING]) +m4trace:configure.in:668: -1- AC_CHECK_FUNCS([dup2 select getdtablesize getgroups gethostname \ setdtablesize getpagesize killpg lstat getpeername sbrk \ getrlimit getrusage gettimeofday waitpid tcgetpgrp \ readlink]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_DUP2], [/* Define to 1 if you have the `dup2\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_DUP2], [/* Define to 1 if you have the `dup2\' function. */ #undef HAVE_DUP2]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_SELECT], [/* Define to 1 if you have the `select\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_SELECT], [/* Define to 1 if you have the `select\' function. */ #undef HAVE_SELECT]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETDTABLESIZE], [/* Define to 1 if you have the `getdtablesize\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETDTABLESIZE], [/* Define to 1 if you have the `getdtablesize\' function. */ #undef HAVE_GETDTABLESIZE]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETGROUPS], [/* Define to 1 if you have the `getgroups\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETGROUPS], [/* Define to 1 if you have the `getgroups\' function. */ #undef HAVE_GETGROUPS]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETHOSTNAME], [/* Define to 1 if you have the `gethostname\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETHOSTNAME], [/* Define to 1 if you have the `gethostname\' function. */ #undef HAVE_GETHOSTNAME]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_SETDTABLESIZE], [/* Define to 1 if you have the `setdtablesize\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_SETDTABLESIZE], [/* Define to 1 if you have the `setdtablesize\' function. */ #undef HAVE_SETDTABLESIZE]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ #undef HAVE_GETPAGESIZE]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_KILLPG], [/* Define to 1 if you have the `killpg\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_KILLPG], [/* Define to 1 if you have the `killpg\' function. */ #undef HAVE_KILLPG]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_LSTAT], [/* Define to 1 if you have the `lstat\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_LSTAT], [/* Define to 1 if you have the `lstat\' function. */ #undef HAVE_LSTAT]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETPEERNAME], [/* Define to 1 if you have the `getpeername\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETPEERNAME], [/* Define to 1 if you have the `getpeername\' function. */ #undef HAVE_GETPEERNAME]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_SBRK], [/* Define to 1 if you have the `sbrk\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_SBRK], [/* Define to 1 if you have the `sbrk\' function. */ #undef HAVE_SBRK]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETRLIMIT], [/* Define to 1 if you have the `getrlimit\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETRLIMIT], [/* Define to 1 if you have the `getrlimit\' function. */ #undef HAVE_GETRLIMIT]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETRUSAGE], [/* Define to 1 if you have the `getrusage\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETRUSAGE], [/* Define to 1 if you have the `getrusage\' function. */ #undef HAVE_GETRUSAGE]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_GETTIMEOFDAY], [/* Define to 1 if you have the `gettimeofday\' function. */ #undef HAVE_GETTIMEOFDAY]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_WAITPID], [/* Define to 1 if you have the `waitpid\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_WAITPID], [/* Define to 1 if you have the `waitpid\' function. */ #undef HAVE_WAITPID]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_TCGETPGRP], [/* Define to 1 if you have the `tcgetpgrp\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_TCGETPGRP], [/* Define to 1 if you have the `tcgetpgrp\' function. */ #undef HAVE_TCGETPGRP]) -m4trace:configure.in:646: -1- AH_OUTPUT([HAVE_READLINK], [/* Define to 1 if you have the `readlink\' function. */ +m4trace:configure.in:668: -1- AH_OUTPUT([HAVE_READLINK], [/* Define to 1 if you have the `readlink\' function. */ #undef HAVE_READLINK]) -m4trace:configure.in:647: -1- AC_LIBSOURCE([rename.c]) -m4trace:configure.in:647: -1- AC_CHECK_FUNCS([rename], [], [_AC_LIBOBJ($ac_func)]) -m4trace:configure.in:647: -1- AH_OUTPUT([HAVE_RENAME], [/* Define to 1 if you have the `rename\' function. */ +m4trace:configure.in:669: -1- AC_LIBSOURCE([rename.c]) +m4trace:configure.in:669: -1- AC_CHECK_FUNCS([rename], [], [_AC_LIBOBJ($ac_func)]) +m4trace:configure.in:669: -1- AH_OUTPUT([HAVE_RENAME], [/* Define to 1 if you have the `rename\' function. */ #undef HAVE_RENAME]) -m4trace:configure.in:647: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:654: -1- AC_CHECK_FUNCS([bcopy bzero confstr sysconf pathconf setenv putenv unsetenv \ +m4trace:configure.in:669: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:676: -1- AC_CHECK_FUNCS([bcopy bzero confstr sysconf pathconf setenv putenv unsetenv \ setlinebuf setvbuf setlocale strchr tcgetattr uname \ ulimit tzset siginterrupt memmove ttyname times raise \ getaddrinfo gethostbyname getservbyname getservent inet_aton \ vsnprintf snprintf vasprintf asprintf fnmatch regcomp regexec]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_BCOPY], [/* Define to 1 if you have the `bcopy\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_BCOPY], [/* Define to 1 if you have the `bcopy\' function. */ #undef HAVE_BCOPY]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_BZERO], [/* Define to 1 if you have the `bzero\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_BZERO], [/* Define to 1 if you have the `bzero\' function. */ #undef HAVE_BZERO]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_CONFSTR], [/* Define to 1 if you have the `confstr\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_CONFSTR], [/* Define to 1 if you have the `confstr\' function. */ #undef HAVE_CONFSTR]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SYSCONF], [/* Define to 1 if you have the `sysconf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SYSCONF], [/* Define to 1 if you have the `sysconf\' function. */ #undef HAVE_SYSCONF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_PATHCONF], [/* Define to 1 if you have the `pathconf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_PATHCONF], [/* Define to 1 if you have the `pathconf\' function. */ #undef HAVE_PATHCONF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SETENV], [/* Define to 1 if you have the `setenv\' function. */ #undef HAVE_SETENV]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_PUTENV], [/* Define to 1 if you have the `putenv\' function. */ #undef HAVE_PUTENV]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_UNSETENV], [/* Define to 1 if you have the `unsetenv\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_UNSETENV], [/* Define to 1 if you have the `unsetenv\' function. */ #undef HAVE_UNSETENV]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SETLINEBUF], [/* Define to 1 if you have the `setlinebuf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SETLINEBUF], [/* Define to 1 if you have the `setlinebuf\' function. */ #undef HAVE_SETLINEBUF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SETVBUF], [/* Define to 1 if you have the `setvbuf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SETVBUF], [/* Define to 1 if you have the `setvbuf\' function. */ #undef HAVE_SETVBUF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SETLOCALE], [/* Define to 1 if you have the `setlocale\' function. */ #undef HAVE_SETLOCALE]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_STRCHR], [/* Define to 1 if you have the `strchr\' function. */ #undef HAVE_STRCHR]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_TCGETATTR], [/* Define to 1 if you have the `tcgetattr\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_TCGETATTR], [/* Define to 1 if you have the `tcgetattr\' function. */ #undef HAVE_TCGETATTR]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_UNAME], [/* Define to 1 if you have the `uname\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_UNAME], [/* Define to 1 if you have the `uname\' function. */ #undef HAVE_UNAME]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_ULIMIT], [/* Define to 1 if you have the `ulimit\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_ULIMIT], [/* Define to 1 if you have the `ulimit\' function. */ #undef HAVE_ULIMIT]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_TZSET], [/* Define to 1 if you have the `tzset\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_TZSET], [/* Define to 1 if you have the `tzset\' function. */ #undef HAVE_TZSET]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SIGINTERRUPT], [/* Define to 1 if you have the `siginterrupt\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SIGINTERRUPT], [/* Define to 1 if you have the `siginterrupt\' function. */ #undef HAVE_SIGINTERRUPT]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_MEMMOVE], [/* Define to 1 if you have the `memmove\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_MEMMOVE], [/* Define to 1 if you have the `memmove\' function. */ #undef HAVE_MEMMOVE]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_TTYNAME], [/* Define to 1 if you have the `ttyname\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_TTYNAME], [/* Define to 1 if you have the `ttyname\' function. */ #undef HAVE_TTYNAME]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_TIMES], [/* Define to 1 if you have the `times\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_TIMES], [/* Define to 1 if you have the `times\' function. */ #undef HAVE_TIMES]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_RAISE], [/* Define to 1 if you have the `raise\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_RAISE], [/* Define to 1 if you have the `raise\' function. */ #undef HAVE_RAISE]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_GETADDRINFO], [/* Define to 1 if you have the `getaddrinfo\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_GETADDRINFO], [/* Define to 1 if you have the `getaddrinfo\' function. */ #undef HAVE_GETADDRINFO]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_GETHOSTBYNAME], [/* Define to 1 if you have the `gethostbyname\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_GETHOSTBYNAME], [/* Define to 1 if you have the `gethostbyname\' function. */ #undef HAVE_GETHOSTBYNAME]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_GETSERVBYNAME], [/* Define to 1 if you have the `getservbyname\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_GETSERVBYNAME], [/* Define to 1 if you have the `getservbyname\' function. */ #undef HAVE_GETSERVBYNAME]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_GETSERVENT], [/* Define to 1 if you have the `getservent\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_GETSERVENT], [/* Define to 1 if you have the `getservent\' function. */ #undef HAVE_GETSERVENT]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_INET_ATON], [/* Define to 1 if you have the `inet_aton\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_INET_ATON], [/* Define to 1 if you have the `inet_aton\' function. */ #undef HAVE_INET_ATON]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_VSNPRINTF], [/* Define to 1 if you have the `vsnprintf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_VSNPRINTF], [/* Define to 1 if you have the `vsnprintf\' function. */ #undef HAVE_VSNPRINTF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_SNPRINTF], [/* Define to 1 if you have the `snprintf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_SNPRINTF], [/* Define to 1 if you have the `snprintf\' function. */ #undef HAVE_SNPRINTF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_VASPRINTF], [/* Define to 1 if you have the `vasprintf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_VASPRINTF], [/* Define to 1 if you have the `vasprintf\' function. */ #undef HAVE_VASPRINTF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_ASPRINTF], [/* Define to 1 if you have the `asprintf\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_ASPRINTF], [/* Define to 1 if you have the `asprintf\' function. */ #undef HAVE_ASPRINTF]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_FNMATCH], [/* Define to 1 if you have the `fnmatch\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_FNMATCH], [/* Define to 1 if you have the `fnmatch\' function. */ #undef HAVE_FNMATCH]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_REGCOMP], [/* Define to 1 if you have the `regcomp\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_REGCOMP], [/* Define to 1 if you have the `regcomp\' function. */ #undef HAVE_REGCOMP]) -m4trace:configure.in:654: -1- AH_OUTPUT([HAVE_REGEXEC], [/* Define to 1 if you have the `regexec\' function. */ +m4trace:configure.in:676: -1- AH_OUTPUT([HAVE_REGEXEC], [/* Define to 1 if you have the `regexec\' function. */ #undef HAVE_REGEXEC]) -m4trace:configure.in:655: -1- AC_CHECK_FUNCS([isascii isblank isgraph isprint isspace isxdigit]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISASCII], [/* Define to 1 if you have the `isascii\' function. */ +m4trace:configure.in:677: -1- AC_CHECK_FUNCS([isascii isblank isgraph isprint isspace isxdigit]) +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISASCII], [/* Define to 1 if you have the `isascii\' function. */ #undef HAVE_ISASCII]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISBLANK], [/* Define to 1 if you have the `isblank\' function. */ +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISBLANK], [/* Define to 1 if you have the `isblank\' function. */ #undef HAVE_ISBLANK]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISGRAPH], [/* Define to 1 if you have the `isgraph\' function. */ +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISGRAPH], [/* Define to 1 if you have the `isgraph\' function. */ #undef HAVE_ISGRAPH]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISPRINT], [/* Define to 1 if you have the `isprint\' function. */ +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISPRINT], [/* Define to 1 if you have the `isprint\' function. */ #undef HAVE_ISPRINT]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISSPACE], [/* Define to 1 if you have the `isspace\' function. */ +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISSPACE], [/* Define to 1 if you have the `isspace\' function. */ #undef HAVE_ISSPACE]) -m4trace:configure.in:655: -1- AH_OUTPUT([HAVE_ISXDIGIT], [/* Define to 1 if you have the `isxdigit\' function. */ +m4trace:configure.in:677: -1- AH_OUTPUT([HAVE_ISXDIGIT], [/* Define to 1 if you have the `isxdigit\' function. */ #undef HAVE_ISXDIGIT]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([getcwd.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strcasecmp.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strerror.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strftime.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strpbrk.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([memset.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strstr.c]) -m4trace:configure.in:656: -1- AC_LIBSOURCE([strnlen.c]) -m4trace:configure.in:656: -1- AC_CHECK_FUNCS([getcwd strcasecmp strerror strftime strpbrk memset strstr strnlen], [], [_AC_LIBOBJ($ac_func)]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ +m4trace:configure.in:678: -1- AC_LIBSOURCE([getcwd.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strcasecmp.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strerror.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strftime.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strpbrk.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([memset.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strstr.c]) +m4trace:configure.in:678: -1- AC_LIBSOURCE([strnlen.c]) +m4trace:configure.in:678: -1- AC_CHECK_FUNCS([getcwd strcasecmp strerror strftime strpbrk memset strstr strnlen], [], [_AC_LIBOBJ($ac_func)]) +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_GETCWD], [/* Define to 1 if you have the `getcwd\' function. */ #undef HAVE_GETCWD]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRCASECMP], [/* Define to 1 if you have the `strcasecmp\' function. */ #undef HAVE_STRCASECMP]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRERROR], [/* Define to 1 if you have the `strerror\' function. */ #undef HAVE_STRERROR]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRFTIME], [/* Define to 1 if you have the `strftime\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRFTIME], [/* Define to 1 if you have the `strftime\' function. */ #undef HAVE_STRFTIME]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRPBRK], [/* Define to 1 if you have the `strpbrk\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRPBRK], [/* Define to 1 if you have the `strpbrk\' function. */ #undef HAVE_STRPBRK]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_MEMSET], [/* Define to 1 if you have the `memset\' function. */ #undef HAVE_MEMSET]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRSTR], [/* Define to 1 if you have the `strstr\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRSTR], [/* Define to 1 if you have the `strstr\' function. */ #undef HAVE_STRSTR]) -m4trace:configure.in:656: -1- AH_OUTPUT([HAVE_STRNLEN], [/* Define to 1 if you have the `strnlen\' function. */ +m4trace:configure.in:678: -1- AH_OUTPUT([HAVE_STRNLEN], [/* Define to 1 if you have the `strnlen\' function. */ #undef HAVE_STRNLEN]) -m4trace:configure.in:656: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtod.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtol.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtoul.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtoll.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtoull.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtoimax.c]) -m4trace:configure.in:657: -1- AC_LIBSOURCE([strtoumax.c]) -m4trace:configure.in:657: -1- AC_CHECK_FUNCS([strtod strtol strtoul strtoll strtoull strtoimax strtoumax], [], [_AC_LIBOBJ($ac_func)]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOD], [/* Define to 1 if you have the `strtod\' function. */ +m4trace:configure.in:678: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtod.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtol.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtoul.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtoll.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtoull.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtoimax.c]) +m4trace:configure.in:679: -1- AC_LIBSOURCE([strtoumax.c]) +m4trace:configure.in:679: -1- AC_CHECK_FUNCS([strtod strtol strtoul strtoll strtoull strtoimax strtoumax], [], [_AC_LIBOBJ($ac_func)]) +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOD], [/* Define to 1 if you have the `strtod\' function. */ #undef HAVE_STRTOD]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOL], [/* Define to 1 if you have the `strtol\' function. */ #undef HAVE_STRTOL]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOUL], [/* Define to 1 if you have the `strtoul\' function. */ #undef HAVE_STRTOUL]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOLL], [/* Define to 1 if you have the `strtoll\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOLL], [/* Define to 1 if you have the `strtoll\' function. */ #undef HAVE_STRTOLL]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOULL], [/* Define to 1 if you have the `strtoull\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOULL], [/* Define to 1 if you have the `strtoull\' function. */ #undef HAVE_STRTOULL]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOIMAX], [/* Define to 1 if you have the `strtoimax\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOIMAX], [/* Define to 1 if you have the `strtoimax\' function. */ #undef HAVE_STRTOIMAX]) -m4trace:configure.in:657: -1- AH_OUTPUT([HAVE_STRTOUMAX], [/* Define to 1 if you have the `strtoumax\' function. */ +m4trace:configure.in:679: -1- AH_OUTPUT([HAVE_STRTOUMAX], [/* Define to 1 if you have the `strtoumax\' function. */ #undef HAVE_STRTOUMAX]) -m4trace:configure.in:657: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:659: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_CONFSTR]) -m4trace:configure.in:659: -1- AH_OUTPUT([HAVE_DECL_CONFSTR], [/* Define to 1 if you have the declaration of `confstr\', and to 0 if you +m4trace:configure.in:679: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:681: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_CONFSTR]) +m4trace:configure.in:681: -1- AH_OUTPUT([HAVE_DECL_CONFSTR], [/* Define to 1 if you have the declaration of `confstr\', and to 0 if you don\'t. */ #undef HAVE_DECL_CONFSTR]) -m4trace:configure.in:659: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_CONFSTR]) -m4trace:configure.in:660: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_PRINTF]) -m4trace:configure.in:660: -1- AH_OUTPUT([HAVE_DECL_PRINTF], [/* Define to 1 if you have the declaration of `printf\', and to 0 if you don\'t. +m4trace:configure.in:681: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_CONFSTR]) +m4trace:configure.in:682: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_PRINTF]) +m4trace:configure.in:682: -1- AH_OUTPUT([HAVE_DECL_PRINTF], [/* Define to 1 if you have the declaration of `printf\', and to 0 if you don\'t. */ #undef HAVE_DECL_PRINTF]) -m4trace:configure.in:660: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_PRINTF]) -m4trace:configure.in:661: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SBRK]) -m4trace:configure.in:661: -1- AH_OUTPUT([HAVE_DECL_SBRK], [/* Define to 1 if you have the declaration of `sbrk\', and to 0 if you don\'t. +m4trace:configure.in:682: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_PRINTF]) +m4trace:configure.in:683: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SBRK]) +m4trace:configure.in:683: -1- AH_OUTPUT([HAVE_DECL_SBRK], [/* Define to 1 if you have the declaration of `sbrk\', and to 0 if you don\'t. */ #undef HAVE_DECL_SBRK]) -m4trace:configure.in:661: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SBRK]) -m4trace:configure.in:662: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRCPY]) -m4trace:configure.in:662: -1- AH_OUTPUT([HAVE_DECL_STRCPY], [/* Define to 1 if you have the declaration of `strcpy\', and to 0 if you don\'t. +m4trace:configure.in:683: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SBRK]) +m4trace:configure.in:684: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRCPY]) +m4trace:configure.in:684: -1- AH_OUTPUT([HAVE_DECL_STRCPY], [/* Define to 1 if you have the declaration of `strcpy\', and to 0 if you don\'t. */ #undef HAVE_DECL_STRCPY]) -m4trace:configure.in:662: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRCPY]) -m4trace:configure.in:663: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRSIGNAL]) -m4trace:configure.in:663: -1- AH_OUTPUT([HAVE_DECL_STRSIGNAL], [/* Define to 1 if you have the declaration of `strsignal\', and to 0 if you +m4trace:configure.in:684: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRCPY]) +m4trace:configure.in:685: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRSIGNAL]) +m4trace:configure.in:685: -1- AH_OUTPUT([HAVE_DECL_STRSIGNAL], [/* Define to 1 if you have the declaration of `strsignal\', and to 0 if you don\'t. */ #undef HAVE_DECL_STRSIGNAL]) -m4trace:configure.in:663: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRSIGNAL]) -m4trace:configure.in:680: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRTOLD]) -m4trace:configure.in:680: -1- AH_OUTPUT([HAVE_DECL_STRTOLD], [/* Define to 1 if you have the declaration of `strtold\', and to 0 if you +m4trace:configure.in:685: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRSIGNAL]) +m4trace:configure.in:702: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRTOLD]) +m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_DECL_STRTOLD], [/* Define to 1 if you have the declaration of `strtold\', and to 0 if you don\'t. */ #undef HAVE_DECL_STRTOLD]) -m4trace:configure.in:680: -1- AC_DEFINE_TRACE_LITERAL([STRTOLD_BROKEN]) -m4trace:configure.in:680: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRTOLD]) -m4trace:configure.in:690: -1- AC_FUNC_MKTIME -m4trace:configure.in:690: -1- AC_CHECK_HEADERS([sys/time.h unistd.h]) -m4trace:configure.in:690: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:702: -1- AC_DEFINE_TRACE_LITERAL([STRTOLD_BROKEN]) +m4trace:configure.in:702: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_STRTOLD]) +m4trace:configure.in:712: -1- AC_FUNC_MKTIME +m4trace:configure.in:712: -1- AC_CHECK_HEADERS([sys/time.h unistd.h]) +m4trace:configure.in:712: -1- AH_OUTPUT([HAVE_SYS_TIME_H], [/* Define to 1 if you have the header file. */ #undef HAVE_SYS_TIME_H]) -m4trace:configure.in:690: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:712: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H]) -m4trace:configure.in:690: -1- AC_CHECK_FUNCS([alarm]) -m4trace:configure.in:690: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */ +m4trace:configure.in:712: -1- AC_CHECK_FUNCS([alarm]) +m4trace:configure.in:712: -1- AH_OUTPUT([HAVE_ALARM], [/* Define to 1 if you have the `alarm\' function. */ #undef HAVE_ALARM]) -m4trace:configure.in:690: -1- AC_LIBSOURCE([mktime.c]) -m4trace:configure.in:690: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:697: -1- AC_CHECK_HEADERS([argz.h errno.h fcntl.h malloc.h stdio_ext.h]) -m4trace:configure.in:697: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:712: -1- AC_LIBSOURCE([mktime.c]) +m4trace:configure.in:712: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:719: -1- AC_CHECK_HEADERS([argz.h errno.h fcntl.h malloc.h stdio_ext.h]) +m4trace:configure.in:719: -1- AH_OUTPUT([HAVE_ARGZ_H], [/* Define to 1 if you have the header file. */ #undef HAVE_ARGZ_H]) -m4trace:configure.in:697: -1- AH_OUTPUT([HAVE_ERRNO_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:719: -1- AH_OUTPUT([HAVE_ERRNO_H], [/* Define to 1 if you have the header file. */ #undef HAVE_ERRNO_H]) -m4trace:configure.in:697: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:719: -1- AH_OUTPUT([HAVE_FCNTL_H], [/* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H]) -m4trace:configure.in:697: -1- AH_OUTPUT([HAVE_MALLOC_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:719: -1- AH_OUTPUT([HAVE_MALLOC_H], [/* Define to 1 if you have the header file. */ #undef HAVE_MALLOC_H]) -m4trace:configure.in:697: -1- AH_OUTPUT([HAVE_STDIO_EXT_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:719: -1- AH_OUTPUT([HAVE_STDIO_EXT_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDIO_EXT_H]) -m4trace:configure.in:700: -1- AC_FUNC_MMAP -m4trace:configure.in:700: -1- AC_CHECK_HEADERS([stdlib.h unistd.h]) -m4trace:configure.in:700: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:722: -1- AC_FUNC_MMAP +m4trace:configure.in:722: -1- AC_CHECK_HEADERS([stdlib.h unistd.h]) +m4trace:configure.in:722: -1- AH_OUTPUT([HAVE_STDLIB_H], [/* Define to 1 if you have the header file. */ #undef HAVE_STDLIB_H]) -m4trace:configure.in:700: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:722: -1- AH_OUTPUT([HAVE_UNISTD_H], [/* Define to 1 if you have the header file. */ #undef HAVE_UNISTD_H]) -m4trace:configure.in:700: -1- AC_CHECK_FUNCS([getpagesize]) -m4trace:configure.in:700: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ +m4trace:configure.in:722: -1- AC_CHECK_FUNCS([getpagesize]) +m4trace:configure.in:722: -1- AH_OUTPUT([HAVE_GETPAGESIZE], [/* Define to 1 if you have the `getpagesize\' function. */ #undef HAVE_GETPAGESIZE]) -m4trace:configure.in:700: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) -m4trace:configure.in:700: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ +m4trace:configure.in:722: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MMAP]) +m4trace:configure.in:722: -1- AH_OUTPUT([HAVE_MMAP], [/* Define to 1 if you have a working `mmap\' system call. */ #undef HAVE_MMAP]) -m4trace:configure.in:702: -1- AC_CHECK_FUNCS([__argz_count __argz_next __argz_stringify dcgettext mempcpy \ +m4trace:configure.in:724: -1- AC_CHECK_FUNCS([__argz_count __argz_next __argz_stringify dcgettext mempcpy \ munmap stpcpy strcspn strdup]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE___ARGZ_COUNT], [/* Define to 1 if you have the `__argz_count\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE___ARGZ_COUNT], [/* Define to 1 if you have the `__argz_count\' function. */ #undef HAVE___ARGZ_COUNT]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE___ARGZ_NEXT], [/* Define to 1 if you have the `__argz_next\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE___ARGZ_NEXT], [/* Define to 1 if you have the `__argz_next\' function. */ #undef HAVE___ARGZ_NEXT]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE___ARGZ_STRINGIFY], [/* Define to 1 if you have the `__argz_stringify\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE___ARGZ_STRINGIFY], [/* Define to 1 if you have the `__argz_stringify\' function. */ #undef HAVE___ARGZ_STRINGIFY]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define to 1 if you have the `dcgettext\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_DCGETTEXT], [/* Define to 1 if you have the `dcgettext\' function. */ #undef HAVE_DCGETTEXT]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_MEMPCPY], [/* Define to 1 if you have the `mempcpy\' function. */ #undef HAVE_MEMPCPY]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_MUNMAP], [/* Define to 1 if you have the `munmap\' function. */ #undef HAVE_MUNMAP]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_STPCPY], [/* Define to 1 if you have the `stpcpy\' function. */ #undef HAVE_STPCPY]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_STRCSPN], [/* Define to 1 if you have the `strcspn\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_STRCSPN], [/* Define to 1 if you have the `strcspn\' function. */ #undef HAVE_STRCSPN]) -m4trace:configure.in:702: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ +m4trace:configure.in:724: -1- AH_OUTPUT([HAVE_STRDUP], [/* Define to 1 if you have the `strdup\' function. */ #undef HAVE_STRDUP]) -m4trace:configure.in:710: -1- AC_SUBST([INTL_DEP]) -m4trace:configure.in:711: -1- AC_SUBST([INTL_INC]) -m4trace:configure.in:712: -1- AC_SUBST([LIBINTL_H]) -m4trace:configure.in:718: -1- AC_CHECK_HEADERS([wctype.h]) -m4trace:configure.in:718: -1- AH_OUTPUT([HAVE_WCTYPE_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:732: -1- AC_SUBST([INTL_DEP]) +m4trace:configure.in:733: -1- AC_SUBST([INTL_INC]) +m4trace:configure.in:734: -1- AC_SUBST([LIBINTL_H]) +m4trace:configure.in:740: -1- AC_CHECK_HEADERS([wctype.h]) +m4trace:configure.in:740: -1- AH_OUTPUT([HAVE_WCTYPE_H], [/* Define to 1 if you have the header file. */ #undef HAVE_WCTYPE_H]) -m4trace:configure.in:718: -1- AC_CHECK_HEADERS([wchar.h]) -m4trace:configure.in:718: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:740: -1- AC_CHECK_HEADERS([wchar.h]) +m4trace:configure.in:740: -1- AH_OUTPUT([HAVE_WCHAR_H], [/* Define to 1 if you have the header file. */ #undef HAVE_WCHAR_H]) -m4trace:configure.in:718: -1- AC_CHECK_HEADERS([langinfo.h]) -m4trace:configure.in:718: -1- AH_OUTPUT([HAVE_LANGINFO_H], [/* Define to 1 if you have the header file. */ +m4trace:configure.in:740: -1- AC_CHECK_HEADERS([langinfo.h]) +m4trace:configure.in:740: -1- AH_OUTPUT([HAVE_LANGINFO_H], [/* Define to 1 if you have the header file. */ #undef HAVE_LANGINFO_H]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSRTOWCS]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBRTOWC]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBRLEN]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCTOMB]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCWIDTH]) -m4trace:configure.in:718: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCSDUP]) -m4trace:configure.in:718: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBSTATE_T]) -m4trace:configure.in:718: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) -m4trace:configure.in:722: -1- AC_CHECK_LIB([dl], [dlopen]) -m4trace:configure.in:722: -1- AH_OUTPUT([HAVE_LIBDL], [/* Define to 1 if you have the `dl\' library (-ldl). */ +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBSRTOWCS]) +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBRTOWC]) +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_MBRLEN]) +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCTOMB]) +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCWIDTH]) +m4trace:configure.in:740: -2- AC_DEFINE_TRACE_LITERAL([HAVE_WCSDUP]) +m4trace:configure.in:740: -1- AC_DEFINE_TRACE_LITERAL([HAVE_MBSTATE_T]) +m4trace:configure.in:740: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LANGINFO_CODESET]) +m4trace:configure.in:744: -1- AC_CHECK_LIB([dl], [dlopen]) +m4trace:configure.in:744: -1- AH_OUTPUT([HAVE_LIBDL], [/* Define to 1 if you have the `dl\' library (-ldl). */ #undef HAVE_LIBDL]) -m4trace:configure.in:722: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBDL]) -m4trace:configure.in:723: -1- AC_CHECK_FUNCS([dlopen dlclose dlsym]) -m4trace:configure.in:723: -1- AH_OUTPUT([HAVE_DLOPEN], [/* Define to 1 if you have the `dlopen\' function. */ +m4trace:configure.in:744: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBDL]) +m4trace:configure.in:745: -1- AC_CHECK_FUNCS([dlopen dlclose dlsym]) +m4trace:configure.in:745: -1- AH_OUTPUT([HAVE_DLOPEN], [/* Define to 1 if you have the `dlopen\' function. */ #undef HAVE_DLOPEN]) -m4trace:configure.in:723: -1- AH_OUTPUT([HAVE_DLCLOSE], [/* Define to 1 if you have the `dlclose\' function. */ +m4trace:configure.in:745: -1- AH_OUTPUT([HAVE_DLCLOSE], [/* Define to 1 if you have the `dlclose\' function. */ #undef HAVE_DLCLOSE]) -m4trace:configure.in:723: -1- AH_OUTPUT([HAVE_DLSYM], [/* Define to 1 if you have the `dlsym\' function. */ +m4trace:configure.in:745: -1- AH_OUTPUT([HAVE_DLSYM], [/* Define to 1 if you have the `dlsym\' function. */ #undef HAVE_DLSYM]) -m4trace:configure.in:727: -1- AC_DECL_SYS_SIGLIST -m4trace:configure.in:727: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SYS_SIGLIST]) -m4trace:configure.in:727: -1- AH_OUTPUT([HAVE_DECL_SYS_SIGLIST], [/* Define to 1 if you have the declaration of `sys_siglist\', and to 0 if you +m4trace:configure.in:749: -1- AC_DECL_SYS_SIGLIST +m4trace:configure.in:749: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SYS_SIGLIST]) +m4trace:configure.in:749: -1- AH_OUTPUT([HAVE_DECL_SYS_SIGLIST], [/* Define to 1 if you have the declaration of `sys_siglist\', and to 0 if you don\'t. */ #undef HAVE_DECL_SYS_SIGLIST]) -m4trace:configure.in:727: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SYS_SIGLIST]) -m4trace:configure.in:731: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INET_ATON]) -m4trace:configure.in:731: -1- AC_LIBSOURCE([inet_aton.c]) -m4trace:configure.in:731: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:737: -1- AC_CHECK_LIB([sun], [getpwent]) -m4trace:configure.in:737: -1- AH_OUTPUT([HAVE_LIBSUN], [/* Define to 1 if you have the `sun\' library (-lsun). */ +m4trace:configure.in:749: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DECL_SYS_SIGLIST]) +m4trace:configure.in:753: -1- AC_DEFINE_TRACE_LITERAL([HAVE_INET_ATON]) +m4trace:configure.in:753: -1- AC_LIBSOURCE([inet_aton.c]) +m4trace:configure.in:753: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:759: -1- AC_CHECK_LIB([sun], [getpwent]) +m4trace:configure.in:759: -1- AH_OUTPUT([HAVE_LIBSUN], [/* Define to 1 if you have the `sun\' library (-lsun). */ #undef HAVE_LIBSUN]) -m4trace:configure.in:737: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSUN]) -m4trace:configure.in:742: -1- AC_CHECK_LIB([socket], [getpeername], [bash_cv_have_socklib=yes], [bash_cv_have_socklib=no], [-lnsl]) -m4trace:configure.in:742: -1- AC_CHECK_LIB([nsl], [t_open], [bash_cv_have_libnsl=yes], [bash_cv_have_libnsl=no]) -m4trace:configure.in:742: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET]) -m4trace:configure.in:742: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPEERNAME]) -m4trace:configure.in:746: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETHOSTBYNAME]) -m4trace:configure.in:750: -1- AC_TYPE_UID_T -m4trace:configure.in:750: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) -m4trace:configure.in:750: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.in:759: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSUN]) +m4trace:configure.in:764: -1- AC_CHECK_LIB([socket], [getpeername], [bash_cv_have_socklib=yes], [bash_cv_have_socklib=no], [-lnsl]) +m4trace:configure.in:764: -1- AC_CHECK_LIB([nsl], [t_open], [bash_cv_have_libnsl=yes], [bash_cv_have_libnsl=no]) +m4trace:configure.in:764: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LIBSOCKET]) +m4trace:configure.in:764: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPEERNAME]) +m4trace:configure.in:768: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETHOSTBYNAME]) +m4trace:configure.in:772: -1- AC_TYPE_UID_T +m4trace:configure.in:772: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) +m4trace:configure.in:772: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ #undef uid_t]) -m4trace:configure.in:750: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) -m4trace:configure.in:750: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.in:772: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) +m4trace:configure.in:772: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ #undef gid_t]) -m4trace:configure.in:750: -1- AC_DEFINE_TRACE_LITERAL([GETGROUPS_T]) -m4trace:configure.in:750: -1- AH_OUTPUT([GETGROUPS_T], [/* Define to the type of elements in the array set by `getgroups\'. Usually +m4trace:configure.in:772: -1- AC_DEFINE_TRACE_LITERAL([GETGROUPS_T]) +m4trace:configure.in:772: -1- AH_OUTPUT([GETGROUPS_T], [/* Define to the type of elements in the array set by `getgroups\'. Usually this is either `int\' or `gid_t\'. */ #undef GETGROUPS_T]) -m4trace:configure.in:751: -1- AC_TYPE_OFF_T -m4trace:configure.in:751: -1- AC_DEFINE_TRACE_LITERAL([off_t]) -m4trace:configure.in:751: -1- AH_OUTPUT([off_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:773: -1- AC_TYPE_OFF_T +m4trace:configure.in:773: -1- AC_DEFINE_TRACE_LITERAL([off_t]) +m4trace:configure.in:773: -1- AH_OUTPUT([off_t], [/* Define to `long\' if does not define. */ #undef off_t]) -m4trace:configure.in:752: -1- AC_TYPE_MODE_T -m4trace:configure.in:752: -1- AC_DEFINE_TRACE_LITERAL([mode_t]) -m4trace:configure.in:752: -1- AH_OUTPUT([mode_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:774: -1- AC_TYPE_MODE_T +m4trace:configure.in:774: -1- AC_DEFINE_TRACE_LITERAL([mode_t]) +m4trace:configure.in:774: -1- AH_OUTPUT([mode_t], [/* Define to `int\' if does not define. */ #undef mode_t]) -m4trace:configure.in:753: -1- AC_TYPE_UID_T -m4trace:configure.in:753: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) -m4trace:configure.in:753: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.in:775: -1- AC_TYPE_UID_T +m4trace:configure.in:775: -1- AC_DEFINE_TRACE_LITERAL([uid_t]) +m4trace:configure.in:775: -1- AH_OUTPUT([uid_t], [/* Define to `int\' if doesn\'t define. */ #undef uid_t]) -m4trace:configure.in:753: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) -m4trace:configure.in:753: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ +m4trace:configure.in:775: -1- AC_DEFINE_TRACE_LITERAL([gid_t]) +m4trace:configure.in:775: -1- AH_OUTPUT([gid_t], [/* Define to `int\' if doesn\'t define. */ #undef gid_t]) -m4trace:configure.in:754: -1- AC_TYPE_PID_T -m4trace:configure.in:754: -1- AC_DEFINE_TRACE_LITERAL([pid_t]) -m4trace:configure.in:754: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:776: -1- AC_TYPE_PID_T +m4trace:configure.in:776: -1- AC_DEFINE_TRACE_LITERAL([pid_t]) +m4trace:configure.in:776: -1- AH_OUTPUT([pid_t], [/* Define to `int\' if does not define. */ #undef pid_t]) -m4trace:configure.in:755: -1- AC_TYPE_SIZE_T -m4trace:configure.in:755: -1- AC_DEFINE_TRACE_LITERAL([size_t]) -m4trace:configure.in:755: -1- AH_OUTPUT([size_t], [/* Define to `unsigned\' if does not define. */ +m4trace:configure.in:777: -1- AC_TYPE_SIZE_T +m4trace:configure.in:777: -1- AC_DEFINE_TRACE_LITERAL([size_t]) +m4trace:configure.in:777: -1- AH_OUTPUT([size_t], [/* Define to `unsigned\' if does not define. */ #undef size_t]) -m4trace:configure.in:756: -1- AC_DEFINE_TRACE_LITERAL([ssize_t]) -m4trace:configure.in:756: -1- AH_OUTPUT([ssize_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:778: -1- AC_DEFINE_TRACE_LITERAL([ssize_t]) +m4trace:configure.in:778: -1- AH_OUTPUT([ssize_t], [/* Define to `int\' if does not define. */ #undef ssize_t]) -m4trace:configure.in:757: -1- AC_DEFINE_TRACE_LITERAL([time_t]) -m4trace:configure.in:757: -1- AH_OUTPUT([time_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([time_t]) +m4trace:configure.in:779: -1- AH_OUTPUT([time_t], [/* Define to `long\' if does not define. */ #undef time_t]) -m4trace:configure.in:759: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_LONG]) -m4trace:configure.in:760: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG]) -m4trace:configure.in:762: -1- AC_TYPE_SIGNAL -m4trace:configure.in:762: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) -m4trace:configure.in:762: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ +m4trace:configure.in:781: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LONG_LONG]) +m4trace:configure.in:782: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNSIGNED_LONG_LONG]) +m4trace:configure.in:784: -1- AC_TYPE_SIGNAL +m4trace:configure.in:784: -1- AC_DEFINE_TRACE_LITERAL([RETSIGTYPE]) +m4trace:configure.in:784: -1- AH_OUTPUT([RETSIGTYPE], [/* Define as the return type of signal handlers (`int\' or `void\'). */ #undef RETSIGTYPE]) -m4trace:configure.in:764: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR]) -m4trace:configure.in:764: -1- AH_OUTPUT([SIZEOF_CHAR], [/* The size of a `char\', as computed by sizeof. */ +m4trace:configure.in:786: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR]) +m4trace:configure.in:786: -1- AH_OUTPUT([SIZEOF_CHAR], [/* The size of a `char\', as computed by sizeof. */ #undef SIZEOF_CHAR]) -m4trace:configure.in:765: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SHORT]) -m4trace:configure.in:765: -1- AH_OUTPUT([SIZEOF_SHORT], [/* The size of a `short\', as computed by sizeof. */ +m4trace:configure.in:787: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_SHORT]) +m4trace:configure.in:787: -1- AH_OUTPUT([SIZEOF_SHORT], [/* The size of a `short\', as computed by sizeof. */ #undef SIZEOF_SHORT]) -m4trace:configure.in:766: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT]) -m4trace:configure.in:766: -1- AH_OUTPUT([SIZEOF_INT], [/* The size of a `int\', as computed by sizeof. */ +m4trace:configure.in:788: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_INT]) +m4trace:configure.in:788: -1- AH_OUTPUT([SIZEOF_INT], [/* The size of a `int\', as computed by sizeof. */ #undef SIZEOF_INT]) -m4trace:configure.in:767: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG]) -m4trace:configure.in:767: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of a `long\', as computed by sizeof. */ +m4trace:configure.in:789: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG]) +m4trace:configure.in:789: -1- AH_OUTPUT([SIZEOF_LONG], [/* The size of a `long\', as computed by sizeof. */ #undef SIZEOF_LONG]) -m4trace:configure.in:768: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR_P]) -m4trace:configure.in:768: -1- AH_OUTPUT([SIZEOF_CHAR_P], [/* The size of a `char *\', as computed by sizeof. */ +m4trace:configure.in:790: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_CHAR_P]) +m4trace:configure.in:790: -1- AH_OUTPUT([SIZEOF_CHAR_P], [/* The size of a `char *\', as computed by sizeof. */ #undef SIZEOF_CHAR_P]) -m4trace:configure.in:769: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_DOUBLE]) -m4trace:configure.in:769: -1- AH_OUTPUT([SIZEOF_DOUBLE], [/* The size of a `double\', as computed by sizeof. */ +m4trace:configure.in:791: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_DOUBLE]) +m4trace:configure.in:791: -1- AH_OUTPUT([SIZEOF_DOUBLE], [/* The size of a `double\', as computed by sizeof. */ #undef SIZEOF_DOUBLE]) -m4trace:configure.in:770: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG_LONG]) -m4trace:configure.in:770: -1- AH_OUTPUT([SIZEOF_LONG_LONG], [/* The size of a `long long\', as computed by sizeof. */ +m4trace:configure.in:792: -1- AC_DEFINE_TRACE_LITERAL([SIZEOF_LONG_LONG]) +m4trace:configure.in:792: -1- AH_OUTPUT([SIZEOF_LONG_LONG], [/* The size of a `long long\', as computed by sizeof. */ #undef SIZEOF_LONG_LONG]) -m4trace:configure.in:772: -1- AC_DEFINE_TRACE_LITERAL([u_int]) -m4trace:configure.in:772: -1- AH_OUTPUT([u_int], [/* Define to `unsigned int\' if does not define. */ +m4trace:configure.in:794: -1- AC_DEFINE_TRACE_LITERAL([u_int]) +m4trace:configure.in:794: -1- AH_OUTPUT([u_int], [/* Define to `unsigned int\' if does not define. */ #undef u_int]) -m4trace:configure.in:773: -1- AC_DEFINE_TRACE_LITERAL([u_long]) -m4trace:configure.in:773: -1- AH_OUTPUT([u_long], [/* Define to `unsigned long\' if does not define. */ +m4trace:configure.in:795: -1- AC_DEFINE_TRACE_LITERAL([u_long]) +m4trace:configure.in:795: -1- AH_OUTPUT([u_long], [/* Define to `unsigned long\' if does not define. */ #undef u_long]) -m4trace:configure.in:775: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.in:775: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ +m4trace:configure.in:797: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) +m4trace:configure.in:797: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ #undef bits16_t]) -m4trace:configure.in:775: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.in:775: -1- AH_OUTPUT([bits16_t], [/* Define to `char\' if does not define. */ +m4trace:configure.in:797: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) +m4trace:configure.in:797: -1- AH_OUTPUT([bits16_t], [/* Define to `char\' if does not define. */ #undef bits16_t]) -m4trace:configure.in:775: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) -m4trace:configure.in:775: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ +m4trace:configure.in:797: -1- AC_DEFINE_TRACE_LITERAL([bits16_t]) +m4trace:configure.in:797: -1- AH_OUTPUT([bits16_t], [/* Define to `short\' if does not define. */ #undef bits16_t]) -m4trace:configure.in:776: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.in:776: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ +m4trace:configure.in:798: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) +m4trace:configure.in:798: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ #undef u_bits16_t]) -m4trace:configure.in:776: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.in:776: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned char\' if does not define. */ +m4trace:configure.in:798: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) +m4trace:configure.in:798: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned char\' if does not define. */ #undef u_bits16_t]) -m4trace:configure.in:776: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) -m4trace:configure.in:776: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ +m4trace:configure.in:798: -1- AC_DEFINE_TRACE_LITERAL([u_bits16_t]) +m4trace:configure.in:798: -1- AH_OUTPUT([u_bits16_t], [/* Define to `unsigned short\' if does not define. */ #undef u_bits16_t]) -m4trace:configure.in:777: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.in:777: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:799: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) +m4trace:configure.in:799: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ #undef bits32_t]) -m4trace:configure.in:777: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.in:777: -1- AH_OUTPUT([bits32_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:799: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) +m4trace:configure.in:799: -1- AH_OUTPUT([bits32_t], [/* Define to `long\' if does not define. */ #undef bits32_t]) -m4trace:configure.in:777: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) -m4trace:configure.in:777: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:799: -1- AC_DEFINE_TRACE_LITERAL([bits32_t]) +m4trace:configure.in:799: -1- AH_OUTPUT([bits32_t], [/* Define to `int\' if does not define. */ #undef bits32_t]) -m4trace:configure.in:778: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.in:778: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ +m4trace:configure.in:800: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) +m4trace:configure.in:800: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ #undef u_bits32_t]) -m4trace:configure.in:778: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.in:778: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned long\' if does not define. */ +m4trace:configure.in:800: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) +m4trace:configure.in:800: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned long\' if does not define. */ #undef u_bits32_t]) -m4trace:configure.in:778: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) -m4trace:configure.in:778: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ +m4trace:configure.in:800: -1- AC_DEFINE_TRACE_LITERAL([u_bits32_t]) +m4trace:configure.in:800: -1- AH_OUTPUT([u_bits32_t], [/* Define to `unsigned int\' if does not define. */ #undef u_bits32_t]) -m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.in:779: -1- AH_OUTPUT([bits64_t], [/* Define to `char *\' if does not define. */ +m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) +m4trace:configure.in:801: -1- AH_OUTPUT([bits64_t], [/* Define to `char *\' if does not define. */ #undef bits64_t]) -m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.in:779: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ +m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) +m4trace:configure.in:801: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ #undef bits64_t]) -m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.in:779: -1- AH_OUTPUT([bits64_t], [/* Define to `long long\' if does not define. */ +m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) +m4trace:configure.in:801: -1- AH_OUTPUT([bits64_t], [/* Define to `long long\' if does not define. */ #undef bits64_t]) -m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.in:779: -1- AH_OUTPUT([bits64_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) +m4trace:configure.in:801: -1- AH_OUTPUT([bits64_t], [/* Define to `long\' if does not define. */ #undef bits64_t]) -m4trace:configure.in:779: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) -m4trace:configure.in:779: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ +m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([bits64_t]) +m4trace:configure.in:801: -1- AH_OUTPUT([bits64_t], [/* Define to `double\' if does not define. */ #undef bits64_t]) -m4trace:configure.in:781: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.in:781: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:803: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) +m4trace:configure.in:803: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ #undef ptrdiff_t]) -m4trace:configure.in:781: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.in:781: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long\' if does not define. */ +m4trace:configure.in:803: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) +m4trace:configure.in:803: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long\' if does not define. */ #undef ptrdiff_t]) -m4trace:configure.in:781: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.in:781: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long long\' if does not define. */ +m4trace:configure.in:803: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) +m4trace:configure.in:803: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `long long\' if does not define. */ #undef ptrdiff_t]) -m4trace:configure.in:781: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) -m4trace:configure.in:781: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ +m4trace:configure.in:803: -1- AC_DEFINE_TRACE_LITERAL([ptrdiff_t]) +m4trace:configure.in:803: -1- AH_OUTPUT([ptrdiff_t], [/* Define to `int\' if does not define. */ #undef ptrdiff_t]) -m4trace:configure.in:784: -1- AC_HEADER_STAT -m4trace:configure.in:784: -1- AC_DEFINE_TRACE_LITERAL([STAT_MACROS_BROKEN]) -m4trace:configure.in:784: -1- AH_OUTPUT([STAT_MACROS_BROKEN], [/* Define to 1 if the `S_IS*\' macros in do not work properly. */ +m4trace:configure.in:806: -1- AC_HEADER_STAT +m4trace:configure.in:806: -1- AC_DEFINE_TRACE_LITERAL([STAT_MACROS_BROKEN]) +m4trace:configure.in:806: -1- AH_OUTPUT([STAT_MACROS_BROKEN], [/* Define to 1 if the `S_IS*\' macros in do not work properly. */ #undef STAT_MACROS_BROKEN]) -m4trace:configure.in:789: -1- AC_DEFINE_TRACE_LITERAL([HAVE_HASH_BANG_EXEC]) -m4trace:configure.in:794: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LSTAT]) -m4trace:configure.in:798: -1- AC_DEFINE_TRACE_LITERAL([CTYPE_NON_ASCII]) -m4trace:configure.in:799: -1- AC_DEFINE_TRACE_LITERAL([DUP2_BROKEN]) -m4trace:configure.in:800: -1- AC_DEFINE_TRACE_LITERAL([PGRP_PIPE]) -m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGNALS]) -m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BSD_SIGNALS]) -m4trace:configure.in:801: -1- AC_DEFINE_TRACE_LITERAL([HAVE_USG_SIGHOLD]) -m4trace:configure.in:804: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_ERRLIST]) -m4trace:configure.in:805: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_SIGLIST]) -m4trace:configure.in:806: -1- AC_DEFINE_TRACE_LITERAL([UNDER_SYS_SIGLIST_DECLARED]) -m4trace:configure.in:806: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNDER_SYS_SIGLIST]) -m4trace:configure.in:809: -1- AC_DEFINE_TRACE_LITERAL([VOID_SIGHANDLER]) -m4trace:configure.in:810: -1- AC_DEFINE_TRACE_LITERAL([clock_t]) -m4trace:configure.in:811: -1- AC_DEFINE_TRACE_LITERAL([sigset_t]) -m4trace:configure.in:812: -1- AC_DEFINE_TRACE_LITERAL([HAVE_QUAD_T]) -m4trace:configure.in:812: -1- AC_DEFINE_TRACE_LITERAL([quad_t]) -m4trace:configure.in:813: -1- AC_DEFINE_TRACE_LITERAL([intmax_t]) -m4trace:configure.in:814: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) -m4trace:configure.in:816: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SOCKLEN_T]) -m4trace:configure.in:816: -1- AC_DEFINE_TRACE_LITERAL([socklen_t]) -m4trace:configure.in:818: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) -m4trace:configure.in:818: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) -m4trace:configure.in:821: -2- AC_DEFINE_TRACE_LITERAL([TERMIOS_LDISC]) -m4trace:configure.in:822: -2- AC_DEFINE_TRACE_LITERAL([TERMIO_LDISC]) -m4trace:configure.in:823: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_INO]) -m4trace:configure.in:824: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_FILENO]) -m4trace:configure.in:825: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_NAMLEN]) -m4trace:configure.in:826: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_SYS_IOCTL]) -m4trace:configure.in:826: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_TERMIOS]) -m4trace:configure.in:827: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TIMEVAL]) -m4trace:configure.in:828: -1- AC_CHECK_MEMBERS([struct stat.st_blocks]) -m4trace:configure.in:828: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_BLOCKS]) -m4trace:configure.in:828: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_BLOCKS], [/* Define to 1 if `st_blocks\' is member of `struct stat\'. */ +m4trace:configure.in:811: -1- AC_DEFINE_TRACE_LITERAL([HAVE_HASH_BANG_EXEC]) +m4trace:configure.in:816: -1- AC_DEFINE_TRACE_LITERAL([HAVE_LSTAT]) +m4trace:configure.in:820: -1- AC_DEFINE_TRACE_LITERAL([CTYPE_NON_ASCII]) +m4trace:configure.in:821: -1- AC_DEFINE_TRACE_LITERAL([DUP2_BROKEN]) +m4trace:configure.in:822: -1- AC_DEFINE_TRACE_LITERAL([PGRP_PIPE]) +m4trace:configure.in:823: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGNALS]) +m4trace:configure.in:823: -1- AC_DEFINE_TRACE_LITERAL([HAVE_BSD_SIGNALS]) +m4trace:configure.in:823: -1- AC_DEFINE_TRACE_LITERAL([HAVE_USG_SIGHOLD]) +m4trace:configure.in:826: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_ERRLIST]) +m4trace:configure.in:827: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SYS_SIGLIST]) +m4trace:configure.in:828: -1- AC_DEFINE_TRACE_LITERAL([UNDER_SYS_SIGLIST_DECLARED]) +m4trace:configure.in:828: -1- AC_DEFINE_TRACE_LITERAL([HAVE_UNDER_SYS_SIGLIST]) +m4trace:configure.in:831: -1- AC_DEFINE_TRACE_LITERAL([VOID_SIGHANDLER]) +m4trace:configure.in:832: -1- AC_DEFINE_TRACE_LITERAL([clock_t]) +m4trace:configure.in:833: -1- AC_DEFINE_TRACE_LITERAL([sigset_t]) +m4trace:configure.in:834: -1- AC_DEFINE_TRACE_LITERAL([HAVE_QUAD_T]) +m4trace:configure.in:834: -1- AC_DEFINE_TRACE_LITERAL([quad_t]) +m4trace:configure.in:835: -1- AC_DEFINE_TRACE_LITERAL([intmax_t]) +m4trace:configure.in:836: -1- AC_DEFINE_TRACE_LITERAL([uintmax_t]) +m4trace:configure.in:838: -1- AC_DEFINE_TRACE_LITERAL([HAVE_SOCKLEN_T]) +m4trace:configure.in:838: -1- AC_DEFINE_TRACE_LITERAL([socklen_t]) +m4trace:configure.in:840: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) +m4trace:configure.in:840: -1- AC_DEFINE_TRACE_LITERAL([RLIMTYPE]) +m4trace:configure.in:843: -2- AC_DEFINE_TRACE_LITERAL([TERMIOS_LDISC]) +m4trace:configure.in:844: -2- AC_DEFINE_TRACE_LITERAL([TERMIO_LDISC]) +m4trace:configure.in:845: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_INO]) +m4trace:configure.in:846: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_FILENO]) +m4trace:configure.in:847: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_DIRENT_D_NAMLEN]) +m4trace:configure.in:848: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_SYS_IOCTL]) +m4trace:configure.in:848: -1- AC_DEFINE_TRACE_LITERAL([STRUCT_WINSIZE_IN_TERMIOS]) +m4trace:configure.in:849: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TIMEVAL]) +m4trace:configure.in:850: -1- AC_CHECK_MEMBERS([struct stat.st_blocks]) +m4trace:configure.in:850: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_STAT_ST_BLOCKS]) +m4trace:configure.in:850: -1- AH_OUTPUT([HAVE_STRUCT_STAT_ST_BLOCKS], [/* Define to 1 if `st_blocks\' is member of `struct stat\'. */ #undef HAVE_STRUCT_STAT_ST_BLOCKS]) -m4trace:configure.in:829: -1- AC_STRUCT_TM -m4trace:configure.in:829: -1- AC_DEFINE_TRACE_LITERAL([TM_IN_SYS_TIME]) -m4trace:configure.in:829: -1- AH_OUTPUT([TM_IN_SYS_TIME], [/* Define to 1 if your declares `struct tm\'. */ +m4trace:configure.in:851: -1- AC_STRUCT_TM +m4trace:configure.in:851: -1- AC_DEFINE_TRACE_LITERAL([TM_IN_SYS_TIME]) +m4trace:configure.in:851: -1- AH_OUTPUT([TM_IN_SYS_TIME], [/* Define to 1 if your declares `struct tm\'. */ #undef TM_IN_SYS_TIME]) -m4trace:configure.in:830: -1- AC_STRUCT_TIMEZONE -m4trace:configure.in:830: -1- AC_CHECK_MEMBERS([struct tm.tm_zone], [], [], [#include +m4trace:configure.in:852: -1- AC_STRUCT_TIMEZONE +m4trace:configure.in:852: -1- AC_CHECK_MEMBERS([struct tm.tm_zone], [], [], [#include #include <$ac_cv_struct_tm> ]) -m4trace:configure.in:830: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TM_TM_ZONE]) -m4trace:configure.in:830: -1- AH_OUTPUT([HAVE_STRUCT_TM_TM_ZONE], [/* Define to 1 if `tm_zone\' is member of `struct tm\'. */ +m4trace:configure.in:852: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TM_TM_ZONE]) +m4trace:configure.in:852: -1- AH_OUTPUT([HAVE_STRUCT_TM_TM_ZONE], [/* Define to 1 if `tm_zone\' is member of `struct tm\'. */ #undef HAVE_STRUCT_TM_TM_ZONE]) -m4trace:configure.in:830: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TM_ZONE]) -m4trace:configure.in:830: -1- AH_OUTPUT([HAVE_TM_ZONE], [/* Define to 1 if your `struct tm\' has `tm_zone\'. Deprecated, use +m4trace:configure.in:852: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TM_ZONE]) +m4trace:configure.in:852: -1- AH_OUTPUT([HAVE_TM_ZONE], [/* Define to 1 if your `struct tm\' has `tm_zone\'. Deprecated, use `HAVE_STRUCT_TM_TM_ZONE\' instead. */ #undef HAVE_TM_ZONE]) -m4trace:configure.in:830: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TZNAME]) -m4trace:configure.in:830: -1- AH_OUTPUT([HAVE_TZNAME], [/* Define to 1 if you don\'t have `tm_zone\' but do have the external array +m4trace:configure.in:852: -1- AC_DEFINE_TRACE_LITERAL([HAVE_TZNAME]) +m4trace:configure.in:852: -1- AH_OUTPUT([HAVE_TZNAME], [/* Define to 1 if you don\'t have `tm_zone\' but do have the external array `tzname\'. */ #undef HAVE_TZNAME]) -m4trace:configure.in:831: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMEZONE]) -m4trace:configure.in:834: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRSIGNAL]) -m4trace:configure.in:835: -1- AC_DEFINE_TRACE_LITERAL([OPENDIR_NOT_ROBUST]) -m4trace:configure.in:836: -1- AC_DEFINE_TRACE_LITERAL([ULIMIT_MAXFDS]) -m4trace:configure.in:837: -1- AC_DEFINE_TRACE_LITERAL([CAN_REDEFINE_GETENV]) -m4trace:configure.in:839: -1- AC_DEFINE_TRACE_LITERAL([GETCWD_BROKEN]) -m4trace:configure.in:839: -1- AC_LIBSOURCE([getcwd.c]) -m4trace:configure.in:839: -1- AC_SUBST([LIB@&t@OBJS]) -m4trace:configure.in:841: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGSETJMP]) -m4trace:configure.in:842: -1- AC_DEFINE_TRACE_LITERAL([STRCOLL_BROKEN]) -m4trace:configure.in:848: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) -m4trace:configure.in:850: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) -m4trace:configure.in:853: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) -m4trace:configure.in:855: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) -m4trace:configure.in:858: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PRINTF_A_FORMAT]) -m4trace:configure.in:861: -1- AC_DEFINE_TRACE_LITERAL([MUST_REINSTALL_SIGHANDLERS]) -m4trace:configure.in:862: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL_MISSING]) -m4trace:configure.in:863: -1- AC_DEFINE_TRACE_LITERAL([NAMED_PIPES_MISSING]) -m4trace:configure.in:866: -1- AC_DEFINE_TRACE_LITERAL([GWINSZ_IN_SYS_IOCTL]) -m4trace:configure.in:866: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 if `TIOCGWINSZ\' requires . */ +m4trace:configure.in:853: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRUCT_TIMEZONE]) +m4trace:configure.in:856: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STRSIGNAL]) +m4trace:configure.in:857: -1- AC_DEFINE_TRACE_LITERAL([OPENDIR_NOT_ROBUST]) +m4trace:configure.in:858: -1- AC_DEFINE_TRACE_LITERAL([ULIMIT_MAXFDS]) +m4trace:configure.in:859: -1- AC_DEFINE_TRACE_LITERAL([CAN_REDEFINE_GETENV]) +m4trace:configure.in:861: -1- AC_DEFINE_TRACE_LITERAL([GETCWD_BROKEN]) +m4trace:configure.in:861: -1- AC_LIBSOURCE([getcwd.c]) +m4trace:configure.in:861: -1- AC_SUBST([LIB@&t@OBJS]) +m4trace:configure.in:863: -1- AC_DEFINE_TRACE_LITERAL([HAVE_POSIX_SIGSETJMP]) +m4trace:configure.in:864: -1- AC_DEFINE_TRACE_LITERAL([STRCOLL_BROKEN]) +m4trace:configure.in:870: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) +m4trace:configure.in:872: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_PUTENV]) +m4trace:configure.in:875: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) +m4trace:configure.in:877: -1- AC_DEFINE_TRACE_LITERAL([HAVE_STD_UNSETENV]) +m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([HAVE_PRINTF_A_FORMAT]) +m4trace:configure.in:883: -1- AC_DEFINE_TRACE_LITERAL([MUST_REINSTALL_SIGHANDLERS]) +m4trace:configure.in:884: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL_MISSING]) +m4trace:configure.in:885: -1- AC_DEFINE_TRACE_LITERAL([NAMED_PIPES_MISSING]) +m4trace:configure.in:888: -1- AC_DEFINE_TRACE_LITERAL([GWINSZ_IN_SYS_IOCTL]) +m4trace:configure.in:888: -1- AH_OUTPUT([GWINSZ_IN_SYS_IOCTL], [/* Define to 1 if `TIOCGWINSZ\' requires . */ #undef GWINSZ_IN_SYS_IOCTL]) -m4trace:configure.in:867: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL]) -m4trace:configure.in:868: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL]) -m4trace:configure.in:870: -1- AC_DEFINE_TRACE_LITERAL([WCONTINUED_BROKEN]) -m4trace:configure.in:873: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES]) -m4trace:configure.in:874: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS]) -m4trace:configure.in:875: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS]) -m4trace:configure.in:876: -1- AC_SUBST([SIGLIST_O]) -m4trace:configure.in:880: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL]) -m4trace:configure.in:888: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo, +m4trace:configure.in:889: -1- AC_DEFINE_TRACE_LITERAL([TIOCSTAT_IN_SYS_IOCTL]) +m4trace:configure.in:890: -1- AC_DEFINE_TRACE_LITERAL([FIONREAD_IN_SYS_IOCTL]) +m4trace:configure.in:892: -1- AC_DEFINE_TRACE_LITERAL([WCONTINUED_BROKEN]) +m4trace:configure.in:895: -1- AC_DEFINE_TRACE_LITERAL([SPEED_T_IN_SYS_TYPES]) +m4trace:configure.in:896: -1- AC_DEFINE_TRACE_LITERAL([HAVE_GETPW_DECLS]) +m4trace:configure.in:897: -1- AC_DEFINE_TRACE_LITERAL([UNUSABLE_RT_SIGNALS]) +m4trace:configure.in:898: -1- AC_SUBST([SIGLIST_O]) +m4trace:configure.in:902: -1- AC_DEFINE_TRACE_LITERAL([RLIMIT_NEEDS_KERNEL]) +m4trace:configure.in:910: -1- AC_CHECK_LIB([termcap], [tgetent], [bash_cv_termcap_lib=libtermcap], [AC_CHECK_LIB(tinfo, tgetent, bash_cv_termcap_lib=libtinfo, [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses, [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, bash_cv_termcap_lib=gnutermcap)])])]) -m4trace:configure.in:888: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses, +m4trace:configure.in:910: -1- AC_CHECK_LIB([tinfo], [tgetent], [bash_cv_termcap_lib=libtinfo], [AC_CHECK_LIB(curses, tgetent, bash_cv_termcap_lib=libcurses, [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, bash_cv_termcap_lib=gnutermcap)])]) -m4trace:configure.in:888: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, +m4trace:configure.in:910: -1- AC_CHECK_LIB([curses], [tgetent], [bash_cv_termcap_lib=libcurses], [AC_CHECK_LIB(ncurses, tgetent, bash_cv_termcap_lib=libncurses, bash_cv_termcap_lib=gnutermcap)]) -m4trace:configure.in:888: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap]) -m4trace:configure.in:890: -1- AC_SUBST([TERMCAP_LIB]) -m4trace:configure.in:891: -1- AC_SUBST([TERMCAP_DEP]) -m4trace:configure.in:893: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) -m4trace:configure.in:893: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) -m4trace:configure.in:893: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) -m4trace:configure.in:893: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) -m4trace:configure.in:894: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN]) -m4trace:configure.in:895: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY]) -m4trace:configure.in:902: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL]) -m4trace:configure.in:908: -1- AC_SUBST([JOBS_O]) -m4trace:configure.in:921: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2]) -m4trace:configure.in:922: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) -m4trace:configure.in:923: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) -m4trace:configure.in:924: -1- AC_DEFINE_TRACE_LITERAL([SVR5]) -m4trace:configure.in:981: -1- AC_SUBST([SHOBJ_CC]) -m4trace:configure.in:982: -1- AC_SUBST([SHOBJ_CFLAGS]) -m4trace:configure.in:983: -1- AC_SUBST([SHOBJ_LD]) -m4trace:configure.in:984: -1- AC_SUBST([SHOBJ_LDFLAGS]) -m4trace:configure.in:985: -1- AC_SUBST([SHOBJ_XLDFLAGS]) -m4trace:configure.in:986: -1- AC_SUBST([SHOBJ_LIBS]) -m4trace:configure.in:987: -1- AC_SUBST([SHOBJ_STATUS]) -m4trace:configure.in:1008: -1- AC_SUBST([PROFILE_FLAGS]) -m4trace:configure.in:1010: -1- AC_SUBST([incdir]) -m4trace:configure.in:1011: -1- AC_SUBST([BUILD_DIR]) -m4trace:configure.in:1013: -1- AC_SUBST([YACC]) -m4trace:configure.in:1014: -1- AC_SUBST([AR]) -m4trace:configure.in:1015: -1- AC_SUBST([ARFLAGS]) -m4trace:configure.in:1017: -1- AC_SUBST([BASHVERS]) -m4trace:configure.in:1018: -1- AC_SUBST([RELSTATUS]) -m4trace:configure.in:1019: -1- AC_SUBST([DEBUG]) -m4trace:configure.in:1020: -1- AC_SUBST([MALLOC_DEBUG]) -m4trace:configure.in:1022: -1- AC_SUBST([host_cpu]) -m4trace:configure.in:1023: -1- AC_SUBST([host_vendor]) -m4trace:configure.in:1024: -1- AC_SUBST([host_os]) -m4trace:configure.in:1026: -1- AC_SUBST([LOCAL_LIBS]) -m4trace:configure.in:1027: -1- AC_SUBST([LOCAL_CFLAGS]) -m4trace:configure.in:1028: -1- AC_SUBST([LOCAL_LDFLAGS]) -m4trace:configure.in:1029: -1- AC_SUBST([LOCAL_DEFS]) -m4trace:configure.in:1043: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ +m4trace:configure.in:910: -1- AC_CHECK_LIB([ncurses], [tgetent], [bash_cv_termcap_lib=libncurses], [bash_cv_termcap_lib=gnutermcap]) +m4trace:configure.in:912: -1- AC_SUBST([TERMCAP_LIB]) +m4trace:configure.in:913: -1- AC_SUBST([TERMCAP_DEP]) +m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) +m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) +m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_FD]) +m4trace:configure.in:915: -1- AC_DEFINE_TRACE_LITERAL([DEV_FD_PREFIX]) +m4trace:configure.in:916: -1- AC_DEFINE_TRACE_LITERAL([HAVE_DEV_STDIN]) +m4trace:configure.in:917: -1- AC_DEFINE_TRACE_LITERAL([DEFAULT_MAIL_DIRECTORY]) +m4trace:configure.in:924: -1- AC_DEFINE_TRACE_LITERAL([JOB_CONTROL]) +m4trace:configure.in:930: -1- AC_SUBST([JOBS_O]) +m4trace:configure.in:943: -1- AC_DEFINE_TRACE_LITERAL([SVR4_2]) +m4trace:configure.in:944: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) +m4trace:configure.in:945: -1- AC_DEFINE_TRACE_LITERAL([SVR4]) +m4trace:configure.in:946: -1- AC_DEFINE_TRACE_LITERAL([SVR5]) +m4trace:configure.in:1003: -1- AC_SUBST([SHOBJ_CC]) +m4trace:configure.in:1004: -1- AC_SUBST([SHOBJ_CFLAGS]) +m4trace:configure.in:1005: -1- AC_SUBST([SHOBJ_LD]) +m4trace:configure.in:1006: -1- AC_SUBST([SHOBJ_LDFLAGS]) +m4trace:configure.in:1007: -1- AC_SUBST([SHOBJ_XLDFLAGS]) +m4trace:configure.in:1008: -1- AC_SUBST([SHOBJ_LIBS]) +m4trace:configure.in:1009: -1- AC_SUBST([SHOBJ_STATUS]) +m4trace:configure.in:1034: -1- AC_SUBST([PROFILE_FLAGS]) +m4trace:configure.in:1036: -1- AC_SUBST([incdir]) +m4trace:configure.in:1037: -1- AC_SUBST([BUILD_DIR]) +m4trace:configure.in:1039: -1- AC_SUBST([YACC]) +m4trace:configure.in:1040: -1- AC_SUBST([AR]) +m4trace:configure.in:1041: -1- AC_SUBST([ARFLAGS]) +m4trace:configure.in:1043: -1- AC_SUBST([BASHVERS]) +m4trace:configure.in:1044: -1- AC_SUBST([RELSTATUS]) +m4trace:configure.in:1045: -1- AC_SUBST([DEBUG]) +m4trace:configure.in:1046: -1- AC_SUBST([MALLOC_DEBUG]) +m4trace:configure.in:1048: -1- AC_SUBST([host_cpu]) +m4trace:configure.in:1049: -1- AC_SUBST([host_vendor]) +m4trace:configure.in:1050: -1- AC_SUBST([host_os]) +m4trace:configure.in:1052: -1- AC_SUBST([LOCAL_LIBS]) +m4trace:configure.in:1053: -1- AC_SUBST([LOCAL_CFLAGS]) +m4trace:configure.in:1054: -1- AC_SUBST([LOCAL_LDFLAGS]) +m4trace:configure.in:1055: -1- AC_SUBST([LOCAL_DEFS]) +m4trace:configure.in:1069: -1- AC_CONFIG_FILES([Makefile builtins/Makefile lib/readline/Makefile lib/glob/Makefile \ lib/intl/Makefile \ lib/malloc/Makefile lib/sh/Makefile lib/termcap/Makefile \ lib/tilde/Makefile doc/Makefile support/Makefile po/Makefile.in \ examples/loadables/Makefile examples/loadables/perl/Makefile \ pathnames.h]) -m4trace:configure.in:1043: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) -m4trace:configure.in:1043: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) +m4trace:configure.in:1069: -1- AC_SUBST([LIB@&t@OBJS], [$ac_libobjs]) +m4trace:configure.in:1069: -1- AC_SUBST([LTLIBOBJS], [$ac_ltlibobjs]) diff --git a/builtins/Makefile.in b/builtins/Makefile.in index 9db2675..26849f1 100644 --- a/builtins/Makefile.in +++ b/builtins/Makefile.in @@ -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 diff --git a/builtins/Makefile.in~ b/builtins/Makefile.in~ index 521632b..9db2675 100644 --- a/builtins/Makefile.in~ +++ b/builtins/Makefile.in~ @@ -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 diff --git a/builtins/common.c b/builtins/common.c index b7ea000..dad6e46 100644 --- a/builtins/common.c +++ b/builtins/common.c @@ -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; diff --git a/builtins/exit.def b/builtins/exit.def index 9384ade..5267567 100644 --- a/builtins/exit.def +++ b/builtins/exit.def @@ -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")); diff --git a/builtins/exit.def~ b/builtins/exit.def~ new file mode 100644 index 0000000..9384ade --- /dev/null +++ b/builtins/exit.def~ @@ -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 + +#include "../bashtypes.h" +#include + +#if defined (HAVE_UNISTD_H) +# include +#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 + } +} diff --git a/builtins/fg_bg.def b/builtins/fg_bg.def index 4fc796e..76f6a26 100644 --- a/builtins/fg_bg.def +++ b/builtins/fg_bg.def @@ -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); diff --git a/builtins/fg_bg.def~ b/builtins/fg_bg.def~ index ea13bef..076f807 100644 --- a/builtins/fg_bg.def~ +++ b/builtins/fg_bg.def~ @@ -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"); diff --git a/builtins/jobs.def b/builtins/jobs.def index 76d1957..c551b12 100644 --- a/builtins/jobs.def +++ b/builtins/jobs.def @@ -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; diff --git a/builtins/jobs.def~ b/builtins/jobs.def~ new file mode 100644 index 0000000..9793f5f --- /dev/null +++ b/builtins/jobs.def~ @@ -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 + +#if defined (JOB_CONTROL) +#include "../bashtypes.h" +#include +#if defined (HAVE_UNISTD_H) +# include +#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 */ diff --git a/builtins/kill.def b/builtins/kill.def index 2598013..03f1c82 100644 --- a/builtins/kill.def +++ b/builtins/kill.def @@ -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); diff --git a/builtins/kill.def~ b/builtins/kill.def~ new file mode 100644 index 0000000..594c745 --- /dev/null +++ b/builtins/kill.def~ @@ -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 + +#include +#include +#if defined (HAVE_UNISTD_H) +# ifdef _MINIX +# include +# endif +# include +#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); +} diff --git a/builtins/trap.def b/builtins/trap.def index 1ecbfbd..533720d 100644 --- a/builtins/trap.def +++ b/builtins/trap.def @@ -214,7 +214,6 @@ showtrap (i) char *t, *p, *sn; p = trap_list[i]; - if (p == (char *)DEFAULT_SIG) return; diff --git a/builtins/trap.def~ b/builtins/trap.def~ index c43bf7a..d19defb 100644 --- a/builtins/trap.def~ +++ b/builtins/trap.def~ @@ -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++) diff --git a/builtins/wait.def b/builtins/wait.def index 9eb66f6..6bf4b8e 100644 --- a/builtins/wait.def +++ b/builtins/wait.def @@ -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); diff --git a/builtins/wait.def~ b/builtins/wait.def~ new file mode 100644 index 0000000..59c6529 --- /dev/null +++ b/builtins/wait.def~ @@ -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 + +#include "../bashtypes.h" +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include + +#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 ...] */ + + /* 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); +} diff --git a/configure b/configure index e44c671..645c75f 100755 --- a/configure +++ b/configure @@ -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 #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 diff --git a/configure.in b/configure.in index 4db80ee..346966b 100644 --- a/configure.in +++ b/configure.in @@ -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) diff --git a/examples/loadables/getconf.c b/examples/loadables/getconf.c index cc6d50b..0bf2079 100644 --- a/examples/loadables/getconf.c +++ b/examples/loadables/getconf.c @@ -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 diff --git a/examples/loadables/getconf.c~ b/examples/loadables/getconf.c~ new file mode 100644 index 0000000..cc6d50b --- /dev/null +++ b/examples/loadables/getconf.c~ @@ -0,0 +1,1488 @@ +/* + * ORIGINAL COPYRIGHT STATEMENT: + * + * Copyright (c) 1994 Winning Strategies, Inc. + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. All advertising materials mentioning features or use of this software + * must display the following acknowledgement: + * This product includes software developed by Winning Strategies, Inc. + * 4. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT + * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF + * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +/* + * POSIX.2 getconf utility + * + * Originally Written by: + * J.T. Conklin (jtc@wimsey.com), Winning Strategies, Inc. + * + * Heavily modified for inclusion in bash by + * Chet Ramey + */ + +#ifdef HAVE_CONFIG_H +# include +#endif + +#ifdef HAVE_SYS_PARAM_H +# include +#endif + +#include +#ifdef HAVE_LIMITS_H +#include +#endif +#ifdef HAVE_LOCALE_H +#include +#endif +#ifdef HAVE_UNISTD_H +#include +#endif +#include + +#include "typemax.h" + +#include "bashansi.h" +#include "shell.h" +#include "builtins.h" +#include "stdc.h" +#include "common.h" +#include "bashgetopt.h" + +#include "getconf.h" + +#ifndef errno +extern int errno; +#endif + +struct conf_variable +{ + const char *name; + enum { SYSCONF, CONFSTR, PATHCONF, CONSTANT, LLCONST, G_UNDEF } type; + long value; +}; + +#ifndef HAVE_CONFSTR +static size_t confstr __P((int, char *, size_t)); +#endif + +#ifndef HAVE_SYSCONF +static long sysconf __P((int)); +#endif + +#ifndef HAVE_PATHCONF +static long pathconf __P((const char *, int)); +#endif + +/* Hack to `encode' values wider than long into a conf_variable */ +#define VAL_LLONG_MIN -1000 +#define VAL_LLONG_MAX -1001 +#define VAL_ULLONG_MAX -1002 + +static const struct conf_variable conf_table[] = +{ + /* POSIX.2 Configurable Variable Values */ + { "PATH", CONFSTR, _CS_PATH }, + { "CS_PATH", CONFSTR, _CS_PATH }, + + /* POSIX.1 Configurable Variable Values (only Solaris?) */ +#if defined (_CS_LFS_CFLAGS) + { "LFS_CFLAGS", CONFSTR, _CS_LFS_CFLAGS }, + { "LFS_LDFLAGS", CONFSTR, _CS_LFS_LDFLAGS }, + { "LFS_LIBS", CONFSTR, _CS_LFS_LIBS }, + { "LFS_LINTFLAGS", CONFSTR, _CS_LFS_LINTFLAGS }, +#endif +#if defined (_CS_LFS64_CFLAGS) + { "LFS64_CFLAGS", CONFSTR, _CS_LFS64_CFLAGS }, + { "LFS64_LDFLAGS", CONFSTR, _CS_LFS64_LDFLAGS }, + { "LFS64_LIBS", CONFSTR, _CS_LFS64_LIBS }, + { "LFS64_LINTFLAGS", CONFSTR, _CS_LFS64_LINTFLAGS }, +#endif + + /* Single UNIX Specification version 2 Configurable Variable Values. The + SYSCONF variables say whether or not the appropriate CONFSTR variables + are available. */ +#if defined (_SC_XBS5_ILP32_OFF32) + { "XBS5_ILP32_OFF32", SYSCONF, _SC_XBS5_ILP32_OFF32 }, + { "_XBS5_ILP32_OFF32", SYSCONF, _SC_XBS5_ILP32_OFF32 }, +#endif +#if defined (_CS_XBS5_ILP32_OFF32_CFLAGS) + { "XBS5_ILP32_OFF32_CFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_CFLAGS }, + { "XBS5_ILP32_OFF32_LDFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_LDFLAGS }, + { "XBS5_ILP32_OFF32_LIBS", CONFSTR, _CS_XBS5_ILP32_OFF32_LIBS }, + { "XBS5_ILP32_OFF32_LINTFLAGS", CONFSTR, _CS_XBS5_ILP32_OFF32_LINTFLAGS }, +#endif +#if defined (_SC_XBS5_ILP32_OFFBIG) + { "XBS5_ILP32_OFFBIG", SYSCONF, _SC_XBS5_ILP32_OFFBIG }, + { "_XBS5_ILP32_OFFBIG", SYSCONF, _SC_XBS5_ILP32_OFFBIG }, +#endif +#if defined (_CS_XBS5_ILP32_OFFBIG_CFLAGS) + { "XBS5_ILP32_OFFBIG_CFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_CFLAGS }, + { "XBS5_ILP32_OFFBIG_LDFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LDFLAGS }, + { "XBS5_ILP32_OFFBIG_LIBS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LIBS }, + { "XBS5_ILP32_OFFBIG_LINTFLAGS", CONFSTR, _CS_XBS5_ILP32_OFFBIG_LINTFLAGS }, +#endif +#if defined (_SC_XBS5_LP64_OFF64) + { "XBS5_LP64_OFF64", SYSCONF, _SC_XBS5_LP64_OFF64 }, + { "_XBS5_LP64_OFF64", SYSCONF, _SC_XBS5_LP64_OFF64 }, +#endif +#if defined (_CS_XBS5_LP64_OFF64_CFLAGS) + { "XBS5_LP64_OFF64_CFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_CFLAGS }, + { "XBS5_LP64_OFF64_LDFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_LDFLAGS }, + { "XBS5_LP64_OFF64_LIBS", CONFSTR, _CS_XBS5_LP64_OFF64_LIBS }, + { "XBS5_LP64_OFF64_LINTFLAGS", CONFSTR, _CS_XBS5_LP64_OFF64_LINTFLAGS }, +#endif +#if defined (_SC_XBS5_LPBIG_OFFBIG) + { "XBS5_LPBIG_OFFBIG", SYSCONF, _SC_XBS5_LPBIG_OFFBIG }, + { "_XBS5_LPBIG_OFFBIG", SYSCONF, _SC_XBS5_LPBIG_OFFBIG }, +#endif +#if defined (_CS_XBS5_LPBIG_OFFBIG_CFLAGS) + { "XBS5_LPBIG_OFFBIG_CFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_CFLAGS }, + { "XBS5_LPBIG_OFFBIG_LDFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LDFLAGS }, + { "XBS5_LPBIG_OFFBIG_LIBS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LIBS }, + { "XBS5_LPBIG_OFFBIG_LINTFLAGS", CONFSTR, _CS_XBS5_LPBIG_OFFBIG_LINTFLAGS }, +#endif + + /* Single UNIX Specification version 3 (POSIX.1-200x) Configurable Variable + Values. The SYSCONF variables say whether or not the appropriate CONFSTR + variables are available. */ + +#if defined (_SC_POSIX_V6_ILP32_OFF32) + { "_POSIX_V6_ILP32_OFF32", SYSCONF, _SC_POSIX_V6_ILP32_OFF32 }, +#endif +#if defined (_CS_POSIX_V6_ILP32_OFF32_CFLAGS) + { "POSIX_V6_ILP32_OFF32_CFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_CFLAGS }, + { "POSIX_V6_ILP32_OFF32_LDFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LDFLAGS }, + { "POSIX_V6_ILP32_OFF32_LIBS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LIBS }, +#endif +#if defined (_CS_POSIX_V6_ILP32_OFF32_LINTFLAGS) + { "POSIX_V6_ILP32_OFF32_LINTFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFF32_LINTFLAGS }, +#endif +#if defined (_SC_POSIX_V6_ILP32_OFFBIG) + { "_POSIX_V6_ILP32_OFFBIG", SYSCONF, _SC_POSIX_V6_ILP32_OFFBIG }, +#endif +#if defined (_CS_POSIX_V6_ILP32_OFFBIG_CFLAGS) + { "POSIX_V6_ILP32_OFFBIG_CFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_CFLAGS }, + { "POSIX_V6_ILP32_OFFBIG_LDFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LDFLAGS }, + { "POSIX_V6_ILP32_OFFBIG_LIBS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LIBS }, +#endif +#if defined (_CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS) + { "POSIX_V6_ILP32_OFFBIG_LINTFLAGS", CONFSTR, _CS_POSIX_V6_ILP32_OFFBIG_LINTFLAGS }, +#endif +#if defined (_SC_POSIX_V6_LP64_OFF64) + { "_POSIX_V6_LP64_OFF64", SYSCONF, _SC_POSIX_V6_LP64_OFF64 }, +#endif +#if defined (_CS_POSIX_V6_LP64_OFF64_CFLAGS) + { "POSIX_V6_LP64_OFF64_CFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_CFLAGS }, + { "POSIX_V6_LP64_OFF64_LDFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LDFLAGS }, + { "POSIX_V6_LP64_OFF64_LIBS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LIBS }, +#endif +#if defined (CS_POSIX_V6_LP64_OFF64_LINTFLAGS) + { "POSIX_V6_LP64_OFF64_LINTFLAGS", CONFSTR, _CS_POSIX_V6_LP64_OFF64_LINTFLAGS }, +#endif +#if defined (_SC_POSIX_V6_LPBIG_OFFBIG) + { "_POSIX_V6_LPBIG_OFFBIG", SYSCONF, _SC_POSIX_V6_LPBIG_OFFBIG }, +#endif +#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS) + { "POSIX_V6_LPBIG_OFFBIG_CFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_CFLAGS }, + { "POSIX_V6_LPBIG_OFFBIG_LDFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LDFLAGS }, + { "POSIX_V6_LPBIG_OFFBIG_LIBS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LIBS }, +#endif +#if defined (_CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS) + { "POSIX_V6_LPBIG_OFFBIG_LINTFLAGS", CONFSTR, _CS_POSIX_V6_LPBIG_OFFBIG_LINTFLAGS }, +#endif + +#if defined (_CS_POSIX_V6_WIDTH_RESTRICTED_ENVS) + { "POSIX_6_WIDTH_RESTRICTED_ENVS", CONFSTR, _CS_POSIX_V6_WIDTH_RESTRICTED_ENVS }, +#endif + + /* POSIX.2 Utility Limit Minimum Values */ +#ifdef _POSIX2_BC_BASE_MAX + { "POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, +#else + { "POSIX2_BC_BASE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_DIM_MAX + { "POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, +#else + { "POSIX2_BC_DIM_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_SCALE_MAX + { "POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, +#else + { "POSIX2_BC_SCALE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_STRING_MAX + { "POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, +#else + { "POSIX2_BC_STRING_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_CHARCLASS_NAME_MAX + { "POSIX2_CHARCLASS_NAME_MAX", CONSTANT, _POSIX2_CHARCLASS_NAME_MAX }, +#else + { "POSIX2_CHARCLASS_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_COLL_WEIGHTS_MAX + { "POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, +#else + { "POSIX2_COLL_WEIGHTS_MAX", G_UNDEF, -1 }, +#endif +#if defined (_POSIX2_EQUIV_CLASS_MAX) + { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, +#endif +#ifdef _POSIX2_EXPR_NEST_MAX + { "POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, +#else + { "POSIX2_EXPR_NEST_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_LINE_MAX + { "POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, +#else + { "POSIX2_LINE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_RE_DUP_MAX + { "POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, +#else + { "POSIX2_RE_DUP_MAX", G_UNDEF, -1 }, +#endif +#if defined (_POSIX2_VERSION) + { "POSIX2_VERSION", CONSTANT, _POSIX2_VERSION }, +#else +# if !defined (_SC_2_VERSION) + { "POSIX2_VERSION", G_UNDEF, -1 }, +# endif +#endif + +#ifdef _POSIX2_BC_BASE_MAX + { "_POSIX2_BC_BASE_MAX", CONSTANT, _POSIX2_BC_BASE_MAX }, +#else + { "_POSIX2_BC_BASE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_DIM_MAX + { "_POSIX2_BC_DIM_MAX", CONSTANT, _POSIX2_BC_DIM_MAX }, +#else + { "_POSIX2_BC_DIM_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_SCALE_MAX + { "_POSIX2_BC_SCALE_MAX", CONSTANT, _POSIX2_BC_SCALE_MAX }, +#else + { "_POSIX2_BC_SCALE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_BC_STRING_MAX + { "_POSIX2_BC_STRING_MAX", CONSTANT, _POSIX2_BC_STRING_MAX }, +#else + { "_POSIX2_BC_STRING_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_CHARCLASS_NAME_MAX + { "_POSIX2_CHARCLASS_NAME_MAX", CONSTANT, _POSIX2_CHARCLASS_NAME_MAX }, +#else + { "_POSIX2_CHARCLASS_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_COLL_WEIGHTS_MAX + { "_POSIX2_COLL_WEIGHTS_MAX", CONSTANT, _POSIX2_COLL_WEIGHTS_MAX }, +#else + { "_POSIX2_COLL_WEIGHTS_MAX", G_UNDEF, -1 }, +#endif +#if defined (_POSIX2_EQUIV_CLASS_MAX) + { "POSIX2_EQUIV_CLASS_MAX", CONSTANT, _POSIX2_EQUIV_CLASS_MAX }, +#endif +#ifdef _POSIX2_EXPR_NEST_MAX + { "_POSIX2_EXPR_NEST_MAX", CONSTANT, _POSIX2_EXPR_NEST_MAX }, +#else + { "_POSIX2_EXPR_NEST_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_LINE_MAX + { "_POSIX2_LINE_MAX", CONSTANT, _POSIX2_LINE_MAX }, +#else + { "_POSIX2_LINE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX2_RE_DUP_MAX + { "_POSIX2_RE_DUP_MAX", CONSTANT, _POSIX2_RE_DUP_MAX }, +#else + { "_POSIX2_RE_DUP_MAX", G_UNDEF, -1 }, +#endif + + /* X/OPEN Maxmimum Values */ +#ifdef _XOPEN_IOV_MAX + { "_XOPEN_IOV_MAX", CONSTANT, _XOPEN_IOV_MAX }, +#else + { "_XOPEN_IOV_MAX", G_UNDEF, -1 }, +#endif +#ifdef _XOPEN_NAME_MAX + { "_XOPEN_NAME_MAX", CONSTANT, _XOPEN_NAME_MAX }, +#else + { "_XOPEN_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _XOPEN_PATH_MAX + { "_XOPEN_PATH_MAX", CONSTANT, _XOPEN_PATH_MAX }, +#else + { "_XOPEN_PATH_MAX", G_UNDEF, -1 }, +#endif + + /* POSIX.1 Minimum Values */ +#ifdef _POSIX_AIO_LISTIO_MAX + { "_POSIX_AIO_LISTIO_MAX", CONSTANT, _POSIX_AIO_LISTIO_MAX }, +#else + { "_POSIX_AIO_LISTIO_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_AIO_MAX + { "_POSIX_AIO_MAX", CONSTANT, _POSIX_AIO_MAX }, +#else + { "_POSIX_AIO_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_ARG_MAX + { "_POSIX_ARG_MAX", CONSTANT, _POSIX_ARG_MAX }, +#else + { "_POSIX_ARG_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_CHILD_MAX + { "_POSIX_CHILD_MAX", CONSTANT, _POSIX_CHILD_MAX }, +#else + { "_POSIX_CHILD_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_DELAYTIMER_MAX + { "_POSIX_DELAYTIMER_MAX", CONSTANT, _POSIX_DELAYTIMER_MAX }, +#else + { "_POSIX_DELAYTIMER_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_HOST_NAME_MAX + { "_POSIX_HOST_NAME_MAX", CONSTANT, _POSIX_HOST_NAME_MAX }, +#else + { "_POSIX_HOST_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_LINK_MAX + { "_POSIX_LINK_MAX", CONSTANT, _POSIX_LINK_MAX }, +#else + { "_POSIX_LINK_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_LOGIN_NAME_MAX + { "_POSIX_LOGIN_NAME_MAX", CONSTANT, _POSIX_LOGIN_NAME_MAX }, +#else + { "_POSIX_LOGIN_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_MAX_CANON + { "_POSIX_MAX_CANON", CONSTANT, _POSIX_MAX_CANON }, +#else + { "_POSIX_MAX_CANON", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_MAX_INPUT + { "_POSIX_MAX_INPUT", CONSTANT, _POSIX_MAX_INPUT }, +#else + { "_POSIX_MAX_INPUT", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_MQ_OPEN_MAX + { "_POSIX_MQ_OPEN_MAX", CONSTANT, _POSIX_MQ_OPEN_MAX }, +#else + { "_POSIX_MQ_OPEN_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_MQ_PRIO_MAX + { "_POSIX_MQ_PRIO_MAX", CONSTANT, _POSIX_MQ_PRIO_MAX }, +#else + { "_POSIX_MQ_PRIO_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_NAME_MAX + { "_POSIX_NAME_MAX", CONSTANT, _POSIX_NAME_MAX }, +#else + { "_POSIX_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_NGROUPS_MAX + { "_POSIX_NGROUPS_MAX", CONSTANT, _POSIX_NGROUPS_MAX }, +#else + { "_POSIX_NGROUPS_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_OPEN_MAX + { "_POSIX_OPEN_MAX", CONSTANT, _POSIX_OPEN_MAX }, +#else + { "_POSIX_OPEN_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_PATH_MAX + { "_POSIX_PATH_MAX", CONSTANT, _POSIX_PATH_MAX }, +#else + { "_POSIX_PATH_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_PIPE_BUF + { "_POSIX_PIPE_BUF", CONSTANT, _POSIX_PIPE_BUF }, +#else + { "_POSIX_PIPE_BUF", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_RE_DUP_MAX + { "_POSIX_RE_DUP_MAX", CONSTANT, _POSIX_RE_DUP_MAX }, +#else + { "_POSIX_RE_DUP_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_RTSIG_MAX + { "_POSIX_RTSIG_MAX", CONSTANT, _POSIX_RTSIG_MAX }, +#else + { "_POSIX_RTSIG_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SEM_NSEMS_MAX + { "_POSIX_SEM_NSEMS_MAX", CONSTANT, _POSIX_SEM_NSEMS_MAX }, +#else + { "_POSIX_SEM_NSEMS_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SEM_VALUE_MAX + { "_POSIX_SEM_VALUE_MAX", CONSTANT, _POSIX_SEM_VALUE_MAX }, +#else + { "_POSIX_SEM_VALUE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SIGQUEUE_MAX + { "_POSIX_SIGQUEUE_MAX", CONSTANT, _POSIX_SIGQUEUE_MAX }, +#else + { "_POSIX_SIGQUEUE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SSIZE_MAX + { "_POSIX_SSIZE_MAX", CONSTANT, _POSIX_SSIZE_MAX }, +#else + { "_POSIX_SSIZE_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SS_REPL_MAX + { "_POSIX_SS_REPL_MAX", CONSTANT, _POSIX_SS_REPL_MAX }, +#else + { "_POSIX_SS_REPL_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_STREAM_MAX + { "_POSIX_STREAM_MAX", CONSTANT, _POSIX_STREAM_MAX }, +#else + { "_POSIX_STREAM_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SYMLINK_MAX + { "_POSIX_SYMLINK_MAX", CONSTANT, _POSIX_SYMLINK_MAX }, +#else + { "_POSIX_SYMLINK_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_SYMLOOP_MAX + { "_POSIX_SYMLOOP_MAX", CONSTANT, _POSIX_SYMLOOP_MAX }, +#else + { "_POSIX_SYMLOOP_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_THREAD_DESTRUCTOR_ITERATIONS + { "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", CONSTANT, _POSIX_THREAD_DESTRUCTOR_ITERATIONS }, +#else + { "_POSIX_THREAD_DESTRUCTOR_ITERATIONS", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_THREAD_KEYS_MAX + { "_POSIX_THREAD_KEYS_MAX", CONSTANT, _POSIX_THREAD_KEYS_MAX }, +#else + { "_POSIX_THREAD_KEYS_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_THREAD_THREADS_MAX + { "_POSIX_THREAD_THREADS_MAX",CONSTANT, _POSIX_THREAD_THREADS_MAX }, +#else + { "_POSIX_THREAD_THREADS_MAX",G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TIMER_MAX + { "_POSIX_TIMER_MAX", CONSTANT, _POSIX_TIMER_MAX }, +#else + { "_POSIX_TIMER_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TRACE_EVENT_NAME_MAX + { "_POSIX_TRACE_EVENT_NAME_MAX", CONSTANT, _POSIX_TRACE_EVENT_NAME_MAX }, +#else + { "_POSIX_TRACE_EVENT_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TRACE_NAME_MAX + { "_POSIX_TRACE_NAME_MAX", CONSTANT, _POSIX_TRACE_NAME_MAX }, +#else + { "_POSIX_TRACE_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TRACE_SYS_MAX + { "_POSIX_TRACE_SYS_MAX", CONSTANT, _POSIX_TRACE_SYS_MAX }, +#else + { "_POSIX_TRACE_SYS_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TRACE_USER_EVENT_MAX + { "_POSIX_TRACE_USER_EVENT_MAX", CONSTANT, _POSIX_TRACE_USER_EVENT_MAX }, +#else + { "_POSIX_TRACE_USER_EVENT_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TTY_NAME_MAX + { "_POSIX_TTY_NAME_MAX", CONSTANT, _POSIX_TTY_NAME_MAX }, +#else + { "_POSIX_TTY_NAME_MAX", G_UNDEF, -1 }, +#endif +#ifdef _POSIX_TZNAME_MAX + { "_POSIX_TZNAME_MAX", CONSTANT, _POSIX_TZNAME_MAX }, +#else + { "_POSIX_TZNAME_MAX", G_UNDEF, -1 }, +#endif + + /* POSIX.1 Maximum Values */ +#ifdef _POSIX_CLOCKRES_MIN + { "_POSIX_CLOCKRES_MIN", CONSTANT, _POSIX_CLOCKRES_MIN }, +#else + { "_POSIX_CLOCKRES_MIN", G_UNDEF, -1 }, +#endif + + /* POSIX.1-2001/XPG6 (and later) Runtime Invariants from */ +#ifdef _SC_SS_REPL_MAX + { "SS_REPL_MAX", SYSCONF, _SC_SS_REPL_MAX }, +#endif +#ifdef _SC_TRACE_EVENT_NAME_MAX + { "TRACE_EVENT_NAME_MAX", SYSCONF, _SC_TRACE_EVENT_NAME_MAX }, +#endif +#ifdef _SC_TRACE_NAME_MAX + { "TRACE_NAME_MAX", SYSCONF, _SC_TRACE_NAME_MAX }, +#endif +#ifdef _SC_TRACE_SYS_MAX + { "TRACE_SYS_MAX", SYSCONF, _SC_TRACE_SYS_MAX }, +#endif +#ifdef _SC_TRACE_USER_EVENT_MAX + { "TRACE_USER_EVENT_MAX", SYSCONF, _SC_TRACE_USER_EVENT_MAX }, +#endif + + /* POSIX.2/XPG 4.2 (and later) Symbolic Utility Limits */ +#ifdef _SC_BC_BASE_MAX + { "BC_BASE_MAX", SYSCONF, _SC_BC_BASE_MAX }, +#endif +#ifdef _SC_BC_DIM_MAX + { "BC_DIM_MAX", SYSCONF, _SC_BC_DIM_MAX }, +#endif +#ifdef _SC_BC_SCALE_MAX + { "BC_SCALE_MAX", SYSCONF, _SC_BC_SCALE_MAX }, +#endif +#ifdef _SC_BC_STRING_MAX + { "BC_STRING_MAX", SYSCONF, _SC_BC_STRING_MAX }, +#endif +#ifdef CHARCLASS_NAME_MAX + { "CHARCLASS_NAME_MAX", CONSTANT, CHARCLASS_NAME_MAX }, +#endif +#ifdef _SC_COLL_WEIGHTS_MAX + { "COLL_WEIGHTS_MAX", SYSCONF, _SC_COLL_WEIGHTS_MAX }, +#endif +#ifdef _SC_EXPR_NEST_MAX + { "EXPR_NEST_MAX", SYSCONF, _SC_EXPR_NEST_MAX }, +#endif +#ifdef _SC_LINE_MAX + { "LINE_MAX", SYSCONF, _SC_LINE_MAX }, +#endif +# ifdef NL_ARGMAX + { "NL_ARGMAX", CONSTANT, NL_ARGMAX }, +#endif +#ifdef NL_LANGMAX + { "NL_LANGMAX", CONSTANT, NL_LANGMAX }, +#endif +#ifdef NL_MSGMAX + { "NL_MSGMAX", CONSTANT, NL_MSGMAX }, +#endif +#ifdef NL_NMAX + { "NL_NMAX", CONSTANT, NL_NMAX }, +#endif +#ifdef NL_SETMAX + { "NL_SETMAX", CONSTANT, NL_SETMAX }, +#endif +#ifdef NL_TEXTMAX + { "NL_TEXTMAX", CONSTANT, NL_TEXTMAX }, +#endif +#ifdef _SC_RAW_SOCKET + { "RAW_SOCKET", SYSCONF, _SC_RAW_SOCKET }, +#endif +#ifdef _SC_RE_DUP_MAX + { "RE_DUP_MAX", SYSCONF, _SC_RE_DUP_MAX }, +#endif + + /* POSIX.2 Optional Facility Configuration Values */ +#ifdef _SC_2_C_BIND + { "POSIX2_C_BIND", SYSCONF, _SC_2_C_BIND }, +#else + { "POSIX2_C_BIND", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_C_DEV + { "POSIX2_C_DEV", SYSCONF, _SC_2_C_DEV }, +#else + { "POSIX2_C_DEV", G_UNDEF, -1 }, +#endif +#if defined (_SC_2_C_VERSION) + { "POSIX2_C_VERSION", SYSCONF, _SC_2_C_VERSION }, +#else + { "POSIX2_C_VERSION", G_UNDEF, -1 }, +#endif +#if defined (_SC_2_CHAR_TERM) + { "POSIX2_CHAR_TERM", SYSCONF, _SC_2_CHAR_TERM }, +#else + { "POSIX2_CHAR_TERM", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_FORT_DEV + { "POSIX2_FORT_DEV", SYSCONF, _SC_2_FORT_DEV }, +#else + { "POSIX2_FORT_DEV", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_FORT_RUN + { "POSIX2_FORT_RUN", SYSCONF, _SC_2_FORT_RUN }, +#else + { "POSIX2_FORT_RUN", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_LOCALEDEF + { "POSIX2_LOCALEDEF", SYSCONF, _SC_2_LOCALEDEF }, +#else + { "POSIX2_LOCALEDEF", G_UNDEF, -1 }, +#endif +#ifdef _SC_2_SW_DEV + { "POSIX2_SW_DEV", SYSCONF, _SC_2_SW_DEV }, +#else + { "POSIX2_SW_DEV", G_UNDEF, -1 }, +#endif +#if defined (_SC2_UPE) + { "POSIX2_UPE", SYSCONF, _SC_2_UPE }, +#else + { "POSIX2_UPE", G_UNDEF, -1 }, +#endif +#if !defined (_POSIX2_VERSION) && defined (_SC_2_VERSION) + { "_POSIX2_VERSION", SYSCONF, _SC_2_VERSION }, +#else + { "_POSIX2_VERSION", G_UNDEF, -1 }, +#endif +#if defined (_SC_REGEX_VERSION) + { "REGEX_VERSION", SYSCONF, _SC_REGEX_VERSION }, + { "_REGEX_VERSION", SYSCONF, _SC_REGEX_VERSION }, +#else + { "REGEX_VERSION", G_UNDEF, -1 }, + { "_REGEX_VERSION", G_UNDEF, -1 }, +#endif + +#if defined (_SC_2_PBS) + { "_POSIX2_PBS", SYSCONF, _SC_2_PBS }, + { "_POSIX2_PBS_ACCOUNTING", SYSCONF, _SC_2_PBS_ACCOUNTING }, +# if defined (_SC_2_PBS_CHECKPOINT) + { "_POSIX2_PBS_CHECKPOINT", SYSCONF, _SC_2_PBS_CHECKPOINT }, +# endif + { "_POSIX2_PBS_LOCATE", SYSCONF, _SC_2_PBS_LOCATE }, + { "_POSIX2_PBS_MESSAGE", SYSCONF, _SC_2_PBS_MESSAGE }, + { "_POSIX2_PBS_TRACK", SYSCONF, _SC_2_PBS_TRACK }, +#endif + + /* POSIX.1 Configurable System Variables */ +#ifdef _SC_ARG_MAX + { "ARG_MAX", SYSCONF, _SC_ARG_MAX }, +#endif +#ifdef _SC_CHILD_MAX + { "CHILD_MAX", SYSCONF, _SC_CHILD_MAX }, +#endif +#ifdef _SC_CLK_TCK + { "CLK_TCK", SYSCONF, _SC_CLK_TCK }, +#endif +#ifdef _SC_DELAYTIMER_MAX + { "DELAYTIMER_MAX", SYSCONF, _SC_DELAYTIMER_MAX }, +#endif +#ifdef _SC_NGROUPS_MAX + { "NGROUPS_MAX", SYSCONF, _SC_NGROUPS_MAX }, +#endif +#ifdef NZERO + { "NZERO", CONSTANT, NZERO }, +#endif +#ifdef _SC_OPEN_MAX + { "OPEN_MAX", SYSCONF, _SC_OPEN_MAX }, +#endif +#ifdef PASS_MAX + { "PASS_MAX", CONSTANT, PASS_MAX }, +#endif +#ifdef _SC_STREAM_MAX + { "STREAM_MAX", SYSCONF, _SC_STREAM_MAX }, +#endif +#ifdef TMP_MAX + { "TMP_MAX", CONSTANT, TMP_MAX }, +#endif +#ifdef _SC_TZNAME_MAX + { "TZNAME_MAX", SYSCONF, _SC_TZNAME_MAX }, +#endif + + /* POSIX.1 Optional Facility Configuration Values */ +#if defined (_SC_ADVISORY_INFO) + { "_POSIX_ADVISORY_INFO", SYSCONF, _SC_ADVISORY_INFO }, +#endif +#if defined (_SC_ASYNCHRONOUS_IO) + { "_POSIX_ASYNCHRONOUS_IO", SYSCONF, _SC_ASYNCHRONOUS_IO }, +#endif +#if defined (_SC_BARRIERS) + { "_POSIX_BARRIERS", SYSCONF, _SC_BARRIERS }, +#endif +#if defined (_SC_BASE) + { "_POSIX_BASE", SYSCONF, _SC_BASE }, +#endif +#if defined (_SC_C_LANG_SUPPORT) + { "_POSIX_C_LANG_SUPPORT", SYSCONF, _SC_C_LANG_SUPPORT }, +#endif +#if defined (_SC_C_LANG_SUPPORT_R) + { "_POSIX_C_LANG_SUPPORT_R", SYSCONF, _SC_C_LANG_SUPPORT_R }, +#endif +#if defined (_SC_CLOCK_SELECTION) + { "_POSIX_CLOCK_SELECTION", SYSCONF, _SC_CLOCK_SELECTION }, +#endif +#if defined (_SC_CPUTIME) + { "_POSIX_CPUTIME", SYSCONF, _SC_CPUTIME }, +#endif +#if defined (_SC_DEVICE_IO) + { "_POSIX_DEVICE_IO", SYSCONF, _SC_DEVICE_IO }, +#endif +#if defined (_SC_DEVICE_SPECIFIC) + { "_POSIX_DEVICE_SPECIFIC", SYSCONF, _SC_DEVICE_SPECIFIC }, +#endif +#if defined (_SC_DEVICE_SPECIFIC_R) + { "_POSIX_DEVICE_SPECIFIC_R", SYSCONF, _SC_DEVICE_SPECIFIC_R }, +#endif +#if defined (_SC_FD_MGMT) + { "_POSIX_FD_MGMT", SYSCONF, _SC_FD_MGMT }, +#endif +#if defined (_SC_FIFO) + { "_POSIX_FIFO", SYSCONF, _SC_FIFO }, +#endif +#if defined (_SC_FILE_ATTRIBUTES) + { "_POSIX_FILE_ATTRIBUTES", SYSCONF, _SC_FILE_ATTRIBUTES }, +#endif +#if defined (_SC_FILE_LOCKING) + { "_POSIX_FILE_LOCKING", SYSCONF, _SC_FILE_LOCKING }, +#endif +#if defined (_SC_FILE_SYSTEM) + { "_POSIX_FILE_SYSTEM", SYSCONF, _SC_FILE_SYSTEM }, +#endif +#if defined (_SC_FSYNC) + { "_POSIX_FSYNC", SYSCONF, _SC_FSYNC }, +#endif +#if defined (_SC_IPV6) + { "_POSIX_IPV6", SYSCONF, _SC_IPV6 }, +#endif +#if defined (_SC_JOB_CONTROL) + { "_POSIX_JOB_CONTROL", SYSCONF, _SC_JOB_CONTROL }, +#endif +#if defined (_SC_MAPPED_FILES) + { "_POSIX_MAPPED_FILES", SYSCONF, _SC_MAPPED_FILES }, +#endif +#if defined (_SC_MEMLOCK) + { "_POSIX_MEMLOCK", SYSCONF, _SC_MEMLOCK }, +#endif +#if defined (_SC_MEMLOCK_RANGE) + { "_POSIX_MEMLOCK_RANGE", SYSCONF, _SC_MEMLOCK_RANGE }, +#endif +#if defined (_SC_MEMORY_PROTECTION) + { "_POSIX_MEMORY_PROTECTION", SYSCONF, _SC_MEMORY_PROTECTION }, +#endif +#if defined (_SC_MESSAGE_PASSING) + { "_POSIX_MESSAGE_PASSING", SYSCONF, _SC_MESSAGE_PASSING }, +#endif +#if defined (_SC_MONOTONIC_CLOCK) + { "_POSIX_MONOTONIC_CLOCK", SYSCONF, _SC_MONOTONIC_CLOCK }, +#endif +#if defined (_SC_MULTI_PROCESS) + { "_POSIX_MULTI_PROCESS", SYSCONF, _SC_MULTI_PROCESS }, +#endif +#if defined (_SC_NETWORKING) + { "_POSIX_NETWORKING", SYSCONF, _SC_NETWORKING }, +#endif +#if defined (_SC_PIPE) + { "_POSIX_PIPE", SYSCONF, _SC_PIPE }, +#endif +#if defined (SC_PRIORITIZED_IO) + { "_POSIX_PRIORITIZED_IO", SYSCONF, _SC_PRIORITIZED_IO }, +#endif +#if defined (_SC_PRIORITY_SCHEDULING) + { "_POSIX_PRIORITY_SCHEDULING", SYSCONF, _SC_PRIORITY_SCHEDULING }, +#endif +#if defined (_SC_READER_WRITER_LOCKS) + { "_POSIX_READER_WRITER_LOCKS", SYSCONF, _SC_READER_WRITER_LOCKS }, +#endif +#if defined (_SC_RAW_SOCKETS) + { "_POSIX_RAW_SOCKETS", SYSCONF, _SC_RAW_SOCKETS }, +#endif +#if defined (_SC_REALTIME_SIGNALS) + { "_POSIX_REALTIME_SIGNALS", SYSCONF, _SC_REALTIME_SIGNALS }, +#endif +#if defined (_SC_REGEXP) + { "_POSIX_REGEXP", SYSCONF, _SC_REGEXP }, +#endif +#if defined (_SC_SAVED_IDS) + { "_POSIX_SAVED_IDS", SYSCONF, _SC_SAVED_IDS }, +#endif +#if defined (_SC_SEMAPHORES) + { "_POSIX_SEMAPHORES", SYSCONF, _SC_SEMAPHORES }, +#endif +#if defined (_SC_SHARED_MEMORY_OBJECTS) + { "_POSIX_SHARED_MEMORY_OBJECTS", SYSCONF, _SC_SHARED_MEMORY_OBJECTS }, +#endif + { "_POSIX_SHELL", CONSTANT, 1 }, +#if defined (_SC_SIGNALS) + { "_POSIX_SIGNALS", SYSCONF, _SC_SIGNALS }, +#endif +#if defined (_SC_SINGLE_PROCESS) + { "_POSIX_SINGLE_PROCESS", SYSCONF, _SC_SINGLE_PROCESS }, +#endif +#if defined (_SC_SPAWN) + { "_POSIX_SPAWN", SYSCONF, _SC_SPAWN }, +#endif +#if defined (_SC_SPIN_LOCKS) + { "_POSIX_SPIN_LOCKS", SYSCONF, _SC_SPIN_LOCKS }, +#endif +#if defined (_SC_SPORADIC_SERVER) + { "_POSIX_SPORADIC_SERVER", SYSCONF, _SC_SPORADIC_SERVER }, +#endif +#if defined (_SC_SYMLOOP_MAX) + { "_POSIX_SYMLOOP_MAX", SYSCONF, _SC_SYMLOOP_MAX }, +#endif +#if defined (_SC_SYNCHRONIZED_IO) + { "_POSIX_SYNCHRONIZED_IO", SYSCONF, _SC_SYNCHRONIZED_IO }, +#endif +#if defined (_SC_SYSTEM_DATABASE) + { "_POSIX_SYSTEM_DATABASE", SYSCONF, _SC_SYSTEM_DATABASE }, +#endif +#if defined (_SC_SYSTEM_DATABASE_R) + { "_POSIX_SYSTEM_DATABASE_R", SYSCONF, _SC_SYSTEM_DATABASE_R }, +#endif +#if defined (_SC_THREAD_ATTR_STACKADDR) + { "_POSIX_THREAD_ATTR_STACKADDR", SYSCONF, _SC_THREAD_ATTR_STACKADDR }, +#endif +#if defined (_SC_THREAD_ATTR_STACKSIZE) + { "_POSIX_THREAD_ATTR_STACKSIZE", SYSCONF, _SC_THREAD_ATTR_STACKSIZE }, +#endif +#if defined (_SC_THREAD_CPUTIME) + { "_POSIX_THREAD_CPUTIME", SYSCONF, _SC_THREAD_CPUTIME }, +#endif +#if defined (_SC_THREAD_PRIO_INHERIT) + { "_POSIX_THREAD_PRIO_INHERIT", SYSCONF, _SC_THREAD_PRIO_INHERIT }, +#endif +#if defined (_SC_THREAD_PRIO_PROTECT) + { "_POSIX_THREAD_PRIO_PROTECT", SYSCONF, _SC_THREAD_PRIO_PROTECT }, +#endif +#if defined (_SC_THREAD_PRIORITY_SCHEDULING) + { "_POSIX_THREAD_PRIORITY_SCHEDULING", SYSCONF, _SC_THREAD_PRIORITY_SCHEDULING }, +#endif +#if defined (_SC_THREAD_PROCESS_SHARED) + { "_POSIX_THREAD_PROCESS_SHARED", SYSCONF, _SC_THREAD_PROCESS_SHARED }, +#endif +#if defined (_SC_THREAD_SAFE_FUNCTIONS) + { "_POSIX_THREAD_SAFE_FUNCTIONS", SYSCONF, _SC_THREAD_SAFE_FUNCTIONS }, +#endif +#if defined (_SC_THREAD_SPORADIC_SERVER) + { "_POSIX_THREAD_SPORADIC_SERVER", SYSCONF, _SC_THREAD_SPORADIC_SERVER }, +#endif +#if defined (_SC_THREADS) + { "_POSIX_THREADS", SYSCONF, _SC_THREADS }, +#endif +#if defined (_SC_TIMEOUTS) + { "_POSIX_TIMEOUTS", SYSCONF, _SC_TIMEOUTS }, +#endif +#if defined (_SC_TIMERS) + { "_POSIX_TIMERS", SYSCONF, _SC_TIMERS }, +#endif +#if defined (_SC_TRACE) + { "_POSIX_TRACE", SYSCONF, _SC_TRACE }, +#endif +#if defined (_SC_TRACE) + { "_POSIX_TRACE_EVENT_FILTER",SYSCONF, _SC_TRACE_EVENT_FILTER }, +#endif +#if defined (_SC_TRACE) + { "_POSIX_TRACE_INHERIT", SYSCONF, _SC_TRACE_INHERIT }, +#endif +#if defined (_SC_TRACE) + { "_POSIX_TRACE_LOG", SYSCONF, _SC_TRACE_LOG }, +#endif +#if defined (_SC_TYPED_MEMORY_OBJECTS) + { "_POSIX_TYPED_MEMORY_OBJECTS", SYSCONF, _SC_TYPED_MEMORY_OBJECTS }, +#endif +#if defined (_SC_VERSION) + { "_POSIX_VERSION", SYSCONF, _SC_VERSION }, +#endif + + /* XPG 4.2 Configurable System Variables. */ +#if defined (_SC_ATEXIT_MAX) + { "ATEXIT_MAX", SYSCONF, _SC_ATEXIT_MAX }, +#endif +#if defined (_SC_GETGR_R_SIZE_MAX) + { "GETGR_R_SIZE_MAX", SYSCONF, _SC_GETGR_R_SIZE_MAX }, +#endif +#if defined (_SC_GETPW_R_SIZE_MAX) + { "GETPW_R_SIZE_MAX", SYSCONF, _SC_GETPW_R_SIZE_MAX }, +#endif +#if defined (_SC_HOST_NAME_MAX) + { "HOST_NAME_MAX", SYSCONF, _SC_HOST_NAME_MAX }, +#endif +#if defined (_SC_IOV_MAX) + { "IOV_MAX", SYSCONF, _SC_IOV_MAX }, +#endif +#if defined (_SC_LOGIN_NAME_MAX) + { "LOGIN_NAME_MAX", SYSCONF, _SC_LOGIN_NAME_MAX }, +#endif +#if defined (_SC_LOGNAME_MAX) + { "LOGNAME_MAX", SYSCONF, _SC_LOGNAME_MAX }, +#endif +#if defined (_SC_PAGESIZE) + { "PAGESIZE", SYSCONF, _SC_PAGESIZE }, +#endif +#if defined (_SC_PAGE_SIZE) + { "PAGE_SIZE", SYSCONF, _SC_PAGE_SIZE }, +#endif +#if defined (_SC_SYMLOOP_MAX) + { "SYMLOOP_MAX", SYSCONF, _SC_SYMLOOP_MAX }, +#endif +#if defined (_SC_TTY_NAME_MAX) + { "TTY_NAME_MAX", SYSCONF, _SC_TTY_NAME_MAX }, +#endif +#if defined (_SC_USER_GROUPS) + { "_POSIX_USER_GROUPS", SYSCONF, _SC_USER_GROUPS }, +#endif +#if defined (_SC_USER_GROUPS_R) + { "_POSIX_USER_GROUPS_R", SYSCONF, _SC_USER_GROUPS_R }, +#endif + +#if defined (_SC_AIO_LISTIO_MAX) + { "AIO_LISTIO_MAX", SYSCONF, _SC_AIO_LISTIO_MAX }, +#endif +#if defined (_SC_AIO_MAX) + { "AIO_MAX", SYSCONF, _SC_AIO_MAX }, +#endif +#if defined (_SC_AIO_PRIO_DELTA_MAX) + { "AIO_PRIO_DELTA_MAX", SYSCONF, _SC_AIO_PRIO_DELTA_MAX }, +#endif +#if defined (_SC_MQ_OPEN_MAX) + { "MQ_OPEN_MAX", SYSCONF, _SC_MQ_OPEN_MAX }, +#endif +#if defined (_SC_MQ_PRIO_MAX) + { "MQ_PRIO_MAX", SYSCONF, _SC_MQ_PRIO_MAX }, +#endif +#if defined (_SC_RTSIG_MAX) + { "RTSIG_MAX", SYSCONF, _SC_RTSIG_MAX }, +#endif +#if defined (_SC_SEM_NSEMS_MAX) + { "SEM_NSEMS_MAX", SYSCONF, _SC_SEM_NSEMS_MAX }, +#endif +#if defined (_SC_SEM_VALUE_MAX) + { "SEM_VALUE_MAX", SYSCONF, _SC_SEM_VALUE_MAX }, +#endif +#if defined (_SC_SIGQUEUE_MAX) + { "SIGQUEUE_MAX", SYSCONF, _SC_SIGQUEUE_MAX }, +#endif +#if defined (_SC_TIMER_MAX) + { "TIMER_MAX", SYSCONF, _SC_TIMER_MAX }, +#endif + +#if defined (_SC_THREAD_DESTRUCTOR_ITERATIONS) + { "PTHREAD_DESTRUCTOR_ITERATIONS", SYSCONF, _SC_THREAD_DESTRUCTOR_ITERATIONS }, +#endif +#if defined (_SC_THREAD_KEYS_MAX) + { "PTHREAD_KEYS_MAX", SYSCONF, _SC_THREAD_KEYS_MAX }, +#endif +#if defined (_SC_THREAD_STACK_MIN) + { "PTHREAD_STACK_MIN", SYSCONF, _SC_THREAD_STACK_MIN }, +#endif +#if defined (_SC_THREAD_THREADS_MAX) + { "PTHREAD_THREADS_MAX", SYSCONF, _SC_THREAD_THREADS_MAX }, +#endif + + /* XPG 4.2 (and later) Optional Facility Configuration Values */ +#if defined (_SC_XOPEN_CRYPT) + { "_XOPEN_CRYPT", SYSCONF, _SC_XOPEN_CRYPT }, +#endif +#if defined (_SC_XOPEN_ENH_I18N) + { "_XOPEN_ENH_I18N", SYSCONF, _SC_XOPEN_ENH_I18N }, +#endif +#if defined (_SC_XOPEN_LEGACY) + { "_XOPEN_LEGACY", SYSCONF, _SC_XOPEN_LEGACY }, +#endif /* _SC_XOPEN_LEGACY */ +#if defined (_SC_XOPEN_REALTIME) + { "_XOPEN_REALTIME", SYSCONF, _SC_XOPEN_REALTIME }, +#endif +#if defined (_SC_XOPEN_REALTIME_THREADS) + { "_XOPEN_REALTIME_THREADS", SYSCONF, _SC_XOPEN_REALTIME_THREADS }, +#endif +#if defined (_SC_XOPEN_SHM) + { "_XOPEN_SHM", SYSCONF, _SC_XOPEN_SHM }, +#endif +#if defined (_SC_XOPEN_STREAMS) + { "_XOPEN_STREAMS", SYSCONF, _SC_XOPEN_STREAMS }, +#endif +#if defined (_SC_XOPEN_UNIX) + { "_XOPEN_UNIX", SYSCONF, _SC_XOPEN_UNIX }, +#endif +#if defined (_SC_XOPEN_VERSION) + { "_XOPEN_VERSION", SYSCONF, _SC_XOPEN_VERSION }, +#endif +#if defined (_SC_XOPEN_XCU_VERSION) + { "_XOPEN_XCU_VERSION", SYSCONF, _SC_XOPEN_XCU_VERSION }, +#endif +#if defined (_SC_XOPEN_XPG2) + { "_XOPEN_XPG2", SYSCONF, _SC_XOPEN_XPG2 }, +#endif +#if defined (_SC_XOPEN_XPG3) + { "_XOPEN_XPG3", SYSCONF, _SC_XOPEN_XPG3 }, +#endif +#if defined (_SC_XOPEN_XPG4) + { "_XOPEN_XPG4", SYSCONF, _SC_XOPEN_XPG4 }, +#endif +#if defined (_SC_XOPEN_XPG5) + { "_XOPEN_XPG5", SYSCONF, _SC_XOPEN_XPG5 }, +#endif + + /* POSIX.1 Configurable Pathname Values */ +#ifdef _PC_LINK_MAX + { "LINK_MAX", PATHCONF, _PC_LINK_MAX }, +#endif +#ifdef _PC_MAX_CANON + { "MAX_CANON", PATHCONF, _PC_MAX_CANON }, +#endif +#ifdef _PC_MAX_INPUT + { "MAX_INPUT", PATHCONF, _PC_MAX_INPUT }, +#endif +#ifdef _PC_NAMW_MAX + { "NAME_MAX", PATHCONF, _PC_NAME_MAX }, +#endif +#ifdef _PC_PATH_MAX + { "PATH_MAX", PATHCONF, _PC_PATH_MAX }, +#endif +#ifdef _PC_PIPE_BUF + { "PIPE_BUF", PATHCONF, _PC_PIPE_BUF }, +#endif +#ifdef _PC_SYMLINK_MAX + { "SYMLINK_MAX", PATHCONF, _PC_SYMLINK_MAX }, +#endif +#ifdef _PC_CHOWN_RESTRICTED + { "_POSIX_CHOWN_RESTRICTED", PATHCONF, _PC_CHOWN_RESTRICTED }, +#endif +#ifdef _PC_NO_TRUNC + { "_POSIX_NO_TRUNC", PATHCONF, _PC_NO_TRUNC }, +#endif +#ifdef _PC_VDISABLE + { "_POSIX_VDISABLE", PATHCONF, _PC_VDISABLE }, +#endif + + /* XPG 4.2 Configurable Pathname Values */ +#if defined (_PC_FILESIZEBITS) + { "FILESIZEBITS", PATHCONF, _PC_FILESIZEBITS }, +#endif +#if defined (_PC_ASYNC_IO) + { "_POSIX_ASYNC_IO", PATHCONF, _PC_ASYNC_IO }, +#endif +#if defined (_PC_PRIO_IO) + { "_POSIX_PRIO_IO", PATHCONF, _PC_PRIO_IO }, +#endif +#if defined (_PC_SYNC_IO) + { "_POSIX_SYNC_IO", PATHCONF, _PC_SYNC_IO }, +#endif + + /* POSIX.1-200x configurable pathname values */ +#if defined (_PC_ALLOC_SIZE_MIN) + { "POSIX_ALLOC_SIZE_MIN", PATHCONF, _PC_ALLOC_SIZE_MIN }, + { "POSIX_REC_INCR_XFER_SIZE", PATHCONF, _PC_REC_INCR_XFER_SIZE }, + { "POSIX_REC_MAX_XFER_SIZE", PATHCONF, _PC_REC_MAX_XFER_SIZE }, + { "POSIX_REC_MIN_XFER_SIZE", PATHCONF, _PC_REC_MIN_XFER_SIZE }, + { "POSIX_REC_XFER_ALIGN", PATHCONF, _PC_REC_XFER_ALIGN }, +#endif + + /* ANSI/ISO C, POSIX.1-200x, XPG 4.2 (and later) C language type limits. */ + { "CHAR_BIT", CONSTANT, CHAR_BIT }, + { "CHAR_MAX", CONSTANT, CHAR_MAX }, + { "CHAR_MIN", CONSTANT, CHAR_MIN }, + { "INT_BIT", CONSTANT, INT_BIT }, + { "INT_MAX", CONSTANT, INT_MAX }, + { "INT_MIN", CONSTANT, INT_MIN }, +#ifdef LLONG_MAX + { "LLONG_MAX", LLCONST, VAL_LLONG_MAX }, + { "LLONG_MIN", LLCONST, VAL_LLONG_MIN }, +#endif + { "LONG_BIT", CONSTANT, LONG_BIT }, + { "LONG_MAX", CONSTANT, LONG_MAX }, + { "LONG_MIN", CONSTANT, LONG_MIN }, +#ifdef MB_LEN_MAX + { "MB_LEN_MAX", CONSTANT, MB_LEN_MAX }, +#endif + { "SCHAR_MAX", CONSTANT, SCHAR_MAX }, + { "SCHAR_MIN", CONSTANT, SCHAR_MIN }, + { "SHRT_MAX", CONSTANT, SHRT_MAX }, + { "SHRT_MIN", CONSTANT, SHRT_MIN }, + { "SIZE_MAX", CONSTANT, SIZE_MAX }, + { "SSIZE_MAX", CONSTANT, SSIZE_MAX }, + { "UCHAR_MAX", CONSTANT, UCHAR_MAX }, + { "UINT_MAX", CONSTANT, UINT_MAX }, +#ifdef ULLONG_MAX + { "ULLONG_MAX", LLCONST, VAL_ULLONG_MAX }, +#endif + { "ULONG_MAX", CONSTANT, ULONG_MAX }, + { "USHRT_MAX", CONSTANT, USHRT_MAX }, + { "WORD_BIT", CONSTANT, WORD_BIT }, + + { NULL } +}; + +static int num_getconf_variables = sizeof(conf_table) / sizeof(struct conf_variable) - 1; + +extern char *this_command_name; +extern char **make_builtin_argv (); + +static void getconf_help (); +static int getconf_print (); +static int getconf_one (); +static int getconf_all (); + +int +getconf_builtin (list) + WORD_LIST *list; +{ + int c, r, opt, aflag; + char **v; + + aflag = 0; + reset_internal_getopt(); + while ((opt = internal_getopt (list, "ahv:")) != -1) { + switch (opt) { + case 'a': + aflag = 1; + break; + case 'h': + getconf_help(); + return(EXECUTION_SUCCESS); + case 'v': + break; /* ignored */ + default: + builtin_usage(); + return(EX_USAGE); + } + } + + list = loptend; + if ((aflag == 0 && list == 0) || (aflag && list) || list_length(list) > 2) { + builtin_usage(); + return(EX_USAGE); + } + + r = aflag ? getconf_all() : getconf_one(list); + + return r; +} + +static void +getconf_help() +{ + const struct conf_variable *cp; + register int i, column; + + builtin_usage(); + printf("Acceptable variable names are:\n"); + for (cp = conf_table; cp->name != NULL; cp++) { + if (cp->type == PATHCONF) + printf("%s pathname\n", cp->name); + else + printf("%s\n", cp->name); + } +} + +static int +getconf_print(cp, vpath, all) +struct conf_variable *cp; +char *vpath; +int all; +{ + long val; + char *sval; + size_t slen; + + switch (cp->type) { + case G_UNDEF: + printf("undefined\n"); + break; + +#ifdef LLONG_MAX + case LLCONST: + switch (cp->value) { + default: + case VAL_LLONG_MIN: + printf ("%lld\n", LLONG_MIN); + break; + case VAL_LLONG_MAX: + printf ("%lld\n", LLONG_MAX); + break; +# if (ULLONG_MAX != LLONG_MAX) + case VAL_ULLONG_MAX: + printf ("%llu\n", ULLONG_MAX); + break; +# endif + } + break; +#endif + case CONSTANT: + switch (cp->value) { + case UCHAR_MAX: + case USHRT_MAX: + case UINT_MAX: +#if (ULONG_MAX != UINT_MAX) + case ULONG_MAX: +#endif +#if (SIZE_MAX != UINT_MAX) && (SIZE_MAX != ULONG_MAX) + case SIZE_MAX: +#endif + + printf("%lu\n", cp->value); + break; + default: + printf("%ld\n", cp->value); + break; + } + break; + + case CONFSTR: + errno = 0; + slen = confstr (cp->value, (char *) 0, (size_t) 0); + if (slen == 0) { + if (errno != 0) { + if (all) + printf ("getconf: %s\n", strerror(errno)); + else + builtin_error ("%s", strerror(errno)); + } else + printf ("undefined\n"); + return (EXECUTION_FAILURE); + } + sval = xmalloc(slen); + + confstr(cp->value, sval, slen); + printf("%s\n", sval); + free(sval); + break; + + case SYSCONF: + errno = 0; + if ((val = sysconf(cp->value)) == -1) { + if (errno != 0) { + if (all) + printf("getconf: %s\n", strerror (errno)); + else + builtin_error ("%s", strerror (errno)); + return (EXECUTION_FAILURE); + } + + printf ("undefined\n"); + } else { + printf("%ld\n", val); + } + break; + + case PATHCONF: + errno = 0; + if ((val = pathconf(vpath, cp->value)) == -1) { + if (errno != 0) { + if (all) + printf("getconf: %s: %s\n", vpath, strerror (errno)); + else + builtin_error ("%s: %s", vpath, strerror (errno)); + return (EXECUTION_FAILURE); + } + + printf ("undefined\n"); + } else { + printf ("%ld\n", val); + } + break; + } + + return (ferror(stdout) ? EXECUTION_FAILURE : EXECUTION_SUCCESS); +} + +static int +getconf_all() +{ + const struct conf_variable *cp; + int ret; + + ret = EXECUTION_SUCCESS; + for (cp = conf_table; cp->name != NULL; cp++) { + printf("%-35s", cp->name); + if (getconf_print(cp, "/", 1) == EXECUTION_FAILURE) + ret = EXECUTION_FAILURE; + } + return ret; +} + +static int +getconf_one(list) + WORD_LIST *list; +{ + const struct conf_variable *cp; + char *vname, *vpath; + + vname = list->word->word; + vpath = (list->next && list->next->word) ? list->next->word->word + : (char *)NULL; + + for (cp = conf_table; cp->name != NULL; cp++) { + if (strcmp(vname, cp->name) == 0) + break; + } + if (cp->name == NULL) { + builtin_error ("%s: unknown variable", vname); + return (EXECUTION_FAILURE); + } + + if (cp->type == PATHCONF) { + if (list->next == 0) { + builtin_usage(); + return(EX_USAGE); + } + } else { + if (list->next) { + builtin_usage(); + return(EX_USAGE); + } + } + + return (getconf_print(cp, vpath, 0)); +} + +static char *getconf_doc[] = { + "getconf writes the current value of a configurable system limit or", + "option variable to the standard output.", + (char *)NULL +}; + +struct builtin getconf_struct = { + "getconf", + getconf_builtin, + BUILTIN_ENABLED, + getconf_doc, + "getconf -[ah] or getconf [-v spec] sysvar or getconf [-v spec] pathvar pathname", + 0 +}; + +#ifndef HAVE_CONFSTR +static size_t +confstr (name, buf, len) + int name; + char *buf; + size_t len; +{ + switch (name) + { + case _CS_PATH: + if (len > 0 && buf) + { + strncpy (buf, STANDARD_UTILS_PATH, len - 1); + buf[len - 1] = '\0'; + } + return (sizeof (STANDARD_UTILS_PATH) + 1); + default: + errno = EINVAL; + return 0; + } +} +#endif + +#ifndef HAVE_SYSCONF +extern long get_clk_tck __P((void)); + +static long +sysconf (name) + int name; +{ +# if defined (_POSIX_VERSION) + switch (name) + { + case _SC_ARG_MAX: + return _POSIX_ARG_MAX; + case _SC_CHILD_MAX: + return _POSIX_CHILD_MAX; + case _SC_CLK_TCK: + return get_clk_tck(); + case _SC_NGROUPS_MAX: + return _POSIX_NGROUPS_MAX; + case _SC_OPEN_MAX: + return _POSIX_OPEN_MAX; + case _SC_JOB_CONTROL: + return _POSIX_JOB_CONTROL; + case _SC_SAVED_IDS: + return _POSIX_SAVED_IDS; + case _SC_VERSION: + return _POSIX_VERSION; + case _SC_BC_BASE_MAX: + return _POSIX2_BC_BASE_MAX; + case _SC_BC_DIM_MAX: + return _POSIX2_BC_DIM_MAX; + case _SC_BC_SCALE_MAX: + return _POSIX2_BC_SCALE_MAX; + case _SC_BC_STRING_MAX: + return _POSIX2_BC_STRING_MAX; + case _SC_COLL_WEIGHTS_MAX: + return -1; + case _SC_EXPR_NEST_MAX: + return _POSIX2_EXPR_NEST_MAX; + case _SC_LINE_MAX: + return _POSIX2_LINE_MAX; + case _SC_RE_DUP_MAX: + return _POSIX2_RE_DUP_MAX; + case _SC_STREAM_MAX: + return _POSIX_STREAM_MAX; + case _SC_TZNAME_MAX: + return _POSIX_TZNAME_MAX; + default: + errno = EINVAL; + return -1; + } +#else + errno = EINVAL; + return -1; +#endif +} +#endif + +#ifndef HAVE_PATHCONF +static long +pathconf (path, name) + const char *path; + int name; +{ +#if defined (_POSIX_VERSION) + switch (name) + { + case _PC_LINK_MAX: + return _POSIX_LINK_MAX; + case _PC_MAX_CANON: + return _POSIX_MAX_CANON; + case _PC_MAX_INPUT: + return _POSIX_MAX_INPUT; + case _PC_NAME_MAX: + return _POSIX_NAME_MAX; + case _PC_PATH_MAX: + return _POSIX_PATH_MAX; + case _PC_PIPE_BUF: + return _POSIX_PIPE_BUF; + case _PC_CHOWN_RESTRICTED: +#ifdef _POSIX_CHOWN_RESTRICTED + return _POSIX_CHOWN_RESTRICTED; +#else + return -1; +#endif + case _PC_NO_TRUNC: +#ifdef _POSIX_NO_TRUNC + return _POSIX_NO_TRUNC; +#else + return -1; +#endif + case _PC_VDISABLE: +#ifdef _POSIX_VDISABLE + return _POSIX_VDISABLE; +#else + return -1; +#endif + default: + errno = EINVAL; + return -1; + } +#else + errno = EINVAL; + return -1; +#endif +} +#endif diff --git a/jobs.c b/jobs.c index d8f3d54..6e35141 100644 --- a/jobs.c +++ b/jobs.c @@ -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); } -/* 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 - 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. */ static int -compact_jobs_list (flags) - int flags; +processes_in_job (job) { - sigset_t set, oset; - register int i, j; - int nremove, ndel; - JOB **newlist; - - if (job_slots == 0 || jobs_list_frozen) - return job_slots; - - 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; + int nproc; + register PROCESS *p; - /* need to increase jobs list to at least CHILD_MAX entries */ - if (nremove < 0) - return job_slots; + nproc = 0; + p = jobs[job]->pipe; + do + { + p = p->next; + nproc++; + } + while (p != jobs[job]->pipe); - BLOCK_CHILD (set, oset); + return nproc; +} - 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; - } - } +/* 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; - if (ndel == 0) - { - UNBLOCK_CHILD (oset); - return job_slots; - } + 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; - newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *)); - for (i = j = 0; i < job_slots; i++) + BLOCK_CHILD (set, oset); + nlist = (JOB **) xmalloc (nsize * sizeof (JOB *)); + for (i = j = 0; i < js.j_jobslots; i++) if (jobs[i]) - newlist[j++] = jobs[i]; + nlist[j++] = jobs[i]; - ndel = j; - for ( ; j < job_slots; j++) - newlist[j] = (JOB *)NULL; + js.j_firstj = 0; + js.j_lastj = (j > 0) ? j - 1: 0; + js.j_jobslots = nsize; free (jobs); - jobs = newlist; + jobs = nlist; UNBLOCK_CHILD (oset); +} - return ndel; +/* 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 js.j_jobslots, then + the list needs to be reallocated. The jobs array is in new memory if + this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ +static int +compact_jobs_list (flags) + int flags; +{ + if (js.j_jobslots == 0 || jobs_list_frozen) + return js.j_jobslots; + + reap_dead_jobs (); + realloc_jobs_list (); + + 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; } } diff --git a/jobs.c.instrumented b/jobs.c.instrumented new file mode 100644 index 0000000..611dfea --- /dev/null +++ b/jobs.c.instrumented @@ -0,0 +1,3699 @@ +/* The thing that makes children, remembers them, and contains wait loops. */ + +/* This file works with both POSIX and BSD systems. It implements job + control. */ + +/* Copyright (C) 1989-2005 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include "config.h" + +#include "bashtypes.h" +#include "trap.h" +#include +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "posixtime.h" + +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) +# include +#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ + +#if defined (HAVE_SYS_FILE_H) +# include +#endif + +#include "filecntl.h" +#include +#include + +#if defined (BUFFERED_INPUT) +# include "input.h" +#endif + +/* Need to include this up here for *_TTY_DRIVER definitions. */ +#include "shtty.h" + +/* Define this if your output is getting swallowed. It's a no-op on + machines with the termio or termios tty drivers. */ +/* #define DRAIN_OUTPUT */ + +/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ +#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) +# include +#endif /* hpux && !TERMIOS_TTY_DRIVER */ + +#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) +/* For struct winsize on SCO */ +/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ +# if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) +# if defined (HAVE_SYS_STREAM_H) +# include +# endif +# include +# endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */ +#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */ + +#include "bashansi.h" +#include "bashintl.h" +#include "shell.h" +#include "jobs.h" +#include "flags.h" + +#include "builtins/builtext.h" +#include "builtins/common.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#define DEFAULT_CHILD_MAX 32 +#define MAX_JOBS_IN_ARRAY 4096 /* testing */ + +/* Take care of system dependencies that must be handled when waiting for + children. The arguments to the WAITPID macro match those to the Posix.1 + waitpid() function. */ + +#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION) +# define WAITPID(pid, statusp, options) \ + wait3 ((union wait *)statusp, options, (struct rusage *)0) +#else +# if defined (_POSIX_VERSION) || defined (HAVE_WAITPID) +# define WAITPID(pid, statusp, options) \ + waitpid ((pid_t)pid, statusp, options) +# else +# if defined (HAVE_WAIT3) +# define WAITPID(pid, statusp, options) \ + wait3 (statusp, options, (struct rusage *)0) +# else +# define WAITPID(pid, statusp, options) \ + wait3 (statusp, options, (int *)0) +# endif /* HAVE_WAIT3 */ +# endif /* !_POSIX_VERSION && !HAVE_WAITPID*/ +#endif /* !(Ultrix && mips && _POSIX_VERSION) */ + +/* getpgrp () varies between systems. Even systems that claim to be + Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ +#if defined (GETPGRP_VOID) +# define getpgid(p) getpgrp () +#else +# define getpgid(p) getpgrp (p) +#endif /* !GETPGRP_VOID */ + +/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the + handler for SIGCHLD. */ +#if defined (MUST_REINSTALL_SIGHANDLERS) +# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler) +#else +# define REINSTALL_SIGCHLD_HANDLER +#endif /* !MUST_REINSTALL_SIGHANDLERS */ + +/* Some systems let waitpid(2) tell callers about stopped children. */ +#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN) +# undef WCONTINUED +# define WCONTINUED 0 +#endif +#if !defined (WIFCONTINUED) +# define WIFCONTINUED(s) (0) +#endif + +/* The number of additional slots to allocate when we run out. */ +#define JOB_SLOTS 8 + +typedef int sh_job_map_func_t __P((JOB *, int, int, int)); + +#if defined (READLINE) +extern void rl_set_screen_size __P((int, int)); +#endif + +/* Variables used here but defined in other files. */ +extern int subshell_environment, line_number; +extern int posixly_correct, shell_level; +extern int interrupt_immediately; +extern int last_command_exit_value, last_command_exit_signal; +extern int loop_level, breaking; +extern int sourcelevel; +extern sh_builtin_func_t *this_shell_builtin; +extern char *shell_name, *this_command_name; +extern sigset_t top_level_mask; +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, 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; + +/* The shell's process group. */ +pid_t shell_pgrp = NO_PID; + +/* The terminal's process group. */ +pid_t terminal_pgrp = NO_PID; + +/* The process group of the shell's parent. */ +pid_t original_pgrp = NO_PID; + +/* The process group of the pipeline currently being made. */ +pid_t pipeline_pgrp = (pid_t)0; + +#if defined (PGRP_PIPE) +/* Pipes which each shell uses to communicate with the process group leader + until all of the processes in a pipeline have been started. Then the + process leader is allowed to continue. */ +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; + +/* Pid of the last asynchronous child. */ +pid_t last_asynchronous_pid = NO_PID; + +/* The pipeline currently being built. */ +PROCESS *the_pipeline = (PROCESS *)NULL; + +/* If this is non-zero, do job control. */ +int job_control = 1; + +/* Call this when you start making children. */ +int already_making_children = 0; + +/* If this is non-zero, $LINES and $COLUMNS are reset after every process + exits from get_tty_state(). */ +int check_window_size; + +/* Functions local to this file. */ + +static void get_new_window_size __P((int)); + +static void run_sigchld_trap __P((int)); + +static sighandler wait_sigint_handler __P((int)); +static sighandler sigchld_handler __P((int)); +static sighandler sigwinch_sighandler __P((int)); +static sighandler sigcont_sighandler __P((int)); +static sighandler sigstop_sighandler __P((int)); + +static int waitchld __P((pid_t, int)); + +static PROCESS *find_pipeline __P((pid_t, int, int *)); + +static char *current_working_directory __P((void)); +static char *job_working_directory __P((void)); +static char *j_strsignal __P((int)); +static char *printable_job_status __P((int, PROCESS *, int)); + +static pid_t find_last_pid __P((int, int)); + +static int set_new_line_discipline __P((int)); +static int map_over_jobs __P((sh_job_map_func_t *, int, int)); +static int job_last_stopped __P((int)); +static int job_last_running __P((int)); +static int most_recent_job_in_state __P((int, JOB_STATE)); +static int find_job __P((pid_t, int)); +static int print_job __P((JOB *, int, int, int)); +static int process_exit_status __P((WAIT)); +static int process_exit_signal __P((WAIT)); +static int job_exit_status __P((int)); +static int job_exit_signal __P((int)); +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 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 *)); +static void set_current_job __P((int)); +static void reset_current __P((void)); +static void set_job_running __P((int)); +static void setjstatus __P((int)); +static void mark_all_jobs_as_dead __P((void)); +static void mark_dead_jobs_as_notified __P((int)); +static void restore_sigint_handler __P((void)); +#if defined (PGRP_PIPE) +static void pipe_read __P((int *)); +static void pipe_close __P((int *)); +#endif + +#if defined (ARRAY_VARS) +static int *pstatuses; /* list of pipeline statuses */ +static int statsize; +#endif + +/* Used to synchronize between wait_for and other functions and the SIGCHLD + signal handler. */ +static int sigchld; +static int queue_sigchld; + +#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++ + +#define UNQUEUE_SIGCHLD(os) \ + do { \ + queue_sigchld--; \ + if (queue_sigchld == 0 && os != sigchld) \ + waitchld (-1, 0); \ + } while (0) + +static SigHandler *old_tstp, *old_ttou, *old_ttin; +static SigHandler *old_cont = (SigHandler *)SIG_DFL; + +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static SigHandler *old_winch = (SigHandler *)SIG_DFL; +#endif + +/* A place to temporarily save the current pipeline. */ +static PROCESS *saved_pipeline; +static int saved_already_making_children; + +/* Set this to non-zero whenever you don't want the jobs list to change at + all: no jobs deleted and no status change notifications. This is used, + for example, when executing SIGCHLD traps, which may run arbitrary + commands. */ +static int jobs_list_frozen; + +static char retcode_name_buffer[64]; + +#if !defined (_POSIX_VERSION) + +/* These are definitions to map POSIX 1003.1 functions onto existing BSD + library functions and system calls. */ +#define setpgid(pid, pgrp) setpgrp (pid, pgrp) +#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) + +pid_t +tcgetpgrp (fd) + int fd; +{ + pid_t pgrp; + + /* ioctl will handle setting errno correctly. */ + if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) + return (-1); + return (pgrp); +} + +#endif /* !_POSIX_VERSION */ + +/* Return the working directory for the current process. Unlike + job_working_directory, this does not call malloc (), nor do any + of the functions it calls. This is so that it can safely be called + from a signal handler. */ +static char * +current_working_directory () +{ + char *dir; + static char d[PATH_MAX]; + + dir = get_string_value ("PWD"); + + if (dir == 0 && the_current_working_directory && no_symbolic_links) + dir = the_current_working_directory; + + if (dir == 0) + { + dir = getcwd (d, sizeof(d)); + if (dir) + dir = d; + } + + return (dir == 0) ? "" : dir; +} + +/* Return the working directory for the current process. */ +static char * +job_working_directory () +{ + char *dir; + + dir = get_string_value ("PWD"); + if (dir) + return (savestring (dir)); + + dir = get_working_directory ("job-working-directory"); + if (dir) + return (dir); + + return (savestring ("")); +} + +void +making_children () +{ + if (already_making_children) + return; + + already_making_children = 1; + start_pipeline (); +} + +void +stop_making_children () +{ + already_making_children = 0; +} + +void +cleanup_the_pipeline () +{ + if (the_pipeline) + { + discard_pipeline (the_pipeline); + the_pipeline = (PROCESS *)NULL; + } +} + +void +save_pipeline (clear) + int clear; +{ + saved_pipeline = the_pipeline; + saved_already_making_children = already_making_children; + if (clear) + the_pipeline = (PROCESS *)NULL; +} + +void +restore_pipeline (discard) + int discard; +{ + PROCESS *old_pipeline; + + old_pipeline = the_pipeline; + the_pipeline = saved_pipeline; + already_making_children = saved_already_making_children; + if (discard) + discard_pipeline (old_pipeline); +} + +/* Start building a pipeline. */ +void +start_pipeline () +{ + if (the_pipeline) + { + cleanup_the_pipeline (); + pipeline_pgrp = 0; +#if defined (PGRP_PIPE) + pipe_close (pgrp_pipe); +#endif + } + +#if defined (PGRP_PIPE) + if (job_control) + { + if (pipe (pgrp_pipe) == -1) + sys_error ("start_pipeline: pgrp pipe"); + } +#endif +} + +/* Stop building a pipeline. Install the process list in the job array. + This returns the index of the newly installed job. + DEFERRED is a command structure to be executed upon satisfactory + execution exit of this pipeline. */ +int +stop_pipeline (async, deferred) + int async; + COMMAND *deferred; +{ + register int i, j; + JOB *newjob; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + +#if defined (PGRP_PIPE) + /* The parent closes the process group synchronization pipe. */ + pipe_close (pgrp_pipe); +#endif + + cleanup_dead_jobs (); + + if (js.j_jobslots == 0) + { + js.j_jobslots = JOB_SLOTS; + jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *)); + + /* Now blank out these new entries. */ + 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 = js.j_jobslots; i; i--) + if (jobs[i - 1]) + break; + } + else + { +#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 ((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 == js.j_jobslots) + { + js.j_jobslots += JOB_SLOTS; + jobs = (JOB **)xrealloc (jobs, (js.j_jobslots * sizeof (JOB *))); + + for (j = i; j < js.j_jobslots; j++) + jobs[j] = (JOB *)NULL; + } + + /* Add the current pipeline to the job list. */ + if (the_pipeline) + { + register PROCESS *p; + int any_alive, any_stopped, n; + + newjob = (JOB *)xmalloc (sizeof (JOB)); + + for (n = 0, p = the_pipeline; p->next != the_pipeline; n++, p = p->next) + ; + p->next = (PROCESS *)NULL; + newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); + for (p = newjob->pipe; p->next; p = p->next) + ; + p->next = newjob->pipe; + + the_pipeline = (PROCESS *)NULL; + newjob->pgrp = pipeline_pgrp; + pipeline_pgrp = 0; + + newjob->flags = 0; + + /* Flag to see if in another pgrp. */ + if (job_control) + newjob->flags |= J_JOBCONTROL; + + /* Set the state of this pipeline. */ + p = newjob->pipe; + any_alive = any_stopped = 0; + do + { + any_alive |= p->running; + any_stopped |= WIFSTOPPED (p->status); + p = p->next; + } + while (p != newjob->pipe); + + newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); + newjob->wd = job_working_directory (); + newjob->deferred = deferred; + + newjob->j_cleanup = (sh_vptrfunc_t *)NULL; + newjob->cleanarg = (PTR_T) NULL; + + jobs[i] = newjob; + if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) + setjstatus (i); + + js.c_injobs += n; + + js.j_lastj = i; +itrace("stop_pipeline: set js.j_lastj = %d", js.j_lastj); + js.j_njobs++; + } + else + newjob = (JOB *)NULL; + + if (async) + { + if (newjob) + newjob->flags &= ~J_FOREGROUND; + reset_current (); + } + else + { + if (newjob) + { + newjob->flags |= J_FOREGROUND; + /* + * !!!!! NOTE !!!!! (chet@ins.cwru.edu) + * + * The currently-accepted job control wisdom says to set the + * terminal's process group n+1 times in an n-step pipeline: + * once in the parent and once in each child. This is where + * the parent gives it away. + * + */ + if (job_control && newjob->pgrp) + give_terminal_to (newjob->pgrp, 0); + } + } + + stop_making_children (); + UNBLOCK_CHILD (oset); + 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; +itrace("reset_job_indices: reset js.j_firstj from %d to %d", old, js.j_firstj); + } + 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; +itrace("reset_job_indices: reset js.j_lastj from %d to %d", old, js.j_lastj); + } +} + +/* Delete all DEAD jobs that the user had received notification about. */ +static void +cleanup_dead_jobs () +{ + register int i; + int os; + + if (js.j_jobslots == 0 || jobs_list_frozen) + return; + + QUEUE_SIGCHLD(os); + + /* 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 js.j_jobslots, then + the list needs to be reallocated. The jobs array is in new memory if + this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ +static int +compact_jobs_list (flags) + int flags; +{ + if (js.j_jobslots == 0 || jobs_list_frozen) + return js.j_jobslots; + + reap_dead_jobs (); + realloc_jobs_list (); + + return (js.j_lastj); +} + +/* Delete the job at INDEX from the job list. Must be called + with SIGCHLD blocked. */ +void +delete_job (job_index, warn_stopped) + int job_index, warn_stopped; +{ + register JOB *temp; + int ndel; + + 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 == js.j_current || job_index == js.j_previous) + reset_current (); + + jobs[job_index] = (JOB *)NULL; + + free (temp->wd); + ndel = discard_pipeline (temp->pipe); + + js.c_injobs -= ndel; + if (temp->state == JDEAD) + js.c_reaped -= ndel; + + if (temp->deferred) + dispose_command (temp->deferred); + + free (temp); + +itrace("delete_job: deleted job %d", job_index); + 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. */ +void +nohup_job (job_index) + int job_index; +{ + register JOB *temp; + + if (js.j_jobslots == 0) + return; + + if (temp = jobs[job_index]) + temp->flags |= J_NOHUP; +} + +/* Get rid of the data structure associated with a process chain. */ +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. + NAME is the command string that will be exec'ed later. + PID is the process id of the child. */ +static void +add_process (name, pid) + char *name; + pid_t pid; +{ + PROCESS *t, *p; + + t = (PROCESS *)xmalloc (sizeof (PROCESS)); + t->next = the_pipeline; + t->pid = pid; + WSTATUS (t->status) = 0; + t->running = PS_RUNNING; + t->command = name; + the_pipeline = t; + + if (t->next == 0) + t->next = t; + else + { + p = t->next; + while (p->next != t->next) + p = p->next; + p->next = t; + } +} + +#if 0 +/* Take the last job and make it the first job. Must be called with + SIGCHLD blocked. */ +int +rotate_the_pipeline () +{ + PROCESS *p; + + if (the_pipeline->next == the_pipeline) + return; + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + the_pipeline = p; +} + +/* Reverse the order of the processes in the_pipeline. Must be called with + SIGCHLD blocked. */ +int +reverse_the_pipeline () +{ + PROCESS *p, *n; + + if (the_pipeline->next == the_pipeline) + return; + + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + p->next = (PROCESS *)NULL; + + n = REVERSE_LIST (the_pipeline, PROCESS *); + + the_pipeline = n; + for (p = the_pipeline; p->next; p = p->next) + ; + p->next = the_pipeline; +} +#endif + +/* Map FUNC over the list of jobs. If FUNC returns non-zero, + then it is time to stop mapping, and that is the return value + for map_over_jobs. FUNC is called with a JOB, arg1, arg2, + and INDEX. */ +static int +map_over_jobs (func, arg1, arg2) + sh_job_map_func_t *func; + int arg1, arg2; +{ + register int i; + int result; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return 0; + + BLOCK_CHILD (set, oset); + + /* 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); + if (result) + break; + } + } + + UNBLOCK_CHILD (oset); + + return (result); +} + +/* Cause all the jobs in the current pipeline to exit. */ +void +terminate_current_pipeline () +{ + if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) + { + killpg (pipeline_pgrp, SIGTERM); + killpg (pipeline_pgrp, SIGCONT); + } +} + +/* Cause all stopped jobs to exit. */ +void +terminate_stopped_jobs () +{ + register int i; + + /* XXX could use js.j_firstj here */ + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i] && STOPPED (i)) + { + killpg (jobs[i]->pgrp, SIGTERM); + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +/* Cause all jobs, running or stopped, to receive a hangup signal. If + a job is marked J_NOHUP, don't send the SIGHUP. */ +void +hangup_all_jobs () +{ + register int i; + + /* XXX could use js.j_firstj here */ + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i]) + { + if ((jobs[i]->flags & J_NOHUP) == 0) + killpg (jobs[i]->pgrp, SIGHUP); + if (STOPPED (i)) + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +void +kill_current_pipeline () +{ + stop_making_children (); + start_pipeline (); +} + +/* Return the pipeline that PID belongs to. Note that the pipeline + doesn't have to belong to a job. Must be called with SIGCHLD blocked. */ +static PROCESS * +find_pipeline (pid, running_only, jobp) + pid_t pid; + int running_only; + int *jobp; /* index into jobs list or NO_JOB */ +{ + int job; + register PROCESS *p; + + /* See if this process is in the pipeline that we are building. */ + if (jobp) + *jobp = NO_JOB; + if (the_pipeline) + { + p = the_pipeline; + do + { + /* Return it if we found it. */ + if (p->pid == pid) + { + if ((running_only && PALIVE(p)) || (running_only == 0)) + return (p); + } + + p = p->next; + } + while (p != the_pipeline); + } + + job = find_job (pid, running_only); + if (jobp) + *jobp = job; + return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe; +} + +/* Return the job index that PID belongs to, or NO_JOB if it doesn't + belong to any job. Must be called with SIGCHLD blocked. */ +static int +find_job (pid, running_only) + pid_t pid; + int running_only; +{ + register int i; + register PROCESS *p; + + /* 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; + + do + { + if (p->pid == pid) + { + if ((running_only && PALIVE(p)) || (running_only == 0)) + return (i); + } + + p = p->next; + } + while (p != jobs[i]->pipe); + } + } + + return (NO_JOB); +} + +/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as + required by find_job. */ +int +get_job_by_pid (pid, block) + pid_t pid; + int block; +{ + int job; + sigset_t set, oset; + + if (block) + BLOCK_CHILD (set, oset); + + job = find_job (pid, 0); + + if (block) + UNBLOCK_CHILD (oset); + + return job; +} + +/* Print descriptive information about the job with leader pid PID. */ +void +describe_pid (pid) + pid_t pid; +{ + int job; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + job = find_job (pid, 0); + + if (job != NO_JOB) + fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid); + else + programming_error (_("describe_pid: %ld: no such pid"), (long)pid); + + UNBLOCK_CHILD (oset); +} + +static char * +j_strsignal (s) + int s; +{ + char *x; + + x = strsignal (s); + if (x == 0) + { + x = retcode_name_buffer; + sprintf (x, "Signal %d", s); + } + return x; +} + +static char * +printable_job_status (j, p, format) + int j; + PROCESS *p; + int format; +{ + static char *temp; + int es; + + temp = "Done"; + + if (STOPPED (j) && format == 0) + { + if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) + temp = "Stopped"; + else + { + temp = retcode_name_buffer; + sprintf (temp, "Stopped(%s)", signal_name (WSTOPSIG (p->status))); + } + } + else if (RUNNING (j)) + temp = "Running"; + else + { + if (WIFSTOPPED (p->status)) + temp = j_strsignal (WSTOPSIG (p->status)); + else if (WIFSIGNALED (p->status)) + temp = j_strsignal (WTERMSIG (p->status)); + else if (WIFEXITED (p->status)) + { + temp = retcode_name_buffer; + es = WEXITSTATUS (p->status); + if (es == 0) + strcpy (temp, "Done"); + else if (posixly_correct) + sprintf (temp, "Done(%d)", es); + else + sprintf (temp, "Exit %d", es); + } + else + temp = "Unknown status"; + } + + return temp; +} + +/* This is the way to print out information on a job if you + know the index. FORMAT is: + + JLIST_NORMAL) [1]+ Running emacs + JLIST_LONG ) [1]+ 2378 Running emacs + -1 ) [1]+ 2378 emacs + + JLIST_NORMAL) [1]+ Stopped ls | more + JLIST_LONG ) [1]+ 2369 Stopped ls + 2367 | more + JLIST_PID_ONLY) + Just list the pid of the process group leader (really + the process group). + JLIST_CHANGED_ONLY) + Use format JLIST_NORMAL, but list only jobs about which + the user has not been notified. */ + +/* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into + the JOBS array corresponding to this pipeline. FORMAT is as described + above. Must be called with SIGCHLD blocked. + + If you're printing a pipeline that's not in the jobs array, like the + current pipeline as it's being created, pass -1 for JOB_INDEX */ +static void +print_pipeline (p, job_index, format, stream) + PROCESS *p; + int job_index, format; + FILE *stream; +{ + PROCESS *first, *last, *show; + int es, name_padding; + char *temp; + + if (p == 0) + return; + + first = last = p; + while (last->next != first) + last = last->next; + + for (;;) + { + if (p != first) + fprintf (stream, format ? " " : " |"); + + if (format != JLIST_STANDARD) + fprintf (stream, "%5ld", (long)p->pid); + + fprintf (stream, " "); + + if (format > -1 && job_index >= 0) + { + show = format ? p : last; + temp = printable_job_status (job_index, show, format); + + if (p != first) + { + if (format) + { + if (show->running == first->running && + WSTATUS (show->status) == WSTATUS (first->status)) + temp = ""; + } + else + temp = (char *)NULL; + } + + if (temp) + { + fprintf (stream, "%s", temp); + + es = STRLEN (temp); + if (es == 0) + es = 2; /* strlen ("| ") */ + name_padding = LONGEST_SIGNAL_DESC - es; + + fprintf (stream, "%*s", name_padding, ""); + + if ((WIFSTOPPED (show->status) == 0) && + (WIFCONTINUED (show->status) == 0) && + WIFCORED (show->status)) + fprintf (stream, "(core dumped) "); + } + } + + if (p != first && format) + fprintf (stream, "| "); + + if (p->command) + fprintf (stream, "%s", p->command); + + if (p == last && job_index >= 0) + { + temp = current_working_directory (); + + if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) + fprintf (stream, " &"); + + if (strcmp (temp, jobs[job_index]->wd) != 0) + fprintf (stream, + " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); + } + + if (format || (p == last)) + { + /* We need to add a CR only if this is an interactive shell, and + we're reporting the status of a completed job asynchronously. + We can't really check whether this particular job is being + reported asynchronously, so just add the CR if the shell is + currently interactive and asynchronous notification is enabled. */ + if (asynchronous_notification && interactive) + fprintf (stream, "\r\n"); + else + fprintf (stream, "\n"); + } + + if (p == last) + break; + p = p->next; + } + fflush (stream); +} + +/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT. + Must be called with SIGCHLD blocked or queued with queue_sigchld */ +static void +pretty_print_job (job_index, format, stream) + int job_index, format; + FILE *stream; +{ + register PROCESS *p; + + /* Format only pid information about the process group leader? */ + if (format == JLIST_PID_ONLY) + { + fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); + return; + } + + if (format == JLIST_CHANGED_ONLY) + { + if (IS_NOTIFIED (job_index)) + return; + format = JLIST_STANDARD; + } + + if (format != JLIST_NONINTERACTIVE) + fprintf (stream, "[%d]%c ", job_index + 1, + (job_index == js.j_current) ? '+': + (job_index == js.j_previous) ? '-' : ' '); + + if (format == JLIST_NONINTERACTIVE) + format = JLIST_LONG; + + p = jobs[job_index]->pipe; + + print_pipeline (p, job_index, format, stream); + + /* We have printed information about this job. When the job's + status changes, waitchld () sets the notification flag to 0. */ + jobs[job_index]->flags |= J_NOTIFIED; +} + +static int +print_job (job, format, state, job_index) + JOB *job; + int format, state, job_index; +{ + if (state == -1 || (JOB_STATE)state == job->state) + pretty_print_job (job_index, format, stdout); + return (0); +} + +void +list_one_job (job, format, ignore, job_index) + JOB *job; + int format, ignore, job_index; +{ + pretty_print_job (job_index, format, stdout); +} + +void +list_stopped_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, (int)JSTOPPED); +} + +void +list_running_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, (int)JRUNNING); +} + +/* List jobs. If FORMAT is non-zero, then the long form of the information + is printed, else just a short version. */ +void +list_all_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, -1); +} + +/* Fork, handling errors. Returns the pid of the newly made child, or 0. + COMMAND is just for remembering the name of the command; we don't do + anything else with it. ASYNC_P says what to do with the tty. If + non-zero, then don't give it away. */ +pid_t +make_child (command, async_p) + char *command; + int async_p; +{ + sigset_t set, oset; + pid_t pid; + + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGINT); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + making_children (); + +#if defined (BUFFERED_INPUT) + /* If default_buffered_input is active, we are reading a script. If + the command is asynchronous, we have already duplicated /dev/null + as fd 0, but have not changed the buffered stream corresponding to + the old fd 0. We don't want to sync the stream in this case. */ + if (default_buffered_input != -1 && + (!async_p || default_buffered_input > 0)) + sync_buffered_stream (default_buffered_input); +#endif /* BUFFERED_INPUT */ + + /* Create the child, handle severe errors. */ + if ((pid = fork ()) < 0) + { + sys_error ("fork"); + + /* Kill all of the processes in the current pipeline. */ + terminate_current_pipeline (); + + /* Discard the current pipeline, if any. */ + if (the_pipeline) + kill_current_pipeline (); + + throw_to_top_level (); /* Reset signals, etc. */ + } + + if (pid == 0) + { + /* In the child. Give this child the right process group, set the + signals to the default state for a new process. */ + pid_t mypid; + + mypid = getpid (); +#if defined (BUFFERED_INPUT) + /* Close default_buffered_input if it's > 0. We don't close it if it's + 0 because that's the file descriptor used when redirecting input, + and it's wrong to close the file in that case. */ + unset_bash_input (0); +#endif /* BUFFERED_INPUT */ + + /* Restore top-level signal mask. */ + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); + + if (job_control) + { + /* All processes in this pipeline belong in the same + process group. */ + + if (pipeline_pgrp == 0) /* This is the first child. */ + pipeline_pgrp = mypid; + + /* Check for running command in backquotes. */ + if (pipeline_pgrp == shell_pgrp) + ignore_tty_job_signals (); + else + default_tty_job_signals (); + + /* Set the process group before trying to mess with the terminal's + process group. This is mandated by POSIX. */ + /* This is in accordance with the Posix 1003.1 standard, + section B.7.2.4, which says that trying to set the terminal + process group with tcsetpgrp() to an unused pgrp value (like + this would have for the first child) is an error. Section + B.4.3.3, p. 237 also covers this, in the context of job control + shells. */ + if (setpgid (mypid, pipeline_pgrp) < 0) + sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp); + + /* By convention (and assumption above), if + pipeline_pgrp == shell_pgrp, we are making a child for + command substitution. + In this case, we don't want to give the terminal to the + shell's process group (we could be in the middle of a + pipeline, for example). */ + if (async_p == 0 && pipeline_pgrp != shell_pgrp) + give_terminal_to (pipeline_pgrp, 0); + +#if defined (PGRP_PIPE) + if (pipeline_pgrp == mypid) + pipe_read (pgrp_pipe); +#endif + } + else /* Without job control... */ + { + if (pipeline_pgrp == 0) + pipeline_pgrp = shell_pgrp; + + /* If these signals are set to SIG_DFL, we encounter the curious + situation of an interactive ^Z to a running process *working* + and stopping the process, but being unable to do anything with + that process to change its state. On the other hand, if they + are set to SIG_IGN, jobs started from scripts do not stop when + the shell running the script gets a SIGTSTP and stops. */ + + default_tty_job_signals (); + } + +#if defined (PGRP_PIPE) + /* Release the process group pipe, since our call to setpgid () + is done. The last call to pipe_close is done in stop_pipeline. */ + pipe_close (pgrp_pipe); +#endif /* PGRP_PIPE */ + + if (async_p) + last_asynchronous_pid = getpid (); + } + else + { + /* In the parent. Remember the pid of the child just created + as the proper pgrp if this is the first child. */ + + if (job_control) + { + if (pipeline_pgrp == 0) + { + pipeline_pgrp = pid; + /* Don't twiddle terminal pgrps in the parent! This is the bug, + not the good thing of twiddling them in the child! */ + /* give_terminal_to (pipeline_pgrp, 0); */ + } + /* This is done on the recommendation of the Rationale section of + the POSIX 1003.1 standard, where it discusses job control and + shells. It is done to avoid possible race conditions. (Ref. + 1003.1 Rationale, section B.4.3.3, page 236). */ + setpgid (pid, pipeline_pgrp); + } + else + { + if (pipeline_pgrp == 0) + pipeline_pgrp = shell_pgrp; + } + + /* Place all processes into the jobs array regardless of the + state of job_control. */ + add_process (command, pid); + + if (async_p) + last_asynchronous_pid = pid; + + 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. */ + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return (pid); +} + +/* These two functions are called only in child processes. */ +void +ignore_tty_job_signals () +{ + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); +} + +void +default_tty_job_signals () +{ + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); +} + +/* When we end a job abnormally, or if we stop a job, we set the tty to the + state kept in here. When a job ends normally, we set the state in here + to the state of the tty. */ + +static TTYSTRUCT shell_tty_info; + +#if defined (NEW_TTY_DRIVER) +static struct tchars shell_tchars; +static struct ltchars shell_ltchars; +#endif /* NEW_TTY_DRIVER */ + +#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) +/* Since the BSD tty driver does not allow us to change the tty modes + while simultaneously waiting for output to drain and preserving + typeahead, we have to drain the output ourselves before calling + ioctl. We cheat by finding the length of the output queue, and + using select to wait for an appropriate length of time. This is + a hack, and should be labeled as such (it's a hastily-adapted + mutation of a `usleep' implementation). It's only reason for + existing is the flaw in the BSD tty driver. */ + +static int ttspeeds[] = +{ + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400 +}; + +static void +draino (fd, ospeed) + int fd, ospeed; +{ + register int delay = ttspeeds[ospeed]; + int n; + + if (!delay) + return; + + while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) + { + if (n > (delay / 100)) + { + struct timeval tv; + + n *= 10; /* 2 bits more for conservativeness. */ + tv.tv_sec = n / delay; + tv.tv_usec = ((n % delay) * 1000000) / delay; + select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); + } + else + break; + } +} +#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ + +/* Return the fd from which we are actually getting input. */ +#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) + +/* Fill the contents of shell_tty_info with the current tty info. */ +int +get_tty_state () +{ + int tty; + + tty = input_tty (); + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) + ioctl (tty, TIOCGETP, &shell_tty_info); + ioctl (tty, TIOCGETC, &shell_tchars); + ioctl (tty, TIOCGLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCGETA, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcgetattr (tty, &shell_tty_info) < 0) + { +#if 0 + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + sys_error ("[%ld: %d] tcgetattr", (long)getpid (), shell_level); +#endif + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + if (check_window_size) + get_new_window_size (0); + } + return 0; +} + +/* Make the current tty use the state in shell_tty_info. */ +int +set_tty_state () +{ + int tty; + + tty = input_tty (); + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) +# if defined (DRAIN_OUTPUT) + draino (tty, shell_tty_info.sg_ospeed); +# endif /* DRAIN_OUTPUT */ + ioctl (tty, TIOCSETN, &shell_tty_info); + ioctl (tty, TIOCSETC, &shell_tchars); + ioctl (tty, TIOCSLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCSETAW, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + { + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + sys_error ("[%ld: %d] tcsetattr", (long)getpid (), shell_level); + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + } + return 0; +} + +/* Given an index into the jobs array JOB, return the pid of the last + process in that job's pipeline. This is the one whose exit status + counts. Must be called with SIGCHLD blocked or queued. */ +static pid_t +find_last_pid (job, block) + int job; + int block; +{ + register PROCESS *p; + sigset_t set, oset; + + if (block) + BLOCK_CHILD (set, oset); + + p = jobs[job]->pipe; + while (p->next != jobs[job]->pipe) + p = p->next; + + if (block) + UNBLOCK_CHILD (oset); + + return (p->pid); +} + +/* Wait for a particular child of the shell to finish executing. + This low-level function prints an error message if PID is not + a child of this shell. It returns -1 if it fails, or whatever + wait_for returns otherwise. If the child is not found in the + jobs table, it returns 127. */ +int +wait_for_single_pid (pid) + pid_t pid; +{ + register PROCESS *child; + sigset_t set, oset; + int r, job; + + BLOCK_CHILD (set, oset); + child = find_pipeline (pid, 0, (int *)NULL); + UNBLOCK_CHILD (oset); + + if (child == 0) + { + internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); + return (127); + } + + r = wait_for (pid); + + /* POSIX.2: if we just waited for a job, we can remove it from the jobs + table. */ + BLOCK_CHILD (set, oset); + job = find_job (pid, 0); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); + + return r; +} + +/* Wait for all of the backgrounds of this shell to finish. */ +void +wait_for_background_pids () +{ + register int i, r, waited_for; + sigset_t set, oset; + pid_t pid; + + for (waited_for = 0;;) + { + BLOCK_CHILD (set, oset); + + /* find first running job; if none running in foreground, break */ + /* 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 == js.j_jobslots) + { + UNBLOCK_CHILD (oset); + break; + } + + /* now wait for the last pid in that job. */ + pid = find_last_pid (i, 0); + UNBLOCK_CHILD (oset); + QUIT; + errno = 0; /* XXX */ + r = wait_for_single_pid (pid); + if (r == -1) + { + /* If we're mistaken about job state, compensate. */ + if (errno == ECHILD) + mark_all_jobs_as_dead (); + } + else + waited_for++; + } + + /* POSIX.2 says the shell can discard the statuses of all completed jobs if + `wait' is called with no arguments. */ + mark_dead_jobs_as_notified (1); + cleanup_dead_jobs (); +} + +/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ +#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids +static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; + +static void +restore_sigint_handler () +{ + if (old_sigint_handler != INVALID_SIGNAL_HANDLER) + { + set_signal_handler (SIGINT, old_sigint_handler); + old_sigint_handler = INVALID_SIGNAL_HANDLER; + } +} + +static int wait_sigint_received; + +/* Handle SIGINT while we are waiting for children in a script to exit. + The `wait' builtin should be interruptible, but all others should be + effectively ignored (i.e. not cause the shell to exit). */ +static sighandler +wait_sigint_handler (sig) + int sig; +{ + SigHandler *sigint_handler; + + if (interrupt_immediately || + (this_shell_builtin && this_shell_builtin == wait_builtin)) + { + last_command_exit_value = EXECUTION_FAILURE; + restore_sigint_handler (); + /* If we got a SIGINT while in `wait', and SIGINT is trapped, do + what POSIX.2 says (see builtins/wait.def for more info). */ + if (this_shell_builtin && this_shell_builtin == wait_builtin && + signal_is_trapped (SIGINT) && + ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler)) + { + interrupt_immediately = 0; + trap_handler (SIGINT); /* set pending_traps[SIGINT] */ + wait_signal_received = SIGINT; + longjmp (wait_intr_buf, 1); + } + + ADDINTERRUPT; + QUIT; + } + + /* XXX - should this be interrupt_state? If it is, the shell will act + as if it got the SIGINT interrupt. */ + wait_sigint_received = 1; + + /* Otherwise effectively ignore the SIGINT and allow the running job to + be killed. */ + SIGRETURN (0); +} + +static int +process_exit_signal (status) + WAIT status; +{ + return (WIFSIGNALED (status) ? WTERMSIG (status) : 0); +} + +static int +process_exit_status (status) + WAIT status; +{ + if (WIFSIGNALED (status)) + return (128 + WTERMSIG (status)); + else if (WIFSTOPPED (status) == 0) + return (WEXITSTATUS (status)); + else + return (EXECUTION_SUCCESS); +} + +/* Return the exit status of the last process in the pipeline for job JOB. + This is the exit status of the entire job. */ +static WAIT +raw_job_exit_status (job) + int job; +{ + register PROCESS *p; + int fail; + + if (pipefail_opt) + { + fail = 0; + p = jobs[job]->pipe; + do + { + if (p->status != EXECUTION_SUCCESS) fail = p->status; + p = p->next; + } + while (p != jobs[job]->pipe); + return fail; + } + + for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) + ; + return (p->status); +} + +/* Return the exit status of job JOB. This is the exit status of the last + (rightmost) process in the job's pipeline, modified if the job was killed + by a signal or stopped. */ +static int +job_exit_status (job) + int job; +{ + return (process_exit_status (raw_job_exit_status (job))); +} + +static int +job_exit_signal (job) + int job; +{ + return (process_exit_signal (raw_job_exit_status (job))); +} + +#define FIND_CHILD(pid, child) \ + do \ + { \ + child = find_pipeline (pid, 0, (int *)NULL); \ + if (child == 0) \ + { \ + give_terminal_to (shell_pgrp, 0); \ + UNBLOCK_CHILD (oset); \ + internal_error (_("wait_for: No record of process %ld"), (long)pid); \ + restore_sigint_handler (); \ + return (termination_state = 127); \ + } \ + } \ + while (0) + +/* Wait for pid (one of our children) to terminate, then + return the termination state. Returns 127 if PID is not found in + the jobs table. Returns -1 if waitchld() returns -1, indicating + that there are no unwaited-for child processes. */ +int +wait_for (pid) + pid_t pid; +{ + int job, termination_state, r; + WAIT s; + register PROCESS *child; + sigset_t set, oset; + register PROCESS *p; + + /* In the case that this code is interrupted, and we longjmp () out of it, + we are relying on the code in throw_to_top_level () to restore the + top-level signal mask. */ + BLOCK_CHILD (set, oset); + + /* Ignore interrupts while waiting for a job run without job control + to finish. We don't want the shell to exit if an interrupt is + received, only if one of the jobs run is killed via SIGINT. If + job control is not set, the job will be run in the same pgrp as + the shell, and the shell will see any signals the job gets. */ + + /* This is possibly a race condition -- should it go in stop_pipeline? */ + wait_sigint_received = 0; + if (job_control == 0) + old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); + + termination_state = last_command_exit_value; + + if (interactive && job_control == 0) + QUIT; + + /* If we say wait_for (), then we have a record of this child somewhere. + If it and none of its peers are running, don't call waitchld(). */ + + job = NO_JOB; + do + { + FIND_CHILD (pid, child); + + /* If this child is part of a job, then we are really waiting for the + job to finish. Otherwise, we are waiting for the child to finish. + We check for JDEAD in case the job state has been set by waitchld + after receipt of a SIGCHLD. */ + if (job == NO_JOB) + job = find_job (pid, 0); + + /* waitchld() takes care of setting the state of the job. If the job + has already exited before this is called, sigchld_handler will have + called waitchld and the state will be set to JDEAD. */ + + if (child->running || (job != NO_JOB && RUNNING (job))) + { +#if defined (WAITPID_BROKEN) /* SCOv4 */ + sigset_t suspend_set; + sigemptyset (&suspend_set); + sigsuspend (&suspend_set); +#else /* !WAITPID_BROKEN */ +# if defined (MUST_UNBLOCK_CHLD) + struct sigaction act, oact; + sigset_t nullset, chldset; + + sigemptyset (&nullset); + sigemptyset (&chldset); + sigprocmask (SIG_SETMASK, &nullset, &chldset); + act.sa_handler = SIG_DFL; + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + act.sa_flags = 0; + sigaction (SIGCHLD, &act, &oact); +# endif + queue_sigchld = 1; + r = waitchld (pid, 1); +# if defined (MUST_UNBLOCK_CHLD) + sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); + sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); +# endif + queue_sigchld = 0; + if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin) + { + termination_state = -1; + goto wait_for_return; + } + + /* If child is marked as running, but waitpid() returns -1/ECHILD, + there is something wrong. Somewhere, wait should have returned + that child's pid. Mark the child as not running and the job, + if it exists, as JDEAD. */ + if (r == -1 && errno == ECHILD) + { + child->running = PS_DONE; + child->status = 0; /* XXX -- can't find true status */ + if (job != NO_JOB) + jobs[job]->state = JDEAD; + } +#endif /* WAITPID_BROKEN */ + } + + /* If the shell is interactive, and job control is disabled, see + if the foreground process has died due to SIGINT and jump out + of the wait loop if it has. waitchld has already restored the + old SIGINT signal handler. */ + if (interactive && job_control == 0) + QUIT; + } + while (child->running || (job != NO_JOB && RUNNING (job))); + + /* The exit state of the command is either the termination state of the + child, or the termination state of the job. If a job, the status + of the last child in the pipeline is the significant one. If the command + or job was terminated by a signal, note that value also. */ + termination_state = (job != NO_JOB) ? job_exit_status (job) + : process_exit_status (child->status); + 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); + + if (job == NO_JOB || IS_JOBCONTROL (job)) + { + /* XXX - under what circumstances is a job not present in the jobs + table (job == NO_JOB)? + 1. command substitution + + In the case of command substitution, at least, it's probably not + the right thing to give the terminal to the shell's process group, + even though there is code in subst.c:command_substitute to work + around it. + + Things that don't: + $PROMPT_COMMAND execution + process substitution + */ +#if 0 +if (job == NO_JOB) + itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); +#endif + + give_terminal_to (shell_pgrp, 0); + } + + /* If the command did not exit cleanly, or the job is just + being stopped, then reset the tty state back to what it + was before this command. Reset the tty state and notify + the user of the job termination only if the shell is + interactive. Clean up any dead jobs in either case. */ + if (job != NO_JOB) + { + if (interactive_shell && subshell_environment == 0) + { + /* This used to use `child->status'. That's wrong, however, for + pipelines. `child' is the first process in the pipeline. It's + likely that the process we want to check for abnormal termination + or stopping is the last process in the pipeline, especially if + it's long-lived and the first process is short-lived. Since we + know we have a job here, we can check all the processes in this + job's pipeline and see if one of them stopped or terminated due + to a signal. We might want to change this later to just check + the last process in the pipeline. If no process exits due to a + signal, S is left as the status of the last job in the pipeline. */ + p = jobs[job]->pipe; + do + { + s = p->status; + if (WIFSIGNALED(s) || WIFSTOPPED(s)) + break; + p = p->next; + } + while (p != jobs[job]->pipe); + + if (WIFSIGNALED (s) || WIFSTOPPED (s)) + { + set_tty_state (); + + /* 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 == js.j_current || IS_FOREGROUND (job))) + get_new_window_size (0); + } + else + get_tty_state (); + + /* If job control is enabled, the job was started with job + control, the job was the foreground job, and it was killed + by SIGINT, then print a newline to compensate for the kernel + printing the ^C without a trailing newline. */ + if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && + WIFSIGNALED (s) && WTERMSIG (s) == SIGINT) + { + /* If SIGINT is not trapped and the shell is in a for, while, + or until loop, act as if the shell received SIGINT as + well, so the loop can be broken. This doesn't call the + SIGINT signal handler; maybe it should. */ + if (signal_is_trapped (SIGINT) == 0 && loop_level) + ADDINTERRUPT; + else + { + putchar ('\n'); + fflush (stdout); + } + } + } + + /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD + signal handler path */ + if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/) + setjstatus (job); + + /* If this job is dead, notify the user of the status. If the shell + is interactive, this will display a message on the terminal. If + the shell is not interactive, make sure we turn on the notify bit + so we don't get an unwanted message about the job's termination, + and so delete_job really clears the slot in the jobs table. */ + notify_and_cleanup (); + } + +wait_for_return: + + UNBLOCK_CHILD (oset); + + /* Restore the original SIGINT signal handler before we return. */ + restore_sigint_handler (); + + return (termination_state); +} + +/* Wait for the last process in the pipeline for JOB. Returns whatever + wait_for returns: the last process's termination state or -1 if there + are no unwaited-for child processes or an error occurs. */ +int +wait_for_job (job) + int job; +{ + pid_t pid; + int r; + sigset_t set, oset; + + BLOCK_CHILD(set, oset); + if (JOBSTATE (job) == JSTOPPED) + internal_warning (_("wait_for_job: job %d is stopped"), job+1); + + pid = find_last_pid (job, 0); + UNBLOCK_CHILD(oset); + r = wait_for (pid); + + /* POSIX.2: we can remove the job from the jobs table if we just waited + for it. */ + BLOCK_CHILD (set, oset); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); + + return r; +} + +/* Print info about dead jobs, and then delete them from the list + of known jobs. This does not actually delete jobs when the + shell is not interactive, because the dead jobs are not marked + as notified. */ +void +notify_and_cleanup () +{ + if (jobs_list_frozen) + return; + + if (interactive || interactive_shell == 0 || sourcelevel) + notify_of_job_status (); + + cleanup_dead_jobs (); +} + +/* Make dead jobs disappear from the jobs array without notification. + This is used when the shell is not interactive. */ +void +reap_dead_jobs () +{ + mark_dead_jobs_as_notified (0); + cleanup_dead_jobs (); +} + +/* Return the next closest (chronologically) job to JOB which is in + STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if + there is no next recent job. */ +static int +most_recent_job_in_state (job, state) + int job; + JOB_STATE state; +{ + register int i, result; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + for (result = NO_JOB, i = job - 1; i >= 0; i--) + { + if (jobs[i] && (JOBSTATE (i) == state)) + { + result = i; + break; + } + } + + UNBLOCK_CHILD (oset); + + return (result); +} + +/* Return the newest *stopped* job older than JOB, or NO_JOB if not + found. */ +static int +job_last_stopped (job) + int job; +{ + return (most_recent_job_in_state (job, JSTOPPED)); +} + +/* Return the newest *running* job older than JOB, or NO_JOB if not + found. */ +static int +job_last_running (job) + int job; +{ + return (most_recent_job_in_state (job, JRUNNING)); +} + +/* Make JOB be the current job, and make previous be useful. Must be + called with SIGCHLD blocked. */ +static void +set_current_job (job) + int job; +{ + int candidate; + + if (js.j_current != job) + { + js.j_previous = js.j_current; + js.j_current = 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 (js.j_current)) + { + candidate = job_last_stopped (js.j_current); + + if (candidate != NO_JOB) + { + js.j_previous = candidate; + return; + } + } + + /* If we get here, there is either only one stopped job, in which case it is + 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(js.j_current) is + JSTOPPED. */ + + candidate = RUNNING (js.j_current) ? job_last_running (js.j_current) + : job_last_running (js.j_jobslots); + + if (candidate != NO_JOB) + { + js.j_previous = candidate; + return; + } + + /* There is only a single job, and it is both `+' and `-'. */ + 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 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. */ + +static void +reset_current () +{ + int candidate; + + 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 (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 (js.j_jobslots); + + /* Third choice: the newest running job. */ + if (candidate == NO_JOB) + candidate = job_last_running (js.j_jobslots); + } + + /* If we found a job to use, then use it. Otherwise, there + are no jobs period. */ + if (candidate != NO_JOB) + set_current_job (candidate); + else + js.j_current = js.j_previous = NO_JOB; +} + +/* Set up the job structures so we know the job and its processes are + all running. */ +static void +set_job_running (job) + int job; +{ + register PROCESS *p; + + /* Each member of the pipeline is now running. */ + p = jobs[job]->pipe; + + do + { + if (WIFSTOPPED (p->status)) + p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */ + p = p->next; + } + while (p != jobs[job]->pipe); + + /* This means that the job is running. */ + JOBSTATE (job) = JRUNNING; +} + +/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, + start the job in the background. JOB is a zero-based index into + JOBS. Returns -1 if it is unable to start a job, and the return + status of the job otherwise. */ +int +start_job (job, foreground) + int job, foreground; +{ + register PROCESS *p; + int already_running; + sigset_t set, oset; + char *wd; + static TTYSTRUCT save_stty; + + BLOCK_CHILD (set, oset); + + if (DEADJOB (job)) + { + internal_error (_("%s: job has terminated"), this_command_name); + UNBLOCK_CHILD (oset); + return (-1); + } + + already_running = RUNNING (job); + + if (foreground == 0 && already_running) + { + internal_error (_("%s: job %d already in background"), this_command_name, job + 1); + UNBLOCK_CHILD (oset); + return (-1); + } + + wd = current_working_directory (); + + /* You don't know about the state of this job. Do you? */ + jobs[job]->flags &= ~J_NOTIFIED; + + if (foreground) + { + set_current_job (job); + jobs[job]->flags |= J_FOREGROUND; + } + + /* Tell the outside world what we're doing. */ + p = jobs[job]->pipe; + + if (foreground == 0) + printf ("[%d]%c ", job + 1, + (job == js.j_current) ? '+': ((job == js.j_previous) ? '-' : ' ')); + + do + { + printf ("%s%s", + p->command ? p->command : "", + p->next != jobs[job]->pipe? " | " : ""); + p = p->next; + } + while (p != jobs[job]->pipe); + + if (foreground == 0) + printf (" &"); + + if (strcmp (wd, jobs[job]->wd) != 0) + printf (" (wd: %s)", polite_directory_format (jobs[job]->wd)); + + printf ("\n"); + + /* Run the job. */ + if (already_running == 0) + set_job_running (job); + + /* Save the tty settings before we start the job in the foreground. */ + if (foreground) + { + get_tty_state (); + save_stty = shell_tty_info; + /* Give the terminal to this job. */ + if (IS_JOBCONTROL (job)) + give_terminal_to (jobs[job]->pgrp, 0); + } + else + jobs[job]->flags &= ~J_FOREGROUND; + + /* If the job is already running, then don't bother jump-starting it. */ + if (already_running == 0) + { + jobs[job]->flags |= J_NOTIFIED; + killpg (jobs[job]->pgrp, SIGCONT); + } + + if (foreground) + { + pid_t pid; + int s; + + pid = find_last_pid (job, 0); + UNBLOCK_CHILD (oset); + s = wait_for (pid); + shell_tty_info = save_stty; + set_tty_state (); + return (s); + } + else + { + reset_current (); + UNBLOCK_CHILD (oset); + return (0); + } +} + +/* Give PID SIGNAL. This determines what job the pid belongs to (if any). + If PID does belong to a job, and the job is stopped, then CONTinue the + job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, + then kill the process group associated with PID. */ +int +kill_pid (pid, sig, group) + pid_t pid; + int sig, group; +{ + register PROCESS *p; + int job, result; + sigset_t set, oset; + + result = EXECUTION_SUCCESS; + if (group) + { + BLOCK_CHILD (set, oset); + p = find_pipeline (pid, 0, &job); + + if (job != NO_JOB) + { + jobs[job]->flags &= ~J_NOTIFIED; + + /* Kill process in backquotes or one started without job control? */ + if (jobs[job]->pgrp == shell_pgrp) + { + p = jobs[job]->pipe; + + do + { + kill (p->pid, sig); + if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP)) + kill (p->pid, SIGCONT); + p = p->next; + } + while (p != jobs[job]->pipe); + } + else + { + result = killpg (jobs[job]->pgrp, sig); + if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) + killpg (jobs[job]->pgrp, SIGCONT); + /* If we're continuing a stopped job via kill rather than bg or + fg, emulate the `bg' behavior. */ + if (p && STOPPED (job) && (sig == SIGCONT)) + { + set_job_running (job); + jobs[job]->flags &= ~J_FOREGROUND; + jobs[job]->flags |= J_NOTIFIED; + } + } + } + else + result = killpg (pid, sig); + + UNBLOCK_CHILD (oset); + } + else + result = kill (pid, sig); + + return (result); +} + +/* sigchld_handler () flushes at least one of the children that we are + waiting for. It gets run when we have gotten a SIGCHLD signal. */ +static sighandler +sigchld_handler (sig) + int sig; +{ + int n, oerrno; + + oerrno = errno; + REINSTALL_SIGCHLD_HANDLER; + sigchld++; + n = 0; + if (queue_sigchld == 0) + n = waitchld (-1, 0); + errno = oerrno; + SIGRETURN (n); +} + +/* waitchld() reaps dead or stopped children. It's called by wait_for and + sigchld_handler, and runs until there aren't any children terminating any + more. + If BLOCK is 1, this is to be a blocking wait for a single child, although + an arriving SIGCHLD could cause the wait to be non-blocking. It returns + the number of children reaped, or -1 if there are no unwaited-for child + processes. */ +static int +waitchld (wpid, block) + pid_t wpid; + int block; +{ + WAIT status; + PROCESS *child; + pid_t pid; + int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; + + call_set_current = children_exited = 0; + last_stopped_job = NO_JOB; + + do + { + /* We don't want to be notified about jobs stopping if job control + is not active. XXX - was interactive_shell instead of job_control */ + waitpid_flags = (job_control && subshell_environment == 0) + ? (WUNTRACED|WCONTINUED) + : 0; + if (sigchld || block == 0) + waitpid_flags |= WNOHANG; + pid = WAITPID (-1, &status, waitpid_flags); + + /* The check for WNOHANG is to make sure we decrement sigchld only + if it was non-zero before we called waitpid. */ + if (sigchld > 0 && (waitpid_flags & WNOHANG)) + sigchld--; + + /* If waitpid returns -1 with errno == ECHILD, there are no more + unwaited-for child processes of this shell. */ + if (pid < 0 && errno == ECHILD) + { + if (children_exited == 0) + return -1; + else + break; + } + + /* If waitpid returns 0, there are running children. If it returns -1, + the only other error POSIX says it can return is EINTR. */ + if (pid <= 0) + continue; /* jumps right to the test */ + + /* children_exited is used to run traps on SIGCHLD. We don't want to + run the trap if a process is just being continued. */ + if (WIFCONTINUED(status) == 0) + children_exited++; + + /* Locate our PROCESS for this pid. */ + child = find_pipeline (pid, 1, &job); /* want running procs only */ + + /* It is not an error to have a child terminate that we did + not have a record of. This child could have been part of + a pipeline in backquote substitution. Even so, I'm not + sure child is ever non-zero. */ + if (child == 0) + continue; + + while (child->pid != pid) + child = child->next; + + /* Remember status, and whether or not the process is running. */ + 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; + + call_set_current += set_job_status_and_cleanup (job); + + if (STOPPED (job)) + last_stopped_job = job; + else if (DEADJOB (job) && last_stopped_job == job) + last_stopped_job = NO_JOB; + } + while ((sigchld || block == 0) && pid > (pid_t)0); + + /* If a job was running and became stopped, then set the current + job. Otherwise, don't change a thing. */ + if (call_set_current) + { + if (last_stopped_job != NO_JOB) + set_current_job (last_stopped_job); + else + reset_current (); + } + + /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ + if (job_control && signal_is_trapped (SIGCHLD) && children_exited && + trap_list[SIGCHLD] != (char *)IGNORE_SIG) + run_sigchld_trap (children_exited); + + /* We have successfully recorded the useful information about this process + that has just changed state. If we notify asynchronously, and the job + that this process belongs to is no longer running, then notify the user + of that fact now. */ + if (asynchronous_notification && interactive) + notify_of_job_status (); + + return (children_exited); +} + +/* Set the status of JOB and perform any necessary cleanup if the job is + marked as JDEAD. + + Currently, the cleanup activity is restricted to handling any SIGINT + received while waiting for a foreground job to finish. */ +static int +set_job_status_and_cleanup (job) + int job; +{ + PROCESS *child; + int tstatus, job_state, any_stopped, any_tstped, call_set_current; + SigHandler *temp_handler; + + child = jobs[job]->pipe; + jobs[job]->flags &= ~J_NOTIFIED; + + call_set_current = 0; + + /* + * COMPUTE JOB STATUS + */ + + /* If all children are not running, but any of them is stopped, then + the job is stopped, not dead. */ + job_state = any_stopped = any_tstped = 0; + do + { + job_state |= child->running; + if (child->running == PS_DONE && (WIFSTOPPED (child->status))) + { + any_stopped = 1; + any_tstped |= interactive && job_control && + (WSTOPSIG (child->status) == SIGTSTP); + } + child = child->next; + } + while (child != jobs[job]->pipe); + + /* If job_state != 0, the job is still running, so don't bother with + setting the process exit status and job state unless we're + transitioning from stopped to running. */ + if (job_state != 0 && JOBSTATE(job) != JSTOPPED) + return 0; + + /* + * SET JOB STATUS + */ + + /* The job is either stopped or dead. Set the state of the job accordingly. */ + if (any_stopped) + { + jobs[job]->state = JSTOPPED; + jobs[job]->flags &= ~J_FOREGROUND; + call_set_current++; + /* Suspending a job with SIGTSTP breaks all active loops. */ + if (any_tstped && loop_level) + breaking = loop_level; + } + else if (job_state != 0) /* was stopped, now running */ + { + jobs[job]->state = JRUNNING; + call_set_current++; + } + else + { + jobs[job]->state = JDEAD; +itrace("job %d marked as JDEAD", job); +#if 0 + if (IS_FOREGROUND (job)) + setjstatus (job); +#endif + + /* If this job has a cleanup function associated with it, call it + with `cleanarg' as the single argument, then set the function + pointer to NULL so it is not inadvertently called twice. The + cleanup function is responsible for deallocating cleanarg. */ + if (jobs[job]->j_cleanup) + { + (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); + jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; + } + } + + /* + * CLEANUP + * + * Currently, we just do special things if we got a SIGINT while waiting + * for a foreground job to complete + */ + + if (JOBSTATE (job) == JDEAD) + { + /* If we're running a shell script and we get a SIGINT with a + SIGINT trap handler, but the foreground job handles it and + does not exit due to SIGINT, run the trap handler but do not + otherwise act as if we got the interrupt. */ + if (wait_sigint_received && interactive_shell == 0 && + WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) && + signal_is_trapped (SIGINT)) + { + int old_frozen; + wait_sigint_received = 0; + last_command_exit_value = process_exit_status (child->status); + + old_frozen = jobs_list_frozen; + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = old_frozen; + } + + /* If the foreground job is killed by SIGINT when job control is not + active, we need to perform some special handling. + + The check of wait_sigint_received is a way to determine if the + SIGINT came from the keyboard (in which case the shell has already + seen it, and wait_sigint_received is non-zero, because keyboard + signals are sent to process groups) or via kill(2) to the foreground + process by another process (or itself). If the shell did receive the + SIGINT, it needs to perform normal SIGINT processing. */ + else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) && + IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0) + { + int old_frozen; + + wait_sigint_received = 0; + + /* If SIGINT is trapped, set the exit status so that the trap + handler can see it. */ + if (signal_is_trapped (SIGINT)) + last_command_exit_value = process_exit_status (child->status); + + /* If the signal is trapped, let the trap handler get it no matter + what and simply return if the trap handler returns. + maybe_call_trap_handler() may cause dead jobs to be removed from + the job table because of a call to execute_command. We work + around this by setting JOBS_LIST_FROZEN. */ + old_frozen = jobs_list_frozen; + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = old_frozen; + if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) + { + /* wait_sigint_handler () has already seen SIGINT and + allowed the wait builtin to jump out. We need to + call the original SIGINT handler, if necessary. If + the original handler is SIG_DFL, we need to resend + the signal to ourselves. */ + + temp_handler = old_sigint_handler; + + /* Bogus. If we've reset the signal handler as the result + of a trap caught on SIGINT, then old_sigint_handler + will point to trap_handler, which now knows nothing about + SIGINT (if we reset the sighandler to the default). + In this case, we have to fix things up. What a crock. */ + if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0) + temp_handler = trap_to_sighandler (SIGINT); + restore_sigint_handler (); + if (temp_handler == SIG_DFL) + termination_unwind_protect (SIGINT); + else if (temp_handler != SIG_IGN) + (*temp_handler) (SIGINT); + } + } + } + + return call_set_current; +} + +/* Build the array of values for the $PIPESTATUS variable from the set of + exit statuses of all processes in the job J. */ +static void +setjstatus (j) + int j; +{ +#if defined (ARRAY_VARS) + register int i; + register PROCESS *p; + + for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++) + ; + i++; + if (statsize < i) + { + pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int)); + statsize = i; + } + i = 0; + p = jobs[j]->pipe; + do + { + pstatuses[i++] = process_exit_status (p->status); + p = p->next; + } + while (p != jobs[j]->pipe); + + pstatuses[i] = -1; /* sentinel */ + set_pipestatus_array (pstatuses, i); +#endif +} + +static void +run_sigchld_trap (nchild) + int nchild; +{ + char *trap_command; + int i; + + /* Turn off the trap list during the call to parse_and_execute () + to avoid potentially infinite recursive calls. Preserve the + values of last_command_exit_value, last_made_pid, and the_pipeline + around the execution of the trap commands. */ + trap_command = savestring (trap_list[SIGCHLD]); + + begin_unwind_frame ("SIGCHLD trap"); + unwind_protect_int (last_command_exit_value); + unwind_protect_int (last_command_exit_signal); + unwind_protect_var (last_made_pid); + unwind_protect_int (interrupt_immediately); + unwind_protect_int (jobs_list_frozen); + unwind_protect_pointer (the_pipeline); + unwind_protect_pointer (subst_assign_varlist); + + /* We have to add the commands this way because they will be run + in reverse order of adding. We don't want maybe_set_sigchld_trap () + to reference freed memory. */ + add_unwind_protect (xfree, trap_command); + add_unwind_protect (maybe_set_sigchld_trap, trap_command); + + subst_assign_varlist = (WORD_LIST *)NULL; + the_pipeline = (PROCESS *)NULL; + + restore_default_signal (SIGCHLD); + jobs_list_frozen = 1; + for (i = 0; i < nchild; i++) + { + interrupt_immediately = 1; + parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); + } + + run_unwind_frame ("SIGCHLD trap"); +} + +/* Function to call when you want to notify people of changes + in job status. This prints out all jobs which are pending + notification to stderr, and marks those printed as already + notified, thus making them candidates for cleanup. */ +static void +notify_of_job_status () +{ + register int job, termsig; + char *dir; + sigset_t set, oset; + WAIT s; + + if (jobs == 0 || js.j_jobslots == 0) + return; + + if (old_ttou != 0) + { + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGTTOU); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + } + else + queue_sigchld++; + + /* 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) + { + s = raw_job_exit_status (job); + termsig = WTERMSIG (s); + + /* POSIX.2 says we have to hang onto the statuses of at most the + last CHILD_MAX background processes if the shell is running a + script. If the shell is not interactive, don't print anything + unless the job was killed by a signal. */ + if (startup_state == 0 && WIFSIGNALED (s) == 0 && + ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) + continue; + +#if 0 + /* If job control is disabled, don't print the status messages. + Mark dead jobs as notified so that they get cleaned up. If + startup_state == 2, we were started to run `-c command', so + don't print anything. */ + if ((job_control == 0 && interactive_shell) || startup_state == 2) +#else + /* If job control is disabled, don't print the status messages. + Mark dead jobs as notified so that they get cleaned up. If + startup_state == 2 and subshell_environment has the + SUBSHELL_COMSUB bit turned on, we were started to run a command + substitution, so don't print anything. */ + if ((job_control == 0 && interactive_shell) || + (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB))) +#endif + { + /* POSIX.2 compatibility: if the shell is not interactive, + hang onto the job corresponding to the last asynchronous + pid until the user has been notified of its status or does + a `wait'. */ + if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid))) + jobs[job]->flags |= J_NOTIFIED; + continue; + } + + /* Print info on jobs that are running in the background, + and on foreground jobs that were killed by anything + except SIGINT (and possibly SIGPIPE). */ + switch (JOBSTATE (job)) + { + case JDEAD: + if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && + termsig != SIGINT && +#if defined (DONT_REPORT_SIGPIPE) + termsig != SIGPIPE && +#endif + signal_is_trapped (termsig) == 0) + { + /* Don't print `0' for a line number. */ + fprintf (stderr, "%s: line %d: ", get_name_for_error (), (line_number == 0) ? 1 : line_number); + pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); + } + else if (IS_FOREGROUND (job)) + { +#if !defined (DONT_REPORT_SIGPIPE) + if (termsig && WIFSIGNALED (s) && termsig != SIGINT) +#else + if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE) +#endif + { + fprintf (stderr, "%s", j_strsignal (termsig)); + + if (WIFCORED (s)) + fprintf (stderr, " (core dumped)"); + + fprintf (stderr, "\n"); + } + } + else + { + if (dir == 0) + dir = current_working_directory (); + pretty_print_job (job, JLIST_STANDARD, stderr); + if (dir && strcmp (dir, jobs[job]->wd) != 0) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + } + + jobs[job]->flags |= J_NOTIFIED; + break; + + case JSTOPPED: + fprintf (stderr, "\n"); + if (dir == 0) + dir = current_working_directory (); + pretty_print_job (job, JLIST_STANDARD, stderr); + if (dir && (strcmp (dir, jobs[job]->wd) != 0)) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + jobs[job]->flags |= J_NOTIFIED; + break; + + case JRUNNING: + case JMIXED: + break; + + default: + programming_error ("notify_of_job_status"); + } + } + } + if (old_ttou != 0) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + else + queue_sigchld--; +} + +/* Initialize the job control mechanism, and set up the tty stuff. */ +int +initialize_job_control (force) + int force; +{ + shell_pgrp = getpgid (0); + + if (shell_pgrp == -1) + { + sys_error ("initialize_job_control: getpgrp failed"); + exit (1); + } + + /* We can only have job control if we are interactive. */ + if (interactive == 0) + { + job_control = 0; + original_pgrp = NO_PID; + shell_tty = fileno (stderr); + } + else + { + /* Get our controlling terminal. If job_control is set, or + interactive is set, then this is an interactive shell no + matter where fd 2 is directed. */ + shell_tty = dup (fileno (stderr)); /* fd 2 */ + + shell_tty = move_to_high_fd (shell_tty, 1, -1); + + /* Compensate for a bug in systems that compiled the BSD + rlogind with DEBUG defined, like NeXT and Alliant. */ + if (shell_pgrp == 0) + { + shell_pgrp = getpid (); + setpgid (0, shell_pgrp); + tcsetpgrp (shell_tty, shell_pgrp); + } + + while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1) + { + if (shell_pgrp != terminal_pgrp) + { + SigHandler *ottin; + + ottin = set_signal_handler(SIGTTIN, SIG_DFL); + kill (0, SIGTTIN); + set_signal_handler (SIGTTIN, ottin); + continue; + } + break; + } + + /* Make sure that we are using the new line discipline. */ + if (set_new_line_discipline (shell_tty) < 0) + { + sys_error ("initialize_job_control: line discipline"); + job_control = 0; + } + else + { + original_pgrp = shell_pgrp; + shell_pgrp = getpid (); + + if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) + { + sys_error ("initialize_job_control: setpgid"); + shell_pgrp = original_pgrp; + } + + job_control = 1; + + /* If (and only if) we just set our process group to our pid, + thereby becoming a process group leader, and the terminal + is not in the same process group as our (new) process group, + then set the terminal's process group to our (new) process + group. If that fails, set our process group back to what it + was originally (so we can still read from the terminal) and + turn off job control. */ + if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp) + { + if (give_terminal_to (shell_pgrp, 0) < 0) + { + setpgid (0, original_pgrp); + shell_pgrp = original_pgrp; + job_control = 0; + } + } + } + if (job_control == 0) + internal_error (_("no job control in this shell")); + } + + if (shell_tty != fileno (stderr)) + SET_CLOSE_ON_EXEC (shell_tty); + + set_signal_handler (SIGCHLD, sigchld_handler); + + change_flag ('m', job_control ? '-' : '+'); + + if (interactive) + get_tty_state (); + + return job_control; +} + +#ifdef DEBUG +void +debug_print_pgrps () +{ + itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", + (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); + itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", + shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); +} +#endif + +/* Set the line discipline to the best this system has to offer. + Return -1 if this is not possible. */ +static int +set_new_line_discipline (tty) + int tty; +{ +#if defined (NEW_TTY_DRIVER) + int ldisc; + + if (ioctl (tty, TIOCGETD, &ldisc) < 0) + return (-1); + + if (ldisc != NTTYDISC) + { + ldisc = NTTYDISC; + + if (ioctl (tty, TIOCSETD, &ldisc) < 0) + return (-1); + } + return (0); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) +# if defined (TERMIO_LDISC) && (NTTYDISC) + if (ioctl (tty, TCGETA, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) + return (-1); + } +# endif /* TERMIO_LDISC && NTTYDISC */ + return (0); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (TERMIOS_LDISC) && defined (NTTYDISC) + if (tcgetattr (tty, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + return (-1); + } +# endif /* TERMIOS_LDISC && NTTYDISC */ + return (0); +#endif /* TERMIOS_TTY_DRIVER */ + +#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) + return (-1); +#endif +} + +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static void +get_new_window_size (from_sig) + int from_sig; +{ + struct winsize win; + + if ((ioctl (shell_tty, TIOCGWINSZ, &win) == 0) && + win.ws_row > 0 && win.ws_col > 0) + { +#if defined (aixpc) + shell_tty_info.c_winsize = win; /* structure copying */ +#endif + sh_set_lines_and_columns (win.ws_row, win.ws_col); +#if defined (READLINE) + rl_set_screen_size (win.ws_row, win.ws_col); +#endif + } +} + +static sighandler +sigwinch_sighandler (sig) + int sig; +{ +#if defined (MUST_REINSTALL_SIGHANDLERS) + set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif /* MUST_REINSTALL_SIGHANDLERS */ + get_new_window_size (1); + SIGRETURN (0); +} +#else +static void +get_new_window_size (from_sig) + int from_sig; +{ +} +#endif /* TIOCGWINSZ && SIGWINCH */ + +void +set_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif +} + +void +unset_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + set_signal_handler (SIGWINCH, old_winch); +#endif +} + +/* Setup this shell to handle C-C, etc. */ +void +initialize_job_signals () +{ + if (interactive) + { + set_signal_handler (SIGINT, sigint_sighandler); + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); + set_sigwinch_handler (); + } + else if (job_control) + { + old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler); + old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler); + old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler); + } + /* Leave these things alone for non-interactive shells without job + control. */ +} + +/* Here we handle CONT signals. */ +static sighandler +sigcont_sighandler (sig) + int sig; +{ + initialize_job_signals (); + set_signal_handler (SIGCONT, old_cont); + kill (getpid (), SIGCONT); + + SIGRETURN (0); +} + +/* Here we handle stop signals while we are running not as a login shell. */ +static sighandler +sigstop_sighandler (sig) + int sig; +{ + set_signal_handler (SIGTSTP, old_tstp); + set_signal_handler (SIGTTOU, old_ttou); + set_signal_handler (SIGTTIN, old_ttin); + + old_cont = set_signal_handler (SIGCONT, sigcont_sighandler); + + give_terminal_to (shell_pgrp, 0); + + kill (getpid (), sig); + + SIGRETURN (0); +} + +/* Give the terminal to PGRP. */ +int +give_terminal_to (pgrp, force) + pid_t pgrp; + int force; +{ + sigset_t set, oset; + int r; + + r = 0; + if (job_control || force) + { + sigemptyset (&set); + sigaddset (&set, SIGTTOU); + sigaddset (&set, SIGTTIN); + sigaddset (&set, SIGTSTP); + sigaddset (&set, SIGCHLD); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + if (tcsetpgrp (shell_tty, pgrp) < 0) + { + /* Maybe we should print an error message? */ +#if 0 + sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", + shell_tty, (long)getpid(), (long)pgrp); +#endif + r = -1; + } + else + terminal_pgrp = pgrp; + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return r; +} + +/* Clear out any jobs in the job array. This is intended to be used by + children of the shell, who should not have any job structures as baggage + when they start executing (forking subshells for parenthesized execution + and functions with pipes are the two that spring to mind). If RUNNING_ONLY + is nonzero, only running jobs are removed from the table. */ +void +delete_all_jobs (running_only) + int running_only; +{ + register int i; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + /* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */ + if (js.j_jobslots) + { + js.j_current = js.j_previous = NO_JOB; + + /* 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); + js.j_jobslots = 0; + js.j_firstj = js.j_lastj = js.j_njobs = 0; + } + } + + UNBLOCK_CHILD (oset); +} + +/* Mark all jobs in the job array so that they don't get a SIGHUP when the + shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ +void +nohup_all_jobs (running_only) + int running_only; +{ + register int i; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + if (js.j_jobslots) + { + /* 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); + } + + UNBLOCK_CHILD (oset); +} + +int +count_all_jobs () +{ + int i, n; + sigset_t set, oset; + + /* This really counts all non-dead jobs. */ + BLOCK_CHILD (set, oset); + /* 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; +} + +static void +mark_all_jobs_as_dead () +{ + register int i; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return; + + BLOCK_CHILD (set, oset); + + /* XXX could use js.j_firstj here */ + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i]) + jobs[i]->state = JDEAD; + + UNBLOCK_CHILD (oset); +} + +/* Mark all dead jobs as notified, so delete_job () cleans them out + of the job table properly. POSIX.2 says we need to save the + status of the last CHILD_MAX jobs, so we count the number of dead + jobs and mark only enough as notified to save CHILD_MAX statuses. */ +static void +mark_dead_jobs_as_notified (force) + int force; +{ + register int i, ndead, ndeadproc; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return; + + BLOCK_CHILD (set, oset); + + /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses + around; just run through the array. */ + if (force) + { + /* 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; + } + UNBLOCK_CHILD (oset); + return; + } + + /* 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 */ + /* 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++; + ndeadproc += processes_in_job (i); + } + } + +if (ndeadproc != js.c_reaped) + itrace("mark_dead_jobs_as_notified: ndeadproc (%d) != js.c_reaped (%d)", ndeadproc, js.c_reaped); + if (js.c_childmax < 0) + js.c_childmax = getmaxchild (); + if (js.c_childmax < 0) + js.c_childmax = DEFAULT_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; + } + +itrace("marking up to %d jobs as notified", ndead, ndeadproc); + /* 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. 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))) + { +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); + } + } + + UNBLOCK_CHILD (oset); +} + +/* Here to allow other parts of the shell (like the trap stuff) to + unfreeze the jobs list. */ +void +unfreeze_jobs_list () +{ + jobs_list_frozen = 0; +} + +/* Allow or disallow job control to take place. Returns the old value + of job_control. */ +int +set_job_control (arg) + int arg; +{ + int old; + + old = job_control; + job_control = arg; + + /* If we're turning on job control, reset pipeline_pgrp so make_child will + put new child processes into the right pgrp */ + if (job_control != old && job_control) + pipeline_pgrp = 0; + + return (old); +} + +/* Turn off all traces of job control. This is run by children of the shell + which are going to do shellsy things, like wait (), etc. */ +void +without_job_control () +{ + stop_making_children (); + start_pipeline (); + delete_all_jobs (0); + set_job_control (0); +} + +/* If this shell is interactive, terminate all stopped jobs and + restore the original terminal process group. This is done + before the `exec' builtin calls shell_execve. */ +void +end_job_control () +{ + if (interactive_shell) /* XXX - should it be interactive? */ + { + terminate_stopped_jobs (); + + if (original_pgrp >= 0) + give_terminal_to (original_pgrp, 1); + } + + if (original_pgrp >= 0) + setpgid (0, original_pgrp); +} + +/* Restart job control by closing shell tty and reinitializing. This is + called after an exec fails in an interactive shell and we do not exit. */ +void +restart_job_control () +{ + if (shell_tty != -1) + close (shell_tty); + initialize_job_control (0); +} + +/* Set the handler to run when the shell receives a SIGCHLD signal. */ +void +set_sigchld_handler () +{ + set_signal_handler (SIGCHLD, sigchld_handler); +} + +#if defined (PGRP_PIPE) +/* Read from the read end of a pipe. This is how the process group leader + blocks until all of the processes in a pipeline have been made. */ +static void +pipe_read (pp) + int *pp; +{ + char ch; + + if (pp[1] >= 0) + { + close (pp[1]); + pp[1] = -1; + } + + if (pp[0] >= 0) + { + while (read (pp[0], &ch, 1) == -1 && errno == EINTR) + ; + } +} + +/* Close the read and write ends of PP, an array of file descriptors. */ +static void +pipe_close (pp) + int *pp; +{ + if (pp[0] >= 0) + close (pp[0]); + + if (pp[1] >= 0) + close (pp[1]); + + pp[0] = pp[1] = -1; +} + +/* Functional interface closes our local-to-job-control pipes. */ +void +close_pgrp_pipe () +{ + pipe_close (pgrp_pipe); +} + +#endif /* PGRP_PIPE */ diff --git a/jobs.c.save1 b/jobs.c.save1 new file mode 100644 index 0000000..ddacb0a --- /dev/null +++ b/jobs.c.save1 @@ -0,0 +1,3614 @@ +/* The thing that makes children, remembers them, and contains wait loops. */ + +/* This file works with both POSIX and BSD systems. It implements job + control. */ + +/* Copyright (C) 1989-2005 Free Software Foundation, Inc. + + This file is part of GNU Bash, the Bourne Again SHell. + + Bash is free software; you can redistribute it and/or modify it under + the terms of the GNU General Public License as published by the Free + Software Foundation; either version 2, or (at your option) any later + version. + + Bash is distributed in the hope that it will be useful, but WITHOUT ANY + WARRANTY; without even the implied warranty of MERCHANTABILITY or + FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + for more details. + + You should have received a copy of the GNU General Public License along + with Bash; see the file COPYING. If not, write to the Free Software + Foundation, 59 Temple Place, Suite 330, Boston, MA 02111 USA. */ + +#include "config.h" + +#include "bashtypes.h" +#include "trap.h" +#include +#include +#include + +#if defined (HAVE_UNISTD_H) +# include +#endif + +#include "posixtime.h" + +#if defined (HAVE_SYS_RESOURCE_H) && defined (HAVE_WAIT3) && !defined (_POSIX_VERSION) && !defined (RLIMTYPE) +# include +#endif /* !_POSIX_VERSION && HAVE_SYS_RESOURCE_H && HAVE_WAIT3 && !RLIMTYPE */ + +#if defined (HAVE_SYS_FILE_H) +# include +#endif + +#include "filecntl.h" +#include +#include + +#if defined (BUFFERED_INPUT) +# include "input.h" +#endif + +/* Need to include this up here for *_TTY_DRIVER definitions. */ +#include "shtty.h" + +/* Define this if your output is getting swallowed. It's a no-op on + machines with the termio or termios tty drivers. */ +/* #define DRAIN_OUTPUT */ + +/* For the TIOCGPGRP and TIOCSPGRP ioctl parameters on HP-UX */ +#if defined (hpux) && !defined (TERMIOS_TTY_DRIVER) +# include +#endif /* hpux && !TERMIOS_TTY_DRIVER */ + +#if !defined (STRUCT_WINSIZE_IN_SYS_IOCTL) +/* For struct winsize on SCO */ +/* sys/ptem.h has winsize but needs mblk_t from sys/stream.h */ +# if defined (HAVE_SYS_PTEM_H) && defined (TIOCGWINSZ) && defined (SIGWINCH) +# if defined (HAVE_SYS_STREAM_H) +# include +# endif +# include +# endif /* HAVE_SYS_PTEM_H && TIOCGWINSZ && SIGWINCH */ +#endif /* !STRUCT_WINSIZE_IN_SYS_IOCTL */ + +#include "bashansi.h" +#include "bashintl.h" +#include "shell.h" +#include "jobs.h" +#include "flags.h" + +#include "builtins/builtext.h" +#include "builtins/common.h" + +#if !defined (errno) +extern int errno; +#endif /* !errno */ + +#define DEFAULT_CHILD_MAX 32 +#define MAX_JOBS_IN_ARRAY 4096 /* testing */ + +/* Take care of system dependencies that must be handled when waiting for + children. The arguments to the WAITPID macro match those to the Posix.1 + waitpid() function. */ + +#if defined (ultrix) && defined (mips) && defined (_POSIX_VERSION) +# define WAITPID(pid, statusp, options) \ + wait3 ((union wait *)statusp, options, (struct rusage *)0) +#else +# if defined (_POSIX_VERSION) || defined (HAVE_WAITPID) +# define WAITPID(pid, statusp, options) \ + waitpid ((pid_t)pid, statusp, options) +# else +# if defined (HAVE_WAIT3) +# define WAITPID(pid, statusp, options) \ + wait3 (statusp, options, (struct rusage *)0) +# else +# define WAITPID(pid, statusp, options) \ + wait3 (statusp, options, (int *)0) +# endif /* HAVE_WAIT3 */ +# endif /* !_POSIX_VERSION && !HAVE_WAITPID*/ +#endif /* !(Ultrix && mips && _POSIX_VERSION) */ + +/* getpgrp () varies between systems. Even systems that claim to be + Posix.1 compatible lie sometimes (Ultrix, SunOS4, apollo). */ +#if defined (GETPGRP_VOID) +# define getpgid(p) getpgrp () +#else +# define getpgid(p) getpgrp (p) +#endif /* !GETPGRP_VOID */ + +/* If the system needs it, REINSTALL_SIGCHLD_HANDLER will reinstall the + handler for SIGCHLD. */ +#if defined (MUST_REINSTALL_SIGHANDLERS) +# define REINSTALL_SIGCHLD_HANDLER signal (SIGCHLD, sigchld_handler) +#else +# define REINSTALL_SIGCHLD_HANDLER +#endif /* !MUST_REINSTALL_SIGHANDLERS */ + +/* Some systems let waitpid(2) tell callers about stopped children. */ +#if !defined (WCONTINUED) || defined (WCONTINUED_BROKEN) +# undef WCONTINUED +# define WCONTINUED 0 +#endif +#if !defined (WIFCONTINUED) +# define WIFCONTINUED(s) (0) +#endif + +/* The number of additional slots to allocate when we run out. */ +#define JOB_SLOTS 8 + +typedef int sh_job_map_func_t __P((JOB *, int, int, int)); + +#if defined (READLINE) +extern void rl_set_screen_size __P((int, int)); +#endif + +/* Variables used here but defined in other files. */ +extern int subshell_environment, line_number; +extern int posixly_correct, shell_level; +extern int interrupt_immediately; +extern int last_command_exit_value, last_command_exit_signal; +extern int loop_level, breaking; +extern int sourcelevel; +extern sh_builtin_func_t *this_shell_builtin; +extern char *shell_name, *this_command_name; +extern sigset_t top_level_mask; +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; + +/* The shell's process group. */ +pid_t shell_pgrp = NO_PID; + +/* The terminal's process group. */ +pid_t terminal_pgrp = NO_PID; + +/* The process group of the shell's parent. */ +pid_t original_pgrp = NO_PID; + +/* The process group of the pipeline currently being made. */ +pid_t pipeline_pgrp = (pid_t)0; + +#if defined (PGRP_PIPE) +/* Pipes which each shell uses to communicate with the process group leader + until all of the processes in a pipeline have been started. Then the + process leader is allowed to continue. */ +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; + +/* Pid of the last asynchronous child. */ +pid_t last_asynchronous_pid = NO_PID; + +/* The pipeline currently being built. */ +PROCESS *the_pipeline = (PROCESS *)NULL; + +/* If this is non-zero, do job control. */ +int job_control = 1; + +/* Call this when you start making children. */ +int already_making_children = 0; + +/* If this is non-zero, $LINES and $COLUMNS are reset after every process + exits from get_tty_state(). */ +int check_window_size; + +/* Functions local to this file. */ + +static void get_new_window_size __P((int)); + +static void run_sigchld_trap __P((int)); + +static sighandler wait_sigint_handler __P((int)); +static sighandler sigchld_handler __P((int)); +static sighandler sigwinch_sighandler __P((int)); +static sighandler sigcont_sighandler __P((int)); +static sighandler sigstop_sighandler __P((int)); + +static int waitchld __P((pid_t, int)); + +static PROCESS *find_pipeline __P((pid_t, int, int *)); + +static char *current_working_directory __P((void)); +static char *job_working_directory __P((void)); +static char *j_strsignal __P((int)); +static char *printable_job_status __P((int, PROCESS *, int)); + +static pid_t find_last_pid __P((int, int)); + +static int set_new_line_discipline __P((int)); +static int map_over_jobs __P((sh_job_map_func_t *, int, int)); +static int job_last_stopped __P((int)); +static int job_last_running __P((int)); +static int most_recent_job_in_state __P((int, JOB_STATE)); +static int find_job __P((pid_t, int)); +static int print_job __P((JOB *, int, int, int)); +static int process_exit_status __P((WAIT)); +static int process_exit_signal __P((WAIT)); +static int job_exit_status __P((int)); +static int job_exit_signal __P((int)); +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 cleanup_dead_jobs __P((void)); +static int processes_in_job __P((int)); +static int compact_jobs_list __P((int)); +static void 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 *)); +static void set_current_job __P((int)); +static void reset_current __P((void)); +static void set_job_running __P((int)); +static void setjstatus __P((int)); +static void mark_all_jobs_as_dead __P((void)); +static void mark_dead_jobs_as_notified __P((int)); +static void restore_sigint_handler __P((void)); +#if defined (PGRP_PIPE) +static void pipe_read __P((int *)); +static void pipe_close __P((int *)); +#endif + +#if defined (ARRAY_VARS) +static int *pstatuses; /* list of pipeline statuses */ +static int statsize; +#endif + +/* Used to synchronize between wait_for and other functions and the SIGCHLD + signal handler. */ +static int sigchld; +static int queue_sigchld; + +#define QUEUE_SIGCHLD(os) (os) = sigchld, queue_sigchld++ + +#define UNQUEUE_SIGCHLD(os) \ + do { \ + queue_sigchld--; \ + if (queue_sigchld == 0 && os != sigchld) \ + waitchld (-1, 0); \ + } while (0) + +static SigHandler *old_tstp, *old_ttou, *old_ttin; +static SigHandler *old_cont = (SigHandler *)SIG_DFL; + +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static SigHandler *old_winch = (SigHandler *)SIG_DFL; +#endif + +/* A place to temporarily save the current pipeline. */ +static PROCESS *saved_pipeline; +static int saved_already_making_children; + +/* Set this to non-zero whenever you don't want the jobs list to change at + all: no jobs deleted and no status change notifications. This is used, + for example, when executing SIGCHLD traps, which may run arbitrary + commands. */ +static int jobs_list_frozen; + +static char retcode_name_buffer[64]; + +#if !defined (_POSIX_VERSION) + +/* These are definitions to map POSIX 1003.1 functions onto existing BSD + library functions and system calls. */ +#define setpgid(pid, pgrp) setpgrp (pid, pgrp) +#define tcsetpgrp(fd, pgrp) ioctl ((fd), TIOCSPGRP, &(pgrp)) + +pid_t +tcgetpgrp (fd) + int fd; +{ + pid_t pgrp; + + /* ioctl will handle setting errno correctly. */ + if (ioctl (fd, TIOCGPGRP, &pgrp) < 0) + return (-1); + return (pgrp); +} + +#endif /* !_POSIX_VERSION */ + +/* Return the working directory for the current process. Unlike + job_working_directory, this does not call malloc (), nor do any + of the functions it calls. This is so that it can safely be called + from a signal handler. */ +static char * +current_working_directory () +{ + char *dir; + static char d[PATH_MAX]; + + dir = get_string_value ("PWD"); + + if (dir == 0 && the_current_working_directory && no_symbolic_links) + dir = the_current_working_directory; + + if (dir == 0) + { + dir = getcwd (d, sizeof(d)); + if (dir) + dir = d; + } + + return (dir == 0) ? "" : dir; +} + +/* Return the working directory for the current process. */ +static char * +job_working_directory () +{ + char *dir; + + dir = get_string_value ("PWD"); + if (dir) + return (savestring (dir)); + + dir = get_working_directory ("job-working-directory"); + if (dir) + return (dir); + + return (savestring ("")); +} + +void +making_children () +{ + if (already_making_children) + return; + + already_making_children = 1; + start_pipeline (); +} + +void +stop_making_children () +{ + already_making_children = 0; +} + +void +cleanup_the_pipeline () +{ + if (the_pipeline) + { + discard_pipeline (the_pipeline); + the_pipeline = (PROCESS *)NULL; + } +} + +void +save_pipeline (clear) + int clear; +{ + saved_pipeline = the_pipeline; + saved_already_making_children = already_making_children; + if (clear) + the_pipeline = (PROCESS *)NULL; +} + +void +restore_pipeline (discard) + int discard; +{ + PROCESS *old_pipeline; + + old_pipeline = the_pipeline; + the_pipeline = saved_pipeline; + already_making_children = saved_already_making_children; + if (discard) + discard_pipeline (old_pipeline); +} + +/* Start building a pipeline. */ +void +start_pipeline () +{ + if (the_pipeline) + { + cleanup_the_pipeline (); + pipeline_pgrp = 0; +#if defined (PGRP_PIPE) + pipe_close (pgrp_pipe); +#endif + } + +#if defined (PGRP_PIPE) + if (job_control) + { + if (pipe (pgrp_pipe) == -1) + sys_error ("start_pipeline: pgrp pipe"); + } +#endif +} + +/* Stop building a pipeline. Install the process list in the job array. + This returns the index of the newly installed job. + DEFERRED is a command structure to be executed upon satisfactory + execution exit of this pipeline. */ +int +stop_pipeline (async, deferred) + int async; + COMMAND *deferred; +{ + register int i, j; + JOB *newjob; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + +#if defined (PGRP_PIPE) + /* The parent closes the process group synchronization pipe. */ + pipe_close (pgrp_pipe); +#endif + + cleanup_dead_jobs (); + + if (js.j_jobslots == 0) + { + js.j_jobslots = JOB_SLOTS; + jobs = (JOB **)xmalloc (js.j_jobslots * sizeof (JOB *)); + + /* Now blank out these new entries. */ + 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 */ + if (interactive) + { + 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 < js.j_jobslots; i++) + if (jobs[i] == 0) + break; + } + + /* Do we need more room? */ + + /* First try compaction */ + if (subshell_environment && interactive_shell && i == js.j_jobslots && js.j_jobslots >= MAX_JOBS_IN_ARRAY) + i = compact_jobs_list (0); + + /* If we can't compact, reallocate */ + if (i == js.j_jobslots) + { + js.j_jobslots += JOB_SLOTS; + jobs = (JOB **)xrealloc (jobs, ((1 + js.j_jobslots) * sizeof (JOB *))); + + for (j = i; j < js.j_jobslots; j++) + jobs[j] = (JOB *)NULL; + } + + /* Add the current pipeline to the job list. */ + if (the_pipeline) + { + register PROCESS *p; + int any_alive, any_stopped; + + newjob = (JOB *)xmalloc (sizeof (JOB)); + + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + p->next = (PROCESS *)NULL; + newjob->pipe = REVERSE_LIST (the_pipeline, PROCESS *); + for (p = newjob->pipe; p->next; p = p->next) + ; + p->next = newjob->pipe; + + the_pipeline = (PROCESS *)NULL; + newjob->pgrp = pipeline_pgrp; + pipeline_pgrp = 0; + + newjob->flags = 0; + + /* Flag to see if in another pgrp. */ + if (job_control) + newjob->flags |= J_JOBCONTROL; + + /* Set the state of this pipeline. */ + p = newjob->pipe; + any_alive = any_stopped = 0; + do + { + any_alive |= p->running; + any_stopped |= WIFSTOPPED (p->status); + p = p->next; + } + while (p != newjob->pipe); + + newjob->state = any_alive ? JRUNNING : (any_stopped ? JSTOPPED : JDEAD); + newjob->wd = job_working_directory (); + newjob->deferred = deferred; + + newjob->j_cleanup = (sh_vptrfunc_t *)NULL; + newjob->cleanarg = (PTR_T) NULL; + + jobs[i] = newjob; + if (newjob->state == JDEAD && (newjob->flags & J_FOREGROUND)) + setjstatus (i); + + js.j_lastj = i; + js.j_njobs++; + } + else + newjob = (JOB *)NULL; + + if (async) + { + if (newjob) + newjob->flags &= ~J_FOREGROUND; + reset_current (); + } + else + { + if (newjob) + { + newjob->flags |= J_FOREGROUND; + /* + * !!!!! NOTE !!!!! (chet@ins.cwru.edu) + * + * The currently-accepted job control wisdom says to set the + * terminal's process group n+1 times in an n-step pipeline: + * once in the parent and once in each child. This is where + * the parent gives it away. + * + */ + if (job_control && newjob->pgrp) + give_terminal_to (newjob->pgrp, 0); + } + } + + stop_making_children (); + UNBLOCK_CHILD (oset); + return (js.j_current); +} + +/* Delete all DEAD jobs that the user had received notification about. */ +static void +cleanup_dead_jobs () +{ + register int i; + int os; + + if (js.j_jobslots == 0 || jobs_list_frozen) + return; + + QUEUE_SIGCHLD(os); + + for (i = 0; i < js.j_jobslots; i++) + 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; +} + +/* 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 js.j_jobslots, then + the list needs to be reallocated. The jobs array is in new memory if + this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ + +/* XXX - this needs changes analogous to mark_dead_jobs_as_notified. */ +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 (js.c_childmax < 0) + js.c_childmax = getmaxchild (); + + /* Take out at most a quarter of the jobs in the jobs array, but leave at + least js.c_childmax */ + nremove = js.j_jobslots >> 2; + if ((js.j_jobslots - nremove) < js.c_childmax) + nremove = js.j_jobslots - js.c_childmax; + + /* need to increase jobs list to at least CHILD_MAX entries */ + if (nremove < 0) + return js.j_jobslots; + + BLOCK_CHILD (set, oset); + + for (ndel = i = 0; i < js.j_jobslots; 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 js.j_jobslots; + } + + newlist = (JOB **)xmalloc ((1 + js.j_jobslots) * sizeof (JOB *)); + for (i = j = 0; i < js.j_jobslots; i++) + if (jobs[i]) + newlist[j++] = jobs[i]; + + js.j_lastj = j - 1; + js.j_firstj = 0; + js.j_njobs = j; + + ndel = j; + for ( ; j < js.j_jobslots; j++) + newlist[j] = (JOB *)NULL; + + free (jobs); + jobs = newlist; + + UNBLOCK_CHILD (oset); + + return ndel; +} + +/* Delete the job at INDEX from the job list. Must be called + with SIGCHLD blocked. */ +void +delete_job (job_index, warn_stopped) + int job_index, warn_stopped; +{ + register JOB *temp; + + 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 == js.j_current || job_index == js.j_previous) + reset_current (); + + jobs[job_index] = (JOB *)NULL; + + free (temp->wd); + discard_pipeline (temp->pipe); + + if (temp->deferred) + dispose_command (temp->deferred); + + free (temp); + + js.j_njobs--; +} + +/* Must be called with SIGCHLD blocked. */ +void +nohup_job (job_index) + int job_index; +{ + register JOB *temp; + + if (js.j_jobslots == 0) + return; + + if (temp = jobs[job_index]) + temp->flags |= J_NOHUP; +} + +/* Get rid of the data structure associated with a process chain. */ +static void +discard_pipeline (chain) + register PROCESS *chain; +{ + register PROCESS *this, *next; + + this = chain; + do + { + next = this->next; + FREE (this->command); + free (this); + this = next; + } + while (this != chain); +} + +/* Add this process to the chain being built in the_pipeline. + NAME is the command string that will be exec'ed later. + PID is the process id of the child. */ +static void +add_process (name, pid) + char *name; + pid_t pid; +{ + PROCESS *t, *p; + + t = (PROCESS *)xmalloc (sizeof (PROCESS)); + t->next = the_pipeline; + t->pid = pid; + WSTATUS (t->status) = 0; + t->running = PS_RUNNING; + t->command = name; + the_pipeline = t; + + if (t->next == 0) + t->next = t; + else + { + p = t->next; + while (p->next != t->next) + p = p->next; + p->next = t; + } +} + +#if 0 +/* Take the last job and make it the first job. Must be called with + SIGCHLD blocked. */ +int +rotate_the_pipeline () +{ + PROCESS *p; + + if (the_pipeline->next == the_pipeline) + return; + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + the_pipeline = p; +} + +/* Reverse the order of the processes in the_pipeline. Must be called with + SIGCHLD blocked. */ +int +reverse_the_pipeline () +{ + PROCESS *p, *n; + + if (the_pipeline->next == the_pipeline) + return; + + for (p = the_pipeline; p->next != the_pipeline; p = p->next) + ; + p->next = (PROCESS *)NULL; + + n = REVERSE_LIST (the_pipeline, PROCESS *); + + the_pipeline = n; + for (p = the_pipeline; p->next; p = p->next) + ; + p->next = the_pipeline; +} +#endif + +/* Map FUNC over the list of jobs. If FUNC returns non-zero, + then it is time to stop mapping, and that is the return value + for map_over_jobs. FUNC is called with a JOB, arg1, arg2, + and INDEX. */ +static int +map_over_jobs (func, arg1, arg2) + sh_job_map_func_t *func; + int arg1, arg2; +{ + register int i; + int result; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return 0; + + BLOCK_CHILD (set, oset); + + for (i = result = 0; i < js.j_jobslots; i++) + { + if (jobs[i]) + { + result = (*func)(jobs[i], arg1, arg2, i); + if (result) + break; + } + } + + UNBLOCK_CHILD (oset); + + return (result); +} + +/* Cause all the jobs in the current pipeline to exit. */ +void +terminate_current_pipeline () +{ + if (pipeline_pgrp && pipeline_pgrp != shell_pgrp) + { + killpg (pipeline_pgrp, SIGTERM); + killpg (pipeline_pgrp, SIGCONT); + } +} + +/* Cause all stopped jobs to exit. */ +void +terminate_stopped_jobs () +{ + register int i; + + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i] && STOPPED (i)) + { + killpg (jobs[i]->pgrp, SIGTERM); + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +/* Cause all jobs, running or stopped, to receive a hangup signal. If + a job is marked J_NOHUP, don't send the SIGHUP. */ +void +hangup_all_jobs () +{ + register int i; + + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i]) + { + if ((jobs[i]->flags & J_NOHUP) == 0) + killpg (jobs[i]->pgrp, SIGHUP); + if (STOPPED (i)) + killpg (jobs[i]->pgrp, SIGCONT); + } + } +} + +void +kill_current_pipeline () +{ + stop_making_children (); + start_pipeline (); +} + +/* Return the pipeline that PID belongs to. Note that the pipeline + doesn't have to belong to a job. Must be called with SIGCHLD blocked. */ +static PROCESS * +find_pipeline (pid, running_only, jobp) + pid_t pid; + int running_only; + int *jobp; /* index into jobs list or NO_JOB */ +{ + int job; + register PROCESS *p; + + /* See if this process is in the pipeline that we are building. */ + if (jobp) + *jobp = NO_JOB; + if (the_pipeline) + { + p = the_pipeline; + do + { + /* Return it if we found it. */ + if (p->pid == pid) + { + if ((running_only && PALIVE(p)) || (running_only == 0)) + return (p); + } + + p = p->next; + } + while (p != the_pipeline); + } + + job = find_job (pid, running_only); + if (jobp) + *jobp = job; + return (job == NO_JOB) ? (PROCESS *)NULL : jobs[job]->pipe; +} + +/* Return the job index that PID belongs to, or NO_JOB if it doesn't + belong to any job. Must be called with SIGCHLD blocked. */ +static int +find_job (pid, running_only) + pid_t pid; + int running_only; +{ + register int i; + register PROCESS *p; + + for (i = 0; i < js.j_jobslots; i++) + { + if (jobs[i]) + { + p = jobs[i]->pipe; + + do + { + if (p->pid == pid) + { + if ((running_only && PALIVE(p)) || (running_only == 0)) + return (i); + } + + p = p->next; + } + while (p != jobs[i]->pipe); + } + } + + return (NO_JOB); +} + +/* Find a job given a PID. If BLOCK is non-zero, block SIGCHLD as + required by find_job. */ +int +get_job_by_pid (pid, block) + pid_t pid; + int block; +{ + int job; + sigset_t set, oset; + + if (block) + BLOCK_CHILD (set, oset); + + job = find_job (pid, 0); + + if (block) + UNBLOCK_CHILD (oset); + + return job; +} + +/* Print descriptive information about the job with leader pid PID. */ +void +describe_pid (pid) + pid_t pid; +{ + int job; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + job = find_job (pid, 0); + + if (job != NO_JOB) + fprintf (stderr, "[%d] %ld\n", job + 1, (long)pid); + else + programming_error (_("describe_pid: %ld: no such pid"), (long)pid); + + UNBLOCK_CHILD (oset); +} + +static char * +j_strsignal (s) + int s; +{ + char *x; + + x = strsignal (s); + if (x == 0) + { + x = retcode_name_buffer; + sprintf (x, "Signal %d", s); + } + return x; +} + +static char * +printable_job_status (j, p, format) + int j; + PROCESS *p; + int format; +{ + static char *temp; + int es; + + temp = "Done"; + + if (STOPPED (j) && format == 0) + { + if (posixly_correct == 0 || p == 0 || (WIFSTOPPED (p->status) == 0)) + temp = "Stopped"; + else + { + temp = retcode_name_buffer; + sprintf (temp, "Stopped(%s)", signal_name (WSTOPSIG (p->status))); + } + } + else if (RUNNING (j)) + temp = "Running"; + else + { + if (WIFSTOPPED (p->status)) + temp = j_strsignal (WSTOPSIG (p->status)); + else if (WIFSIGNALED (p->status)) + temp = j_strsignal (WTERMSIG (p->status)); + else if (WIFEXITED (p->status)) + { + temp = retcode_name_buffer; + es = WEXITSTATUS (p->status); + if (es == 0) + strcpy (temp, "Done"); + else if (posixly_correct) + sprintf (temp, "Done(%d)", es); + else + sprintf (temp, "Exit %d", es); + } + else + temp = "Unknown status"; + } + + return temp; +} + +/* This is the way to print out information on a job if you + know the index. FORMAT is: + + JLIST_NORMAL) [1]+ Running emacs + JLIST_LONG ) [1]+ 2378 Running emacs + -1 ) [1]+ 2378 emacs + + JLIST_NORMAL) [1]+ Stopped ls | more + JLIST_LONG ) [1]+ 2369 Stopped ls + 2367 | more + JLIST_PID_ONLY) + Just list the pid of the process group leader (really + the process group). + JLIST_CHANGED_ONLY) + Use format JLIST_NORMAL, but list only jobs about which + the user has not been notified. */ + +/* Print status for pipeline P. If JOB_INDEX is >= 0, it is the index into + the JOBS array corresponding to this pipeline. FORMAT is as described + above. Must be called with SIGCHLD blocked. + + If you're printing a pipeline that's not in the jobs array, like the + current pipeline as it's being created, pass -1 for JOB_INDEX */ +static void +print_pipeline (p, job_index, format, stream) + PROCESS *p; + int job_index, format; + FILE *stream; +{ + PROCESS *first, *last, *show; + int es, name_padding; + char *temp; + + if (p == 0) + return; + + first = last = p; + while (last->next != first) + last = last->next; + + for (;;) + { + if (p != first) + fprintf (stream, format ? " " : " |"); + + if (format != JLIST_STANDARD) + fprintf (stream, "%5ld", (long)p->pid); + + fprintf (stream, " "); + + if (format > -1 && job_index >= 0) + { + show = format ? p : last; + temp = printable_job_status (job_index, show, format); + + if (p != first) + { + if (format) + { + if (show->running == first->running && + WSTATUS (show->status) == WSTATUS (first->status)) + temp = ""; + } + else + temp = (char *)NULL; + } + + if (temp) + { + fprintf (stream, "%s", temp); + + es = STRLEN (temp); + if (es == 0) + es = 2; /* strlen ("| ") */ + name_padding = LONGEST_SIGNAL_DESC - es; + + fprintf (stream, "%*s", name_padding, ""); + + if ((WIFSTOPPED (show->status) == 0) && + (WIFCONTINUED (show->status) == 0) && + WIFCORED (show->status)) + fprintf (stream, "(core dumped) "); + } + } + + if (p != first && format) + fprintf (stream, "| "); + + if (p->command) + fprintf (stream, "%s", p->command); + + if (p == last && job_index >= 0) + { + temp = current_working_directory (); + + if (RUNNING (job_index) && (IS_FOREGROUND (job_index) == 0)) + fprintf (stream, " &"); + + if (strcmp (temp, jobs[job_index]->wd) != 0) + fprintf (stream, + " (wd: %s)", polite_directory_format (jobs[job_index]->wd)); + } + + if (format || (p == last)) + { + /* We need to add a CR only if this is an interactive shell, and + we're reporting the status of a completed job asynchronously. + We can't really check whether this particular job is being + reported asynchronously, so just add the CR if the shell is + currently interactive and asynchronous notification is enabled. */ + if (asynchronous_notification && interactive) + fprintf (stream, "\r\n"); + else + fprintf (stream, "\n"); + } + + if (p == last) + break; + p = p->next; + } + fflush (stream); +} + +/* Print information to STREAM about jobs[JOB_INDEX] according to FORMAT. + Must be called with SIGCHLD blocked or queued with queue_sigchld */ +static void +pretty_print_job (job_index, format, stream) + int job_index, format; + FILE *stream; +{ + register PROCESS *p; + + /* Format only pid information about the process group leader? */ + if (format == JLIST_PID_ONLY) + { + fprintf (stream, "%ld\n", (long)jobs[job_index]->pipe->pid); + return; + } + + if (format == JLIST_CHANGED_ONLY) + { + if (IS_NOTIFIED (job_index)) + return; + format = JLIST_STANDARD; + } + + if (format != JLIST_NONINTERACTIVE) + fprintf (stream, "[%d]%c ", job_index + 1, + (job_index == js.j_current) ? '+': + (job_index == js.j_previous) ? '-' : ' '); + + if (format == JLIST_NONINTERACTIVE) + format = JLIST_LONG; + + p = jobs[job_index]->pipe; + + print_pipeline (p, job_index, format, stream); + + /* We have printed information about this job. When the job's + status changes, waitchld () sets the notification flag to 0. */ + jobs[job_index]->flags |= J_NOTIFIED; +} + +static int +print_job (job, format, state, job_index) + JOB *job; + int format, state, job_index; +{ + if (state == -1 || (JOB_STATE)state == job->state) + pretty_print_job (job_index, format, stdout); + return (0); +} + +void +list_one_job (job, format, ignore, job_index) + JOB *job; + int format, ignore, job_index; +{ + pretty_print_job (job_index, format, stdout); +} + +void +list_stopped_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, (int)JSTOPPED); +} + +void +list_running_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, (int)JRUNNING); +} + +/* List jobs. If FORMAT is non-zero, then the long form of the information + is printed, else just a short version. */ +void +list_all_jobs (format) + int format; +{ + cleanup_dead_jobs (); + map_over_jobs (print_job, format, -1); +} + +/* Fork, handling errors. Returns the pid of the newly made child, or 0. + COMMAND is just for remembering the name of the command; we don't do + anything else with it. ASYNC_P says what to do with the tty. If + non-zero, then don't give it away. */ +pid_t +make_child (command, async_p) + char *command; + int async_p; +{ + sigset_t set, oset; + pid_t pid; + + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGINT); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + making_children (); + +#if defined (BUFFERED_INPUT) + /* If default_buffered_input is active, we are reading a script. If + the command is asynchronous, we have already duplicated /dev/null + as fd 0, but have not changed the buffered stream corresponding to + the old fd 0. We don't want to sync the stream in this case. */ + if (default_buffered_input != -1 && + (!async_p || default_buffered_input > 0)) + sync_buffered_stream (default_buffered_input); +#endif /* BUFFERED_INPUT */ + + /* Create the child, handle severe errors. */ + if ((pid = fork ()) < 0) + { + sys_error ("fork"); + + /* Kill all of the processes in the current pipeline. */ + terminate_current_pipeline (); + + /* Discard the current pipeline, if any. */ + if (the_pipeline) + kill_current_pipeline (); + + throw_to_top_level (); /* Reset signals, etc. */ + } + + if (pid == 0) + { + /* In the child. Give this child the right process group, set the + signals to the default state for a new process. */ + pid_t mypid; + + mypid = getpid (); +#if defined (BUFFERED_INPUT) + /* Close default_buffered_input if it's > 0. We don't close it if it's + 0 because that's the file descriptor used when redirecting input, + and it's wrong to close the file in that case. */ + unset_bash_input (0); +#endif /* BUFFERED_INPUT */ + + /* Restore top-level signal mask. */ + sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); + + if (job_control) + { + /* All processes in this pipeline belong in the same + process group. */ + + if (pipeline_pgrp == 0) /* This is the first child. */ + pipeline_pgrp = mypid; + + /* Check for running command in backquotes. */ + if (pipeline_pgrp == shell_pgrp) + ignore_tty_job_signals (); + else + default_tty_job_signals (); + + /* Set the process group before trying to mess with the terminal's + process group. This is mandated by POSIX. */ + /* This is in accordance with the Posix 1003.1 standard, + section B.7.2.4, which says that trying to set the terminal + process group with tcsetpgrp() to an unused pgrp value (like + this would have for the first child) is an error. Section + B.4.3.3, p. 237 also covers this, in the context of job control + shells. */ + if (setpgid (mypid, pipeline_pgrp) < 0) + sys_error ("child setpgid (%ld to %ld)", (long)mypid, (long)pipeline_pgrp); + + /* By convention (and assumption above), if + pipeline_pgrp == shell_pgrp, we are making a child for + command substitution. + In this case, we don't want to give the terminal to the + shell's process group (we could be in the middle of a + pipeline, for example). */ + if (async_p == 0 && pipeline_pgrp != shell_pgrp) + give_terminal_to (pipeline_pgrp, 0); + +#if defined (PGRP_PIPE) + if (pipeline_pgrp == mypid) + pipe_read (pgrp_pipe); +#endif + } + else /* Without job control... */ + { + if (pipeline_pgrp == 0) + pipeline_pgrp = shell_pgrp; + + /* If these signals are set to SIG_DFL, we encounter the curious + situation of an interactive ^Z to a running process *working* + and stopping the process, but being unable to do anything with + that process to change its state. On the other hand, if they + are set to SIG_IGN, jobs started from scripts do not stop when + the shell running the script gets a SIGTSTP and stops. */ + + default_tty_job_signals (); + } + +#if defined (PGRP_PIPE) + /* Release the process group pipe, since our call to setpgid () + is done. The last call to pipe_close is done in stop_pipeline. */ + pipe_close (pgrp_pipe); +#endif /* PGRP_PIPE */ + + if (async_p) + last_asynchronous_pid = getpid (); + } + else + { + /* In the parent. Remember the pid of the child just created + as the proper pgrp if this is the first child. */ + + if (job_control) + { + if (pipeline_pgrp == 0) + { + pipeline_pgrp = pid; + /* Don't twiddle terminal pgrps in the parent! This is the bug, + not the good thing of twiddling them in the child! */ + /* give_terminal_to (pipeline_pgrp, 0); */ + } + /* This is done on the recommendation of the Rationale section of + the POSIX 1003.1 standard, where it discusses job control and + shells. It is done to avoid possible race conditions. (Ref. + 1003.1 Rationale, section B.4.3.3, page 236). */ + setpgid (pid, pipeline_pgrp); + } + else + { + if (pipeline_pgrp == 0) + pipeline_pgrp = shell_pgrp; + } + + /* Place all processes into the jobs array regardless of the + state of job_control. */ + add_process (command, pid); + + if (async_p) + last_asynchronous_pid = pid; + + 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. */ + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return (pid); +} + +/* These two functions are called only in child processes. */ +void +ignore_tty_job_signals () +{ + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); +} + +void +default_tty_job_signals () +{ + set_signal_handler (SIGTSTP, SIG_DFL); + set_signal_handler (SIGTTIN, SIG_DFL); + set_signal_handler (SIGTTOU, SIG_DFL); +} + +/* When we end a job abnormally, or if we stop a job, we set the tty to the + state kept in here. When a job ends normally, we set the state in here + to the state of the tty. */ + +static TTYSTRUCT shell_tty_info; + +#if defined (NEW_TTY_DRIVER) +static struct tchars shell_tchars; +static struct ltchars shell_ltchars; +#endif /* NEW_TTY_DRIVER */ + +#if defined (NEW_TTY_DRIVER) && defined (DRAIN_OUTPUT) +/* Since the BSD tty driver does not allow us to change the tty modes + while simultaneously waiting for output to drain and preserving + typeahead, we have to drain the output ourselves before calling + ioctl. We cheat by finding the length of the output queue, and + using select to wait for an appropriate length of time. This is + a hack, and should be labeled as such (it's a hastily-adapted + mutation of a `usleep' implementation). It's only reason for + existing is the flaw in the BSD tty driver. */ + +static int ttspeeds[] = +{ + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, + 1800, 2400, 4800, 9600, 19200, 38400 +}; + +static void +draino (fd, ospeed) + int fd, ospeed; +{ + register int delay = ttspeeds[ospeed]; + int n; + + if (!delay) + return; + + while ((ioctl (fd, TIOCOUTQ, &n) == 0) && n) + { + if (n > (delay / 100)) + { + struct timeval tv; + + n *= 10; /* 2 bits more for conservativeness. */ + tv.tv_sec = n / delay; + tv.tv_usec = ((n % delay) * 1000000) / delay; + select (fd, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv); + } + else + break; + } +} +#endif /* NEW_TTY_DRIVER && DRAIN_OUTPUT */ + +/* Return the fd from which we are actually getting input. */ +#define input_tty() (shell_tty != -1) ? shell_tty : fileno (stderr) + +/* Fill the contents of shell_tty_info with the current tty info. */ +int +get_tty_state () +{ + int tty; + + tty = input_tty (); + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) + ioctl (tty, TIOCGETP, &shell_tty_info); + ioctl (tty, TIOCGETC, &shell_tchars); + ioctl (tty, TIOCGLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCGETA, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcgetattr (tty, &shell_tty_info) < 0) + { +#if 0 + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + sys_error ("[%ld: %d] tcgetattr", (long)getpid (), shell_level); +#endif + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + if (check_window_size) + get_new_window_size (0); + } + return 0; +} + +/* Make the current tty use the state in shell_tty_info. */ +int +set_tty_state () +{ + int tty; + + tty = input_tty (); + if (tty != -1) + { +#if defined (NEW_TTY_DRIVER) +# if defined (DRAIN_OUTPUT) + draino (tty, shell_tty_info.sg_ospeed); +# endif /* DRAIN_OUTPUT */ + ioctl (tty, TIOCSETN, &shell_tty_info); + ioctl (tty, TIOCSETC, &shell_tchars); + ioctl (tty, TIOCSLTC, &shell_ltchars); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) + ioctl (tty, TCSETAW, &shell_tty_info); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + { + /* Only print an error message if we're really interactive at + this time. */ + if (interactive) + sys_error ("[%ld: %d] tcsetattr", (long)getpid (), shell_level); + return -1; + } +#endif /* TERMIOS_TTY_DRIVER */ + } + return 0; +} + +/* Given an index into the jobs array JOB, return the pid of the last + process in that job's pipeline. This is the one whose exit status + counts. Must be called with SIGCHLD blocked or queued. */ +static pid_t +find_last_pid (job, block) + int job; + int block; +{ + register PROCESS *p; + sigset_t set, oset; + + if (block) + BLOCK_CHILD (set, oset); + + p = jobs[job]->pipe; + while (p->next != jobs[job]->pipe) + p = p->next; + + if (block) + UNBLOCK_CHILD (oset); + + return (p->pid); +} + +/* Wait for a particular child of the shell to finish executing. + This low-level function prints an error message if PID is not + a child of this shell. It returns -1 if it fails, or whatever + wait_for returns otherwise. If the child is not found in the + jobs table, it returns 127. */ +int +wait_for_single_pid (pid) + pid_t pid; +{ + register PROCESS *child; + sigset_t set, oset; + int r, job; + + BLOCK_CHILD (set, oset); + child = find_pipeline (pid, 0, (int *)NULL); + UNBLOCK_CHILD (oset); + + if (child == 0) + { + internal_error (_("wait: pid %ld is not a child of this shell"), (long)pid); + return (127); + } + + r = wait_for (pid); + + /* POSIX.2: if we just waited for a job, we can remove it from the jobs + table. */ + BLOCK_CHILD (set, oset); + job = find_job (pid, 0); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); + + return r; +} + +/* Wait for all of the backgrounds of this shell to finish. */ +void +wait_for_background_pids () +{ + register int i, r, waited_for; + sigset_t set, oset; + pid_t pid; + + for (waited_for = 0;;) + { + BLOCK_CHILD (set, oset); + + /* find first running job; if none running in foreground, break */ + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0) + break; + + if (i == js.j_jobslots) + { + UNBLOCK_CHILD (oset); + break; + } + + /* now wait for the last pid in that job. */ + pid = find_last_pid (i, 0); + UNBLOCK_CHILD (oset); + QUIT; + errno = 0; /* XXX */ + r = wait_for_single_pid (pid); + if (r == -1) + { + /* If we're mistaken about job state, compensate. */ + if (errno == ECHILD) + mark_all_jobs_as_dead (); + } + else + waited_for++; + } + + /* POSIX.2 says the shell can discard the statuses of all completed jobs if + `wait' is called with no arguments. */ + mark_dead_jobs_as_notified (1); + cleanup_dead_jobs (); +} + +/* Make OLD_SIGINT_HANDLER the SIGINT signal handler. */ +#define INVALID_SIGNAL_HANDLER (SigHandler *)wait_for_background_pids +static SigHandler *old_sigint_handler = INVALID_SIGNAL_HANDLER; + +static void +restore_sigint_handler () +{ + if (old_sigint_handler != INVALID_SIGNAL_HANDLER) + { + set_signal_handler (SIGINT, old_sigint_handler); + old_sigint_handler = INVALID_SIGNAL_HANDLER; + } +} + +static int wait_sigint_received; + +/* Handle SIGINT while we are waiting for children in a script to exit. + The `wait' builtin should be interruptible, but all others should be + effectively ignored (i.e. not cause the shell to exit). */ +static sighandler +wait_sigint_handler (sig) + int sig; +{ + SigHandler *sigint_handler; + + if (interrupt_immediately || + (this_shell_builtin && this_shell_builtin == wait_builtin)) + { + last_command_exit_value = EXECUTION_FAILURE; + restore_sigint_handler (); + /* If we got a SIGINT while in `wait', and SIGINT is trapped, do + what POSIX.2 says (see builtins/wait.def for more info). */ + if (this_shell_builtin && this_shell_builtin == wait_builtin && + signal_is_trapped (SIGINT) && + ((sigint_handler = trap_to_sighandler (SIGINT)) == trap_handler)) + { + interrupt_immediately = 0; + trap_handler (SIGINT); /* set pending_traps[SIGINT] */ + wait_signal_received = SIGINT; + longjmp (wait_intr_buf, 1); + } + + ADDINTERRUPT; + QUIT; + } + + /* XXX - should this be interrupt_state? If it is, the shell will act + as if it got the SIGINT interrupt. */ + wait_sigint_received = 1; + + /* Otherwise effectively ignore the SIGINT and allow the running job to + be killed. */ + SIGRETURN (0); +} + +static int +process_exit_signal (status) + WAIT status; +{ + return (WIFSIGNALED (status) ? WTERMSIG (status) : 0); +} + +static int +process_exit_status (status) + WAIT status; +{ + if (WIFSIGNALED (status)) + return (128 + WTERMSIG (status)); + else if (WIFSTOPPED (status) == 0) + return (WEXITSTATUS (status)); + else + return (EXECUTION_SUCCESS); +} + +/* Return the exit status of the last process in the pipeline for job JOB. + This is the exit status of the entire job. */ +static WAIT +raw_job_exit_status (job) + int job; +{ + register PROCESS *p; + int fail; + + if (pipefail_opt) + { + fail = 0; + p = jobs[job]->pipe; + do + { + if (p->status != EXECUTION_SUCCESS) fail = p->status; + p = p->next; + } + while (p != jobs[job]->pipe); + return fail; + } + + for (p = jobs[job]->pipe; p->next != jobs[job]->pipe; p = p->next) + ; + return (p->status); +} + +/* Return the exit status of job JOB. This is the exit status of the last + (rightmost) process in the job's pipeline, modified if the job was killed + by a signal or stopped. */ +static int +job_exit_status (job) + int job; +{ + return (process_exit_status (raw_job_exit_status (job))); +} + +static int +job_exit_signal (job) + int job; +{ + return (process_exit_signal (raw_job_exit_status (job))); +} + +#define FIND_CHILD(pid, child) \ + do \ + { \ + child = find_pipeline (pid, 0, (int *)NULL); \ + if (child == 0) \ + { \ + give_terminal_to (shell_pgrp, 0); \ + UNBLOCK_CHILD (oset); \ + internal_error (_("wait_for: No record of process %ld"), (long)pid); \ + restore_sigint_handler (); \ + return (termination_state = 127); \ + } \ + } \ + while (0) + +/* Wait for pid (one of our children) to terminate, then + return the termination state. Returns 127 if PID is not found in + the jobs table. Returns -1 if waitchld() returns -1, indicating + that there are no unwaited-for child processes. */ +int +wait_for (pid) + pid_t pid; +{ + int job, termination_state, r; + WAIT s; + register PROCESS *child; + sigset_t set, oset; + register PROCESS *p; + + /* In the case that this code is interrupted, and we longjmp () out of it, + we are relying on the code in throw_to_top_level () to restore the + top-level signal mask. */ + BLOCK_CHILD (set, oset); + + /* Ignore interrupts while waiting for a job run without job control + to finish. We don't want the shell to exit if an interrupt is + received, only if one of the jobs run is killed via SIGINT. If + job control is not set, the job will be run in the same pgrp as + the shell, and the shell will see any signals the job gets. */ + + /* This is possibly a race condition -- should it go in stop_pipeline? */ + wait_sigint_received = 0; + if (job_control == 0) + old_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler); + + termination_state = last_command_exit_value; + + if (interactive && job_control == 0) + QUIT; + + /* If we say wait_for (), then we have a record of this child somewhere. + If it and none of its peers are running, don't call waitchld(). */ + + job = NO_JOB; + do + { + FIND_CHILD (pid, child); + + /* If this child is part of a job, then we are really waiting for the + job to finish. Otherwise, we are waiting for the child to finish. + We check for JDEAD in case the job state has been set by waitchld + after receipt of a SIGCHLD. */ + if (job == NO_JOB) + job = find_job (pid, 0); + + /* waitchld() takes care of setting the state of the job. If the job + has already exited before this is called, sigchld_handler will have + called waitchld and the state will be set to JDEAD. */ + + if (child->running || (job != NO_JOB && RUNNING (job))) + { +#if defined (WAITPID_BROKEN) /* SCOv4 */ + sigset_t suspend_set; + sigemptyset (&suspend_set); + sigsuspend (&suspend_set); +#else /* !WAITPID_BROKEN */ +# if defined (MUST_UNBLOCK_CHLD) + struct sigaction act, oact; + sigset_t nullset, chldset; + + sigemptyset (&nullset); + sigemptyset (&chldset); + sigprocmask (SIG_SETMASK, &nullset, &chldset); + act.sa_handler = SIG_DFL; + sigemptyset (&act.sa_mask); + sigemptyset (&oact.sa_mask); + act.sa_flags = 0; + sigaction (SIGCHLD, &act, &oact); +# endif + queue_sigchld = 1; + r = waitchld (pid, 1); +# if defined (MUST_UNBLOCK_CHLD) + sigaction (SIGCHLD, &oact, (struct sigaction *)NULL); + sigprocmask (SIG_SETMASK, &chldset, (sigset_t *)NULL); +# endif + queue_sigchld = 0; + if (r == -1 && errno == ECHILD && this_shell_builtin == wait_builtin) + { + termination_state = -1; + goto wait_for_return; + } + + /* If child is marked as running, but waitpid() returns -1/ECHILD, + there is something wrong. Somewhere, wait should have returned + that child's pid. Mark the child as not running and the job, + if it exists, as JDEAD. */ + if (r == -1 && errno == ECHILD) + { + child->running = PS_DONE; + child->status = 0; /* XXX -- can't find true status */ + if (job != NO_JOB) + jobs[job]->state = JDEAD; + } +#endif /* WAITPID_BROKEN */ + } + + /* If the shell is interactive, and job control is disabled, see + if the foreground process has died due to SIGINT and jump out + of the wait loop if it has. waitchld has already restored the + old SIGINT signal handler. */ + if (interactive && job_control == 0) + QUIT; + } + while (child->running || (job != NO_JOB && RUNNING (job))); + + /* The exit state of the command is either the termination state of the + child, or the termination state of the job. If a job, the status + of the last child in the pipeline is the significant one. If the command + or job was terminated by a signal, note that value also. */ + termination_state = (job != NO_JOB) ? job_exit_status (job) + : process_exit_status (child->status); + 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); + + if (job == NO_JOB || IS_JOBCONTROL (job)) + { + /* XXX - under what circumstances is a job not present in the jobs + table (job == NO_JOB)? + 1. command substitution + + In the case of command substitution, at least, it's probably not + the right thing to give the terminal to the shell's process group, + even though there is code in subst.c:command_substitute to work + around it. + + Things that don't: + $PROMPT_COMMAND execution + process substitution + */ +#if 0 +if (job == NO_JOB) + itrace("wait_for: job == NO_JOB, giving the terminal to shell_pgrp (%ld)", (long)shell_pgrp); +#endif + + give_terminal_to (shell_pgrp, 0); + } + + /* If the command did not exit cleanly, or the job is just + being stopped, then reset the tty state back to what it + was before this command. Reset the tty state and notify + the user of the job termination only if the shell is + interactive. Clean up any dead jobs in either case. */ + if (job != NO_JOB) + { + if (interactive_shell && subshell_environment == 0) + { + /* This used to use `child->status'. That's wrong, however, for + pipelines. `child' is the first process in the pipeline. It's + likely that the process we want to check for abnormal termination + or stopping is the last process in the pipeline, especially if + it's long-lived and the first process is short-lived. Since we + know we have a job here, we can check all the processes in this + job's pipeline and see if one of them stopped or terminated due + to a signal. We might want to change this later to just check + the last process in the pipeline. If no process exits due to a + signal, S is left as the status of the last job in the pipeline. */ + p = jobs[job]->pipe; + do + { + s = p->status; + if (WIFSIGNALED(s) || WIFSTOPPED(s)) + break; + p = p->next; + } + while (p != jobs[job]->pipe); + + if (WIFSIGNALED (s) || WIFSTOPPED (s)) + { + set_tty_state (); + + /* 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 == js.j_current || IS_FOREGROUND (job))) + get_new_window_size (0); + } + else + get_tty_state (); + + /* If job control is enabled, the job was started with job + control, the job was the foreground job, and it was killed + by SIGINT, then print a newline to compensate for the kernel + printing the ^C without a trailing newline. */ + if (job_control && IS_JOBCONTROL (job) && IS_FOREGROUND (job) && + WIFSIGNALED (s) && WTERMSIG (s) == SIGINT) + { + /* If SIGINT is not trapped and the shell is in a for, while, + or until loop, act as if the shell received SIGINT as + well, so the loop can be broken. This doesn't call the + SIGINT signal handler; maybe it should. */ + if (signal_is_trapped (SIGINT) == 0 && loop_level) + ADDINTERRUPT; + else + { + putchar ('\n'); + fflush (stdout); + } + } + } + + /* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD + signal handler path */ + if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/) + setjstatus (job); + + /* If this job is dead, notify the user of the status. If the shell + is interactive, this will display a message on the terminal. If + the shell is not interactive, make sure we turn on the notify bit + so we don't get an unwanted message about the job's termination, + and so delete_job really clears the slot in the jobs table. */ + notify_and_cleanup (); + } + +wait_for_return: + + UNBLOCK_CHILD (oset); + + /* Restore the original SIGINT signal handler before we return. */ + restore_sigint_handler (); + + return (termination_state); +} + +/* Wait for the last process in the pipeline for JOB. Returns whatever + wait_for returns: the last process's termination state or -1 if there + are no unwaited-for child processes or an error occurs. */ +int +wait_for_job (job) + int job; +{ + pid_t pid; + int r; + sigset_t set, oset; + + BLOCK_CHILD(set, oset); + if (JOBSTATE (job) == JSTOPPED) + internal_warning (_("wait_for_job: job %d is stopped"), job+1); + + pid = find_last_pid (job, 0); + UNBLOCK_CHILD(oset); + r = wait_for (pid); + + /* POSIX.2: we can remove the job from the jobs table if we just waited + for it. */ + BLOCK_CHILD (set, oset); + if (job != NO_JOB && jobs[job] && DEADJOB (job)) + jobs[job]->flags |= J_NOTIFIED; + UNBLOCK_CHILD (oset); + + return r; +} + +/* Print info about dead jobs, and then delete them from the list + of known jobs. This does not actually delete jobs when the + shell is not interactive, because the dead jobs are not marked + as notified. */ +void +notify_and_cleanup () +{ + if (jobs_list_frozen) + return; + + if (interactive || interactive_shell == 0 || sourcelevel) + notify_of_job_status (); + + cleanup_dead_jobs (); +} + +/* Make dead jobs disappear from the jobs array without notification. + This is used when the shell is not interactive. */ +void +reap_dead_jobs () +{ + mark_dead_jobs_as_notified (0); + cleanup_dead_jobs (); +} + +/* Return the next closest (chronologically) job to JOB which is in + STATE. STATE can be JSTOPPED, JRUNNING. NO_JOB is returned if + there is no next recent job. */ +static int +most_recent_job_in_state (job, state) + int job; + JOB_STATE state; +{ + register int i, result; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + for (result = NO_JOB, i = job - 1; i >= 0; i--) + { + if (jobs[i] && (JOBSTATE (i) == state)) + { + result = i; + break; + } + } + + UNBLOCK_CHILD (oset); + + return (result); +} + +/* Return the newest *stopped* job older than JOB, or NO_JOB if not + found. */ +static int +job_last_stopped (job) + int job; +{ + return (most_recent_job_in_state (job, JSTOPPED)); +} + +/* Return the newest *running* job older than JOB, or NO_JOB if not + found. */ +static int +job_last_running (job) + int job; +{ + return (most_recent_job_in_state (job, JRUNNING)); +} + +/* Make JOB be the current job, and make previous be useful. Must be + called with SIGCHLD blocked. */ +static void +set_current_job (job) + int job; +{ + int candidate; + + if (js.j_current != job) + { + js.j_previous = js.j_current; + js.j_current = 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 (js.j_current)) + { + candidate = job_last_stopped (js.j_current); + + if (candidate != NO_JOB) + { + js.j_previous = candidate; + return; + } + } + + /* If we get here, there is either only one stopped job, in which case it is + 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(js.j_current) is + JSTOPPED. */ + + candidate = RUNNING (js.j_current) ? job_last_running (js.j_current) + : job_last_running (js.j_jobslots); + + if (candidate != NO_JOB) + { + js.j_previous = candidate; + return; + } + + /* There is only a single job, and it is both `+' and `-'. */ + 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 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. */ + +static void +reset_current () +{ + int candidate; + + 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 (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 (js.j_jobslots); + + /* Third choice: the newest running job. */ + if (candidate == NO_JOB) + candidate = job_last_running (js.j_jobslots); + } + + /* If we found a job to use, then use it. Otherwise, there + are no jobs period. */ + if (candidate != NO_JOB) + set_current_job (candidate); + else + js.j_current = js.j_previous = NO_JOB; +} + +/* Set up the job structures so we know the job and its processes are + all running. */ +static void +set_job_running (job) + int job; +{ + register PROCESS *p; + + /* Each member of the pipeline is now running. */ + p = jobs[job]->pipe; + + do + { + if (WIFSTOPPED (p->status)) + p->running = PS_RUNNING; /* XXX - could be PS_STOPPED */ + p = p->next; + } + while (p != jobs[job]->pipe); + + /* This means that the job is running. */ + JOBSTATE (job) = JRUNNING; +} + +/* Start a job. FOREGROUND if non-zero says to do that. Otherwise, + start the job in the background. JOB is a zero-based index into + JOBS. Returns -1 if it is unable to start a job, and the return + status of the job otherwise. */ +int +start_job (job, foreground) + int job, foreground; +{ + register PROCESS *p; + int already_running; + sigset_t set, oset; + char *wd; + static TTYSTRUCT save_stty; + + BLOCK_CHILD (set, oset); + + if (DEADJOB (job)) + { + internal_error (_("%s: job has terminated"), this_command_name); + UNBLOCK_CHILD (oset); + return (-1); + } + + already_running = RUNNING (job); + + if (foreground == 0 && already_running) + { + internal_error (_("%s: job %d already in background"), this_command_name, job + 1); + UNBLOCK_CHILD (oset); + return (-1); + } + + wd = current_working_directory (); + + /* You don't know about the state of this job. Do you? */ + jobs[job]->flags &= ~J_NOTIFIED; + + if (foreground) + { + set_current_job (job); + jobs[job]->flags |= J_FOREGROUND; + } + + /* Tell the outside world what we're doing. */ + p = jobs[job]->pipe; + + if (foreground == 0) + printf ("[%d]%c ", job + 1, + (job == js.j_current) ? '+': ((job == js.j_previous) ? '-' : ' ')); + + do + { + printf ("%s%s", + p->command ? p->command : "", + p->next != jobs[job]->pipe? " | " : ""); + p = p->next; + } + while (p != jobs[job]->pipe); + + if (foreground == 0) + printf (" &"); + + if (strcmp (wd, jobs[job]->wd) != 0) + printf (" (wd: %s)", polite_directory_format (jobs[job]->wd)); + + printf ("\n"); + + /* Run the job. */ + if (already_running == 0) + set_job_running (job); + + /* Save the tty settings before we start the job in the foreground. */ + if (foreground) + { + get_tty_state (); + save_stty = shell_tty_info; + /* Give the terminal to this job. */ + if (IS_JOBCONTROL (job)) + give_terminal_to (jobs[job]->pgrp, 0); + } + else + jobs[job]->flags &= ~J_FOREGROUND; + + /* If the job is already running, then don't bother jump-starting it. */ + if (already_running == 0) + { + jobs[job]->flags |= J_NOTIFIED; + killpg (jobs[job]->pgrp, SIGCONT); + } + + if (foreground) + { + pid_t pid; + int s; + + pid = find_last_pid (job, 0); + UNBLOCK_CHILD (oset); + s = wait_for (pid); + shell_tty_info = save_stty; + set_tty_state (); + return (s); + } + else + { + reset_current (); + UNBLOCK_CHILD (oset); + return (0); + } +} + +/* Give PID SIGNAL. This determines what job the pid belongs to (if any). + If PID does belong to a job, and the job is stopped, then CONTinue the + job after giving it SIGNAL. Returns -1 on failure. If GROUP is non-null, + then kill the process group associated with PID. */ +int +kill_pid (pid, sig, group) + pid_t pid; + int sig, group; +{ + register PROCESS *p; + int job, result; + sigset_t set, oset; + + result = EXECUTION_SUCCESS; + if (group) + { + BLOCK_CHILD (set, oset); + p = find_pipeline (pid, 0, &job); + + if (job != NO_JOB) + { + jobs[job]->flags &= ~J_NOTIFIED; + + /* Kill process in backquotes or one started without job control? */ + if (jobs[job]->pgrp == shell_pgrp) + { + p = jobs[job]->pipe; + + do + { + kill (p->pid, sig); + if (p->running == PS_DONE && (sig == SIGTERM || sig == SIGHUP)) + kill (p->pid, SIGCONT); + p = p->next; + } + while (p != jobs[job]->pipe); + } + else + { + result = killpg (jobs[job]->pgrp, sig); + if (p && STOPPED (job) && (sig == SIGTERM || sig == SIGHUP)) + killpg (jobs[job]->pgrp, SIGCONT); + /* If we're continuing a stopped job via kill rather than bg or + fg, emulate the `bg' behavior. */ + if (p && STOPPED (job) && (sig == SIGCONT)) + { + set_job_running (job); + jobs[job]->flags &= ~J_FOREGROUND; + jobs[job]->flags |= J_NOTIFIED; + } + } + } + else + result = killpg (pid, sig); + + UNBLOCK_CHILD (oset); + } + else + result = kill (pid, sig); + + return (result); +} + +/* sigchld_handler () flushes at least one of the children that we are + waiting for. It gets run when we have gotten a SIGCHLD signal. */ +static sighandler +sigchld_handler (sig) + int sig; +{ + int n, oerrno; + + oerrno = errno; + REINSTALL_SIGCHLD_HANDLER; + sigchld++; +itrace("sigchld_handler: sigchld = %d", sigchld); + n = 0; + if (queue_sigchld == 0) + n = waitchld (-1, 0); + errno = oerrno; + SIGRETURN (n); +} + +/* waitchld() reaps dead or stopped children. It's called by wait_for and + sigchld_handler, and runs until there aren't any children terminating any + more. + If BLOCK is 1, this is to be a blocking wait for a single child, although + an arriving SIGCHLD could cause the wait to be non-blocking. It returns + the number of children reaped, or -1 if there are no unwaited-for child + processes. */ +static int +waitchld (wpid, block) + pid_t wpid; + int block; +{ + WAIT status; + PROCESS *child; + pid_t pid; + int call_set_current, last_stopped_job, job, children_exited, waitpid_flags; + + call_set_current = children_exited = 0; + last_stopped_job = NO_JOB; + + do + { + /* We don't want to be notified about jobs stopping if job control + is not active. XXX - was interactive_shell instead of job_control */ + waitpid_flags = (job_control && subshell_environment == 0) + ? (WUNTRACED|WCONTINUED) + : 0; + if (sigchld || block == 0) + waitpid_flags |= WNOHANG; + pid = WAITPID (-1, &status, waitpid_flags); + + /* The check for WNOHANG is to make sure we decrement sigchld only + if it was non-zero before we called waitpid. */ + if (sigchld > 0 && (waitpid_flags & WNOHANG)) + sigchld--; + + /* If waitpid returns -1 with errno == ECHILD, there are no more + unwaited-for child processes of this shell. */ + if (pid < 0 && errno == ECHILD) + { + if (children_exited == 0) + return -1; + else + break; + } + + /* If waitpid returns 0, there are running children. If it returns -1, + the only other error POSIX says it can return is EINTR. */ + if (pid <= 0) + continue; /* jumps right to the test */ + + /* children_exited is used to run traps on SIGCHLD. We don't want to + run the trap if a process is just being continued. */ + if (WIFCONTINUED(status) == 0) + children_exited++; + + /* Locate our PROCESS for this pid. */ + child = find_pipeline (pid, 1, &job); /* want running procs only */ + + /* It is not an error to have a child terminate that we did + not have a record of. This child could have been part of + a pipeline in backquote substitution. Even so, I'm not + sure child is ever non-zero. */ + if (child == 0) + continue; + + while (child->pid != pid) + child = child->next; + + /* Remember status, and whether or not the process is running. */ + child->status = status; + child->running = WIFCONTINUED(status) ? PS_RUNNING : PS_DONE; + + if (child->running == PS_DONE) + { + js.c_reaped++; + js.c_totreaped++; + } + + if (job == NO_JOB) + continue; + + call_set_current += set_job_status_and_cleanup (job); + + if (STOPPED (job)) + last_stopped_job = job; + else if (DEADJOB (job) && last_stopped_job == job) + last_stopped_job = NO_JOB; + } + while ((sigchld || block == 0) && pid > (pid_t)0); + + /* If a job was running and became stopped, then set the current + job. Otherwise, don't change a thing. */ + if (call_set_current) + { + if (last_stopped_job != NO_JOB) + set_current_job (last_stopped_job); + else + reset_current (); + } + + /* Call a SIGCHLD trap handler for each child that exits, if one is set. */ + if (job_control && signal_is_trapped (SIGCHLD) && children_exited && + trap_list[SIGCHLD] != (char *)IGNORE_SIG) + run_sigchld_trap (children_exited); + + /* We have successfully recorded the useful information about this process + that has just changed state. If we notify asynchronously, and the job + that this process belongs to is no longer running, then notify the user + of that fact now. */ + if (asynchronous_notification && interactive) + notify_of_job_status (); + + return (children_exited); +} + +/* Set the status of JOB and perform any necessary cleanup if the job is + marked as JDEAD. + + Currently, the cleanup activity is restricted to handling any SIGINT + received while waiting for a foreground job to finish. */ +static int +set_job_status_and_cleanup (job) + int job; +{ + PROCESS *child; + int tstatus, job_state, any_stopped, any_tstped, call_set_current; + SigHandler *temp_handler; + + child = jobs[job]->pipe; + jobs[job]->flags &= ~J_NOTIFIED; + + call_set_current = 0; + + /* + * COMPUTE JOB STATUS + */ + + /* If all children are not running, but any of them is stopped, then + the job is stopped, not dead. */ + job_state = any_stopped = any_tstped = 0; + do + { + job_state |= child->running; + if (child->running == PS_DONE && (WIFSTOPPED (child->status))) + { + any_stopped = 1; + any_tstped |= interactive && job_control && + (WSTOPSIG (child->status) == SIGTSTP); + } + child = child->next; + } + while (child != jobs[job]->pipe); + + /* If job_state != 0, the job is still running, so don't bother with + setting the process exit status and job state unless we're + transitioning from stopped to running. */ + if (job_state != 0 && JOBSTATE(job) != JSTOPPED) + return 0; + + /* + * SET JOB STATUS + */ + + /* The job is either stopped or dead. Set the state of the job accordingly. */ + if (any_stopped) + { + jobs[job]->state = JSTOPPED; + jobs[job]->flags &= ~J_FOREGROUND; + call_set_current++; + /* Suspending a job with SIGTSTP breaks all active loops. */ + if (any_tstped && loop_level) + breaking = loop_level; + } + else if (job_state != 0) /* was stopped, now running */ + { + jobs[job]->state = JRUNNING; + call_set_current++; + } + else + { + jobs[job]->state = JDEAD; +itrace("job %d marked as JDEAD", job); +#if 0 + if (IS_FOREGROUND (job)) + setjstatus (job); +#endif + + /* If this job has a cleanup function associated with it, call it + with `cleanarg' as the single argument, then set the function + pointer to NULL so it is not inadvertently called twice. The + cleanup function is responsible for deallocating cleanarg. */ + if (jobs[job]->j_cleanup) + { + (*jobs[job]->j_cleanup) (jobs[job]->cleanarg); + jobs[job]->j_cleanup = (sh_vptrfunc_t *)NULL; + } + } + + /* + * CLEANUP + * + * Currently, we just do special things if we got a SIGINT while waiting + * for a foreground job to complete + */ + + if (JOBSTATE (job) == JDEAD) + { + /* If we're running a shell script and we get a SIGINT with a + SIGINT trap handler, but the foreground job handles it and + does not exit due to SIGINT, run the trap handler but do not + otherwise act as if we got the interrupt. */ + if (wait_sigint_received && interactive_shell == 0 && + WIFSIGNALED (child->status) == 0 && IS_FOREGROUND (job) && + signal_is_trapped (SIGINT)) + { + int old_frozen; + wait_sigint_received = 0; + last_command_exit_value = process_exit_status (child->status); + + old_frozen = jobs_list_frozen; + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = old_frozen; + } + + /* If the foreground job is killed by SIGINT when job control is not + active, we need to perform some special handling. + + The check of wait_sigint_received is a way to determine if the + SIGINT came from the keyboard (in which case the shell has already + seen it, and wait_sigint_received is non-zero, because keyboard + signals are sent to process groups) or via kill(2) to the foreground + process by another process (or itself). If the shell did receive the + SIGINT, it needs to perform normal SIGINT processing. */ + else if (wait_sigint_received && (WTERMSIG (child->status) == SIGINT) && + IS_FOREGROUND (job) && IS_JOBCONTROL (job) == 0) + { + int old_frozen; + + wait_sigint_received = 0; + + /* If SIGINT is trapped, set the exit status so that the trap + handler can see it. */ + if (signal_is_trapped (SIGINT)) + last_command_exit_value = process_exit_status (child->status); + + /* If the signal is trapped, let the trap handler get it no matter + what and simply return if the trap handler returns. + maybe_call_trap_handler() may cause dead jobs to be removed from + the job table because of a call to execute_command. We work + around this by setting JOBS_LIST_FROZEN. */ + old_frozen = jobs_list_frozen; + jobs_list_frozen = 1; + tstatus = maybe_call_trap_handler (SIGINT); + jobs_list_frozen = old_frozen; + if (tstatus == 0 && old_sigint_handler != INVALID_SIGNAL_HANDLER) + { + /* wait_sigint_handler () has already seen SIGINT and + allowed the wait builtin to jump out. We need to + call the original SIGINT handler, if necessary. If + the original handler is SIG_DFL, we need to resend + the signal to ourselves. */ + + temp_handler = old_sigint_handler; + + /* Bogus. If we've reset the signal handler as the result + of a trap caught on SIGINT, then old_sigint_handler + will point to trap_handler, which now knows nothing about + SIGINT (if we reset the sighandler to the default). + In this case, we have to fix things up. What a crock. */ + if (temp_handler == trap_handler && signal_is_trapped (SIGINT) == 0) + temp_handler = trap_to_sighandler (SIGINT); + restore_sigint_handler (); + if (temp_handler == SIG_DFL) + termination_unwind_protect (SIGINT); + else if (temp_handler != SIG_IGN) + (*temp_handler) (SIGINT); + } + } + } + + return call_set_current; +} + +/* Build the array of values for the $PIPESTATUS variable from the set of + exit statuses of all processes in the job J. */ +static void +setjstatus (j) + int j; +{ +#if defined (ARRAY_VARS) + register int i; + register PROCESS *p; + + for (i = 1, p = jobs[j]->pipe; p->next != jobs[j]->pipe; p = p->next, i++) + ; + i++; + if (statsize < i) + { + pstatuses = (int *)xrealloc (pstatuses, i * sizeof (int)); + statsize = i; + } + i = 0; + p = jobs[j]->pipe; + do + { + pstatuses[i++] = process_exit_status (p->status); + p = p->next; + } + while (p != jobs[j]->pipe); + + pstatuses[i] = -1; /* sentinel */ + set_pipestatus_array (pstatuses, i); +#endif +} + +static void +run_sigchld_trap (nchild) + int nchild; +{ + char *trap_command; + int i; + + /* Turn off the trap list during the call to parse_and_execute () + to avoid potentially infinite recursive calls. Preserve the + values of last_command_exit_value, last_made_pid, and the_pipeline + around the execution of the trap commands. */ + trap_command = savestring (trap_list[SIGCHLD]); + + begin_unwind_frame ("SIGCHLD trap"); + unwind_protect_int (last_command_exit_value); + unwind_protect_int (last_command_exit_signal); + unwind_protect_var (last_made_pid); + unwind_protect_int (interrupt_immediately); + unwind_protect_int (jobs_list_frozen); + unwind_protect_pointer (the_pipeline); + unwind_protect_pointer (subst_assign_varlist); + + /* We have to add the commands this way because they will be run + in reverse order of adding. We don't want maybe_set_sigchld_trap () + to reference freed memory. */ + add_unwind_protect (xfree, trap_command); + add_unwind_protect (maybe_set_sigchld_trap, trap_command); + + subst_assign_varlist = (WORD_LIST *)NULL; + the_pipeline = (PROCESS *)NULL; + + restore_default_signal (SIGCHLD); + jobs_list_frozen = 1; + for (i = 0; i < nchild; i++) + { + interrupt_immediately = 1; + parse_and_execute (savestring (trap_command), "trap", SEVAL_NOHIST|SEVAL_RESETLINE); + } + + run_unwind_frame ("SIGCHLD trap"); +} + +/* Function to call when you want to notify people of changes + in job status. This prints out all jobs which are pending + notification to stderr, and marks those printed as already + notified, thus making them candidates for cleanup. */ +static void +notify_of_job_status () +{ + register int job, termsig; + char *dir; + sigset_t set, oset; + WAIT s; + + if (jobs == 0 || js.j_jobslots == 0) + return; + + if (old_ttou != 0) + { + sigemptyset (&set); + sigaddset (&set, SIGCHLD); + sigaddset (&set, SIGTTOU); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + } + else + queue_sigchld++; + + for (job = 0, dir = (char *)NULL; job < js.j_jobslots; job++) + { + if (jobs[job] && IS_NOTIFIED (job) == 0) + { + s = raw_job_exit_status (job); + termsig = WTERMSIG (s); + + /* POSIX.2 says we have to hang onto the statuses of at most the + last CHILD_MAX background processes if the shell is running a + script. If the shell is not interactive, don't print anything + unless the job was killed by a signal. */ + if (startup_state == 0 && WIFSIGNALED (s) == 0 && + ((DEADJOB (job) && IS_FOREGROUND (job) == 0) || STOPPED (job))) + continue; + +#if 0 + /* If job control is disabled, don't print the status messages. + Mark dead jobs as notified so that they get cleaned up. If + startup_state == 2, we were started to run `-c command', so + don't print anything. */ + if ((job_control == 0 && interactive_shell) || startup_state == 2) +#else + /* If job control is disabled, don't print the status messages. + Mark dead jobs as notified so that they get cleaned up. If + startup_state == 2 and subshell_environment has the + SUBSHELL_COMSUB bit turned on, we were started to run a command + substitution, so don't print anything. */ + if ((job_control == 0 && interactive_shell) || + (startup_state == 2 && (subshell_environment & SUBSHELL_COMSUB))) +#endif + { + /* POSIX.2 compatibility: if the shell is not interactive, + hang onto the job corresponding to the last asynchronous + pid until the user has been notified of its status or does + a `wait'. */ + if (DEADJOB (job) && (interactive_shell || (find_last_pid (job, 0) != last_asynchronous_pid))) + jobs[job]->flags |= J_NOTIFIED; + continue; + } + + /* Print info on jobs that are running in the background, + and on foreground jobs that were killed by anything + except SIGINT (and possibly SIGPIPE). */ + switch (JOBSTATE (job)) + { + case JDEAD: + if (interactive_shell == 0 && termsig && WIFSIGNALED (s) && + termsig != SIGINT && +#if defined (DONT_REPORT_SIGPIPE) + termsig != SIGPIPE && +#endif + signal_is_trapped (termsig) == 0) + { + /* Don't print `0' for a line number. */ + fprintf (stderr, "%s: line %d: ", get_name_for_error (), (line_number == 0) ? 1 : line_number); + pretty_print_job (job, JLIST_NONINTERACTIVE, stderr); + } + else if (IS_FOREGROUND (job)) + { +#if !defined (DONT_REPORT_SIGPIPE) + if (termsig && WIFSIGNALED (s) && termsig != SIGINT) +#else + if (termsig && WIFSIGNALED (s) && termsig != SIGINT && termsig != SIGPIPE) +#endif + { + fprintf (stderr, "%s", j_strsignal (termsig)); + + if (WIFCORED (s)) + fprintf (stderr, " (core dumped)"); + + fprintf (stderr, "\n"); + } + } + else + { + if (dir == 0) + dir = current_working_directory (); + pretty_print_job (job, JLIST_STANDARD, stderr); + if (dir && strcmp (dir, jobs[job]->wd) != 0) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + } + + jobs[job]->flags |= J_NOTIFIED; + break; + + case JSTOPPED: + fprintf (stderr, "\n"); + if (dir == 0) + dir = current_working_directory (); + pretty_print_job (job, JLIST_STANDARD, stderr); + if (dir && (strcmp (dir, jobs[job]->wd) != 0)) + fprintf (stderr, + "(wd now: %s)\n", polite_directory_format (dir)); + jobs[job]->flags |= J_NOTIFIED; + break; + + case JRUNNING: + case JMIXED: + break; + + default: + programming_error ("notify_of_job_status"); + } + } + } + if (old_ttou != 0) + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + else + queue_sigchld--; +} + +/* Initialize the job control mechanism, and set up the tty stuff. */ +int +initialize_job_control (force) + int force; +{ + shell_pgrp = getpgid (0); + + if (shell_pgrp == -1) + { + sys_error ("initialize_job_control: getpgrp failed"); + exit (1); + } + + /* We can only have job control if we are interactive. */ + if (interactive == 0) + { + job_control = 0; + original_pgrp = NO_PID; + shell_tty = fileno (stderr); + } + else + { + /* Get our controlling terminal. If job_control is set, or + interactive is set, then this is an interactive shell no + matter where fd 2 is directed. */ + shell_tty = dup (fileno (stderr)); /* fd 2 */ + + shell_tty = move_to_high_fd (shell_tty, 1, -1); + + /* Compensate for a bug in systems that compiled the BSD + rlogind with DEBUG defined, like NeXT and Alliant. */ + if (shell_pgrp == 0) + { + shell_pgrp = getpid (); + setpgid (0, shell_pgrp); + tcsetpgrp (shell_tty, shell_pgrp); + } + + while ((terminal_pgrp = tcgetpgrp (shell_tty)) != -1) + { + if (shell_pgrp != terminal_pgrp) + { + SigHandler *ottin; + + ottin = set_signal_handler(SIGTTIN, SIG_DFL); + kill (0, SIGTTIN); + set_signal_handler (SIGTTIN, ottin); + continue; + } + break; + } + + /* Make sure that we are using the new line discipline. */ + if (set_new_line_discipline (shell_tty) < 0) + { + sys_error ("initialize_job_control: line discipline"); + job_control = 0; + } + else + { + original_pgrp = shell_pgrp; + shell_pgrp = getpid (); + + if ((original_pgrp != shell_pgrp) && (setpgid (0, shell_pgrp) < 0)) + { + sys_error ("initialize_job_control: setpgid"); + shell_pgrp = original_pgrp; + } + + job_control = 1; + + /* If (and only if) we just set our process group to our pid, + thereby becoming a process group leader, and the terminal + is not in the same process group as our (new) process group, + then set the terminal's process group to our (new) process + group. If that fails, set our process group back to what it + was originally (so we can still read from the terminal) and + turn off job control. */ + if (shell_pgrp != original_pgrp && shell_pgrp != terminal_pgrp) + { + if (give_terminal_to (shell_pgrp, 0) < 0) + { + setpgid (0, original_pgrp); + shell_pgrp = original_pgrp; + job_control = 0; + } + } + } + if (job_control == 0) + internal_error (_("no job control in this shell")); + } + + if (shell_tty != fileno (stderr)) + SET_CLOSE_ON_EXEC (shell_tty); + + set_signal_handler (SIGCHLD, sigchld_handler); + + change_flag ('m', job_control ? '-' : '+'); + + if (interactive) + get_tty_state (); + + return job_control; +} + +#ifdef DEBUG +void +debug_print_pgrps () +{ + itrace("original_pgrp = %ld shell_pgrp = %ld terminal_pgrp = %ld", + (long)original_pgrp, (long)shell_pgrp, (long)terminal_pgrp); + itrace("tcgetpgrp(%d) -> %ld, getpgid(0) -> %ld", + shell_tty, (long)tcgetpgrp (shell_tty), (long)getpgid(0)); +} +#endif + +/* Set the line discipline to the best this system has to offer. + Return -1 if this is not possible. */ +static int +set_new_line_discipline (tty) + int tty; +{ +#if defined (NEW_TTY_DRIVER) + int ldisc; + + if (ioctl (tty, TIOCGETD, &ldisc) < 0) + return (-1); + + if (ldisc != NTTYDISC) + { + ldisc = NTTYDISC; + + if (ioctl (tty, TIOCSETD, &ldisc) < 0) + return (-1); + } + return (0); +#endif /* NEW_TTY_DRIVER */ + +#if defined (TERMIO_TTY_DRIVER) +# if defined (TERMIO_LDISC) && (NTTYDISC) + if (ioctl (tty, TCGETA, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (ioctl (tty, TCSETAW, &shell_tty_info) < 0) + return (-1); + } +# endif /* TERMIO_LDISC && NTTYDISC */ + return (0); +#endif /* TERMIO_TTY_DRIVER */ + +#if defined (TERMIOS_TTY_DRIVER) +# if defined (TERMIOS_LDISC) && defined (NTTYDISC) + if (tcgetattr (tty, &shell_tty_info) < 0) + return (-1); + + if (shell_tty_info.c_line != NTTYDISC) + { + shell_tty_info.c_line = NTTYDISC; + if (tcsetattr (tty, TCSADRAIN, &shell_tty_info) < 0) + return (-1); + } +# endif /* TERMIOS_LDISC && NTTYDISC */ + return (0); +#endif /* TERMIOS_TTY_DRIVER */ + +#if !defined (NEW_TTY_DRIVER) && !defined (TERMIO_TTY_DRIVER) && !defined (TERMIOS_TTY_DRIVER) + return (-1); +#endif +} + +#if defined (TIOCGWINSZ) && defined (SIGWINCH) +static void +get_new_window_size (from_sig) + int from_sig; +{ + struct winsize win; + + if ((ioctl (shell_tty, TIOCGWINSZ, &win) == 0) && + win.ws_row > 0 && win.ws_col > 0) + { +#if defined (aixpc) + shell_tty_info.c_winsize = win; /* structure copying */ +#endif + sh_set_lines_and_columns (win.ws_row, win.ws_col); +#if defined (READLINE) + rl_set_screen_size (win.ws_row, win.ws_col); +#endif + } +} + +static sighandler +sigwinch_sighandler (sig) + int sig; +{ +#if defined (MUST_REINSTALL_SIGHANDLERS) + set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif /* MUST_REINSTALL_SIGHANDLERS */ + get_new_window_size (1); + SIGRETURN (0); +} +#else +static void +get_new_window_size (from_sig) + int from_sig; +{ +} +#endif /* TIOCGWINSZ && SIGWINCH */ + +void +set_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + old_winch = set_signal_handler (SIGWINCH, sigwinch_sighandler); +#endif +} + +void +unset_sigwinch_handler () +{ +#if defined (TIOCGWINSZ) && defined (SIGWINCH) + set_signal_handler (SIGWINCH, old_winch); +#endif +} + +/* Setup this shell to handle C-C, etc. */ +void +initialize_job_signals () +{ + if (interactive) + { + set_signal_handler (SIGINT, sigint_sighandler); + set_signal_handler (SIGTSTP, SIG_IGN); + set_signal_handler (SIGTTOU, SIG_IGN); + set_signal_handler (SIGTTIN, SIG_IGN); + set_sigwinch_handler (); + } + else if (job_control) + { + old_tstp = set_signal_handler (SIGTSTP, sigstop_sighandler); + old_ttin = set_signal_handler (SIGTTIN, sigstop_sighandler); + old_ttou = set_signal_handler (SIGTTOU, sigstop_sighandler); + } + /* Leave these things alone for non-interactive shells without job + control. */ +} + +/* Here we handle CONT signals. */ +static sighandler +sigcont_sighandler (sig) + int sig; +{ + initialize_job_signals (); + set_signal_handler (SIGCONT, old_cont); + kill (getpid (), SIGCONT); + + SIGRETURN (0); +} + +/* Here we handle stop signals while we are running not as a login shell. */ +static sighandler +sigstop_sighandler (sig) + int sig; +{ + set_signal_handler (SIGTSTP, old_tstp); + set_signal_handler (SIGTTOU, old_ttou); + set_signal_handler (SIGTTIN, old_ttin); + + old_cont = set_signal_handler (SIGCONT, sigcont_sighandler); + + give_terminal_to (shell_pgrp, 0); + + kill (getpid (), sig); + + SIGRETURN (0); +} + +/* Give the terminal to PGRP. */ +int +give_terminal_to (pgrp, force) + pid_t pgrp; + int force; +{ + sigset_t set, oset; + int r; + + r = 0; + if (job_control || force) + { + sigemptyset (&set); + sigaddset (&set, SIGTTOU); + sigaddset (&set, SIGTTIN); + sigaddset (&set, SIGTSTP); + sigaddset (&set, SIGCHLD); + sigemptyset (&oset); + sigprocmask (SIG_BLOCK, &set, &oset); + + if (tcsetpgrp (shell_tty, pgrp) < 0) + { + /* Maybe we should print an error message? */ +#if 0 + sys_error ("tcsetpgrp(%d) failed: pid %ld to pgrp %ld", + shell_tty, (long)getpid(), (long)pgrp); +#endif + r = -1; + } + else + terminal_pgrp = pgrp; + sigprocmask (SIG_SETMASK, &oset, (sigset_t *)NULL); + } + + return r; +} + +/* Clear out any jobs in the job array. This is intended to be used by + children of the shell, who should not have any job structures as baggage + when they start executing (forking subshells for parenthesized execution + and functions with pipes are the two that spring to mind). If RUNNING_ONLY + is nonzero, only running jobs are removed from the table. */ +void +delete_all_jobs (running_only) + int running_only; +{ + register int i; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + /* XXX - need to set j_lastj, j_firstj appropriately if running_only != 0. */ + if (js.j_jobslots) + { + js.j_current = js.j_previous = NO_JOB; + + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) + delete_job (i, 1); + + if (running_only == 0) + { + free ((char *)jobs); + js.j_jobslots = 0; + js.j_firstj = js.j_lastj = js.j_njobs = 0; + } + } + + UNBLOCK_CHILD (oset); +} + +/* Mark all jobs in the job array so that they don't get a SIGHUP when the + shell gets one. If RUNNING_ONLY is nonzero, mark only running jobs. */ +void +nohup_all_jobs (running_only) + int running_only; +{ + register int i; + sigset_t set, oset; + + BLOCK_CHILD (set, oset); + + if (js.j_jobslots) + { + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i] && (running_only == 0 || (running_only && RUNNING(i)))) + nohup_job (i); + } + + UNBLOCK_CHILD (oset); +} + +int +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 < js.j_jobslots; i++) + if (jobs[i] && DEADJOB(i) == 0) + n++; + UNBLOCK_CHILD (oset); + return n; +} + +static void +mark_all_jobs_as_dead () +{ + register int i; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return; + + BLOCK_CHILD (set, oset); + + for (i = 0; i < js.j_jobslots; i++) + if (jobs[i]) + jobs[i]->state = JDEAD; + + UNBLOCK_CHILD (oset); +} + +/* Mark all dead jobs as notified, so delete_job () cleans them out + of the job table properly. POSIX.2 says we need to save the + status of the last CHILD_MAX jobs, so we count the number of dead + jobs and mark only enough as notified to save CHILD_MAX statuses. */ +static void +mark_dead_jobs_as_notified (force) + int force; +{ + register int i, ndead, ndeadproc; + sigset_t set, oset; + + if (js.j_jobslots == 0) + return; + + BLOCK_CHILD (set, oset); + + /* If FORCE is non-zero, we don't have to keep CHILD_MAX statuses + around; just run through the array. */ + if (force) + { + 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; + } + UNBLOCK_CHILD (oset); + return; + } + + /* Mark enough dead jobs as notified to keep CHILD_MAX jobs left in the + array not marked as notified. */ + + /* Count the number of dead jobs */ + for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++) + { + if (jobs[i] && DEADJOB (i)) + { + ndead++; + ndeadproc += processes_in_job (i); + } + } + + if (js.c_childmax < 0) + js.c_childmax = getmaxchild (); + if (js.c_childmax < 0) + js.c_childmax = DEFAULT_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 jobs is less than CHILD_MAX and + we're not forcing a cleanup. */ +#if 1 + if (ndead <= js.c_childmax) +#else + if (ndeadproc <= js.c_childmax) +#endif + { + UNBLOCK_CHILD (oset); + return; + } + +itrace("marking %d jobs as notified", ndead-js.c_childmax); + /* 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. 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. */ + 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; +itrace("marking job %d as notified", i); + if (--ndead <= js.c_childmax) + break; + } + } + + UNBLOCK_CHILD (oset); +} + +/* Here to allow other parts of the shell (like the trap stuff) to + unfreeze the jobs list. */ +void +unfreeze_jobs_list () +{ + jobs_list_frozen = 0; +} + +/* Allow or disallow job control to take place. Returns the old value + of job_control. */ +int +set_job_control (arg) + int arg; +{ + int old; + + old = job_control; + job_control = arg; + + /* If we're turning on job control, reset pipeline_pgrp so make_child will + put new child processes into the right pgrp */ + if (job_control != old && job_control) + pipeline_pgrp = 0; + + return (old); +} + +/* Turn off all traces of job control. This is run by children of the shell + which are going to do shellsy things, like wait (), etc. */ +void +without_job_control () +{ + stop_making_children (); + start_pipeline (); + delete_all_jobs (0); + set_job_control (0); +} + +/* If this shell is interactive, terminate all stopped jobs and + restore the original terminal process group. This is done + before the `exec' builtin calls shell_execve. */ +void +end_job_control () +{ + if (interactive_shell) /* XXX - should it be interactive? */ + { + terminate_stopped_jobs (); + + if (original_pgrp >= 0) + give_terminal_to (original_pgrp, 1); + } + + if (original_pgrp >= 0) + setpgid (0, original_pgrp); +} + +/* Restart job control by closing shell tty and reinitializing. This is + called after an exec fails in an interactive shell and we do not exit. */ +void +restart_job_control () +{ + if (shell_tty != -1) + close (shell_tty); + initialize_job_control (0); +} + +/* Set the handler to run when the shell receives a SIGCHLD signal. */ +void +set_sigchld_handler () +{ + set_signal_handler (SIGCHLD, sigchld_handler); +} + +#if defined (PGRP_PIPE) +/* Read from the read end of a pipe. This is how the process group leader + blocks until all of the processes in a pipeline have been made. */ +static void +pipe_read (pp) + int *pp; +{ + char ch; + + if (pp[1] >= 0) + { + close (pp[1]); + pp[1] = -1; + } + + if (pp[0] >= 0) + { + while (read (pp[0], &ch, 1) == -1 && errno == EINTR) + ; + } +} + +/* Close the read and write ends of PP, an array of file descriptors. */ +static void +pipe_close (pp) + int *pp; +{ + if (pp[0] >= 0) + close (pp[0]); + + if (pp[1] >= 0) + close (pp[1]); + + pp[0] = pp[1] = -1; +} + +/* Functional interface closes our local-to-job-control pipes. */ +void +close_pgrp_pipe () +{ + pipe_close (pgrp_pipe); +} + +#endif /* PGRP_PIPE */ diff --git a/jobs.c~ b/jobs.c~ index fed5dd2..702c021 100644 --- a/jobs.c~ +++ b/jobs.c~ @@ -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); } -/* 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 - 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. */ static int -compact_jobs_list (flags) - int flags; +processes_in_job (job) { - sigset_t set, oset; - register int i, j; - int nremove, ndel; - JOB **newlist; - - if (job_slots == 0 || jobs_list_frozen) - return job_slots; - - 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; + int nproc; + register PROCESS *p; - /* need to increase jobs list to at least CHILD_MAX entries */ - if (nremove < 0) - return job_slots; + nproc = 0; + p = jobs[job]->pipe; + do + { + p = p->next; + nproc++; + } + while (p != jobs[job]->pipe); - BLOCK_CHILD (set, oset); + return nproc; +} - 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; - } - } +/* 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; - if (ndel == 0) - { - UNBLOCK_CHILD (oset); - return job_slots; - } + 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; - newlist = (JOB **)xmalloc ((1 + job_slots) * sizeof (JOB *)); - for (i = j = 0; i < job_slots; i++) + BLOCK_CHILD (set, oset); + nlist = (JOB **) xmalloc (nsize * sizeof (JOB *)); + for (i = j = 0; i < js.j_jobslots; i++) if (jobs[i]) - newlist[j++] = jobs[i]; + nlist[j++] = jobs[i]; - ndel = j; - for ( ; j < job_slots; j++) - newlist[j] = (JOB *)NULL; + js.j_firstj = 0; + js.j_lastj = (j > 0) ? j - 1: 0; + js.j_jobslots = nsize; free (jobs); - jobs = newlist; + jobs = nlist; UNBLOCK_CHILD (oset); +} - return ndel; +/* 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 js.j_jobslots, then + the list needs to be reallocated. The jobs array is in new memory if + this returns > 0 and < js.j_jobslots. FLAGS is reserved for future use. */ +static int +compact_jobs_list (flags) + int flags; +{ + if (js.j_jobslots == 0 || jobs_list_frozen) + return js.j_jobslots; + + reap_dead_jobs (); + realloc_jobs_list (); + + 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); } } diff --git a/jobs.h b/jobs.h index bcfaf18..ca22dba 100644 --- a/jobs.h +++ b/jobs.h @@ -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; diff --git a/jobs.h~ b/jobs.h~ new file mode 100644 index 0000000..e79e6f8 --- /dev/null +++ b/jobs.h~ @@ -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_ */ diff --git a/lib/readline/history.c b/lib/readline/history.c index d99b76e..161c977 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -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); } diff --git a/lib/readline/mbutil.c b/lib/readline/mbutil.c index 933eecc..73e0b34 100644 --- a/lib/readline/mbutil.c +++ b/lib/readline/mbutil.c @@ -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 diff --git a/lib/sh/netconn.c b/lib/sh/netconn.c index d05aef5..89838cc 100644 --- a/lib/sh/netconn.c +++ b/lib/sh/netconn.c @@ -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. */ diff --git a/parse.y b/parse.y index 356141a..0817724 100644 --- a/parse.y +++ b/parse.y @@ -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); diff --git a/parse.y~ b/parse.y~ index 641f4e7..b36a9e5 100644 --- a/parse.y~ +++ b/parse.y~ @@ -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); diff --git a/pcomplete.c b/pcomplete.c index 9f5121e..f94f5d9 100644 --- a/pcomplete.c +++ b/pcomplete.c @@ -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"); diff --git a/pcomplete.c~ b/pcomplete.c~ index 371f084..f49faae 100644 --- a/pcomplete.c~ +++ b/pcomplete.c~ @@ -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); diff --git a/subst.c b/subst.c index 7009f32..ee4c925 100644 --- a/subst.c +++ b/subst.c @@ -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 */ } diff --git a/subst.c~ b/subst.c~ index fab69ec..7009f32 100644 --- a/subst.c~ +++ b/subst.c~ @@ -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; diff --git a/trap.c b/trap.c index ef1d95a..77b6d76 100644 --- a/trap.c +++ b/trap.c @@ -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++) diff --git a/trap.c~ b/trap.c~ index c2ee296..ef1d95a 100644 --- a/trap.c~ +++ b/trap.c~ @@ -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