From dcb2f4489f921dc8b615a0bc402acbca396c759f Mon Sep 17 00:00:00 2001 From: Chet Ramey Date: Mon, 21 Sep 2015 17:02:33 -0400 Subject: [PATCH] commit bash-20150918 snapshot --- CHANGES | 9 ++++- CHANGES-4.4 | 9 ++++- CWRU/CWRU.chlog | 86 +++++++++++++++++++++++++++++++++++++++++ array.c | 5 ++- assoc.c | 14 ++++--- builtins/evalstring.c | 4 ++ builtins/exec.def | 9 ++++- config.h.in | 3 ++ configure | 12 ++++++ configure.ac | 1 + doc/bash.1 | 3 +- doc/bashref.texi | 3 +- lib/readline/history.c | 9 +++++ lib/readline/readline.c | 2 +- lib/readline/util.c | 2 +- parse.y | 34 ++++++++++++++-- shell.h | 4 ++ subst.c | 53 ++++++++++++++++++------- syntax.h | 2 + tests/array.right | 1 + tests/array21.sub | 6 +++ tests/exp.right | 2 +- tests/exp8.sub | 2 +- tests/nquote.right | 6 +++ tests/nquote.tests | 1 + tests/nquote3.sub | 6 +++ variables.c | 17 ++++++-- 27 files changed, 266 insertions(+), 39 deletions(-) create mode 100644 tests/nquote3.sub diff --git a/CHANGES b/CHANGES index 4bc2ac54..109906ad 100644 --- a/CHANGES +++ b/CHANGES @@ -1,5 +1,5 @@ -This document details the changes between this version, bash-4.4-alpha, and -the previous version, bash-4.3-release. +This document details the changes between this version, bash-4.4-beta, and +the previous version, bash-4.4-alpha. 1. Change to Bash @@ -80,6 +80,11 @@ y. Fixed a problem with the expansion of $'\c?'. z. Bash no longer splits the expansion of here-strings, as the documentation has always said. +aa. Bash now puts `s' in the value of $- if the shell is reading from standard + input. + +bb. Fixed a bug that caused the shell to crash if invoked with a NULL environment. + 2. Changes to Readline a. Colored completion prefixes are now displayed using a different color, less diff --git a/CHANGES-4.4 b/CHANGES-4.4 index d1f39b57..96429190 100644 --- a/CHANGES-4.4 +++ b/CHANGES-4.4 @@ -1,5 +1,5 @@ -This document details the changes between this version, bash-4.4-alpha, and -the previous version, bash-4.3-release. +This document details the changes between this version, bash-4.4-beta, and +the previous version, bash-4.4-alpha. 1. Change to Bash @@ -80,6 +80,11 @@ y. Fixed a problem with the expansion of $'\c?'. z. Bash no longer splits the expansion of here-strings, as the documentation has always said. +aa. Bash now puts `s' in the value of $- if the shell is reading from standard + input. + +bb. Fixed a bug that caused the shell to crash if invoked with a NULL environment. + 2. Changes to Readline a. Colored completion prefixes are now displayed using a different color, less diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index f021a5fd..200ed770 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -9570,3 +9570,89 @@ lib/readline/kill.c - _rl_copy_to_kill_ring: don't assume that rl_kill_ring has been allocated if _rl_last_command_was_kill is non-zero; make sure it's non-null before indexing into it + + 9/15 + ---- +variables.c + - initialize_shell_variables: cope with a NULL env pointer. Fixes bug + reported by ziyunfei <446240525@qq.com> + + 9/16 + ---- +builtins/exec.def + - exec_builtin: if -c is supplied, pass an empty array instead of a NULL + pointer to shell_execve + +variables.c + - set_pwd: only believe $PWD if it begins with a slash; try to canonicalize + it and set it to physical path if canonicalization fails. Reported by + ziyunfei <446240525@qq.com> + + 9/17 + ---- +subst.c + - do_compound_assignment: make sure to dispose of word list generated by + expand_compound_array_assignment; fixes memory leak reported in + https://bugzilla.redhat.com/show_bug.cgi?id=1264101 + +variables.c + - adjust_shell_level: clamp the value of shell_level at 1000 and reset + there, instead of > 1000, since the itos replacement code doesn't + handle the value 1000. Fixes bug reported by ziyunfei <446240525@qq.com> + +shell.h,parse.y + - save_parser_state,restore_parser_state: now save and restore redir_stack, + short-circuiting if need_here_doc == 0. If we save a non-zero value for + need_here_doc, we have to make sure there is something valid for + gather_here_documents to work on. Fixes bug reported by + Brian Carpenter + + 9/18 + ---- +array.c + - array_to_assign: use ansic_shouldquote to check whether each element + value contains non-printable characters and use ansic_quote to + generate the value instead of using sh_double_quote unconditionally + +assoc.c + - assoc_to_assign: if either the key or the value of an associative array + element contains non-printable characters (ansic_shouldquote returns + true), use ansic_quote to quote them instead of using double quotes + unconditionally + + 9/19 + ---- +subst.c + - pat_subst: handle REP being NULL. Fixes bug reported by Brian + Carpenter + +builtins/evalstring.c + - parse_string: if we get a longjmp to top_level with DISCARD as the + code (in which case we are going to go on), return -DISCARD to our + caller (always xparse_dolparen) after doing our own cleanup instead + of calling jump_to_top_level + +parse.y + - xparse_dolparen: if parse_string returns < 0, do the appropriate + cleanup and then jump_to_top_level with the negative of the return + value. This allows us to do the appropriate parser cleanup in + case we're not going to exit the shell. Fixes bug reported by Brian + Carpenter + +subst.c + - extract_delimited_string: if a recursive call to one of the extract_ + functions or a call to ADVANCE_CHAR leaves i past the end of the + string, cut the loop off at the end of the string. Fixes bug + reported by Brian Carpenter + + 9/20 + ---- +subst.c + - get_var_and_type: return appropriate values if variable indirection + results in a NULL variable. Fixes bug reported by Brian Carpenter + + +lib/readline/history.c + - history_get_time: handle strtol overflows caused by malicious + modifications to timestamps in the history file. Fixes issue + reported by rens@endoria.net diff --git a/array.c b/array.c index bf31acd0..230d2c9f 100644 --- a/array.c +++ b/array.c @@ -869,7 +869,10 @@ int quoted; for (ae = element_forw(a->head); ae != a->head; ae = element_forw(ae)) { is = inttostr (element_index(ae), indstr, sizeof(indstr)); - valstr = element_value (ae) ? sh_double_quote (element_value(ae)) + valstr = element_value (ae) ? + (ansic_shouldquote (element_value (ae)) ? + ansic_quote (element_value(ae), 0, (int *)0) : + sh_double_quote (element_value (ae))) : (char *)NULL; elen = STRLEN (is) + 8 + STRLEN (valstr); RESIZE_MALLOCED_BUFFER (result, rlen, (elen + 1), rsize, rsize); diff --git a/assoc.c b/assoc.c index bf160e58..84a387c2 100644 --- a/assoc.c +++ b/assoc.c @@ -436,17 +436,19 @@ assoc_to_assign (hash, quoted) for (i = 0; i < hash->nbuckets; i++) for (tlist = hash_items (i, hash); tlist; tlist = tlist->next) { -#if 1 - if (sh_contains_shell_metas (tlist->key)) + if (ansic_shouldquote (tlist->key)) + istr = ansic_quote (tlist->key, 0, (int *)0); + else if (sh_contains_shell_metas (tlist->key)) istr = sh_double_quote (tlist->key); else if (ALL_ELEMENT_SUB (tlist->key[0]) && tlist->key[1] == '\0') istr = sh_double_quote (tlist->key); else istr = tlist->key; -#else - istr = tlist->key; -#endif - vstr = tlist->data ? sh_double_quote ((char *)tlist->data) : (char *)0; + + vstr = tlist->data ? (ansic_shouldquote ((char *)tlist->data) ? + ansic_quote ((char *)tlist->data, 0, (int *)0) : + sh_double_quote ((char *)tlist->data)) + : (char *)0; elen = STRLEN (istr) + 8 + STRLEN (vstr); RESIZE_MALLOCED_BUFFER (ret, rlen, (elen+1), rsize, rsize); diff --git a/builtins/evalstring.c b/builtins/evalstring.c index d367e103..11abc459 100644 --- a/builtins/evalstring.c +++ b/builtins/evalstring.c @@ -573,10 +573,14 @@ itrace("parse_string: longjmp executed: code = %d", code); run_unwind_frame (PS_TAG); + /* If we return < 0, the caller (xparse_dolparen) will jump_to_top_level for + us, after doing cleanup */ if (should_jump_to_top_level) { if (parse_and_execute_level == 0) top_level_cleanup (); + if (code == DISCARD) + return -DISCARD; jump_to_top_level (code); } diff --git a/builtins/exec.def b/builtins/exec.def index d9715115..0551664b 100644 --- a/builtins/exec.def +++ b/builtins/exec.def @@ -142,6 +142,7 @@ exec_builtin (list) #endif /* RESTRICTED_SHELL */ args = strvec_from_word_list (list, 1, 0, (int *)NULL); + env = (char **)0; /* A command with a slash anywhere in its name is not looked up in $PATH. */ command = absolute_program (args[0]) ? args[0] : search_for_command (args[0], 1); @@ -193,7 +194,10 @@ exec_builtin (list) adjust_shell_level (-1); if (cleanenv) - env = (char **)NULL; + { + env = strvec_create (1); + env[0] = (char *)0; + } else { maybe_make_export_env (); @@ -242,6 +246,9 @@ failed_exec: if (args) strvec_dispose (args); + if (env && env != export_env) + strvec_dispose (env); + initialize_traps (); initialize_signals (1); diff --git a/config.h.in b/config.h.in index 492aa218..a5bdfa9a 100644 --- a/config.h.in +++ b/config.h.in @@ -946,6 +946,9 @@ /* Define if you have the header file. */ #undef HAVE_LANGINFO_H +/* Define if you have the header file. */ +#undef HAVE_LIBAUDIT_H + /* Define if you have the header file. */ #undef HAVE_LIBINTL_H diff --git a/configure b/configure index 726134d5..ed57f7e1 100755 --- a/configure +++ b/configure @@ -10157,6 +10157,18 @@ fi +for ac_header in libaudit.h +do : + ac_fn_c_check_header_mongrel "$LINENO" "libaudit.h" "ac_cv_header_libaudit_h" "$ac_includes_default" +if test "x$ac_cv_header_libaudit_h" = xyes; then : + cat >>confdefs.h <<_ACEOF +#define HAVE_LIBAUDIT_H 1 +_ACEOF + +fi + +done + ac_fn_c_check_decl "$LINENO" "AUDIT_USER_TTY" "ac_cv_have_decl_AUDIT_USER_TTY" "#include " if test "x$ac_cv_have_decl_AUDIT_USER_TTY" = xyes; then : diff --git a/configure.ac b/configure.ac index 7a3261bb..a435d81f 100644 --- a/configure.ac +++ b/configure.ac @@ -798,6 +798,7 @@ AC_REPLACE_FUNCS(dprintf) AC_REPLACE_FUNCS(strchrnul) AC_REPLACE_FUNCS(strdup) +AC_CHECK_HEADERS(libaudit.h) AC_CHECK_DECLS([AUDIT_USER_TTY],,, [[#include ]]) AC_CHECK_DECLS([confstr]) diff --git a/doc/bash.1 b/doc/bash.1 index 3587414f..18b69746 100644 --- a/doc/bash.1 +++ b/doc/bash.1 @@ -3170,7 +3170,8 @@ The expansion is a string that is the result of expanding the value of \fIparameter\fP as if it were a prompt string (see \fBPROMPTING\fP below). .TP .B A -The expansion is a string in the form of a \fBdeclare\fP command that, if +The expansion is a string in the form of +an assignment statement or \fBdeclare\fP command that, if evaluated, will recreate \fIparameter\fP with its attributes and value. .TP .B a diff --git a/doc/bashref.texi b/doc/bashref.texi index 55914043..d4a482f4 100644 --- a/doc/bashref.texi +++ b/doc/bashref.texi @@ -2209,7 +2209,8 @@ escape sequences expanded as with the @code{$'@dots{}'} quoting mechansim. The expansion is a string that is the result of expanding the value of @var{parameter} as if it were a prompt string (@pxref{Controlling the Prompt}). @item A -The expansion is a string in the form of a @code{declare} command that, if +The expansion is a string in the form of +an assignment statement or @code{declare} command that, if evaluated, will recreate @var{parameter} with its attributes and value. @item a The expansion is a string consisting of flag values representing diff --git a/lib/readline/history.c b/lib/readline/history.c index 92398db7..a0b12e1d 100644 --- a/lib/readline/history.c +++ b/lib/readline/history.c @@ -43,11 +43,17 @@ # include #endif +#include + #include "history.h" #include "histlib.h" #include "xmalloc.h" +#if !defined (errno) +extern int errno; +#endif + /* How big to make the_history when we first allocate it. */ #define DEFAULT_HISTORY_INITIAL_SIZE 502 @@ -239,7 +245,10 @@ history_get_time (hist) ts = hist->timestamp; if (ts[0] != history_comment_char) return 0; + errno = 0; t = (time_t) strtol (ts + 1, (char **)NULL, 10); /* XXX - should use strtol() here */ + if (errno == ERANGE) + return (time_t)0; return t; } diff --git a/lib/readline/readline.c b/lib/readline/readline.c index 332b8cb8..6f30e3de 100644 --- a/lib/readline/readline.c +++ b/lib/readline/readline.c @@ -386,7 +386,7 @@ readline (prompt) RL_SETSTATE (RL_STATE_CALLBACK); #endif -#if HAVE_DECL_AUDIT_USER_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT) +#if HAVE_DECL_AUDIT_USER_TTY && defined (HAVE_LIBAUDIT_H) && defined (ENABLE_TTY_AUDIT_SUPPORT) if (value) _rl_audit_tty (value); #endif diff --git a/lib/readline/util.c b/lib/readline/util.c index b253f08c..4840494b 100644 --- a/lib/readline/util.c +++ b/lib/readline/util.c @@ -549,7 +549,7 @@ _rl_settracefp (fp) #endif /* DEBUG */ -#if HAVE_DECL_AUDIT_USER_TTY && defined (ENABLE_TTY_AUDIT_SUPPORT) +#if HAVE_DECL_AUDIT_USER_TTY && defined (HAVE_LIBAUDIT_H) && defined (ENABLE_TTY_AUDIT_SUPPORT) #include #include #include diff --git a/parse.y b/parse.y index f9299fa8..3a5bccd5 100644 --- a/parse.y +++ b/parse.y @@ -268,8 +268,6 @@ int parser_state; /* Variables to manage the task of reading here documents, because we need to defer the reading until after a complete command has been collected. */ -#define HEREDOC_MAX 16 - static REDIRECT *redir_stack[HEREDOC_MAX]; int need_here_doc; @@ -2703,6 +2701,7 @@ gather_here_documents () make_here_document (redir_stack[r++], line_number); parser_state &= ~PST_HEREDOC; need_here_doc--; + redir_stack[r - 1] = 0; /* XXX */ } } @@ -4094,7 +4093,7 @@ xparse_dolparen (base, string, indp, flags) parser_state |= PST_CMDSUBST|PST_EOFTOKEN; /* allow instant ')' */ /*(*/ shell_eof_token = ')'; - parse_string (string, "command substitution", sflags, &ep); + nc = parse_string (string, "command substitution", sflags, &ep); shell_eof_token = orig_eof_token; restore_parser_state (&ps); @@ -4104,6 +4103,11 @@ xparse_dolparen (base, string, indp, flags) token_to_read = 0; + /* If parse_string returns < 0, we need to jump to top level with the + negative of the return value */ + if (nc < 0) + jump_to_top_level (-nc); /* XXX */ + /* Need to find how many characters parse_and_execute consumed, update *indp, if flags != 0, copy the portion of the string parsed into RET and return it. If flags & 1 (EX_NOALLOC) we can return NULL. */ @@ -6143,6 +6147,8 @@ sh_parser_state_t * save_parser_state (ps) sh_parser_state_t *ps; { + int i; + if (ps == 0) ps = (sh_parser_state_t *)xmalloc (sizeof (sh_parser_state_t)); if (ps == 0) @@ -6177,6 +6183,16 @@ save_parser_state (ps) ps->echo_input_at_read = echo_input_at_read; ps->need_here_doc = need_here_doc; +#if 0 + for (i = 0; i < HEREDOC_MAX; i++) + ps->redir_stack[i] = redir_stack[i]; +#else + if (need_here_doc == 0) + ps->redir_stack[0] = 0; + else + memcpy (ps->redir_stack, redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); +#endif + ps->token = token; ps->token_buffer_size = token_buffer_size; /* Force reallocation on next call to read_token_word */ @@ -6190,6 +6206,8 @@ void restore_parser_state (ps) sh_parser_state_t *ps; { + int i; + if (ps == 0) return; @@ -6226,6 +6244,16 @@ restore_parser_state (ps) echo_input_at_read = ps->echo_input_at_read; need_here_doc = ps->need_here_doc; +#if 0 + for (i = 0; i < HEREDOC_MAX; i++) + redir_stack[i] = ps->redir_stack[i]; +#else + if (need_here_doc == 0) + redir_stack[0] = 0; + else + memcpy (redir_stack, ps->redir_stack, sizeof (redir_stack[0]) * HEREDOC_MAX); +#endif + FREE (token); token = ps->token; token_buffer_size = ps->token_buffer_size; diff --git a/shell.h b/shell.h index c9affdf2..86fb05da 100644 --- a/shell.h +++ b/shell.h @@ -130,6 +130,8 @@ extern struct user_info current_user; # define USE_VAR(x) #endif +#define HEREDOC_MAX 16 + /* Structure in which to save partial parsing state when doing things like PROMPT_COMMAND and bash_execute_unix_command execution. */ @@ -171,6 +173,8 @@ typedef struct _sh_parser_state_t { int echo_input_at_read; int need_here_doc; + /* structures affecting the parser */ + REDIRECT *redir_stack[HEREDOC_MAX]; } sh_parser_state_t; typedef struct _sh_input_line_state_t { diff --git a/subst.c b/subst.c index 5df5a5ed..a9938b46 100644 --- a/subst.c +++ b/subst.c @@ -1290,6 +1290,15 @@ extract_delimited_string (string, sindex, opener, alt_opener, closer, flags) { c = string[i]; + /* If a recursive call or a call to ADVANCE_CHAR leaves the index beyond + the end of the string, catch it and cut the loop. */ + if (i > slen) + { + i = slen; + c = string[i = slen]; + break; + } + if (c == 0) break; @@ -2792,6 +2801,8 @@ do_compound_assignment (name, value, flags) v = make_local_array_variable (name, 0); if (v) assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); } /* In a function but forcing assignment in global context */ else if (mkglobal && variable_context) @@ -2808,6 +2819,8 @@ do_compound_assignment (name, value, flags) v = convert_var_to_array (v); if (v) assign_compound_array_list (v, list, flags); + if (list) + dispose_words (list); } else v = assign_array_from_string (name, value, flags); @@ -6828,7 +6841,15 @@ get_var_and_type (varname, value, ind, quoted, flags, varp, valp) /* XXX - what if vname == 0 || *vname == 0 ? */ else vname = varname; - + + if (vname == 0) + { + vtype = VT_VARIABLE; + *varp = (SHELL_VAR *)NULL; + *valp = (char *)NULL; + return (vtype); + } + /* This sets vtype to VT_VARIABLE or VT_POSPARMS */ vtype = (vname[0] == '@' || vname[0] == '*') && vname[1] == '\0'; if (vtype == VT_POSPARMS && vname[0] == '*') @@ -7109,8 +7130,12 @@ pat_subst (string, pat, rep, mflags) } else if (*string == 0 && (match_pattern (string, pat, mtype, &s, &e) != 0)) { - ret = (char *)xmalloc (STRLEN (rep) + 1); - strcpy (ret, rep); + replen = STRLEN (rep); + ret = (char *)xmalloc (replen + 1); + if (replen == 0) + ret[0] = '\0'; + else + strcpy (ret, rep); return (ret); } @@ -7123,22 +7148,22 @@ pat_subst (string, pat, rep, mflags) break; l = s - str; - if (rxpand) + if (rep && rxpand) { - int x; - mlen = e - s; - mstr = xmalloc (mlen + 1); + int x; + mlen = e - s; + mstr = xmalloc (mlen + 1); for (x = 0; x < mlen; x++) mstr[x] = s[x]; - mstr[mlen] = '\0'; - rstr = strcreplace (rep, '&', mstr, 0); - rslen = strlen (rstr); + mstr[mlen] = '\0'; + rstr = strcreplace (rep, '&', mstr, 0); + rslen = strlen (rstr); } else - { - rstr = rep; - rslen = replen; - } + { + rstr = rep; + rslen = replen; + } RESIZE_MALLOCED_BUFFER (ret, rptr, (l + rslen), rsize, 64); diff --git a/syntax.h b/syntax.h index e01110e7..9a9a2fa7 100644 --- a/syntax.h +++ b/syntax.h @@ -75,6 +75,8 @@ extern int sh_syntabsiz; #define shellblank(c) (sh_syntaxtab[(unsigned char)(c)] & CBLANK) +#define parserblank(c) ((c) == ' ' || (c) == '\t') + #define issyntype(c, t) ((sh_syntaxtab[(unsigned char)(c)] & (t)) != 0) #define notsyntype(c,t) ((sh_syntaxtab[(unsigned char)(c)] & (t)) == 0) diff --git a/tests/array.right b/tests/array.right index 770787ba..031a0b7e 100644 --- a/tests/array.right +++ b/tests/array.right @@ -501,3 +501,4 @@ unset ./array21.sub: line 20: typeset: A: not found declare -a a=() declare -A A=() +declare -a foo=([0]="1" [1]="(4 5 6)" [2]="3") diff --git a/tests/array21.sub b/tests/array21.sub index 5dfa16b8..d1f705e3 100644 --- a/tests/array21.sub +++ b/tests/array21.sub @@ -29,3 +29,9 @@ a=() typeset -p a A=() typeset -p A + +declare -a foo +declare foo='(1 2 3)' +declare foo[1]='(4 5 6)' + +declare -p foo diff --git a/tests/exp.right b/tests/exp.right index 3f9d9edd..165f41b9 100644 --- a/tests/exp.right +++ b/tests/exp.right @@ -227,6 +227,6 @@ argv[3] = declare -- var="x\001y\177z"$ argv[1] = <$'x\001y\177z'> argv[1] = -var=$'x\001y\177z'$ +var=$'x\001y\177z' argv[1] = declare -a array=([0]="x\001y\177z")$ diff --git a/tests/exp8.sub b/tests/exp8.sub index 34d9ef1f..f4997778 100644 --- a/tests/exp8.sub +++ b/tests/exp8.sub @@ -10,7 +10,7 @@ declare -p var | sed -n l recho ${var@Q} recho ${var@P} -echo ${var@A} | sed -n l +echo ${var@A} array=( "$var" ) recho ${array[@]} diff --git a/tests/nquote.right b/tests/nquote.right index 9d1290ef..79bd587d 100644 --- a/tests/nquote.right +++ b/tests/nquote.right @@ -56,3 +56,9 @@ $'\'' $'\'abcd\'' ' 1 +argv[1] = <^?> +0000000 del nl +0000002 +0000000 esc fs gs rs us del nl +0000007 +\q diff --git a/tests/nquote.tests b/tests/nquote.tests index aa0a9d88..80d3cb46 100644 --- a/tests/nquote.tests +++ b/tests/nquote.tests @@ -117,3 +117,4 @@ recho "$( args $'A\tB' )" ${THIS_SH} ./nquote1.sub ${THIS_SH} ./nquote2.sub +${THIS_SH} ./nquote3.sub diff --git a/tests/nquote3.sub b/tests/nquote3.sub new file mode 100644 index 00000000..6c84a641 --- /dev/null +++ b/tests/nquote3.sub @@ -0,0 +1,6 @@ +recho $'\c?' + +echo $'\c?' |od -a +echo $'\c[\c\\\c]\c^\c_\c?' |od -a + +echo $'\q' diff --git a/variables.c b/variables.c index c8e22f73..80d125df 100644 --- a/variables.c +++ b/variables.c @@ -338,7 +338,7 @@ initialize_shell_variables (env, privmode) create_variable_tables (); - for (string_index = 0; string = env[string_index++]; ) + for (string_index = 0; env && (string = env[string_index++]); ) { char_index = 0; name = string; @@ -796,7 +796,7 @@ adjust_shell_level (change) shell_level = old_level + change; if (shell_level < 0) shell_level = 0; - else if (shell_level > 1000) + else if (shell_level >= 1000) { internal_warning (_("shell level (%d) too high, resetting to 1"), shell_level); shell_level = 1; @@ -844,16 +844,25 @@ void set_pwd () { SHELL_VAR *temp_var, *home_var; - char *temp_string, *home_string; + char *temp_string, *home_string, *current_dir; home_var = find_variable ("HOME"); home_string = home_var ? value_cell (home_var) : (char *)NULL; temp_var = find_variable ("PWD"); + /* Follow posix rules for importing PWD */ if (temp_var && imported_p (temp_var) && (temp_string = value_cell (temp_var)) && + temp_string[0] == '/' && same_file (temp_string, ".", (struct stat *)NULL, (struct stat *)NULL)) - set_working_directory (temp_string); + { + current_dir = sh_canonpath (temp_string, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + if (current_dir == 0) + current_dir = get_working_directory ("shell_init"); + else + set_working_directory (current_dir); + free (current_dir); + } else if (home_string && interactive_shell && login_shell && same_file (home_string, ".", (struct stat *)NULL, (struct stat *)NULL)) {