diff options
Diffstat (limited to 'shell')
-rw-r--r-- | shell/ash.c | 83 |
1 files changed, 79 insertions, 4 deletions
diff --git a/shell/ash.c b/shell/ash.c index bfdd94047..d8f41327b 100644 --- a/shell/ash.c +++ b/shell/ash.c | |||
@@ -3579,6 +3579,72 @@ static struct job *curjob; //lots | |||
3579 | /* number of presumed living untracked jobs */ | 3579 | /* number of presumed living untracked jobs */ |
3580 | static int jobless; //4 | 3580 | static int jobless; //4 |
3581 | 3581 | ||
3582 | #if 0 | ||
3583 | /* Bash has a feature: it restores termios after a successful wait for | ||
3584 | * a foreground job which had at least one stopped or sigkilled member. | ||
3585 | * The probable rationale is that SIGSTOP and SIGKILL can preclude task from | ||
3586 | * properly restoring tty state. Should we do this too? | ||
3587 | * A reproducer: ^Z an interactive python: | ||
3588 | * | ||
3589 | * # python | ||
3590 | * Python 2.7.12 (...) | ||
3591 | * >>> ^Z | ||
3592 | * { python leaves tty in -icanon -echo state. We do survive that... } | ||
3593 | * [1]+ Stopped python | ||
3594 | * { ...however, next program (python #2) does not survive it well: } | ||
3595 | * # python | ||
3596 | * Python 2.7.12 (...) | ||
3597 | * >>> Traceback (most recent call last): | ||
3598 | * { above, I typed "qwerty<CR>", but -echo state is still in effect } | ||
3599 | * File "<stdin>", line 1, in <module> | ||
3600 | * NameError: name 'qwerty' is not defined | ||
3601 | * | ||
3602 | * The implementation below is modeled on bash code and seems to work. | ||
3603 | * However, I'm not sure we should do this. For one: what if I'd fg | ||
3604 | * the stopped python instead? It'll be confused by "restored" tty state. | ||
3605 | */ | ||
3606 | static struct termios shell_tty_info; | ||
3607 | static void | ||
3608 | get_tty_state(void) | ||
3609 | { | ||
3610 | if (rootshell && ttyfd >= 0) | ||
3611 | tcgetattr(ttyfd, &shell_tty_info); | ||
3612 | } | ||
3613 | static void | ||
3614 | set_tty_state(void) | ||
3615 | { | ||
3616 | /* if (rootshell) - caller ensures this */ | ||
3617 | if (ttyfd >= 0) | ||
3618 | tcsetattr(ttyfd, TCSADRAIN, &shell_tty_info); | ||
3619 | } | ||
3620 | static int | ||
3621 | job_signal_status(struct job *jp) | ||
3622 | { | ||
3623 | int status; | ||
3624 | unsigned i; | ||
3625 | struct procstat *ps = jp->ps; | ||
3626 | for (i = 0; i < jp->nprocs; i++) { | ||
3627 | status = ps[i].ps_status; | ||
3628 | if (WIFSIGNALED(status) || WIFSTOPPED(status)) | ||
3629 | return status; | ||
3630 | } | ||
3631 | return 0; | ||
3632 | } | ||
3633 | static void | ||
3634 | restore_tty_if_stopped_or_signaled(struct job *jp) | ||
3635 | { | ||
3636 | //TODO: check what happens if we come from waitforjob() in expbackq() | ||
3637 | if (rootshell) { | ||
3638 | int s = job_signal_status(jp); | ||
3639 | if (s) /* WIFSIGNALED(s) || WIFSTOPPED(s) */ | ||
3640 | set_tty_state(); | ||
3641 | } | ||
3642 | } | ||
3643 | #else | ||
3644 | # define get_tty_state() ((void)0) | ||
3645 | # define restore_tty_if_stopped_or_signaled(jp) ((void)0) | ||
3646 | #endif | ||
3647 | |||
3582 | static void | 3648 | static void |
3583 | set_curjob(struct job *jp, unsigned mode) | 3649 | set_curjob(struct job *jp, unsigned mode) |
3584 | { | 3650 | { |
@@ -3910,8 +3976,10 @@ restartjob(struct job *jp, int mode) | |||
3910 | goto out; | 3976 | goto out; |
3911 | jp->state = JOBRUNNING; | 3977 | jp->state = JOBRUNNING; |
3912 | pgid = jp->ps[0].ps_pid; | 3978 | pgid = jp->ps[0].ps_pid; |
3913 | if (mode == FORK_FG) | 3979 | if (mode == FORK_FG) { |
3980 | get_tty_state(); | ||
3914 | xtcsetpgrp(ttyfd, pgid); | 3981 | xtcsetpgrp(ttyfd, pgid); |
3982 | } | ||
3915 | killpg(pgid, SIGCONT); | 3983 | killpg(pgid, SIGCONT); |
3916 | ps = jp->ps; | 3984 | ps = jp->ps; |
3917 | i = jp->nprocs; | 3985 | i = jp->nprocs; |
@@ -4445,7 +4513,7 @@ makejob(/*union node *node,*/ int nprocs) | |||
4445 | memset(jp, 0, sizeof(*jp)); | 4513 | memset(jp, 0, sizeof(*jp)); |
4446 | #if JOBS | 4514 | #if JOBS |
4447 | /* jp->jobctl is a bitfield. | 4515 | /* jp->jobctl is a bitfield. |
4448 | * "jp->jobctl |= jobctl" likely to give awful code */ | 4516 | * "jp->jobctl |= doing_jobctl" likely to give awful code */ |
4449 | if (doing_jobctl) | 4517 | if (doing_jobctl) |
4450 | jp->jobctl = 1; | 4518 | jp->jobctl = 1; |
4451 | #endif | 4519 | #endif |
@@ -5040,6 +5108,8 @@ waitforjob(struct job *jp) | |||
5040 | #if JOBS | 5108 | #if JOBS |
5041 | if (jp->jobctl) { | 5109 | if (jp->jobctl) { |
5042 | xtcsetpgrp(ttyfd, rootpid); | 5110 | xtcsetpgrp(ttyfd, rootpid); |
5111 | restore_tty_if_stopped_or_signaled(jp); | ||
5112 | |||
5043 | /* | 5113 | /* |
5044 | * This is truly gross. | 5114 | * This is truly gross. |
5045 | * If we're doing job control, then we did a TIOCSPGRP which | 5115 | * If we're doing job control, then we did a TIOCSPGRP which |
@@ -8852,13 +8922,15 @@ static int | |||
8852 | evalsubshell(union node *n, int flags) | 8922 | evalsubshell(union node *n, int flags) |
8853 | { | 8923 | { |
8854 | struct job *jp; | 8924 | struct job *jp; |
8855 | int backgnd = (n->type == NBACKGND); | 8925 | int backgnd = (n->type == NBACKGND); /* FORK_BG(1) if yes, else FORK_FG(0) */ |
8856 | int status; | 8926 | int status; |
8857 | 8927 | ||
8858 | expredir(n->nredir.redirect); | 8928 | expredir(n->nredir.redirect); |
8859 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) | 8929 | if (!backgnd && (flags & EV_EXIT) && !may_have_traps) |
8860 | goto nofork; | 8930 | goto nofork; |
8861 | INT_OFF; | 8931 | INT_OFF; |
8932 | if (backgnd == FORK_FG) | ||
8933 | get_tty_state(); | ||
8862 | jp = makejob(/*n,*/ 1); | 8934 | jp = makejob(/*n,*/ 1); |
8863 | if (forkshell(jp, n, backgnd) == 0) { | 8935 | if (forkshell(jp, n, backgnd) == 0) { |
8864 | /* child */ | 8936 | /* child */ |
@@ -8873,7 +8945,7 @@ evalsubshell(union node *n, int flags) | |||
8873 | } | 8945 | } |
8874 | /* parent */ | 8946 | /* parent */ |
8875 | status = 0; | 8947 | status = 0; |
8876 | if (!backgnd) | 8948 | if (backgnd == FORK_FG) |
8877 | status = waitforjob(jp); | 8949 | status = waitforjob(jp); |
8878 | INT_ON; | 8950 | INT_ON; |
8879 | return status; | 8951 | return status; |
@@ -8965,6 +9037,8 @@ evalpipe(union node *n, int flags) | |||
8965 | pipelen++; | 9037 | pipelen++; |
8966 | flags |= EV_EXIT; | 9038 | flags |= EV_EXIT; |
8967 | INT_OFF; | 9039 | INT_OFF; |
9040 | if (n->npipe.pipe_backgnd == 0) | ||
9041 | get_tty_state(); | ||
8968 | jp = makejob(/*n,*/ pipelen); | 9042 | jp = makejob(/*n,*/ pipelen); |
8969 | prevfd = -1; | 9043 | prevfd = -1; |
8970 | for (lp = n->npipe.cmdlist; lp; lp = lp->next) { | 9044 | for (lp = n->npipe.cmdlist; lp; lp = lp->next) { |
@@ -9647,6 +9721,7 @@ evalcommand(union node *cmd, int flags) | |||
9647 | if (!(flags & EV_EXIT) || may_have_traps) { | 9721 | if (!(flags & EV_EXIT) || may_have_traps) { |
9648 | /* No, forking off a child is necessary */ | 9722 | /* No, forking off a child is necessary */ |
9649 | INT_OFF; | 9723 | INT_OFF; |
9724 | get_tty_state(); | ||
9650 | jp = makejob(/*cmd,*/ 1); | 9725 | jp = makejob(/*cmd,*/ 1); |
9651 | if (forkshell(jp, cmd, FORK_FG) != 0) { | 9726 | if (forkshell(jp, cmd, FORK_FG) != 0) { |
9652 | /* parent */ | 9727 | /* parent */ |