hush: add ctrl-Z handling for nofork'ed case
This commit is contained in:
parent
706fdc98c3
commit
a6a1785a30
@ -61,6 +61,8 @@ int sleep_main(int argc, char **argv)
|
|||||||
#endif /* FEATURE_FANCY_SLEEP */
|
#endif /* FEATURE_FANCY_SLEEP */
|
||||||
|
|
||||||
if (sleep(duration)) {
|
if (sleep(duration)) {
|
||||||
|
//for hush debugging:
|
||||||
|
sleep(1);
|
||||||
bb_perror_nomsg_and_die();
|
bb_perror_nomsg_and_die();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
89
shell/hush.c
89
shell/hush.c
@ -431,6 +431,56 @@ static const struct built_in_command bltins[] = {
|
|||||||
{ NULL, NULL, NULL }
|
{ NULL, NULL, NULL }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* move to libbb? */
|
||||||
|
static void signal_SA_RESTART(int sig, void (*handler)(int))
|
||||||
|
{
|
||||||
|
struct sigaction sa;
|
||||||
|
sa.sa_handler = handler;
|
||||||
|
sa.sa_flags = SA_RESTART;
|
||||||
|
sigemptyset(&sa.sa_mask);
|
||||||
|
sigaction(sig, &sa, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static sigjmp_buf nofork_jb;
|
||||||
|
static smallint nofork_flag;
|
||||||
|
static struct pipe *nofork_pipe;
|
||||||
|
|
||||||
|
static void handler_ctrl_z(int sig)
|
||||||
|
{
|
||||||
|
pid_t pid;
|
||||||
|
|
||||||
|
fprintf(stderr, "got tty sig %d\n", sig);
|
||||||
|
if (!nofork_flag)
|
||||||
|
return;
|
||||||
|
pid = fork();
|
||||||
|
if (pid < 0) /* can't fork. Pretend there were no Ctrl-Z */
|
||||||
|
return;
|
||||||
|
fprintf(stderr, "bg'ing nofork\n");
|
||||||
|
nofork_flag = 0;
|
||||||
|
nofork_pipe->running_progs = 1;
|
||||||
|
nofork_pipe->stopped_progs = 0;
|
||||||
|
if (!pid) { /* child */
|
||||||
|
fprintf(stderr, "setting pgrp for child\n");
|
||||||
|
setpgrp();
|
||||||
|
signal(sig, SIG_DFL); /* make child do default action (stop) */
|
||||||
|
raise(sig); /* resend TSTP so that child will be stopped */
|
||||||
|
fprintf(stderr, "returning to child\n");
|
||||||
|
/* return to nofork, it will eventually exit now,
|
||||||
|
* not return back to shell */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* parent */
|
||||||
|
/* finish filling up pipe info */
|
||||||
|
nofork_pipe->pgrp = pid; /* child is in its own pgrp */
|
||||||
|
nofork_pipe->progs[0].pid = pid;
|
||||||
|
nofork_pipe->running_progs = 1;
|
||||||
|
nofork_pipe->stopped_progs = 0;
|
||||||
|
/* parent needs to longjmp out of running nofork.
|
||||||
|
* we will "return" exitcode 0, with child put in background */
|
||||||
|
// as usual we can have all kinds of nasty problems with leaked malloc data here
|
||||||
|
siglongjmp(nofork_jb, 1);
|
||||||
|
}
|
||||||
|
|
||||||
/* Restores tty foreground process group, and exits.
|
/* Restores tty foreground process group, and exits.
|
||||||
* May be called as signal handler for fatal signal
|
* May be called as signal handler for fatal signal
|
||||||
* (will faithfully resend signal to itself, producing correct exit state)
|
* (will faithfully resend signal to itself, producing correct exit state)
|
||||||
@ -1535,14 +1585,32 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
}
|
}
|
||||||
#if ENABLE_FEATURE_SH_STANDALONE
|
#if ENABLE_FEATURE_SH_STANDALONE
|
||||||
{
|
{
|
||||||
// FIXME: applet runs like part of shell - for example, it ignores
|
|
||||||
// SIGINT! Try to Ctrl-C out of "rm -i"... doesn't work
|
|
||||||
const struct bb_applet *a = find_applet_by_name(argv[i]);
|
const struct bb_applet *a = find_applet_by_name(argv[i]);
|
||||||
if (a && a->nofork) {
|
if (a && a->nofork) {
|
||||||
setup_redirects(child, squirrel);
|
setup_redirects(child, squirrel);
|
||||||
|
if (sigsetjmp(nofork_jb, 1) == 0) {
|
||||||
|
// enable ctrl_z here, not globally?
|
||||||
|
nofork_flag = 1;
|
||||||
|
/* TSTP handler will store pid there etc */
|
||||||
|
nofork_pipe = pi;
|
||||||
rcode = run_nofork_applet(a, argv + i);
|
rcode = run_nofork_applet(a, argv + i);
|
||||||
|
if (--nofork_flag != 0)
|
||||||
|
/* Ctrl-Z! forked, we are child */
|
||||||
|
exit(rcode);
|
||||||
restore_redirects(squirrel);
|
restore_redirects(squirrel);
|
||||||
return rcode;
|
return rcode;
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Exiting nofork early\n");
|
||||||
|
/* Ctrl-Z, forked, we are parent.
|
||||||
|
* Sighandler has longjmped us here */
|
||||||
|
//problem: run_nofork_applet did not do the
|
||||||
|
// "restore" trick and globals are trashed:
|
||||||
|
// for one, applet_name is not "hush" :)
|
||||||
|
// need to split run_nofork_applet into setup/run/restore...
|
||||||
|
restore_redirects(squirrel);
|
||||||
|
insert_bg_job(pi);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -1585,7 +1653,7 @@ static int run_pipe_real(struct pipe *pi)
|
|||||||
/* Don't do pgrp restore anymore on fatal signals */
|
/* Don't do pgrp restore anymore on fatal signals */
|
||||||
set_fatal_sighandler(SIG_DFL);
|
set_fatal_sighandler(SIG_DFL);
|
||||||
}
|
}
|
||||||
|
// in non-interactive case fatal sigs are already SIG_DFL
|
||||||
close_all();
|
close_all();
|
||||||
if (nextin != 0) {
|
if (nextin != 0) {
|
||||||
dup2(nextin, 0);
|
dup2(nextin, 0);
|
||||||
@ -2927,17 +2995,16 @@ static void setup_job_control(void)
|
|||||||
{
|
{
|
||||||
pid_t shell_pgrp;
|
pid_t shell_pgrp;
|
||||||
|
|
||||||
saved_task_pgrp = getpgrp();
|
saved_task_pgrp = shell_pgrp = getpgrp();
|
||||||
debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp);
|
debug_printf("saved_task_pgrp=%d\n", saved_task_pgrp);
|
||||||
fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
|
fcntl(interactive_fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
|
||||||
/* Loop until we are in the foreground. */
|
/* If we were ran as 'hush &',
|
||||||
while (1) {
|
* sleep until we are in the foreground. */
|
||||||
shell_pgrp = getpgrp();
|
while (tcgetpgrp(interactive_fd) != shell_pgrp) {
|
||||||
if (tcgetpgrp(interactive_fd) == shell_pgrp)
|
/* Send TTIN to ourself (will stop us) */
|
||||||
break;
|
|
||||||
// and this does... what? need a comment here
|
|
||||||
kill(- shell_pgrp, SIGTTIN);
|
kill(- shell_pgrp, SIGTTIN);
|
||||||
|
shell_pgrp = getpgrp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Ignore job-control and misc signals. */
|
/* Ignore job-control and misc signals. */
|
||||||
@ -2954,6 +3021,8 @@ static void setup_job_control(void)
|
|||||||
|
|
||||||
/* Grab control of the terminal. */
|
/* Grab control of the terminal. */
|
||||||
tcsetpgrp(interactive_fd, shell_pgrp);
|
tcsetpgrp(interactive_fd, shell_pgrp);
|
||||||
|
|
||||||
|
signal_SA_RESTART(SIGTSTP, handler_ctrl_z);
|
||||||
}
|
}
|
||||||
|
|
||||||
int hush_main(int argc, char **argv);
|
int hush_main(int argc, char **argv);
|
||||||
|
Loading…
Reference in New Issue
Block a user