From 2ade60747db41771498ab2b85ce6e3c3389f2c26 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Wed, 13 Oct 2021 09:08:59 -0700 Subject: feat(rc): added unix port of rc with linenoise --- sys/cmd/rc/havefork.c | 300 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 300 insertions(+) create mode 100644 sys/cmd/rc/havefork.c (limited to 'sys/cmd/rc/havefork.c') diff --git a/sys/cmd/rc/havefork.c b/sys/cmd/rc/havefork.c new file mode 100644 index 0000000..02120e8 --- /dev/null +++ b/sys/cmd/rc/havefork.c @@ -0,0 +1,300 @@ +#ifdef Plan9 +#include +#endif +#include +#if defined(PLAN9PORT) && defined(__sun__) +# define BSD_COMP /* sigh. for TIOCNOTTY */ +#endif +#include +#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; +} -- cgit v1.2.1