diff options
| author | Jari Aalto <jari.aalto@cante.net> | 1996-12-23 17:02:34 +0000 |
|---|---|---|
| committer | Jari Aalto <jari.aalto@cante.net> | 2009-09-12 16:46:49 +0000 |
| commit | ccc6cda312fea9f0468ee65b8f368e9653e1380b (patch) | |
| tree | b059878adcfd876c4acb8030deda1eeb918c7e75 /shell.c | |
| parent | 726f63884db0132f01745f1fb4465e6621088ccf (diff) | |
| download | android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.tar.gz android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.tar.bz2 android_external_bash-ccc6cda312fea9f0468ee65b8f368e9653e1380b.zip | |
Imported from ../bash-2.0.tar.gz.
Diffstat (limited to 'shell.c')
| -rw-r--r-- | shell.c | 1852 |
1 files changed, 688 insertions, 1164 deletions
@@ -32,22 +32,28 @@ */ #define INSTALL_DEBUG_MODE +#include "config.h" + #include "bashtypes.h" +#include <sys/file.h> +#include "posixstat.h" +#include "bashansi.h" #include <stdio.h> #include <signal.h> #include <errno.h> -#include <sys/file.h> #include "filecntl.h" #include <pwd.h> -#include "posixstat.h" -#include "bashansi.h" -#if defined (HAVE_VARARGS_H) -#include <varargs.h> +#if defined (HAVE_UNISTD_H) +# include <unistd.h> #endif #include "shell.h" #include "flags.h" +#include "trap.h" +#include "mailcheck.h" +#include "builtins.h" +#include "builtins/common.h" #if defined (JOB_CONTROL) #include "jobs.h" @@ -62,49 +68,31 @@ #endif #include <tilde/tilde.h> +#include <glob/fnmatch.h> -#if defined (USG) && !defined (HAVE_GETPW_DECLS) +#if !defined (HAVE_GETPW_DECLS) extern struct passwd *getpwuid (); -#endif /* USG && !HAVE_GETPW_DECLS */ +#endif /* !HAVE_GETPW_DECLS */ -extern int yydebug; #if !defined (errno) extern int errno; #endif -extern char *dist_version; +extern char *dist_version, *release_status; extern int patch_level, build_version; -extern int subshell_environment; /* Found in execute_cmd.c. */ +extern int subshell_environment; extern int last_command_exit_value; -extern int return_catch_flag; -extern jmp_buf return_catch; -extern int need_here_doc, current_command_line_count, line_number; -extern char *ps1_prompt, **prompt_string_pointer; -extern int loop_level, continuing, breaking; -extern int parse_and_execute_level; +extern int line_number; +extern char *primary_prompt, *secondary_prompt; +extern int expand_aliases; 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. */ -static int shell_initialized = 0; -static int sourced_env = 0; - -/* The current maintainer of the shell. You change this in the - Makefile. */ -#if !defined (MAINTAINER) -#define MAINTAINER "bash-maintainers@prep.ai.mit.edu" -#endif - -char *the_current_maintainer = MAINTAINER; - -char *primary_prompt = PPROMPT; -char *secondary_prompt = SPROMPT; +int shell_initialized = 0; COMMAND *global_command = (COMMAND *)NULL; -/* Non-zero after SIGINT. */ -int interrupt_state = 0; - /* Information about the current user. */ struct user_info current_user = { @@ -151,46 +139,44 @@ int executing = 0; /* The number of commands executed so far. */ int current_command_number = 1; -/* The environment at the top-level REP loop. We use this in the case of - error return. */ -jmp_buf top_level, catch; - -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) -/* The signal masks that this shell runs with. */ -sigset_t top_level_mask; -#endif /* JOB_CONTROL */ - /* Non-zero is the recursion depth for commands. */ int indirection_level = 0; -/* The number of times BASH has been executed. This is set - by initialize_variables () in variables.c. */ -int shell_level = 0; - /* The name of this shell, as taken from argv[0]. */ char *shell_name = (char *)NULL; /* time in seconds when the shell was started */ time_t shell_start_time; +/* Are we running in an emacs shell window? */ +int running_under_emacs; + /* The name of the .(shell)rc file. */ static char *bashrc_file = "~/.bashrc"; /* Non-zero means to act more like the Bourne shell on startup. */ -static int act_like_sh = 0; +static int act_like_sh; + +/* Non-zero if this shell is being run by `su'. */ +static int su_shell; + +/* Non-zero if we have already expanded and sourced $ENV. */ +static int sourced_env; + +/* Is this shell running setuid? */ +static int running_setuid; /* Values for the long-winded argument names. */ -static int debugging = 0; /* Do debugging things. */ -static int no_rc = 0; /* Don't execute ~/.bashrc */ -static int no_profile = 0; /* Don't execute .profile */ -static int do_version = 0; /* Display interesting version info. */ -static int quiet = 0; /* Be quiet when starting up. */ -static int make_login_shell = 0; /* Make this shell be a `-bash' shell. */ +static int debugging; /* Do debugging things. */ +static int no_rc; /* Don't execute ~/.bashrc */ +static int no_profile; /* Don't execute .profile */ +static int do_version; /* Display interesting version info. */ +static int make_login_shell; /* Make this shell be a `-bash' shell. */ +static int want_initial_help; /* --help option */ int no_line_editing = 0; /* Don't do fancy line editing. */ -int no_brace_expansion = 0; /* Non-zero means no foo{a,b} -> fooa foob. */ - int posixly_correct = 0; /* Non-zero means posix.2 superset. */ +int dump_translatable_strings; /* Dump strings in $"...", don't execute. */ /* Some long-winded argument names. These are obviously new. */ #define Int 1 @@ -202,15 +188,19 @@ struct { char **char_value; } long_args[] = { { "debug", Int, &debugging, (char **)0x0 }, - { "norc", Int, &no_rc, (char **)0x0 }, + { "dump-strings", Int, &dump_translatable_strings, (char **)0x0 }, + { "help", Int, &want_initial_help, (char **)0x0 }, + { "login", Int, &make_login_shell, (char **)0x0 }, + { "noediting", Int, &no_line_editing, (char **)0x0 }, { "noprofile", Int, &no_profile, (char **)0x0 }, + { "norc", Int, &no_rc, (char **)0x0 }, + { "posix", Int, &posixly_correct, (char **)0x0 }, { "rcfile", Charp, (int *)0x0, &bashrc_file }, +#if defined (RESTRICTED_SHELL) + { "restricted", Int, &restricted, (char **)0x0 }, +#endif + { "verbose", Int, &echo_input_at_read, (char **)0x0 }, { "version", Int, &do_version, (char **)0x0 }, - { "quiet", Int, &quiet, (char **)0x0 }, - { "login", Int, &make_login_shell, (char **)0x0 }, - { "nolineediting", Int, &no_line_editing, (char **)0x0 }, - { "nobraceexpansion", Int, &no_brace_expansion, (char **)0x0 }, - { "posix", Int, &posixly_correct, (char **)0x0 }, { (char *)0x0, Int, (int *)0x0, (char **)0x0 } }; @@ -218,7 +208,7 @@ struct { longjmp back to main to execute a shell script, instead of calling main () again and resulting in indefinite, possibly fatal, stack growth. */ -jmp_buf subshell_top_level; +procenv_t subshell_top_level; int subshell_argc; char **subshell_argv; char **subshell_envp; @@ -228,55 +218,53 @@ char **subshell_envp; int default_buffered_input = -1; #endif -static int want_pending_command; +static int read_from_stdin; /* -s flag supplied */ +static int want_pending_command; /* -c flag supplied */ static char *local_pending_command; -static int isnetconn (); +static FILE *default_input; + +static int parse_long_options (); +static int parse_shell_options (); static void run_startup_files (); +static int bind_args (); +static int open_shell_script (); +static void set_bash_input (); +static int run_one_command (); + +static int uidget (); +static int isnetconn (); +static void init_interactive (), init_noninteractive (); +static void set_shell_name (); static void shell_initialize (); static void shell_reinitialize (); -static void initialize_signals (); -static void initialize_terminating_signals (); +static void show_shell_usage (); + +int main (argc, argv, env) int argc; char **argv, **env; { register int i; - int arg_index, locally_skip_execution; - int top_level_arg_index, read_from_stdin; - FILE *default_input; - - /* There is a bug in the NeXT 2.1 rlogind that causes opens - of /dev/tty to fail. */ -#if defined (RLOGIN_PGRP_BUG) - { - int tty_fd; - - tty_fd = open ("/dev/tty", O_RDWR); - - if (tty_fd < 0) - { - char *tty; - tty = (char *)ttyname (fileno (stdin)); - tty_fd = open (tty, O_RDWR); - } - close (tty_fd); - } -#endif /* RLOGIN_PGRP_BUG */ + int code; + volatile int locally_skip_execution; + volatile int arg_index, top_level_arg_index; + + /* Catch early SIGINTs. */ + code = setjmp (top_level); + if (code) + exit (2); + + check_dev_tty (); /* Wait forever if we are debugging a login shell. */ while (debugging_login_shell); - current_user.uid = getuid (); - current_user.gid = getgid (); - current_user.euid = geteuid (); - current_user.egid = getegid (); + set_default_locale (); - /* See whether or not we are running setuid or setgid. */ - privileged_mode = (current_user.uid != current_user.euid) || - (current_user.gid != current_user.egid); + running_setuid = uidget (); posixly_correct = (getenv ("POSIXLY_CORRECT") != (char *)NULL) || (getenv ("POSIX_PEDANTIC") != (char *)NULL); @@ -293,12 +281,10 @@ main (argc, argv, env) sourced_env = 0; } - /* Initialize local variables for all `invocations' of main (). */ + /* Initialize `local' variables for all `invocations' of main (). */ arg_index = 1; local_pending_command = (char *)NULL; - want_pending_command = 0; - locally_skip_execution = 0; - read_from_stdin = 0; + want_pending_command = locally_skip_execution = read_from_stdin = 0; default_input = stdin; #if defined (BUFFERED_INPUT) default_buffered_input = -1; @@ -321,75 +307,28 @@ main (argc, argv, env) exit (2); } - /* Here's a hack. If the name of this shell is "sh", then don't do - any startup files; just try to be more like /bin/sh. */ - /* XXX - next version - make this be the same as -posix. */ - shell_name = base_pathname (argv[0]); - if (*shell_name == '-') - shell_name++; - if (shell_name[0] == 's' && shell_name[1] == 'h' && !shell_name[2]) - act_like_sh++; - - yydebug = 0; - shell_environment = env; - shell_name = argv[0]; - dollar_vars[0] = savestring (shell_name); - - if (*shell_name == '-') - { - shell_name++; - login_shell++; - } - -#if defined (JOB_CONTROL) - if (act_like_sh) - job_control = 0; /* XXX - not posix */ -#endif /* JOB_CONTROL */ - + set_shell_name (argv[0]); shell_start_time = NOW; /* NOW now defined in general.h */ - /* A program may start an interactive shell with - "execl ("/bin/bash", "-", NULL)". - If so, default the name of this shell to our name. */ - if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) - shell_name = "bash"; - /* Parse argument flags from the input line. */ /* Find full word arguments first. */ - while ((arg_index != argc) && *(argv[arg_index]) == '-') + arg_index = parse_long_options (argv, arg_index, argc); + + if (want_initial_help) { - for (i = 0; long_args[i].name; i++) - { - if (STREQ (&(argv[arg_index][1]), long_args[i].name)) - { - if (long_args[i].type == Int) - *long_args[i].int_value = 1; - else - { - if (!argv[++arg_index]) - { - report_error ("option `%s' expected an argument", - long_args[i].name); - exit (1); - } - else - *long_args[i].char_value = argv[arg_index]; - } - goto handle_next_arg; - } - } - break; /* No such argument. Maybe flag arg. */ - handle_next_arg: - arg_index++; + show_shell_usage (stdout); + exit (EXECUTION_SUCCESS); } - /* If we're in a strict Posix.2 mode, turn on interactive comments. */ - if (posixly_correct) - interactive_comments = 1; + if (do_version) + { + show_shell_version (1); + exit (EXECUTION_SUCCESS); + } - /* If user supplied the "-login" flag, then set and invert LOGIN_SHELL. */ + /* If user supplied the "--login" flag, then set and invert LOGIN_SHELL. */ if (make_login_shell) { login_shell++; @@ -398,66 +337,18 @@ main (argc, argv, env) /* All done with full word options; do standard shell option parsing.*/ this_command_name = shell_name; /* for error reporting */ - while (arg_index != argc && argv[arg_index] && - (*argv[arg_index] == '-' || *argv[arg_index] == '+')) - { - /* There are flag arguments, so parse them. */ - int arg_character, on_or_off, next_arg; - char *o_option, *arg_string; - - i = 1; - next_arg = arg_index + 1; - arg_string = argv[arg_index]; - on_or_off = arg_string[0]; - - /* A single `-' signals the end of options. From the 4.3 BSD sh. - An option `--' means the same thing; this is the standard - getopt(3) meaning. */ - if (arg_string[0] == '-' && - (arg_string[1] == '\0' || - (arg_string[1] == '-' && arg_string[2] == '\0'))) - { - arg_index++; - break; - } - - while (arg_character = arg_string[i++]) - { - switch (arg_character) - { - case 'c': - want_pending_command = 1; - break; + arg_index = parse_shell_options (argv, arg_index, argc); - case 's': - read_from_stdin = 1; - break; - - case 'o': - o_option = argv[next_arg]; - if (!o_option) - { - list_minus_o_opts (); - break; - } - if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) - exit (1); - next_arg++; - break; + if (dump_translatable_strings) + read_but_dont_execute = 1; - default: - if (change_flag (arg_character, on_or_off) == FLAG_ERROR) - { - report_error ("%c%c: bad option", on_or_off, arg_character); - exit (1); - } + /* If we're in a strict Posix.2 mode, turn on interactive comments and + other Posix.2 things. */ + if (posixly_correct) + posix_initialize (posixly_correct); - } - } - /* Can't do just a simple increment anymore -- what about - "bash -abouo emacs ignoreeof -hP"? */ - arg_index = next_arg; - } + if (running_setuid && privileged_mode == 0) + disable_priv_mode (); /* Need to get the argument to a -c option processed in the above loop. The next arg is a command to execute, and the @@ -465,14 +356,14 @@ main (argc, argv, env) if (want_pending_command) { local_pending_command = argv[arg_index]; - if (!local_pending_command) + if (local_pending_command == 0) { - report_error ("`-c' requires an argument"); - exit (1); + report_error ("option `-c' requires an argument"); + exit (EX_USAGE); } arg_index++; } - this_command_name = (char *)NULL; + this_command_name = (char *)NULL; /* First, let the outside world know about our interactive status. A shell is interactive if the `-i' flag was given, or if all of @@ -489,23 +380,9 @@ main (argc, argv, env) read_from_stdin) && /* -s flag with args, and */ isatty (fileno (stdin)) && /* Input is a terminal and */ isatty (fileno (stdout)))) /* output is a terminal. */ - { - interactive_shell = startup_state = interactive = 1; - } + init_interactive (); else - { -#if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; -#endif /* HISTORY */ - interactive_shell = startup_state = interactive = 0; - no_line_editing = 1; -#if defined (JOB_CONTROL) - job_control = 0; -#endif /* JOB_CONTROL */ - } + init_noninteractive (); #define CLOSE_FDS_AT_LOGIN #if defined (CLOSE_FDS_AT_LOGIN) @@ -527,43 +404,42 @@ main (argc, argv, env) Variables from the environment are expected to be set, etc. */ shell_initialize (); + set_default_locale_vars (); + if (interactive_shell) { - char *term = getenv ("TERM"); + char *term; + + term = getenv ("TERM"); no_line_editing |= term && (STREQ (term, "emacs")); + term = getenv ("EMACS"); + running_under_emacs = term ? ((fnmatch ("*term*", term, 0) == 0) ? 2 : 1) + : 0; } top_level_arg_index = arg_index; - if (!quiet && do_version) - show_shell_version (); - /* 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. */ - { - int code; - - code = setjmp (top_level); - - if (code) - { - if (code == EXITPROG) - goto exit_shell; - else - locally_skip_execution++; - } - } + code = setjmp (top_level); + if (code) + { + if (code == EXITPROG) + exit_shell (last_command_exit_value); + else + locally_skip_execution++; + } arg_index = top_level_arg_index; /* Execute the start-up scripts. */ - if (!interactive_shell) + if (interactive_shell == 0) { makunbound ("PS1", shell_variables); makunbound ("PS2", shell_variables); - interactive = 0; + interactive = expand_aliases = 0; } else { @@ -571,43 +447,52 @@ main (argc, argv, env) interactive = 1; } - if (!locally_skip_execution) + if (locally_skip_execution == 0 && running_setuid == 0) run_startup_files (); + /* If we are invoked as `sh', turn on Posix mode. */ + if (act_like_sh) + posix_initialize (posixly_correct = 1); + #if defined (RESTRICTED_SHELL) - /* I turn on the restrictions afterwards because it is explictly - stated in the POSIX spec that PATH cannot be set in a restricted - shell, except in .profile. */ - maybe_make_restricted (shell_name); + /* Turn on the restrictions after parsing the startup files. */ + maybe_make_restricted (shell_name); #endif /* RESTRICTED_SHELL */ - if (local_pending_command) - { - /* Bind remaining args to $0 ... $n */ - WORD_LIST *args = (WORD_LIST *)NULL; - while (arg_index != argc) - args = make_word_list (make_word (argv[arg_index++]), args); - if (args) - { - args = REVERSE_LIST (args, WORD_LIST *); - /* Posix.2 4.56.3 says that the first argument after - sh -c command becomes $0, and the rest of the arguments - are bound to $1 ... $N. */ - shell_name = savestring (args->word->word); /* XXX */ - dollar_vars[0] = savestring (args->word->word); - remember_args (args->next, 1); - dispose_words (args); - } - - startup_state = 2; + if (local_pending_command) + { + arg_index = bind_args (argv, arg_index, argc, 0); + + startup_state = 2; #if defined (ONESHOT) - run_one_command (local_pending_command); - goto exit_shell; + run_one_command (local_pending_command); + exit_shell (last_command_exit_value); #else /* ONESHOT */ - with_input_from_string (local_pending_command, "-c"); - goto read_and_execute; + with_input_from_string (local_pending_command, "-c"); + goto read_and_execute; #endif /* !ONESHOT */ - } + } + + /* 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++; + } + else if (interactive == 0) + /* 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 */ +#else + setbuf (default_input, (char *)NULL); +#endif /* !BUFFERED_INPUT */ + + set_bash_input (); + + /* Bind remaining args to $1 ... $n */ + arg_index = bind_args (argv, arg_index, argc, 1); /* Do the things that should be done only for interactive shells. */ if (interactive_shell) @@ -618,7 +503,8 @@ main (argc, argv, env) #if defined (HISTORY) /* Initialize the interactive history stuff. */ - if (!shell_initialized) + bash_initialize_history (); + if (shell_initialized == 0) load_history (); #endif /* HISTORY */ @@ -627,180 +513,151 @@ main (argc, argv, env) get_tty_state (); } - /* Get possible input filename. */ - if ((arg_index != argc) && !read_from_stdin) - { - int fd; - char *filename; +#if !defined (ONESHOT) + read_and_execute: +#endif /* !ONESHOT */ - free (dollar_vars[0]); - dollar_vars[0] = savestring (argv[arg_index]); - filename = savestring (argv[arg_index]); + shell_initialized = 1; - fd = open (filename, O_RDONLY); - if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) - { - char *path_filename; - /* If it's not in the current directory, try looking through PATH - for it. */ - path_filename = find_path_file (argv[arg_index]); - if (path_filename) - { - free (filename); - filename = path_filename; - fd = open (filename, O_RDONLY); - } - } + /* Read commands until exit condition. */ + reader_loop (); + exit_shell (last_command_exit_value); +} - arg_index++; - if (fd < 0) +static int +parse_long_options (argv, arg_start, arg_end) + char **argv; + int arg_start, arg_end; +{ + int arg_index, longarg, i; + char *arg_string; + + arg_index = arg_start; + while ((arg_index != arg_end) && (arg_string = argv[arg_index]) && + (*arg_string == '-')) + { + longarg = 0; + + /* Make --login equivalent to -login. */ + if (arg_string[1] == '-' && arg_string[2]) { - file_error (filename); - exit (1); + longarg = 1; + arg_string++; } - /* Only do this with file descriptors we can seek on. */ - if (lseek (fd, 0L, 1) != -1) + for (i = 0; long_args[i].name; i++) { - unsigned char sample[80]; - int sample_len; - - /* Check to see if the `file' in `bash file' is a binary file - according to the same tests done by execute_simple_command (), - and report an error and exit if it is. */ - sample_len = read (fd, sample, sizeof (sample)); - if (sample_len > 0 && (check_binary_file (sample, sample_len))) + if (STREQ (arg_string + 1, long_args[i].name)) { - report_error ("%s: cannot execute binary file", filename); - exit (EX_BINARY_FILE); + if (long_args[i].type == Int) + *long_args[i].int_value = 1; + else if (argv[++arg_index] == 0) + { + report_error ("option `%s' requires an argument", + long_args[i].name); + exit (EX_USAGE); + } + else + *long_args[i].char_value = argv[arg_index]; + + break; } - /* Now rewind the file back to the beginning. */ - lseek (fd, 0L, 0); } - -#if defined (BUFFERED_INPUT) - default_buffered_input = fd; - if (default_buffered_input == -1) + if (long_args[i].name == 0) { - file_error (filename); - exit (127); + if (longarg) + { + report_error ("%s: unrecognized option", argv[arg_index]); + exit (EX_USAGE); + } + break; /* No such argument. Maybe flag arg. */ } - SET_CLOSE_ON_EXEC (default_buffered_input); -#else /* !BUFFERED_INPUT */ + arg_index++; + } - /* Open the script. But try to move the file descriptor to a randomly - large one, in the hopes that any descriptors used by the script will - not match with ours. */ - { - int script_fd, nfds; - - nfds = getdtablesize (); - if (nfds <= 0) - nfds = 20; - if (nfds > 256) - nfds = 256; - script_fd = dup2 (fd, nfds - 1); - if (script_fd) - { - close (fd); - fd = script_fd; - } - } - - default_input = fdopen (fd, "r"); - - if (!default_input) - { - file_error (filename); - exit (127); - } + return (arg_index); +} - SET_CLOSE_ON_EXEC (fd); - if (fileno (default_input) != fd) - SET_CLOSE_ON_EXEC (fileno (default_input)); +static int +parse_shell_options (argv, arg_start, arg_end) + char **argv; + int arg_start, arg_end; +{ + int arg_index; + int arg_character, on_or_off, next_arg, i; + char *o_option, *arg_string; -#endif /* !BUFFERED_INPUT */ + arg_index = arg_start; + while (arg_index != arg_end && (arg_string = argv[arg_index]) && + (*arg_string == '-' || *arg_string == '+')) + { + /* There are flag arguments, so parse them. */ + next_arg = arg_index + 1; - if (!interactive_shell || (!isatty (fd))) - { -#if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; -#endif /* HISTORY */ - interactive = interactive_shell = 0; - no_line_editing = 1; -#if defined (JOB_CONTROL) - set_job_control (0); -#endif /* JOB_CONTROL */ - } - else - { - /* I don't believe that this code is ever executed, even in - the presence of /dev/fd. */ - dup2 (fd, 0); - close (fd); - fclose (default_input); - } - } - else if (!interactive) - /* 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 */ -#else - setbuf (default_input, (char *)NULL); -#endif /* !BUFFERED_INPUT */ + /* A single `-' signals the end of options. From the 4.3 BSD sh. + An option `--' means the same thing; this is the standard + getopt(3) meaning. */ + if (arg_string[0] == '-' && + (arg_string[1] == '\0' || + (arg_string[1] == '-' && arg_string[2] == '\0'))) + return (next_arg); - /* Bind remaining args to $1 ... $n */ - { - WORD_LIST *args = (WORD_LIST *)NULL; - while (arg_index != argc) - args = make_word_list (make_word (argv[arg_index++]), args); - args = REVERSE_LIST (args, WORD_LIST *); - remember_args (args, 1); - dispose_words (args); - } + i = 1; + on_or_off = arg_string[0]; + while (arg_character = arg_string[i++]) + { + switch (arg_character) + { + case 'c': + want_pending_command = 1; + break; -#if defined (BUFFERED_INPUT) - if (!interactive) - unset_nodelay_mode (default_buffered_input); - else - unset_nodelay_mode (fileno (stdin)); -#else - unset_nodelay_mode (fileno (stdin)); -#endif /* !BUFFERED_INPUT */ + case 's': + read_from_stdin = 1; + break; - /* with_input_from_stdin really means `with_input_from_readline' */ - if (interactive && !no_line_editing) - with_input_from_stdin (); - else -#if defined (BUFFERED_INPUT) - { - if (!interactive) - with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); - else - with_input_from_stream (default_input, dollar_vars[0]); - } -#else /* !BUFFERED_INPUT */ - with_input_from_stream (default_input, dollar_vars[0]); -#endif /* !BUFFERED_INPUT */ + case 'o': + o_option = argv[next_arg]; + if (o_option == 0) + { + list_minus_o_opts (); + break; + } + if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS) + exit (EX_USAGE); + next_arg++; + break; -#if !defined (ONESHOT) - read_and_execute: -#endif /* !ONESHOT */ + case 'D': + dump_translatable_strings = 1; + break; - shell_initialized = 1; + default: + if (change_flag (arg_character, on_or_off) == FLAG_ERROR) + { + report_error ("%c%c: unrecognized option", on_or_off, arg_character); + exit (EX_USAGE); + } + } + } + /* Can't do just a simple increment anymore -- what about + "bash -abouo emacs ignoreeof -hP"? */ + arg_index = next_arg; + } - /* Read commands until exit condition. */ - reader_loop (); + return (arg_index); +} - exit_shell: - /* Do trap[0] if defined. */ +/* Exit the shell with status S. */ +int +exit_shell (s) + int s; +{ + /* Do trap[0] if defined. Allow it to override the exit status + passed to us. */ if (signal_is_trapped (0)) - last_command_exit_value = run_exit_trap (); + s = run_exit_trap (); #if defined (PROCESS_SUBSTITUTION) unlink_fifo_list (); @@ -818,51 +675,23 @@ main (argc, argv, env) #endif /* JOB_CONTROL */ /* Always return the exit status of the last command to our parent. */ - exit (last_command_exit_value); + exit (s); } -#if !defined (SYS_PROFILE) -# define SYS_PROFILE "/etc/profile" -#endif /* !SYS_PROFILE */ - /* 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 - for both interactive and non-interactive shells (section 4.56.5.3) */ -static void -run_startup_files () -{ - if (!posixly_correct) - { - if (login_shell) - { - /* We don't execute .bashrc for login shells. */ - no_rc++; - if (no_profile == 0) - maybe_execute_file (SYS_PROFILE, 1); - } - - if (login_shell && !no_profile) - { - if (act_like_sh) - maybe_execute_file ("~/.profile", 1); - else - { - if (maybe_execute_file ("~/.bash_profile", 1) == 0) - if (maybe_execute_file ("~/.bash_login", 1) == 0) - maybe_execute_file ("~/.profile", 1); - } - } + for interactive shells only. (section 4.56.5.3) */ - /* Execute ~/.bashrc for most shells. Never execute it if - ACT_LIKE_SH is set, or if NO_RC is set. +/* Execute ~/.bashrc for most shells. Never execute it if + ACT_LIKE_SH is set, or if NO_RC is set. - If the executable file "/usr/gnu/src/bash/foo" contains: + If the executable file "/usr/gnu/src/bash/foo" contains: - #!/usr/gnu/bin/bash - echo hello + #!/usr/gnu/bin/bash + echo hello - then: + then: COMMAND EXECUTE BASHRC -------------------------------- @@ -874,154 +703,158 @@ run_startup_files () echo ls | bash NO login NO bash YES - */ - if (!act_like_sh && !no_rc && - (interactive_shell || (isnetconn (fileno (stdin)) && - local_pending_command))) - maybe_execute_file (bashrc_file, 1); +*/ + +static void +execute_env_file (env_file) + char *env_file; +{ + char *fn; + WORD_LIST *list; + + if (env_file && *env_file) + { + list = expand_string_unsplit (env_file, Q_DOUBLE_QUOTES); + if (list) + { + fn = string_list (list); + dispose_words (list); + + if (fn && *fn) + maybe_execute_file (fn, 1); + FREE (fn); + } } +} - /* Try a TMB suggestion. If running a script, then execute the - file mentioned in the ENV variable. */ - if (!privileged_mode && sourced_env++ == 0 && act_like_sh == 0 && - (posixly_correct || !interactive_shell)) +static void +run_startup_files () +{ + /* get the rshd case out of the way first. */ + if (interactive_shell == 0 && no_rc == 0 && login_shell == 0 && + act_like_sh == 0 && local_pending_command && isnetconn (fileno (stdin))) { - char *env_file = (char *)NULL; +#ifdef SYS_BASHRC + maybe_execute_file (SYS_BASHRC, 1); +#endif + maybe_execute_file (bashrc_file, 1); + return; + } - if (!posixly_correct) - env_file = getenv ("BASH_ENV"); - if (!env_file) - env_file = getenv ("ENV"); + /* A non-interactive shell not named `sh' and not in posix mode reads and + executes commands from $BASH_ENV. If `su' starts a shell with `-c cmd' + and `-su' as the name of the shell, we want to read the startup files. + No other non-interactive shells read any startup files. */ + if (interactive_shell == 0 && !(su_shell && login_shell)) + { + if (posixly_correct == 0 && act_like_sh == 0 && privileged_mode == 0 && + sourced_env++ == 0) + execute_env_file (get_string_value ("BASH_ENV")); + return; + } - if (env_file && *env_file) - { - WORD_LIST *list; - char *expanded_file_name; + /* Interactive shell or `-su' shell. */ + if (posixly_correct == 0) /* bash, sh */ + { + /* We don't execute .bashrc for login shells. */ + if (login_shell) + no_rc++; - list = expand_string_unsplit (env_file, 1); - if (list) - { - expanded_file_name = string_list (list); - dispose_words (list); + /* Execute /etc/profile and one of the personal login shell + initialization files. */ + if (login_shell && no_profile == 0) + { + maybe_execute_file (SYS_PROFILE, 1); - if (expanded_file_name && *expanded_file_name) - maybe_execute_file (expanded_file_name, 1); + if (act_like_sh) /* sh */ + maybe_execute_file ("~/.profile", 1); + else if ((maybe_execute_file ("~/.bash_profile", 1) == 0) && + (maybe_execute_file ("~/.bash_login", 1) == 0)) /* bash */ + maybe_execute_file ("~/.profile", 1); + } - if (expanded_file_name) - free (expanded_file_name); - } + /* bash */ + if (act_like_sh == 0 && no_rc == 0) + { +#ifdef SYS_BASHRC + maybe_execute_file (SYS_BASHRC, 1); +#endif + maybe_execute_file (bashrc_file, 1); } + /* sh */ + else if (act_like_sh && privileged_mode == 0 && sourced_env++ == 0) + execute_env_file (get_string_value ("ENV")); + } + else /* bash --posix, sh --posix */ + { + /* bash and sh */ + if (interactive_shell && privileged_mode == 0 && sourced_env++ == 0) + execute_env_file (get_string_value ("ENV")); } } #if defined (RESTRICTED_SHELL) -/* Perhaps make this shell a `restricted' one, based on NAME. - If the basename of NAME is "rbash", then this shell is restricted. +/* Perhaps make this shell a `restricted' one, based on NAME. If the + basename of NAME is "rbash", then this shell is restricted. The + name of the restricted shell is a configurable option, see config.h. In a restricted shell, PATH and SHELL are read-only and non-unsettable. Do this also if `restricted' is already set to 1; maybe the shell was started with -r. */ +int maybe_make_restricted (name) char *name; { char *temp; temp = base_pathname (shell_name); - if (restricted || (STREQ (temp, "rbash"))) + if (restricted || (STREQ (temp, RESTRICTED_SHELL_NAME))) { set_var_read_only ("PATH"); - non_unsettable ("PATH"); set_var_read_only ("SHELL"); - non_unsettable ("SHELL"); restricted++; } + return (restricted); } #endif /* RESTRICTED_SHELL */ -/* Try to execute the contents of FNAME. If FNAME doesn't exist, - that is not an error, but other kinds of errors are. A non-zero - FORCE_NONINTERACTIVE means to set the value of `interactive' to - 0 so things like job control are disabled; the value is unchanged - otherwise. Returns -1 in the case of an error, 0 in the case that - the file was not found, and 1 if the file was found and executed. */ -maybe_execute_file (fname, force_noninteractive) - char *fname; - int force_noninteractive; +/* Fetch the current set of uids and gids and return 1 if we're running + setuid or setgid. */ +static int +uidget () { - jmp_buf old_return_catch; - int return_val, fd, tresult, old_interactive; - char *filename, *string; - struct stat file_info; + uid_t u; - filename = tilde_expand (fname); - fd = open (filename, O_RDONLY); - - if (fd < 0) + u = getuid (); + if (current_user.uid != u) { -file_error_and_exit: - if (errno != ENOENT) - file_error (filename); - free (filename); - return ((errno == ENOENT) ? 0 : -1); + FREE (current_user.user_name); + FREE (current_user.shell); + FREE (current_user.home_dir); + current_user.user_name = current_user.shell = current_user.home_dir = (char *)NULL; } + current_user.uid = u; + current_user.gid = getgid (); + current_user.euid = geteuid (); + current_user.egid = getegid (); - if (fstat (fd, &file_info) == -1) - goto file_error_and_exit; - - if (S_ISDIR (file_info.st_mode)) - { - internal_error ("%s: cannot execute directories", filename); - free (filename); - return -1; - } - - string = (char *)xmalloc (1 + (int)file_info.st_size); - tresult = read (fd, string, file_info.st_size); - - { - int tt = errno; - close (fd); - errno = tt; - } - - if (tresult != file_info.st_size) - { - free (string); - goto file_error_and_exit; - } - string[file_info.st_size] = '\0'; - - return_catch_flag++; - xbcopy ((char *)return_catch, (char *)old_return_catch, sizeof (jmp_buf)); - - if (force_noninteractive) - { - old_interactive = interactive; - interactive = 0; - } - - return_val = setjmp (return_catch); - - /* If `return' was seen outside of a function, but in the script, then - force parse_and_execute () to clean up. */ - if (return_val) - parse_and_execute_cleanup (); - else - tresult = parse_and_execute (string, filename, -1); - - if (force_noninteractive) - interactive = old_interactive; - - return_catch_flag--; - xbcopy ((char *)old_return_catch, (char *)return_catch, sizeof (jmp_buf)); - - free (filename); + /* See whether or not we are running setuid or setgid. */ + return (current_user.uid != current_user.euid) || + (current_user.gid != current_user.egid); +} - return (1); +void +disable_priv_mode () +{ + setuid (current_user.uid); + setgid (current_user.gid); + current_user.euid = current_user.uid; + current_user.egid = current_user.gid; } #if defined (ONESHOT) /* Run one command, given as the argument to the -c option. Tell parse_and_execute not to fork for a simple command. */ +static int run_one_command (command) char *command; { @@ -1044,232 +877,229 @@ run_one_command (command) case DISCARD: return last_command_exit_value = 1; default: - programming_error ("Bad jump %d", code); + programming_error ("run_one_command: bad jump: code %d", code); } } return (parse_and_execute (savestring (command), "-c", -1)); } #endif /* ONESHOT */ -reader_loop () +static int +bind_args (argv, arg_start, arg_end, start_index) + char **argv; + int arg_start, arg_end, start_index; { - int our_indirection_level; - COMMAND *current_command = (COMMAND *)NULL; - - our_indirection_level = ++indirection_level; + register int i; + WORD_LIST *args; - while (!EOF_Reached) + for (i = arg_start, args = (WORD_LIST *)NULL; i != arg_end; i++) + args = make_word_list (make_word (argv[i]), args); + if (args) { - int code; - - code = setjmp (top_level); - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - if (interactive_shell && signal_is_ignored (SIGINT) == 0) - set_signal_handler (SIGINT, sigint_sighandler); - - if (code != NOT_JUMPED) + args = REVERSE_LIST (args, WORD_LIST *); + if (start_index == 0) /* bind to $0...$n for sh -c command */ { - indirection_level = our_indirection_level; - - switch (code) - { - /* Some kind of throw to top_level has occured. */ - case FORCE_EOF: - case EXITPROG: - current_command = (COMMAND *)NULL; - EOF_Reached = EOF; - goto exec_done; - - case DISCARD: - /* Obstack free command elements, etc. */ - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - last_command_exit_value = 1; - break; - - default: - programming_error ("Bad jump %d", code); - } + /* Posix.2 4.56.3 says that the first argument after sh -c command + becomes $0, and the rest of the arguments become $1...$n */ + shell_name = savestring (args->word->word); + dollar_vars[0] = savestring (args->word->word); + remember_args (args->next, 1); } + else /* bind to $1...$n for shell script */ + remember_args (args, 1); - executing = 0; - dispose_used_env_vars (); + dispose_words (args); + } -#if (defined (Ultrix) && defined (mips)) || !defined (HAVE_ALLOCA) - /* Attempt to reclaim memory allocated with alloca (). */ - (void) alloca (0); -#endif + return (i); +} - if (read_command () == 0) - { - if (global_command) - { - current_command = global_command; +void +unbind_args () +{ + remember_args ((WORD_LIST *)NULL, 1); +} - current_command_number++; +static int +open_shell_script (script_name) + char *script_name; +{ + int fd; + char *filename, *path_filename; + unsigned char sample[80]; + int sample_len; - /* POSIX spec: "-n: The shell reads commands but does - not execute them; this can be used to check for shell - script syntax errors. The shell ignores the -n option - for interactive shells. " */ - if (interactive_shell || !read_but_dont_execute) - { - executing = 1; - execute_command (current_command); - } + free (dollar_vars[0]); + dollar_vars[0] = savestring (script_name); + filename = savestring (script_name); - exec_done: - if (current_command) - { - dispose_command (current_command); - current_command = (COMMAND *)NULL; - } - QUIT; - } - } - else + fd = open (filename, O_RDONLY); + if ((fd < 0) && (errno == ENOENT) && (absolute_program (filename) == 0)) + { + /* If it's not in the current directory, try looking through PATH + for it. */ + path_filename = find_path_file (script_name); + if (path_filename) { - /* Parse error, maybe discard rest of stream if not interactive. */ - if (!interactive) - EOF_Reached = EOF; + free (filename); + filename = path_filename; + fd = open (filename, O_RDONLY); } - if (just_one_command) - EOF_Reached = EOF; } - indirection_level--; -} - -/* Return a string denoting what our indirection level is. */ -static char indirection_string[100]; -char * -indirection_level_string () -{ - register int i, j; - char *ps4; + if (fd < 0) + { + int e = errno; + file_error (filename); + exit ((e == ENOENT) ? EX_NOTFOUND : EX_NOINPUT); + } - indirection_string[0] = '\0'; - ps4 = get_string_value ("PS4"); + /* Only do this with file descriptors we can seek on. */ + if (lseek (fd, 0L, 1) != -1) + { + /* Check to see if the `file' in `bash file' is a binary file + according to the same tests done by execute_simple_command (), + and report an error and exit if it is. */ + sample_len = read (fd, sample, sizeof (sample)); + if (sample_len > 0 && (check_binary_file (sample, sample_len))) + { + internal_error ("%s: cannot execute binary file", filename); + exit (EX_BINARY_FILE); + } + /* Now rewind the file back to the beginning. */ + lseek (fd, 0L, 0); + } - if (ps4 == 0 || *ps4 == '\0') - return (indirection_string); - - ps4 = decode_prompt_string (ps4); +#if defined (BUFFERED_INPUT) + default_buffered_input = fd; + if (default_buffered_input == -1) + { + file_error (filename); + exit (EX_NOTFOUND); + } + SET_CLOSE_ON_EXEC (default_buffered_input); +#else /* !BUFFERED_INPUT */ + /* Open the script. But try to move the file descriptor to a randomly + large one, in the hopes that any descriptors used by the script will + not match with ours. */ + fd = move_to_high_fd (fd, 0); - for (i = 0; *ps4 && i < indirection_level && i < 99; i++) - indirection_string[i] = *ps4; + default_input = fdopen (fd, "r"); - for (j = 1; *ps4 && ps4[j] && i < 99; i++, j++) - indirection_string[i] = ps4[j]; + if (default_input == 0) + { + file_error (filename); + exit (EX_NOTFOUND); + } - indirection_string[i] = '\0'; - free (ps4); - return (indirection_string); -} + SET_CLOSE_ON_EXEC (fd); + if (fileno (default_input) != fd) + SET_CLOSE_ON_EXEC (fileno (default_input)); +#endif /* !BUFFERED_INPUT */ -static sighandler -alrm_catcher(i) - int i; -{ - printf ("%ctimed out waiting for input: auto-logout\n", '\07'); - longjmp (top_level, EXITPROG); -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* !VOID_SIGHANDLER */ + if (interactive_shell == 0 || isatty (fd) == 0) + init_noninteractive (); + else + { + /* I don't believe that this code is ever executed, even in + the presence of /dev/fd. */ + dup2 (fd, 0); + close (fd); + fd = 0; +#if defined (BUFFERED_INPUT) + default_buffered_input = 0; +#else + fclose (default_input); + default_input = stdin; +#endif + } + free (filename); + return (fd); } -parse_command () +/* Initialize the input routines for the parser. */ +static void +set_bash_input () { - int r; - - need_here_doc = 0; - run_pending_traps (); + /* Make sure the fd from which we are reading input is not in + no-delay mode. */ +#if defined (BUFFERED_INPUT) + if (interactive == 0) + unset_nodelay_mode (default_buffered_input); + else +#endif /* !BUFFERED_INPUT */ + unset_nodelay_mode (fileno (stdin)); - /* Allow the execution of a random command just before the printing - of each primary prompt. If the shell variable PROMPT_COMMAND - is set then the value of it is the command to execute. */ - if (interactive && bash_input.type != st_string) + /* with_input_from_stdin really means `with_input_from_readline' */ + if (interactive && no_line_editing == 0) + with_input_from_stdin (); + else +#if defined (BUFFERED_INPUT) { - char *command_to_execute; - - command_to_execute = get_string_value ("PROMPT_COMMAND"); - if (command_to_execute) - execute_prompt_command (command_to_execute); + if (interactive == 0) + with_input_from_buffered_stream (default_buffered_input, dollar_vars[0]); + else + with_input_from_stream (default_input, dollar_vars[0]); } - - current_command_line_count = 0; - r = yyparse (); - - if (need_here_doc) - gather_here_documents (); - - return (r); +#else /* !BUFFERED_INPUT */ + with_input_from_stream (default_input, dollar_vars[0]); +#endif /* !BUFFERED_INPUT */ } -read_command () +#if !defined (PROGRAM) +# define PROGRAM "bash" +#endif + +static void +set_shell_name (argv0) + char *argv0; { - SHELL_VAR *tmout_var = (SHELL_VAR *)NULL; - int tmout_len = 0, result; - SigHandler *old_alrm = (SigHandler *)NULL; + /* Here's a hack. If the name of this shell is "sh", then don't do + any startup files; just try to be more like /bin/sh. */ + shell_name = base_pathname (argv0); + if (*shell_name == '-') + shell_name++; + if (shell_name[0] == 's' && shell_name[1] == 'h' && shell_name[2] == '\0') + act_like_sh++; + if (shell_name[0] == 's' && shell_name[1] == 'u' && shell_name[2] == '\0') + su_shell++; - prompt_string_pointer = &ps1_prompt; - global_command = (COMMAND *)NULL; + shell_name = argv0; + FREE (dollar_vars[0]); + dollar_vars[0] = savestring (shell_name); - /* Only do timeouts if interactive. */ - if (interactive) + if (*shell_name == '-') { - tmout_var = find_variable ("TMOUT"); - - if (tmout_var && tmout_var->value) - { - tmout_len = atoi (tmout_var->value); - if (tmout_len > 0) - { - old_alrm = set_signal_handler (SIGALRM, alrm_catcher); - alarm (tmout_len); - } - } + shell_name++; + login_shell++; } - QUIT; - - current_command_line_count = 0; - result = parse_command (); + /* A program may start an interactive shell with + "execl ("/bin/bash", "-", NULL)". + If so, default the name of this shell to our name. */ + if (!shell_name || !*shell_name || (shell_name[0] == '-' && !shell_name[1])) + shell_name = PROGRAM; +} - if (interactive && tmout_var && (tmout_len > 0)) - { - alarm(0); - set_signal_handler (SIGALRM, old_alrm); - } - return (result); +static void +init_interactive () +{ + interactive_shell = startup_state = interactive = 1; + expand_aliases = 1; } -/* Cause STREAM to buffer lines as opposed to characters or blocks. */ static void -line_buffer_stream (stream) - FILE *stream; +init_noninteractive () { - /* If your machine doesn't have either of setlinebuf or setvbuf, - you can just comment out the buffering commands, and the shell - will still work. It will take more cycles, though. */ -#if defined (HAVE_SETLINEBUF) - setlinebuf (stream); -#else -# if defined (_IOLBF) -# if defined (REVERSED_SETVBUF_ARGS) - setvbuf (stream, _IOLBF, (char *)NULL, BUFSIZ); -# else /* !REVERSED_SETVBUF_ARGS */ - setvbuf (stream, (char *)NULL, _IOLBF, BUFSIZ); -# endif /* !REVERSED_SETVBUF_ARGS */ -# endif /* _IOLBF */ -#endif /* !HAVE_SETLINEBUF */ +#if defined (HISTORY) + bash_history_reinit (0); +#endif /* HISTORY */ + interactive_shell = startup_state = interactive = 0; + expand_aliases = 0; + no_line_editing = 1; +#if defined (JOB_CONTROL) + set_job_control (0); +#endif /* JOB_CONTROL */ } /* Do whatever is necessary to initialize the shell. @@ -1277,9 +1107,12 @@ line_buffer_stream (stream) static void shell_initialize () { + struct passwd *entry; + char hostname[256]; + /* Line buffer output for stderr and stdout. */ - line_buffer_stream (stderr); - line_buffer_stream (stdout); + setlinebuf (stderr); + setlinebuf (stdout); /* Sort the array of shell builtins so that the binary search in find_shell_builtin () works correctly. */ @@ -1292,40 +1125,48 @@ shell_initialize () initialize_traps (); initialize_signals (); - /* Initialize current_user.name and current_host_name. */ - { - struct passwd *entry = getpwuid (current_user.uid); - char hostname[256]; - - if (gethostname (hostname, 255) < 0) - current_host_name = "??host??"; - else - current_host_name = savestring (hostname); - - if (entry) - { - current_user.user_name = savestring (entry->pw_name); - if (entry->pw_shell && entry->pw_shell[0]) - current_user.shell = savestring (entry->pw_shell); - else + /* It's highly unlikely that this will change. */ + if (current_host_name == 0) + { + /* Initialize current_user.name and current_host_name. */ + if (gethostname (hostname, 255) < 0) + current_host_name = "??host??"; + else + current_host_name = savestring (hostname); + } + + /* Don't fetch this more than once. */ + if (current_user.user_name == 0) + { + entry = getpwuid (current_user.uid); + if (entry) + { + current_user.user_name = savestring (entry->pw_name); + current_user.shell = (entry->pw_shell && entry->pw_shell[0]) + ? savestring (entry->pw_shell) + : savestring ("/bin/sh"); + current_user.home_dir = savestring (entry->pw_dir); + } + else + { + current_user.user_name = savestring ("I have no name!"); current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring (entry->pw_dir); - } - else - { - current_user.user_name = savestring ("I have no name!"); - current_user.shell = savestring ("/bin/sh"); - current_user.home_dir = savestring ("/"); - } - - endpwent (); - } + current_user.home_dir = savestring ("/"); + } + endpwent (); + } /* Initialize our interface to the tilde expander. */ tilde_initialize (); - /* Initialize internal and environment variables. */ - initialize_shell_variables (shell_environment); + /* 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); +#else + initialize_shell_variables (shell_environment, privileged_mode||running_setuid); +#endif /* Initialize filename hash tables. */ initialize_filename_hashing (); @@ -1335,6 +1176,9 @@ shell_initialize () /* Initialize input streams to null. */ initialize_bash_input (); + + /* Initialize the shell options. */ + initialize_shell_options (); } /* Function called by main () when it appears that the shell has already @@ -1360,12 +1204,10 @@ shell_reinitialize () 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; #if defined (HISTORY) -# if defined (BANG_HISTORY) - history_expansion = 0; -# endif - remember_on_history = 0; + bash_history_reinit (0); #endif /* HISTORY */ #if defined (RESTRICTED_SHELL) @@ -1378,383 +1220,58 @@ shell_reinitialize () /* Delete all variables and functions. They will be reinitialized when the environment is parsed. */ - delete_all_variables (shell_variables); delete_all_variables (shell_functions); +#if 0 /* Pretend the PATH variable has changed. */ - sv_path ("PATH"); -} - -static void -initialize_signals () -{ - initialize_terminating_signals (); - initialize_job_signals (); -#if defined (INITIALIZE_SIGLIST) - initialize_siglist (); -#endif -} - -void -reinitialize_signals () -{ - initialize_terminating_signals (); - initialize_job_signals (); -} - -/* A structure describing a signal that terminates the shell if not - caught. The orig_handler member is present so children can reset - these signals back to their original handlers. */ -struct termsig { - int signum; - SigHandler *orig_handler; -}; - -#define NULL_HANDLER (SigHandler *)SIG_DFL - -/* The list of signals that would terminate the shell if not caught. - We catch them, but just so that we can write the history file, - and so forth. */ -static struct termsig terminating_signals[] = { -#ifdef SIGHUP - SIGHUP, NULL_HANDLER, -#endif - -#ifdef SIGINT - SIGINT, NULL_HANDLER, -#endif - -#ifdef SIGILL - SIGILL, NULL_HANDLER, -#endif - -#ifdef SIGTRAP - SIGTRAP, NULL_HANDLER, -#endif - -#ifdef SIGIOT - SIGIOT, NULL_HANDLER, -#endif - -#ifdef SIGDANGER - SIGDANGER, NULL_HANDLER, -#endif - -#ifdef SIGEMT - SIGEMT, NULL_HANDLER, -#endif - -#ifdef SIGFPE - SIGFPE, NULL_HANDLER, -#endif - -#ifdef SIGBUS - SIGBUS, NULL_HANDLER, -#endif - -#ifdef SIGSEGV - SIGSEGV, NULL_HANDLER, -#endif - -#ifdef SIGSYS - SIGSYS, NULL_HANDLER, -#endif - -#ifdef SIGPIPE - SIGPIPE, NULL_HANDLER, -#endif - -#ifdef SIGALRM - SIGALRM, NULL_HANDLER, -#endif - -#ifdef SIGTERM - SIGTERM, NULL_HANDLER, -#endif - -#ifdef SIGXCPU - SIGXCPU, NULL_HANDLER, -#endif - -#ifdef SIGXFSZ - SIGXFSZ, NULL_HANDLER, -#endif - -#ifdef SIGVTALRM - SIGVTALRM, NULL_HANDLER, + flush_hashed_filenames (); #endif - -#ifdef SIGPROF - SIGPROF, NULL_HANDLER, -#endif - -#ifdef SIGLOST - SIGLOST, NULL_HANDLER, -#endif - -#ifdef SIGUSR1 - SIGUSR1, NULL_HANDLER, -#endif - -#ifdef SIGUSR2 - SIGUSR2, NULL_HANDLER, -#endif -}; - -#define TERMSIGS_LENGTH (sizeof (terminating_signals) / sizeof (struct termsig)) - -#define XSIG(x) (terminating_signals[x].signum) -#define XHANDLER(x) (terminating_signals[x].orig_handler) - -/* This function belongs here? */ -sighandler -termination_unwind_protect (sig) - int sig; -{ - if (sig == SIGINT && signal_is_trapped (SIGINT)) - run_interrupt_trap (); - -#if defined (HISTORY) - if (interactive_shell) - maybe_save_shell_history (); -#endif /* HISTORY */ - -#if defined (JOB_CONTROL) - if (interactive && sig == SIGHUP) - hangup_all_jobs (); - end_job_control (); -#endif /* JOB_CONTROL */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_exit_trap (); - set_signal_handler (sig, SIG_DFL); - kill (getpid (), sig); - -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ } -/* Initialize signals that will terminate the shell to do some - unwind protection. */ static void -initialize_terminating_signals () +show_shell_usage (fp) + FILE *fp; { - register int i; - - /* The following code is to avoid an expensive call to - set_signal_handler () for each terminating_signals. Fortunately, - this is possible in Posix. Unfortunately, we have to call signal () - on non-Posix systems for each signal in terminating_signals. */ -#if defined (_POSIX_VERSION) - struct sigaction act, oact; - - act.sa_handler = termination_unwind_protect; - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - sigemptyset (&oact.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - sigaddset (&act.sa_mask, XSIG (i)); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - sigaction (XSIG (i), &act, &oact); - terminating_signals[i].orig_handler = oact.sa_handler; - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && oact.sa_handler == SIG_IGN) - { - sigaction (XSIG (i), &oact, &act); - set_signal_ignored (XSIG (i)); - } - } - -#else /* !_POSIX_VERSION */ - - for (i = 0; i < TERMSIGS_LENGTH; i++) + int i; + char *set_opts, *s, *t; + + fprintf (fp, "GNU bash, version %s-(%s)\n", shell_version_string (), MACHTYPE); + fprintf (fp, "Usage:\t%s [GNU long option] [option] ...\n\t%s [GNU long option] [option] script-file ...\n", + shell_name, shell_name); + fputs ("GNU long options:\n", fp); + for (i = 0; long_args[i].name; i++) + fprintf (fp, "\t--%s\n", long_args[i].name); + + fputs ("Shell options:\n", fp); + fputs ("\t-irsD or -c command\t\t(invocation only)\n", fp); + + 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); + if (set_opts) { - terminating_signals[i].orig_handler = - set_signal_handler (XSIG (i), termination_unwind_protect); - /* Don't do anything with signals that are ignored at shell entry - if the shell is not interactive. */ - if (!interactive_shell && terminating_signals[i].orig_handler == SIG_IGN) - { - set_signal_handler (XSIG (i), SIG_IGN); - set_signal_ignored (XSIG (i)); - } + s = strchr (set_opts, '['); + if (s == 0) + s = set_opts; + while (*++s == '-') + ; + t = strchr (s, ']'); + if (t) + *t = '\0'; + fprintf (fp, "\t-%s or -o option\n", s); + free (set_opts); } -#endif /* !_POSIX_VERSION */ - -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) - /* All shells use the signal mask they inherit, and pass it along - to child processes. Children will never block SIGCHLD, though. */ - sigemptyset (&top_level_mask); - sigprocmask (SIG_BLOCK, (sigset_t *)NULL, &top_level_mask); - sigdelset (&top_level_mask, SIGCHLD); -#endif /* JOB_CONTROL || _POSIX_VERSION */ - - /* And, some signals that are specifically ignored by the shell. */ - set_signal_handler (SIGQUIT, SIG_IGN); - - if (interactive) - { - set_signal_handler (SIGINT, sigint_sighandler); - set_signal_handler (SIGTERM, SIG_IGN); - } -} - -void -reset_terminating_signals () -{ - register int i; - -#if defined (_POSIX_VERSION) - struct sigaction act; - - act.sa_flags = 0; - sigemptyset (&act.sa_mask); - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - /* Skip a signal if it's trapped or handled specially, because the - trap code will restore the correct value. */ - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - act.sa_handler = XHANDLER (i); - sigaction (XSIG (i), &act, (struct sigaction *) NULL); - } -#else - for (i = 0; i < TERMSIGS_LENGTH; i++) - { - if (signal_is_trapped (XSIG (i)) || signal_is_special (XSIG (i))) - continue; - - set_signal_handler (XSIG (i), XHANDLER (i)); - } -#endif + 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"); } -#undef XSIG -#undef XHANDLER - -/* What to do when we've been interrupted, and it is safe to handle it. */ -void -throw_to_top_level () -{ - int print_newline = 0; - - if (interrupt_state) - { - print_newline = 1; - interrupt_state--; - } - - if (interrupt_state) - return; - - last_command_exit_value |= 128; - - /* Run any traps set on SIGINT. */ - run_interrupt_trap (); - - /* Cleanup string parser environment. */ - while (parse_and_execute_level) - parse_and_execute_cleanup (); - -#if defined (JOB_CONTROL) - give_terminal_to (shell_pgrp); -#endif /* JOB_CONTROL */ -#if defined (JOB_CONTROL) || defined (_POSIX_VERSION) - sigprocmask (SIG_SETMASK, &top_level_mask, (sigset_t *)NULL); -#endif - - reset_parser (); - -#if defined (READLINE) - if (interactive) - bashline_reinitialize (); -#endif /* READLINE */ - -#if defined (PROCESS_SUBSTITUTION) - unlink_fifo_list (); -#endif /* PROCESS_SUBSTITUTION */ - - run_unwind_protects (); - loop_level = continuing = breaking = 0; - return_catch_flag = 0; - - if (interactive && print_newline) - { - fflush (stdout); - fprintf (stderr, "\n"); - fflush (stderr); - } - - /* An interrupted `wait' command in a script does not exit the script. */ - if (interactive || (interactive_shell && !shell_initialized) || - (print_newline && signal_is_trapped (SIGINT))) - longjmp (top_level, DISCARD); - else - longjmp (top_level, EXITPROG); -} - -/* When non-zero, we throw_to_top_level (). */ -int interrupt_immediately = 0; - -/* What we really do when SIGINT occurs. */ -sighandler -sigint_sighandler (sig) - int sig; -{ -#if defined (USG) && !defined (_POSIX_VERSION) - set_signal_handler (sig, sigint_sighandler); -#endif - - /* interrupt_state needs to be set for the stack of interrupts to work - right. Should it be set unconditionally? */ - if (!interrupt_state) - interrupt_state++; - - if (interrupt_immediately) - { - interrupt_immediately = 0; - throw_to_top_level (); - } -#if !defined (VOID_SIGHANDLER) - return (0); -#endif /* VOID_SIGHANDLER */ -} - -/* Give version information about this shell. */ -char * -shell_version_string () -{ - static char tt[16] = { '\0' }; - - if (!tt[0]) - sprintf (tt, "%s.%d(%d)", dist_version, patch_level, build_version); - return tt; -} - -void -show_shell_version () -{ - printf ("GNU %s, version %s\n", base_pathname (shell_name), - shell_version_string ()); -} - -#if !defined (USG) && defined (ENOTSOCK) -# if !defined (HAVE_SOCKETS) -# define HAVE_SOCKETS -# endif -#endif - -#if defined (HAVE_SOCKETS) -#include <sys/socket.h> +/* The second and subsequent conditions must match those used to decide + whether or not to call getpeername() in isnetconn(). */ +#if defined (HAVE_SYS_SOCKET_H) && defined (HAVE_GETPEERNAME) && !defined (SVR4_2) +# include <sys/socket.h> #endif /* Is FD a socket or network connection? */ @@ -1762,22 +1279,29 @@ static int isnetconn (fd) int fd; { -#if defined (USGr4) || defined (USGr4_2) +#if defined (HAVE_GETPEERNAME) && !defined (SVR4_2) + int rv, l; + struct sockaddr sa; + + l = sizeof(sa); + rv = getpeername(0, &sa, &l); + /* Solaris 2.5 getpeername() returns EINVAL if the fd is not a socket. */ + return ((rv < 0 && (errno == ENOTSOCK || errno == EINVAL)) ? 0 : 1); +#else /* !HAVE_GETPEERNAME || SVR4_2 */ +# if defined (SVR4) || defined (SVR4_2) /* Sockets on SVR4 and SVR4.2 are character special (streams) devices. */ struct stat sb; + if (isatty (fd)) + return (0); if (fstat (fd, &sb) < 0) return (0); +# if defined (S_ISFIFO) + if (S_ISFIFO (sb.st_mode)) + return (0); +# endif /* S_ISFIFO */ return (S_ISCHR (sb.st_mode)); -#else /* !USGr4 && !USGr4_2 */ -# if defined (HAVE_SOCKETS) - int rv, l; - struct sockaddr sa; - - l = sizeof(sa); - rv = getpeername(0, &sa, &l); - return ((rv < 0 && errno == ENOTSOCK) ? 0 : 1); -# else /* !HAVE_SOCKETS */ +# else /* !SVR4 && !SVR4_2 */ # if defined (S_ISSOCK) struct stat sb; @@ -1787,6 +1311,6 @@ isnetconn (fd) # else /* !S_ISSOCK */ return (0); # endif /* !S_ISSOCK */ -# endif /* !HAVE_SOCKETS */ -#endif /* !USGr4 && !USGr4_2 */ +# endif /* !SVR4 && !SVR4_2 */ +#endif /* !HAVE_GETPEERNAME || SVR4_2 */ } |
