diff options
author | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:42:11 +0000 |
---|---|---|
committer | Denis Vlasenko <vda.linux@googlemail.com> | 2007-04-28 16:42:11 +0000 |
commit | a6a1785a30d6fe011eeabec3c19e154dc475b1b0 (patch) | |
tree | 2233696369eac228e4fe16caa802888d6fb0b17b | |
parent | 706fdc98c3d30687d1ce359f58424c87e253017c (diff) | |
download | busybox-w32-a6a1785a30d6fe011eeabec3c19e154dc475b1b0.tar.gz busybox-w32-a6a1785a30d6fe011eeabec3c19e154dc475b1b0.tar.bz2 busybox-w32-a6a1785a30d6fe011eeabec3c19e154dc475b1b0.zip |
hush: add ctrl-Z handling for nofork'ed case
-rw-r--r-- | coreutils/sleep.c | 2 | ||||
-rw-r--r-- | shell/hush.c | 95 |
2 files changed, 84 insertions, 13 deletions
diff --git a/coreutils/sleep.c b/coreutils/sleep.c index 592005bab..b758de33b 100644 --- a/coreutils/sleep.c +++ b/coreutils/sleep.c | |||
@@ -61,6 +61,8 @@ int sleep_main(int argc, char **argv) | |||
61 | #endif /* FEATURE_FANCY_SLEEP */ | 61 | #endif /* FEATURE_FANCY_SLEEP */ |
62 | 62 | ||
63 | if (sleep(duration)) { | 63 | if (sleep(duration)) { |
64 | //for hush debugging: | ||
65 | sleep(1); | ||
64 | bb_perror_nomsg_and_die(); | 66 | bb_perror_nomsg_and_die(); |
65 | } | 67 | } |
66 | 68 | ||
diff --git a/shell/hush.c b/shell/hush.c index e2ce3676d..c87f3b566 100644 --- a/shell/hush.c +++ b/shell/hush.c | |||
@@ -431,6 +431,56 @@ static const struct built_in_command bltins[] = { | |||
431 | { NULL, NULL, NULL } | 431 | { NULL, NULL, NULL } |
432 | }; | 432 | }; |
433 | 433 | ||
434 | /* move to libbb? */ | ||
435 | static void signal_SA_RESTART(int sig, void (*handler)(int)) | ||
436 | { | ||
437 | struct sigaction sa; | ||
438 | sa.sa_handler = handler; | ||
439 | sa.sa_flags = SA_RESTART; | ||
440 | sigemptyset(&sa.sa_mask); | ||
441 | sigaction(sig, &sa, NULL); | ||
442 | } | ||
443 | |||
444 | static sigjmp_buf nofork_jb; | ||
445 | static smallint nofork_flag; | ||
446 | static struct pipe *nofork_pipe; | ||
447 | |||
448 | static void handler_ctrl_z(int sig) | ||
449 | { | ||
450 | pid_t pid; | ||
451 | |||
452 | fprintf(stderr, "got tty sig %d\n", sig); | ||
453 | if (!nofork_flag) | ||
454 | return; | ||
455 | pid = fork(); | ||
456 | if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */ | ||
457 | return; | ||
458 | fprintf(stderr, "bg'ing nofork\n"); | ||
459 | nofork_flag = 0; | ||
460 | nofork_pipe->running_progs = 1; | ||
461 | nofork_pipe->stopped_progs = 0; | ||
462 | if (!pid) { /* child */ | ||
463 | fprintf(stderr, "setting pgrp for child\n"); | ||
464 | setpgrp(); | ||
465 | signal(sig, SIG_DFL); /* make child do default action (stop) */ | ||
466 | raise(sig); /* resend TSTP so that child will be stopped */ | ||
467 | fprintf(stderr, "returning to child\n"); | ||
468 | /* return to nofork, it will eventually exit now, | ||
469 | * not return back to shell */ | ||
470 | return; | ||
471 | } | ||
472 | /* parent */ | ||
473 | /* finish filling up pipe info */ | ||
474 | nofork_pipe->pgrp = pid; /* child is in its own pgrp */ | ||
475 | nofork_pipe->progs[0].pid = pid; | ||
476 | nofork_pipe->running_progs = 1; | ||
477 | nofork_pipe->stopped_progs = 0; | ||
478 | /* parent needs to longjmp out of running nofork. | ||
479 | * we will "return" exitcode 0, with child put in background */ | ||
480 | // as usual we can have all kinds of nasty problems with leaked malloc data here | ||
481 | siglongjmp(nofork_jb, 1); | ||
482 | } | ||
483 | |||
434 | /* Restores tty foreground process group, and exits. | 484 | /* Restores tty foreground process group, and exits. |
435 | * May be called as signal handler for fatal signal | 485 | * May be called as signal handler for fatal signal |
436 | * (will faithfully resend signal to itself, producing correct exit state) | 486 | * (will faithfully resend signal to itself, producing correct exit state) |
@@ -1535,14 +1585,32 @@ static int run_pipe_real(struct pipe *pi) | |||
1535 | } | 1585 | } |
1536 | #if ENABLE_FEATURE_SH_STANDALONE | 1586 | #if ENABLE_FEATURE_SH_STANDALONE |
1537 | { | 1587 | { |
1538 | // FIXME: applet runs like part of shell - for example, it ignores | ||
1539 | // SIGINT! Try to Ctrl-C out of "rm -i"... doesn't work | ||
1540 | const struct bb_applet *a = find_applet_by_name(argv[i]); | 1588 | const struct bb_applet *a = find_applet_by_name(argv[i]); |
1541 | if (a && a->nofork) { | 1589 | if (a && a->nofork) { |
1542 | setup_redirects(child, squirrel); | 1590 | setup_redirects(child, squirrel); |
1543 | rcode = run_nofork_applet(a, argv + i); | 1591 | if (sigsetjmp(nofork_jb, 1) == 0) { |
1544 | restore_redirects(squirrel); | 1592 | // enable ctrl_z here, not globally? |
1545 | return rcode; | 1593 | nofork_flag = 1; |
1594 | /* TSTP handler will store pid there etc */ | ||
1595 | nofork_pipe = pi; | ||
1596 | rcode = run_nofork_applet(a, argv + i); | ||
1597 | if (--nofork_flag != 0) | ||
1598 | /* Ctrl-Z! forked, we are child */ | ||
1599 | exit(rcode); | ||
1600 | restore_redirects(squirrel); | ||
1601 | return rcode; | ||
1602 | } else { | ||
1603 | fprintf(stderr, "Exiting nofork early\n"); | ||
1604 | /* Ctrl-Z, forked, we are parent. | ||
1605 | * Sighandler has longjmped us here */ | ||
1606 | //problem: run_nofork_applet did not do the | ||
1607 | // "restore" trick and globals are trashed: | ||
1608 | // for one, applet_name is not "hush" :) | ||
1609 | // need to split run_nofork_applet into setup/run/restore... | ||
1610 | restore_redirects(squirrel); | ||
1611 | insert_bg_job(pi); | ||
1612 | return 0; | ||
1613 | } | ||
1546 | } | 1614 | } |
1547 | } | 1615 | } |
1548 | #endif | 1616 | #endif |
@@ -1585,7 +1653,7 @@ static int run_pipe_real(struct pipe *pi) | |||
1585 | /* Don't do pgrp restore anymore on fatal signals */ | 1653 | /* Don't do pgrp restore anymore on fatal signals */ |
1586 | set_fatal_sighandler(SIG_DFL); | 1654 | set_fatal_sighandler(SIG_DFL); |
1587 | } | 1655 | } |
1588 | 1656 | // in non-interactive case fatal sigs are already SIG_DFL | |
1589 | close_all(); | 1657 | close_all(); |
1590 | if (nextin != 0) { | 1658 | if (nextin != 0) { |
1591 | dup2(nextin, 0); | 1659 | dup2(nextin, 0); |
@@ -2927,17 +2995,16 @@ static void setup_job_control(void) | |||
2927 | { | 2995 | { |
2928 | pid_t shell_pgrp; | 2996 | pid_t shell_pgrp; |
2929 | 2997 | ||
2930 | saved_task_pgrp = getpgrp(); | 2998 | saved_task_pgrp = shell_pgrp = getpgrp(); |
2931 | debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp); | 2999 | debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp); |
2932 | fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); | 3000 | fcntl(interactive_fd, F_SETFD, FD_CLOEXEC); |
2933 | 3001 | ||
2934 | /* Loop until we are in the foreground. */ | 3002 | /* If we were ran as 'hush &', |
2935 | while (1) { | 3003 | * sleep until we are in the foreground. */ |
2936 | shell_pgrp = getpgrp(); | 3004 | while (tcgetpgrp(interactive_fd) != shell_pgrp) { |
2937 | if (tcgetpgrp(interactive_fd) == shell_pgrp) | 3005 | /* Send TTIN to ourself (will stop us) */ |
2938 | break; | ||
2939 | // and this does... what? need a comment here | ||
2940 | kill(- shell_pgrp, SIGTTIN); | 3006 | kill(- shell_pgrp, SIGTTIN); |
3007 | shell_pgrp = getpgrp(); | ||
2941 | } | 3008 | } |
2942 | 3009 | ||
2943 | /* Ignore job-control and misc signals. */ | 3010 | /* Ignore job-control and misc signals. */ |
@@ -2954,6 +3021,8 @@ static void setup_job_control(void) | |||
2954 | 3021 | ||
2955 | /* Grab control of the terminal. */ | 3022 | /* Grab control of the terminal. */ |
2956 | tcsetpgrp(interactive_fd, shell_pgrp); | 3023 | tcsetpgrp(interactive_fd, shell_pgrp); |
3024 | |||
3025 | signal_SA_RESTART(SIGTSTP, handler_ctrl_z); | ||
2957 | } | 3026 | } |
2958 | 3027 | ||
2959 | int hush_main(int argc, char **argv); | 3028 | int hush_main(int argc, char **argv); |