From 52881e9f23d1b02f75f2c1f5e704edc283be5cdf Mon Sep 17 00:00:00 2001 From: Denis Vlasenko Date: Sat, 21 Apr 2007 13:42:52 +0000 Subject: [PATCH] hush: fix more backgrounding bugs. Plenty of them remains still. --- shell/README | 8 +++++++- shell/hush.c | 32 ++++++++++++++++++++++---------- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/shell/README b/shell/README index bcd84dcad..b78d651a5 100644 --- a/shell/README +++ b/shell/README @@ -1,6 +1,12 @@ Various bits of what is known about busybox shells, in no particular order. -2007-04-22 +2007-04-21 +hush: fixed non-backgrounding of "sleep 1 &" and totally broken +"sleep 1 | sleep 2 &". Noticed a bug where successive jobs +get numbers 1,2,3 even when job #1 has exited before job# 2 is started. +(bash reuses #1 in this case) + +2007-04-21 hush: "sleep 1 | exit 3; echo $?" prints 0 because $? is substituted _before_ pipe gets executed!! run_list_real() already has "pipe;echo" parsed and handed to it for execution, so it sees "pipe"; "echo 0". diff --git a/shell/hush.c b/shell/hush.c index db93f8dcb..046e098d9 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -384,6 +384,7 @@ static int parse_string_outer(const char *s, int flag); static int parse_file_outer(FILE *f); /* job management: */ static int checkjobs(struct pipe* fg_pipe); +static int checkjobs_and_fg_shell(struct pipe* fg_pipe); static void insert_bg_job(struct pipe *pi); static void remove_bg_job(struct pipe *pi); /* local variable support */ @@ -648,6 +649,8 @@ static int builtin_fg_bg(struct child_prog *child) bb_error_msg("%s: %d: no such job", child->argv[0], jobnum); return EXIT_FAILURE; found: + // TODO: bash prints a string representation + // of job being foregrounded (like "sleep 1 | cat") if (*child->argv[0] == 'f') { /* Put the job into the foreground. */ tcsetpgrp(interactive_fd, pi->pgrp); @@ -658,6 +661,7 @@ static int builtin_fg_bg(struct child_prog *child) pi->progs[i].is_stopped = 0; i = kill(- pi->pgrp, SIGCONT); + pi->stopped_progs = 0; if (i < 0) { if (errno == ESRCH) { remove_bg_job(pi); @@ -666,7 +670,8 @@ static int builtin_fg_bg(struct child_prog *child) } } - pi->stopped_progs = 0; + if (*child->argv[0] == 'f') + return checkjobs_and_fg_shell(pi); return EXIT_SUCCESS; } @@ -1350,6 +1355,18 @@ static int checkjobs(struct pipe* fg_pipe) return rcode; } +static int checkjobs_and_fg_shell(struct pipe* fg_pipe) +{ + pid_t p; + int rcode = checkjobs(fg_pipe); + /* Job finished, move the shell to the foreground */ + p = getpgid(0); + debug_printf("fg'ing ourself: getpgid(0)=%d\n", (int)p); + if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY) + bb_perror_msg("tcsetpgrp-4a"); + return rcode; +} + /* run_pipe_real() starts all the jobs, but doesn't wait for anything * to finish. See checkjobs(). * @@ -1377,6 +1394,7 @@ static int run_pipe_real(struct pipe *pi) /* it is not always needed, but we aim to smaller code */ int squirrel[] = { -1, -1, -1 }; int rcode; + const int single_fg = (pi->num_progs == 1 && pi->followup != PIPE_BG); nextin = 0; pi->pgrp = -1; @@ -1386,7 +1404,7 @@ static int run_pipe_real(struct pipe *pi) * pseudo_exec. "echo foo | read bar" doesn't work on bash, either. */ child = &(pi->progs[0]); - if (pi->num_progs == 1 && child->group && child->subshell == 0) { + if (single_fg && child->group && child->subshell == 0) { debug_printf("non-subshell grouping\n"); setup_redirects(child, squirrel); /* XXX could we merge code with following builtin case, @@ -1396,7 +1414,7 @@ static int run_pipe_real(struct pipe *pi) return rcode; } - if (pi->num_progs == 1 && pi->progs[0].argv != NULL) { + if (single_fg && pi->progs[0].argv != NULL) { for (i = 0; is_assignment(child->argv[i]); i++) continue; if (i != 0 && child->argv[i] == NULL) { @@ -1675,13 +1693,7 @@ static int run_list_real(struct pipe *pi) rcode = EXIT_SUCCESS; } else { if (interactive_fd) { - pid_t p; - rcode = checkjobs(pi); - /* move the shell to the foreground */ - p = getpgid(0); - if (tcsetpgrp(interactive_fd, p) && errno != ENOTTY) - bb_perror_msg("tcsetpgrp-4"); - debug_printf("getpgid(0)=%d\n", (int)p); + rcode = checkjobs_and_fg_shell(pi); } else { rcode = checkjobs(pi); }