hush: make job control and interactiveness configurable, part 1

This commit is contained in:
Denis Vlasenko 2007-04-28 16:48:04 +00:00
parent 0937be5fa6
commit b81b3df1fa
2 changed files with 111 additions and 14 deletions

View File

@ -176,6 +176,15 @@ config HUSH
word ), arithmetic expansion, aliases, brace expansion, tilde word ), arithmetic expansion, aliases, brace expansion, tilde
expansion, &> and >& redirection of stdout+stderr, etc. expansion, &> and >& redirection of stdout+stderr, etc.
config HUSH_INTERACTIVE
bool "Interactive mode"
default y
depends on HUSH
help
Enable interactive mode (Ctrl-Z, Ctrl-C, command editing)
in the hush shell. Without this, hush reads and executes
stdin just like a shell script from the file.
config LASH config LASH
bool "lash" bool "lash"

View File

@ -51,7 +51,7 @@
* Here Documents ( << word ) * Here Documents ( << word )
* Functions * Functions
* Major bugs: * Major bugs:
* job handling woefully incomplete and buggy * job handling woefully incomplete and buggy (improved --vda)
* reserved word execution woefully incomplete and buggy * reserved word execution woefully incomplete and buggy
* to-do: * to-do:
* port selected bugfixes from post-0.49 busybox lash - done? * port selected bugfixes from post-0.49 busybox lash - done?
@ -86,6 +86,16 @@
/* Finer-grained debug switch */ /* Finer-grained debug switch */
//#define DEBUG_SHELL_JOBS //#define DEBUG_SHELL_JOBS
//TODO: rename HUSH_INTERACTIVE -> HUSH_JOB,
//create HUSH_INTERACTIVE which controls only prompt + line editing,
//make HUSH_JOB dependent on it
#if !ENABLE_HUSH_INTERACTIVE
#undef ENABLE_FEATURE_EDITING
#define ENABLE_FEATURE_EDITING 0
#undef ENABLE_FEATURE_EDITING_FANCY_PROMPT
#define ENABLE_FEATURE_EDITING_FANCY_PROMPT 0
#endif
#define SPECIAL_VAR_SYMBOL 03 #define SPECIAL_VAR_SYMBOL 03
#define FLAG_EXIT_FROM_LOOP 1 #define FLAG_EXIT_FROM_LOOP 1
@ -169,10 +179,10 @@ struct p_context {
}; };
struct redir_struct { struct redir_struct {
struct redir_struct *next; /* pointer to the next redirect in the list */
redir_type type; /* type of redirection */ redir_type type; /* type of redirection */
int fd; /* file descriptor being redirected */ int fd; /* file descriptor being redirected */
int dup; /* -1, or file descriptor being duplicated */ int dup; /* -1, or file descriptor being duplicated */
struct redir_struct *next; /* pointer to the next redirect in the list */
glob_t word; /* *word.gl_pathv is the filename */ glob_t word; /* *word.gl_pathv is the filename */
}; };
@ -190,14 +200,16 @@ struct child_prog {
}; };
struct pipe { struct pipe {
int jobid; /* job number */ struct pipe *next;
int num_progs; /* total number of programs in job */ int num_progs; /* total number of programs in job */
int running_progs; /* number of programs running (not exited) */ int running_progs; /* number of programs running (not exited) */
char *cmdtext; /* name of job */
char *cmdbuf; /* buffer various argv's point into */ char *cmdbuf; /* buffer various argv's point into */
#if ENABLE_HUSH_INTERACTIVE
int jobid; /* job number */
char *cmdtext; /* name of job */
pid_t pgrp; /* process group ID for the job */ pid_t pgrp; /* process group ID for the job */
#endif
struct child_prog *progs; /* array of commands in pipe */ struct child_prog *progs; /* array of commands in pipe */
struct pipe *next; /* to track background commands */
int stopped_progs; /* number of programs alive, but stopped */ int stopped_progs; /* number of programs alive, but stopped */
int job_context; /* bitmask defining current context */ int job_context; /* bitmask defining current context */
pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */ pipe_style followup; /* PIPE_BG, PIPE_SEQ, PIPE_OR, PIPE_AND */
@ -205,16 +217,16 @@ struct pipe {
}; };
struct close_me { struct close_me {
int fd;
struct close_me *next; struct close_me *next;
int fd;
}; };
struct variables { struct variables {
struct variables *next;
const char *name; const char *name;
const char *value; const char *value;
int flg_export; int flg_export;
int flg_read_only; int flg_read_only;
struct variables *next;
}; };
/* globals, connect us to the outside world /* globals, connect us to the outside world
@ -230,18 +242,22 @@ static unsigned char map[256];
static int fake_mode; static int fake_mode;
static struct close_me *close_me_head; static struct close_me *close_me_head;
static const char *cwd; static const char *cwd;
static struct pipe *job_list;
static unsigned last_bg_pid; static unsigned last_bg_pid;
#if ENABLE_HUSH_INTERACTIVE
static int last_jobid; static int last_jobid;
static struct pipe *job_list;
/* 'interactive_fd' is a fd# open to ctty, if we have one /* 'interactive_fd' is a fd# open to ctty, if we have one
* _AND_ if we decided to mess with job control */ * _AND_ if we decided to mess with job control */
static int interactive_fd; static int interactive_fd;
static pid_t saved_task_pgrp; static pid_t saved_task_pgrp;
static pid_t saved_tty_pgrp; static pid_t saved_tty_pgrp;
#else
enum { interactive_fd = 0 };
#endif
static const char *PS1; static const char *PS1;
static const char *PS2; static const char *PS2;
static struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; static struct variables shell_ver = { NULL, "HUSH_VERSION", "0.01", 1, 1 };
static struct variables *top_vars = &shell_ver; static struct variables *top_vars = &shell_ver;
@ -322,9 +338,11 @@ static int builtin_eval(char **argv);
static int builtin_exec(char **argv); static int builtin_exec(char **argv);
static int builtin_exit(char **argv); static int builtin_exit(char **argv);
static int builtin_export(char **argv); static int builtin_export(char **argv);
#if ENABLE_HUSH_INTERACTIVE
static int builtin_fg_bg(char **argv); static int builtin_fg_bg(char **argv);
static int builtin_help(char **argv);
static int builtin_jobs(char **argv); static int builtin_jobs(char **argv);
#endif
static int builtin_help(char **argv);
static int builtin_pwd(char **argv); static int builtin_pwd(char **argv);
static int builtin_read(char **argv); static int builtin_read(char **argv);
static int builtin_set(char **argv); static int builtin_set(char **argv);
@ -387,10 +405,14 @@ static int parse_string_outer(const char *s, int flag);
static int parse_file_outer(FILE *f); static int parse_file_outer(FILE *f);
/* job management: */ /* job management: */
static int checkjobs(struct pipe* fg_pipe); static int checkjobs(struct pipe* fg_pipe);
#if ENABLE_HUSH_INTERACTIVE
static int checkjobs_and_fg_shell(struct pipe* fg_pipe); static int checkjobs_and_fg_shell(struct pipe* fg_pipe);
static void insert_bg_job(struct pipe *pi); static void insert_bg_job(struct pipe *pi);
static void remove_bg_job(struct pipe *pi); static void remove_bg_job(struct pipe *pi);
static void delete_finished_bg_job(struct pipe *pi); static void delete_finished_bg_job(struct pipe *pi);
#else
int checkjobs_and_fg_shell(struct pipe* fg_pipe); /* never called */
#endif
/* local variable support */ /* local variable support */
static char **make_list_in(char **inp, char *name); static char **make_list_in(char **inp, char *name);
static char *insert_var_value(char *inp); static char *insert_var_value(char *inp);
@ -405,7 +427,9 @@ static void unset_local_var(const char *name);
* For example, 'unset foo | whatever' will parse and run, but foo will * For example, 'unset foo | whatever' will parse and run, but foo will
* still be set at the end. */ * still be set at the end. */
static const struct built_in_command bltins[] = { static const struct built_in_command bltins[] = {
#if ENABLE_HUSH_INTERACTIVE
{ "bg", "Resume a job in the background", builtin_fg_bg }, { "bg", "Resume a job in the background", builtin_fg_bg },
#endif
{ "break", "Exit for, while or until loop", builtin_not_written }, { "break", "Exit for, while or until loop", builtin_not_written },
{ "cd", "Change working directory", builtin_cd }, { "cd", "Change working directory", builtin_cd },
{ "continue", "Continue for, while or until loop", builtin_not_written }, { "continue", "Continue for, while or until loop", builtin_not_written },
@ -415,8 +439,10 @@ static const struct built_in_command bltins[] = {
builtin_exec }, builtin_exec },
{ "exit", "Exit from shell()", builtin_exit }, { "exit", "Exit from shell()", builtin_exit },
{ "export", "Set environment variable", builtin_export }, { "export", "Set environment variable", builtin_export },
#if ENABLE_HUSH_INTERACTIVE
{ "fg", "Bring job into the foreground", builtin_fg_bg }, { "fg", "Bring job into the foreground", builtin_fg_bg },
{ "jobs", "Lists the active jobs", builtin_jobs }, { "jobs", "Lists the active jobs", builtin_jobs },
#endif
{ "pwd", "Print current directory", builtin_pwd }, { "pwd", "Print current directory", builtin_pwd },
{ "read", "Input environment variable", builtin_read }, { "read", "Input environment variable", builtin_read },
{ "return", "Return from a function", builtin_not_written }, { "return", "Return from a function", builtin_not_written },
@ -431,6 +457,9 @@ static const struct built_in_command bltins[] = {
{ NULL, NULL, NULL } { NULL, NULL, NULL }
}; };
#if ENABLE_HUSH_INTERACTIVE
#if ENABLE_FEATURE_SH_STANDALONE
/* move to libbb? */ /* move to libbb? */
static void signal_SA_RESTART(int sig, void (*handler)(int)) static void signal_SA_RESTART(int sig, void (*handler)(int))
{ {
@ -440,6 +469,7 @@ static void signal_SA_RESTART(int sig, void (*handler)(int))
sigemptyset(&sa.sa_mask); sigemptyset(&sa.sa_mask);
sigaction(sig, &sa, NULL); sigaction(sig, &sa, NULL);
} }
#endif
/* Signals are grouped, we handle them in batches */ /* Signals are grouped, we handle them in batches */
static void set_fatal_sighandler(void (*handler)(int)) static void set_fatal_sighandler(void (*handler)(int))
@ -469,6 +499,7 @@ static void set_misc_sighandler(void (*handler)(int))
} }
/* SIGCHLD is special and handled separately */ /* SIGCHLD is special and handled separately */
#if ENABLE_FEATURE_SH_STANDALONE
static void set_every_sighandler(void (*handler)(int)) static void set_every_sighandler(void (*handler)(int))
{ {
set_fatal_sighandler(handler); set_fatal_sighandler(handler);
@ -477,9 +508,9 @@ static void set_every_sighandler(void (*handler)(int))
signal(SIGCHLD, handler); signal(SIGCHLD, handler);
} }
static struct pipe *nofork_pipe;
struct nofork_save_area nofork_save; struct nofork_save_area nofork_save;
static sigjmp_buf nofork_jb; static sigjmp_buf nofork_jb;
static struct pipe *nofork_pipe;
static void handler_ctrl_c(int sig) static void handler_ctrl_c(int sig)
{ {
@ -522,6 +553,8 @@ static void handler_ctrl_z(int sig)
siglongjmp(nofork_jb, 1); siglongjmp(nofork_jb, 1);
} }
#endif
/* Restores tty foreground process group, and exits. /* Restores tty foreground process group, and exits.
* May be called as signal handler for fatal signal * May be called as signal handler for fatal signal
* (will faithfully resend signal to itself, producing correct exit state) * (will faithfully resend signal to itself, producing correct exit state)
@ -559,6 +592,16 @@ static void hush_exit(int exitcode)
sigexit(- (exitcode & 0xff)); sigexit(- (exitcode & 0xff));
} }
#else /* !INTERACTIVE */
#define set_fatal_sighandler(handler) ((void)0)
#define set_jobctrl_sighandler(handler) ((void)0)
#define set_misc_sighandler(handler) ((void)0)
#define hush_exit(e) exit(-(e))
#endif /* INTERACTIVE */
static const char *set_cwd(void) static const char *set_cwd(void)
{ {
if (cwd == bb_msg_unknown) if (cwd == bb_msg_unknown)
@ -684,6 +727,7 @@ static int builtin_export(char **argv)
return res; return res;
} }
#if ENABLE_HUSH_INTERACTIVE
/* built-in 'fg' and 'bg' handler */ /* built-in 'fg' and 'bg' handler */
static int builtin_fg_bg(char **argv) static int builtin_fg_bg(char **argv)
{ {
@ -745,6 +789,7 @@ static int builtin_fg_bg(char **argv)
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#endif
/* built-in 'help' handler */ /* built-in 'help' handler */
static int builtin_help(char **argv ATTRIBUTE_UNUSED) static int builtin_help(char **argv ATTRIBUTE_UNUSED)
@ -762,6 +807,7 @@ static int builtin_help(char **argv ATTRIBUTE_UNUSED)
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#if ENABLE_HUSH_INTERACTIVE
/* built-in 'jobs' handler */ /* built-in 'jobs' handler */
static int builtin_jobs(char **argv ATTRIBUTE_UNUSED) static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
{ {
@ -778,6 +824,7 @@ static int builtin_jobs(char **argv ATTRIBUTE_UNUSED)
} }
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
#endif
/* built-in 'pwd' handler */ /* built-in 'pwd' handler */
static int builtin_pwd(char **argv ATTRIBUTE_UNUSED) static int builtin_pwd(char **argv ATTRIBUTE_UNUSED)
@ -1272,7 +1319,9 @@ static void pseudo_exec(struct child_prog *child)
if (child->group) { if (child->group) {
debug_printf("runtime nesting to group\n"); debug_printf("runtime nesting to group\n");
// FIXME: do not modify globals! Think vfork! // FIXME: do not modify globals! Think vfork!
#if ENABLE_HUSH_INTERACTIVE
interactive_fd = 0; /* crucial!!!! */ interactive_fd = 0; /* crucial!!!! */
#endif
rcode = run_list_real(child->group); rcode = run_list_real(child->group);
/* OK to leak memory by not calling free_pipe_list, /* OK to leak memory by not calling free_pipe_list,
* since this process is about to exit */ * since this process is about to exit */
@ -1284,6 +1333,7 @@ static void pseudo_exec(struct child_prog *child)
_exit(EXIT_SUCCESS); _exit(EXIT_SUCCESS);
} }
#if ENABLE_HUSH_INTERACTIVE
static const char *get_cmdtext(struct pipe *pi) static const char *get_cmdtext(struct pipe *pi)
{ {
char **argv; char **argv;
@ -1312,7 +1362,9 @@ static const char *get_cmdtext(struct pipe *pi)
p[-1] = '\0'; p[-1] = '\0';
return pi->cmdtext; return pi->cmdtext;
} }
#endif
#if ENABLE_HUSH_INTERACTIVE
static void insert_bg_job(struct pipe *pi) static void insert_bg_job(struct pipe *pi)
{ {
struct pipe *thejob; struct pipe *thejob;
@ -1376,6 +1428,7 @@ static void delete_finished_bg_job(struct pipe *pi)
free_pipe(pi, 0); free_pipe(pi, 0);
free(pi); free(pi);
} }
#endif
/* Checks to see if any processes have exited -- if they /* Checks to see if any processes have exited -- if they
have, figure out why and see if a job has completed */ have, figure out why and see if a job has completed */
@ -1383,8 +1436,10 @@ static int checkjobs(struct pipe* fg_pipe)
{ {
int attributes; int attributes;
int status; int status;
#if ENABLE_HUSH_INTERACTIVE
int prognum = 0; int prognum = 0;
struct pipe *pi; struct pipe *pi;
#endif
pid_t childpid; pid_t childpid;
int rcode = 0; int rcode = 0;
@ -1401,6 +1456,10 @@ static int checkjobs(struct pipe* fg_pipe)
* 1 <========== bg pipe is not fully done, but exitcode is already known! * 1 <========== bg pipe is not fully done, but exitcode is already known!
*/ */
//FIXME: non-interactive bash does not continue even if all processes in fg pipe
//are stopped. Testcase: "cat | cat" in a script (not on command line)
// + killall -STOP cat
wait_more: wait_more:
while ((childpid = waitpid(-1, &status, attributes)) > 0) { while ((childpid = waitpid(-1, &status, attributes)) > 0) {
const int dead = WIFEXITED(status) || WIFSIGNALED(status); const int dead = WIFEXITED(status) || WIFSIGNALED(status);
@ -1437,8 +1496,10 @@ static int checkjobs(struct pipe* fg_pipe)
fg_pipe->running_progs, fg_pipe->stopped_progs); fg_pipe->running_progs, fg_pipe->stopped_progs);
if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) { if (fg_pipe->running_progs - fg_pipe->stopped_progs <= 0) {
/* All processes in fg pipe have exited/stopped */ /* All processes in fg pipe have exited/stopped */
#if ENABLE_HUSH_INTERACTIVE
if (fg_pipe->running_progs) if (fg_pipe->running_progs)
insert_bg_job(fg_pipe); insert_bg_job(fg_pipe);
#endif
return rcode; return rcode;
} }
/* There are still running processes in the fg pipe */ /* There are still running processes in the fg pipe */
@ -1448,6 +1509,7 @@ static int checkjobs(struct pipe* fg_pipe)
/* fall through to searching process in bg pipes */ /* fall through to searching process in bg pipes */
} }
#if ENABLE_HUSH_INTERACTIVE
/* We asked to wait for bg or orphaned children */ /* We asked to wait for bg or orphaned children */
/* No need to remember exitcode in this case */ /* No need to remember exitcode in this case */
for (pi = job_list; pi; pi = pi->next) { for (pi = job_list; pi; pi = pi->next) {
@ -1458,11 +1520,13 @@ static int checkjobs(struct pipe* fg_pipe)
prognum++; prognum++;
} }
} }
#endif
/* Happens when shell is used as init process (init=/bin/sh) */ /* Happens when shell is used as init process (init=/bin/sh) */
debug_printf("checkjobs: pid %d was not in our list!\n", childpid); debug_printf("checkjobs: pid %d was not in our list!\n", childpid);
goto wait_more; goto wait_more;
#if ENABLE_HUSH_INTERACTIVE
found_pi_and_prognum: found_pi_and_prognum:
if (dead) { if (dead) {
/* child exited */ /* child exited */
@ -1478,6 +1542,7 @@ static int checkjobs(struct pipe* fg_pipe)
pi->stopped_progs++; pi->stopped_progs++;
pi->progs[prognum].is_stopped = 1; pi->progs[prognum].is_stopped = 1;
} }
#endif
} }
/* wait found no children or failed */ /* wait found no children or failed */
@ -1491,6 +1556,7 @@ static int checkjobs(struct pipe* fg_pipe)
return rcode; return rcode;
} }
#if ENABLE_HUSH_INTERACTIVE
static int checkjobs_and_fg_shell(struct pipe* fg_pipe) static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
{ {
pid_t p; pid_t p;
@ -1502,11 +1568,14 @@ static int checkjobs_and_fg_shell(struct pipe* fg_pipe)
bb_perror_msg("tcsetpgrp-4a"); bb_perror_msg("tcsetpgrp-4a");
return rcode; return rcode;
} }
#endif
#if ENABLE_FEATURE_SH_STANDALONE
/* run_pipe_real's helper */ /* run_pipe_real's helper */
static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a, static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a,
char **argv) char **argv)
{ {
#if ENABLE_HUSH_INTERACTIVE
int rcode; int rcode;
/* TSTP handler will store pid etc in pi */ /* TSTP handler will store pid etc in pi */
nofork_pipe = pi; nofork_pipe = pi;
@ -1532,7 +1601,11 @@ static int run_single_fg_nofork(struct pipe *pi, const struct bb_applet *a,
else else
putchar('\n'); /* bash does this on Ctrl-C */ putchar('\n'); /* bash does this on Ctrl-C */
return 0; return 0;
#else
return run_nofork_applet(a, argv);
#endif
} }
#endif
/* run_pipe_real() starts all the jobs, but doesn't wait for anything /* run_pipe_real() starts all the jobs, but doesn't wait for anything
* to finish. See checkjobs(). * to finish. See checkjobs().
@ -1564,7 +1637,9 @@ static int run_pipe_real(struct pipe *pi)
const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG);
nextin = 0; nextin = 0;
#if ENABLE_HUSH_INTERACTIVE
pi->pgrp = -1; pi->pgrp = -1;
#endif
pi->running_progs = 0; pi->running_progs = 0;
pi->stopped_progs = 0; pi->stopped_progs = 0;
@ -1691,6 +1766,7 @@ static int run_pipe_real(struct pipe *pi)
if (!child->pid) { /* child */ if (!child->pid) { /* child */
/* Every child adds itself to new process group /* Every child adds itself to new process group
* with pgid == pid of first child in pipe */ * with pgid == pid of first child in pipe */
#if ENABLE_HUSH_INTERACTIVE
if (interactive_fd) { if (interactive_fd) {
/* Don't do pgrp restore anymore on fatal signals */ /* Don't do pgrp restore anymore on fatal signals */
set_fatal_sighandler(SIG_DFL); set_fatal_sighandler(SIG_DFL);
@ -1702,6 +1778,7 @@ static int run_pipe_real(struct pipe *pi)
tcsetpgrp(interactive_fd, pi->pgrp); tcsetpgrp(interactive_fd, pi->pgrp);
} }
} }
#endif
// in non-interactive case fatal sigs are already SIG_DFL // in non-interactive case fatal sigs are already SIG_DFL
close_all(); close_all();
if (nextin != 0) { if (nextin != 0) {
@ -1728,9 +1805,11 @@ static int run_pipe_real(struct pipe *pi)
pi->running_progs++; pi->running_progs++;
#if ENABLE_HUSH_INTERACTIVE
/* Second and next children need to know pid of first one */ /* Second and next children need to know pid of first one */
if (pi->pgrp < 0) if (pi->pgrp < 0)
pi->pgrp = child->pid; pi->pgrp = child->pid;
#endif
/* Don't check for errors. The child may be dead already, /* Don't check for errors. The child may be dead already,
* in which case setpgid returns error code EACCES. */ * in which case setpgid returns error code EACCES. */
@ -1858,7 +1937,9 @@ static int run_list_real(struct pipe *pi)
/* XXX check bash's behavior with nontrivial pipes */ /* XXX check bash's behavior with nontrivial pipes */
/* XXX compute jobid */ /* XXX compute jobid */
/* XXX what does bash do with attempts to background builtins? */ /* XXX what does bash do with attempts to background builtins? */
#if ENABLE_HUSH_INTERACTIVE
insert_bg_job(pi); insert_bg_job(pi);
#endif
rcode = EXIT_SUCCESS; rcode = EXIT_SUCCESS;
} else { } else {
if (interactive_fd) { if (interactive_fd) {
@ -1931,8 +2012,10 @@ static int free_pipe(struct pipe *pi, int indent)
} }
free(pi->progs); /* children are an array, they get freed all at once */ free(pi->progs); /* children are an array, they get freed all at once */
pi->progs = NULL; pi->progs = NULL;
#if ENABLE_HUSH_INTERACTIVE
free(pi->cmdtext); free(pi->cmdtext);
pi->cmdtext = NULL; pi->cmdtext = NULL;
#endif
return ret_code; return ret_code;
} }
@ -3041,6 +3124,7 @@ static int parse_file_outer(FILE *f)
return rcode; return rcode;
} }
#if ENABLE_HUSH_INTERACTIVE
/* Make sure we have a controlling tty. If we get started under a job /* Make sure we have a controlling tty. If we get started under a job
* aware app (like bash for example), make sure we are now in charge so * aware app (like bash for example), make sure we are now in charge so
* we don't fight over who gets the foreground */ * we don't fight over who gets the foreground */
@ -3055,7 +3139,7 @@ static void setup_job_control(void)
/* If we were ran as 'hush &', /* If we were ran as 'hush &',
* sleep until we are in the foreground. */ * sleep until we are in the foreground. */
while (tcgetpgrp(interactive_fd) != shell_pgrp) { while (tcgetpgrp(interactive_fd) != shell_pgrp) {
/* Send TTIN to ourself (will stop us) */ /* Send TTIN to ourself (should stop us) */
kill(- shell_pgrp, SIGTTIN); kill(- shell_pgrp, SIGTTIN);
shell_pgrp = getpgrp(); shell_pgrp = getpgrp();
} }
@ -3073,6 +3157,7 @@ static void setup_job_control(void)
/* Grab control of the terminal. */ /* Grab control of the terminal. */
tcsetpgrp(interactive_fd, getpid()); tcsetpgrp(interactive_fd, getpid());
} }
#endif
int hush_main(int argc, char **argv); int hush_main(int argc, char **argv);
int hush_main(int argc, char **argv) int hush_main(int argc, char **argv)
@ -3095,11 +3180,13 @@ int hush_main(int argc, char **argv)
ifs = NULL; ifs = NULL;
/* map[] is taken care of with call to update_ifs_map() */ /* map[] is taken care of with call to update_ifs_map() */
fake_mode = 0; fake_mode = 0;
interactive_fd = 0;
close_me_head = NULL; close_me_head = NULL;
#if ENABLE_HUSH_INTERACTIVE
interactive_fd = 0;
last_bg_pid = 0; last_bg_pid = 0;
job_list = NULL; job_list = NULL;
last_jobid = 0; last_jobid = 0;
#endif
/* Initialize some more globals to non-zero values */ /* Initialize some more globals to non-zero values */
set_cwd(); set_cwd();
@ -3154,6 +3241,7 @@ int hush_main(int argc, char **argv)
#endif #endif
} }
} }
#if ENABLE_HUSH_INTERACTIVE
/* A shell is interactive if the '-i' flag was given, or if all of /* A shell is interactive if the '-i' flag was given, or if all of
* the following conditions are met: * the following conditions are met:
* no -c command * no -c command
@ -3180,7 +3268,6 @@ int hush_main(int argc, char **argv)
// to (inadvertently) close/redirect it // to (inadvertently) close/redirect it
} }
} }
debug_printf("\ninteractive_fd=%d\n", interactive_fd); debug_printf("\ninteractive_fd=%d\n", interactive_fd);
if (interactive_fd) { if (interactive_fd) {
/* Looks like they want an interactive shell */ /* Looks like they want an interactive shell */
@ -3196,6 +3283,7 @@ int hush_main(int argc, char **argv)
printf("Enter 'help' for a list of built-in commands.\n\n"); printf("Enter 'help' for a list of built-in commands.\n\n");
#endif #endif
} }
#endif
if (argv[optind] == NULL) { if (argv[optind] == NULL) {
opt = parse_file_outer(stdin); opt = parse_file_outer(stdin);