From b8a53fb6380de6741a7057cb43e95eb0dad1b023 Mon Sep 17 00:00:00 2001 From: tjr Date: Thu, 11 Jul 2002 06:42:11 +0000 Subject: Don't assume the shell's controlling terminal is attached to file descriptor 2. Instead, open /dev/tty. This problem stopped commands in subshells from being executed correctly if standard error was redirected. PR: 36671 Obtained from: NetBSD (but simplified) --- bin/sh/jobs.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) (limited to 'bin') diff --git a/bin/sh/jobs.c b/bin/sh/jobs.c index 7b4e42d..a8cf28d 100644 --- a/bin/sh/jobs.c +++ b/bin/sh/jobs.c @@ -45,6 +45,7 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -87,6 +88,7 @@ int initialpgrp; /* pgrp of shell on invocation */ int in_waitcmd = 0; /* are we in waitcmd()? */ int in_dowait = 0; /* are we in dowait()? */ volatile sig_atomic_t breakwaitcmd = 0; /* should wait be terminated? */ +static int ttyfd = -1; #if JOBS STATIC void restartjob(struct job *); @@ -122,21 +124,36 @@ MKINIT int jobctl; void setjobctl(int on) { + int i; if (on == jobctl || rootshell == 0) return; if (on) { + if (ttyfd != -1) + close(ttyfd); + if ((ttyfd = open(_PATH_TTY, O_RDWR)) < 0) { + i = 0; + while (i <= 2 && !isatty(i)) + i++; + if (i > 2 || (ttyfd = dup(i)) < 0) + goto out; + } + if (fcntl(ttyfd, FD_CLOEXEC, 1) < 0) { + close(ttyfd); + ttyfd = -1; + goto out; + } do { /* while we are in the background */ - initialpgrp = tcgetpgrp(2); + initialpgrp = tcgetpgrp(ttyfd); if (initialpgrp < 0) { - out2str("sh: can't access tty; job control turned off\n"); +out: out2str("sh: can't access tty; job control turned off\n"); mflag = 0; return; } if (initialpgrp == -1) initialpgrp = getpgrp(); else if (initialpgrp != getpgrp()) { - killpg(initialpgrp, SIGTTIN); + killpg(0, SIGTTIN); continue; } } while (0); @@ -144,10 +161,12 @@ setjobctl(int on) setsignal(SIGTTOU); setsignal(SIGTTIN); setpgid(0, rootpid); - tcsetpgrp(2, rootpid); + tcsetpgrp(ttyfd, rootpid); } else { /* turning job control off */ setpgid(0, initialpgrp); - tcsetpgrp(2, initialpgrp); + tcsetpgrp(ttyfd, initialpgrp); + close(ttyfd); + ttyfd = -1; setsignal(SIGTSTP); setsignal(SIGTTOU); setsignal(SIGTTIN); @@ -187,7 +206,7 @@ fgcmd(int argc __unused, char **argv) out1c('\n'); flushout(&output); pgrp = jp->ps[0].pid; - tcsetpgrp(2, pgrp); + tcsetpgrp(ttyfd, pgrp); restartjob(jp); INTOFF; status = waitforjob(jp, (int *)NULL); @@ -742,7 +761,7 @@ forkshell(struct job *jp, union node *n, int mode) pgrp = jp->ps[0].pid; if (setpgid(0, pgrp) == 0 && mode == FORK_FG) { /*** this causes superfluous TIOCSPGRPS ***/ - if (tcsetpgrp(2, pgrp) < 0) + if (tcsetpgrp(ttyfd, pgrp) < 0) error("tcsetpgrp failed, errno=%d", errno); } setsignal(SIGTSTP); @@ -840,7 +859,7 @@ waitforjob(struct job *jp, int *origstatus) dotrap(); #if JOBS if (jp->jobctl) { - if (tcsetpgrp(2, mypgrp) < 0) + if (tcsetpgrp(ttyfd, mypgrp) < 0) error("tcsetpgrp failed, errno=%d\n", errno); } if (jp->state == JOBSTOPPED) -- cgit v1.1