commit bash-20190920 snapshot

This commit is contained in:
Chet Ramey
2019-09-23 09:42:14 -04:00
parent db26b1cf58
commit d111b2af6e
24 changed files with 4954 additions and 4654 deletions
+74
View File
@@ -6560,3 +6560,77 @@ m4/intl.m4
- gt_INTL_SUBDIR_CORE: add back check for localeconv, removed in
newer gettext releases
9/16
----
builtins/help.def
- help_builtin: make the closing quote printed after the argument list
for a glob pattern argument a translatable string to ease translation
for certain languages. Report from Roland Illig <roland.illig@gmx.de>
builtins/{reserved,complete,exec,getopts}.def
- minor typographical fixes from Roland Illig <roland.illig@gmx.de>
siglist.c
- include general.h for INT_STRLEN_BOUND
- initialize_siglist: use the same string for the strlen and xmalloc
for the message about an unknown signal number; use INT_STRLEN_BOUND
instead of a fixed 10 for the number
builtins/getopts.def,doc/{bash.1,bashref.texi}
- getopts: minor changes to the description of the effect of supplying
additional arguments. Report from Roland Illig <roland.illig@gmx.de>
9/17
----
jobs.[ch]
- save_proc_status: external interface to bgp_add, takes care of
blocking and unblocking SIGCHLD
- __P -> PARAMS
9/18
----
jobs.[ch]
- procsub_{free,add,search,delete,waitpid,waitall,clear,prune}: new
functions to keep track of the list of active process substitutions
and their statuses. Implementation is currently a singly-linked list
of PROCESS *, so functions that expect a PROCESS * to manipulate
continue to work. Inspired by report from leo.dalecki@ntymail.com
- find_pipeline,cleanup_dead_jobs,wait_for_background_pids: call new
procsub_* functions to manage procsub list; don't call the functions
in subst.c any more
subst.c
- process_substitute: call procsub_add with the PROCESS * returned
from make_child; let the functions in jobs.c manage the list.
waitchld continues to set the pid field in the fifo list as a hint
that a particular fd or FIFO is no longer used and can be reaped
- process_substitute: let the child process clear out any existing
procsub pid list
- wait_procsubs: no longer compiled in
sig.c
- termsig_handler: replace discard_last_procsub_child with call to
procsub_clear
lib/readline/display.c
- init_line_structures: fix a problem which results in references to
uninitialized memory when gdb sets the number of columns to 32767
(their `unlimited'). Modification of change from 5/23. Report and
fix from Andrew Burgess <andrew.burgess@embecosm.com>
9/19
----
parse.y
- xparse_dolparen: after calling parse_string to consume input, make
sure to reset the parser (reset_parser()) before restoring the EOF
token and the parser_state variable. Fixes issue with nested traps
running command substitutions in command lines with command
substitutions reported by Travis Everett <travis.a.everett@gmail.com>
9/20
----
doc/{bashref.texi,bash.1}
- fixed a typo in the example for the =~ operator: the ? should follow
the (a), not precede it. Report from hk <hkadeveloper@gmail.com>
- some changes to the text describing regular expression matching for
the =~ operator
+3 -3
View File
@@ -2,7 +2,7 @@ This file is caller.def, from which is created caller.c. It implements the
builtin "caller" in Bash.
Copyright (C) 2002-2008 Rocky Bernstein for Free Software Foundation, Inc.
Copyright (C) 2008-2013 Free Software Foundation, Inc.
Copyright (C) 2008-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -135,8 +135,8 @@ caller_builtin (list)
static char *caller_doc[] = {
N_("Returns the context of the current subroutine call.\n\
\n\
Without EXPR, returns "$line $filename". With EXPR, returns\n\
"$line $subroutine $filename"; this extra information can be used to\n\
Without EXPR, returns \"$line $filename\". With EXPR, returns\n\
\"$line $subroutine $filename\"; this extra information can be used to\n\
provide a stack trace.\n\
\n\
The value of EXPR indicates how many call frames to go back before the\n\
+3 -3
View File
@@ -1,7 +1,7 @@
This file is complete.def, from which is created complete.c.
It implements the builtins "complete", "compgen", and "compopt" in Bash.
Copyright (C) 1999-2015 Free Software Foundation, Inc.
Copyright (C) 1999-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -23,7 +23,7 @@ $PRODUCES complete.c
$BUILTIN complete
$DEPENDS_ON PROGRAMMABLE_COMPLETION
$FUNCTION complete_builtin
$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
$SHORT_DOC complete [-abcdefgjksuv] [-pr] [-DEI] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [name ...]
Specify how arguments are to be completed by Readline.
For each NAME, specify how arguments are to be completed. If no options
@@ -694,7 +694,7 @@ print_cmd_completions (list)
$BUILTIN compgen
$DEPENDS_ON PROGRAMMABLE_COMPLETION
$FUNCTION compgen_builtin
$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
$SHORT_DOC compgen [-abcdefgjksuv] [-o option] [-A action] [-G globpat] [-W wordlist] [-F function] [-C command] [-X filterpat] [-P prefix] [-S suffix] [word]
Display possible completions depending on the options.
Intended to be used from within a shell function generating possible
+2 -2
View File
@@ -1,7 +1,7 @@
This file is exec.def, from which is created exec.c.
It implements the builtin "exec" in Bash.
Copyright (C) 1987-2015 Free Software Foundation, Inc.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -22,7 +22,7 @@ $PRODUCES exec.c
$BUILTIN exec
$FUNCTION exec_builtin
$SHORT_DOC exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
$SHORT_DOC exec [-cl] [-a name] [command [argument ...]] [redirection ...]
Replace the shell with the given command.
Execute COMMAND, replacing this shell with the specified program.
+4 -4
View File
@@ -1,7 +1,7 @@
This file is getopts.def, from which is created getopts.c.
It implements the builtin "getopts" in Bash.
Copyright (C) 1987-2015 Free Software Foundation, Inc.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -22,7 +22,7 @@ $PRODUCES getopts.c
$BUILTIN getopts
$FUNCTION getopts_builtin
$SHORT_DOC getopts optstring name [arg]
$SHORT_DOC getopts optstring name [arg ...]
Parse option arguments.
Getopts is used by shell procedures to parse positional parameters
@@ -54,8 +54,8 @@ If the shell variable OPTERR has the value 0, getopts disables the
printing of error messages, even if the first character of
OPTSTRING is not a colon. OPTERR has the value 1 by default.
Getopts normally parses the positional parameters ($0 - $9), but if
more arguments are given, they are parsed instead.
Getopts normally parses the positional parameters, but if arguments
are supplied as ARG values, they are parsed instead.
Exit Status:
Returns success if an option is found; fails if the end of options is
+2 -2
View File
@@ -1,7 +1,7 @@
This file is help.def, from which is created help.c.
It implements the builtin "help" in Bash.
Copyright (C) 1987-2015 Free Software Foundation, Inc.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -132,7 +132,7 @@ help_builtin (list)
{
printf ("%s", ngettext ("Shell commands matching keyword `", "Shell commands matching keywords `", (list->next ? 2 : 1)));
print_word_list (list, ", ");
printf ("'\n\n");
printf ("%s", _("'\n\n"));
}
for (match_found = 0, pattern = ""; list; list = list->next)
+2 -2
View File
@@ -2,7 +2,7 @@ This file is reserved.def, in which the shell reserved words are defined.
It has no direct C file production, but defines builtins for the Bash
builtin help command.
Copyright (C) 1987-2009 Free Software Foundation, Inc.
Copyright (C) 1987-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -194,7 +194,7 @@ $SHORT_DOC (( expression ))
Evaluate arithmetic expression.
The EXPRESSION is evaluated according to the rules for arithmetic
evaluation. Equivalent to "let EXPRESSION".
evaluation. Equivalent to `let "EXPRESSION"'.
Exit Status:
Returns 1 if EXPRESSION evaluates to 0; returns 0 otherwise.
+9 -6
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Mon Jul 8 15:14:50 EDT 2019
.\" Last Change: Fri Sep 20 15:30:19 EDT 2019
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2019 July 8" "GNU Bash 5.0"
.TH BASH 1 "2019 September 20" "GNU Bash 5.0"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -742,7 +742,9 @@ to be matched as a string.
An additional binary operator, \fB=~\fP, is available, with the same
precedence as \fB==\fP and \fB!=\fP.
When it is used, the string to the right of the operator is considered
a POSIX extended regular expression and matched accordingly (as in \fIregex\fP(3)).
a POSIX extended regular expression and matched accordingly
(using the POSIX \fIregcomp\fP and \fIregexec\fP interfaces
usually described in \fIregex\fP(3)).
The return value is 0 if the string matches
the pattern, and 1 otherwise.
If the regular expression is syntactically incorrect, the conditional
@@ -8494,7 +8496,7 @@ does not specify a valid job or
.I jobspec
specifies a job that was started without job control.
.TP
\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIargs\fP]
\fBgetopts\fP \fIoptstring\fP \fIname\fP [\fIarg ...\fP]
.B getopts
is used by shell procedures to parse positional parameters.
.I optstring
@@ -8540,8 +8542,9 @@ and \fIname\fP is set to ?.
.sp 1
.B getopts
normally parses the positional parameters, but if more arguments are
given in
.IR args ,
supplied as
.I arg
values,
.B getopts
parses those instead.
.sp 1
BIN
View File
Binary file not shown.
+4451 -4441
View File
File diff suppressed because it is too large Load Diff
+3 -3
View File
@@ -1,4 +1,4 @@
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018/MacPorts 2018.47642_7) (preloaded format=pdfetex 2019.1.16) 8 JUL 2019 15:16
This is pdfTeX, Version 3.14159265-2.6-1.40.19 (TeX Live 2018/MacPorts 2018.47642_7) (preloaded format=pdfetex 2019.1.16) 20 SEP 2019 14:50
entering extended mode
restricted \write18 enabled.
file:line:error style messages enabled.
@@ -286,7 +286,7 @@ Overfull \vbox (0.67252pt too high) has occurred while \output is active
Here is how much of TeX's memory you used:
4069 strings out of 497100
47090 string characters out of 6206794
137042 words of memory out of 5000000
137054 words of memory out of 5000000
4846 multiletter control sequences out of 15000+600000
34315 words of font info for 116 fonts, out of 8000000 for 9000
51 hyphenation exceptions out of 8191
@@ -308,7 +308,7 @@ s/type1/public/amsfonts/cm/cmtt12.pfb></opt/local/share/texmf-texlive/fonts/typ
e1/public/amsfonts/cm/cmtt9.pfb></opt/local/share/texmf-texlive/fonts/type1/pub
lic/cm-super/sfrm1095.pfb></opt/local/share/texmf-texlive/fonts/type1/public/cm
-super/sfrm1440.pfb>
Output written on bashref.pdf (187 pages, 757503 bytes).
Output written on bashref.pdf (187 pages, 757573 bytes).
PDF statistics:
2644 PDF objects out of 2984 (max. 8388607)
2411 compressed objects within 25 object streams
BIN
View File
Binary file not shown.
+9 -7
View File
@@ -1033,7 +1033,8 @@ An additional binary operator, @samp{=~}, is available, with the same
precedence as @samp{==} and @samp{!=}.
When it is used, the string to the right of the operator is considered
a @sc{POSIX} extended regular expression and matched accordingly
(as in @i{regex}3)).
(using the @sc{POSIX} @code{regcomp} and @code{regexec} interfaces
usually described in @i{regex}(3)).
The return value is 0 if the string matches
the pattern, and 1 otherwise.
If the regular expression is syntactically incorrect, the conditional
@@ -1057,11 +1058,12 @@ string matching the @var{n}th parenthesized subexpression.
For example, the following will match a line
(stored in the shell variable @var{line})
if there is a sequence of characters in the value consisting of
if there is a sequence of characters anywhere in the value consisting of
any number, including zero, of
space characters, zero or one instances of @samp{a}, then a @samp{b}:
characters in the @code{space} character class,
zero or one instances of @samp{a}, then a @samp{b}:
@example
[[ $line =~ [[:space:]]*?(a)b ]]
[[ $line =~ [[:space:]]*(a)?b ]]
@end example
@noindent
@@ -1077,7 +1079,7 @@ expressions while paying attention to the shell's quote removal.
Using a shell variable to store the pattern decreases these problems.
For example, the following is equivalent to the above:
@example
pattern='[[:space:]]*?(a)b'
pattern='[[:space:]]*(a)?b'
[[ $line =~ $pattern ]]
@end example
@@ -3574,7 +3576,7 @@ with a name that is not a shell function.
@item getopts
@btindex getopts
@example
getopts @var{optstring} @var{name} [@var{args}]
getopts @var{optstring} @var{name} [@var{arg} @dots{}]
@end example
@code{getopts} is used by shell scripts to parse positional parameters.
@@ -3603,7 +3605,7 @@ and @var{name} is set to @samp{?}.
@code{getopts}
normally parses the positional parameters, but if more arguments are
given in @var{args}, @code{getopts} parses those instead.
supplied as @var{arg} values, @code{getopts} parses those instead.
@code{getopts} can report errors in two ways. If the first character of
@var{optstring} is a colon, @var{silent}
+3 -3
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2019 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Mon Jul 8 15:10:15 EDT 2019
@set LASTCHANGE Fri Sep 20 15:29:59 EDT 2019
@set EDITION 5.0
@set VERSION 5.0
@set UPDATED 8 July 2019
@set UPDATED-MONTH July 2019
@set UPDATED 20 September 2019
@set UPDATED-MONTH September 2019
-9
View File
@@ -4304,15 +4304,6 @@ execute_simple_command (simple_command, pipe_in, pipe_out, async, fds_to_close)
if (pipe_out != NO_PIPE)
result = last_command_exit_value;
close_pipes (pipe_in, pipe_out);
#if defined (PROCESS_SUBSTITUTION) && defined (HAVE_DEV_FD)
#if 0
/* Close /dev/fd file descriptors in the parent after forking the
last child in a (possibly one-element) pipeline. Defer this
until any running shell function completes. */
if (pipe_out == NO_PIPE && variable_context == 0) /* XXX */
unlink_fifo_list (); /* XXX */
#endif
#endif
command_line = (char *)NULL; /* don't free this. */
#if 0
bind_lastarg ((char *)NULL);
+277 -89
View File
@@ -87,7 +87,7 @@ extern int errno;
#endif /* !errno */
#if !defined (HAVE_KILLPG)
extern int killpg __P((pid_t, int));
extern int killpg PARAMS((pid_t, int));
#endif
#if !DEFAULT_CHILD_MAX
@@ -162,7 +162,7 @@ extern int killpg __P((pid_t, int));
/* 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));
typedef int sh_job_map_func_t PARAMS((JOB *, int, int, int));
/* Variables used here but defined in other files. */
extern sigset_t top_level_mask;
@@ -170,13 +170,15 @@ extern WORD_LIST *subst_assign_varlist;
extern SigHandler **original_signals;
extern void set_original_signal __P((int, SigHandler *));
extern void set_original_signal PARAMS((int, SigHandler *));
static struct jobstats zerojs = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
struct jobstats js = { -1L, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, NO_JOB, NO_JOB, 0, 0 };
ps_index_t pidstat_table[PIDSTAT_TABLE_SZ];
struct bgpids bgpids = { 0, 0, 0 };
struct bgpids bgpids = { 0, 0, 0, 0 };
struct procchain procsubs = { 0, 0, 0 };
/* The array of known jobs. */
JOB **jobs = (JOB **)NULL;
@@ -236,75 +238,75 @@ PROCESS *last_procsub_child = (PROCESS *)NULL;
void debug_print_pgrps (void);
static sighandler wait_sigint_handler __P((int));
static sighandler sigchld_handler __P((int));
static sighandler sigcont_sighandler __P((int));
static sighandler sigstop_sighandler __P((int));
static sighandler wait_sigint_handler PARAMS((int));
static sighandler sigchld_handler PARAMS((int));
static sighandler sigcont_sighandler PARAMS((int));
static sighandler sigstop_sighandler PARAMS((int));
static int waitchld __P((pid_t, int));
static int waitchld PARAMS((pid_t, int));
static PROCESS *find_pid_in_pipeline __P((pid_t, PROCESS *, int));
static PROCESS *find_pipeline __P((pid_t, int, int *));
static PROCESS *find_process __P((pid_t, int, int *));
static PROCESS *find_pid_in_pipeline PARAMS((pid_t, PROCESS *, int));
static PROCESS *find_pipeline PARAMS((pid_t, int, int *));
static PROCESS *find_process PARAMS((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 char *current_working_directory PARAMS((void));
static char *job_working_directory PARAMS((void));
static char *j_strsignal PARAMS((int));
static char *printable_job_status PARAMS((int, PROCESS *, int));
static PROCESS *find_last_proc __P((int, int));
static pid_t find_last_pid __P((int, int));
static PROCESS *find_last_proc PARAMS((int, int));
static pid_t find_last_pid PARAMS((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, PROCESS **));
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 set_job_status_and_cleanup __P((int));
static int set_new_line_discipline PARAMS((int));
static int map_over_jobs PARAMS((sh_job_map_func_t *, int, int));
static int job_last_stopped PARAMS((int));
static int job_last_running PARAMS((int));
static int most_recent_job_in_state PARAMS((int, JOB_STATE));
static int find_job PARAMS((pid_t, int, PROCESS **));
static int print_job PARAMS((JOB *, int, int, int));
static int process_exit_status PARAMS((WAIT));
static int process_exit_signal PARAMS((WAIT));
static int set_job_status_and_cleanup PARAMS((int));
static WAIT job_signal_status __P((int));
static WAIT raw_job_exit_status __P((int));
static WAIT job_signal_status PARAMS((int));
static WAIT raw_job_exit_status PARAMS((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 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 int maybe_give_terminal_to __P((pid_t, pid_t, 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));
static void notify_of_job_status PARAMS((void));
static void reset_job_indices PARAMS((void));
static void cleanup_dead_jobs PARAMS((void));
static int processes_in_job PARAMS((int));
static void realloc_jobs_list PARAMS((void));
static int compact_jobs_list PARAMS((int));
static void add_process PARAMS((char *, pid_t));
static void print_pipeline PARAMS((PROCESS *, int, int, FILE *));
static void pretty_print_job PARAMS((int, int, FILE *));
static void set_current_job PARAMS((int));
static void reset_current PARAMS((void));
static void set_job_running PARAMS((int));
static void setjstatus PARAMS((int));
static int maybe_give_terminal_to PARAMS((pid_t, pid_t, int));
static void mark_all_jobs_as_dead PARAMS((void));
static void mark_dead_jobs_as_notified PARAMS((int));
static void restore_sigint_handler PARAMS((void));
#if defined (PGRP_PIPE)
static void pipe_read __P((int *));
static void pipe_read PARAMS((int *));
#endif
/* Hash table manipulation */
static ps_index_t *pshash_getbucket __P((pid_t));
static void pshash_delindex __P((ps_index_t));
static ps_index_t *pshash_getbucket PARAMS((pid_t));
static void pshash_delindex PARAMS((ps_index_t));
/* Saved background process status management */
static struct pidstat *bgp_add __P((pid_t, int));
static int bgp_delete __P((pid_t));
static void bgp_clear __P((void));
static int bgp_search __P((pid_t));
static struct pidstat *bgp_add PARAMS((pid_t, int));
static int bgp_delete PARAMS((pid_t));
static void bgp_clear PARAMS((void));
static int bgp_search PARAMS((pid_t));
static struct pipeline_saver *alloc_pipeline_saver __P((void));
static struct pipeline_saver *alloc_pipeline_saver PARAMS((void));
static ps_index_t bgp_getindex __P((void));
static void bgp_resize __P((void)); /* XXX */
static ps_index_t bgp_getindex PARAMS((void));
static void bgp_resize PARAMS((void)); /* XXX */
#if defined (ARRAY_VARS)
static int *pstatuses; /* list of pipeline statuses */
@@ -441,6 +443,7 @@ cleanup_the_pipeline ()
discard_pipeline (disposer);
}
/* Not used right now */
void
discard_last_procsub_child ()
{
@@ -889,7 +892,7 @@ bgp_delete (pid)
break;
if (orig_psi == bgpids.storage[psi].bucket_next) /* catch reported bug */
{
internal_warning ("bgp_delete: LOOP: psi (%d) == storage[psi].bucket_next", psi);
internal_warning (_("bgp_delete: LOOP: psi (%d) == storage[psi].bucket_next"), psi);
return 0;
}
}
@@ -942,7 +945,7 @@ bgp_search (pid)
return (bgpids.storage[psi].status);
if (orig_psi == bgpids.storage[psi].bucket_next) /* catch reported bug */
{
internal_warning ("bgp_search: LOOP: psi (%d) == storage[psi].bucket_next", psi);
internal_warning (_("bgp_search: LOOP: psi (%d) == storage[psi].bucket_next"), psi);
return -1;
}
}
@@ -958,6 +961,195 @@ bgp_prune ()
}
#endif
/* External interface to bgp_add; takes care of blocking and unblocking
SIGCHLD. Not really used. */
void
save_proc_status (pid, status)
pid_t pid;
int status;
{
sigset_t set, oset;
BLOCK_CHILD (set, oset);
bgp_add (pid, status);
UNBLOCK_CHILD (oset);
}
#if defined (PROCESS_SUBSTITUTION)
/* Functions to add and remove PROCESS * children from the list of running
asynchronous process substitutions. The list is currently a simple singly
linked list of PROCESS *, so it works with the set of callers that want
a child. subst.c:process_substitute adds to the list, the various wait*
functions manipulate child->running and child->status, and processes are
eventually removed from the list and added to the bgpids table. */
static void
procsub_free (p)
PROCESS *p;
{
FREE (p->command);
free (p);
}
PROCESS *
procsub_add (p)
PROCESS *p;
{
sigset_t set, oset;
BLOCK_CHILD (set, oset);
if (procsubs.head == 0)
{
procsubs.head = procsubs.end = p;
procsubs.nproc = 0;
}
else
{
procsubs.end->next = p;
procsubs.end = p;
}
procsubs.nproc++;
UNBLOCK_CHILD (oset);
return p;
}
PROCESS *
procsub_search (pid)
pid_t pid;
{
PROCESS *p;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
for (p = procsubs.head; p; p = p->next)
if (p->pid == pid)
break;
UNBLOCK_CHILD (oset);
return p;
}
PROCESS *
procsub_delete (pid)
pid_t pid;
{
PROCESS *p, *prev;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
for (p = prev = procsubs.head; p; prev = p, p = p->next)
if (p->pid == pid)
{
prev->next = p->next;
break;
}
if (p == 0)
{
UNBLOCK_CHILD (oset);
return p;
}
if (p == procsubs.head)
procsubs.head = procsubs.head->next;
else if (p == procsubs.end)
procsubs.end = prev;
procsubs.nproc--;
if (procsubs.nproc == 0)
procsubs.head = procsubs.end = 0;
else if (procsubs.nproc == 1) /* XXX */
procsubs.end = procsubs.head;
/* this can't be called anywhere in a signal handling path */
bgp_add (p->pid, process_exit_status (p->status));
UNBLOCK_CHILD (oset);
return (p);
}
int
procsub_waitpid (pid)
pid_t pid;
{
PROCESS *p;
int r;
p = procsub_search (pid);
if (p == 0)
return -1;
if (p->running == PS_DONE)
return (p->status);
r = wait_for (p->pid);
return (r); /* defer removing until later */
}
void
procsub_waitall ()
{
PROCESS *p;
int r;
for (p = procsubs.head; p; p = p->next)
{
if (p->running == PS_DONE)
continue;
r = wait_for (p->pid);
}
}
void
procsub_clear ()
{
PROCESS *p, *ps;
sigset_t set, oset;
BLOCK_CHILD (set, oset);
for (ps = procsubs.head; ps; )
{
p = ps;
ps = ps->next;
procsub_free (p);
}
procsubs.head = procsubs.end = 0;
procsubs.nproc = 0;
UNBLOCK_CHILD (oset);
}
/* Must be called with SIGCHLD blocked. */
void
procsub_prune ()
{
PROCESS *ohead, *oend, *ps, *p;
int onproc;
if (procsubs.nproc == 0)
return;
ohead = procsubs.head;
oend = procsubs.end;
onproc = procsubs.nproc;
procsubs.head = procsubs.end = 0;
procsubs.nproc = 0;
for (p = ohead; p; )
{
ps = p->next;
p->next = 0;
if (p->running == PS_DONE)
{
bgp_add (p->pid, process_exit_status (p->status));
procsub_free (p);
}
else
procsub_add (p);
p = ps;
}
}
#endif
/* 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. This wraps around, but the rest of the code does not. At
@@ -981,7 +1173,7 @@ reset_job_indices ()
js.j_firstj++;
}
if (js.j_firstj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
if (jobs[js.j_lastj] == 0)
{
@@ -997,7 +1189,7 @@ reset_job_indices ()
js.j_lastj--;
}
if (js.j_lastj == old)
js.j_firstj = js.j_lastj = js.j_njobs = 0;
js.j_firstj = js.j_lastj = js.j_njobs = 0;
}
}
@@ -1029,13 +1221,8 @@ cleanup_dead_jobs ()
}
#if defined (PROCESS_SUBSTITUTION)
if (last_procsub_child && last_procsub_child->running == PS_DONE)
{
bgp_add (last_procsub_child->pid, process_exit_status (last_procsub_child->status)); /* XXX */
discard = last_procsub_child;
last_procsub_child = (PROCESS *)NULL;
discard_pipeline (discard);
}
procsub_prune ();
last_procsub_child = (PROCESS *)NULL;
#endif
#if defined (COPROCESS_SUPPORT)
@@ -1307,10 +1494,10 @@ add_process (name, pid)
{
# ifdef DEBUG
if (j == NO_JOB)
internal_warning (_("add_process: process %5ld (%s) in the_pipeline"), (long)p->pid, p->command);
internal_warning ("add_process: process %5ld (%s) in the_pipeline", (long)p->pid, p->command);
# endif
if (PALIVE (p))
internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command);
internal_warning (_("add_process: pid %5ld (%s) marked as still alive"), (long)p->pid, p->command);
p->running = PS_RECYCLED; /* mark as recycled */
}
#endif
@@ -1533,6 +1720,7 @@ find_pipeline (pid, alive_only, jobp)
p = (PROCESS *)NULL;
if (jobp)
*jobp = NO_JOB;
if (the_pipeline && (p = find_pid_in_pipeline (pid, the_pipeline, alive_only)))
return (p);
@@ -1540,10 +1728,11 @@ find_pipeline (pid, alive_only, jobp)
for (save = saved_pipeline; save; save = save->next)
if (save->pipeline && (p = find_pid_in_pipeline (pid, save->pipeline, alive_only)))
return (p);
/* Now look in the last process substitution pipeline, since that sets $! */
if (last_procsub_child && (p = find_pid_in_pipeline (pid, last_procsub_child, alive_only)))
#if defined (PROCESS_SUBSTITUTION)
if (procsubs.nproc > 0 && (p = procsub_search (pid)) && ((alive_only == 0 && PRECYCLED(p) == 0) || PALIVE(p)))
return (p);
#endif
job = find_job (pid, alive_only, &p);
if (jobp)
@@ -2090,7 +2279,7 @@ make_child (command, async_p)
#endif
#if defined (RECYCLES_PIDS)
if (last_asynchronous_pid == mypid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
}
@@ -2128,7 +2317,7 @@ make_child (command, async_p)
last_asynchronous_pid = pid;
#if defined (RECYCLES_PIDS)
else if (last_asynchronous_pid == pid)
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
/* Avoid pid aliasing. 1 seems like a safe, unusual pid value. */
last_asynchronous_pid = 1;
#endif
@@ -2137,7 +2326,7 @@ make_child (command, async_p)
delete_old_job (pid);
/* Perform the check for pid reuse unconditionally. Some systems reuse
PIDs before giving a process CHILD_MAX/_SC_CHILD_MAX unique ones. */
PIDs before giving a process CHILD_MAX/_SC_CHILD_MAX unique ones. */
bgp_delete (pid); /* new process, discard any saved status */
last_made_pid = pid;
@@ -2501,10 +2690,7 @@ wait_for_background_pids (ps)
}
#if defined (PROCESS_SUBSTITUTION)
if (last_procsub_child && last_procsub_child->pid != NO_PID && last_procsub_child->pid == last_asynchronous_pid)
r = wait_for (last_procsub_child->pid);
wait_procsubs ();
reap_procsubs ();
procsub_waitall ();
#endif
/* POSIX.2 says the shell can discard the statuses of all completed jobs if
@@ -2740,11 +2926,11 @@ wait_for (pid)
temp_sigint_handler = set_signal_handler (SIGINT, wait_sigint_handler);
if (temp_sigint_handler == wait_sigint_handler)
{
{
#if defined (DEBUG)
internal_warning ("wait_for: recursively setting old_sigint_handler to wait_sigint_handler: running_trap = %d", running_trap);
#endif
}
}
else
old_sigint_handler = temp_sigint_handler;
waiting_for_child = 0;
@@ -3022,7 +3208,7 @@ if (job == NO_JOB)
}
/* Moved here from set_job_status_and_cleanup, which is in the SIGCHLD
signal handler path */
signal handler path */
if (DEADJOB (job) && IS_FOREGROUND (job) /*&& subshell_environment == 0*/)
setjstatus (job);
@@ -3142,8 +3328,8 @@ return_job:
/* Make sure there is a background job to wait for */
BLOCK_CHILD (set, oset);
for (i = 0; i < js.j_jobslots; i++)
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
break;
if (jobs[i] && RUNNING (i) && IS_FOREGROUND (i) == 0)
break;
if (i == js.j_jobslots)
{
UNBLOCK_CHILD (oset);
@@ -3678,10 +3864,10 @@ itrace("waitchld: waitpid returns %d block = %d children_exited = %d", pid, bloc
/* If the child process did die due to SIGINT, forget our assumption
that it caught or otherwise handled it. */
if (WIFSIGNALED (status) && WTERMSIG (status) == SIGINT)
child_caught_sigint = 0;
child_caught_sigint = 0;
/* children_exited is used to run traps on SIGCHLD. We don't want to
run the trap if a process is just being continued. */
run the trap if a process is just being continued. */
if (WIFCONTINUED(status) == 0)
{
children_exited++;
@@ -3697,7 +3883,9 @@ itrace("waitchld: waitpid returns %d block = %d children_exited = %d", pid, bloc
#if defined (PROCESS_SUBSTITUTION)
/* Only manipulate the list of process substitutions while SIGCHLD
is blocked. */
is blocked. We only use this as a hint that we can remove FIFOs
or close file descriptors corresponding to terminated process
substitutions. */
if ((ind = find_procsub_child (pid)) >= 0)
set_procsub_status (ind, pid, WSTATUS (status));
#endif
@@ -4693,7 +4881,7 @@ mark_dead_jobs_as_notified (force)
way to avoid pid aliasing and reuse problems than keeping the POSIX-
mandated CHILD_MAX jobs around. delete_job() takes care of keeping the
bgpids list regulated. */
/* Count the number of dead jobs */
/* XXX could use js.j_firstj here */
for (i = ndead = ndeadproc = 0; i < js.j_jobslots; i++)
+81 -63
View File
@@ -1,6 +1,6 @@
/* jobs.h -- structures and definitions used by the jobs.c file. */
/* Copyright (C) 1993-2017 Free Software Foundation, Inc.
/* Copyright (C) 1993-2019 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -175,6 +175,14 @@ struct procstat {
bits16_t status;
};
/* A standalone singly-linked list of PROCESS *, used in various places
including keeping track of process substitutions. */
struct procchain {
PROCESS *head;
PROCESS *end;
int nproc;
};
#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. */
@@ -203,87 +211,97 @@ extern PROCESS *last_procsub_child;
extern JOB **jobs;
extern void making_children __P((void));
extern void stop_making_children __P((void));
extern void cleanup_the_pipeline __P((void));
extern void discard_last_procsub_child __P((void));
extern void save_pipeline __P((int));
extern PROCESS *restore_pipeline __P((int));
extern void start_pipeline __P((void));
extern int stop_pipeline __P((int, COMMAND *));
extern int discard_pipeline __P((PROCESS *));
extern void append_process __P((char *, pid_t, int, int));
extern void making_children PARAMS((void));
extern void stop_making_children PARAMS((void));
extern void cleanup_the_pipeline PARAMS((void));
extern void discard_last_procsub_child PARAMS((void));
extern void save_pipeline PARAMS((int));
extern PROCESS *restore_pipeline PARAMS((int));
extern void start_pipeline PARAMS((void));
extern int stop_pipeline PARAMS((int, COMMAND *));
extern int discard_pipeline PARAMS((PROCESS *));
extern void append_process PARAMS((char *, pid_t, int, int));
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 void save_proc_status PARAMS((pid_t, int));
extern int count_all_jobs __P((void));
extern PROCESS *procsub_add PARAMS((PROCESS *));
extern PROCESS *procsub_search PARAMS((pid_t));
extern PROCESS *procsub_delete PARAMS((pid_t));
extern int procsub_waitpid PARAMS((pid_t));
extern void procsub_waitall PARAMS((void));
extern void procsub_clear PARAMS((void));
extern void procsub_prune PARAMS((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));
extern void delete_job PARAMS((int, int));
extern void nohup_job PARAMS((int));
extern void delete_all_jobs PARAMS((int));
extern void nohup_all_jobs PARAMS((int));
extern int count_all_jobs PARAMS((void));
extern void terminate_current_pipeline PARAMS((void));
extern void terminate_stopped_jobs PARAMS((void));
extern void hangup_all_jobs PARAMS((void));
extern void kill_current_pipeline PARAMS((void));
#if defined (__STDC__) && defined (pid_t)
extern int get_job_by_pid __P((int, int));
extern void describe_pid __P((int));
extern int get_job_by_pid PARAMS((int, int));
extern void describe_pid PARAMS((int));
#else
extern int get_job_by_pid __P((pid_t, int));
extern void describe_pid __P((pid_t));
extern int get_job_by_pid PARAMS((pid_t, int));
extern void describe_pid PARAMS((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 void list_one_job PARAMS((JOB *, int, int, int));
extern void list_all_jobs PARAMS((int));
extern void list_stopped_jobs PARAMS((int));
extern void list_running_jobs PARAMS((int));
extern pid_t make_child __P((char *, int));
extern pid_t make_child PARAMS((char *, int));
extern int get_tty_state __P((void));
extern int set_tty_state __P((void));
extern int get_tty_state PARAMS((void));
extern int set_tty_state PARAMS((void));
extern int job_exit_status __P((int));
extern int job_exit_signal __P((int));
extern int job_exit_status PARAMS((int));
extern int job_exit_signal PARAMS((int));
extern int wait_for_single_pid __P((pid_t, int));
extern void wait_for_background_pids __P((struct procstat *));
extern int wait_for __P((pid_t));
extern int wait_for_job __P((int, int, struct procstat *));
extern int wait_for_any_job __P((int, struct procstat *));
extern int wait_for_single_pid PARAMS((pid_t, int));
extern void wait_for_background_pids PARAMS((struct procstat *));
extern int wait_for PARAMS((pid_t));
extern int wait_for_job PARAMS((int, int, struct procstat *));
extern int wait_for_any_job PARAMS((int, struct procstat *));
extern void wait_sigint_cleanup __P((void));
extern void wait_sigint_cleanup PARAMS((void));
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 notify_and_cleanup PARAMS((void));
extern void reap_dead_jobs PARAMS((void));
extern int start_job PARAMS((int, int));
extern int kill_pid PARAMS((pid_t, int, int));
extern int initialize_job_control PARAMS((int));
extern void initialize_job_signals PARAMS((void));
extern int give_terminal_to PARAMS((pid_t, int));
extern void run_sigchld_trap __P((int));
extern void run_sigchld_trap PARAMS((int));
extern int freeze_jobs_list __P((void));
extern void unfreeze_jobs_list __P((void));
extern void set_jobs_list_frozen __P((int));
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));
extern void get_original_tty_job_signals __P((void));
extern int freeze_jobs_list PARAMS((void));
extern void unfreeze_jobs_list PARAMS((void));
extern void set_jobs_list_frozen PARAMS((int));
extern int set_job_control PARAMS((int));
extern void without_job_control PARAMS((void));
extern void end_job_control PARAMS((void));
extern void restart_job_control PARAMS((void));
extern void set_sigchld_handler PARAMS((void));
extern void ignore_tty_job_signals PARAMS((void));
extern void default_tty_job_signals PARAMS((void));
extern void get_original_tty_job_signals PARAMS((void));
extern void init_job_stats __P((void));
extern void init_job_stats PARAMS((void));
extern void close_pgrp_pipe __P((void));
extern void save_pgrp_pipe __P((int *, int));
extern void restore_pgrp_pipe __P((int *));
extern void close_pgrp_pipe PARAMS((void));
extern void save_pgrp_pipe PARAMS((int *, int));
extern void restore_pgrp_pipe PARAMS((int *));
extern void set_maxchild __P((int));
extern void set_maxchild PARAMS((int));
extern int job_control; /* set to 0 in nojobs.c */
+3 -1
View File
@@ -605,7 +605,9 @@ static void
init_line_structures (int minsize)
{
register int n;
int osize;
osize = minsize;
if (minsize <= _rl_screenwidth) /* XXX - for gdb */
minsize = _rl_screenwidth + 1;
@@ -625,7 +627,7 @@ init_line_structures (int minsize)
invisible_line = (char *)xrealloc (invisible_line, line_size);
}
for (n = minsize; n < line_size; n++)
for (n = osize; n < line_size; n++)
{
visible_line[n] = 0;
invisible_line[n] = 1;
+6 -4
View File
@@ -4435,7 +4435,7 @@ xparse_dolparen (base, string, indp, flags)
return ret;
}
/*itrace("xparse_dolparen: size = %d shell_input_line = `%s'", shell_input_line_size, shell_input_line);*/
/*itrace("xparse_dolparen: size = %d shell_input_line = `%s' string=`%s'", shell_input_line_size, shell_input_line, string);*/
sflags = SEVAL_NONINT|SEVAL_NOHIST|SEVAL_NOFREE;
if (flags & SX_NOLONGJMP)
sflags |= SEVAL_NOLONGJMP;
@@ -4459,11 +4459,13 @@ xparse_dolparen (base, string, indp, flags)
if (current_token == shell_eof_token)
yyclearin; /* might want to clear lookahead token unconditionally */
reset_parser ();
/* reset_parser() clears shell_input_line and associated variables, including
parser_state, so we want to reset things, then restore what we need. */
restore_input_line_state (&ls);
shell_eof_token = orig_eof_token;
restore_parser_state (&ps);
reset_parser ();
/* reset_parser clears shell_input_line and associated variables */
restore_input_line_state (&ls);
#if defined (ALIAS) || defined (DPAREN_ARITHMETIC)
pushed_string_list = saved_pushed_strings;
+1 -1
View File
@@ -584,7 +584,7 @@ termsig_handler (sig)
#if defined (PROCESS_SUBSTITUTION)
unlink_fifo_list ();
# if defined (JOB_CONTROL)
discard_last_procsub_child ();
procsub_clear ();
# endif
#endif /* PROCESS_SUBSTITUTION */
+2 -3
View File
@@ -23,7 +23,7 @@
#if !defined (HAVE_SYS_SIGLIST) && !defined (HAVE_UNDER_SYS_SIGLIST) && !defined (HAVE_STRSIGNAL)
#include <stdio.h>
#include "bashtypes.h"
#include "general.h"
#include <signal.h>
#include "siglist.h"
@@ -33,7 +33,6 @@
#endif
#include "bashintl.h"
#include "xmalloc.h"
char *sys_siglist[NSIG];
@@ -220,7 +219,7 @@ initialize_siglist ()
if (!sys_siglist[i])
{
sys_siglist[i] =
(char *)xmalloc (10 + strlen (_("Unknown Signal #")));
(char *)xmalloc (INT_STRLEN_BOUND (int) + 1 + strlen (_("Unknown Signal #%d")));
sprintf (sys_siglist[i], _("Unknown Signal #%d"), i);
}
+15 -4
View File
@@ -5539,6 +5539,8 @@ reap_procsubs ()
reap_some_procsubs (nfifo);
}
#if 0
/* UNUSED */
void
wait_procsubs ()
{
@@ -5549,11 +5551,12 @@ wait_procsubs ()
if (fifo_list[i].proc != (pid_t)-1 && fifo_list[i].proc > 0)
{
r = wait_for (fifo_list[i].proc);
/* add to bgpids list? have to make interface public */
save_proc_status (fifo_list[i].proc, r);
fifo_list[i].proc = (pid_t)-1;
}
}
}
#endif
int
fifos_pending ()
@@ -5773,6 +5776,8 @@ reap_procsubs ()
reap_some_procsubs (totfds);
}
#if 0
/* UNUSED */
void
wait_procsubs ()
{
@@ -5783,11 +5788,12 @@ wait_procsubs ()
if (dev_fd_list[i] != (pid_t)-1 && dev_fd_list[i] > 0)
{
r = wait_for (dev_fd_list[i]);
/* add to bgpids list? have to make interface public */
save_proc_status (dev_fd_list[i], r);
dev_fd_list[i] = (pid_t)-1;
}
}
}
#endif
#if defined (NOTDEF)
print_dev_fd_list ()
@@ -5937,9 +5943,11 @@ process_substitute (string, open_for_read_in_child)
if (pid > 0)
{
#if defined (JOB_CONTROL)
if (last_procsub_child)
discard_last_procsub_child ();
last_procsub_child = restore_pipeline (0);
/* We assume that last_procsub_child->next == last_procsub_child because
of how jobs.c:add_process() works. */
last_procsub_child->next = 0;
procsub_add (last_procsub_child);
#endif
#if defined (HAVE_DEV_FD)
@@ -5967,6 +5975,9 @@ process_substitute (string, open_for_read_in_child)
/* make sure we don't have any job control */
set_job_control (0);
/* Clear out any existing list of process substitutions */
procsub_clear ();
/* The idea is that we want all the jobs we start from an async process
substitution to be in the same process group, but not the same pgrp
as our parent shell, since we don't want to affect our parent shell's
+1 -1
View File
@@ -19,7 +19,7 @@ declare: usage: declare [-aAfFgilnrtux] [-p] [name[=value] ...]
./errors.tests: line 74: declare: `/bin/sh': not a valid identifier
./errors.tests: line 78: declare: cannot use `-f' to make functions
./errors.tests: line 81: exec: -i: invalid option
exec: usage: exec [-cl] [-a name] [command [arguments ...]] [redirection ...]
exec: usage: exec [-cl] [-a name] [command [argument ...]] [redirection ...]
./errors.tests: line 85: export: XPATH: not a function
./errors.tests: line 88: break: only meaningful in a `for', `while', or `until' loop
./errors.tests: line 89: continue: only meaningful in a `for', `while', or `until' loop
+3 -3
View File
@@ -1,9 +1,9 @@
getopts: usage: getopts optstring name [arg]
getopts: usage: getopts optstring name [arg ...]
2
getopts: usage: getopts optstring name [arg]
getopts: usage: getopts optstring name [arg ...]
2
./getopts.tests: line 23: getopts: -a: invalid option
getopts: usage: getopts optstring name [arg]
getopts: usage: getopts optstring name [arg ...]
-a specified
-b bval specified
remaining args: one two three