Imported from ../bash-2.02.tar.gz.

This commit is contained in:
Jari Aalto 1998-04-17 19:52:44 +00:00
commit cce855bc5b
323 changed files with 33916 additions and 12321 deletions

266
shell.c
View file

@ -35,7 +35,9 @@
#include "config.h"
#include "bashtypes.h"
#include <sys/file.h>
#ifndef _MINIX
# include <sys/file.h>
#endif
#include "posixstat.h"
#include "bashansi.h"
#include <stdio.h>
@ -61,6 +63,7 @@
#include "input.h"
#include "execute_cmd.h"
#include "findcmd.h"
#if defined (HISTORY)
# include "bashhist.h"
@ -86,6 +89,7 @@ extern int line_number;
extern char *primary_prompt, *secondary_prompt;
extern int expand_aliases;
extern char *this_command_name;
extern int array_needs_making;
/* Non-zero means that this shell has already been run; i.e. you should
call shell_reinitialize () if you need to start afresh. */
@ -119,6 +123,10 @@ int interactive = 0;
/* Non-zero means that the shell was started as an interactive shell. */
int interactive_shell = 0;
/* Non-zero means to send a SIGHUP to all jobs when an interactive login
shell exits. */
int hup_on_exit = 0;
/* Tells what state the shell was in when it started:
0 = non-interactive shell script
1 = interactive
@ -177,6 +185,8 @@ static int want_initial_help; /* --help option */
int no_line_editing = 0; /* Don't do fancy line editing. */
int posixly_correct = 0; /* Non-zero means posix.2 superset. */
int dump_translatable_strings; /* Dump strings in $"...", don't execute. */
int dump_po_strings; /* Dump strings in $"..." in po format */
int wordexp_only = 0; /* Do word expansion only */
/* Some long-winded argument names. These are obviously new. */
#define Int 1
@ -188,6 +198,7 @@ struct {
char **char_value;
} long_args[] = {
{ "debug", Int, &debugging, (char **)0x0 },
{ "dump-po-strings", Int, &dump_po_strings, (char **)0x0 },
{ "dump-strings", Int, &dump_translatable_strings, (char **)0x0 },
{ "help", Int, &want_initial_help, (char **)0x0 },
{ "login", Int, &make_login_shell, (char **)0x0 },
@ -201,6 +212,7 @@ struct {
#endif
{ "verbose", Int, &echo_input_at_read, (char **)0x0 },
{ "version", Int, &do_version, (char **)0x0 },
{ "wordexp", Int, &wordexp_only, (char **)0x0 },
{ (char *)0x0, Int, (int *)0x0, (char **)0x0 }
};
@ -231,6 +243,7 @@ static int bind_args ();
static int open_shell_script ();
static void set_bash_input ();
static int run_one_command ();
static int run_wordexp ();
static int uidget ();
static int isnetconn ();
@ -242,6 +255,22 @@ static void shell_reinitialize ();
static void show_shell_usage ();
#ifdef __CYGWIN32__
static void
_cygwin32_check_tmp ()
{
struct stat sb;
if (stat ("/tmp", &sb) < 0)
internal_warning ("could not find /tmp, please create!");
else
{
if (S_ISDIR (sb.st_mode) == 0)
internal_warning ("/tmp must be a valid directory name");
}
}
#endif /* __CYGWIN32__ */
int
main (argc, argv, env)
int argc;
@ -259,6 +288,10 @@ main (argc, argv, env)
check_dev_tty ();
#ifdef __CYGWIN32__
_cygwin32_check_tmp ();
#endif
/* Wait forever if we are debugging a login shell. */
while (debugging_login_shell);
@ -339,6 +372,9 @@ main (argc, argv, env)
this_command_name = shell_name; /* for error reporting */
arg_index = parse_shell_options (argv, arg_index, argc);
if (dump_po_strings)
dump_translatable_strings = 1;
if (dump_translatable_strings)
read_but_dont_execute = 1;
@ -371,6 +407,7 @@ main (argc, argv, env)
if (forced_interactive || /* -i flag */
(!local_pending_command && /* No -c command and ... */
wordexp_only == 0 && /* No --wordexp and ... */
((arg_index == argc) || /* no remaining args or... */
read_from_stdin) && /* -s flag with args, and */
isatty (fileno (stdin)) && /* Input is a terminal and */
@ -480,13 +517,20 @@ main (argc, argv, env)
}
#if defined (RESTRICTED_SHELL)
/* Turn on the restrictions after parsing the startup files. This
/* Turn on the restrictions after executing the startup files. This
means that `bash -r' or `set -r' invoked from a startup file will
turn on the restrictions after the startup files are executed. */
restricted = saverst || restricted;
maybe_make_restricted (shell_name);
#endif /* RESTRICTED_SHELL */
if (wordexp_only)
{
startup_state = 3;
last_command_exit_value = run_wordexp (argv[arg_index]);
exit_shell (last_command_exit_value);
}
if (local_pending_command)
{
arg_index = bind_args (argv, arg_index, argc, 0);
@ -650,7 +694,7 @@ parse_shell_options (argv, arg_start, arg_end)
o_option = argv[next_arg];
if (o_option == 0)
{
list_minus_o_opts (-1);
list_minus_o_opts (-1, (on_or_off == '-') ? 0 : 1);
break;
}
if (set_minus_o_option (on_or_off, o_option) != EXECUTION_SUCCESS)
@ -680,7 +724,7 @@ parse_shell_options (argv, arg_start, arg_end)
}
/* Exit the shell with status S. */
int
void
exit_shell (s)
int s;
{
@ -699,6 +743,11 @@ exit_shell (s)
#endif /* HISTORY */
#if defined (JOB_CONTROL)
/* If the user has run `shopt -s huponexit', hangup all jobs when we exit
an interactive login shell. ksh does this unconditionally. */
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. */
end_job_control ();
@ -763,18 +812,67 @@ run_startup_files ()
#if defined (JOB_CONTROL)
int old_job_control;
#endif
int sourced_login, run_by_ssh;
SHELL_VAR *sshvar;
/* get the rshd case out of the way first. */
/* get the rshd/sshd 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)))
act_like_sh == 0 && local_pending_command)
{
/* Find out if we were invoked by ssh. If so, set RUN_BY_SSH to 1. */
sshvar = find_variable ("SSH_CLIENT");
if (sshvar)
{
run_by_ssh = 1;
/* Now that we've tested the variable, we need to unexport it. */
sshvar->attributes &= ~att_exported;
array_needs_making = 1;
}
else
run_by_ssh = 0;
/* If we were run by sshd or we think we were run by rshd, execute
~/.bashrc. */
if (run_by_ssh || isnetconn (fileno (stdin)))
{
#ifdef SYS_BASHRC
maybe_execute_file (SYS_BASHRC, 1);
maybe_execute_file (SYS_BASHRC, 1);
#endif
maybe_execute_file (bashrc_file, 1);
return;
maybe_execute_file (bashrc_file, 1);
return;
}
}
#if defined (JOB_CONTROL)
/* Startup files should be run without job control enabled. */
old_job_control = interactive_shell ? set_job_control (0) : 0;
#endif
sourced_login = 0;
#if defined (NON_INTERACTIVE_LOGIN_SHELLS)
if (login_shell)
{
/* We don't execute .bashrc for login shells. */
no_rc++;
/* Execute /etc/profile and one of the personal login shell
initialization files. */
if (no_profile == 0)
{
maybe_execute_file (SYS_PROFILE, 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);
}
sourced_login = 1;
}
#endif /* NON_INTERACTIVE_LOGIN_SHELLS */
/* 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.
@ -787,30 +885,27 @@ run_startup_files ()
return;
}
#if defined (JOB_CONTROL)
/* Startup files should be run without job control enabled. */
old_job_control = set_job_control (0);
#endif
/* Interactive shell or `-su' shell. */
if (posixly_correct == 0) /* bash, sh */
{
/* We don't execute .bashrc for login shells. */
if (login_shell)
no_rc++;
if (login_shell && sourced_login++ == 0)
{
/* We don't execute .bashrc for login shells. */
no_rc++;
/* Execute /etc/profile and one of the personal login shell
initialization files. */
if (login_shell && no_profile == 0)
{
maybe_execute_file (SYS_PROFILE, 1);
/* Execute /etc/profile and one of the personal login shell
initialization files. */
if (no_profile == 0)
{
maybe_execute_file (SYS_PROFILE, 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 (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);
}
}
/* bash */
if (act_like_sh == 0 && no_rc == 0)
@ -894,6 +989,75 @@ disable_priv_mode ()
current_user.egid = current_user.gid;
}
static int
run_wordexp (words)
char *words;
{
int code, nw, nb;
WORD_DESC *w;
WORD_LIST *wl, *result;
code = setjmp (top_level);
if (code != NOT_JUMPED)
{
switch (code)
{
/* Some kind of throw to top_level has occured. */
case FORCE_EOF:
return last_command_exit_value = 127;
case EXITPROG:
return last_command_exit_value;
case DISCARD:
return last_command_exit_value = 1;
default:
programming_error ("run_wordexp: bad jump: code %d", code);
}
}
/* Run it through the parser to get a list of words and expand them */
if (words && *words)
{
with_input_from_string (words, "--wordexp");
if (parse_command () != 0)
return (126);
if (global_command == 0)
{
printf ("0\n0\n");
return (0);
}
if (global_command->type != cm_simple)
return (126);
wl = global_command->value.Simple->words;
result = wl ? expand_words_no_vars (wl) : (WORD_LIST *)0;
}
else
result = (WORD_LIST *)0;
last_command_exit_value = 0;
if (result == 0)
{
printf ("0\n0\n");
return (0);
}
/* Count up the number of words and bytes, and print them. Don't count
the trailing NUL byte. */
for (nw = nb = 0, wl = result; wl; wl = wl->next)
{
nw++;
nb += strlen (wl->word->word);
}
printf ("%u\n%u\n", nw, nb);
/* Print each word on a separate line. This will have to be changed when
the interface to glibc is completed. */
for (wl = result; wl; wl = wl->next)
printf ("%s\n", wl->word->word);
return (0);
}
#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. */
@ -1110,6 +1274,31 @@ set_bash_input ()
#endif /* !BUFFERED_INPUT */
}
/* Close the current shell script input source and forget about it. This is
extern so execute_cmd.c:initialize_subshell() can call it. If CHECK_ZERO
is non-zero, we close default_buffered_input even if it's the standard
input (fd 0). */
void
unset_bash_input (check_zero)
int check_zero;
{
#if defined (BUFFERED_INPUT)
if ((check_zero && default_buffered_input >= 0) ||
(check_zero == 0 && default_buffered_input > 0))
{
close_buffered_fd (default_buffered_input);
default_buffered_input = bash_input.location.buffered_fd = -1;
}
#else /* !BUFFERED_INPUT */
if (default_input)
{
fclose (default_input);
default_input = (FILE *)NULL;
}
#endif /* !BUFFERED_INPUT */
}
#if !defined (PROGRAM)
# define PROGRAM "bash"
#endif
@ -1201,8 +1390,13 @@ shell_initialize ()
char hostname[256];
/* Line buffer output for stderr and stdout. */
setlinebuf (stderr);
setlinebuf (stdout);
#if defined (SunOS5)
if (shell_initialized == 0)
#endif
{
setlinebuf (stderr);
setlinebuf (stdout);
}
/* Sort the array of shell builtins so that the binary search in
find_shell_builtin () works correctly. */
@ -1254,8 +1448,14 @@ shell_initialize ()
/* Initialize input streams to null. */
initialize_bash_input ();
/* Initialize the shell options. */
initialize_shell_options ();
/* Initialize the shell options. Don't import the shell options
from the environment variable $SHELLOPTS if we are 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);
#else
initialize_shell_options (privileged_mode||running_setuid);
#endif
}
/* Function called by main () when it appears that the shell has already
@ -1366,7 +1566,7 @@ isnetconn (fd)
struct sockaddr sa;
l = sizeof(sa);
rv = getpeername(0, &sa, &l);
rv = getpeername(fd, &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 */