fix comsub inside parameter expansion in here-document; fix readline longjmp botch; posix change for unset non-identifier; posix change for double quotes inside backquote comsub in here-document; add missing posix pieces to umask builtin

This commit is contained in:
Chet Ramey
2022-12-19 09:38:15 -05:00
parent 49918d90cd
commit c4a2e37470
26 changed files with 360 additions and 100 deletions
+78
View File
@@ -4667,3 +4667,81 @@ subst.c
- parameter_brace_expand_length: handle namerefs with values that are
valid length expansion expressions but invalid identifiers. From
ed7-aspire4925@hotmail.com via https://savannah.gnu.org/support/?110799
12/13
-----
subst.c
- extract_heredoc_dolbrace_string: fix off-by-one error after calling
extract_command_subst and extract_process_subst that caused it to
copy one too many parsed characters. Fix for bug reported by
Norbert Lange <nolange79@gmail.com>
12/14
-----
execute_cmd.c
- execute_cond_node: if a regular expression fails to compile, print
an error message. Report from Emanuele Torre <torreemanuele6@gmail.com>
back on 6/15/2022
trap.c
- trap_variable_context -> trap_return_context, initialize from
funcnest + sourcenest instead of variable_context so we handle
shell function execution and `./source', both of which can use
`return'. Idea from Koichi Murase <myoga.murase@gmail.com>
builtins/common.c
- get_exitstat: compare trap_return_context against funcnest+sourcenest,
since that's how it's initialized now
lib/readline/readline.c
- readline_internal_charloop: if we're not using the callback interface,
don't restore _rl_top_level from olevel, since we will just be going
around the loop again and will potentially need to use it multiple
times. Report from Emanuele Torre <torreemanuele6@gmail.com>
12/15
-----
shell.h
- EX_UTILERROR: new generic special builtin return status to indicate a
POSIX utility error that should cause a non-interactive shell to abort
execute_cmd.c
- builtin_status: translate EX_UTILERROR to EXECUTION_FAILURE
builtins/set.def
- unset_builtin: return EX_UTILERROR if posix_utility_error is set;
set it when trying to unset a non-identifier (variable) or a
non-unsettable or readonly variable
12/16
-----
subst.c
- de_backslash: now takes a second argument with the current quoting
flags
- de_backslash: if the quoting flags include Q_HERE_DOCUMENT and the
shell is in posix mode, remove backslashes quoting double quotes
subst.h
- de_backslash: update extern declaration
lib/readline/histexpand.c
- history_expand_internal,get_history_word_specifier,get_subst_pattern,
hist_error,history_find_word,hist_string_extract_single_quoted:
now take const char * string arguments
lib/readline/mbutil.c
- _rl_get_char_len,_rl_adjust_point,_rl_find_next_mbchar_internal,
_rl_find_next_mbchar,_rl_find_prev_mbchar,_rl_find_prev_mbchar_internal,
_rl_test_nonzero,_rl_find_prev_utf8char,_rl_is_mbchar_matched,
_rl_compare_chars,_rl_char_value: take const char * string arguments
12/17
-----
builtins/umask.def
- parse_symbolic_umask: add missing POSIX pieces:
o `action' of ugo, meaning to copy portions of initial mask
o multiple `op' specs as part of the action string (`u=r-w')
(resets perm)
o missing perm characters Xst in action string
o default `who' equivalent to `a' instead of fixing up later
+1
View File
@@ -978,6 +978,7 @@ tests/builtins4.sub f
tests/builtins5.sub f
tests/builtins6.sub f
tests/builtins7.sub f
tests/builtins8.sub f
tests/source1.sub f
tests/source2.sub f
tests/source3.sub f
+1 -1
View File
@@ -573,7 +573,7 @@ get_exitstat (list)
trap gets to change $?, though, since that is part of its reason for
existing, and because the extended debug mode does things with the
return value. */
if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1 && variable_context == trap_variable_context)
if (this_shell_builtin == return_builtin && running_trap > 0 && running_trap != DEBUG_TRAP+1 && trap_return_context == funcnest + sourcenest)
return (trap_saved_exit_value);
return (last_command_exit_value);
}
+11 -4
View File
@@ -836,9 +836,11 @@ unset_builtin (list)
{
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
int global_unset_func, global_unset_var, vflags, base_vflags, valid_id;
int posix_utility_error;
char *name, *tname;
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
unset_function = unset_variable = unset_array = nameref = 0;
posix_utility_error = any_failed = 0;
global_unset_func = global_unset_var = 0;
reset_internal_getopt ();
@@ -918,6 +920,7 @@ unset_builtin (list)
if (unset_function == 0 && valid_id == 0)
{
sh_invalidid (name);
posix_utility_error++;
NEXT_VARIABLE ();
}
@@ -930,6 +933,7 @@ unset_builtin (list)
if (var && unset_function == 0 && non_unsettable_p (var))
{
builtin_error (_("%s: cannot unset"), name);
posix_utility_error++;
NEXT_VARIABLE ();
}
@@ -952,6 +956,7 @@ unset_builtin (list)
{
builtin_error (_("%s: cannot unset: readonly %s"),
var->name, unset_function ? "function" : "variable");
posix_utility_error++;
NEXT_VARIABLE ();
}
@@ -1008,8 +1013,10 @@ unset_builtin (list)
/* This is what Posix.2 says: ``If neither -f nor -v
is specified, the name refers to a variable; if a variable by
that name does not exist, a function by that name, if any,
shall be unset.'' */
that name does not exist, it is unspecified whether a function
by that name, if any, shall be unset.'' The unspecified part is a
recent addition, so we continue to try to unset a shell function if
we don't find a variable named NAME. */
if (tem == -1 && nameref == 0 && unset_function == 0 && unset_variable == 0)
tem = unbind_func (name);
@@ -1024,5 +1031,5 @@ unset_builtin (list)
list = list->next;
}
return (any_failed ? EXECUTION_FAILURE : EXECUTION_SUCCESS);
return (any_failed ? (posix_utility_error ? EX_UTILERROR : EXECUTION_FAILURE) : EXECUTION_SUCCESS);
}
+102 -36
View File
@@ -1,7 +1,7 @@
This file is umask.def, from which is created umask.c.
It implements the builtin "umask" in Bash.
Copyright (C) 1987-2020 Free Software Foundation, Inc.
Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -186,17 +186,46 @@ print_symbolic_umask (um)
printf ("u=%s,g=%s,o=%s\n", ubits, gbits, obits);
}
static inline mode_t
copyuser (mask)
mode_t mask;
{
return ((mask & S_IRUSR) ? S_IRUGO : 0) |
((mask & S_IWUSR) ? S_IWUGO : 0) |
((mask & S_IXUSR) ? S_IXUGO : 0);
}
static inline mode_t
copygroup (mask)
mode_t mask;
{
return ((mask & S_IRGRP) ? S_IRUGO : 0) |
((mask & S_IWGRP) ? S_IWUGO : 0) |
((mask & S_IXGRP) ? S_IXUGO : 0);
}
static inline mode_t
copyother (mask)
mode_t mask;
{
return ((mask & S_IROTH) ? S_IRUGO : 0) |
((mask & S_IWOTH) ? S_IWUGO : 0) |
((mask & S_IXOTH) ? S_IXUGO : 0);
}
int
parse_symbolic_mode (mode, initial_bits)
char *mode;
int initial_bits;
mode_t initial_bits;
{
int who, op, perm, bits, c;
char op, c;
mode_t who, perm, bits;
char *s;
for (s = mode, bits = initial_bits;;)
{
who = op = perm = 0;
who = 0;
op = 0;
/* Parse the `who' portion of the symbolic mode clause. */
while (member (*s, "agou"))
@@ -220,7 +249,13 @@ parse_symbolic_mode (mode, initial_bits)
}
}
/* default `who' is `a' */
if (who == 0)
who = S_IRWXU | S_IRWXG | S_IRWXO;
/* The operation is now sitting in *s. */
start_op:
perm = 0;
op = *s++;
switch (op)
{
@@ -233,57 +268,87 @@ parse_symbolic_mode (mode, initial_bits)
return (-1);
}
/* Parse out the `perm' section of the symbolic mode clause. */
while (member (*s, "rwx"))
/* Parse out the `action' section of the symbolic mode clause. An
action can be a set of permissions (rwxXst), a copy specification
(ugo), or another op (+-=). */
while (member (*s, "rwxXstugo"))
{
c = *s++;
switch (c)
switch (*s)
{
/* First the copy specification */
case 'u':
perm = copyuser (initial_bits);
break;
case 'g':
perm = copygroup (initial_bits);
break;
case 'o':
perm = copyother (initial_bits);
break;
/* Then the permissions. */
case 'r':
perm |= S_IRUGO;
break;
case 'w':
perm |= S_IWUGO;
break;
case 'X':
/* for chmod, this includes S_ISDIR but that doesn't make sense here */
if ((initial_bits & S_IXUGO) == 0)
break; /* no-op if original mask doesn't include execute bits */
/* FALLTHROUGH */
case 'x':
perm |= S_IXUGO;
break;
case 's':
#ifdef S_ISUID
perm |= S_ISUID | S_ISGID;
break;
#else
goto spec_error;
#endif
case 't':
#ifdef S_ISVTX
perm |= S_ISVTX;
break;
#else
goto spec_error;
#endif
}
s++;
}
/* Now perform the operation or return an error for a
bad permission string. */
if (!*s || *s == ',')
perm &= who;
switch (op)
{
if (who)
perm &= who;
switch (op)
{
case '+':
bits |= perm;
break;
case '-':
bits &= ~perm;
break;
case '=':
if (who == 0)
who = S_IRWXU | S_IRWXG | S_IRWXO;
bits &= ~who;
bits |= perm;
break;
/* No other values are possible. */
}
if (*s == '\0')
break;
else
s++; /* skip past ',' */
case '+':
bits |= perm;
break;
case '-':
bits &= ~perm;
break;
case '=':
bits &= ~who;
bits |= perm;
break;
}
/* Break if the end of the action string, loop if we're going to parse
another `who', go back to parsing another op if we have an op spec
(+-=). Return an invalid mode character error for everything else. */
if (*s == '\0')
break;
else if (*s == ',')
s++; /* skip past ',' */
else if (*s == '+' || *s == '-' || *s == '=')
goto start_op;
else
{
spec_error:
builtin_error (_("`%c': invalid symbolic mode character"), *s);
return (-1);
}
@@ -299,7 +364,8 @@ static int
symbolic_umask (list)
WORD_LIST *list;
{
int um, bits;
mode_t um;
int bits;
/* Get the initial umask. Don't change it yet. */
um = umask (022);
+13
View File
@@ -8248,6 +8248,12 @@ the @sc{posix} standard, and include things like passing incorrect options,
redirection errors, variable assignment errors for assignments preceding
the command name, and so on.
@item
The @code{unset} builtin with the @option{-v} option specified returns a
fatal error if it attempts to unset a @code{readonly} or @code{non-unsettable}
variable, or encounters a variable name argument that is an invalid identifier,
which causes a non-interactive shell to exit.
@item
A non-interactive shell exits with an error status if a variable
assignment error occurs when no command name follows the assignment
@@ -8434,6 +8440,13 @@ arguments corresponding to floating point conversion specifiers, instead of
Bash removes an exited background process's status from the list of such
statuses after the @code{wait} builtin is used to obtain it.
@item
A double quote character (@samp{"}) is treated specially when it appears
in a backquoted command substitution in the body of a here-document that
undergoes expansion.
That means, for example, that a backslash preceding a double quote
character will escape it and the backslash will be removed.
@end enumerate
There is other @sc{posix} behavior that Bash does not implement by
+3
View File
@@ -4014,6 +4014,8 @@ execute_cond_node (cond)
#endif
result = sh_regmatch (arg1, arg2, mflags);
if (result == 2)
builtin_error (_("invalid regular expression `%s'"), arg2);
}
else
#endif /* COND_REGEXP */
@@ -4869,6 +4871,7 @@ builtin_status (result)
case EX_REDIRFAIL:
case EX_BADASSIGN:
case EX_EXPFAIL:
case EX_UTILERROR:
r = EXECUTION_FAILURE;
break;
default:
-1
View File
@@ -2732,7 +2732,6 @@ int
rl_forced_update_display (void)
{
register char *temp;
register int tlen;
if (visible_line)
memset (visible_line, 0, line_size);
+8 -8
View File
@@ -70,12 +70,12 @@ static int subst_rhs_len;
specifications from word designators. Static for now */
static char *history_event_delimiter_chars = HISTORY_EVENT_DELIMITERS;
static char *get_history_word_specifier (char *, char *, int *);
static char *get_history_word_specifier (const char *, char *, int *);
static int history_tokenize_word (const char *, int);
static char **history_tokenize_internal (const char *, int, int *);
static char *history_substring (const char *, int, int);
static void freewords (char **, int);
static char *history_find_word (char *, int);
static char *history_find_word (const char *, int);
static char *quote_breaks (char *);
@@ -319,7 +319,7 @@ get_history_event (const char *string, int *caller_index, int delimiting_quote)
to the closing single quote. FLAGS currently used to allow backslash
to escape a single quote (e.g., for bash $'...'). */
static void
hist_string_extract_single_quoted (char *string, int *sindex, int flags)
hist_string_extract_single_quoted (const char *string, int *sindex, int flags)
{
register int i;
@@ -374,7 +374,7 @@ quote_breaks (char *s)
}
static char *
hist_error(char *s, int start, int current, int errtype)
hist_error(const char *s, int start, int current, int errtype)
{
char *temp;
const char *emsg;
@@ -434,7 +434,7 @@ hist_error(char *s, int start, int current, int errtype)
subst_rhs is allowed to be set to the empty string. */
static char *
get_subst_pattern (char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
get_subst_pattern (const char *str, int *iptr, int delimiter, int is_rhs, int *lenptr)
{
register int si, i, j, k;
char *s;
@@ -527,7 +527,7 @@ postproc_subst_rhs (void)
*END_INDEX_PTR, and the expanded specifier in *RET_STRING. */
/* need current line for !# */
static int
history_expand_internal (char *string, int start, int qc, int *end_index_ptr, char **ret_string, char *current_line)
history_expand_internal (const char *string, int start, int qc, int *end_index_ptr, char **ret_string, char *current_line)
{
int i, n, starting_index;
int substitute_globally, subst_bywords, want_quotes, print_only;
@@ -1303,7 +1303,7 @@ history_expand (char *hstring, char **output)
CALLER_INDEX is the offset in SPEC to start looking; it is updated
to point to just after the last character parsed. */
static char *
get_history_word_specifier (char *spec, char *from, int *caller_index)
get_history_word_specifier (const char *spec, char *from, int *caller_index)
{
register int i = *caller_index;
int first, last;
@@ -1696,7 +1696,7 @@ freewords (char **words, int start)
in the history line LINE. Used to save the word matched by the
last history !?string? search. */
static char *
history_find_word (char *line, int ind)
history_find_word (const char *line, int ind)
{
char **words, *s;
int i, wind;
+12 -12
View File
@@ -148,7 +148,7 @@ _rl_utf8_mblen (const char *s, size_t n)
}
static int
_rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_zero)
_rl_find_next_mbchar_internal (const char *string, int seed, int count, int find_non_zero)
{
size_t tmp, len;
mbstate_t ps;
@@ -228,7 +228,7 @@ _rl_find_next_mbchar_internal (char *string, int seed, int count, int find_non_z
}
static inline int
_rl_test_nonzero (char *string, int ind, int len)
_rl_test_nonzero (const char *string, int ind, int len)
{
size_t tmp;
WCHAR_T wc;
@@ -242,7 +242,7 @@ _rl_test_nonzero (char *string, int ind, int len)
/* experimental -- needs to handle zero-width characters better */
static int
_rl_find_prev_utf8char (char *string, int seed, int find_non_zero)
_rl_find_prev_utf8char (const char *string, int seed, int find_non_zero)
{
char *s;
unsigned char b;
@@ -288,7 +288,7 @@ _rl_find_prev_utf8char (char *string, int seed, int find_non_zero)
}
/*static*/ int
_rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero)
_rl_find_prev_mbchar_internal (const char *string, int seed, int find_non_zero)
{
mbstate_t ps;
int prev, non_zero_prev, point, length;
@@ -356,7 +356,7 @@ _rl_find_prev_mbchar_internal (char *string, int seed, int find_non_zero)
if an invalid multibyte sequence was encountered. It returns (size_t)(-2)
if it couldn't parse a complete multibyte character. */
int
_rl_get_char_len (char *src, mbstate_t *ps)
_rl_get_char_len (const char *src, mbstate_t *ps)
{
size_t tmp, l;
int mb_cur_max;
@@ -368,7 +368,7 @@ _rl_get_char_len (char *src, mbstate_t *ps)
else
{
mb_cur_max = MB_CUR_MAX;
tmp = mbrlen((const char *)src, (l < mb_cur_max) ? l : mb_cur_max, ps);
tmp = mbrlen(src, (l < mb_cur_max) ? l : mb_cur_max, ps);
}
if (tmp == (size_t)(-2))
{
@@ -394,7 +394,7 @@ _rl_get_char_len (char *src, mbstate_t *ps)
/* compare the specified two characters. If the characters matched,
return 1. Otherwise return 0. */
int
_rl_compare_chars (char *buf1, int pos1, mbstate_t *ps1, char *buf2, int pos2, mbstate_t *ps2)
_rl_compare_chars (const char *buf1, int pos1, mbstate_t *ps1, const char *buf2, int pos2, mbstate_t *ps2)
{
int i, w1, w2;
@@ -417,7 +417,7 @@ _rl_compare_chars (char *buf1, int pos1, mbstate_t *ps1, char *buf2, int pos2, m
if point is invalid (point < 0 || more than string length),
it returns -1 */
int
_rl_adjust_point (char *string, int point, mbstate_t *ps)
_rl_adjust_point (const char *string, int point, mbstate_t *ps)
{
size_t tmp;
int length, pos;
@@ -457,7 +457,7 @@ _rl_adjust_point (char *string, int point, mbstate_t *ps)
}
int
_rl_is_mbchar_matched (char *string, int seed, int end, char *mbchar, int length)
_rl_is_mbchar_matched (const char *string, int seed, int end, char *mbchar, int length)
{
int i;
@@ -471,7 +471,7 @@ _rl_is_mbchar_matched (char *string, int seed, int end, char *mbchar, int length
}
WCHAR_T
_rl_char_value (char *buf, int ind)
_rl_char_value (const char *buf, int ind)
{
size_t tmp;
WCHAR_T wc;
@@ -500,7 +500,7 @@ _rl_char_value (char *buf, int ind)
characters. */
#undef _rl_find_next_mbchar
int
_rl_find_next_mbchar (char *string, int seed, int count, int flags)
_rl_find_next_mbchar (const char *string, int seed, int count, int flags)
{
#if defined (HANDLE_MULTIBYTE)
return _rl_find_next_mbchar_internal (string, seed, count, flags);
@@ -514,7 +514,7 @@ _rl_find_next_mbchar (char *string, int seed, int count, int flags)
we look for non-zero-width multibyte characters. */
#undef _rl_find_prev_mbchar
int
_rl_find_prev_mbchar (char *string, int seed, int flags)
_rl_find_prev_mbchar (const char *string, int seed, int flags)
{
#if defined (HANDLE_MULTIBYTE)
return _rl_find_prev_mbchar_internal (string, seed, flags);
+2 -1
View File
@@ -590,7 +590,8 @@ readline_internal_charloop (void)
{
(*rl_redisplay_function) ();
_rl_want_redisplay = 0;
memcpy ((void *)_rl_top_level, (void *)olevel, sizeof (procenv_t));
if (RL_ISSTATE (RL_STATE_CALLBACK))
memcpy ((void *)_rl_top_level, (void *)olevel, sizeof (procenv_t));
/* If we longjmped because of a timeout, handle it here. */
if (RL_ISSTATE (RL_STATE_TIMEOUT))
+7 -7
View File
@@ -104,21 +104,21 @@
#define MB_FIND_ANY 0x00
#define MB_FIND_NONZERO 0x01
extern int _rl_find_prev_mbchar (char *, int, int);
extern int _rl_find_next_mbchar (char *, int, int, int);
extern int _rl_find_prev_mbchar (const char *, int, int);
extern int _rl_find_next_mbchar (const char *, int, int, int);
#ifdef HANDLE_MULTIBYTE
extern int _rl_compare_chars (char *, int, mbstate_t *, char *, int, mbstate_t *);
extern int _rl_get_char_len (char *, mbstate_t *);
extern int _rl_adjust_point (char *, int, mbstate_t *);
extern int _rl_compare_chars (const char *, int, mbstate_t *, const char *, int, mbstate_t *);
extern int _rl_get_char_len (const char *, mbstate_t *);
extern int _rl_adjust_point (const char *, int, mbstate_t *);
extern int _rl_read_mbchar (char *, int);
extern int _rl_read_mbstring (int, char *, int);
extern int _rl_is_mbchar_matched (char *, int, int, char *, int);
extern int _rl_is_mbchar_matched (const char *, int, int, char *, int);
extern WCHAR_T _rl_char_value (char *, int);
extern WCHAR_T _rl_char_value (const char *, int);
extern int _rl_walphabetic (WCHAR_T);
#define _rl_to_wupper(wc) (iswlower (wc) ? towupper (wc) : (wc))
-5
View File
@@ -3072,12 +3072,7 @@ alias_expand_token (tokstr)
char *expanded;
alias_t *ap;
#if 0
if (((parser_state & PST_ALEXPNEXT) || command_token_position (last_read_token)) &&
(parser_state & PST_CASEPAT) == 0)
#else
if ((parser_state & PST_ALEXPNEXT) || assignment_acceptable (last_read_token))
#endif
{
ap = find_alias (tokstr);
+1 -1
View File
@@ -25,6 +25,6 @@
regexp `^#define[ ]*PATCHLEVEL', since that's what support/mkversion.sh
looks for to find the patch level (for the sccs version string). */
#define PATCHLEVEL 12
#define PATCHLEVEL 15
#endif /* _PATCHLEVEL_H_ */
+1
View File
@@ -73,6 +73,7 @@ extern int EOF_Reached;
#define EX_BADASSIGN 260 /* variable assignment error */
#define EX_EXPFAIL 261 /* word expansion failed */
#define EX_DISKFALLBACK 262 /* fall back to disk command from builtin */
#define EX_UTILERROR 263 /* Posix special builtin utility error */
/* Flag values that control parameter pattern substitution. */
#define MATCH_ANY 0x000
+7 -5
View File
@@ -85,7 +85,6 @@ extern int errno;
#define VT_STARSUB 128 /* $* or ${array[*]} -- used to split */
/* Flags for quoted_strchr */
#define ST_BACKSL 0x01
#define ST_CTLESC 0x02
@@ -1699,7 +1698,7 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
t = extract_command_subst (string, &si, flags);
CHECK_STRING_OVERRUN (i, si, slen, c);
tlen = si - i - 1;
tlen = si - i - 2;
RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
result[result_index++] = c;
result[result_index++] = LPAREN;
@@ -1719,7 +1718,7 @@ extract_heredoc_dolbrace_string (string, sindex, quoted, flags)
t = extract_process_subst (string, (string[i] == '<' ? "<(" : ">)"), &si, flags);
CHECK_STRING_OVERRUN (i, si, slen, c);
tlen = si - i - 1;
tlen = si - i - 2;
RESIZE_MALLOCED_BUFFER (result, result_index, tlen + 4, result_size, 64);
result[result_index++] = c;
result[result_index++] = LPAREN;
@@ -2002,8 +2001,9 @@ extract_dollar_brace_string (string, sindex, quoted, flags)
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
char *
de_backslash (string)
de_backslash (string, qflags)
char *string;
int qflags;
{
register size_t slen;
register int i, j, prev_i;
@@ -2018,6 +2018,8 @@ de_backslash (string)
if (string[i] == '\\' && (string[i + 1] == '`' || string[i + 1] == '\\' ||
string[i + 1] == '$'))
i++;
else if (posixly_correct && (qflags & Q_HERE_DOCUMENT) && string[i] == '\\' && string[i + 1] == '"')
i++;
prev_i = i;
ADVANCE_CHAR (string, slen, i);
if (j < prev_i)
@@ -11327,7 +11329,7 @@ add_string:
temp1 = substring (string, t_index, sindex + 1);
else
{
de_backslash (temp);
de_backslash (temp, quoted);
tword = command_substitute (temp, quoted, PF_BACKQUOTE);
temp1 = tword ? tword->word : (char *)NULL;
if (tword)
+1 -1
View File
@@ -75,7 +75,7 @@
/* Remove backslashes which are quoting backquotes from STRING. Modifies
STRING, and returns a pointer to it. */
extern char * de_backslash PARAMS((char *));
extern char * de_backslash PARAMS((char *, int));
/* Replace instances of \! in a string with !. */
extern void unquote_bang PARAMS((char *));
+14 -1
View File
@@ -278,4 +278,17 @@ type
+ command -p -- command -v type
type
+ set +x
./builtins.tests: line 284: exit: status: numeric argument required
u=rw,g=rx,o=rx
u=r,g=rx,o=rx
u=rwx,g=rwx,o=
u=rw,g=wx,o=rx
u=rx,g=rx,o=rx
u=rwx,g=rx,o=rwx
u=rwx,g=rwx,o=rx
u=rx,g=rx,o=rx
u=rwx,g=rx,o=rx
u=rwx,g=rwx,o=rwx
u=rwx,g=rwx,o=rwx
u=rwx,g=rx,o=rx
u=rwx,g=rx,o=rx
./builtins.tests: line 287: exit: status: numeric argument required
+4 -1
View File
@@ -87,7 +87,7 @@ BVAR=xxx eval echo $AVAR
unset -v AVAR BVAR
# test umask
# basic umask tests
mask=$(umask)
umask 022
umask
@@ -280,6 +280,9 @@ ${THIS_SH} ./builtins6.sub
# test behavior of command builtin after changing it to a pseudo-keyword
${THIS_SH} ./builtins7.sub
# POSIX complete symbolic umask tests
${THIS_SH} ./builtins8.sub
# this must be last -- it is a fatal error
exit status
+54
View File
@@ -0,0 +1,54 @@
umask 022
umask u=r+w
umask -S
umask 022
umask u=r-w
umask -S
umask 022
umask g+u,o+rwx-u
umask -S
umask 022
umask u=r+w,g=wx,o+xr
umask -S
umask 022
umask u+w=r+x
umask -S
umask 022
umask o=u
umask -S
umask 022
umask g=u
umask -S
umask 022
umask u=rwx,u-w
umask -S
umask 022
umask u=xwr
umask -S
umask 022
umask +xwr
umask -S
umask 022
umask a+xwr
umask -S
umask 022
umask +xr
umask -S
umask 022
umask a+xr
umask -S
+5
View File
@@ -76,6 +76,11 @@ echo $(echo $( echo nested )
)
)
BUILDDIR=/builds/test
read << EOC
Dir: ${BUILDDIR#<(echo a)/}
EOC
${THIS_SH} ./comsub1.sub
${THIS_SH} ./comsub2.sub
${THIS_SH} ./comsub3.sub
+1
View File
@@ -76,6 +76,7 @@ match control-a 2
match control-a 3
match control-a 4
match control-a 5
./cond-regexp2.sub: line 18: [[: invalid regular expression `[\.'
ok 1
ok 2
ok 3
+7 -2
View File
@@ -48,7 +48,7 @@ hash: usage: hash [-lr] [-p pathname] [-dt] [name ...]
./errors.tests: line 157: umask: `:': invalid symbolic mode operator
./errors.tests: line 160: umask: -i: invalid option
umask: usage: umask [-p] [-S] [mode]
./errors.tests: line 164: umask: `u': invalid symbolic mode character
./errors.tests: line 164: umask: `p': invalid symbolic mode character
./errors.tests: line 173: VAR: readonly variable
./errors.tests: line 176: declare: VAR: readonly variable
./errors.tests: line 177: declare: VAR: readonly variable
@@ -210,4 +210,9 @@ DEBUG
bash: line 1: return: can only `return' from a function or sourced script
after return
bash: line 1: return: can only `return' from a function or sourced script
./errors.tests: line 305: `!!': not a valid identifier
sh: line 1: unset: a: cannot unset: readonly variable
sh: line 1: unset: `a-b': not a valid identifier
sh: line 1: /nosuchfile: No such file or directory
sh: line 1: trap: SIGNOSIG: invalid signal specification
after trap
./errors.tests: line 316: `!!': not a valid identifier
+12 -1
View File
@@ -161,7 +161,7 @@ umask -i
# bad assignments shouldn't change the umask
mask=$(umask)
umask g=u
umask g=p
mask2=$(umask)
if [ "$mask" != "$mask2" ]; then
echo "umask errors change process umask"
@@ -297,6 +297,17 @@ ${THIS_SH} ./errors9.sub
${THIS_SH} -c 'return ; echo after return' bash
${THIS_SH} -o posix -c 'return ; echo after return' bash
# various posix-mode special builtin fatal (or not) errors
# posix says unsetting readonly variables is a fatal error
${THIS_SH} -o posix -c 'readonly a=a ; unset -v a; echo after unset 1' sh
# the same with non-identifiers
${THIS_SH} -o posix -c 'unset -v a-b; echo after unset 2' sh
# and sourcing a non-existent file is fatal too
${THIS_SH} -o posix -c '. /nosuchfile ; echo after source' sh
# but trap specifying a bad signal nunber is non-fatal
${THIS_SH} -o posix -c 'trap "echo bad" SIGNOSIG; echo after trap' sh
# this must be last!
# in posix mode, a function name must be a valid identifier
# this can't go in posix2.tests, since it causes the shell to exit
+14 -12
View File
@@ -1,7 +1,7 @@
/* trap.c -- Not the trap command, but useful functions for manipulating
those objects. The trap command is in builtins/trap.def. */
/* Copyright (C) 1987-2021 Free Software Foundation, Inc.
/* Copyright (C) 1987-2022 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -113,9 +113,11 @@ int pending_traps[NSIG];
trap command (e.g., when `return' is executed in the trap command). */
int running_trap;
/* The variable context (function execution level) when we began running
this trap command. */
int trap_variable_context;
/* The execution context (function/source execution level) when we began
running this trap command. This is used to determine whether we have
executed any shell functions or sourced files from the trap action, and
determines where `return' without arguments gets its return status. */
int trap_return_context;
/* Set to last_command_exit_value before running a trap. */
int trap_saved_exit_value;
@@ -341,7 +343,7 @@ run_pending_traps ()
ps = save_pipestatus_array ();
#endif
old_running = running_trap;
old_context = trap_variable_context;
old_context = trap_return_context;
for (sig = 1; sig < NSIG; sig++)
{
@@ -351,7 +353,7 @@ run_pending_traps ()
{
/* XXX - set last_command_exit_value = trap_saved_exit_value here? */
running_trap = sig + 1;
trap_variable_context = variable_context;
trap_return_context = funcnest + sourcenest;
if (sig == SIGINT)
{
@@ -477,7 +479,7 @@ run_pending_traps ()
if (function_code)
{
running_trap = old_running; /* XXX */
trap_variable_context = old_context;
trap_return_context = old_context;
/* caller will set last_command_exit_value */
sh_longjmp (return_catch, 1);
}
@@ -486,7 +488,7 @@ run_pending_traps ()
pending_traps[sig] = 0; /* XXX - move before evalstring? */
running_trap = old_running;
trap_variable_context = old_context;
trap_return_context = old_context;
}
}
@@ -1006,7 +1008,7 @@ run_exit_trap ()
retval = trap_saved_exit_value;
running_trap = 1;
trap_variable_context = variable_context;
trap_return_context = funcnest + sourcenest;
code = setjmp_nosigs (top_level);
@@ -1091,14 +1093,14 @@ _run_trap_internal (sig, tag)
old_trap = trap_list[sig];
old_modes = sigmodes[sig];
old_running = running_trap;
old_context = trap_variable_context;
old_context = trap_return_context;
sigmodes[sig] |= SIG_INPROGRESS;
sigmodes[sig] &= ~SIG_CHANGED; /* just to be sure */
trap_command = savestring (old_trap);
running_trap = sig + 1;
trap_variable_context = variable_context;
trap_return_context = funcnest + sourcenest;
old_int = interrupt_state; /* temporarily suppress pending interrupts */
CLRINTERRUPT;
@@ -1161,7 +1163,7 @@ _run_trap_internal (sig, tag)
running_trap = old_running;
interrupt_state = old_int;
trap_variable_context = old_context;
trap_return_context = old_context;
if (sigmodes[sig] & SIG_CHANGED)
{
+1 -1
View File
@@ -63,7 +63,7 @@ extern char *trap_list[];
extern int trapped_signal_received;
extern int wait_signal_received;
extern int running_trap;
extern int trap_variable_context;
extern int trap_return_context;
extern int trap_saved_exit_value;
extern int suppress_debug_trap_verbose;