aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/rc/havefork.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd/rc/havefork.c')
-rw-r--r--src/cmd/rc/havefork.c51
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;
}