diff options
| author | Eric Andersen <andersen@codepoet.org> | 2001-06-22 06:49:26 +0000 |
|---|---|---|
| committer | Eric Andersen <andersen@codepoet.org> | 2001-06-22 06:49:26 +0000 |
| commit | 52a97ca00cf5d290c9beb65ba7c217a5ed69ee42 (patch) | |
| tree | d87fec02a954a19653c67025d22ba8ecb8df4123 /shell | |
| parent | c798b0776264950350b53a0aa58101bb1dfcf6dc (diff) | |
| download | busybox-w32-52a97ca00cf5d290c9beb65ba7c217a5ed69ee42.tar.gz busybox-w32-52a97ca00cf5d290c9beb65ba7c217a5ed69ee42.tar.bz2 busybox-w32-52a97ca00cf5d290c9beb65ba7c217a5ed69ee42.zip | |
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
Diffstat (limited to 'shell')
| -rw-r--r-- | shell/hush.c | 79 |
1 files changed, 52 insertions, 27 deletions
diff --git a/shell/hush.c b/shell/hush.c index a9d3a16ac..fa01d9135 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
| @@ -257,6 +257,7 @@ static char *PS2; | |||
| 257 | struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; | 257 | struct variables shell_ver = { "HUSH_VERSION", "0.01", 1, 1, 0 }; |
| 258 | struct variables *top_vars = &shell_ver; | 258 | struct variables *top_vars = &shell_ver; |
| 259 | 259 | ||
| 260 | |||
| 260 | #define B_CHUNK (100) | 261 | #define B_CHUNK (100) |
| 261 | #define B_NOSPAC 1 | 262 | #define B_NOSPAC 1 |
| 262 | 263 | ||
| @@ -394,7 +395,7 @@ static void remove_bg_job(struct pipe *pi); | |||
| 394 | static char *get_local_var(const char *var); | 395 | static char *get_local_var(const char *var); |
| 395 | static void unset_local_var(const char *name); | 396 | static void unset_local_var(const char *name); |
| 396 | static int set_local_var(const char *s, int flg_export); | 397 | static int set_local_var(const char *s, int flg_export); |
| 397 | 398 | static void sigchld_handler(int sig); | |
| 398 | 399 | ||
| 399 | /* Table of built-in functions. They can be forked or not, depending on | 400 | /* Table of built-in functions. They can be forked or not, depending on |
| 400 | * context: within pipes, they fork. As simple commands, they do not. | 401 | * context: within pipes, they fork. As simple commands, they do not. |
| @@ -556,7 +557,6 @@ static int builtin_fg_bg(struct child_prog *child) | |||
| 556 | error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); | 557 | error_msg("%s: bad argument '%s'", child->argv[0], child->argv[1]); |
| 557 | return EXIT_FAILURE; | 558 | return EXIT_FAILURE; |
| 558 | } | 559 | } |
| 559 | |||
| 560 | for (pi = job_list; pi; pi = pi->next) { | 560 | for (pi = job_list; pi; pi = pi->next) { |
| 561 | if (pi->jobid == jobnum) { | 561 | if (pi->jobid == jobnum) { |
| 562 | break; | 562 | break; |
| @@ -567,6 +567,7 @@ static int builtin_fg_bg(struct child_prog *child) | |||
| 567 | return EXIT_FAILURE; | 567 | return EXIT_FAILURE; |
| 568 | } | 568 | } |
| 569 | } | 569 | } |
| 570 | |||
| 570 | if (*child->argv[0] == 'f') { | 571 | if (*child->argv[0] == 'f') { |
| 571 | /* Make this job the foreground job */ | 572 | /* Make this job the foreground job */ |
| 572 | signal(SIGTTOU, SIG_IGN); | 573 | signal(SIGTTOU, SIG_IGN); |
| @@ -613,6 +614,7 @@ static int builtin_jobs(struct child_prog *child) | |||
| 613 | status_string = "Stopped"; | 614 | status_string = "Stopped"; |
| 614 | else | 615 | else |
| 615 | status_string = "Running"; | 616 | status_string = "Running"; |
| 617 | |||
| 616 | printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); | 618 | printf(JOB_STATUS_FORMAT, job->jobid, status_string, job->text); |
| 617 | } | 619 | } |
| 618 | return EXIT_SUCCESS; | 620 | return EXIT_SUCCESS; |
| @@ -1142,7 +1144,7 @@ static void insert_bg_job(struct pipe *pi) | |||
| 1142 | 1144 | ||
| 1143 | /* add thejob to the list of running jobs */ | 1145 | /* add thejob to the list of running jobs */ |
| 1144 | if (!job_list) { | 1146 | if (!job_list) { |
| 1145 | thejob = job_list= xmalloc(sizeof(*thejob)); | 1147 | thejob = job_list = xmalloc(sizeof(*thejob)); |
| 1146 | } else { | 1148 | } else { |
| 1147 | for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; | 1149 | for (thejob = job_list; thejob->next; thejob = thejob->next) /* nothing */; |
| 1148 | thejob->next = xmalloc(sizeof(*thejob)); | 1150 | thejob->next = xmalloc(sizeof(*thejob)); |
| @@ -1178,14 +1180,14 @@ static void remove_bg_job(struct pipe *pi) | |||
| 1178 | struct pipe *prev_pipe; | 1180 | struct pipe *prev_pipe; |
| 1179 | 1181 | ||
| 1180 | if (pi == job_list) { | 1182 | if (pi == job_list) { |
| 1181 | job_list= pi->next; | 1183 | job_list = pi->next; |
| 1182 | } else { | 1184 | } else { |
| 1183 | prev_pipe = job_list; | 1185 | prev_pipe = job_list; |
| 1184 | while (prev_pipe->next != pi) | 1186 | while (prev_pipe->next != pi) |
| 1185 | prev_pipe = prev_pipe->next; | 1187 | prev_pipe = prev_pipe->next; |
| 1186 | prev_pipe->next = pi->next; | 1188 | prev_pipe->next = pi->next; |
| 1187 | } | 1189 | } |
| 1188 | 1190 | pi->stopped_progs = 0; | |
| 1189 | free_pipe(pi, 0); | 1191 | free_pipe(pi, 0); |
| 1190 | free(pi); | 1192 | free(pi); |
| 1191 | } | 1193 | } |
| @@ -1210,7 +1212,7 @@ static int checkjobs(struct pipe* fg_pipe) | |||
| 1210 | int i, rcode = 0; | 1212 | int i, rcode = 0; |
| 1211 | for (i=0; i < fg_pipe->num_progs; i++) { | 1213 | for (i=0; i < fg_pipe->num_progs; i++) { |
| 1212 | if (fg_pipe->progs[i].pid == childpid) { | 1214 | if (fg_pipe->progs[i].pid == childpid) { |
| 1213 | if (i==fg_pipe->num_progs-1) | 1215 | if (i==fg_pipe->num_progs-1) |
| 1214 | rcode=WEXITSTATUS(status); | 1216 | rcode=WEXITSTATUS(status); |
| 1215 | (fg_pipe->num_progs)--; | 1217 | (fg_pipe->num_progs)--; |
| 1216 | return(rcode); | 1218 | return(rcode); |
| @@ -1220,8 +1222,9 @@ static int checkjobs(struct pipe* fg_pipe) | |||
| 1220 | 1222 | ||
| 1221 | for (pi = job_list; pi; pi = pi->next) { | 1223 | for (pi = job_list; pi; pi = pi->next) { |
| 1222 | prognum = 0; | 1224 | prognum = 0; |
| 1223 | while (prognum < pi->num_progs && | 1225 | while (prognum < pi->num_progs && pi->progs[prognum].pid != childpid) { |
| 1224 | pi->progs[prognum].pid != childpid) prognum++; | 1226 | prognum++; |
| 1227 | } | ||
| 1225 | if (prognum < pi->num_progs) | 1228 | if (prognum < pi->num_progs) |
| 1226 | break; | 1229 | break; |
| 1227 | } | 1230 | } |
| @@ -1245,9 +1248,14 @@ static int checkjobs(struct pipe* fg_pipe) | |||
| 1245 | pi->stopped_progs++; | 1248 | pi->stopped_progs++; |
| 1246 | pi->progs[prognum].is_stopped = 1; | 1249 | pi->progs[prognum].is_stopped = 1; |
| 1247 | 1250 | ||
| 1251 | #if 0 | ||
| 1252 | /* Printing this stuff is a pain, since it tends to | ||
| 1253 | * overwrite the prompt an inconveinient moments. So | ||
| 1254 | * don't do that. */ | ||
| 1248 | if (pi->stopped_progs == pi->num_progs) { | 1255 | if (pi->stopped_progs == pi->num_progs) { |
| 1249 | printf(JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); | 1256 | printf("\n"JOB_STATUS_FORMAT, pi->jobid, "Stopped", pi->text); |
| 1250 | } | 1257 | } |
| 1258 | #endif | ||
| 1251 | } | 1259 | } |
| 1252 | } | 1260 | } |
| 1253 | 1261 | ||
| @@ -1394,7 +1402,6 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1394 | 1402 | ||
| 1395 | /* XXX test for failed fork()? */ | 1403 | /* XXX test for failed fork()? */ |
| 1396 | if (!(child->pid = fork())) { | 1404 | if (!(child->pid = fork())) { |
| 1397 | |||
| 1398 | signal(SIGTTOU, SIG_DFL); | 1405 | signal(SIGTTOU, SIG_DFL); |
| 1399 | 1406 | ||
| 1400 | close_all(); | 1407 | close_all(); |
| @@ -1414,7 +1421,7 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1414 | /* Like bash, explicit redirects override pipes, | 1421 | /* Like bash, explicit redirects override pipes, |
| 1415 | * and the pipe fd is available for dup'ing. */ | 1422 | * and the pipe fd is available for dup'ing. */ |
| 1416 | setup_redirects(child,NULL); | 1423 | setup_redirects(child,NULL); |
| 1417 | 1424 | ||
| 1418 | if (interactive && pi->followup!=PIPE_BG) { | 1425 | if (interactive && pi->followup!=PIPE_BG) { |
| 1419 | /* If we (the child) win the race, put ourselves in the process | 1426 | /* If we (the child) win the race, put ourselves in the process |
| 1420 | * group whose leader is the first process in this pipe. */ | 1427 | * group whose leader is the first process in this pipe. */ |
| @@ -1423,15 +1430,17 @@ static int run_pipe_real(struct pipe *pi) | |||
| 1423 | } | 1430 | } |
| 1424 | if (setpgid(0, pi->pgrp) == 0) { | 1431 | if (setpgid(0, pi->pgrp) == 0) { |
| 1425 | signal(SIGTTOU, SIG_IGN); | 1432 | signal(SIGTTOU, SIG_IGN); |
| 1426 | tcsetpgrp(ctty, pi->pgrp); | 1433 | tcsetpgrp(2, pi->pgrp); |
| 1427 | signal(SIGTTOU, SIG_DFL); | 1434 | signal(SIGTTOU, SIG_DFL); |
| 1428 | } | 1435 | } |
| 1429 | } | 1436 | } |
| 1430 | 1437 | ||
| 1431 | pseudo_exec(child); | 1438 | pseudo_exec(child); |
| 1432 | } | 1439 | } |
| 1433 | /* Put our child in the process group whose leader is the | 1440 | |
| 1434 | * first process in this pipe. */ | 1441 | |
| 1442 | /* put our child in the process group whose leader is the | ||
| 1443 | first process in this pipe */ | ||
| 1435 | if (pi->pgrp < 0) { | 1444 | if (pi->pgrp < 0) { |
| 1436 | pi->pgrp = child->pid; | 1445 | pi->pgrp = child->pid; |
| 1437 | } | 1446 | } |
| @@ -1478,18 +1487,18 @@ static int run_list_real(struct pipe *pi) | |||
| 1478 | insert_bg_job(pi); | 1487 | insert_bg_job(pi); |
| 1479 | rcode = EXIT_SUCCESS; | 1488 | rcode = EXIT_SUCCESS; |
| 1480 | } else { | 1489 | } else { |
| 1481 | |||
| 1482 | if (interactive) { | 1490 | if (interactive) { |
| 1483 | /* move the new process group into the foreground */ | 1491 | /* move the new process group into the foreground */ |
| 1484 | if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY) | 1492 | if (tcsetpgrp(ctty, pi->pgrp) && errno != ENOTTY) |
| 1485 | perror_msg("tcsetpgrp-3"); | 1493 | perror_msg("tcsetpgrp-3"); |
| 1486 | rcode = checkjobs(pi); | 1494 | rcode = checkjobs(pi); |
| 1495 | /* move the shell to the foreground */ | ||
| 1487 | if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY) | 1496 | if (tcsetpgrp(ctty, getpgid(0)) && errno != ENOTTY) |
| 1488 | perror_msg("tcsetpgrp-4"); | 1497 | perror_msg("tcsetpgrp-4"); |
| 1489 | } else { | 1498 | } else { |
| 1490 | rcode = checkjobs(pi); | 1499 | rcode = checkjobs(pi); |
| 1491 | } | 1500 | } |
| 1492 | debug_printf("pipe_wait returned %d\n",rcode); | 1501 | debug_printf("checkjobs returned %d\n",rcode); |
| 1493 | } | 1502 | } |
| 1494 | last_return_code=rcode; | 1503 | last_return_code=rcode; |
| 1495 | if ( rmode == RES_IF || rmode == RES_ELIF ) | 1504 | if ( rmode == RES_IF || rmode == RES_ELIF ) |
| @@ -1517,6 +1526,9 @@ static int free_pipe(struct pipe *pi, int indent) | |||
| 1517 | struct redir_struct *r, *rnext; | 1526 | struct redir_struct *r, *rnext; |
| 1518 | int a, i, ret_code=0; | 1527 | int a, i, ret_code=0; |
| 1519 | char *ind = indenter(indent); | 1528 | char *ind = indenter(indent); |
| 1529 | |||
| 1530 | if (pi->stopped_progs > 0) | ||
| 1531 | return ret_code; | ||
| 1520 | final_printf("%s run pipe: (pid %d)\n",ind,getpid()); | 1532 | final_printf("%s run pipe: (pid %d)\n",ind,getpid()); |
| 1521 | for (i=0; i<pi->num_progs; i++) { | 1533 | for (i=0; i<pi->num_progs; i++) { |
| 1522 | child = &pi->progs[i]; | 1534 | child = &pi->progs[i]; |
| @@ -2516,6 +2528,27 @@ static int parse_file_outer(FILE *f) | |||
| 2516 | return rcode; | 2528 | return rcode; |
| 2517 | } | 2529 | } |
| 2518 | 2530 | ||
| 2531 | static void sigchld_handler(int sig) | ||
| 2532 | { | ||
| 2533 | checkjobs(NULL); | ||
| 2534 | signal(SIGCHLD, sigchld_handler); | ||
| 2535 | } | ||
| 2536 | |||
| 2537 | static void setup_job_control() | ||
| 2538 | { | ||
| 2539 | /* If we get started under a job aware app (like bash | ||
| 2540 | * for example), make sure we are now in charge so we | ||
| 2541 | * don't fight over who gets the foreground */ | ||
| 2542 | /* don't pay any attention to this signal; it just confuses | ||
| 2543 | things and isn't really meant for shells anyway */ | ||
| 2544 | setpgrp(); | ||
| 2545 | controlling_tty(0); | ||
| 2546 | signal(SIGTTOU, SIG_IGN); | ||
| 2547 | setpgid(0, getpid()); | ||
| 2548 | tcsetpgrp(ctty, getpid()); | ||
| 2549 | signal(SIGCHLD, sigchld_handler); | ||
| 2550 | } | ||
| 2551 | |||
| 2519 | 2552 | ||
| 2520 | int shell_main(int argc, char **argv) | 2553 | int shell_main(int argc, char **argv) |
| 2521 | { | 2554 | { |
| @@ -2536,11 +2569,11 @@ int shell_main(int argc, char **argv) | |||
| 2536 | interactive = 0; | 2569 | interactive = 0; |
| 2537 | close_me_head = NULL; | 2570 | close_me_head = NULL; |
| 2538 | last_bg_pid = 0; | 2571 | last_bg_pid = 0; |
| 2572 | job_list = NULL; | ||
| 2539 | last_jobid = 0; | 2573 | last_jobid = 0; |
| 2540 | 2574 | ||
| 2541 | /* Initialize some more globals to non-zero values */ | 2575 | /* Initialize some more globals to non-zero values */ |
| 2542 | set_cwd(); | 2576 | set_cwd(); |
| 2543 | job_list = NULL; | ||
| 2544 | #ifdef BB_FEATURE_COMMAND_EDITING | 2577 | #ifdef BB_FEATURE_COMMAND_EDITING |
| 2545 | cmdedit_set_initial_prompt(); | 2578 | cmdedit_set_initial_prompt(); |
| 2546 | #else | 2579 | #else |
| @@ -2558,16 +2591,6 @@ int shell_main(int argc, char **argv) | |||
| 2558 | last_return_code=EXIT_SUCCESS; | 2591 | last_return_code=EXIT_SUCCESS; |
| 2559 | 2592 | ||
| 2560 | 2593 | ||
| 2561 | /* If we get started under a job aware app (like bash | ||
| 2562 | * for example), make sure we are now in charge so we | ||
| 2563 | * don't fight over who gets the foreground */ | ||
| 2564 | /* don't pay any attention to this signal; it just confuses | ||
| 2565 | things and isn't really meant for shells anyway */ | ||
| 2566 | controlling_tty(0); | ||
| 2567 | signal(SIGTTOU, SIG_IGN); | ||
| 2568 | setpgid(0, getpid()); | ||
| 2569 | tcsetpgrp(ctty, getpid()); | ||
| 2570 | |||
| 2571 | if (argv[0] && argv[0][0] == '-') { | 2594 | if (argv[0] && argv[0][0] == '-') { |
| 2572 | debug_printf("\nsourcing /etc/profile\n"); | 2595 | debug_printf("\nsourcing /etc/profile\n"); |
| 2573 | input = xfopen("/etc/profile", "r"); | 2596 | input = xfopen("/etc/profile", "r"); |
| @@ -2620,7 +2643,9 @@ int shell_main(int argc, char **argv) | |||
| 2620 | if (interactive) { | 2643 | if (interactive) { |
| 2621 | /* Looks like they want an interactive shell */ | 2644 | /* Looks like they want an interactive shell */ |
| 2622 | fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); | 2645 | fprintf(stdout, "\nhush -- the humble shell v0.01 (testing)\n\n"); |
| 2646 | setup_job_control(); | ||
| 2623 | } | 2647 | } |
| 2648 | |||
| 2624 | if (argv[optind]==NULL) { | 2649 | if (argv[optind]==NULL) { |
| 2625 | opt=parse_file_outer(stdin); | 2650 | opt=parse_file_outer(stdin); |
| 2626 | goto final_return; | 2651 | goto final_return; |
