aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenis Vlasenko <vda.linux@googlemail.com>2007-04-28 16:42:11 +0000
committerDenis Vlasenko <vda.linux@googlemail.com>2007-04-28 16:42:11 +0000
commita6a1785a30d6fe011eeabec3c19e154dc475b1b0 (patch)
tree2233696369eac228e4fe16caa802888d6fb0b17b
parent706fdc98c3d30687d1ce359f58424c87e253017c (diff)
downloadbusybox-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.c2
-rw-r--r--shell/hush.c95
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:
65sleep(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? */
435static 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
444static sigjmp_buf nofork_jb;
445static smallint nofork_flag;
446static struct pipe *nofork_pipe;
447
448static 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
2959int hush_main(int argc, char **argv); 3028int hush_main(int argc, char **argv);