diff options
Diffstat (limited to 'src/cmd/rc/havefork.c')
-rw-r--r-- | src/cmd/rc/havefork.c | 51 |
1 files changed, 48 insertions, 3 deletions
diff --git a/src/cmd/rc/havefork.c b/src/cmd/rc/havefork.c index e81046d6..45419f0d 100644 --- a/src/cmd/rc/havefork.c +++ b/src/cmd/rc/havefork.c @@ -1,3 +1,9 @@ +#include <u.h> +#include <signal.h> +#if defined(PLAN9PORT) && defined(__sun__) +# define BSD_COMP /* sigh. for TIOCNOTTY */ +#endif +#include <sys/ioctl.h> #include "rc.h" #include "getflags.h" #include "exec.h" @@ -10,6 +16,7 @@ void Xasync(void) { int null = open("/dev/null", 0); + int tty; int pid; char npid[10]; if(null<0){ @@ -22,11 +29,39 @@ Xasync(void) Xerror("try again"); break; case 0: - pushredir(ROPEN, null, 0); + clearwaitpids(); + /* + * I don't know what the right thing to do here is, + * so this is all experimentally determined. + * If we just dup /dev/null onto 0, then running + * ssh foo & will reopen /dev/tty, try to read a password, + * get a signal, and repeat, in a tight loop, forever. + * Arguably this is a bug in ssh (it behaves the same + * way under bash as under rc) but I'm fixing it here + * anyway. If we dissociate the process from the tty, + * then it won't be able to open /dev/tty ever again. + * The SIG_IGN on SIGTTOU makes writing the tty + * (via fd 1 or 2, for example) succeed even though + * our pgrp is not the terminal's controlling pgrp. + */ + if((tty = open("/dev/tty", OREAD)) >= 0){ + /* + * Should make reads of tty fail, writes succeed. + */ + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + ioctl(tty, TIOCNOTTY); + close(tty); + } + if(isatty(0)) + pushredir(ROPEN, null, 0); + else + close(null); start(runq->code, runq->pc+1, runq->local); runq->ret = 0; break; default: + addwaitpid(pid); close(null); runq->pc = runq->code[runq->pc].i; inttoascii(npid, pid); @@ -52,12 +87,14 @@ Xpipe(void) Xerror("try again"); break; case 0: + clearwaitpids(); start(p->code, pc+2, runq->local); runq->ret = 0; close(pfd[PRD]); pushredir(ROPEN, pfd[PWR], lfd); break; default: + addwaitpid(forkid); start(p->code, p->code[pc].i, runq->local); close(pfd[PWR]); pushredir(ROPEN, pfd[PRD], rfd); @@ -93,11 +130,13 @@ Xbackq(void) close(pfd[PWR]); return; case 0: + clearwaitpids(); close(pfd[PRD]); start(runq->code, runq->pc+1, runq->local); pushredir(ROPEN, pfd[PWR], 1); return; default: + addwaitpid(pid); close(pfd[PWR]); f = openfd(pfd[PRD]); s = wd; @@ -134,7 +173,7 @@ void Xpipefd(void) { struct thread *p = runq; - int pc = p->pc; + int pc = p->pc, pid; char name[40]; int pfd[2]; int sidefd, mainfd; @@ -150,17 +189,19 @@ Xpipefd(void) sidefd = pfd[PRD]; mainfd = pfd[PWR]; } - switch(fork()){ + switch(pid = fork()){ case -1: Xerror("try again"); break; case 0: + clearwaitpids(); start(p->code, pc+2, runq->local); close(mainfd); pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); runq->ret = 0; break; default: + addwaitpid(pid); close(sidefd); pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */ strcpy(name, Fdprefix); @@ -180,10 +221,12 @@ Xsubshell(void) Xerror("try again"); break; case 0: + clearwaitpids(); start(runq->code, runq->pc+1, runq->local); runq->ret = 0; break; default: + addwaitpid(pid); Waitfor(pid, 1); runq->pc = runq->code[runq->pc].i; break; @@ -201,6 +244,7 @@ execforkexec(void) case -1: return -1; case 0: + clearwaitpids(); pushword("exec"); execexec(); strcpy(buf, "can't exec: "); @@ -208,5 +252,6 @@ execforkexec(void) errstr(buf+n, ERRMAX-n); Exit(buf); } + addwaitpid(pid); return pid; } |