X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fbash.git;a=blobdiff_plain;f=shell.c;h=a2b2a55e0c5441242fcad7e505e56aa5a5efbe4d;hp=bbc8a66cc2ebb27162da8b36e87ff3d2e90e5bef;hb=HEAD;hpb=ac50fbac377e32b98d2de396f016ea81e8ee9961 diff --git a/shell.c b/shell.c index bbc8a66cc..ebd89651e 100644 --- a/shell.c +++ b/shell.c @@ -1,6 +1,6 @@ /* shell.c -- GNU's idea of the POSIX shell specification. */ -/* Copyright (C) 1987-2012 Free Software Foundation, Inc. +/* Copyright (C) 1987-2021 Free Software Foundation, Inc. This file is part of GNU Bash, the Bourne Again SHell. @@ -38,7 +38,9 @@ #include #include #include "filecntl.h" -#include +#if defined (HAVE_PWD_H) +# include +#endif #if defined (HAVE_UNISTD_H) # include @@ -49,6 +51,7 @@ #define NEED_SH_SETLINEBUF_DECL /* used in externs.h */ #include "shell.h" +#include "parser.h" #include "flags.h" #include "trap.h" #include "mailcheck.h" @@ -57,6 +60,10 @@ #if defined (JOB_CONTROL) #include "jobs.h" +#else +extern int running_in_background; +extern int initialize_job_control PARAMS((int)); +extern int get_tty_state PARAMS((void)); #endif /* JOB_CONTROL */ #include "input.h" @@ -65,6 +72,8 @@ #if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) # include +#elif defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC) +# include #endif #if defined (HISTORY) @@ -73,6 +82,7 @@ #endif #if defined (READLINE) +# include # include "bashline.h" #endif @@ -95,21 +105,12 @@ extern int errno; extern char **environ; /* used if no third argument to main() */ #endif -extern char *dist_version, *release_status; -extern int patch_level, build_version; -extern int shell_level; -extern int subshell_environment; -extern int last_command_exit_value; -extern int line_number; -extern int expand_aliases; -extern int array_needs_making; extern int gnu_error_format; -extern char *primary_prompt, *secondary_prompt; -extern char *this_command_name; /* Non-zero means that this shell has already been run; i.e. you should call shell_reinitialize () if you need to start afresh. */ int shell_initialized = 0; +int bash_argv_initialized = 0; COMMAND *global_command = (COMMAND *)NULL; @@ -158,6 +159,7 @@ int autocd = 0; This is a superset of the information provided by interactive_shell. */ int startup_state = 0; +int reading_shell_script = 0; /* Special debugging helper. */ int debugging_login_shell = 0; @@ -179,6 +181,7 @@ char *shell_name = (char *)NULL; /* time in seconds when the shell was started */ time_t shell_start_time; +struct timeval shellstart; /* Are we running in an emacs shell window? */ int running_under_emacs; @@ -191,7 +194,7 @@ int have_devfd = 0; #endif /* The name of the .(shell)rc file. */ -static char *bashrc_file = "~/.bashrc"; +static char *bashrc_file = DEFAULT_BASHRC; /* Non-zero means to act more like the Bourne shell on startup. */ static int act_like_sh; @@ -219,11 +222,15 @@ int no_line_editing = 0; /* non-zero -> don't do fancy line editing. */ #else int no_line_editing = 1; /* can't have line editing without readline */ #endif +#if defined (TRANSLATABLE_STRINGS) int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ int dump_po_strings; /* Dump strings in $"..." in po format */ +#endif int wordexp_only = 0; /* Do word expansion only */ int protected_mode = 0; /* No command substitution with --wordexp */ +int pretty_print_mode = 0; /* pretty-print a shell script */ + #if defined (STRICT_POSIX) int posixly_correct = 1; /* Non-zero means posix.2 superset. */ #else @@ -243,8 +250,10 @@ static const struct { #if defined (DEBUGGER) { "debugger", Int, &debugging_mode, (char **)0x0 }, #endif +#if defined (TRANSLATABLE_STRINGS) { "dump-po-strings", Int, &dump_po_strings, (char **)0x0 }, { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, +#endif { "help", Int, &want_initial_help, (char **)0x0 }, { "init-file", Charp, (int *)0x0, &bashrc_file }, { "login", Int, &make_login_shell, (char **)0x0 }, @@ -252,6 +261,7 @@ static const struct { { "noprofile", Int, &no_profile, (char **)0x0 }, { "norc", Int, &no_rc, (char **)0x0 }, { "posix", Int, &posixly_correct, (char **)0x0 }, + { "pretty-print", Int, &pretty_print_mode, (char **)0x0 }, #if defined (WORDEXP_OPTION) { "protected", Int, &protected_mode, (char **)0x0 }, #endif @@ -259,7 +269,7 @@ static const struct { #if defined (RESTRICTED_SHELL) { "restricted", Int, &restricted, (char **)0x0 }, #endif - { "verbose", Int, &echo_input_at_read, (char **)0x0 }, + { "verbose", Int, &verbose_flag, (char **)0x0 }, { "version", Int, &do_version, (char **)0x0 }, #if defined (WORDEXP_OPTION) { "wordexp", Int, &wordexp_only, (char **)0x0 }, @@ -289,6 +299,7 @@ int want_pending_command; /* -c flag supplied */ /* This variable is not static so it can be bound to $BASH_EXECUTION_STRING */ char *command_execution_string; /* argument to -c option */ +char *shell_script_filename; /* shell script */ int malloc_trace_at_exit = 0; @@ -299,35 +310,38 @@ static FILE *default_input; static STRING_INT_ALIST *shopt_alist; static int shopt_ind = 0, shopt_len = 0; -static int parse_long_options __P((char **, int, int)); -static int parse_shell_options __P((char **, int, int)); -static int bind_args __P((char **, int, int, int)); +static int parse_long_options PARAMS((char **, int, int)); +static int parse_shell_options PARAMS((char **, int, int)); +static int bind_args PARAMS((char **, int, int, int)); -static void start_debugger __P((void)); +static void start_debugger PARAMS((void)); -static void add_shopt_to_alist __P((char *, int)); -static void run_shopt_alist __P((void)); +static void add_shopt_to_alist PARAMS((char *, int)); +static void run_shopt_alist PARAMS((void)); -static void execute_env_file __P((char *)); -static void run_startup_files __P((void)); -static int open_shell_script __P((char *)); -static void set_bash_input __P((void)); -static int run_one_command __P((char *)); +static void execute_env_file PARAMS((char *)); +static void run_startup_files PARAMS((void)); +static int open_shell_script PARAMS((char *)); +static void set_bash_input PARAMS((void)); +static int run_one_command PARAMS((char *)); #if defined (WORDEXP_OPTION) -static int run_wordexp __P((char *)); +static int run_wordexp PARAMS((char *)); #endif -static int uidget __P((void)); +static int uidget PARAMS((void)); -static void init_interactive __P((void)); -static void init_noninteractive __P((void)); -static void init_interactive_script __P((void)); +static void set_option_defaults PARAMS((void)); +static void reset_option_defaults PARAMS((void)); -static void set_shell_name __P((char *)); -static void shell_initialize __P((void)); -static void shell_reinitialize __P((void)); +static void init_interactive PARAMS((void)); +static void init_noninteractive PARAMS((void)); +static void init_interactive_script PARAMS((void)); -static void show_shell_usage __P((FILE *, int)); +static void set_shell_name PARAMS((char *)); +static void shell_initialize PARAMS((void)); +static void shell_reinitialize PARAMS((void)); + +static void show_shell_usage PARAMS((FILE *, int)); #ifdef __CYGWIN__ static void @@ -388,9 +402,7 @@ main (argc, argv, env) xtrace_init (); #if defined (USING_BASH_MALLOC) && defined (DEBUG) && !defined (DISABLE_MALLOC_WRAPPERS) -# if 1 - malloc_set_register (1); -# endif + malloc_set_register (1); /* XXX - change to 1 for malloc debugging */ #endif check_dev_tty (); @@ -413,7 +425,7 @@ main (argc, argv, env) mcheck (programming_error, (void (*) ())0); #endif /* USE_GNU_MALLOC_LIBRARY */ - if (setjmp (subshell_top_level)) + if (setjmp_sigs (subshell_top_level)) { argc = subshell_argc; argv = subshell_argv; @@ -427,7 +439,7 @@ main (argc, argv, env) arg_index = 1; if (arg_index > argc) arg_index = argc; - command_execution_string = (char *)NULL; + command_execution_string = shell_script_filename = (char *)NULL; want_pending_command = locally_skip_execution = read_from_stdin = 0; default_input = stdin; #if defined (BUFFERED_INPUT) @@ -453,13 +465,15 @@ main (argc, argv, env) shell_environment = env; set_shell_name (argv[0]); - shell_start_time = NOW; /* NOW now defined in general.h */ + + gettimeofday (&shellstart, 0); + shell_start_time = shellstart.tv_sec; /* Parse argument flags from the input line. */ /* Find full word arguments first. */ arg_index = parse_long_options (argv, arg_index, argc); - + if (want_initial_help) { show_shell_usage (stdout, 1); @@ -472,6 +486,8 @@ main (argc, argv, env) exit (EXECUTION_SUCCESS); } + echo_input_at_read = verbose_flag; /* --verbose given */ + /* All done with full word options; do standard shell option parsing.*/ this_command_name = shell_name; /* for error reporting */ arg_index = parse_shell_options (argv, arg_index, argc); @@ -486,11 +502,13 @@ main (argc, argv, env) set_login_shell ("login_shell", login_shell != 0); +#if defined (TRANSLATABLE_STRINGS) if (dump_po_strings) dump_translatable_strings = 1; if (dump_translatable_strings) read_but_dont_execute = 1; +#endif if (running_setuid && privileged_mode == 0) disable_priv_mode (); @@ -510,8 +528,6 @@ main (argc, argv, env) } this_command_name = (char *)NULL; - cmd_init(); /* initialize the command object caches */ - /* First, let the outside world know about our interactive status. A shell is interactive if the `-i' flag was given, or if all of the following conditions are met: @@ -567,24 +583,45 @@ main (argc, argv, env) set_default_locale_vars (); /* - * M-x term -> TERM=eterm EMACS=22.1 (term:0.96) (eterm) - * M-x shell -> TERM=dumb EMACS=t (no line editing) - * M-x terminal -> TERM=emacs-em7955 EMACS= (line editing) + * M-x term -> TERM=eterm-color INSIDE_EMACS='251,term:0.96' (eterm) + * M-x shell -> TERM='dumb' INSIDE_EMACS='25.1,comint' (no line editing) + * + * Older versions of Emacs may set EMACS to 't' or to something like + * '22.1 (term:0.96)' instead of (or in addition to) setting INSIDE_EMACS. + * They may set TERM to 'eterm' instead of 'eterm-color'. They may have + * a now-obsolete command that sets neither EMACS nor INSIDE_EMACS: + * M-x terminal -> TERM='emacs-em7955' (line editing) */ if (interactive_shell) { - char *term, *emacs; + char *term, *emacs, *inside_emacs; + int emacs_term, in_emacs; term = get_string_value ("TERM"); emacs = get_string_value ("EMACS"); + inside_emacs = get_string_value ("INSIDE_EMACS"); + + if (inside_emacs) + { + emacs_term = strstr (inside_emacs, ",term:") != 0; + in_emacs = 1; + } + else if (emacs) + { + /* Infer whether we are in an older Emacs. */ + emacs_term = strstr (emacs, " (term:") != 0; + in_emacs = emacs_term || STREQ (emacs, "t"); + } + else + in_emacs = emacs_term = 0; /* Not sure any emacs terminal emulator sets TERM=emacs any more */ - no_line_editing |= term && (STREQ (term, "emacs")); - no_line_editing |= emacs && emacs[0] == 't' && emacs[1] == '\0' && STREQ (term, "dumb"); + no_line_editing |= STREQ (term, "emacs"); + no_line_editing |= in_emacs && STREQ (term, "dumb"); /* running_under_emacs == 2 for `eterm' */ - running_under_emacs = (emacs != 0) || (term && STREQN (term, "emacs", 5)); - running_under_emacs += term && STREQN (term, "eterm", 5) && emacs && strstr (emacs, "term"); + running_under_emacs = in_emacs || STREQN (term, "emacs", 5); + running_under_emacs += emacs_term && STREQN (term, "eterm", 5); if (running_under_emacs) gnu_error_format = 1; @@ -596,10 +633,10 @@ main (argc, argv, env) /* Give this shell a place to longjmp to before executing the startup files. This allows users to press C-c to abort the lengthy startup. */ - code = setjmp (top_level); + code = setjmp_sigs (top_level); if (code) { - if (code == EXITPROG || code == ERREXIT) + if (code == EXITPROG || code == ERREXIT || code == EXITBLTIN) exit_shell (last_command_exit_value); else { @@ -646,13 +683,43 @@ main (argc, argv, env) restricted = 0; #endif + /* Set positional parameters before running startup files. top_level_arg_index + holds the index of the current argument before setting the positional + parameters, so any changes performed in the startup files won't affect + later option processing. */ + if (wordexp_only) + ; /* nothing yet */ + else if (command_execution_string) + arg_index = bind_args (argv, arg_index, argc, 0); /* $0 ... $n */ + else if (arg_index != argc && read_from_stdin == 0) + { + shell_script_filename = argv[arg_index++]; + arg_index = bind_args (argv, arg_index, argc, 1); /* $1 ... $n */ + } + else + arg_index = bind_args (argv, arg_index, argc, 1); /* $1 ... $n */ + /* The startup files are run with `set -e' temporarily disabled. */ if (locally_skip_execution == 0 && running_setuid == 0) { + char *t; + old_errexit_flag = exit_immediately_on_error; exit_immediately_on_error = 0; + /* Temporarily set $0 while running startup files, then restore it so + we get better error messages when trying to open script files. */ + if (shell_script_filename) + { + t = dollar_vars[0]; + dollar_vars[0] = exec_argv0 ? savestring (exec_argv0) : savestring (shell_script_filename); + } run_startup_files (); + if (shell_script_filename) + { + free (dollar_vars[0]); + dollar_vars[0] = t; + } exit_immediately_on_error += old_errexit_flag; } @@ -676,14 +743,16 @@ main (argc, argv, env) if (wordexp_only) { startup_state = 3; - last_command_exit_value = run_wordexp (argv[arg_index]); + last_command_exit_value = run_wordexp (argv[top_level_arg_index]); exit_shell (last_command_exit_value); } #endif + cmd_init (); /* initialize the command object caches */ + uwp_init (); + if (command_execution_string) { - arg_index = bind_args (argv, arg_index, argc, 0); startup_state = 2; if (debugging_mode) @@ -701,26 +770,27 @@ main (argc, argv, env) /* Get possible input filename and set up default_buffered_input or default_input as appropriate. */ - if (arg_index != argc && read_from_stdin == 0) - { - open_shell_script (argv[arg_index]); - arg_index++; - } + if (shell_script_filename) + open_shell_script (shell_script_filename); else if (interactive == 0) - /* In this mode, bash is reading a script from stdin, which is a - pipe or redirected file. */ + { + /* In this mode, bash is reading a script from stdin, which is a + pipe or redirected file. */ #if defined (BUFFERED_INPUT) - default_buffered_input = fileno (stdin); /* == 0 */ + default_buffered_input = fileno (stdin); /* == 0 */ #else - setbuf (default_input, (char *)NULL); + setbuf (default_input, (char *)NULL); #endif /* !BUFFERED_INPUT */ + read_from_stdin = 1; + } + else if (top_level_arg_index == argc) /* arg index before startup files */ + /* "If there are no operands and the -c option is not specified, the -s + option shall be assumed." */ + read_from_stdin = 1; set_bash_input (); - /* Bind remaining args to $1 ... $n */ - arg_index = bind_args (argv, arg_index, argc, 1); - - if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && dollar_vars[1]) + if (debugging_mode && locally_skip_execution == 0 && running_setuid == 0 && (reading_shell_script || interactive_shell == 0)) start_debugger (); /* Do the things that should be done only for interactive shells. */ @@ -751,6 +821,14 @@ main (argc, argv, env) shell_initialized = 1; + if (pretty_print_mode && interactive_shell) + { + internal_warning (_("pretty-printing mode ignored in interactive shells")); + pretty_print_mode = 0; + } + if (pretty_print_mode) + exit_shell (pretty_print_loop ()); + /* Read commands until exit condition. */ reader_loop (); exit_shell (last_command_exit_value); @@ -857,7 +935,9 @@ parse_shell_options (argv, arg_start, arg_end) o_option = argv[next_arg]; if (o_option == 0) { + set_option_defaults (); list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1); + reset_option_defaults (); break; } if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) @@ -881,7 +961,9 @@ parse_shell_options (argv, arg_start, arg_end) break; case 'D': +#if defined (TRANSLATABLE_STRINGS) dump_translatable_strings = 1; +#endif break; default: @@ -909,13 +991,21 @@ exit_shell (s) fflush (stdout); /* XXX */ fflush (stderr); + /* Clean up the terminal if we are in a state where it's been modified. */ +#if defined (READLINE) + if (RL_ISSTATE (RL_STATE_TERMPREPPED) && rl_deprep_term_function) + (*rl_deprep_term_function) (); +#endif + if (read_tty_modified ()) + read_tty_cleanup (); + /* Do trap[0] if defined. Allow it to override the exit status passed to us. */ if (signal_is_trapped (0)) s = run_exit_trap (); #if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); + unlink_all_fifos (); #endif /* PROCESS_SUBSTITUTION */ #if defined (HISTORY) @@ -933,10 +1023,12 @@ exit_shell (s) if (interactive_shell && login_shell && hup_on_exit) hangup_all_jobs (); - /* If this shell is interactive, terminate all stopped jobs and - restore the original terminal process group. Don't do this if we're - in a subshell and calling exit_shell after, for example, a failed - word expansion. */ + /* If this shell is interactive, or job control is active, terminate all + stopped jobs and restore the original terminal process group. Don't do + this if we're in a subshell and calling exit_shell after, for example, + a failed word expansion. We want to do this even if the shell is not + interactive because we set the terminal's process group when job control + is enabled regardless of the interactive status. */ if (subshell_environment == 0) end_job_control (); #endif /* JOB_CONTROL */ @@ -952,8 +1044,9 @@ sh_exit (s) int s; { #if defined (MALLOC_DEBUG) && defined (USING_BASH_MALLOC) - if (malloc_trace_at_exit) + if (malloc_trace_at_exit && (subshell_environment & (SUBSHELL_COMSUB|SUBSHELL_PROCSUB)) == 0) trace_malloc_stats (get_name_for_error (), (char *)NULL); + /* mlocation_write_table (); */ #endif exit (s); @@ -971,12 +1064,20 @@ subshell_exit (s) /* Do trap[0] if defined. Allow it to override the exit status passed to us. */ + last_command_exit_value = s; if (signal_is_trapped (0)) s = run_exit_trap (); sh_exit (s); } +void +set_exit_status (s) + int s; +{ + set_pipestatus_from_exit (last_command_exit_value = s); +} + /* Source the bash startup files. If POSIXLY_CORRECT is non-zero, we obey the Posix.2 startup file rules: $ENV is expanded, and if the file it names exists, that file is sourced. The Posix.2 rules are in effect @@ -1027,6 +1128,7 @@ run_startup_files () #endif int sourced_login, run_by_ssh; +#if 1 /* TAG:bash-5.3 andrew.gregory.8@gmail.com 2/21/2022 */ /* get the rshd/sshd case out of the way first. */ if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && act_like_sh == 0 && command_execution_string) @@ -1036,11 +1138,16 @@ run_startup_files () (find_variable ("SSH2_CLIENT") != (SHELL_VAR *)0); #else run_by_ssh = 0; +#endif #endif /* If we were run by sshd or we think we were run by rshd, execute ~/.bashrc if we are a top-level shell. */ +#if 1 /* TAG:bash-5.3 */ if ((run_by_ssh || isnetconn (fileno (stdin))) && shell_level < 2) +#else + if (isnetconn (fileno (stdin) && shell_level < 2) +#endif { #ifdef SYS_BASHRC # if defined (__OPENNT) @@ -1188,10 +1295,15 @@ maybe_make_restricted (name) temp++; if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) { +#if defined (RBASH_STATIC_PATH_VALUE) + bind_variable ("PATH", RBASH_STATIC_PATH_VALUE, 0); + stupidly_hack_special_variables ("PATH"); /* clear hash table */ +#endif set_var_read_only ("PATH"); set_var_read_only ("SHELL"); set_var_read_only ("ENV"); set_var_read_only ("BASH_ENV"); + set_var_read_only ("HISTFILE"); restricted = 1; } return (restricted); @@ -1226,8 +1338,28 @@ uidget () void disable_priv_mode () { - setuid (current_user.uid); - setgid (current_user.gid); + int e; + +#if HAVE_SETRESUID + if (setresuid (current_user.uid, current_user.uid, current_user.uid) < 0) +#else + if (setuid (current_user.uid) < 0) +#endif + { + e = errno; + sys_error (_("cannot set uid to %d: effective uid %d"), current_user.uid, current_user.euid); +#if defined (EXIT_ON_SETUID_FAILURE) + if (e == EAGAIN) + exit (e); +#endif + } +#if HAVE_SETRESGID + if (setresgid (current_user.gid, current_user.gid, current_user.gid) < 0) +#else + if (setgid (current_user.gid) < 0) +#endif + sys_error (_("cannot set gid to %d: effective gid %d"), current_user.gid, current_user.egid); + current_user.euid = current_user.uid; current_user.egid = current_user.gid; } @@ -1251,6 +1383,7 @@ run_wordexp (words) return last_command_exit_value = 127; case ERREXIT: case EXITPROG: + case EXITBLTIN: return last_command_exit_value; case DISCARD: return last_command_exit_value = 1; @@ -1329,6 +1462,7 @@ run_one_command (command) return last_command_exit_value = 127; case ERREXIT: case EXITPROG: + case EXITBLTIN: return last_command_exit_value; case DISCARD: return last_command_exit_value = 1; @@ -1336,7 +1470,7 @@ run_one_command (command) command_error ("run_one_command", CMDERR_BADJUMP, code, 0); } } - return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST)); + return (parse_and_execute (savestring (command), "-c", SEVAL_NOHIST|SEVAL_RESETLINE)); } #endif /* ONESHOT */ @@ -1346,13 +1480,21 @@ bind_args (argv, arg_start, arg_end, start_index) int arg_start, arg_end, start_index; { register int i; - WORD_LIST *args; + WORD_LIST *args, *tl; + + for (i = arg_start, args = tl = (WORD_LIST *)NULL; i < arg_end; i++) + { + if (args == 0) + args = tl = make_word_list (make_word (argv[i]), args); + else + { + tl->next = make_word_list (make_word (argv[i]), (WORD_LIST *)NULL); + tl = tl->next; + } + } - for (i = arg_start, args = (WORD_LIST *)NULL; i < arg_end; i++) - args = make_word_list (make_word (argv[i]), args); if (args) { - args = REVERSE_LIST (args, WORD_LIST *); if (start_index == 0) /* bind to $0...$n for sh -c command */ { /* Posix.2 4.56.3 says that the first argument after sh -c command @@ -1361,12 +1503,23 @@ bind_args (argv, arg_start, arg_end, start_index) FREE (dollar_vars[0]); dollar_vars[0] = savestring (args->word->word); remember_args (args->next, 1); - push_args (args->next); /* BASH_ARGV and BASH_ARGC */ + if (debugging_mode) + { + push_args (args->next); /* BASH_ARGV and BASH_ARGC */ + bash_argv_initialized = 1; + } } else /* bind to $1...$n for shell script */ { remember_args (args, 1); - push_args (args); /* BASH_ARGV and BASH_ARGC */ + /* We do this unconditionally so something like -O extdebug doesn't + do it first. We're setting the definitive positional params + here. */ + if (debugging_mode) + { + push_args (args); /* BASH_ARGV and BASH_ARGC */ + bash_argv_initialized = 1; + } } dispose_words (args); @@ -1387,12 +1540,21 @@ start_debugger () { #if defined (DEBUGGER) && defined (DEBUGGER_START_FILE) int old_errexit; + int r; old_errexit = exit_immediately_on_error; exit_immediately_on_error = 0; - maybe_execute_file (DEBUGGER_START_FILE, 1); - function_trace_mode = 1; + r = force_execute_file (DEBUGGER_START_FILE, 1); + if (r < 0) + { + internal_warning (_("cannot start debugger; debugging mode disabled")); + debugging_mode = 0; + } + error_trace_mode = function_trace_mode = debugging_mode; + + set_shellopts (); + set_bashopts (); exit_immediately_on_error += old_errexit; #endif @@ -1435,7 +1597,10 @@ open_shell_script (script_name) { e = errno; file_error (filename); - exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); +#if defined (JOB_CONTROL) + end_job_control (); /* just in case we were run as bash -i script */ +#endif + sh_exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); } free (dollar_vars[0]); @@ -1446,6 +1611,20 @@ open_shell_script (script_name) exec_argv0 = (char *)NULL; } + if (file_isdir (filename)) + { +#if defined (EISDIR) + errno = EISDIR; +#else + errno = EINVAL; +#endif + file_error (filename); +#if defined (JOB_CONTROL) + end_job_control (); /* just in case we were run as bash -i script */ +#endif + sh_exit (EX_NOINPUT); + } + #if defined (ARRAY_VARS) GET_ARRAY_FROM_VAR ("FUNCNAME", funcname_v, funcname_a); GET_ARRAY_FROM_VAR ("BASH_SOURCE", bash_source_v, bash_source_a); @@ -1478,17 +1657,30 @@ open_shell_script (script_name) { e = errno; if ((fstat (fd, &sb) == 0) && S_ISDIR (sb.st_mode)) - internal_error (_("%s: is a directory"), filename); + { +#if defined (EISDIR) + errno = EISDIR; + file_error (filename); +#else + internal_error (_("%s: Is a directory"), filename); +#endif + } else { errno = e; file_error (filename); } +#if defined (JOB_CONTROL) + end_job_control (); /* just in case we were run as bash -i script */ +#endif exit (EX_NOEXEC); } else if (sample_len > 0 && (check_binary_file (sample, sample_len))) { internal_error (_("%s: cannot execute binary file"), filename); +#if defined (JOB_CONTROL) + end_job_control (); /* just in case we were run as bash -i script */ +#endif exit (EX_BINARY_FILE); } /* Now rewind the file back to the beginning. */ @@ -1538,6 +1730,8 @@ open_shell_script (script_name) init_interactive_script (); free (filename); + + reading_shell_script = 1; return (fd); } @@ -1626,21 +1820,52 @@ set_shell_name (argv0) shell_name = PROGRAM; } +/* Some options are initialized to -1 so we have a way to determine whether + they were set on the command line. This is an issue when listing the option + values at invocation (`bash -o'), so we set the defaults here and reset + them after the call to list_minus_o_options (). */ +/* XXX - could also do this for histexp_flag, jobs_m_flag */ +static void +set_option_defaults () +{ +#if defined (HISTORY) + enable_history_list = 0; +#endif +} + +static void +reset_option_defaults () +{ +#if defined (HISTORY) + enable_history_list = -1; +#endif +} + static void init_interactive () { - expand_aliases = interactive_shell = startup_state = 1; - interactive = 1; + expand_aliases = expaliases_flag = 1; + interactive_shell = startup_state = interactive = 1; +#if defined (HISTORY) + if (enable_history_list == -1) + enable_history_list = 1; /* set default */ + remember_on_history = enable_history_list; +# if defined (BANG_HISTORY) + histexp_flag = history_expansion; /* XXX */ +# endif +#endif } static void init_noninteractive () { #if defined (HISTORY) + if (enable_history_list == -1) /* set default */ + enable_history_list = 0; bash_history_reinit (0); #endif /* HISTORY */ interactive_shell = startup_state = interactive = 0; - expand_aliases = posixly_correct; /* XXX - was 0 not posixly_correct */ + expand_aliases = expaliases_flag = posixly_correct; /* XXX - was 0 not posixly_correct */ no_line_editing = 1; #if defined (JOB_CONTROL) /* Even if the shell is not interactive, enable job control if the -i or @@ -1652,8 +1877,15 @@ init_noninteractive () static void init_interactive_script () { +#if defined (HISTORY) + if (enable_history_list == -1) + enable_history_list = 1; +#endif init_noninteractive (); - expand_aliases = interactive_shell = startup_state = 1; + expand_aliases = expaliases_flag = interactive_shell = startup_state = 1; +#if defined (HISTORY) + remember_on_history = enable_history_list; /* XXX */ +#endif } void @@ -1684,7 +1916,9 @@ get_current_user_info () current_user.shell = savestring ("/bin/sh"); current_user.home_dir = savestring ("/"); } +#if defined (HAVE_GETPWENT) endpwent (); +#endif } } @@ -1694,6 +1928,7 @@ static void shell_initialize () { char hostname[256]; + int should_be_restricted; /* Line buffer output for stderr and stdout. */ if (shell_initialized == 0) @@ -1732,11 +1967,15 @@ shell_initialize () /* Initialize our interface to the tilde expander. */ tilde_initialize (); +#if defined (RESTRICTED_SHELL) + should_be_restricted = shell_is_restricted (shell_name); +#endif + /* Initialize internal and environment variables. Don't import shell functions from the environment if we are running in privileged or restricted mode or if the shell is running setuid. */ #if defined (RESTRICTED_SHELL) - initialize_shell_variables (shell_environment, privileged_mode||restricted||running_setuid); + initialize_shell_variables (shell_environment, privileged_mode||restricted||should_be_restricted||running_setuid); #else initialize_shell_variables (shell_environment, privileged_mode||running_setuid); #endif @@ -1754,8 +1993,8 @@ shell_initialize () running in privileged or restricted mode or if the shell is running setuid. */ #if defined (RESTRICTED_SHELL) - initialize_shell_options (privileged_mode||restricted||running_setuid); - initialize_bashopts (privileged_mode||restricted||running_setuid); + initialize_shell_options (privileged_mode||restricted||should_be_restricted||running_setuid); + initialize_bashopts (privileged_mode||restricted||should_be_restricted||running_setuid); #else initialize_shell_options (privileged_mode||running_setuid); initialize_bashopts (privileged_mode||running_setuid); @@ -1784,13 +2023,15 @@ shell_reinitialize () /* Things that get 0. */ login_shell = make_login_shell = interactive = executing = 0; debugging = do_version = line_number = last_command_exit_value = 0; - forced_interactive = interactive_shell = subshell_environment = 0; - expand_aliases = 0; + forced_interactive = interactive_shell = 0; + subshell_environment = running_in_background = 0; + expand_aliases = expaliases_flag = 0; + bash_argv_initialized = 0; /* XXX - should we set jobs_m_flag to 0 here? */ #if defined (HISTORY) - bash_history_reinit (0); + bash_history_reinit (enable_history_list = 0); #endif /* HISTORY */ #if defined (RESTRICTED_SHELL) @@ -1799,7 +2040,7 @@ shell_reinitialize () /* Ensure that the default startup file is used. (Except that we don't execute this file for reinitialized shells). */ - bashrc_file = "~/.bashrc"; + bashrc_file = DEFAULT_BASHRC; /* Delete all variables and functions. They will be reinitialized when the environment is parsed. */ @@ -1836,7 +2077,11 @@ show_shell_usage (fp, extra) for (i = 0, set_opts = 0; shell_builtins[i].name; i++) if (STREQ (shell_builtins[i].name, "set")) - set_opts = savestring (shell_builtins[i].short_doc); + { + set_opts = savestring (shell_builtins[i].short_doc); + break; + } + if (set_opts) { s = strchr (set_opts, '['); @@ -1856,6 +2101,9 @@ show_shell_usage (fp, extra) fprintf (fp, _("Type `%s -c \"help set\"' for more information about shell options.\n"), shell_name); fprintf (fp, _("Type `%s -c help' for more information about shell builtin commands.\n"), shell_name); fprintf (fp, _("Use the `bashbug' command to report bugs.\n")); + fprintf (fp, "\n"); + fprintf (fp, _("bash home page: \n")); + fprintf (fp, _("General help using GNU software: \n")); } }