shithub: riscv

Download patch

ref: 4ad3f4f2fd225b0ac5c9f49e3c5713a5996becd3
parent: 45d6bca5f0c405a3fc3e485d23a52e980627988f
author: cinap_lenrek <cinap_lenrek@felloff.net>
date: Sun May 15 20:37:49 EDT 2016

rc: remove historical unix and win32 ports

--- a/sys/src/cmd/rc/code.c
+++ b/sys/src/cmd/rc/code.c
@@ -108,13 +108,10 @@
 		break;
 	case '&':
 		emitf(Xasync);
-		if(havefork){
-			p = emiti(0);
-			outcode(c0, eflag);
-			emitf(Xexit);
-			stuffdot(p);
-		} else
-			emits(fnstr(c0));
+		p = emiti(0);
+		outcode(c0, eflag);
+		emitf(Xexit);
+		stuffdot(p);
 		break;
 	case ';':
 		outcode(c0, eflag);
@@ -129,13 +126,10 @@
 		break;
 	case '`':
 		emitf(Xbackq);
-		if(havefork){
-			p = emiti(0);
-			outcode(c0, 0);
-			emitf(Xexit);
-			stuffdot(p);
-		} else
-			emits(fnstr(c0));
+		p = emiti(0);
+		outcode(c0, 0);
+		emitf(Xexit);
+		stuffdot(p);
 		break;
 	case ANDAND:
 		outcode(c0, 0);
@@ -211,13 +205,10 @@
 		break;
 	case SUBSHELL:
 		emitf(Xsubshell);
-		if(havefork){
-			p = emiti(0);
-			outcode(c0, eflag);
-			emitf(Xexit);
-			stuffdot(p);
-		} else
-			emits(fnstr(c0));
+		p = emiti(0);
+		outcode(c0, eflag);
+		emitf(Xexit);
+		stuffdot(p);
 		if(eflag)
 			emitf(Xeflag);
 		break;
@@ -304,14 +295,10 @@
 	case PIPEFD:
 		emitf(Xpipefd);
 		emiti(t->rtype);
-		if(havefork){
-			p = emiti(0);
-			outcode(c0, eflag);
-			emitf(Xexit);
-			stuffdot(p);
-		} else {
-			emits(fnstr(c0));
-		}
+		p = emiti(0);
+		outcode(c0, eflag);
+		emitf(Xexit);
+		stuffdot(p);
 		break;
 	case REDIR:
 		emitf(Xmark);
@@ -366,16 +353,11 @@
 		emitf(Xpipe);
 		emiti(t->fd0);
 		emiti(t->fd1);
-		if(havefork){
-			p = emiti(0);
-			q = emiti(0);
-			outcode(c0, eflag);
-			emitf(Xexit);
-			stuffdot(p);
-		} else {
-			emits(fnstr(c0));
-			q = emiti(0);
-		}
+		p = emiti(0);
+		q = emiti(0);
+		outcode(c0, eflag);
+		emitf(Xexit);
+		stuffdot(p);
 		outcode(c1, eflag);
 		emitf(Xreturn);
 		stuffdot(q);
