From 52a97ca00cf5d290c9beb65ba7c217a5ed69ee42 Mon Sep 17 00:00:00 2001 From: Eric Andersen Date: Fri, 22 Jun 2001 06:49:26 +0000 Subject: [PATCH] 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 --- hush.c | 79 +++++++++++++++++++++++++++++++++++++++--------------------- shell/hush.c | 79 +++++++++++++++++++++++++++++++++++++++--------------------- 2 files changed, 104 insertions(+), 54 deletions(-) diff --git a/hush.c b/hush.c index a9d3a16..fa01d91 100644 --- a/hush.c +++ b/hush.c @@ -257,6 +257,7 @@ static char *PS2; struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; struct variables *top_vars = &shell_ver; + #define B_CHUNK (100) #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 void unset_local_var(const char *name); 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 * 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]); return EXIT_FAILURE; } - for (pi = job_list; pi; pi = pi->next) { if (pi->jobid == jobnum) { break; @@ -567,6 +567,7 @@ static int builtin_fg_bg(struct child_prog *child) return EXIT_FAILURE; } } + if (*child->argv[0] == 'f') { /* Make this job the foreground job */ signal(SIGTTOU, SIG_IGN); @@ -613,6 +614,7 @@ static int builtin_jobs(struct child_prog *child) status_string = "Stopped"; else status_string = "Running"; + printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); } return EXIT_SUCCESS; @@ -1142,7 +1144,7 @@ static void insert_bg_job(struct pipe *pi) /* add thejob to the list of running jobs */ if (!job_list) { - thejob = job_list= xmalloc(sizeof(*thejob)); + thejob = job_list = xmalloc(sizeof(*thejob)); } else { for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; thejob->next = xmalloc(sizeof(*thejob)); @@ -1178,14 +1180,14 @@ static void remove_bg_job(struct pipe *pi) struct pipe *prev_pipe; if (pi == job_list) { - job_list= pi->next; + job_list = pi->next; } else { prev_pipe = job_list; while (prev_pipe->next != pi) prev_pipe = prev_pipe->next; prev_pipe->next = pi->next; } - + pi->stopped_progs = 0; free_pipe(pi, 0); free(pi); } @@ -1210,7 +1212,7 @@ static int checkjobs(struct pipe* fg_pipe) int i, rcode = 0; for (i=0; i < fg_pipe->num_progs; i++) { if (fg_pipe->progs[i].pid == childpid) { - if (i==fg_pipe->num_progs-1) + if (i==fg_pipe->num_progs-1) rcode=WEXITSTATUS(status); (fg_pipe->num_progs)--; return(rcode); @@ -1220,8 +1222,9 @@ static int checkjobs(struct pipe* fg_pipe) for (pi = job_list; pi; pi = pi->next) { prognum = 0; - while (prognum < pi->num_progs && - pi->progs[prognum].pid != childpid) prognum++; + while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { + prognum++; + } if (prognum < pi->num_progs) break; } @@ -1245,9 +1248,14 @@ static int checkjobs(struct pipe* fg_pipe) pi->stopped_progs++; 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) { - 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()? */ if (!(child->pid = fork())) { - signal(SIGTTOU, SIG_DFL); close_all(); @@ -1414,7 +1421,7 @@ static int run_pipe_real(struct pipe *pi) /* Like bash, explicit redirects override pipes, * and the pipe fd is available for dup'ing. */ setup_redirects(child,NULL); - + if (interactive && pi->followup!=PIPE_BG) { /* If we (the child) win the race, put ourselves in the process * 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) { signal(SIGTTOU, SIG_IGN); - tcsetpgrp(ctty, pi->pgrp); + tcsetpgrp(2, pi->pgrp); signal(SIGTTOU, SIG_DFL); } } 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) { pi->pgrp = child->pid; } @@ -1478,18 +1487,18 @@ static int run_list_real(struct pipe *pi) insert_bg_job(pi); rcode = EXIT_SUCCESS; } else { - if (interactive) { /* move the new process group into the foreground */ if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY) perror_msg("tcsetpgrp-3"); rcode = checkjobs(pi); + /* move the shell to the foreground */ if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY) perror_msg("tcsetpgrp-4"); } else { rcode = checkjobs(pi); } - debug_printf("pipe_wait returned %d\n",rcode); + debug_printf("checkjobs returned %d\n",rcode); } last_return_code=rcode; 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; int a, i, ret_code=0; char *ind = indenter(indent); + + if (pi->stopped_progs > 0) + return ret_code; final_printf("%s run pipe: (pid %d)\n",ind,getpid()); for (i=0; inum_progs; i++) { child = &pi->progs[i]; @@ -2516,6 +2528,27 @@ static int parse_file_outer(FILE *f) 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) { @@ -2536,11 +2569,11 @@ int shell_main(int argc, char **argv) interactive = 0; close_me_head = NULL; last_bg_pid = 0; + job_list = NULL; last_jobid = 0; /* Initialize some more globals to non-zero values */ set_cwd(); - job_list = NULL; #ifdef BB_FEATURE_COMMAND_EDITING cmdedit_set_initial_prompt(); #else @@ -2558,16 +2591,6 @@ int shell_main(int argc, char **argv) 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] == '-') { debug_printf("\nsourcing /etc/profile\n"); input = xfopen("/etc/profile", "r"); @@ -2620,7 +2643,9 @@ int shell_main(int argc, char **argv) if (interactive) { /* Looks like they want an interactive shell */ fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); + setup_job_control(); } + if (argv[optind]==NULL) { opt=parse_file_outer(stdin); goto final_return; diff --git a/shell/hush.c b/shell/hush.c index a9d3a16..fa01d91 100644 --- a/shell/hush.c +++ b/shell/hush.c @@ -257,6 +257,7 @@ static char *PS2; struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; struct variables *top_vars = &shell_ver; + #define B_CHUNK (100) #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 void unset_local_var(const char *name); 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 * 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]); return EXIT_FAILURE; } - for (pi = job_list; pi; pi = pi->next) { if (pi->jobid == jobnum) { break; @@ -567,6 +567,7 @@ static int builtin_fg_bg(struct child_prog *child) return EXIT_FAILURE; } } + if (*child->argv[0] == 'f') { /* Make this job the foreground job */ signal(SIGTTOU, SIG_IGN); @@ -613,6 +614,7 @@ static int builtin_jobs(struct child_prog *child) status_string = "Stopped"; else status_string = "Running"; + printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); } return EXIT_SUCCESS; @@ -1142,7 +1144,7 @@ static void insert_bg_job(struct pipe *pi) /* add thejob to the list of running jobs */ if (!job_list) { - thejob = job_list= xmalloc(sizeof(*thejob)); + thejob = job_list = xmalloc(sizeof(*thejob)); } else { for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; thejob->next = xmalloc(sizeof(*thejob)); @@ -1178,14 +1180,14 @@ static void remove_bg_job(struct pipe *pi) struct pipe *prev_pipe; if (pi == job_list) { - job_list= pi->next; + job_list = pi->next; } else { prev_pipe = job_list; while (prev_pipe->next != pi) prev_pipe = prev_pipe->next; prev_pipe->next = pi->next; } - + pi->stopped_progs = 0; free_pipe(pi, 0); free(pi); } @@ -1210,7 +1212,7 @@ static int checkjobs(struct pipe* fg_pipe) int i, rcode = 0; for (i=0; i < fg_pipe->num_progs; i++) { if (fg_pipe->progs[i].pid == childpid) { - if (i==fg_pipe->num_progs-1) + if (i==fg_pipe->num_progs-1) rcode=WEXITSTATUS(status); (fg_pipe->num_progs)--; return(rcode); @@ -1220,8 +1222,9 @@ static int checkjobs(struct pipe* fg_pipe) for (pi = job_list; pi; pi = pi->next) { prognum = 0; - while (prognum < pi->num_progs && - pi->progs[prognum].pid != childpid) prognum++; + while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { + prognum++; + } if (prognum < pi->num_progs) break; } @@ -1245,9 +1248,14 @@ static int checkjobs(struct pipe* fg_pipe) pi->stopped_progs++; 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) { - 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()? */ if (!(child->pid = fork())) { - signal(SIGTTOU, SIG_DFL); close_all(); @@ -1414,7 +1421,7 @@ static int run_pipe_real(struct pipe *pi) /* Like bash, explicit redirects override pipes, * and the pipe fd is available for dup'ing. */ setup_redirects(child,NULL); - + if (interactive && pi->followup!=PIPE_BG) { /* If we (the child) win the race, put ourselves in the process * 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) { signal(SIGTTOU, SIG_IGN); - tcsetpgrp(ctty, pi->pgrp); + tcsetpgrp(2, pi->pgrp); signal(SIGTTOU, SIG_DFL); } } 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) { pi->pgrp = child->pid; } @@ -1478,18 +1487,18 @@ static int run_list_real(struct pipe *pi) insert_bg_job(pi); rcode = EXIT_SUCCESS; } else { - if (interactive) { /* move the new process group into the foreground */ if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY) perror_msg("tcsetpgrp-3"); rcode = checkjobs(pi); + /* move the shell to the foreground */ if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY) perror_msg("tcsetpgrp-4"); } else { rcode = checkjobs(pi); } - debug_printf("pipe_wait returned %d\n",rcode); + debug_printf("checkjobs returned %d\n",rcode); } last_return_code=rcode; 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; int a, i, ret_code=0; char *ind = indenter(indent); + + if (pi->stopped_progs > 0) + return ret_code; final_printf("%s run pipe: (pid %d)\n",ind,getpid()); for (i=0; inum_progs; i++) { child = &pi->progs[i]; @@ -2516,6 +2528,27 @@ static int parse_file_outer(FILE *f) 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) { @@ -2536,11 +2569,11 @@ int shell_main(int argc, char **argv) interactive = 0; close_me_head = NULL; last_bg_pid = 0; + job_list = NULL; last_jobid = 0; /* Initialize some more globals to non-zero values */ set_cwd(); - job_list = NULL; #ifdef BB_FEATURE_COMMAND_EDITING cmdedit_set_initial_prompt(); #else @@ -2558,16 +2591,6 @@ int shell_main(int argc, char **argv) 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] == '-') { debug_printf("\nsourcing /etc/profile\n"); input = xfopen("/etc/profile", "r"); @@ -2620,7 +2643,9 @@ int shell_main(int argc, char **argv) if (interactive) { /* Looks like they want an interactive shell */ fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); + setup_job_control(); } + if (argv[optind]==NULL) { opt=parse_file_outer(stdin); goto final_return; -- 2.7.4