| #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" |
| #include "io.h" |
| #include "fns.h" |
| |
| int havefork = 1; |
| |
| void |
| Xasync(void) |
| { |
| int null = open("/dev/null", 0); |
| int tty; |
| int pid; |
| char npid[10]; |
| if(null<0){ |
| Xerror("Can't open /dev/null\n"); |
| return; |
| } |
| switch(pid = rfork(RFFDG|RFPROC|RFNOTEG)){ |
| case -1: |
| close(null); |
| Xerror("try again"); |
| break; |
| case 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); |
| setvar("apid", newword(npid, (word *)0)); |
| break; |
| } |
| } |
| |
| void |
| Xpipe(void) |
| { |
| struct thread *p = runq; |
| int pc = p->pc, forkid; |
| int lfd = p->code[pc++].i; |
| int rfd = p->code[pc++].i; |
| int pfd[2]; |
| if(pipe(pfd)<0){ |
| Xerror("can't get pipe"); |
| return; |
| } |
| switch(forkid = fork()){ |
| case -1: |
| 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); |
| p->pc = p->code[pc+1].i; |
| p->pid = forkid; |
| break; |
| } |
| } |
| |
| /* |
| * Who should wait for the exit from the fork? |
| */ |
| void |
| Xbackq(void) |
| { |
| struct thread *p = runq; |
| char wd[8193]; |
| int c, n; |
| char *s, *ewd=&wd[8192], *stop, *q; |
| struct io *f; |
| var *ifs = vlook("ifs"); |
| word *v, *nextv; |
| int pfd[2]; |
| int pid; |
| Rune r; |
| stop = ifs->val?ifs->val->word:""; |
| if(pipe(pfd)<0){ |
| Xerror("can't make pipe"); |
| return; |
| } |
| switch(pid = fork()){ |
| case -1: |
| Xerror("try again"); |
| close(pfd[PRD]); |
| 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; |
| v = 0; |
| while((c = rchr(f))!=EOF){ |
| if(s != ewd) { |
| *s++ = c; |
| for(q=stop; *q; q+=n) { |
| n = chartorune(&r, q); |
| if(s-wd >= n && memcmp(s-n, q, n) == 0) { |
| s -= n; |
| goto stop; |
| } |
| } |
| continue; |
| } |
| stop: |
| if(s != wd) { |
| *s = '\0'; |
| v = newword(wd, v); |
| } |
| s = wd; |
| } |
| if(s!=wd){ |
| *s='\0'; |
| v = newword(wd, v); |
| } |
| closeio(f); |
| Waitfor(pid, 0); |
| /* v points to reversed arglist -- reverse it onto argv */ |
| while(v){ |
| nextv = v->next; |
| v->next = runq->argv->words; |
| runq->argv->words = v; |
| v = nextv; |
| } |
| p->pc = p->code[p->pc].i; |
| return; |
| } |
| } |
| |
| void |
| Xpipefd(void) |
| { |
| struct thread *p = runq; |
| int pc = p->pc, pid; |
| char name[40]; |
| int pfd[2]; |
| struct { int sidefd, mainfd; } fd[2], *r, *w; |
| |
| r = &fd[0]; |
| w = &fd[1]; |
| switch(p->code[pc].i){ |
| case READ: |
| w = nil; |
| break; |
| case WRITE: |
| r = nil; |
| } |
| |
| if(r){ |
| if(pipe(pfd)<0){ |
| Xerror("can't get pipe"); |
| return; |
| } |
| r->sidefd = pfd[PWR]; |
| r->mainfd = pfd[PRD]; |
| } |
| if(w){ |
| if(pipe(pfd)<0){ |
| Xerror("can't get pipe"); |
| return; |
| } |
| w->sidefd = pfd[PRD]; |
| w->mainfd = pfd[PWR]; |
| } |
| switch(pid = fork()){ |
| case -1: |
| Xerror("try again"); |
| break; |
| case 0: |
| clearwaitpids(); |
| start(p->code, pc+2, runq->local); |
| if(r){ |
| close(r->mainfd); |
| pushredir(ROPEN, r->sidefd, 1); |
| } |
| if(w){ |
| close(w->mainfd); |
| pushredir(ROPEN, w->sidefd, 0); |
| } |
| runq->ret = 0; |
| break; |
| default: |
| addwaitpid(pid); |
| if(w){ |
| close(w->sidefd); |
| pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */ |
| strcpy(name, Fdprefix); |
| inttoascii(name+strlen(name), w->mainfd); |
| pushword(name); |
| } |
| if(r){ |
| close(r->sidefd); |
| pushredir(ROPEN, r->mainfd, r->mainfd); |
| strcpy(name, Fdprefix); |
| inttoascii(name+strlen(name), r->mainfd); |
| pushword(name); |
| } |
| p->pc = p->code[pc+1].i; |
| break; |
| } |
| } |
| |
| void |
| Xsubshell(void) |
| { |
| int pid; |
| switch(pid = fork()){ |
| case -1: |
| 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; |
| } |
| } |
| |
| int |
| execforkexec(void) |
| { |
| int pid; |
| int n; |
| char buf[ERRMAX]; |
| |
| switch(pid = fork()){ |
| case -1: |
| return -1; |
| case 0: |
| clearwaitpids(); |
| pushword("exec"); |
| execexec(); |
| strcpy(buf, "can't exec: "); |
| n = strlen(buf); |
| errstr(buf+n, ERRMAX-n); |
| Exit(buf); |
| } |
| addwaitpid(pid); |
| return pid; |
| } |