Some more cleanups. Of special importance, never free a pipe
that still has running jobs. Instead, we ignore it and expect it to be cleaned by the background job stuff. -Erik
This commit is contained in:
parent
c798b07762
commit
52a97ca00c
79
hush.c
79
hush.c
@ -257,6 +257,7 @@ static char *PS2;
|
|||||||
struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
|
struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
|
||||||
struct variables *top_vars = &shell_ver;
|
struct variables *top_vars = &shell_ver;
|
||||||
|
|
||||||
|
|
||||||
#define B_CHUNK (100)
|
#define B_CHUNK (100)
|
||||||
#define B_NOSPAC 1
|
#define B_NOSPAC 1
|
||||||
|
|
||||||
@ -394,7 +395,7 @@ static void remove_bg_job(struct pipe *pi);
|
|||||||
static char *get_local_var(const char *var);
|
static char *get_local_var(const char *var);
|
||||||
static void unset_local_var(const char *name);
|
static void unset_local_var(const char *name);
|
||||||
static int set_local_var(const char *s, int flg_export);
|
static int set_local_var(const char *s, int flg_export);
|
||||||
|
static void sigchld_handler(int sig);
|
||||||
|
|
||||||
/* Table of built-in functions. They can be forked or not, depending on
|
/* Table of built-in functions. They can be forked or not, depending on
|
||||||
* context: within pipes, they fork. As simple commands, they do not.
|
* context: within pipes, they fork. As simple commands, they do not.
|
||||||
@ -556,7 +557,6 @@ static int builtin_fg_bg(struct child_prog *child)
|
|||||||
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pi = job_list; pi; pi = pi->next) {
|
for (pi = job_list; pi; pi = pi->next) {
|
||||||
if (pi->jobid == jobnum) {
|
if (pi->jobid == jobnum) {
|
||||||
break;
|
break;
|
||||||
@ -567,6 +567,7 @@ static int builtin_fg_bg(struct child_prog *child)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*child->argv[0] == 'f') {
|
if (*child->argv[0] == 'f') {
|
||||||
/* Make this job the foreground job */
|
/* Make this job the foreground job */
|
||||||
signal(SIGTTOU, SIG_IGN);
|
signal(SIGTTOU, SIG_IGN);
|
||||||
@ -613,6 +614,7 @@ static int builtin_jobs(struct child_prog *child)
|
|||||||
status_string = "Stopped";
|
status_string = "Stopped";
|
||||||
else
|
else
|
||||||
status_string = "Running";
|
status_string = "Running";
|
||||||
|
|
||||||
printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
|
printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
@ -1142,7 +1144,7 @@ static void insert_bg_job(struct pipe *pi)
|
|||||||
|
|
||||||
/* add thejob to the list of running jobs */
|
/* add thejob to the list of running jobs */
|
||||||
if (!job_list) {
|
if (!job_list) {
|
||||||
thejob = job_list= xmalloc(sizeof(*thejob));
|
thejob = job_list = xmalloc(sizeof(*thejob));
|
||||||
} else {
|
} else {
|
||||||
for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
|
for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
|
||||||
thejob->next = xmalloc(sizeof(*thejob));
|
thejob->next = xmalloc(sizeof(*thejob));
|
||||||
@ -1178,14 +1180,14 @@ static void remove_bg_job(struct pipe *pi)
|
|||||||
struct pipe *prev_pipe;
|
struct pipe *prev_pipe;
|
||||||
|
|
||||||
if (pi == job_list) {
|
if (pi == job_list) {
|
||||||
job_list= pi->next;
|
job_list = pi->next;
|
||||||
} else {
|
} else {
|
||||||
prev_pipe = job_list;
|
prev_pipe = job_list;
|
||||||
while (prev_pipe->next != pi)
|
while (prev_pipe->next != pi)
|
||||||
prev_pipe = prev_pipe->next;
|
prev_pipe = prev_pipe->next;
|
||||||
prev_pipe->next = pi->next;
|
prev_pipe->next = pi->next;
|
||||||
}
|
}
|
||||||
|
pi->stopped_progs = 0;
|
||||||
free_pipe(pi, 0);
|
free_pipe(pi, 0);
|
||||||
free(pi);
|
free(pi);
|
||||||
}
|
}
|
||||||
@ -1210,7 +1212,7 @@ static int checkjobs(struct pipe* fg_pipe)
|
|||||||
int i, rcode = 0;
|
int i, rcode = 0;
|
||||||
for (i=0; i < fg_pipe->num_progs; i++) {
|
for (i=0; i < fg_pipe->num_progs; i++) {
|
||||||
if (fg_pipe->progs[i].pid == childpid) {
|
if (fg_pipe->progs[i].pid == childpid) {
|
||||||
if (i==fg_pipe->num_progs-1)
|
if (i==fg_pipe->num_progs-1)
|
||||||
rcode=WEXITSTATUS(status);
|
rcode=WEXITSTATUS(status);
|
||||||
(fg_pipe->num_progs)--;
|
(fg_pipe->num_progs)--;
|
||||||
return(rcode);
|
return(rcode);
|
||||||
@ -1220,8 +1222,9 @@ static int checkjobs(struct pipe* fg_pipe)
|
|||||||
|
|
||||||
for (pi = job_list; pi; pi = pi->next) {
|
for (pi = job_list; pi; pi = pi->next) {
|
||||||
prognum = 0;
|
prognum = 0;
|
||||||
while (prognum < pi->num_progs &&
|
while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
|
||||||
pi->progs[prognum].pid != childpid) prognum++;
|
prognum++;
|
||||||
|
}
|
||||||
if (prognum < pi->num_progs)
|
if (prognum < pi->num_progs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1245,9 +1248,14 @@ 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;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Printing this stuff is a pain, since it tends to
|
||||||
|
* overwrite the prompt an inconveinient moments. So
|
||||||
|
* don't do that. */
|
||||||
if (pi->stopped_progs == pi->num_progs) {
|
if (pi->stopped_progs == pi->num_progs) {
|
||||||
printf(JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
|
printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,7 +1402,6 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
|
|
||||||
/* XXX test for failed fork()? */
|
/* XXX test for failed fork()? */
|
||||||
if (!(child->pid = fork())) {
|
if (!(child->pid = fork())) {
|
||||||
|
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
@ -1414,7 +1421,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
/* Like bash, explicit redirects override pipes,
|
/* Like bash, explicit redirects override pipes,
|
||||||
* and the pipe fd is available for dup'ing. */
|
* and the pipe fd is available for dup'ing. */
|
||||||
setup_redirects(child,NULL);
|
setup_redirects(child,NULL);
|
||||||
|
|
||||||
if (interactive && pi->followup!=PIPE_BG) {
|
if (interactive && pi->followup!=PIPE_BG) {
|
||||||
/* If we (the child) win the race, put ourselves in the process
|
/* If we (the child) win the race, put ourselves in the process
|
||||||
* group whose leader is the first process in this pipe. */
|
* group whose leader is the first process in this pipe. */
|
||||||
@ -1423,15 +1430,17 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
if (setpgid(0, pi->pgrp) == 0) {
|
if (setpgid(0, pi->pgrp) == 0) {
|
||||||
signal(SIGTTOU, SIG_IGN);
|
signal(SIGTTOU, SIG_IGN);
|
||||||
tcsetpgrp(ctty, pi->pgrp);
|
tcsetpgrp(2, pi->pgrp);
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo_exec(child);
|
pseudo_exec(child);
|
||||||
}
|
}
|
||||||
/* Put our child in the process group whose leader is the
|
|
||||||
* first process in this pipe. */
|
|
||||||
|
/* put our child in the process group whose leader is the
|
||||||
|
first process in this pipe */
|
||||||
if (pi->pgrp < 0) {
|
if (pi->pgrp < 0) {
|
||||||
pi->pgrp = child->pid;
|
pi->pgrp = child->pid;
|
||||||
}
|
}
|
||||||
@ -1478,18 +1487,18 @@ static int run_list_real(struct pipe *pi)
|
|||||||
insert_bg_job(pi);
|
insert_bg_job(pi);
|
||||||
rcode = EXIT_SUCCESS;
|
rcode = EXIT_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY)
|
if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp-3");
|
perror_msg("tcsetpgrp-3");
|
||||||
rcode = checkjobs(pi);
|
rcode = checkjobs(pi);
|
||||||
|
/* move the shell to the foreground */
|
||||||
if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY)
|
if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp-4");
|
perror_msg("tcsetpgrp-4");
|
||||||
} else {
|
} else {
|
||||||
rcode = checkjobs(pi);
|
rcode = checkjobs(pi);
|
||||||
}
|
}
|
||||||
debug_printf("pipe_wait returned %d\n",rcode);
|
debug_printf("checkjobs returned %d\n",rcode);
|
||||||
}
|
}
|
||||||
last_return_code=rcode;
|
last_return_code=rcode;
|
||||||
if ( rmode == RES_IF || rmode == RES_ELIF )
|
if ( rmode == RES_IF || rmode == RES_ELIF )
|
||||||
@ -1517,6 +1526,9 @@ static int free_pipe(struct pipe *pi, int indent)
|
|||||||
struct redir_struct *r, *rnext;
|
struct redir_struct *r, *rnext;
|
||||||
int a, i, ret_code=0;
|
int a, i, ret_code=0;
|
||||||
char *ind = indenter(indent);
|
char *ind = indenter(indent);
|
||||||
|
|
||||||
|
if (pi->stopped_progs > 0)
|
||||||
|
return ret_code;
|
||||||
final_printf("%s run pipe: (pid %d)\n",ind,getpid());
|
final_printf("%s run pipe: (pid %d)\n",ind,getpid());
|
||||||
for (i=0; i<pi->num_progs; i++) {
|
for (i=0; i<pi->num_progs; i++) {
|
||||||
child = &pi->progs[i];
|
child = &pi->progs[i];
|
||||||
@ -2516,6 +2528,27 @@ static int parse_file_outer(FILE *f)
|
|||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sigchld_handler(int sig)
|
||||||
|
{
|
||||||
|
checkjobs(NULL);
|
||||||
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_job_control()
|
||||||
|
{
|
||||||
|
/* If we get started under a job aware app (like bash
|
||||||
|
* for example), make sure we are now in charge so we
|
||||||
|
* don't fight over who gets the foreground */
|
||||||
|
/* don't pay any attention to this signal; it just confuses
|
||||||
|
things and isn't really meant for shells anyway */
|
||||||
|
setpgrp();
|
||||||
|
controlling_tty(0);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
setpgid(0, getpid());
|
||||||
|
tcsetpgrp(ctty, getpid());
|
||||||
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -2536,11 +2569,11 @@ int shell_main(int argc, char **argv)
|
|||||||
interactive = 0;
|
interactive = 0;
|
||||||
close_me_head = NULL;
|
close_me_head = NULL;
|
||||||
last_bg_pid = 0;
|
last_bg_pid = 0;
|
||||||
|
job_list = NULL;
|
||||||
last_jobid = 0;
|
last_jobid = 0;
|
||||||
|
|
||||||
/* Initialize some more globals to non-zero values */
|
/* Initialize some more globals to non-zero values */
|
||||||
set_cwd();
|
set_cwd();
|
||||||
job_list = NULL;
|
|
||||||
#ifdef BB_FEATURE_COMMAND_EDITING
|
#ifdef BB_FEATURE_COMMAND_EDITING
|
||||||
cmdedit_set_initial_prompt();
|
cmdedit_set_initial_prompt();
|
||||||
#else
|
#else
|
||||||
@ -2558,16 +2591,6 @@ int shell_main(int argc, char **argv)
|
|||||||
last_return_code=EXIT_SUCCESS;
|
last_return_code=EXIT_SUCCESS;
|
||||||
|
|
||||||
|
|
||||||
/* If we get started under a job aware app (like bash
|
|
||||||
* for example), make sure we are now in charge so we
|
|
||||||
* don't fight over who gets the foreground */
|
|
||||||
/* don't pay any attention to this signal; it just confuses
|
|
||||||
things and isn't really meant for shells anyway */
|
|
||||||
controlling_tty(0);
|
|
||||||
signal(SIGTTOU, SIG_IGN);
|
|
||||||
setpgid(0, getpid());
|
|
||||||
tcsetpgrp(ctty, getpid());
|
|
||||||
|
|
||||||
if (argv[0] && argv[0][0] == '-') {
|
if (argv[0] && argv[0][0] == '-') {
|
||||||
debug_printf("\nsourcing /etc/profile\n");
|
debug_printf("\nsourcing /etc/profile\n");
|
||||||
input = xfopen("/etc/profile", "r");
|
input = xfopen("/etc/profile", "r");
|
||||||
@ -2620,7 +2643,9 @@ int shell_main(int argc, char **argv)
|
|||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* Looks like they want an interactive shell */
|
/* Looks like they want an interactive shell */
|
||||||
fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
|
fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
|
||||||
|
setup_job_control();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[optind]==NULL) {
|
if (argv[optind]==NULL) {
|
||||||
opt=parse_file_outer(stdin);
|
opt=parse_file_outer(stdin);
|
||||||
goto final_return;
|
goto final_return;
|
||||||
|
79
shell/hush.c
79
shell/hush.c
@ -257,6 +257,7 @@ static char *PS2;
|
|||||||
struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
|
struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 };
|
||||||
struct variables *top_vars = &shell_ver;
|
struct variables *top_vars = &shell_ver;
|
||||||
|
|
||||||
|
|
||||||
#define B_CHUNK (100)
|
#define B_CHUNK (100)
|
||||||
#define B_NOSPAC 1
|
#define B_NOSPAC 1
|
||||||
|
|
||||||
@ -394,7 +395,7 @@ static void remove_bg_job(struct pipe *pi);
|
|||||||
static char *get_local_var(const char *var);
|
static char *get_local_var(const char *var);
|
||||||
static void unset_local_var(const char *name);
|
static void unset_local_var(const char *name);
|
||||||
static int set_local_var(const char *s, int flg_export);
|
static int set_local_var(const char *s, int flg_export);
|
||||||
|
static void sigchld_handler(int sig);
|
||||||
|
|
||||||
/* Table of built-in functions. They can be forked or not, depending on
|
/* Table of built-in functions. They can be forked or not, depending on
|
||||||
* context: within pipes, they fork. As simple commands, they do not.
|
* context: within pipes, they fork. As simple commands, they do not.
|
||||||
@ -556,7 +557,6 @@ static int builtin_fg_bg(struct child_prog *child)
|
|||||||
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
for (pi = job_list; pi; pi = pi->next) {
|
for (pi = job_list; pi; pi = pi->next) {
|
||||||
if (pi->jobid == jobnum) {
|
if (pi->jobid == jobnum) {
|
||||||
break;
|
break;
|
||||||
@ -567,6 +567,7 @@ static int builtin_fg_bg(struct child_prog *child)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (*child->argv[0] == 'f') {
|
if (*child->argv[0] == 'f') {
|
||||||
/* Make this job the foreground job */
|
/* Make this job the foreground job */
|
||||||
signal(SIGTTOU, SIG_IGN);
|
signal(SIGTTOU, SIG_IGN);
|
||||||
@ -613,6 +614,7 @@ static int builtin_jobs(struct child_prog *child)
|
|||||||
status_string = "Stopped";
|
status_string = "Stopped";
|
||||||
else
|
else
|
||||||
status_string = "Running";
|
status_string = "Running";
|
||||||
|
|
||||||
printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
|
printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text);
|
||||||
}
|
}
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
@ -1142,7 +1144,7 @@ static void insert_bg_job(struct pipe *pi)
|
|||||||
|
|
||||||
/* add thejob to the list of running jobs */
|
/* add thejob to the list of running jobs */
|
||||||
if (!job_list) {
|
if (!job_list) {
|
||||||
thejob = job_list= xmalloc(sizeof(*thejob));
|
thejob = job_list = xmalloc(sizeof(*thejob));
|
||||||
} else {
|
} else {
|
||||||
for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
|
for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */;
|
||||||
thejob->next = xmalloc(sizeof(*thejob));
|
thejob->next = xmalloc(sizeof(*thejob));
|
||||||
@ -1178,14 +1180,14 @@ static void remove_bg_job(struct pipe *pi)
|
|||||||
struct pipe *prev_pipe;
|
struct pipe *prev_pipe;
|
||||||
|
|
||||||
if (pi == job_list) {
|
if (pi == job_list) {
|
||||||
job_list= pi->next;
|
job_list = pi->next;
|
||||||
} else {
|
} else {
|
||||||
prev_pipe = job_list;
|
prev_pipe = job_list;
|
||||||
while (prev_pipe->next != pi)
|
while (prev_pipe->next != pi)
|
||||||
prev_pipe = prev_pipe->next;
|
prev_pipe = prev_pipe->next;
|
||||||
prev_pipe->next = pi->next;
|
prev_pipe->next = pi->next;
|
||||||
}
|
}
|
||||||
|
pi->stopped_progs = 0;
|
||||||
free_pipe(pi, 0);
|
free_pipe(pi, 0);
|
||||||
free(pi);
|
free(pi);
|
||||||
}
|
}
|
||||||
@ -1210,7 +1212,7 @@ static int checkjobs(struct pipe* fg_pipe)
|
|||||||
int i, rcode = 0;
|
int i, rcode = 0;
|
||||||
for (i=0; i < fg_pipe->num_progs; i++) {
|
for (i=0; i < fg_pipe->num_progs; i++) {
|
||||||
if (fg_pipe->progs[i].pid == childpid) {
|
if (fg_pipe->progs[i].pid == childpid) {
|
||||||
if (i==fg_pipe->num_progs-1)
|
if (i==fg_pipe->num_progs-1)
|
||||||
rcode=WEXITSTATUS(status);
|
rcode=WEXITSTATUS(status);
|
||||||
(fg_pipe->num_progs)--;
|
(fg_pipe->num_progs)--;
|
||||||
return(rcode);
|
return(rcode);
|
||||||
@ -1220,8 +1222,9 @@ static int checkjobs(struct pipe* fg_pipe)
|
|||||||
|
|
||||||
for (pi = job_list; pi; pi = pi->next) {
|
for (pi = job_list; pi; pi = pi->next) {
|
||||||
prognum = 0;
|
prognum = 0;
|
||||||
while (prognum < pi->num_progs &&
|
while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) {
|
||||||
pi->progs[prognum].pid != childpid) prognum++;
|
prognum++;
|
||||||
|
}
|
||||||
if (prognum < pi->num_progs)
|
if (prognum < pi->num_progs)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1245,9 +1248,14 @@ 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;
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
/* Printing this stuff is a pain, since it tends to
|
||||||
|
* overwrite the prompt an inconveinient moments. So
|
||||||
|
* don't do that. */
|
||||||
if (pi->stopped_progs == pi->num_progs) {
|
if (pi->stopped_progs == pi->num_progs) {
|
||||||
printf(JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
|
printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1394,7 +1402,6 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
|
|
||||||
/* XXX test for failed fork()? */
|
/* XXX test for failed fork()? */
|
||||||
if (!(child->pid = fork())) {
|
if (!(child->pid = fork())) {
|
||||||
|
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
|
|
||||||
close_all();
|
close_all();
|
||||||
@ -1414,7 +1421,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
/* Like bash, explicit redirects override pipes,
|
/* Like bash, explicit redirects override pipes,
|
||||||
* and the pipe fd is available for dup'ing. */
|
* and the pipe fd is available for dup'ing. */
|
||||||
setup_redirects(child,NULL);
|
setup_redirects(child,NULL);
|
||||||
|
|
||||||
if (interactive && pi->followup!=PIPE_BG) {
|
if (interactive && pi->followup!=PIPE_BG) {
|
||||||
/* If we (the child) win the race, put ourselves in the process
|
/* If we (the child) win the race, put ourselves in the process
|
||||||
* group whose leader is the first process in this pipe. */
|
* group whose leader is the first process in this pipe. */
|
||||||
@ -1423,15 +1430,17 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
if (setpgid(0, pi->pgrp) == 0) {
|
if (setpgid(0, pi->pgrp) == 0) {
|
||||||
signal(SIGTTOU, SIG_IGN);
|
signal(SIGTTOU, SIG_IGN);
|
||||||
tcsetpgrp(ctty, pi->pgrp);
|
tcsetpgrp(2, pi->pgrp);
|
||||||
signal(SIGTTOU, SIG_DFL);
|
signal(SIGTTOU, SIG_DFL);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pseudo_exec(child);
|
pseudo_exec(child);
|
||||||
}
|
}
|
||||||
/* Put our child in the process group whose leader is the
|
|
||||||
* first process in this pipe. */
|
|
||||||
|
/* put our child in the process group whose leader is the
|
||||||
|
first process in this pipe */
|
||||||
if (pi->pgrp < 0) {
|
if (pi->pgrp < 0) {
|
||||||
pi->pgrp = child->pid;
|
pi->pgrp = child->pid;
|
||||||
}
|
}
|
||||||
@ -1478,18 +1487,18 @@ static int run_list_real(struct pipe *pi)
|
|||||||
insert_bg_job(pi);
|
insert_bg_job(pi);
|
||||||
rcode = EXIT_SUCCESS;
|
rcode = EXIT_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* move the new process group into the foreground */
|
/* move the new process group into the foreground */
|
||||||
if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY)
|
if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp-3");
|
perror_msg("tcsetpgrp-3");
|
||||||
rcode = checkjobs(pi);
|
rcode = checkjobs(pi);
|
||||||
|
/* move the shell to the foreground */
|
||||||
if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY)
|
if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY)
|
||||||
perror_msg("tcsetpgrp-4");
|
perror_msg("tcsetpgrp-4");
|
||||||
} else {
|
} else {
|
||||||
rcode = checkjobs(pi);
|
rcode = checkjobs(pi);
|
||||||
}
|
}
|
||||||
debug_printf("pipe_wait returned %d\n",rcode);
|
debug_printf("checkjobs returned %d\n",rcode);
|
||||||
}
|
}
|
||||||
last_return_code=rcode;
|
last_return_code=rcode;
|
||||||
if ( rmode == RES_IF || rmode == RES_ELIF )
|
if ( rmode == RES_IF || rmode == RES_ELIF )
|
||||||
@ -1517,6 +1526,9 @@ static int free_pipe(struct pipe *pi, int indent)
|
|||||||
struct redir_struct *r, *rnext;
|
struct redir_struct *r, *rnext;
|
||||||
int a, i, ret_code=0;
|
int a, i, ret_code=0;
|
||||||
char *ind = indenter(indent);
|
char *ind = indenter(indent);
|
||||||
|
|
||||||
|
if (pi->stopped_progs > 0)
|
||||||
|
return ret_code;
|
||||||
final_printf("%s run pipe: (pid %d)\n",ind,getpid());
|
final_printf("%s run pipe: (pid %d)\n",ind,getpid());
|
||||||
for (i=0; i<pi->num_progs; i++) {
|
for (i=0; i<pi->num_progs; i++) {
|
||||||
child = &pi->progs[i];
|
child = &pi->progs[i];
|
||||||
@ -2516,6 +2528,27 @@ static int parse_file_outer(FILE *f)
|
|||||||
return rcode;
|
return rcode;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void sigchld_handler(int sig)
|
||||||
|
{
|
||||||
|
checkjobs(NULL);
|
||||||
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void setup_job_control()
|
||||||
|
{
|
||||||
|
/* If we get started under a job aware app (like bash
|
||||||
|
* for example), make sure we are now in charge so we
|
||||||
|
* don't fight over who gets the foreground */
|
||||||
|
/* don't pay any attention to this signal; it just confuses
|
||||||
|
things and isn't really meant for shells anyway */
|
||||||
|
setpgrp();
|
||||||
|
controlling_tty(0);
|
||||||
|
signal(SIGTTOU, SIG_IGN);
|
||||||
|
setpgid(0, getpid());
|
||||||
|
tcsetpgrp(ctty, getpid());
|
||||||
|
signal(SIGCHLD, sigchld_handler);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int shell_main(int argc, char **argv)
|
int shell_main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
@ -2536,11 +2569,11 @@ int shell_main(int argc, char **argv)
|
|||||||
interactive = 0;
|
interactive = 0;
|
||||||
close_me_head = NULL;
|
close_me_head = NULL;
|
||||||
last_bg_pid = 0;
|
last_bg_pid = 0;
|
||||||
|
job_list = NULL;
|
||||||
last_jobid = 0;
|
last_jobid = 0;
|
||||||
|
|
||||||
/* Initialize some more globals to non-zero values */
|
/* Initialize some more globals to non-zero values */
|
||||||
set_cwd();
|
set_cwd();
|
||||||
job_list = NULL;
|
|
||||||
#ifdef BB_FEATURE_COMMAND_EDITING
|
#ifdef BB_FEATURE_COMMAND_EDITING
|
||||||
cmdedit_set_initial_prompt();
|
cmdedit_set_initial_prompt();
|
||||||
#else
|
#else
|
||||||
@ -2558,16 +2591,6 @@ int shell_main(int argc, char **argv)
|
|||||||
last_return_code=EXIT_SUCCESS;
|
last_return_code=EXIT_SUCCESS;
|
||||||
|
|
||||||
|
|
||||||
/* If we get started under a job aware app (like bash
|
|
||||||
* for example), make sure we are now in charge so we
|
|
||||||
* don't fight over who gets the foreground */
|
|
||||||
/* don't pay any attention to this signal; it just confuses
|
|
||||||
things and isn't really meant for shells anyway */
|
|
||||||
controlling_tty(0);
|
|
||||||
signal(SIGTTOU, SIG_IGN);
|
|
||||||
setpgid(0, getpid());
|
|
||||||
tcsetpgrp(ctty, getpid());
|
|
||||||
|
|
||||||
if (argv[0] && argv[0][0] == '-') {
|
if (argv[0] && argv[0][0] == '-') {
|
||||||
debug_printf("\nsourcing /etc/profile\n");
|
debug_printf("\nsourcing /etc/profile\n");
|
||||||
input = xfopen("/etc/profile", "r");
|
input = xfopen("/etc/profile", "r");
|
||||||
@ -2620,7 +2643,9 @@ int shell_main(int argc, char **argv)
|
|||||||
if (interactive) {
|
if (interactive) {
|
||||||
/* Looks like they want an interactive shell */
|
/* Looks like they want an interactive shell */
|
||||||
fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
|
fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n");
|
||||||
|
setup_job_control();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (argv[optind]==NULL) {
|
if (argv[optind]==NULL) {
|
||||||
opt=parse_file_outer(stdin);
|
opt=parse_file_outer(stdin);
|
||||||
goto final_return;
|
goto final_return;
|
||||||
|
Loading…
Reference in New Issue
Block a user