--- a/sys/src/cmd/rc/compiling.on.unix
+++ /dev/null
@@ -1,1866 +1,0 @@
-From geoff@collyer.net Fri Dec 19 01:21:40 EST 2003
-Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:21:39 EST 2003
-Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:21:35 EST 2003
-Message-ID: <c790d8b1e06b3918ad2c7848a3ae0ec7@collyer.net>
-subject: rc on unix, part 1
-From: Geoff Collyer <geoff@collyer.net>
-Date: Thu, 18 Dec 2003 22:21:33 -0800
-To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
-MIME-Version: 1.0
-Content-Type: text/plain; charset="US-ASCII"
-Content-Transfer-Encoding: 7bit
-
-I got /sys/src/cmd/rc to compile under APE (in preparation for moving it
-to Unixes) with the following changed files.  I cadged some include files
-from rsc but had to edit lib9.h slightly.  I'll send the include files
-separately.  I can't tell if it works yet, but it does complain about
-/usr/lib/rcmain being absent when I start it.  Oh, and I haven't yet
-simulated the effect of the OCEXEC bit.
-
-
-# To unbundle, run this file
-echo mkfile
-sed 's/^X//' >mkfile <<'!'
-X</$objtype/mkfile
-
-TARG=rc
-COMMONOFILES=\
-X	code.$O\
-X	exec.$O\
-X	getflags.$O\
-X	glob.$O\
-X	here.$O\
-X	io.$O\
-X	lex.$O\
-X	pcmd.$O\
-X	pfnc.$O\
-X	simple.$O\
-X	subr.$O\
-X	trap.$O\
-X	tree.$O\
-X	var.$O\
-X	havefork.$O\
-
-PLAN9OFILES=plan9.$O\
-
-UNIXOFILES=unix.$O\
-
-OFILES=$COMMONOFILES $UNIXOFILES y.tab.$O
-
-HFILES=rc.h\
-X	x.tab.h\
-X	io.h\
-X	exec.h\
-X	fns.h\
-
-YFILES=syn.y
-
-BIN=/$objtype/bin
-
-UPDATE=\
-X	mkfile\
-X	$HFILES\
-X	${COMMONOFILES:%.$O=%.c}\
-X	${UNIXOFILES:%.$O=%.c}\
-X	${PLAN9OFILES:%.$O=%.c}\
-X	$YFILES\
-X	${TARG:%=/386/bin/%}\
-
-CC=pcc -c -B -I../include
-LD=pcc
-
-X</sys/src/cmd/mkone
-
-x.tab.h: y.tab.h
-X	cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
-
-clean:V:
-X	rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
-
-regress: $O.out
-X	cd test
-X	mk
-
-unregress:V:
-X	for(test in test/*.test) rc $test >$test.out
-
-listing:
-X	pr mkfile $HFILES $FILES $FILES9 $FILESUNIX $YFILES|lp -du
-!
-echo simple.c
-sed 's/^X//' >simple.c <<'!'
-X/*
-X * Maybe `simple' is a misnomer.
-X */
-X#include "rc.h"
-X#include "getflags.h"
-X#include "exec.h"
-X#include "io.h"
-X#include "fns.h"
-X/*
-X * Search through the following code to see if we're just going to exit.
-X */
-exitnext(void){
-X	union code *c=&runq->code[runq->pc];
-X	while(c->f==Xpopredir) c++;
-X	return c->f==Xexit;
-X}
-
-void
-XXsimple(void)
-X{
-X	word *a;
-X	thread *p = runq;
-X	var *v;
-X	struct builtin *bp;
-X	int pid;
-X	globlist();
-X	a = runq->argv->words;
-X	if(a==0){
-X		Xerror1("empty argument list");
-X		return;
-X	}
-X	if(flag['x'])
-X		pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
-X	v = gvlook(a->word);
-X	if(v->fn)
-X		execfunc(v);
-X	else{
-X		if(strcmp(a->word, "builtin")==0){
-X			if(count(a)==1){
-X				pfmt(err, "builtin: empty argument list\n");
-X				setstatus("empty arg list");
-X				poplist();
-X				return;
-X			}
-X			a = a->next;
-X			popword();
-X		}
-X		for(bp = Builtin;bp->name;bp++)
-X			if(strcmp(a->word, bp->name)==0){
-X				(*bp->fnc)();
-X				return;
-X			}
-X		if(exitnext()){
-X			/* fork and wait is redundant */
-X			pushword("exec");
-X			execexec();
-X			Xexit();
-X		}
-X		else{
-X			flush(err);
-X			Updenv();	/* necessary so changes don't go out again */
-X			if((pid = execforkexec()) < 0){
-X				Xerror("try again");
-X				return;
-X			}
-
-X			/* interrupts don't get us out */
-X			poplist();
-X			while(Waitfor(pid, 1) < 0)
-X				;
-X		}
-X	}
-X}
-struct word nullpath = { "", 0};
-
-void
-doredir(redir *rp)
-X{
-X	if(rp){
-X		doredir(rp->next);
-X		switch(rp->type){
-X		case ROPEN:
-X			if(rp->from!=rp->to){
-X				Dup(rp->from, rp->to);
-X				close(rp->from);
-X			}
-X			break;
-X		case RDUP:
-X			Dup(rp->from, rp->to);
-X			break;
-X		case RCLOSE:
-X			close(rp->from);
-X			break;
-X		}
-X	}
-X}
-
-word*
-searchpath(char *w)
-X{
-X	word *path;
-X	if(strncmp(w, "/", 1)==0
-X	|| strncmp(w, "#", 1)==0
-X	|| strncmp(w, "./", 2)==0
-X	|| strncmp(w, "../", 3)==0
-X	|| (path = vlook("path")->val)==0)
-X		path=&nullpath;
-X	return path;
-X}
-
-void
-execexec(void)
-X{
-X	popword();	/* "exec" */
-X	if(runq->argv->words==0){
-X		Xerror1("empty argument list");
-X		return;
-X	}
-X	doredir(runq->redir);
-X	Execute(runq->argv->words, searchpath(runq->argv->words->word));
-X	poplist();
-X}
-
-void
-execfunc(var *func)
-X{
-X	word *starval;
-X	popword();
-X	starval = runq->argv->words;
-X	runq->argv->words = 0;
-X	poplist();
-X	start(func->fn, func->pc, (struct var *)0);
-X	runq->local = newvar(strdup("*"), runq->local);
-X	runq->local->val = starval;
-X	runq->local->changed = 1;
-X}
-
-int
-dochdir(char *word)
-X{
-X	/* report to /dev/wdir if it exists and we're interactive */
-X	static int wdirfd = -2;
-X	if(chdir(word)<0) return -1;
-X	if(flag['i']!=0){
-X		if(wdirfd==-2)	/* try only once */
-X			/* TODO: arrange close-on-exec on Unix */
-X			wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
-X		if(wdirfd>=0)
-X			write(wdirfd, word, strlen(word));
-X	}
-X	return 1;
-X}
-
-void
-execcd(void)
-X{
-X	word *a = runq->argv->words;
-X	word *cdpath;
-X	char dir[512];
-X	setstatus("can't cd");
-X	cdpath = vlook("cdpath")->val;
-X	switch(count(a)){
-X	default:
-X		pfmt(err, "Usage: cd [directory]\n");
-X		break;
-X	case 2:
-X		if(a->next->word[0]=='/' || cdpath==0)
-X			cdpath=&nullpath;
-X		for(;cdpath;cdpath = cdpath->next){
-X			strcpy(dir, cdpath->word);
-X			if(dir[0])
-X				strcat(dir, "/");
-X			strcat(dir, a->next->word);
-X			if(dochdir(dir)>=0){
-X				if(strlen(cdpath->word)
-X				&& strcmp(cdpath->word, ".")!=0)
-X					pfmt(err, "%s\n", dir);
-X				setstatus("");
-X				break;
-X			}
-X		}
-X		if(cdpath==0)
-X			pfmt(err, "Can't cd %s: %r\n", a->next->word);
-X		break;
-X	case 1:
-X		a = vlook("home")->val;
-X		if(count(a)>=1){
-X			if(dochdir(a->word)>=0)
-X				setstatus("");
-X			else
-X				pfmt(err, "Can't cd %s: %r\n", a->word);
-X		}
-X		else
-X			pfmt(err, "Can't cd -- $home empty\n");
-X		break;
-X	}
-X	poplist();
-X}
-
-void
-execexit(void)
-X{
-X	switch(count(runq->argv->words)){
-X	default:
-X		pfmt(err, "Usage: exit [status]\nExiting anyway\n");
-X	case 2:
-X		setstatus(runq->argv->words->next->word);
-X	case 1:	Xexit();
-X	}
-X}
-
-void
-execshift(void)
-X{
-X	int n;
-X	word *a;
-X	var *star;
-X	switch(count(runq->argv->words)){
-X	default:
-X		pfmt(err, "Usage: shift [n]\n");
-X		setstatus("shift usage");
-X		poplist();
-X		return;
-X	case 2:
-X		n = atoi(runq->argv->words->next->word);
-X		break;
-X	case 1:
-X		n = 1;
-X		break;
-X	}
-X	star = vlook("*");
-X	for(;n && star->val;--n){
-X		a = star->val->next;
-X		efree(star->val->word);
-X		efree((char *)star->val);
-X		star->val = a;
-X		star->changed = 1;
-X	}
-X	setstatus("");
-X	poplist();
-X}
-
-int
-octal(char *s)
-X{
-X	int n = 0;
-X	while(*s==' ' || *s=='\t' || *s=='\n') s++;
-X	while('0'<=*s && *s<='7') n = n*8+*s++-'0';
-X	return n;
-X}
-
-int
-mapfd(int fd)
-X{
-X	redir *rp;
-X	for(rp = runq->redir;rp;rp = rp->next){
-X		switch(rp->type){
-X		case RCLOSE:
-X			if(rp->from==fd)
-X				fd=-1;
-X			break;
-X		case RDUP:
-X		case ROPEN:
-X			if(rp->to==fd)
-X				fd = rp->from;
-X			break;
-X		}
-X	}
-X	return fd;
-X}
-union code rdcmds[4];
-
-void
-execcmds(io *f)
-X{
-X	static int first = 1;
-X	if(first){
-X		rdcmds[0].i = 1;
-X		rdcmds[1].f = Xrdcmds;
-X		rdcmds[2].f = Xreturn;
-X		first = 0;
-X	}
-X	start(rdcmds, 1, runq->local);
-X	runq->cmdfd = f;
-X	runq->iflast = 0;
-X}
-
-void
-execeval(void)
-X{
-X	char *cmdline, *s, *t;
-X	int len = 0;
-X	word *ap;
-X	if(count(runq->argv->words)<=1){
-X		Xerror1("Usage: eval cmd ...");
-X		return;
-X	}
-X	eflagok = 1;
-X	for(ap = runq->argv->words->next;ap;ap = ap->next)
-X		len+=1+strlen(ap->word);
-X	cmdline = emalloc(len);
-X	s = cmdline;
-X	for(ap = runq->argv->words->next;ap;ap = ap->next){
-X		for(t = ap->word;*t;) *s++=*t++;
-X		*s++=' ';
-X	}
-X	s[-1]='\n';
-X	poplist();
-X	execcmds(opencore(cmdline, len));
-X	efree(cmdline);
-X}
-union code dotcmds[14];
-
-void
-execdot(void)
-X{
-X	int iflag = 0;
-X	int fd;
-X	list *av;
-X	thread *p = runq;
-X	char *zero;
-X	static int first = 1;
-X	char file[512];
-X	word *path;
-X	if(first){
-X		dotcmds[0].i = 1;
-X		dotcmds[1].f = Xmark;
-X		dotcmds[2].f = Xword;
-X		dotcmds[3].s="0";
-X		dotcmds[4].f = Xlocal;
-X		dotcmds[5].f = Xmark;
-X		dotcmds[6].f = Xword;
-X		dotcmds[7].s="*";
-X		dotcmds[8].f = Xlocal;
-X		dotcmds[9].f = Xrdcmds;
-X		dotcmds[10].f = Xunlocal;
-X		dotcmds[11].f = Xunlocal;
-X		dotcmds[12].f = Xreturn;
-X		first = 0;
-X	}
-X	else
-X		eflagok = 1;
-X	popword();
-X	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
-X		iflag = 1;
-X		popword();
-X	}
-X	/* get input file */
-X	if(p->argv->words==0){
-X		Xerror1("Usage: . [-i] file [arg ...]");
-X		return;
-X	}
-X	zero = strdup(p->argv->words->word);
-X	popword();
-X	fd=-1;
-X	for(path = searchpath(zero);path;path = path->next){
-X		strcpy(file, path->word);
-X		if(file[0])
-X			strcat(file, "/");
-X		strcat(file, zero);
-X		if((fd = open(file, 0))>=0) break;
-X		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */
-X			fd = Dup1(0);
-X			if(fd>=0)
-X				break;
-X		}
-X	}
-X	if(fd<0){
-X		pfmt(err, "%s: ", zero);
-X		setstatus("can't open");
-X		Xerror(".: can't open");
-X		return;
-X	}
-X	/* set up for a new command loop */
-X	start(dotcmds, 1, (struct var *)0);
-X	pushredir(RCLOSE, fd, 0);
-X	runq->cmdfile = zero;
-X	runq->cmdfd = openfd(fd);
-X	runq->iflag = iflag;
-X	runq->iflast = 0;
-X	/* push $* value */
-X	pushlist();
-X	runq->argv->words = p->argv->words;
-X	/* free caller's copy of $* */
-X	av = p->argv;
-X	p->argv = av->next;
-X	efree((char *)av);
-X	/* push $0 value */
-X	pushlist();
-X	pushword(zero);
-X	ndot++;
-X}
-
-void
-execflag(void)
-X{
-X	char *letter, *val;
-X	switch(count(runq->argv->words)){
-X	case 2:
-X		setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
-X		break;
-X	case 3:
-X		letter = runq->argv->words->next->word;
-X		val = runq->argv->words->next->next->word;
-X		if(strlen(letter)==1){
-X			if(strcmp(val, "+")==0){
-X				flag[letter[0]] = flagset;
-X				break;
-X			}
-X			if(strcmp(val, "-")==0){
-X				flag[letter[0]] = 0;
-X				break;
-X			}
-X		}
-X	default:
-X		Xerror1("Usage: flag [letter] [+-]");
-X		return;
-X	}
-X	poplist();
-X}
-
-void
-execwhatis(void){	/* mildly wrong -- should fork before writing */
-X	word *a, *b, *path;
-X	var *v;
-X	struct builtin *bp;
-X	char file[512];
-X	struct io out[1];
-X	int found, sep;
-X	a = runq->argv->words->next;
-X	if(a==0){
-X		Xerror1("Usage: whatis name ...");
-X		return;
-X	}
-X	setstatus("");
-X	out->fd = mapfd(1);
-X	out->bufp = out->buf;
-X	out->ebuf = &out->buf[NBUF];
-X	out->strp = 0;
-X	for(;a;a = a->next){
-X		v = vlook(a->word);
-X		if(v->val){
-X			pfmt(out, "%s=", a->word);
-X			if(v->val->next==0)
-X				pfmt(out, "%q\n", v->val->word);
-X			else{
-X				sep='(';
-X				for(b = v->val;b && b->word;b = b->next){
-X					pfmt(out, "%c%q", sep, b->word);
-X					sep=' ';
-X				}
-X				pfmt(out, ")\n");
-X			}
-X			found = 1;
-X		}
-X		else
-X			found = 0;
-X		v = gvlook(a->word);
-X		if(v->fn)
-X			pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
-X		else{
-X			for(bp = Builtin;bp->name;bp++)
-X				if(strcmp(a->word, bp->name)==0){
-X					pfmt(out, "builtin %s\n", a->word);
-X					break;
-X				}
-X			if(!bp->name){
-X				for(path = searchpath(a->word);path;path = path->next){
-X					strcpy(file, path->word);
-X					if(file[0])
-X						strcat(file, "/");
-X					strcat(file, a->word);
-X					if(Executable(file)){
-X						pfmt(out, "%s\n", file);
-X						break;
-X					}
-X				}
-X				if(!path && !found){
-X					pfmt(err, "%s: not found\n", a->word);
-X					setstatus("not found");
-X				}
-X			}
-X		}
-X	}
-X	poplist();
-X	flush(err);
-X}
-
-void
-execwait(void)
-X{
-X	switch(count(runq->argv->words)){
-X	default:
-X		Xerror1("Usage: wait [pid]");
-X		return;
-X	case 2:
-X		Waitfor(atoi(runq->argv->words->next->word), 0);
-X		break;
-X	case 1:
-X		Waitfor(-1, 0);
-X		break;
-X	}
-X	poplist();
-X}
-!
-echo havefork.c
-sed 's/^X//' >havefork.c <<'!'
-X#include "rc.h"
-X#include "getflags.h"
-X#include "exec.h"
-X#include "io.h"
-X#include "fns.h"
-
-int havefork = 1;
-
-void
-XXasync(void)
-X{
-X	int null = open("/dev/null", 0);
-X	int pid;
-X	char npid[10];
-X	if(null<0){
-X		Xerror("Can't open /dev/null\n");
-X		return;
-X	}
-X#ifdef Unix
-X	pid = fork();
-X#else
-X	pid = rfork(RFFDG|RFPROC|RFNOTEG);
-X#endif
-X	switch(pid){
-X	case -1:
-X		close(null);
-X		Xerror("try again");
-X		break;
-X	case 0:
-X		pushredir(ROPEN, null, 0);
-X		start(runq->code, runq->pc+1, runq->local);
-X		runq->ret = 0;
-X		break;
-X	default:
-X		close(null);
-X		runq->pc = runq->code[runq->pc].i;
-X		inttoascii(npid, pid);
-X		setvar("apid", newword(npid, (word *)0));
-X		break;
-X	}
-X}
-
-void
-XXpipe(void)
-X{
-X	struct thread *p = runq;
-X	int pc = p->pc, forkid;
-X	int lfd = p->code[pc++].i;
-X	int rfd = p->code[pc++].i;
-X	int pfd[2];
-X	if(pipe(pfd)<0){
-X		Xerror("can't get pipe");
-X		return;
-X	}
-X	switch(forkid = fork()){
-X	case -1:
-X		Xerror("try again");
-X		break;
-X	case 0:
-X		start(p->code, pc+2, runq->local);
-X		runq->ret = 0;
-X		close(pfd[PRD]);
-X		pushredir(ROPEN, pfd[PWR], lfd);
-X		break;
-X	default:
-X		start(p->code, p->code[pc].i, runq->local);
-X		close(pfd[PWR]);
-X		pushredir(ROPEN, pfd[PRD], rfd);
-X		p->pc = p->code[pc+1].i;
-X		p->pid = forkid;
-X		break;
-X	}
-X}
-
-X/*
-X * Who should wait for the exit from the fork?
-X */
-void
-XXbackq(void)
-X{
-X	char wd[8193];
-X	int c;
-X	char *s, *ewd=&wd[8192], *stop;
-X	struct io *f;
-X	var *ifs = vlook("ifs");
-X	word *v, *nextv;
-X	int pfd[2];
-X	int pid;
-X	stop = ifs->val?ifs->val->word:"";
-X	if(pipe(pfd)<0){
-X		Xerror("can't make pipe");
-X		return;
-X	}
-X	switch(pid = fork()){
-X	case -1:
-X		Xerror("try again");
-X		close(pfd[PRD]);
-X		close(pfd[PWR]);
-X		return;
-X	case 0:
-X		close(pfd[PRD]);
-X		start(runq->code, runq->pc+1, runq->local);
-X		pushredir(ROPEN, pfd[PWR], 1);
-X		return;
-X	default:
-X		close(pfd[PWR]);
-X		f = openfd(pfd[PRD]);
-X		s = wd;
-X		v = 0;
-X		while((c = rchr(f))!=EOF){
-X			if(strchr(stop, c) || s==ewd){
-X				if(s!=wd){
-X					*s='\0';
-X					v = newword(wd, v);
-X					s = wd;
-X				}
-X			}
-X			else *s++=c;
-X		}
-X		if(s!=wd){
-X			*s='\0';
-X			v = newword(wd, v);
-X		}
-X		closeio(f);
-X		Waitfor(pid, 0);
-X		/* v points to reversed arglist -- reverse it onto argv */
-X		while(v){
-X			nextv = v->next;
-X			v->next = runq->argv->words;
-X			runq->argv->words = v;
-X			v = nextv;
-X		}
-X		runq->pc = runq->code[runq->pc].i;
-X		return;
-X	}
-X}
-
-void
-XXpipefd(void)
-X{
-X	struct thread *p = runq;
-X	int pc = p->pc;
-X	char name[40];
-X	int pfd[2];
-X	int sidefd, mainfd;
-X	if(pipe(pfd)<0){
-X		Xerror("can't get pipe");
-X		return;
-X	}
-X	if(p->code[pc].i==READ){
-X		sidefd = pfd[PWR];
-X		mainfd = pfd[PRD];
-X	}
-X	else{
-X		sidefd = pfd[PRD];
-X		mainfd = pfd[PWR];
-X	}
-X	switch(fork()){
-X	case -1:
-X		Xerror("try again");
-X		break;
-X	case 0:
-X		start(p->code, pc+2, runq->local);
-X		close(mainfd);
-X		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
-X		runq->ret = 0;
-X		break;
-X	default:
-X		close(sidefd);
-X		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
-X		strcpy(name, Fdprefix);
-X		inttoascii(name+strlen(name), mainfd);
-X		pushword(name);
-X		p->pc = p->code[pc+1].i;
-X		break;
-X	}
-X}
-
-void
-XXsubshell(void)
-X{
-X	int pid;
-X	switch(pid = fork()){
-X	case -1:
-X		Xerror("try again");
-X		break;
-X	case 0:
-X		start(runq->code, runq->pc+1, runq->local);
-X		runq->ret = 0;
-X		break;
-X	default:
-X		Waitfor(pid, 1);
-X		runq->pc = runq->code[runq->pc].i;
-X		break;
-X	}
-X}
-
-int
-execforkexec(void)
-X{
-X	int pid;
-X	int n;
-X	char buf[ERRMAX];
-
-X	switch(pid = fork()){
-X	case -1:
-X		return -1;
-X	case 0:
-X		pushword("exec");
-X		execexec();
-X		strcpy(buf, "can't exec: ");
-X		n = strlen(buf);
-X		errstr(buf+n, ERRMAX-n);
-X		Exit(buf);
-X	}
-X	return pid;
-X}
-!
-echo rc.h
-sed 's/^X//' >rc.h <<'!'
-X/*
-X * Plan9 is defined for plan 9
-X * V9 is defined for 9th edition
-X * Sun is defined for sun-os
-X * Please don't litter the code with ifdefs.  The three below should be enough.
-X */
-X#define Unix
-
-X#ifdef	Plan9
-X#include <u.h>
-X#include <libc.h>
-X#define	NSIG	32
-X#define	SIGINT	2
-X#define	SIGQUIT	3
-X#endif
-
-X#ifdef Unix
-X#define _POSIX_SOURCE
-X#define _BSD_EXTENSION
-
-X#include <stdlib.h>
-X#include <stdarg.h>
-X#include <string.h>
-X#include <unistd.h>
-X#include <fcntl.h>
-X#include <lib9.h>
-X#include <signal.h>
-X#endif
-
-X#ifndef ERRMAX
-X#define ERRMAX 128
-X#endif
-
-X#define	YYMAXDEPTH	500
-X#ifndef PAREN
-X#include "x.tab.h"
-X#endif
-typedef struct tree tree;
-typedef struct word word;
-typedef struct io io;
-typedef union code code;
-typedef struct var var;
-typedef struct list list;
-typedef struct redir redir;
-typedef struct thread thread;
-typedef struct builtin builtin;
-
-struct tree{
-X	int type;
-X	int rtype, fd0, fd1;		/* details of REDIR PIPE DUP tokens */
-X	char *str;
-X	int quoted;
-X	int iskw;
-X	tree *child[3];
-X	tree *next;
-X};
-tree *newtree(void);
-tree *token(char*, int), *klook(char*), *tree1(int, tree*);
-tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
-tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
-tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
-tree *simplemung(tree*), *heredoc(tree*);
-void freetree(tree*);
-tree *cmdtree;
-X/*
-X * The first word of any code vector is a reference count.
-X * Always create a new reference to a code vector by calling codecopy(.).
-X * Always call codefree(.) when deleting a reference.
-X */
-union code{
-X	void (*f)(void);
-X	int i;
-X	char *s;
-X};
-char *promptstr;
-int doprompt;
-X#define	NTOK	8192
-char tok[NTOK];
-X#define	APPEND	1
-X#define	WRITE	2
-X#define	READ	3
-X#define	HERE	4
-X#define	DUPFD	5
-X#define	CLOSE	6
-struct var{
-X	char *name;		/* ascii name */
-X	word *val;	/* value */
-X	int changed;
-X	code *fn;		/* pointer to function's code vector */
-X	int fnchanged;
-X	int pc;			/* pc of start of function */
-X	var *next;	/* next on hash or local list */
-X};
-var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
-X#define	NVAR	521
-var *gvar[NVAR];				/* hash for globals */
-X#define	new(type)	((type *)emalloc(sizeof(type)))
-char *emalloc(long);
-void *Malloc(ulong);
-void efree(char*);
-X#define	NOFILE	128		/* should come from <param.h> */
-struct here{
-X	tree *tag;
-X	char *name;
-X	struct here *next;
-X};
-int mypid;
-X/*
-X * Glob character escape in strings:
-X *	In a string, GLOB must be followed by *?[ or GLOB.
-X *	GLOB* matches any string
-X *	GLOB? matches any single character
-X *	GLOB[...] matches anything in the brackets
-X *	GLOBGLOB matches GLOB
-X */
-X#define	GLOB	((char)0x01)
-X/*
-X * onebyte(c), twobyte(c), threebyte(c)
-X * Is c the first character of a one- two- or three-byte utf sequence?
-X */
-X#define	onebyte(c)	((c&0x80)==0x00)
-X#define	twobyte(c)	((c&0xe0)==0xc0)
-X#define	threebyte(c)	((c&0xf0)==0xe0)
-char **argp;
-char **args;
-int nerror;		/* number of errors encountered during compilation */
-int doprompt;		/* is it time for a prompt? */
-X/*
-X * Which fds are the reading/writing end of a pipe?
-X * Unfortunately, this can vary from system to system.
-X * 9th edition Unix doesn't care, the following defines
-X * work on plan 9.
-X */
-X#define	PRD	0
-X#define	PWR	1
-char Rcmain[], Fdprefix[];
-X#define	register
-X/*
-X * How many dot commands have we executed?
-X * Used to ensure that -v flag doesn't print rcmain.
-X */
-int ndot;
-char *getstatus(void);
-int lastc;
-int lastword;
-!
-echo unix.c
-sed 's/^X//' >unix.c <<'!'
-X/*
-X * Unix versions of system-specific functions
-X *	By convention, exported routines herein have names beginning with an
-X *	upper case letter.
-X */
-X#include "rc.h"
-X#include "io.h"
-X#include "exec.h"
-X#include "getflags.h"
-X#include <errno.h>
-
-char Rcmain[]="/usr/lib/rcmain";
-char Fdprefix[]="/dev/fd/";
-
-void execfinit(void);
-
-struct builtin Builtin[] = {
-X	"cd",		execcd,
-X	"whatis",	execwhatis,
-X	"eval",		execeval,
-X	"exec",		execexec,	/* but with popword first */
-X	"exit",		execexit,
-X	"shift",	execshift,
-X	"wait",		execwait,
-X	"umask",	execumask,
-X	".",		execdot,
-X	"finit",	execfinit,
-X	"flag",		execflag,
-X	0
-X};
-X#define	SEP	'\1'
-char **environp;
-
-struct word*
-enval(s)
-register char *s;
-X{
-X	char *t, c;
-X	struct word *v;
-X	for(t = s;*t && *t!=SEP;t++);
-X	c=*t;
-X	*t='\0';
-X	v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
-X	*t = c;
-X	return v;
-X}
-
-void
-Vinit(void)
-X{
-X	extern char **environ;
-X	char *s;
-X	char **env = environ;
-X	environp = env;
-X	for(;*env;env++){
-X		for(s=*env;*s && *s!='(' && *s!='=';s++);
-X		switch(*s){
-X		case '\0':
-X			pfmt(err, "environment %q?\n", *env);
-X			break;
-X		case '=':
-X			*s='\0';
-X			setvar(*env, enval(s+1));
-X			*s='=';
-X			break;
-X		case '(':	/* ignore functions for now */
-X			break;
-X		}
-X	}
-X}
-
-char **envp;
-
-void
-XXrdfn(void)
-X{
-X	char *s;
-X	int len;
-X	for(;*envp;envp++){
-X		for(s=*envp;*s && *s!='(' && *s!='=';s++);
-X		switch(*s){
-X		case '\0':
-X			pfmt(err, "environment %q?\n", *envp);
-X			break;
-X		case '=':	/* ignore variables */
-X			break;
-X		case '(':		/* Bourne again */
-X			s=*envp+3;
-X			envp++;
-X			len = strlen(s);
-X			s[len]='\n';
-X			execcmds(opencore(s, len+1));
-X			s[len]='\0';
-X			return;
-X		}
-X	}
-X	Xreturn();
-X}
-
-union code rdfns[4];
-
-void
-execfinit(void)
-X{
-X	static int first = 1;
-X	if(first){
-X		rdfns[0].i = 1;
-X		rdfns[1].f = Xrdfn;
-X		rdfns[2].f = Xjump;
-X		rdfns[3].i = 1;
-X		first = 0;
-X	}
-X	Xpopm();
-X	envp = environp;
-X	start(rdfns, 1, runq->local);
-X}
-
-int
-cmpenv(const void *aa, const void *ab)
-X{
-X	char **a = aa, **b = ab;
-
-X	return strcmp(*a, *b);
-X}
-
-char **
-mkenv(void)
-X{
-X	char **env, **ep, *p, *q;
-X	struct var **h, *v;
-X	struct word *a;
-X	int nvar = 0, nchr = 0, sep;
-
-X	/*
-X	 * Slightly kludgy loops look at locals then globals.
-X	 * locals no longer exist - geoff
-X	 */
-X	for(h = gvar-1; h != &gvar[NVAR]; h++)
-X	for(v = h >= gvar? *h: runq->local; v ;v = v->next){
-X		if((v==vlook(v->name)) && v->val){
-X			nvar++;
-X			nchr+=strlen(v->name)+1;
-X			for(a = v->val;a;a = a->next)
-X				nchr+=strlen(a->word)+1;
-X		}
-X		if(v->fn){
-X			nvar++;
-X			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
-X		}
-X	}
-X	env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
-X	ep = env;
-X	p = (char *)&env[nvar+1];
-X	for(h = gvar-1; h != &gvar[NVAR]; h++)
-X	for(v = h >= gvar? *h: runq->local;v;v = v->next){
-X		if((v==vlook(v->name)) && v->val){
-X			*ep++=p;
-X			q = v->name;
-X			while(*q) *p++=*q++;
-X			sep='=';
-X			for(a = v->val;a;a = a->next){
-X				*p++=sep;
-X				sep = SEP;
-X				q = a->word;
-X				while(*q) *p++=*q++;
-X			}
-X			*p++='\0';
-X		}
-X		if(v->fn){
-X			*ep++=p;
-X			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
-X			*p++='f'; *p++='n'; *p++=' ';
-X			q = v->name;
-X			while(*q) *p++=*q++;
-X			*p++=' ';
-X			q = v->fn[v->pc-1].s;
-X			while(*q) *p++=*q++;
-X			*p++='\0';
-X		}
-X	}
-X	*ep = 0;
-X	qsort((void *)env, nvar, sizeof ep[0], cmpenv);
-X	return env;	
-X}
-char *sigmsg[] = {
-X/*  0 normal  */ 0,
-X/*  1 SIGHUP  */ "Hangup",
-X/*  2 SIGINT  */ 0,
-X/*  3 SIGQUIT */ "Quit",
-X/*  4 SIGILL  */ "Illegal instruction",
-X/*  5 SIGTRAP */ "Trace/BPT trap",
-X/*  6 SIGIOT  */ "abort",
-X/*  7 SIGEMT  */ "EMT trap",
-X/*  8 SIGFPE  */ "Floating exception",
-X/*  9 SIGKILL */ "Killed",
-X/* 10 SIGBUS  */ "Bus error",
-X/* 11 SIGSEGV */ "Memory fault",
-X/* 12 SIGSYS  */ "Bad system call",
-X/* 13 SIGPIPE */ 0,
-X/* 14 SIGALRM */ "Alarm call",
-X/* 15 SIGTERM */ "Terminated",
-X/* 16 unused  */ "signal 16",
-X/* 17 SIGSTOP */ "Process stopped",
-X/* 18 unused  */ "signal 18",
-X/* 19 SIGCONT */ "Process continued",
-X/* 20 SIGCHLD */ "Child death",
-X};
-
-void
-Waitfor(int pid, int persist)
-X{
-X	int wpid, sig;
-X	struct thread *p;
-X	int wstat;
-X	char wstatstr[12];
-
-X	for(;;){
-X		errno = 0;
-X		wpid = wait(&wstat);
-X		if(errno==EINTR && persist)
-X			continue;
-X		if(wpid==-1)
-X			break;
-X		sig = wstat&0177;
-X		if(sig==0177){
-X			pfmt(err, "trace: ");
-X			sig = (wstat>>8)&0177;
-X		}
-X		if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
-X			if(pid!=wpid)
-X				pfmt(err, "%d: ", wpid);
-X			if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
-X				pfmt(err, "%s", sigmsg[sig]);
-X			else if(sig==0177) pfmt(err, "stopped by ptrace");
-X			else pfmt(err, "signal %d", sig);
-X			if(wstat&0200)pfmt(err, " -- core dumped");
-X			pfmt(err, "\n");
-X		}
-X		wstat = sig?sig+1000:(wstat>>8)&0xFF;
-X		if(wpid==pid){
-X			inttoascii(wstatstr, wstat);
-X			setstatus(wstatstr);
-X			break;
-X		}
-X		else{
-X			for(p = runq->ret;p;p = p->ret)
-X				if(p->pid==wpid){
-X					p->pid=-1;
-X					inttoascii(p->status, wstat);
-X					break;
-X				}
-X		}
-X	}
-X}
-
-char **
-mkargv(a)
-register struct word *a;
-X{
-X	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
-X	char **argp = argv+1;	/* leave one at front for runcoms */
-
-X	for(;a;a = a->next)
-X		*argp++=a->word;
-X	*argp = 0;
-X	return argv;
-X}
-
-void
-Updenv(void)
-X{
-X}
-
-void
-Execute(struct word *args, struct word *path)
-X{
-X	char *msg="not found";
-X#ifdef ETXTBSY
-X	int txtbusy = 0;
-X#endif
-X	char **env = mkenv();
-X	char **argv = mkargv(args);
-X	char file[512];
-
-X	for(;path;path = path->next){
-X		strcpy(file, path->word);
-X		if(file[0])
-X			strcat(file, "/");
-X		strcat(file, argv[1]);
-X#ifdef ETXTBSY
-ReExec:
-X#endif
-X		execve(file, argv+1, env);
-X		switch(errno){
-X		case ENOEXEC:
-X			pfmt(err, "%s: Bourne again\n", argv[1]);
-X			argv[0]="sh";
-X			argv[1] = strdup(file);
-X			execve("/bin/sh", argv, env);
-X			goto Bad;
-X#ifdef ETXTBSY
-X		case ETXTBSY:
-X			if(++txtbusy!=5){
-X				sleep(txtbusy);
-X				goto ReExec;
-X			}
-X			msg="text busy"; goto Bad;
-X#endif
-X		case EACCES:
-X			msg="no access";
-X			break;
-X		case ENOMEM:
-X			msg="not enough memory"; goto Bad;
-X		case E2BIG:
-X			msg="too big"; goto Bad;
-X		}
-X	}
-Bad:
-X	pfmt(err, "%s: %s\n", argv[1], msg);
-X	efree((char *)env);
-X	efree((char *)argv);
-X}
-
-X#define	NDIR	14		/* should get this from param.h */
-
-Globsize(p)
-register char *p;
-X{
-X	int isglob = 0, globlen = NDIR+1;
-X	for(;*p;p++){
-X		if(*p==GLOB){
-X			p++;
-X			if(*p!=GLOB)
-X				isglob++;
-X			globlen+=*p=='*'?NDIR:1;
-X		}
-X		else
-X			globlen++;
-X	}
-X	return isglob?globlen:0;
-X}
-
-X#include <sys/types.h>
-X#include <dirent.h>
-
-X#define	NDIRLIST	50
-
-DIR *dirlist[NDIRLIST];
-
-Opendir(name)
-char *name;
-X{
-X	DIR **dp;
-X	for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
-X		if(*dp==0){
-X			*dp = opendir(name);
-X			return *dp?dp-dirlist:-1;
-X		}
-X	return -1;
-X}
-
-int
-Readdir(int f, char *p, int /* onlydirs */ )
-X{
-X	struct dirent *dp = readdir(dirlist[f]);
-
-X	if(dp==0)
-X		return 0;
-X	strcpy(p, dp->d_name);
-X	return 1;
-X}
-
-void
-Closedir(int f)
-X{
-X	closedir(dirlist[f]);
-X	dirlist[f] = 0;
-X}
-
-char *Signame[] = {
-X	"sigexit",	"sighup",	"sigint",	"sigquit",
-X	"sigill",	"sigtrap",	"sigiot",	"sigemt",
-X	"sigfpe",	"sigkill",	"sigbus",	"sigsegv",
-X	"sigsys",	"sigpipe",	"sigalrm",	"sigterm",
-X	"sig16",	"sigstop",	"sigtstp",	"sigcont",
-X	"sigchld",	"sigttin",	"sigttou",	"sigtint",
-X	"sigxcpu",	"sigxfsz",	"sig26",	"sig27",
-X	"sig28",	"sig29",	"sig30",	"sig31",
-X	0,
-X};
-
-void
-gettrap(int sig)
-X{
-X	signal(sig, gettrap);
-X	trap[sig]++;
-X	ntrap++;
-X	if(ntrap>=NSIG){
-X		pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
-X		signal(SIGABRT, (void (*)())0);
-X		kill(getpid(), SIGABRT);
-X	}
-X}
-
-void
-Trapinit(void)
-X{
-X	int i;
-X	void (*sig)();
-
-X	if(1 || flag['d']){	/* wrong!!! */
-X		sig = signal(SIGINT, gettrap);
-X		if(sig==SIG_IGN)
-X			signal(SIGINT, SIG_IGN);
-X	}
-X	else{
-X		for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
-X			sig = signal(i, gettrap);
-X			if(sig==SIG_IGN)
-X				signal(i, SIG_IGN);
-X		}
-X	}
-X}
-
-Unlink(name)
-char *name;
-X{
-X	return unlink(name);
-X}
-Write(fd, buf, cnt)
-char *buf;
-X{
-X	return write(fd, buf, cnt);
-X}
-Read(fd, buf, cnt)
-char *buf;
-X{
-X	return read(fd, buf, cnt);
-X}
-Seek(fd, cnt, whence)
-long cnt;
-X{
-X	return lseek(fd, cnt, whence);
-X}
-Executable(file)
-char *file;
-X{
-X	return(access(file, 01)==0);
-X}
-Creat(file)
-char *file;
-X{
-X	return creat(file, 0666);
-X}
-Dup(a, b){
-X	return dup2(a, b);
-X}
-Dup1(a){
-X	return dup(a);
-X}
-X/*
-X * Wrong:  should go through components of a|b|c and return the maximum.
-X */
-void
-Exit(char *stat)
-X{
-X	int n = 0;
-
-X	while(*stat){
-X		if(*stat!='|'){
-X			if(*stat<'0' || '9'<*stat)
-X				exit(1);
-X			else n = n*10+*stat-'0';
-X		}
-X		stat++;
-X	}
-X	exit(n);
-X}
-Eintr(){
-X	return errno==EINTR;
-X}
-
-void
-Noerror()
-X{
-X	errno = 0;
-X}
-Isatty(fd){
-X	return isatty(fd);
-X}
-
-void
-Abort()
-X{
-X	abort();
-X}
-
-void
-execumask(void)		/* wrong -- should fork before writing */
-X{
-X	int m;
-X	struct io out[1];
-X	switch(count(runq->argv->words)){
-X	default:
-X		pfmt(err, "Usage: umask [umask]\n");
-X		setstatus("umask usage");
-X		poplist();
-X		return;
-X	case 2:
-X		umask(octal(runq->argv->words->next->word));
-X		break;
-X	case 1: 
-X		umask(m = umask(0));
-X		out->fd = mapfd(1);
-X		out->bufp = out->buf;
-X		out->ebuf=&out->buf[NBUF];
-X		out->strp = 0;
-X		pfmt(out, "%o\n", m);
-X		break;
-X	}
-X	setstatus("");
-X	poplist();
-X}
-
-void
-Memcpy(a, b, n)
-char *a, *b;
-X{
-X	memmove(a, b, n);
-X}
-
-void*
-Malloc(unsigned long n)
-X{
-X	return (void *)malloc(n);
-X}
-
-void
-errstr(char *buf, int len)
-X{
-X	strncpy(buf, strerror(errno), len);
-X}
-!
-
-From geoff@collyer.net Fri Dec 19 01:23:26 EST 2003
-Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:23:25 EST 2003
-Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:23:22 EST 2003
-Message-ID: <0b5ea130198a21a49139759d00d69939@collyer.net>
-subject: rc on unix, part 2
-From: Geoff Collyer <geoff@collyer.net>
-Date: Thu, 18 Dec 2003 22:23:21 -0800
-To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
-MIME-Version: 1.0
-Content-Type: text/plain; charset="US-ASCII"
-Content-Transfer-Encoding: 7bit
-
-These are the include files I used to emulate plan 9's include
-files on Unix (APE).
-
-
-# To unbundle, run this file
-mkdir include
-echo include/bio.h
-sed 's/^X//' >include/bio.h <<'!'
-X#ifndef _BIOH_
-X#define _BIOH_ 1
-
-X#include <sys/types.h>	/* for off_t */
-X#include <fcntl.h>	/* for O_RDONLY, O_WRONLY */
-
-typedef	struct	Biobuf	Biobuf;
-
-enum
-X{
-X	Bsize		= 8*1024,
-X	Bungetsize	= 4,		/* space for ungetc */
-X	Bmagic		= 0x314159,
-X	Beof		= -1,
-X	Bbad		= -2,
-
-X	Binactive	= 0,		/* states */
-X	Bractive,
-X	Bwactive,
-X	Bracteof,
-
-X	Bend
-X};
-
-struct	Biobuf
-X{
-X	int	icount;		/* neg num of bytes at eob */
-X	int	ocount;		/* num of bytes at bob */
-X	int	rdline;		/* num of bytes after rdline */
-X	int	runesize;		/* num of bytes of last getrune */
-X	int	state;		/* r/w/inactive */
-X	int	fid;		/* open file */
-X	int	flag;		/* magic if malloc'ed */
-X	off_t	offset;		/* offset of buffer in file */
-X	int	bsize;		/* size of buffer */
-X	unsigned char*	bbuf;		/* pointer to beginning of buffer */
-X	unsigned char*	ebuf;		/* pointer to end of buffer */
-X	unsigned char*	gbuf;		/* pointer to good data in buf */
-X	unsigned char	b[Bungetsize+Bsize];
-X};
-
-X#define	BGETC(bp)\
-X	((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
-X#define	BPUTC(bp,c)\
-X	((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
-X#define	BOFFSET(bp)\
-X	(((bp)->state==Bractive)?\
-X		(bp)->offset + (bp)->icount:\
-X	(((bp)->state==Bwactive)?\
-X		(bp)->offset + ((bp)->bsize + (bp)->ocount):\
-X		-1))
-X#define	BLINELEN(bp)\
-X	(bp)->rdline
-X#define	BFILDES(bp)\
-X	(bp)->fid
-
-int	Bbuffered(Biobuf*);
-int	Bfildes(Biobuf*);
-int	Bflush(Biobuf*);
-int	Bgetc(Biobuf*);
-int	Bgetd(Biobuf*, double*);
-int	Binit(Biobuf*, int, int);
-int	Binits(Biobuf*, int, int, unsigned char*, int);
-int	Blinelen(Biobuf*);
-off_t	Boffset(Biobuf*);
-Biobuf*	Bopen(char*, int);
-int	Bprint(Biobuf*, char*, ...);
-int	Bputc(Biobuf*, int);
-void*	Brdline(Biobuf*, int);
-long	Bread(Biobuf*, void*, long);
-off_t	Bseek(Biobuf*, off_t, int);
-int	Bterm(Biobuf*);
-int	Bungetc(Biobuf*);
-long	Bwrite(Biobuf*, void*, long);
-
-long	Bgetrune(Biobuf*);
-int	Bputrune(Biobuf*, long);
-int	Bungetrune(Biobuf*);
-
-X#endif
-!
-echo include/fmt.h
-sed 's/^X//' >include/fmt.h <<'!'
-
-X/*
-X * The authors of this software are Rob Pike and Ken Thompson.
-X *              Copyright (c) 2002 by Lucent Technologies.
-X * Permission to use, copy, modify, and distribute this software for any
-X * purpose without fee is hereby granted, provided that this entire notice
-X * is included in all copies of any software which is or includes a copy
-X * or modification of this software and in all copies of the supporting
-X * documentation for such software.
-X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
-X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
-X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
-X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-X */
-
-X#ifndef _FMTH_
-X#define _FMTH_ 1
-
-X#include <stdarg.h>
-
-X#ifndef _UTFH_
-X#include <utf.h>
-X#endif
-
-typedef struct Fmt	Fmt;
-struct Fmt{
-X	unsigned char	runes;		/* output buffer is runes or chars? */
-X	void	*start;			/* of buffer */
-X	void	*to;			/* current place in the buffer */
-X	void	*stop;			/* end of the buffer; overwritten if flush fails */
-X	int	(*flush)(Fmt *);	/* called when to == stop */
-X	void	*farg;			/* to make flush a closure */
-X	int	nfmt;			/* num chars formatted so far */
-X	va_list	args;			/* args passed to dofmt */
-X	int	r;			/* % format Rune */
-X	int	width;
-X	int	prec;
-X	unsigned long	flags;
-X};
-
-enum{
-X	FmtWidth	= 1,
-X	FmtLeft		= FmtWidth << 1,
-X	FmtPrec		= FmtLeft << 1,
-X	FmtSharp	= FmtPrec << 1,
-X	FmtSpace	= FmtSharp << 1,
-X	FmtSign		= FmtSpace << 1,
-X	FmtZero		= FmtSign << 1,
-X	FmtUnsigned	= FmtZero << 1,
-X	FmtShort	= FmtUnsigned << 1,
-X	FmtLong		= FmtShort << 1,
-X	FmtVLong	= FmtLong << 1,
-X	FmtComma	= FmtVLong << 1,
-X	FmtByte		= FmtComma << 1,
-X	FmtLDouble	= FmtByte << 1,
-
-X	FmtFlag		= FmtLDouble << 1
-X};
-
-extern	int	print(char*, ...);
-extern	char*	seprint(char*, char*, char*, ...);
-extern	char*	vseprint(char*, char*, char*, va_list);
-extern	int	snprint(char*, int, char*, ...);
-extern	int	vsnprint(char*, int, char*, va_list);
-extern	char*	smprint(char*, ...);
-extern	char*	vsmprint(char*, va_list);
-extern	int	sprint(char*, char*, ...);
-extern	int	fprint(int, char*, ...);
-extern	int	vfprint(int, char*, va_list);
-
-extern	int	runesprint(Rune*, char*, ...);
-extern	int	runesnprint(Rune*, int, char*, ...);
-extern	int	runevsnprint(Rune*, int, char*, va_list);
-extern	Rune*	runeseprint(Rune*, Rune*, char*, ...);
-extern	Rune*	runevseprint(Rune*, Rune*, char*, va_list);
-extern	Rune*	runesmprint(char*, ...);
-extern	Rune*	runevsmprint(char*, va_list);
-
-extern	int	fmtfdinit(Fmt*, int, char*, int);
-extern	int	fmtfdflush(Fmt*);
-extern	int	fmtstrinit(Fmt*);
-extern	char*	fmtstrflush(Fmt*);
-
-extern	int	quotestrfmt(Fmt *f);
-extern	void	quotefmtinstall(void);
-extern	int	(*fmtdoquote)(int);
-
-
-extern	int	fmtinstall(int, int (*)(Fmt*));
-extern	int	dofmt(Fmt*, char*);
-extern	int	fmtprint(Fmt*, char*, ...);
-extern	int	fmtvprint(Fmt*, char*, va_list);
-extern	int	fmtrune(Fmt*, int);
-extern	int	fmtstrcpy(Fmt*, char*);
-
-extern	double	fmtstrtod(const char *, char **);
-extern	double	fmtcharstod(int(*)(void*), void*);
-
-X#endif
-!
-echo include/lib9.h
-sed 's/^X//' >include/lib9.h <<'!'
-X#include <string.h>
-X#include "utf.h"
-
-X#define nil ((void*)0)
-
-X#define uchar _fmtuchar
-X#define ushort _fmtushort
-X#define uint _fmtuint
-X#define ulong _fmtulong
-X#define vlong _fmtvlong
-X#define uvlong _fmtuvlong
-
-typedef unsigned char		uchar;
-typedef unsigned short		ushort;
-typedef unsigned int		uint;
-typedef unsigned long		ulong;
-
-X#define OREAD O_RDONLY
-X#define OWRITE O_WRONLY
-X#define ORDWR O_RDWR
-X#define OCEXEC 0
-!
-echo include/regexp9.h
-sed 's/^X//' >include/regexp9.h <<'!'
-X#ifndef _REGEXP9H_
-
-X#define _REGEXP9H_ 1
-X#include <utf.h>
-
-typedef struct Resub		Resub;
-typedef struct Reclass		Reclass;
-typedef struct Reinst		Reinst;
-typedef struct Reprog		Reprog;
-
-X/*
-X *	Sub expression matches
-X */
-struct Resub{
-X	union
-X	{
-X		char *sp;
-X		Rune *rsp;
-X	}s;
-X	union
-X	{
-X		char *ep;
-X		Rune *rep;
-X	}e;
-X};
-
-X/*
-X *	character class, each pair of rune's defines a range
-X */
-struct Reclass{
-X	Rune	*end;
-X	Rune	spans[64];
-X};
-
-X/*
-X *	Machine instructions
-X */
-struct Reinst{
-X	int	type;
-X	union	{
-X		Reclass	*cp;		/* class pointer */
-X		Rune	r;		/* character */
-X		int	subid;		/* sub-expression id for RBRA and LBRA */
-X		Reinst	*right;		/* right child of OR */
-X	}u1;
-X	union {	/* regexp relies on these two being in the same union */
-X		Reinst *left;		/* left child of OR */
-X		Reinst *next;		/* next instruction for CAT & LBRA */
-X	}u2;
-X};
-
-X/*
-X *	Reprogram definition
-X */
-struct Reprog{
-X	Reinst	*startinst;	/* start pc */
-X	Reclass	class[16];	/* .data */
-X	Reinst	firstinst[5];	/* .text */
-X};
-
-extern Reprog	*regcomp(char*);
-extern Reprog	*regcomplit(char*);
-extern Reprog	*regcompnl(char*);
-extern void	regerror(char*);
-extern int	regexec(Reprog*, char*, Resub*, int);
-extern void	regsub(char*, char*, int, Resub*, int);
-
-extern int	rregexec(Reprog*, Rune*, Resub*, int);
-extern void	rregsub(Rune*, Rune*, Resub*, int);
-
-X#endif
-!
-echo include/utf.h
-sed 's/^X//' >include/utf.h <<'!'
-X#ifndef _UTFH_
-X#define _UTFH_ 1
-
-typedef unsigned short Rune;	/* 16 bits */
-
-enum
-X{
-X	UTFmax		= 3,		/* maximum bytes per rune */
-X	Runesync	= 0x80,		/* cannot represent part of a UTF sequence (<) */
-X	Runeself	= 0x80,		/* rune and UTF sequences are the same (<) */
-X	Runeerror	= 0x80,		/* decoding error in UTF */
-X};
-
-X/*
-X * rune routines
-X */
-extern	int	runetochar(char*, Rune*);
-extern	int	chartorune(Rune*, char*);
-extern	int	runelen(long);
-extern	int	runenlen(Rune*, int);
-extern	int	fullrune(char*, int);
-extern	int	utflen(char*);
-extern	int	utfnlen(char*, long);
-extern	char*	utfrune(char*, long);
-extern	char*	utfrrune(char*, long);
-extern	char*	utfutf(char*, char*);
-extern	char*	utfecpy(char*, char*, char*);
-
-extern	Rune*	runestrcat(Rune*, Rune*);
-extern	Rune*	runestrchr(Rune*, Rune);
-extern	int	runestrcmp(Rune*, Rune*);
-extern	Rune*	runestrcpy(Rune*, Rune*);
-extern	Rune*	runestrncpy(Rune*, Rune*, long);
-extern	Rune*	runestrecpy(Rune*, Rune*, Rune*);
-extern	Rune*	runestrdup(Rune*);
-extern	Rune*	runestrncat(Rune*, Rune*, long);
-extern	int	runestrncmp(Rune*, Rune*, long);
-extern	Rune*	runestrrchr(Rune*, Rune);
-extern	long	runestrlen(Rune*);
-extern	Rune*	runestrstr(Rune*, Rune*);
-
-extern	Rune	tolowerrune(Rune);
-extern	Rune	totitlerune(Rune);
-extern	Rune	toupperrune(Rune);
-extern	int	isalpharune(Rune);
-extern	int	islowerrune(Rune);
-extern	int	isspacerune(Rune);
-extern	int	istitlerune(Rune);
-extern	int	isupperrune(Rune);
-
-X#endif
-!
-
--- a/sys/src/cmd/rc/exec.h
+++ b/sys/src/cmd/rc/exec.h
@@ -68,7 +68,6 @@
 };
 extern struct builtin Builtin[];
 int eflagok;			/* kludge flag so that -e doesn't exit in startup */
-int havefork;
 
 void execcd(void), execwhatis(void), execeval(void), execexec(void);
 int execforkexec(void);
--- a/sys/src/cmd/rc/havefork.c
+++ b/sys/src/cmd/rc/havefork.c
@@ -4,8 +4,6 @@
 #include "io.h"
 #include "fns.h"
 
-int havefork = 1;
-
 void
 Xasync(void)
 {
--- a/sys/src/cmd/rc/haventfork.c
+++ /dev/null
@@ -1,217 +1,0 @@
-#include "rc.h"
-#include "getflags.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-
-int havefork = 0;
-
-static char **
-rcargv(char *s)
-{
-	int argc;
-	char **argv;
-	word *p;
-
-	p = vlook("*")->val;
-	argv = emalloc((count(p)+6)*sizeof(char*));
-	argc = 0;
-	argv[argc++] = argv0;
-	if(flag['e'])
-		argv[argc++] = "-Se";
-	else
-		argv[argc++] = "-S";
-	argv[argc++] = "-c";
-	argv[argc++] = s;
-	for(p = vlook("*")->val; p; p = p->next)
-		argv[argc++] = p->word;
-	argv[argc] = 0;
-	return argv;
-}
-
-void
-Xasync(void)
-{
-	uint pid;
-	char buf[20], **argv;
-
-	Updenv();
-
-	argv = rcargv(runq->code[runq->pc].s);
-	pid = ForkExecute(argv0, argv, -1, 1, 2);
-	free(argv);
-
-	if(pid == 0) {
-		Xerror("proc failed");
-		return;
-	}
-
-	runq->pc++;
-	sprint(buf, "%d", pid);
-	setvar("apid", newword(buf, (word *)0));
-}
-
-enum { Stralloc = 100, };
-
-void
-Xbackq(void)
-{
-	char **argv;
-	int c, l;
-	char *s, *wd, *ewd, *stop;
-	struct io *f;
-	var *ifs = vlook("ifs");
-	word *v, *nextv;
-	int pfd[2];
-	int pid;
-
-	stop = ifs->val?ifs->val->word:"";
-	if(pipe(pfd)<0){
-		Xerror("can't make pipe");
-		return;
-	}
-
-	Updenv();
-
-	argv = rcargv(runq->code[runq->pc].s);
-	pid = ForkExecute(argv0, argv, -1, pfd[1], 2);
-	free(argv);
-
-	close(pfd[1]);
-
-	if(pid == 0) {
-		Xerror("proc failed");
-		close(pfd[0]);
-		return;
-	}
-
-	f = openfd(pfd[0]);
-		s = wd = ewd = 0;
-	v = 0;
-	while((c=rchr(f))!=EOF){
-		if(s==ewd){
-			l = s-wd;
-			wd = erealloc(wd, l+Stralloc);
-			ewd = wd+l+Stralloc-1;
-			s = wd+l;
-		}
-		if(strchr(stop, c)){
-			if(s!=wd){
-				*s='\0';
-				v = newword(wd, v);
-				s = wd;
-			}
-		}
-		else *s++=c;
-	}
-	if(s!=wd){
-		*s='\0';
-		v=newword(wd, v);
-	}
-	free(wd);
-	closeio(f);
-	Waitfor(pid, 1);
-	/* 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;
-	}
-	runq->pc++;
-}
-
-void
-Xpipe(void)
-{
-	thread *p=runq;
-	int pc=p->pc, pid;
-	int rfd=p->code[pc+1].i;
-	int pfd[2];
-	char **argv;
-
-	if(pipe(pfd)<0){
-		Xerror1("can't get pipe");
-		return;
-	}
-
-	Updenv();
-
-	argv = rcargv(runq->code[pc+2].s);
-	pid = ForkExecute(argv0, argv, 0, pfd[1], 2);
-	free(argv);
-	close(pfd[1]);
-
-	if(pid == 0) {
-		Xerror("proc failed");
-		close(pfd[0]);
-		return;
-	}
-
-	start(p->code, pc+4, runq->local);
-	pushredir(ROPEN, pfd[0], rfd);
-	p->pc=p->code[pc+3].i;
-	p->pid=pid;
-}
-
-void
-Xpipefd(void)
-{
-	Abort();
-}
-
-void
-Xsubshell(void)
-{
-	char **argv;
-	int pid;
-
-	Updenv();
-
-	argv = rcargv(runq->code[runq->pc].s);
-	pid = ForkExecute(argv0, argv, -1, 1, 2);
-	free(argv);
-
-	if(pid < 0) {
-		Xerror("proc failed");
-		return;
-	}
-
-	Waitfor(pid, 1);
-	runq->pc++;
-}
-
-/*
- *  start a process running the cmd on the stack and return its pid.
- */
-int
-execforkexec(void)
-{
-	char **argv;
-	char file[1024];
-	int nc, mc;
-	word *path;
-	int pid;
-
-	if(runq->argv->words==0)
-		return -1;
-	argv = mkargv(runq->argv->words);
-	mc = strlen(argv[1])+1;
-	for(path = searchpath(runq->argv->words->word);path;path = path->next){
-		nc = strlen(path->word);
-		if(nc + mc >= sizeof file - 1)	/* 1 for / */
-			continue;
-		if(nc > 0){
-			memmove(file, path->word, nc);
-			file[nc++] = '/';
-		}
-		memmove(file+nc, argv[1], mc);
-		pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
-		if(pid >= 0){
-			free(argv);
-			return pid;
-		}
-	}
-	free(argv);
-	return -1;
-}
--- a/sys/src/cmd/rc/mkfile
+++ b/sys/src/cmd/rc/mkfile
@@ -1,7 +1,7 @@
 </$objtype/mkfile
 
 TARG=rc
-COMMONOFILES=\
+OFILES=\
 	code.$O\
 	exec.$O\
 	getflags.$O\
@@ -17,13 +17,9 @@
 	tree.$O\
 	var.$O\
 	havefork.$O\
+	plan9.$O\
+	y.tab.$O\
 
-PLAN9OFILES=plan9.$O\
-
-UNIXOFILES=unix.$O\
-
-OFILES=$COMMONOFILES $PLAN9OFILES y.tab.$O
-
 HFILES=rc.h\
 	x.tab.h\
 	io.h\
@@ -38,9 +34,7 @@
 UPDATE=\
 	mkfile\
 	$HFILES\
-	${COMMONOFILES:%.$O=%.c}\
-	${UNIXOFILES:%.$O=%.c}\
-	${PLAN9OFILES:%.$O=%.c}\
+	${OFILES:%.$O=%.c}\
 	$YFILES\
 	${TARG:%=/386/bin/%}\
 
@@ -51,13 +45,3 @@
 
 clean:V:
 	rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
-
-regress: $O.out
-	cd test
-	mk
-
-unregress:V:
-	for(test in test/*.test) rc $test >$test.out
-
-listing:
-	pr mkfile $HFILES $FILES $FILES9 $FILESUNIX $YFILES|lp -du
--- a/sys/src/cmd/rc/unix.c
+++ /dev/null
@@ -1,466 +1,0 @@
-/*
- * Unix versions of system-specific functions
- *	By convention, exported routines herein have names beginning with an
- *	upper case letter.
- */
-#include "rc.h"
-#include "exec.h"
-#include <errno.h>
-char Rcmain[]="/usr/lib/rcmain";
-char Fdprefix[]="/dev/fd/";
-int execumask(), execfinit();
-struct builtin Builtin[] = {
-	"cd",		execcd,
-	"whatis",	execwhatis,
-	"eval",		execeval,
-	"exec",		execexec,	/* but with popword first */
-	"exit",		execexit,
-	"shift",	execshift,
-	"wait",		execwait,
-	"umask",	execumask,
-	".",		execdot,
-	"finit",	execfinit,
-	"flag",		execflag,
-	0
-};
-#define	SEP	'\1'
-char **environp;
-
-struct word*
-enval(s)
-register char *s;
-{
-	char *t, c;
-	struct word *v;
-	for(t = s;*t && *t!=SEP;t++);
-	c=*t;
-	*t='\0';
-	v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
-	*t = c;
-	return v;
-}
-Vinit(){
-	extern char **environ;
-	char *s;
-	char **env = environ;
-	environp = env;
-	for(;*env;env++){
-		for(s=*env;*s && *s!='(' && *s!='=';s++);
-		switch(*s){
-		case '\0':
-			pfmt(err, "environment %q?\n", *env);
-			break;
-		case '=':
-			*s='\0';
-			setvar(*env, enval(s+1));
-			*s='=';
-			break;
-		case '(':	/* ignore functions for now */
-			break;
-		}
-	}
-}
-char **envp;
-Xrdfn(){
-	char *s;
-	int len;
-	for(;*envp;envp++){
-		for(s=*envp;*s && *s!='(' && *s!='=';s++);
-		switch(*s){
-		case '\0':
-			pfmt(err, "environment %q?\n", *envp);
-			break;
-		case '=':	/* ignore variables */
-			break;
-		case '(':		/* Bourne again */
-			s=*envp+3;
-			envp++;
-			len = strlen(s);
-			s[len]='\n';
-			execcmds(opencore(s, len+1));
-			s[len]='\0';
-			return;
-		}
-	}
-	Xreturn();
-}
-union code rdfns[4];
-execfinit(){
-	static int first = 1;
-	if(first){
-		rdfns[0].i = 1;
-		rdfns[1].f = Xrdfn;
-		rdfns[2].f = Xjump;
-		rdfns[3].i = 1;
-		first = 0;
-	}
-	Xpopm();
-	envp = environp;
-	start(rdfns, 1, runq->local);
-}
-cmpenv(a, b)
-char **a, **b;
-{
-	return strcmp(*a, *b);
-}
-
-char*
-*mkenv()
-{
-	char **env, **ep, *p, *q;
-	struct var **h, *v;
-	struct word *a;
-	int nvar = 0, nchr = 0, sep;
-	/*
-	 * Slightly kludgy loops look at locals then globals
-	 */
-	for(h = var-1;h!=&var[NVAR];h++) for(v = h>=var?*h:runq->local;v;v = v->next){
-		if((v==vlook(v->name)) && v->val){
-			nvar++;
-			nchr+=strlen(v->name)+1;
-			for(a = v->val;a;a = a->next)
-				nchr+=strlen(a->word)+1;
-		}
-		if(v->fn){
-			nvar++;
-			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
-		}
-	}
-	env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
-	ep = env;
-	p = (char *)&env[nvar+1];
-	for(h = var-1;h!=&var[NVAR];h++) for(v = h>=var?*h:runq->local;v;v = v->next){
-		if((v==vlook(v->name)) && v->val){
-			*ep++=p;
-			q = v->name;
-			while(*q) *p++=*q++;
-			sep='=';
-			for(a = v->val;a;a = a->next){
-				*p++=sep;
-				sep = SEP;
-				q = a->word;
-				while(*q) *p++=*q++;
-			}
-			*p++='\0';
-		}
-		if(v->fn){
-			*ep++=p;
-			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
-			*p++='f'; *p++='n'; *p++=' ';
-			q = v->name;
-			while(*q) *p++=*q++;
-			*p++=' ';
-			q = v->fn[v->pc-1].s;
-			while(*q) *p++=*q++;
-			*p++='\0';
-		}
-	}
-	*ep = 0;
-	qsort((char *)env, nvar, sizeof ep[0], cmpenv);
-	return env;	
-}
-char *sigmsg[] = {
-/*  0 normal  */ 0,
-/*  1 SIGHUP  */ "Hangup",
-/*  2 SIGINT  */ 0,
-/*  3 SIGQUIT */ "Quit",
-/*  4 SIGILL  */ "Illegal instruction",
-/*  5 SIGTRAP */ "Trace/BPT trap",
-/*  6 SIGIOT  */ "abort",
-/*  7 SIGEMT  */ "EMT trap",
-/*  8 SIGFPE  */ "Floating exception",
-/*  9 SIGKILL */ "Killed",
-/* 10 SIGBUS  */ "Bus error",
-/* 11 SIGSEGV */ "Memory fault",
-/* 12 SIGSYS  */ "Bad system call",
-/* 13 SIGPIPE */ 0,
-/* 14 SIGALRM */ "Alarm call",
-/* 15 SIGTERM */ "Terminated",
-/* 16 unused  */ "signal 16",
-/* 17 SIGSTOP */ "Process stopped",
-/* 18 unused  */ "signal 18",
-/* 19 SIGCONT */ "Process continued",
-/* 20 SIGCHLD */ "Child death",
-};
-Waitfor(pid, persist){
-	int wpid, sig;
-	struct thread *p;
-	int wstat;
-	char wstatstr[12];
-	for(;;){
-		errno = 0;
-		wpid = wait(&wstat);
-		if(errno==EINTR && persist)
-			continue;
-		if(wpid==-1)
-			break;
-		sig = wstat&0177;
-		if(sig==0177){
-			pfmt(err, "trace: ");
-			sig = (wstat>>8)&0177;
-		}
-		if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
-			if(pid!=wpid)
-				pfmt(err, "%d: ", wpid);
-			if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
-				pfmt(err, "%s", sigmsg[sig]);
-			else if(sig==0177) pfmt(err, "stopped by ptrace");
-			else pfmt(err, "signal %d", sig);
-			if(wstat&0200)pfmt(err, " -- core dumped");
-			pfmt(err, "\n");
-		}
-		wstat = sig?sig+1000:(wstat>>8)&0xFF;
-		if(wpid==pid){
-			inttoascii(wstatstr, wstat);
-			setstatus(wstatstr);
-			break;
-		}
-		else{
-			for(p = runq->ret;p;p = p->ret)
-				if(p->pid==wpid){
-					p->pid=-1;
-					inttoascii(p->status, wstat);
-					break;
-				}
-		}
-	}
-}
-
-char*
-*mkargv(a)
-register struct word *a;
-{
-	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
-	char **argp = argv+1;	/* leave one at front for runcoms */
-	for(;a;a = a->next) *argp++=a->word;
-	*argp = 0;
-	return argv;
-}
-Updenv(){}
-Execute(args, path)
-register struct word *args, *path;
-{
-	char *msg="not found";
-	int txtbusy = 0;
-	char **env = mkenv();
-	char **argv = mkargv(args);
-	char file[512];
-	for(;path;path = path->next){
-		strcpy(file, path->word);
-		if(file[0])
-			strcat(file, "/");
-		strcat(file, argv[1]);
-	ReExec:
-		execve(file, argv+1, env);
-		switch(errno){
-		case ENOEXEC:
-			pfmt(err, "%s: Bourne again\n", argv[1]);
-			argv[0]="sh";
-			argv[1] = estrdup(file);
-			execve("/bin/sh", argv, env);
-			goto Bad;
-		case ETXTBSY:
-			if(++txtbusy!=5){
-				sleep(txtbusy);
-				goto ReExec;
-			}
-			msg="text busy"; goto Bad;
-		case EACCES:
-			msg="no access";
-			break;
-		case ENOMEM:
-			msg="not enough memory"; goto Bad;
-		case E2BIG:
-			msg="too big"; goto Bad;
-		}
-	}
-Bad:
-	setstatus(msg);
-	pfmt(err, "%s: %s\n", argv[1], msg);
-	free(env);
-	free(argv);
-}
-#define	NDIR	14		/* should get this from param.h */
-Globsize(p)
-register char *p;
-{
-	int isglob = 0, globlen = NDIR+1;
-	for(;*p;p++){
-		if(*p==GLOB){
-			p++;
-			if(*p!=GLOB)
-				isglob++;
-			globlen+=*p=='*'?NDIR:1;
-		}
-		else
-			globlen++;
-	}
-	return isglob?globlen:0;
-}
-#include <sys/types.h>
-#include <ndir.h>
-#define	NDIRLIST	50
-DIR *dirlist[NDIRLIST];
-Opendir(name)
-char *name;
-{
-	DIR **dp;
-	for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
-		if(*dp==0){
-			*dp = opendir(name);
-			return *dp?dp-dirlist:-1;
-		}
-	return -1;
-}
-Readdir(f, p, onlydirs)
-int f;
-void *p;
-int onlydirs;		/* ignored, just advisory */
-{
-	struct direct *dp = readdir(dirlist[f]);
-	if(dp==0)
-		return 0;
-	strncpy(p, dp->d_name, NDIR);
-	return 1;
-}
-Closedir(f){
-	closedir(dirlist[f]);
-	dirlist[f] = 0;
-}
-char *Signame[] = {
-	"sigexit",	"sighup",	"sigint",	"sigquit",
-	"sigill",	"sigtrap",	"sigiot",	"sigemt",
-	"sigfpe",	"sigkill",	"sigbus",	"sigsegv",
-	"sigsys",	"sigpipe",	"sigalrm",	"sigterm",
-	"sig16",	"sigstop",	"sigtstp",	"sigcont",
-	"sigchld",	"sigttin",	"sigttou",	"sigtint",
-	"sigxcpu",	"sigxfsz",	"sig26",	"sig27",
-	"sig28",	"sig29",	"sig30",	"sig31",
-	0,
-};
-
-int
-gettrap(sig)
-{
-	signal(sig, gettrap);
-	trap[sig]++;
-	ntrap++;
-	if(ntrap>=NSIG){
-		pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
-		signal(SIGIOT, (int (*)())0);
-		kill(getpid(), SIGIOT);
-	}
-}
-Trapinit(){
-	int i;
-	int (*sig)();
-	if(1 || flag['d']){	/* wrong!!! */
-		sig = signal(SIGINT, gettrap);
-		if(sig==SIG_IGN)
-			signal(SIGINT, SIG_IGN);
-	}
-	else{
-		for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
-			sig = signal(i, gettrap);
-			if(sig==SIG_IGN)
-				signal(i, SIG_IGN);
-		}
-	}
-}
-Unlink(name)
-char *name;
-{
-	return unlink(name);
-}
-Write(fd, buf, cnt)
-void *buf;
-{
-	return write(fd, buf, cnt);
-}
-Read(fd, buf, cnt)
-void *buf;
-{
-	return read(fd, buf, cnt);
-}
-Seek(fd, cnt, whence)
-long cnt;
-{
-	return lseek(fd, cnt, whence);
-}
-Executable(file)
-char *file;
-{
-	return(access(file, 01)==0);
-}
-Creat(file)
-char *file;
-{
-	return creat(file, 0666);
-}
-Dup(a, b){
-	return dup2(a, b);
-}
-Dup1(a){
-	return dup(a);
-}
-/*
- * Wrong:  should go through components of a|b|c and return the maximum.
- */
-Exit(stat)
-register char *stat;
-{
-	int n = 0;
-	while(*stat){
-		if(*stat!='|'){
-			if(*stat<'0' || '9'<*stat)
-				exit(1);
-			else n = n*10+*stat-'0';
-		}
-		stat++;
-	}
-	exit(n);
-}
-Eintr(){
-	return errno==EINTR;
-}
-Noerror(){
-	errno = 0;
-}
-Isatty(fd){
-	return isatty(fd);
-}
-Abort(){
-	abort();
-}
-static int
-octal(char *s)
-{
-	int n = 0;
-	while(*s==' ' || *s=='\t' || *s=='\n') s++;
-	while('0'<=*s && *s<='7') n = n*8+*s++-'0';
-	return n;
-}
-execumask(){		/* wrong -- should fork before writing */
-	int m;
-	struct io out[1];
-	switch(count(runq->argv->words)){
-	default:
-		pfmt(err, "Usage: umask [umask]\n");
-		setstatus("umask usage");
-		poplist();
-		return;
-	case 2:
-		umask(octal(runq->argv->words->next->word));
-		break;
-	case 1: 
-		umask(m = umask(0));
-		out->fd = mapfd(1);
-		out->bufp = out->buf;
-		out->ebuf=&out->buf[NBUF];
-		out->strp = 0;
-		pfmt(out, "%o\n", m);
-		break;
-	}
-	setstatus("");
-	poplist();
-}
--- a/sys/src/cmd/rc/win32.c
+++ /dev/null
@@ -1,549 +1,0 @@
-/*
- * Plan 9 versions of system-specific functions
- *	By convention, exported routines herein have names beginning with an
- *	upper case letter.
- */
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-#include "getflags.h"
-char *Signame[] = {
-	"sigexit",	"sighup",	"sigint",	"sigquit",
-	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
-	0
-};
-char *syssigname[] = {
-	"exit",		/* can't happen */
-	"hangup",
-	"interrupt",
-	"quit",		/* can't happen */
-	"alarm",
-	"kill",
-	"sys: fp: ",
-	"term",
-	0
-};
-char Rcmain[]="/rc/lib/rcmain";
-char Fdprefix[]="/fd/";
-void execfinit(void);
-void execbind(void);
-
-builtin Builtin[] = {
-	"cd",		execcd,
-	"whatis",	execwhatis,
-	"eval",		execeval,
-	"exec",		execexec,	/* but with popword first */
-	"exit",		execexit,
-	"shift",	execshift,
-	"wait",		execwait,
-	".",		execdot,
-	"finit",	execfinit,
-	"flag",		execflag,
-	0
-};
-
-void
-Vinit(void)
-{
-	int dir, f, len;
-	word *val;
-	char *buf, *s;
-	Dir *ent;
-	int i, nent;
-	char envname[256];
-	dir = open("/env", OREAD);
-	if(dir<0){
-		pfmt(err, "rc: can't open /env: %r\n");
-		return;
-	}
-	ent = nil;
-	for(;;){
-		nent = dirread(dir, &ent);
-		if(nent <= 0)
-			break;
-		for(i = 0; i<nent; i++){
-			len = ent[i].length;
-			if(len && strncmp(ent[i].name, "fn#", 3)!=0){
-				snprint(envname, sizeof envname, "/env/%s", ent[i].name);
-				if((f = open(envname, 0))>=0){
-					buf = emalloc((int)len+1);
-					read(f, buf, (long)len);
-					val = 0;
-					/* Charitably add a 0 at the end if need be */
-					if(buf[len-1])
-						buf[len++]='\0';
-					s = buf+len-1;
-					for(;;){
-						while(s!=buf && s[-1]!='\0') --s;
-						val = newword(s, val);
-						if(s==buf)
-							break;
-						--s;
-					}
-					setvar(ent[i].name, val);
-					vlook(ent[i].name)->changed = 0;
-					close(f);
-					free(buf);
-				}
-			}
-		}
-		free(ent);
-	}
-	close(dir);
-}
-int envdir;
-
-void
-Xrdfn(void)
-{
-	int f, len;
-	static Dir *ent, *allocent;
-	static int nent;
-	Dir *e;
-	char envname[256];
-
-	for(;;){
-		if(nent == 0){
-			free(allocent);
-			nent = dirread(envdir, &allocent);
-			ent = allocent;
-		}
-		if(nent <= 0)
-			break;
-		while(nent){
-			e = ent++;
-			nent--;
-			len = e->length;
-			if(len && strncmp(e->name, "fn#", 3)==0){
-				snprint(envname, sizeof envname, "/env/%s", e->name);
-				if((f = open(envname, 0))>=0){
-					execcmds(openfd(f));
-					return;
-				}
-			}
-		}
-	}
-	close(envdir);
-	Xreturn();
-}
-union code rdfns[4];
-
-void
-execfinit(void)
-{
-	static int first = 1;
-	if(first){
-		rdfns[0].i = 1;
-		rdfns[1].f = Xrdfn;
-		rdfns[2].f = Xjump;
-		rdfns[3].i = 1;
-		first = 0;
-	}
-	Xpopm();
-	envdir = open("/env", 0);
-	if(envdir<0){
-		pfmt(err, "rc: can't open /env: %r\n");
-		return;
-	}
-	start(rdfns, 1, runq->local);
-}
-
-int
-Waitfor(int pid, int persist)
-{
-	thread *p;
-	Waitmsg *w;
-	char errbuf[ERRMAX];
-
-	while((w = wait()) != nil){
-		if(w->pid==pid){
-			setstatus(w->msg);
-			free(w);
-			return 0;
-		}
-		for(p = runq->ret;p;p = p->ret)
-			if(p->pid==w->pid){
-				p->pid=-1;
-				strcpy(p->status, w->msg);
-			}
-		free(w);
-	}
-
-	errstr(errbuf, sizeof errbuf);
-	if(strcmp(errbuf, "interrupted")==0) return -1;
-	return 0;
-}
-
-char*
-*mkargv(word *a)
-{
-	char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
-	char **argp = argv+1;	/* leave one at front for runcoms */
-	for(;a;a = a->next) *argp++=a->word;
-	*argp = 0;
-	return argv;
-}
-
-void
-addenv(var *v)
-{
-	char envname[256];
-	word *w;
-	int f;
-	io *fd;
-	if(v->changed){
-		v->changed = 0;
-		snprint(envname, sizeof envname, "/env/%s", v->name);
-		if((f = Creat(envname))<0)
-			pfmt(err, "rc: can't open %s: %r\n", envname);
-		else{
-			for(w = v->val;w;w = w->next)
-				write(f, w->word, strlen(w->word)+1L);
-			close(f);
-		}
-	}
-	if(v->fnchanged){
-		v->fnchanged = 0;
-		snprint(envname, sizeof envname, "/env/fn#%s", v->name);
-		if((f = Creat(envname))<0)
-			pfmt(err, "rc: can't open %s: %r\n", envname);
-		else{
-			if(v->fn){
-				fd = openfd(f);
-				pfmt(fd, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
-				closeio(fd);
-			}
-			close(f);
-		}
-	}
-}
-
-void
-updenvlocal(var *v)
-{
-	if(v){
-		updenvlocal(v->next);
-		addenv(v);
-	}
-}
-
-void
-Updenv(void)
-{
-	var *v, **h;
-	for(h = gvar;h!=&gvar[NVAR];h++)
-		for(v=*h;v;v = v->next)
-			addenv(v);
-	if(runq)
-		updenvlocal(runq->local);
-}
-
-int
-ForkExecute(char *file, char **argv, int sin, int sout, int serr)
-{
-	int pid;
-
-{int i;
-fprint(2, "forkexec %s", file);
-for(i = 0; argv[i]; i++)fprint(2, " %s", argv[i]);
-fprint(2, " %d %d %d\n", sin, sout, serr);
-}
-	if(access(file, 1) != 0)
-		return -1;
-fprint(2, "forking\n");
-	switch(pid = fork()){
-	case -1:
-		return -1;
-	case 0:
-		if(sin >= 0)
-			dup(sin, 0);
-		else
-			close(0);
-		if(sout >= 0)
-			dup(sout, 1);
-		else
-			close(1);
-		if(serr >= 0)
-			dup(serr, 2);
-		else
-			close(2);
-fprint(2, "execing\n");
-		exec(file, argv);
-fprint(2, "exec: %r\n");
-		exits(file);
-	}
-	return pid;
-}
-
-void
-Execute(word *args, word *path)
-{
-	char **argv = mkargv(args);
-	char file[1024];
-	int nc;
-	Updenv();
-	for(;path;path = path->next){
-		nc = strlen(path->word);
-		if(nc<1024){
-			strcpy(file, path->word);
-			if(file[0]){
-				strcat(file, "/");
-				nc++;
-			}
-			if(nc+strlen(argv[1])<1024){
-				strcat(file, argv[1]);
-				exec(file, argv+1);
-			}
-			else werrstr("command name too long");
-		}
-	}
-	rerrstr(file, sizeof file);
-	setstatus(file);
-	pfmt(err, "%s: %s\n", argv[1], file);
-	free(argv);
-}
-#define	NDIR	256		/* shoud be a better way */
-
-int
-Globsize(char *p)
-{
-	int isglob = 0, globlen = NDIR+1;
-	for(;*p;p++){
-		if(*p==GLOB){
-			p++;
-			if(*p!=GLOB)
-				isglob++;
-			globlen+=*p=='*'?NDIR:1;
-		}
-		else
-			globlen++;
-	}
-	return isglob?globlen:0;
-}
-#define	NFD	50
-#define	NDBUF	32
-struct{
-	Dir	*dbuf;
-	int	i;
-	int	n;
-}dir[NFD];
-
-int
-Opendir(char *name)
-{
-	Dir *db;
-	int f;
-	f = open(name, 0);
-	if(f==-1)
-		return f;
-	db = dirfstat(f);
-	if(db!=nil && (db->mode&DMDIR)){
-		if(f<NFD){
-			dir[f].i = 0;
-			dir[f].n = 0;
-		}
-		free(db);
-		return f;
-	}
-	free(db);
-	close(f);
-	return -1;
-}
-
-static int
-trimdirs(Dir *d, int nd)
-{
-	int r, w;
-
-	for(r=w=0; r<nd; r++)
-		if(d[r].mode&DMDIR)
-			d[w++] = d[r];
-	return w;
-}
-
-/*
- * onlydirs is advisory -- it means you only
- * need to return the directories.  it's okay to
- * return files too (e.g., on unix where you can't
- * tell during the readdir), but that just makes 
- * the globber work harder.
- */
-int
-Readdir(int f, void *p, int onlydirs)
-{
-	int n;
-
-	if(f<0 || f>=NFD)
-		return 0;
-Again:
-	if(dir[f].i==dir[f].n){	/* read */
-		free(dir[f].dbuf);
-		dir[f].dbuf = 0;
-		n = dirread(f, &dir[f].dbuf);
-		if(n>0){
-			if(onlydirs){
-				n = trimdirs(dir[f].dbuf, n);
-				if(n == 0)
-					goto Again;
-			}	
-			dir[f].n = n;
-		}else
-			dir[f].n = 0;
-		dir[f].i = 0;
-	}
-	if(dir[f].i == dir[f].n)
-		return 0;
-	strncpy(p, dir[f].dbuf[dir[f].i].name, NDIR);
-	dir[f].i++;
-	return 1;
-}
-
-void
-Closedir(int f)
-{
-	if(f>=0 && f<NFD){
-		free(dir[f].dbuf);
-		dir[f].i = 0;
-		dir[f].n = 0;
-		dir[f].dbuf = 0;
-	}
-	close(f);
-}
-int interrupted = 0;
-void
-notifyf(void*, char *s)
-{
-	int i;
-	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
-		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
-		goto Out;
-	}
-	pfmt(err, "rc: note: %s\n", s);
-	noted(NDFLT);
-	return;
-Out:
-	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
-		trap[i]++;
-		ntrap++;
-	}
-	if(ntrap>=32){	/* rc is probably in a trap loop */
-		pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
-		abort();
-	}
-	noted(NCONT);
-}
-
-void
-Trapinit(void)
-{
-	notify(notifyf);
-}
-
-void
-Unlink(char *name)
-{
-	remove(name);
-}
-
-long
-Write(int fd, void *buf, long cnt)
-{
-	return write(fd, buf, (long)cnt);
-}
-
-long
-Read(int fd, void *buf, long cnt)
-{
-	return read(fd, buf, cnt);
-}
-
-long
-Seek(int fd, long cnt, long whence)
-{
-	return seek(fd, cnt, whence);
-}
-
-int
-Executable(char *file)
-{
-	Dir *statbuf;
-	int ret;
-
-	statbuf = dirstat(file);
-	if(statbuf == nil)
-		return 0;
-	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
-	free(statbuf);
-	return ret;
-}
-
-int
-Creat(char *file)
-{
-	return create(file, 1, 0666L);
-}
-
-int
-Dup(int a, int b)
-{
-	return dup(a, b);
-}
-
-int
-Dup1(int)
-{
-	return -1;
-}
-
-void
-Exit(char *stat)
-{
-	Updenv();
-	setstatus(stat);
-	exits(truestatus()?"":getstatus());
-}
-
-int
-Eintr(void)
-{
-	return interrupted;
-}
-
-void
-Noerror(void)
-{
-	interrupted = 0;
-}
-
-int
-Isatty(int fd)
-{
-	Dir *d1, *d2;
-	int ret;
-
-	d1 = dirfstat(fd);
-	if(d1 == nil)
-		return 0;
-	if(strncmp(d1->name, "ptty", 4)==0){	/* fwd complaints to philw */
-		free(d1);
-		return 1;
-	}
-	d2 = dirstat("/dev/cons");
-	if(d2 == nil){
-		free(d1);
-		return 0;
-	}
-	ret = (d1->type==d2->type&&d1->dev==d2->dev&&d1->qid.path==d2->qid.path);
-	free(d1);
-	free(d2);
-	return ret;
-}
-
-void
-Abort(void)
-{
-	pfmt(err, "aborting\n");
-	flush(err);
-	Exit("aborting");
-}