sync with plan 9
diff --git a/src/cmd/rc/code.c b/src/cmd/rc/code.c
index 748b9f8..0ae90ee 100644
--- a/src/cmd/rc/code.c
+++ b/src/cmd/rc/code.c
@@ -7,9 +7,9 @@
 #define	c1	t->child[1]
 #define	c2	t->child[2]
 int codep, ncode;
-#define	emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
-#define	emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
-#define	emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
+#define	emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
+#define	emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
+#define	emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
 void stuffdot(int);
 char *fnstr(tree*);
 void outcode(tree*, int);
@@ -17,22 +17,32 @@
 int iscase(tree*);
 code *codecopy(code*);
 void codefree(code*);
-int morecode(void){
+
+int
+morecode(void)
+{
 	ncode+=100;
-	codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
-	if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
+	codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
+	if(codebuf==0)
+		panic("Can't realloc %d bytes in morecode!",
 				ncode*sizeof codebuf[0]);
 	return 0;
 }
-void stuffdot(int a){
-	if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
-	codebuf[a].i=codep;
-}
-int compile(tree *t)
+
+void
+stuffdot(int a)
 {
-	ncode=100;
-	codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
-	codep=0;
+	if(a<0 || codep<=a)
+		panic("Bad address %d in stuffdot", a);
+	codebuf[a].i = codep;
+}
+
+int
+compile(tree *t)
+{
+	ncode = 100;
+	codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+	codep = 0;
 	emiti(0);			/* reference count */
 	outcode(t, flag['e']?1:0);
 	if(nerror){
@@ -44,31 +54,39 @@
 	emitf(0);
 	return 1;
 }
-void cleanhere(char *f)
+
+void
+cleanhere(char *f)
 {
 	emitf(Xdelhere);
 	emits(strdup(f));
 }
-char *fnstr(tree *t)
+
+char*
+fnstr(tree *t)
 {
-	io *f=openstr();
+	io *f = openstr();
 	char *v;
 	extern char nl;
-	char svnl=nl;
+	char svnl = nl;
 	nl=';';
 	pfmt(f, "%t", t);
-	nl=svnl;
-	v=f->strp;
-	f->strp=0;
+	nl = svnl;
+	v = f->strp;
+	f->strp = 0;
 	closeio(f);
 	return v;
 }
-void outcode(tree *t, int eflag)
+
+void
+outcode(tree *t, int eflag)
 {
 	int p, q;
 	tree *tt;
-	if(t==0) return;
-	if(t->type!=NOT && t->type!=';') runq->iflast=0;
+	if(t==0)
+		return;
+	if(t->type!=NOT && t->type!=';')
+		runq->iflast = 0;
 	switch(t->type){
 	default:
 		pfmt(err, "bad type %d in outcode\n", t->type);
@@ -92,10 +110,13 @@
 		break;
 	case '&':
 		emitf(Xasync);
-		p=emiti(0);
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
+		if(havefork){
+			p = emiti(0);
+			outcode(c0, eflag);
+			emitf(Xexit);
+			stuffdot(p);
+		} else
+			emits(fnstr(c0));
 		break;
 	case ';':
 		outcode(c0, eflag);
@@ -110,15 +131,18 @@
 		break;
 	case '`':
 		emitf(Xbackq);
-		p=emiti(0);
-		outcode(c0, 0);
-		emitf(Xexit);
-		stuffdot(p);
+		if(havefork){
+			p = emiti(0);
+			outcode(c0, 0);
+			emitf(Xexit);
+			stuffdot(p);
+		} else
+			emits(fnstr(c0));
 		break;
 	case ANDAND:
 		outcode(c0, 0);
 		emitf(Xtrue);
-		p=emiti(0);
+		p = emiti(0);
 		outcode(c1, eflag);
 		stuffdot(p);
 		break;
@@ -144,7 +168,7 @@
 		outcode(c0, eflag);
 		if(c1){
 			emitf(Xfn);
-			p=emiti(0);
+			p = emiti(0);
 			emits(fnstr(c1));
 			outcode(c1, eflag);
 			emitf(Xunlocal);	/* get rid of $* */
@@ -157,22 +181,23 @@
 	case IF:
 		outcode(c0, 0);
 		emitf(Xif);
-		p=emiti(0);
+		p = emiti(0);
 		outcode(c1, eflag);
 		emitf(Xwastrue);
 		stuffdot(p);
 		break;
 	case NOT:
-		if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
+		if(!runq->iflast)
+			yyerror("`if not' does not follow `if(...)'");
 		emitf(Xifnot);
-		p=emiti(0);
+		p = emiti(0);
 		outcode(c0, eflag);
 		stuffdot(p);
 		break;
 	case OROR:
 		outcode(c0, 0);
 		emitf(Xfalse);
-		p=emiti(0);
+		p = emiti(0);
 		outcode(c1, eflag);
 		stuffdot(p);
 		break;
@@ -183,15 +208,20 @@
 		emitf(Xmark);
 		outcode(c0, eflag);
 		emitf(Xsimple);
-		if(eflag) emitf(Xeflag);
+		if(eflag)
+			emitf(Xeflag);
 		break;
 	case SUBSHELL:
 		emitf(Xsubshell);
-		p=emiti(0);
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
-		if(eflag) emitf(Xeflag);
+		if(havefork){
+			p = emiti(0);
+			outcode(c0, eflag);
+			emitf(Xexit);
+			stuffdot(p);
+		} else
+			emits(fnstr(c0));
+		if(eflag)
+			emitf(Xeflag);
 		break;
 	case SWITCH:
 		codeswitch(t, eflag);
@@ -202,14 +232,16 @@
 		emitf(Xmark);
 		outcode(c0, eflag);
 		emitf(Xmatch);
-		if(eflag) emitf(Xeflag);
+		if(eflag)
+			emitf(Xeflag);
 		break;
 	case WHILE:
-		q=codep;
+		q = codep;
 		outcode(c0, 0);
-		if(q==codep) emitf(Xsettrue);	/* empty condition == while(true) */
+		if(q==codep)
+			emitf(Xsettrue);	/* empty condition == while(true) */
 		emitf(Xtrue);
-		p=emiti(0);
+		p = emiti(0);
 		outcode(c1, eflag);
 		emitf(Xjump);
 		emiti(q);
@@ -235,8 +267,8 @@
 		emitf(Xmark);
 		outcode(c0, eflag);
 		emitf(Xlocal);
-		p=emitf(Xfor);
-		q=emiti(0);
+		p = emitf(Xfor);
+		q = emiti(0);
 		outcode(c2, eflag);
 		emitf(Xjump);
 		emiti(p);
@@ -263,10 +295,14 @@
 	case PIPEFD:
 		emitf(Xpipefd);
 		emiti(t->rtype);
-		p=emiti(0);
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
+		if(havefork){
+			p = emiti(0);
+			outcode(c0, eflag);
+			emitf(Xexit);
+			stuffdot(p);
+		} else {
+			emits(fnstr(c0));
+		}
 		break;
 	case REDIR:
 		emitf(Xmark);
@@ -283,28 +319,31 @@
 		case HERE:
 			emitf(Xread);
 			break;
+		case RDWR:
+			emitf(Xrdwr);
+			break;
 		}
 		emiti(t->fd0);
 		outcode(c1, eflag);
 		emitf(Xpopredir);
 		break;
 	case '=':
-		tt=t;
-		for(;t && t->type=='=';t=c2);
+		tt = t;
+		for(;t && t->type=='=';t = c2);
 		if(t){
-			for(t=tt;t->type=='=';t=c2){
+			for(t = tt;t->type=='=';t = c2){
 				emitf(Xmark);
 				outcode(c1, eflag);
 				emitf(Xmark);
 				outcode(c0, eflag);
 				emitf(Xlocal);
 			}
-			t=tt;
+			t = tt;
 			outcode(c2, eflag);
-			for(;t->type=='=';t=c2) emitf(Xunlocal);
+			for(;t->type=='=';t = c2) emitf(Xunlocal);
 		}
 		else{
-			for(t=tt;t;t=c2){
+			for(t = tt;t;t = c2){
 				emitf(Xmark);
 				outcode(c1, eflag);
 				emitf(Xmark);
@@ -312,17 +351,22 @@
 				emitf(Xassign);
 			}
 		}
-		t=tt;	/* so tests below will work */
+		t = tt;	/* so tests below will work */
 		break;
 	case PIPE:
 		emitf(Xpipe);
 		emiti(t->fd0);
 		emiti(t->fd1);
-		p=emiti(0);
-		q=emiti(0);
-		outcode(c0, eflag);
-		emitf(Xexit);
-		stuffdot(p);
+		if(havefork){
+			p = emiti(0);
+			q = emiti(0);
+			outcode(c0, eflag);
+			emitf(Xexit);
+			stuffdot(p);
+		} else {
+			emits(fnstr(c0));
+			q = emiti(0);
+		}
 		outcode(c1, eflag);
 		emitf(Xreturn);
 		stuffdot(q);
@@ -330,8 +374,8 @@
 		break;
 	}
 	if(t->type!=NOT && t->type!=';')
-		runq->iflast=t->type==IF;
-	else if(c0) runq->iflast=c0->type==IF;
+		runq->iflast = t->type==IF;
+	else if(c0) runq->iflast = c0->type==IF;
 }
 /*
  * switch code looks like this:
@@ -353,7 +397,9 @@
  * leave:
  *	Xpopm
  */
-void codeswitch(tree *t, int eflag)
+
+void
+codeswitch(tree *t, int eflag)
 {
 	int leave;		/* patch jump address to leave switch */
 	int out;		/* jump here to leave switch */
@@ -368,23 +414,23 @@
 	emitf(Xmark);
 	outcode(c0, eflag);
 	emitf(Xjump);
-	nextcase=emiti(0);
-	out=emitf(Xjump);
-	leave=emiti(0);
+	nextcase = emiti(0);
+	out = emitf(Xjump);
+	leave = emiti(0);
 	stuffdot(nextcase);
-	t=c1->child[0];
+	t = c1->child[0];
 	while(t->type==';'){
-		tt=c1;
+		tt = c1;
 		emitf(Xmark);
-		for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
+		for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
 		emitf(Xcase);
-		nextcase=emiti(0);
-		t=tt;
+		nextcase = emiti(0);
+		t = tt;
 		for(;;){
 			if(t->type==';'){
 				if(iscase(c0)) break;
 				outcode(c0, eflag);
-				t=c1;
+				t = c1;
 			}
 			else{
 				if(!iscase(t)) outcode(t, eflag);
@@ -398,23 +444,32 @@
 	stuffdot(leave);
 	emitf(Xpopm);
 }
-int iscase(tree *t)
+
+int
+iscase(tree *t)
 {
-	if(t->type!=SIMPLE) return 0;
-	do t=c0; while(t->type==ARGLIST);
+	if(t->type!=SIMPLE)
+		return 0;
+	do t = c0; while(t->type==ARGLIST);
 	return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
 }
-code *codecopy(code *cp)
+
+code*
+codecopy(code *cp)
 {
 	cp[0].i++;
 	return cp;
 }
-void codefree(code *cp)
+
+void
+codefree(code *cp)
 {
 	code *p;
-	if(--cp[0].i!=0) return;
-	for(p=cp+1;p->f;p++){
+	if(--cp[0].i!=0)
+		return;
+	for(p = cp+1;p->f;p++){
 		if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+		|| p->f==Xrdwr
 		|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
 		|| p->f==Xfor || p->f==Xjump
 		|| p->f==Xsubshell || p->f==Xtrue) p++;
diff --git a/src/cmd/rc/exec.c b/src/cmd/rc/exec.c
index 72e5784..86d97cd 100644
--- a/src/cmd/rc/exec.c
+++ b/src/cmd/rc/exec.c
@@ -1,9 +1,3 @@
-#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"
@@ -13,91 +7,118 @@
  * Start executing the given code at the given pc with the given redirection
  */
 char *argv0="rc";
-void start(code *c, int pc, var *local)
+
+void
+start(code *c, int pc, var *local)
 {
-	struct thread *p=new(struct thread);
-	p->code=codecopy(c);
-	p->pc=pc;
-	p->argv=0;
-	p->redir=p->startredir=runq?runq->redir:0;
-	p->local=local;
-	p->cmdfile=0;
-	p->cmdfd=0;
-	p->eof=0;
-	p->iflag=0;
-	p->lineno=1;
-	p->pid=-1;
-	p->ret=runq;
-	runq=p;
+	struct thread *p = new(struct thread);
+
+	p->code = codecopy(c);
+	p->pc = pc;
+	p->argv = 0;
+	p->redir = p->startredir = runq?runq->redir:0;
+	p->local = local;
+	p->cmdfile = 0;
+	p->cmdfd = 0;
+	p->eof = 0;
+	p->iflag = 0;
+	p->lineno = 1;
+	p->ret = runq;
+	runq = p;
 }
-word *newword(char *wd, word *next)
+
+word*
+newword(char *wd, word *next)
 {
-	word *p=new(word);
-	p->word=strdup(wd);
-	p->next=next;
+	word *p = new(word);
+	p->word = strdup(wd);
+	p->next = next;
 	return p;
 }
-void pushword(char *wd)
+
+void
+pushword(char *wd)
 {
-	if(runq->argv==0) panic("pushword but no argv!", 0);
-	runq->argv->words=newword(wd, runq->argv->words);
+	if(runq->argv==0)
+		panic("pushword but no argv!", 0);
+	runq->argv->words = newword(wd, runq->argv->words);
 }
-void popword(void){
+
+void
+popword(void)
+{
 	word *p;
-	if(runq->argv==0) panic("popword but no argv!", 0);
-	p=runq->argv->words;
-	if(p==0) panic("popword but no word!", 0);
-	runq->argv->words=p->next;
+	if(runq->argv==0)
+		panic("popword but no argv!", 0);
+	p = runq->argv->words;
+	if(p==0)
+		panic("popword but no word!", 0);
+	runq->argv->words = p->next;
 	efree(p->word);
 	efree((char *)p);
 }
-void freelist(word *w)
+
+void
+freelist(word *w)
 {
 	word *nw;
 	while(w){
-		nw=w->next;
+		nw = w->next;
 		efree(w->word);
 		efree((char *)w);
-		w=nw;
+		w = nw;
 	}
 }
-void pushlist(void){
-	list *p=new(list);
-	p->next=runq->argv;
-	p->words=0;
-	runq->argv=p;
+
+void
+pushlist(void)
+{
+	list *p = new(list);
+	p->next = runq->argv;
+	p->words = 0;
+	runq->argv = p;
 }
-void poplist(void){
-	list *p=runq->argv;
-	if(p==0) panic("poplist but no argv", 0);
+
+void
+poplist(void)
+{
+	list *p = runq->argv;
+	if(p==0)
+		panic("poplist but no argv", 0);
 	freelist(p->words);
-	runq->argv=p->next;
+	runq->argv = p->next;
 	efree((char *)p);
 }
-int count(word *w)
+
+int
+count(word *w)
 {
 	int n;
-	for(n=0;w;n++) w=w->next;
+	for(n = 0;w;n++) w = w->next;
 	return n;
 }
-void pushredir(int type, int from, int to){
-	redir * rp=new(redir);
-	rp->type=type;
-	rp->from=from;
-	rp->to=to;
-	rp->next=runq->redir;
-	runq->redir=rp;
-}
-var *newvar(char *name, var *next)
+
+void
+pushredir(int type, int from, int to)
 {
-	var *v=new(var);
-	v->name=name;
-	v->val=0;
-	v->fn=0;
-	v->changed=0;
-	v->fnchanged=0;
-	v->next=next;
-	v->changefn = 0;
+	redir * rp = new(redir);
+	rp->type = type;
+	rp->from = from;
+	rp->to = to;
+	rp->next = runq->redir;
+	runq->redir = rp;
+}
+
+var*
+newvar(char *name, var *next)
+{
+	var *v = new(var);
+	v->name = name;
+	v->val = 0;
+	v->fn = 0;
+	v->changed = 0;
+	v->fnchanged = 0;
+	v->next = next;
 	return v;
 }
 /*
@@ -117,50 +138,55 @@
 	/* needed for rcmain later */
 	putenv("PLAN9", unsharp("#9"));
 
-	argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
-	if(argc==-1) usage("[file [arg ...]]");
-	if(argv[0][0]=='-') flag['l']=flagset;
-	if(flag['I']) flag['i'] = 0;
+	argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
+	if(argc==-1)
+		usage("[file [arg ...]]");
+	if(argv[0][0]=='-')
+		flag['l'] = flagset;
+	if(flag['I'])
+		flag['i'] = 0;
 	else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
-	rcmain=flag['m']?flag['m'][0]:Rcmain(); 
-	err=openfd(2);
+	rcmain = flag['m'] ? flag['m'][0] : Rcmain();
+	err = openfd(2);
 	kinit();
 	Trapinit();
 	Vinit();
-	itoa(num, mypid=getpid());
+	inttoascii(num, mypid = getpid());
 	pathinit();
 	setvar("pid", newword(num, (word *)0));
 	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
 				:(word *)0);
 	setvar("rcname", newword(argv[0], (word *)0));
-	i=0;
-	bootstrap[i++].i=1;
-	bootstrap[i++].f=Xmark;
-	bootstrap[i++].f=Xword;
+	i = 0;
+	bootstrap[i++].i = 1;
+	bootstrap[i++].f = Xmark;
+	bootstrap[i++].f = Xword;
 	bootstrap[i++].s="*";
-	bootstrap[i++].f=Xassign;
-	bootstrap[i++].f=Xmark;
-	bootstrap[i++].f=Xmark;
-	bootstrap[i++].f=Xword;
+	bootstrap[i++].f = Xassign;
+	bootstrap[i++].f = Xmark;
+	bootstrap[i++].f = Xmark;
+	bootstrap[i++].f = Xword;
 	bootstrap[i++].s="*";
-	bootstrap[i++].f=Xdol;
-	bootstrap[i++].f=Xword;
-	bootstrap[i++].s=rcmain;
-	bootstrap[i++].f=Xword;
+	bootstrap[i++].f = Xdol;
+	bootstrap[i++].f = Xword;
+	bootstrap[i++].s = rcmain;
+	bootstrap[i++].f = Xword;
 	bootstrap[i++].s=".";
-	bootstrap[i++].f=Xsimple;
-	bootstrap[i++].f=Xexit;
-	bootstrap[i].i=0;
+	bootstrap[i++].f = Xsimple;
+	bootstrap[i++].f = Xexit;
+	bootstrap[i].i = 0;
 	start(bootstrap, 1, (var *)0);
 	/* prime bootstrap argv */
 	pushlist();
 	argv0 = strdup(argv[0]);
-	for(i=argc-1;i!=0;--i) pushword(argv[i]);
+	for(i = argc-1;i!=0;--i) pushword(argv[i]);
 	for(;;){
-		if(flag['r']) pfnc(err, runq);
+		if(flag['r'])
+			pfnc(err, runq);
 		runq->pc++;
 		(*runq->code[runq->pc-1].f)();
-		if(ntrap) dotrap();
+		if(ntrap)
+			dotrap();
 	}
 }
 /*
@@ -197,6 +223,7 @@
  * Xpipefd[type]{... Xreturn}		connect {} to pipe (input or output,
  * 					depending on type), push /dev/fd/??
  * Xpopm(value)				pop value from stack
+ * Xrdwr(file)[fd]			open file for reading and writing
  * Xread(file)[fd]			open file to read
  * Xsettraps(names){... Xreturn}		define trap functions
  * Xshowtraps				print trap list
@@ -208,16 +235,24 @@
  * Xword[string]			push string
  * Xwrite(file)[fd]			open file to write
  */
-void Xappend(void){
+
+void
+Xappend(void)
+{
 	char *file;
 	int f;
 	switch(count(runq->argv->words)){
-	default: Xerror1(">> requires singleton"); return;
-	case 0: Xerror1(">> requires file"); return;
-	case 1: break;
+	default:
+		Xerror1(">> requires singleton");
+		return;
+	case 0:
+		Xerror1(">> requires file");
+		return;
+	case 1:
+		break;
 	}
-	file=runq->argv->words->word;
-	if((f=open(file, 1))<0 && (f=Creat(file))<0){
+	file = runq->argv->words->word;
+	if((f = open(file, 1))<0 && (f = Creat(file))<0){
 		pfmt(err, "%s: ", file);
 		Xerror("can't open");
 		return;
@@ -227,126 +262,114 @@
 	runq->pc++;
 	poplist();
 }
-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:
-		/*
-		 * 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:
-		close(null);
-		runq->pc=runq->code[runq->pc].i;
-		itoa(npid, pid);
-		setvar("apid", newword(npid, (word *)0));
-		break;
-	}
-}
-void Xsettrue(void){
+
+void
+Xsettrue(void)
+{
 	setstatus("");
 }
-void Xbang(void){
+
+void
+Xbang(void)
+{
 	setstatus(truestatus()?"false":"");
 }
-void Xclose(void){
+
+void
+Xclose(void)
+{
 	pushredir(RCLOSE, runq->code[runq->pc].i, 0);
 	runq->pc++;
 }
-void Xdup(void){
+
+void
+Xdup(void)
+{
 	pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
 	runq->pc+=2;
 }
-void Xeflag(void){
+
+void
+Xeflag(void)
+{
 	if(eflagok && !truestatus()) Xexit();
 }
-void Xexit(void){
+
+void
+Xexit(void)
+{
 	struct var *trapreq;
 	struct word *starval;
-	static int beenhere=0;
+	static int beenhere = 0;
 	if(getpid()==mypid && !beenhere){
-		trapreq=vlook("sigexit");
+		trapreq = vlook("sigexit");
 		if(trapreq->fn){
-			beenhere=1;
+			beenhere = 1;
 			--runq->pc;
-			starval=vlook("*")->val;
+			starval = vlook("*")->val;
 			start(trapreq->fn, trapreq->pc, (struct var *)0);
-			runq->local=newvar(strdup("*"), runq->local);
-			runq->local->val=copywords(starval, (struct word *)0);
-			runq->local->changed=1;
-			runq->redir=runq->startredir=0;
+			runq->local = newvar(strdup("*"), runq->local);
+			runq->local->val = copywords(starval, (struct word *)0);
+			runq->local->changed = 1;
+			runq->redir = runq->startredir = 0;
 			return;
 		}
 	}
 	Exit(getstatus());
 }
-void Xfalse(void){
-	if(truestatus()) runq->pc=runq->code[runq->pc].i;
+
+void
+Xfalse(void)
+{
+	if(truestatus()) runq->pc = runq->code[runq->pc].i;
 	else runq->pc++;
 }
 int ifnot;		/* dynamic if not flag */
-void Xifnot(void){
+
+void
+Xifnot(void)
+{
 	if(ifnot)
 		runq->pc++;
 	else
-		runq->pc=runq->code[runq->pc].i;
+		runq->pc = runq->code[runq->pc].i;
 }
-void Xjump(void){
-	runq->pc=runq->code[runq->pc].i;
+
+void
+Xjump(void)
+{
+	runq->pc = runq->code[runq->pc].i;
 }
-void Xmark(void){
+
+void
+Xmark(void)
+{
 	pushlist();
 }
-void Xpopm(void){
+
+void
+Xpopm(void)
+{
 	poplist();
 }
-void Xread(void){
+
+void
+Xread(void)
+{
 	char *file;
 	int f;
 	switch(count(runq->argv->words)){
-	default: Xerror1("< requires singleton\n"); return;
-	case 0: Xerror1("< requires file\n"); return;
-	case 1: break;
+	default:
+		Xerror1("< requires singleton\n");
+		return;
+	case 0:
+		Xerror1("< requires file\n");
+		return;
+	case 1:
+		break;
 	}
-	file=runq->argv->words->word;
-	if((f=open(file, 0))<0){
+	file = runq->argv->words->word;
+	if((f = open(file, 0))<0){
 		pfmt(err, "%s: ", file);
 		Xerror("can't open");
 		return;
@@ -355,51 +378,110 @@
 	runq->pc++;
 	poplist();
 }
-void turfredir(void){
+
+void
+Xrdwr(void)
+{
+	char *file;
+	int f;
+
+	switch(count(runq->argv->words)){
+	default:
+		Xerror1("<> requires singleton\n");
+		return;
+	case 0:
+		Xerror1("<> requires file\n");
+		return;
+	case 1:
+		break;
+	}
+	file = runq->argv->words->word;
+	if((f = open(file, ORDWR))<0){
+		pfmt(err, "%s: ", file);
+		Xerror("can't open");
+		return;
+	}
+	pushredir(ROPEN, f, runq->code[runq->pc].i);
+	runq->pc++;
+	poplist();
+}
+
+void
+turfredir(void)
+{
 	while(runq->redir!=runq->startredir)
 		Xpopredir();
 }
-void Xpopredir(void){
-	struct redir *rp=runq->redir;
-	if(rp==0) panic("turfredir null!", 0);
-	runq->redir=rp->next;
-	if(rp->type==ROPEN) close(rp->from);
+
+void
+Xpopredir(void)
+{
+	struct redir *rp = runq->redir;
+	if(rp==0)
+		panic("turfredir null!", 0);
+	runq->redir = rp->next;
+	if(rp->type==ROPEN)
+		close(rp->from);
 	efree((char *)rp);
 }
-void Xreturn(void){
-	struct thread *p=runq;
+
+void
+Xreturn(void)
+{
+	struct thread *p = runq;
 	turfredir();
 	while(p->argv) poplist();
 	codefree(p->code);
-	runq=p->ret;
+	runq = p->ret;
 	efree((char *)p);
-	if(runq==0) Exit(getstatus());
+	if(runq==0)
+		Exit(getstatus());
 }
-void Xtrue(void){
+
+void
+Xtrue(void)
+{
 	if(truestatus()) runq->pc++;
-	else runq->pc=runq->code[runq->pc].i;
+	else runq->pc = runq->code[runq->pc].i;
 }
-void Xif(void){
-	ifnot=1;
+
+void
+Xif(void)
+{
+	ifnot = 1;
 	if(truestatus()) runq->pc++;
-	else runq->pc=runq->code[runq->pc].i;
+	else runq->pc = runq->code[runq->pc].i;
 }
-void Xwastrue(void){
-	ifnot=0;
+
+void
+Xwastrue(void)
+{
+	ifnot = 0;
 }
-void Xword(void){
+
+void
+Xword(void)
+{
 	pushword(runq->code[runq->pc++].s);
 }
-void Xwrite(void){
+
+void
+Xwrite(void)
+{
 	char *file;
 	int f;
 	switch(count(runq->argv->words)){
-	default: Xerror1("> requires singleton\n"); return;
-	case 0: Xerror1("> requires file\n"); return;
-	case 1: break;
+	default:
+		Xerror1("> requires singleton\n");
+		return;
+	case 0:
+		Xerror1("> requires file\n");
+		return;
+	case 1:
+		break;
 	}
-	file=runq->argv->words->word;
-	if((f=Creat(file))<0){
+	file = runq->argv->words->word;
+	if((f = Creat(file))<0){
 		pfmt(err, "%s: ", file);
 		Xerror("can't open");
 		return;
@@ -408,31 +490,35 @@
 	runq->pc++;
 	poplist();
 }
-char *_list2str(word *words, int c){
+
+char*
+list2str(word *words)
+{
 	char *value, *s, *t;
-	int len=0;
+	int len = 0;
 	word *ap;
-	for(ap=words;ap;ap=ap->next)
+	for(ap = words;ap;ap = ap->next)
 		len+=1+strlen(ap->word);
-	value=emalloc(len+1);
-	s=value;
-	for(ap=words;ap;ap=ap->next){
-		for(t=ap->word;*t;) *s++=*t++;
-		*s++=c;
+	value = emalloc(len+1);
+	s = value;
+	for(ap = words;ap;ap = ap->next){
+		for(t = ap->word;*t;) *s++=*t++;
+		*s++=' ';
 	}
-	if(s==value) *s='\0';
+	if(s==value)
+		*s='\0';
 	else s[-1]='\0';
 	return value;
 }
-char *list2str(word *words){
-	return _list2str(words, ' ');
-}
-void Xmatch(void){
+
+void
+Xmatch(void)
+{
 	word *p;
 	char *subject;
-	subject=list2str(runq->argv->words);
+	subject = list2str(runq->argv->words);
 	setstatus("no match");
-	for(p=runq->argv->next->words;p;p=p->next)
+	for(p = runq->argv->next->words;p;p = p->next)
 		if(match(subject, p->word, '\0')){
 			setstatus("");
 			break;
@@ -441,14 +527,17 @@
 	poplist();
 	poplist();
 }
-void Xcase(void){
+
+void
+Xcase(void)
+{
 	word *p;
 	char *s;
-	int ok=0;
-	s=list2str(runq->argv->next->words);
-	for(p=runq->argv->words;p;p=p->next){
+	int ok = 0;
+	s = list2str(runq->argv->next->words);
+	for(p = runq->argv->words;p;p = p->next){
 		if(match(s, p->word, '\0')){
-			ok=1;
+			ok = 1;
 			break;
 		}
 	}
@@ -456,28 +545,33 @@
 	if(ok)
 		runq->pc++;
 	else
-		runq->pc=runq->code[runq->pc].i;
+		runq->pc = runq->code[runq->pc].i;
 	poplist();
 }
-word *conclist(word *lp, word *rp, word *tail)
+
+word*
+conclist(word *lp, word *rp, word *tail)
 {
 	char *buf;
 	word *v;
 	if(lp->next || rp->next)
-		tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
+		tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
 			tail);
-	buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
+	buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
 	strcpy(buf, lp->word);
 	strcat(buf, rp->word);
-	v=newword(buf, tail);
+	v = newword(buf, tail);
 	efree(buf);
 	return v;
 }
-void Xconc(void){
-	word *lp=runq->argv->words;
-	word *rp=runq->argv->next->words;
-	word *vp=runq->argv->next->next->words;
-	int lc=count(lp), rc=count(rp);
+
+void
+Xconc(void)
+{
+	word *lp = runq->argv->words;
+	word *rp = runq->argv->next->words;
+	word *vp = runq->argv->next->next->words;
+	int lc = count(lp), rc = count(rp);
 	if(lc!=0 || rc!=0){
 		if(lc==0 || rc==0){
 			Xerror1("null list in concatenation");
@@ -487,42 +581,48 @@
 			Xerror1("mismatched list lengths in concatenation");
 			return;
 		}
-		vp=conclist(lp, rp, vp);
+		vp = conclist(lp, rp, vp);
 	}
 	poplist();
 	poplist();
-	runq->argv->words=vp;
+	runq->argv->words = vp;
 }
-void Xassign(void){
+
+void
+Xassign(void)
+{
 	var *v;
 	if(count(runq->argv->words)!=1){
 		Xerror1("variable name not singleton!");
 		return;
 	}
 	deglob(runq->argv->words->word);
-	v=vlook(runq->argv->words->word);
+	v = vlook(runq->argv->words->word);
 	poplist();
 	globlist();
 	freewords(v->val);
-	v->val=runq->argv->words;
-	v->changed=1;
-	if(v->changefn)
-		v->changefn(v);
-	runq->argv->words=0;
+	v->val = runq->argv->words;
+	v->changed = 1;
+	runq->argv->words = 0;
 	poplist();
 }
 /*
  * copy arglist a, adding the copy to the front of tail
  */
-word *copywords(word *a, word *tail)
+
+word*
+copywords(word *a, word *tail)
 {
-	word *v=0, **end;
-	for(end=&v;a;a=a->next,end=&(*end)->next)
-		*end=newword(a->word, 0);
-	*end=tail;
+	word *v = 0, **end;
+	for(end=&v;a;a = a->next,end=&(*end)->next)
+		*end = newword(a->word, 0);
+	*end = tail;
 	return v;
 }
-void Xdol(void){
+
+void
+Xdol(void)
+{
 	word *a, *star;
 	char *s, *t;
 	int n;
@@ -530,24 +630,27 @@
 		Xerror1("variable name not singleton!");
 		return;
 	}
-	s=runq->argv->words->word;
+	s = runq->argv->words->word;
 	deglob(s);
-	n=0;
-	for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
-	a=runq->argv->next->words;
+	n = 0;
+	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
+	a = runq->argv->next->words;
 	if(n==0 || *t)
-		a=copywords(vlook(s)->val, a);
+		a = copywords(vlook(s)->val, a);
 	else{
-		star=vlook("*")->val;
+		star = vlook("*")->val;
 		if(star && 1<=n && n<=count(star)){
-			while(--n) star=star->next;
-			a=newword(star->word, a);
+			while(--n) star = star->next;
+			a = newword(star->word, a);
 		}
 	}
 	poplist();
-	runq->argv->words=a;
+	runq->argv->words = a;
 }
-void Xqdol(void){
+
+void
+Xqdol(void)
+{
 	word *a, *p;
 	char *s;
 	int n;
@@ -555,20 +658,20 @@
 		Xerror1("variable name not singleton!");
 		return;
 	}
-	s=runq->argv->words->word;
+	s = runq->argv->words->word;
 	deglob(s);
-	a=vlook(s)->val;
+	a = vlook(s)->val;
 	poplist();
-	n=count(a);
+	n = count(a);
 	if(n==0){
 		pushword("");
 		return;
 	}
-	for(p=a;p;p=p->next) n+=strlen(p->word);
-	s=emalloc(n);
+	for(p = a;p;p = p->next) n+=strlen(p->word);
+	s = emalloc(n);
 	if(a){
 		strcpy(s, a->word);
-		for(p=a->next;p;p=p->next){
+		for(p = a->next;p;p = p->next){
 			strcat(s, " ");
 			strcat(s, p->word);
 		}
@@ -578,37 +681,47 @@
 	pushword(s);
 	efree(s);
 }
-word *subwords(word *val, int len, word *sub, word *a)
+
+word*
+subwords(word *val, int len, word *sub, word *a)
 {
 	int n;
 	char *s;
-	if(!sub) return a;
-	a=subwords(val, len, sub->next, a);
-	s=sub->word;
+	if(!sub)
+		return a;
+	a = subwords(val, len, sub->next, a);
+	s = sub->word;
 	deglob(s);
-	n=0;
-	while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
-	if(n<1 || len<n) return a;
-	for(;n!=1;--n) val=val->next;
+	n = 0;
+	while('0'<=*s && *s<='9') n = n*10+ *s++ -'0';
+	if(n<1 || len<n)
+		return a;
+	for(;n!=1;--n) val = val->next;
 	return newword(val->word, a);
 }
-void Xsub(void){
+
+void
+Xsub(void)
+{
 	word *a, *v;
 	char *s;
 	if(count(runq->argv->next->words)!=1){
 		Xerror1("variable name not singleton!");
 		return;
 	}
-	s=runq->argv->next->words->word;
+	s = runq->argv->next->words->word;
 	deglob(s);
-	a=runq->argv->next->next->words;
-	v=vlook(s)->val;
-	a=subwords(v, count(v), runq->argv->words, a);
+	a = runq->argv->next->next->words;
+	v = vlook(s)->val;
+	a = subwords(v, count(v), runq->argv->words, a);
 	poplist();
 	poplist();
-	runq->argv->words=a;
+	runq->argv->words = a;
 }
-void Xcount(void){
+
+void
+Xcount(void)
+{
 	word *a;
 	char *s, *t;
 	int n;
@@ -617,112 +730,102 @@
 		Xerror1("variable name not singleton!");
 		return;
 	}
-	s=runq->argv->words->word;
+	s = runq->argv->words->word;
 	deglob(s);
-	n=0;
-	for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+	n = 0;
+	for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
 	if(n==0 || *t){
-		a=vlook(s)->val;
-		itoa(num, count(a));
+		a = vlook(s)->val;
+		inttoascii(num, count(a));
 	}
 	else{
-		a=vlook("*")->val;
-		itoa(num, a && 1<=n && n<=count(a)?1:0);
+		a = vlook("*")->val;
+		inttoascii(num, a && 1<=n && n<=count(a)?1:0);
 	}
 	poplist();
 	pushword(num);
 }
-void Xlocal(void){
+
+void
+Xlocal(void)
+{
 	if(count(runq->argv->words)!=1){
 		Xerror1("variable name must be singleton\n");
 		return;
 	}
 	deglob(runq->argv->words->word);
-	runq->local=newvar(strdup(runq->argv->words->word), runq->local);
-	runq->local->val=copywords(runq->argv->next->words, (word *)0);
-	runq->local->changed=1;
+	runq->local = newvar(strdup(runq->argv->words->word), runq->local);
+	runq->local->val = copywords(runq->argv->next->words, (word *)0);
+	runq->local->changed = 1;
 	poplist();
 	poplist();
 }
-void Xunlocal(void){
-	var *v=runq->local, *hid;
-	if(v==0) panic("Xunlocal: no locals!", 0);
-	runq->local=v->next;
-	hid=vlook(v->name);
-	hid->changed=1;
+
+void
+Xunlocal(void)
+{
+	var *v = runq->local, *hid;
+	if(v==0)
+		panic("Xunlocal: no locals!", 0);
+	runq->local = v->next;
+	hid = vlook(v->name);
+	hid->changed = 1;
 	efree(v->name);
 	freewords(v->val);
 	efree((char *)v);
 }
-void freewords(word *w)
+
+void
+freewords(word *w)
 {
 	word *nw;
 	while(w){
 		efree(w->word);
-		nw=w->next;
+		nw = w->next;
 		efree((char *)w);
-		w=nw;
+		w = nw;
 	}
 }
-void Xfn(void){
+
+void
+Xfn(void)
+{
 	var *v;
 	word *a;
 	int end;
-	end=runq->code[runq->pc].i;
-	for(a=runq->argv->words;a;a=a->next){
-		v=gvlook(a->word);
-		if(v->fn) codefree(v->fn);
-		v->fn=codecopy(runq->code);
-		v->pc=runq->pc+2;
-		v->fnchanged=1;
+	end = runq->code[runq->pc].i;
+	for(a = runq->argv->words;a;a = a->next){
+		v = gvlook(a->word);
+		if(v->fn)
+			codefree(v->fn);
+		v->fn = codecopy(runq->code);
+		v->pc = runq->pc+2;
+		v->fnchanged = 1;
 	}
-	runq->pc=end;
+	runq->pc = end;
 	poplist();
 }
-void Xdelfn(void){
+
+void
+Xdelfn(void)
+{
 	var *v;
 	word *a;
-	for(a=runq->argv->words;a;a=a->next){
-		v=gvlook(a->word);
-		if(v->fn) codefree(v->fn);
-		v->fn=0;
-		v->fnchanged=1;
+	for(a = runq->argv->words;a;a = a->next){
+		v = gvlook(a->word);
+		if(v->fn)
+			codefree(v->fn);
+		v->fn = 0;
+		v->fnchanged = 1;
 	}
 	poplist();
 }
-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:
-		start(p->code, pc+2, runq->local);
-		runq->ret=0;
-		close(pfd[PRD]);
-		pushredir(ROPEN, pfd[PWR], lfd);
-		break;
-	default:
-		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;
-	}
-}
-char *concstatus(char *s, char *t)
+
+char*
+concstatus(char *s, char *t)
 {
 	static char v[NSTATUS+1];
-	int n=strlen(s);
+	int n = strlen(s);
 	strncpy(v, s, NSTATUS);
 	if(n<NSTATUS){
 		v[n]='|';
@@ -731,7 +834,10 @@
 	v[NSTATUS]='\0';
 	return v;
 }
-void Xpipewait(void){
+
+void
+Xpipewait(void)
+{
 	char status[NSTATUS+1];
 	if(runq->pid==-1)
 		setstatus(concstatus(runq->status, getstatus()));
@@ -743,31 +849,35 @@
 		setstatus(concstatus(getstatus(), status));
 	}
 }
-void Xrdcmds(void){
-	struct thread *p=runq;
+
+void
+Xrdcmds(void)
+{
+	struct thread *p = runq;
 	word *prompt;
 	flush(err);
-	nerror=0;
+	nerror = 0;
 	if(flag['s'] && !truestatus())
 		pfmt(err, "status=%v\n", vlook("status")->val);
 	if(runq->iflag){
-		prompt=vlook("prompt")->val;
+		prompt = vlook("prompt")->val;
 		if(prompt)
-			promptstr=prompt->word;
+			promptstr = prompt->word;
 		else
 			promptstr="% ";
 	}
 	Noerror();
 	if(yyparse()){
 		if(!p->iflag || p->eof && !Eintr()){
-			if(p->cmdfile) efree(p->cmdfile);
+			if(p->cmdfile)
+				efree(p->cmdfile);
 			closeio(p->cmdfd);
 			Xreturn();	/* should this be omitted? */
 		}
 		else{
 			if(Eintr()){
 				pchr(err, '\n');
-				p->eof=0;
+				p->eof = 0;
 			}
 			--p->pc;	/* go back for next command */
 		}
@@ -779,7 +889,9 @@
 	}
 	freenodes();
 }
-void Xerror(char *s)
+
+void
+Xerror(char *s)
 {
 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
 		pfmt(err, "rc: %s: %r\n", s);
@@ -789,7 +901,9 @@
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
 }
-void Xerror1(char *s)
+
+void
+Xerror1(char *s)
 {
 	if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
 		pfmt(err, "rc: %s\n", s);
@@ -799,150 +913,55 @@
 	setstatus("error");
 	while(!runq->iflag) Xreturn();
 }
-void Xbackq(void){
-	char wd[8193];
-	int c;
-	char *s, *ewd=&wd[8192], *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;
-	}
-	switch(pid=fork()){
-	case -1: Xerror("try again");
-		close(pfd[PRD]);
-		close(pfd[PWR]);
-		return;
-	case 0:
-		close(pfd[PRD]);
-		start(runq->code, runq->pc+1, runq->local);
-		pushredir(ROPEN, pfd[PWR], 1);
-		return;
-	default:
-		close(pfd[PWR]);
-		f=openfd(pfd[PRD]);
-		s=wd;
-		v=0;
-		while((c=rchr(f))!=EOF){
-			if(strchr(stop, c) || s==ewd){
-				if(s!=wd){
-					*s='\0';
-					v=newword(wd, v);
-					s=wd;
-				}
-			}
-			else *s++=c;
-		}
-		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;
-		}
-		runq->pc=runq->code[runq->pc].i;
-		return;
-	}
-}
-/*
- * Who should wait for the exit from the fork?
- */
-void Xpipefd(void){
-	struct thread *p=runq;
-	int pc=p->pc;
-	char name[40];
-	int pfd[2];
-	int sidefd, mainfd;
-	if(pipe(pfd)<0){
-		Xerror("can't get pipe");
-		return;
-	}
-	if(p->code[pc].i==READ){
-		sidefd=pfd[PWR];
-		mainfd=pfd[PRD];
-	}
-	else{
-		sidefd=pfd[PRD];
-		mainfd=pfd[PWR];
-	}
-	switch(fork()){
-	case -1:
-		Xerror("try again");
-		break;
-	case 0:
-		start(p->code, pc+2, runq->local);
-		close(mainfd);
-		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
-		runq->ret=0;
-		break;
-	default:
-		close(sidefd);
-		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
-		strcpy(name, Fdprefix);
-		itoa(name+strlen(name), 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:
-		start(runq->code, runq->pc+1, runq->local);
-		runq->ret=0;
-		break;
-	default:
-		Waitfor(pid, 1);
-		runq->pc=runq->code[runq->pc].i;
-		break;
-	}
-}
-void setstatus(char *s)
+
+void
+setstatus(char *s)
 {
 	setvar("status", newword(s, (word *)0));
 }
-char *getstatus(void){
-	var *status=vlook("status");
+
+char*
+getstatus(void)
+{
+	var *status = vlook("status");
 	return status->val?status->val->word:"";
 }
-int truestatus(void){
+
+int
+truestatus(void)
+{
 	char *s;
-	for(s=getstatus();*s;s++)
-		if(*s!='|' && *s!='0') return 0;
+	for(s = getstatus();*s;s++)
+		if(*s!='|' && *s!='0')
+			return 0;
 	return 1;
 }
-void Xdelhere(void){
+
+void
+Xdelhere(void)
+{
 	Unlink(runq->code[runq->pc++].s);
 }
-void Xfor(void){
+
+void
+Xfor(void)
+{
 	if(runq->argv->words==0){
 		poplist();
-		runq->pc=runq->code[runq->pc].i;
+		runq->pc = runq->code[runq->pc].i;
 	}
 	else{
 		freelist(runq->local->val);
-		runq->local->val=runq->argv->words;
-		runq->local->changed=1;
-		runq->argv->words=runq->argv->words->next;
-		runq->local->val->next=0;
+		runq->local->val = runq->argv->words;
+		runq->local->changed = 1;
+		runq->argv->words = runq->argv->words->next;
+		runq->local->val->next = 0;
 		runq->pc++;
 	}
 }
-void Xglob(void){
+
+void
+Xglob(void)
+{
 	globlist();
 }
diff --git a/src/cmd/rc/exec.h b/src/cmd/rc/exec.h
index 1704b6f..06d2991 100644
--- a/src/cmd/rc/exec.h
+++ b/src/cmd/rc/exec.h
@@ -5,6 +5,7 @@
 extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void);
 extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
 extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
+extern void Xrdwr(void);
 extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
 extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
 extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
@@ -51,7 +52,6 @@
 	int iflag;			/* interactive? */
 	int lineno;			/* linenumber */
 	int pid;			/* process for Xpipewait to wait for */
-	int done;			/* have we seen a wait message for this process? */
 	char status[NSTATUS];		/* status for Xpipewait */
 	tree *treenodes;		/* tree nodes created by this process */
 	thread *ret;		/* who continues when this finishes */
@@ -61,12 +61,16 @@
 code *codebuf;				/* compiler output */
 int ntrap;				/* number of outstanding traps */
 int trap[NSIG];				/* number of outstanding traps per type */
-extern struct builtin{
+struct builtin{
 	char *name;
 	void (*fnc)(void);
-}Builtin[];
+};
+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);
 void execexit(void), execshift(void);
 void execwait(void), execumask(void), execdot(void), execflag(void);
 void execfunc(var*), execcmds(io *);
diff --git a/src/cmd/rc/fns.h b/src/cmd/rc/fns.h
index b9e5cb7..f645478 100644
--- a/src/cmd/rc/fns.h
+++ b/src/cmd/rc/fns.h
@@ -7,13 +7,14 @@
 int	Executable(char*);
 void	Execute(word*,  word*);
 void	Exit(char*);
+int	ForkExecute(char*, char**, int, int, int);
 int	Globsize(char*);
 int	Isatty(int);
 void	Memcpy(char*, char*, long);
 void	Noerror(void);
 int	Opendir(char*);
 long	Read(int, char*, long);
-int	Readdir(int, char*);
+int	Readdir(int, char*, int);
 long	Seek(int, long, long);
 void	Trapinit(void);
 void	Unlink(char*);
@@ -27,7 +28,6 @@
 void	codefree(code*);
 int	compile(tree*);
 char *	list2str(word*);
-char *	_list2str(word*, int);
 int	count(word*);
 void	deglob(char*);
 void	dotrap(void);
@@ -35,10 +35,12 @@
 void	freewords(word*);
 void	globlist(void);
 int	idchr(int);
-void	itoa(char*, long);
+void	inttoascii(char*, long);
 void	kinit(void);
+int	mapfd(int);
 int	match(char*, char*, int);
 int	matchfn(char*, char*);
+char**	mkargv(word*);
 void	panic(char*, int);
 void	pathinit(void);
 void	poplist(void);
@@ -48,9 +50,9 @@
 void	pushredir(int, int, int);
 void	pushword(char*);
 void	readhere(void);
+word*	searchpath(char*);
 void	setstatus(char*);
 void	setvar(char*, word*);
-void	_setvar(char*, word*, int);
 void	skipnl(void);
 void	start(code*, int, var*);
 int	truestatus(void);
diff --git a/src/cmd/rc/getflags.c b/src/cmd/rc/getflags.c
index c452067..09f6e3a 100644
--- a/src/cmd/rc/getflags.c
+++ b/src/cmd/rc/getflags.c
@@ -3,7 +3,7 @@
 #include "rc.h"
 #include "getflags.h"
 #include "fns.h"
-char *flagset[]={"<flag>"};
+char *flagset[] = {"<flag>"};
 char **flag[NFLAG];
 char cmdline[NCMDLINE+1];
 char *cmdname;
@@ -19,105 +19,118 @@
 #define	FLAGSYN	3
 #define	BADFLAG	4
 static int badflag;
-int getflags(int argc, char *argv[], char *flags, int stop)
+
+int
+getflags(int argc, char *argv[], char *flags, int stop)
 {
 	char *s, *t;
 	int i, j, c, count;
-	flagarg=flags;
-	if(cmdname==0) cmdname=argv[0];
-	s=cmdline;
-	for(i=0;i!=argc;i++){
-		for(t=argv[i];*t;t++)
+	flagarg = flags;
+	if(cmdname==0)
+		cmdname = argv[0];
+	s = cmdline;
+	for(i = 0;i!=argc;i++){
+		for(t = argv[i];*t;t++)
 			if(s!=&cmdline[NCMDLINE])
 				*s++=*t;
 		if(i!=argc-1 && s!=&cmdline[NCMDLINE])
 			*s++=' ';
 	}
 	*s='\0';
-	i=1;
+	i = 1;
 	while(i!=argc){
 		if(argv[i][0]!='-' || argv[i][1]=='\0'){
-			if(stop) return argc;
+			if(stop)
+				return argc;
 			i++;
 			continue;
 		}
-		s=argv[i]+1;
+		s = argv[i]+1;
 		while(*s){
 			c=*s++;
-			count=scanflag(c, flags);
-			if(count==-1) return -1;
-			if(flag[c]){ reason=RESET; badflag=c; return -1; }
+			count = scanflag(c, flags);
+			if(count==-1)
+				return -1;
+			if(flag[c]){ reason = RESET; badflag = c; return -1; }
 			if(count==0){
-				flag[c]=flagset;
+				flag[c] = flagset;
 				if(*s=='\0'){
-					for(j=i+1;j<=argc;j++)
-						argv[j-1]=argv[j];
+					for(j = i+1;j<=argc;j++)
+						argv[j-1] = argv[j];
 					--argc;
 				}
 			}
 			else{
 				if(*s=='\0'){
-					for(j=i+1;j<=argc;j++)
-						argv[j-1]=argv[j];
+					for(j = i+1;j<=argc;j++)
+						argv[j-1] = argv[j];
 					--argc;
-					s=argv[i];
+					s = argv[i];
 				}
 				if(argc-i<count){
-					reason=FEWARGS;
-					badflag=c;
+					reason = FEWARGS;
+					badflag = c;
 					return -1;
 				}
 				reverse(argv+i, argv+argc);
 				reverse(argv+i, argv+argc-count);
 				reverse(argv+argc-count+1, argv+argc);
 				argc-=count;
-				flag[c]=argv+argc+1;
-				flag[c][0]=s;
+				flag[c] = argv+argc+1;
+				flag[c][0] = s;
 				s="";
 			}
 		}
 	}
 	return argc;
 }
-static void reverse(char **p, char **q)
+
+static void
+reverse(char **p, char **q)
 {
 	char *t;
-	for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
+	for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
 }
-static int scanflag(int c, char *f)
+
+static int
+scanflag(int c, char *f)
 {
 	int fc, count;
-	if(0<=c && c<NFLAG) while(*f){
-		if(*f==' '){
-			f++;
-			continue;
-		}
-		fc=*f++;
-		if(*f==':'){
-			f++;
-			if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; }
-			count=0;
-			while('0'<=*f && *f<='9') count=count*10+*f++-'0';
-		}
-		else
-			count=0;
-		if(*f=='['){
-			do{
+	if(0<=c && c<NFLAG)
+		while(*f){
+			if(*f==' '){
 				f++;
-				if(*f=='\0'){ reason=FLAGSYN; return -1; }
-			}while(*f!=']');
-			f++;
+				continue;
+			}
+			fc=*f++;
+			if(*f==':'){
+				f++;
+				if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; }
+				count = 0;
+				while('0'<=*f && *f<='9') count = count*10+*f++-'0';
+			}
+			else
+				count = 0;
+			if(*f=='['){
+				do{
+					f++;
+					if(*f=='\0'){ reason = FLAGSYN; return -1; }
+				}while(*f!=']');
+				f++;
+			}
+			if(c==fc)
+				return count;
 		}
-		if(c==fc) return count;
-	}
-	reason=BADFLAG;
-	badflag=c;
+	reason = BADFLAG;
+	badflag = c;
 	return -1;
 }
-void usage(char *tail)
+
+void
+usage(char *tail)
 {
 	char *s, *t, c;
-	int count, nflag=0;
+	int count, nflag = 0;
 	switch(reason){
 	case RESET:
 		errs("Flag -");
@@ -140,46 +153,52 @@
 	}
 	errs("Usage: ");
 	errs(cmdname);
-	for(s=flagarg;*s;){
+	for(s = flagarg;*s;){
 		c=*s;
-		if(*s++==' ') continue;
+		if(*s++==' ')
+			continue;
 		if(*s==':'){
 			s++;
-			count=0;
-			while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+			count = 0;
+			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
 		}
-		else count=0;
+		else count = 0;
 		if(count==0){
-			if(nflag==0) errs(" [-");
+			if(nflag==0)
+				errs(" [-");
 			nflag++;
 			errc(c);
 		}
 		if(*s=='['){
 			s++;
 			while(*s!=']' && *s!='\0') s++;
-			if(*s==']') s++;
+			if(*s==']')
+				s++;
 		}
 	}
-	if(nflag) errs("]");
-	for(s=flagarg;*s;){
+	if(nflag)
+		errs("]");
+	for(s = flagarg;*s;){
 		c=*s;
-		if(*s++==' ') continue;
+		if(*s++==' ')
+			continue;
 		if(*s==':'){
 			s++;
-			count=0;
-			while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+			count = 0;
+			while('0'<=*s && *s<='9') count = count*10+*s++-'0';
 		}
-		else count=0;
+		else count = 0;
 		if(count!=0){
 			errs(" [-");
 			errc(c);
 			if(*s=='['){
 				s++;
-				t=s;
+				t = s;
 				while(*s!=']' && *s!='\0') s++;
 				errs(" ");
 				errn(t, s-t);
-				if(*s==']') s++;
+				if(*s==']')
+					s++;
 			}
 			else
 				while(count--) errs(" arg");
@@ -188,7 +207,8 @@
 		else if(*s=='['){
 			s++;
 			while(*s!=']' && *s!='\0') s++;
-			if(*s==']') s++;
+			if(*s==']')
+				s++;
 		}
 	}
 	if(tail){
@@ -198,20 +218,27 @@
 	errs("\n");
 	Exit("bad flags");
 }
-static void errn(char *s, int count)
+
+static void
+errn(char *s, int count)
 {
 	while(count){ errc(*s++); --count; }
 }
-static void errs(char *s)
+
+static void
+errs(char *s)
 {
 	while(*s) errc(*s++);
 }
 #define	NBUF	80
-static char buf[NBUF], *bufp=buf;
-static void errc(int c){
+static char buf[NBUF], *bufp = buf;
+
+static void
+errc(int c)
+{
 	*bufp++=c;
 	if(bufp==&buf[NBUF] || c=='\n'){
 		Write(2, buf, bufp-buf);
-		bufp=buf;
+		bufp = buf;
 	}
 }
diff --git a/src/cmd/rc/glob.c b/src/cmd/rc/glob.c
index fcd09c0..6eaa831 100644
--- a/src/cmd/rc/glob.c
+++ b/src/cmd/rc/glob.c
@@ -6,68 +6,77 @@
 /*
  * delete all the GLOB marks from s, in place
  */
-void deglob(char *s)
+
+void
+deglob(char *s)
 {
-	char *t=s;
+	char *t = s;
 	do{
-		if(*t==GLOB) t++;
+		if(*t==GLOB)
+			t++;
 		*s++=*t;
 	}while(*t++);
 }
-int globcmp(const void *s, const void *t)
+
+int
+globcmp(const void *s, const void *t)
 {
 	return strcmp(*(char**)s, *(char**)t);
 }
-void globsort(word *left, word *right)
+
+void
+globsort(word *left, word *right)
 {
 	char **list;
 	word *a;
-	int n=0;
-	for(a=left;a!=right;a=a->next) n++;
-	list=(char **)emalloc(n*sizeof(char *));
-	for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
-	qsort((char *)list, n, sizeof(char *), globcmp);
-	for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
+	int n = 0;
+	for(a = left;a!=right;a = a->next) n++;
+	list = (char **)emalloc(n*sizeof(char *));
+	for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
+	qsort((void *)list, n, sizeof(void *), globcmp);
+	for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
 	efree((char *)list);
 }
 /*
  * Push names prefixed by globname and suffixed by a match of p onto the astack.
  * namep points to the end of the prefix in globname.
  */
-void globdir(char *p, char *namep)
+
+void
+globdir(char *p, char *namep)
 {
 	char *t, *newp;
 	int f;
 	/* scan the pattern looking for a component with a metacharacter in it */
 	if(*p=='\0'){
-		globv=newword(globname, globv);
+		globv = newword(globname, globv);
 		return;
 	}
-	t=namep;
-	newp=p;
+	t = namep;
+	newp = p;
 	while(*newp){
 		if(*newp==GLOB)
 			break;
 		*t=*newp++;
 		if(*t++=='/'){
-			namep=t;
-			p=newp;
+			namep = t;
+			p = newp;
 		}
 	}
 	/* If we ran out of pattern, append the name if accessible */
 	if(*newp=='\0'){
 		*t='\0';
 		if(access(globname, 0)==0)
-			globv=newword(globname, globv);
+			globv = newword(globname, globv);
 		return;
 	}
 	/* read the directory and recur for any entry that matches */
 	*namep='\0';
-	if((f=Opendir(globname[0]?globname:"."))<0) return;
+	if((f = Opendir(globname[0]?globname:"."))<0) return;
 	while(*newp!='/' && *newp!='\0') newp++;
-	while(Readdir(f, namep)){
+	while(Readdir(f, namep, *newp=='/')){
 		if(matchfn(namep, p)){
-			for(t=namep;*t;t++);
+			for(t = namep;*t;t++);
 			globdir(newp, t);
 		}
 	}
@@ -77,22 +86,24 @@
  * Push all file names matched by p on the current thread's stack.
  * If there are no matches, the list consists of p.
  */
-void glob(char *p)
+
+void
+glob(char *p)
 {
-	word *svglobv=globv;
-	int globlen=Globsize(p);
+	word *svglobv = globv;
+	int globlen = Globsize(p);
 	if(!globlen){
 		deglob(p);
-		globv=newword(p, globv);
+		globv = newword(p, globv);
 		return;
 	}
-	globname=emalloc(globlen);
+	globname = emalloc(globlen);
 	globname[0]='\0';
 	globdir(p, globname);
 	efree(globname);
 	if(svglobv==globv){
 		deglob(p);
-		globv=newword(p, globv);
+		globv = newword(p, globv);
 	}
 	else
 		globsort(globv, svglobv);
@@ -100,12 +111,18 @@
 /*
  * Do p and q point at equal utf codes
  */
-int equtf(char *p, char *q){
-	if(*p!=*q) return 0;
+
+int
+equtf(char *p, char *q)
+{
+	if(*p!=*q)
+		return 0;
 	if(twobyte(*p)) return p[1]==q[1];
 	if(threebyte(*p)){
-		if(p[1]!=q[1]) return 0;
-		if(p[1]=='\0') return 1;	/* broken code at end of string! */
+		if(p[1]!=q[1])
+			return 0;
+		if(p[1]=='\0')
+			return 1;	/* broken code at end of string! */
 		return p[2]==q[2];
 	}
 	return 1;
@@ -114,7 +131,10 @@
  * Return a pointer to the next utf code in the string,
  * not jumping past nuls in broken utf codes!
  */
-char *nextutf(char *p){
+
+char*
+nextutf(char *p)
+{
 	if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
 	if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
 	return p+1;
@@ -122,7 +142,10 @@
 /*
  * Convert the utf code at *p to a unicode value
  */
-int unicode(char *p){
+
+int
+unicode(char *p)
+{
 	int u=*p&0xff;
 	if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
 	if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
@@ -135,77 +158,97 @@
  * ? matches any single character
  * [...] matches the enclosed list of characters
  */
-int matchfn(char *s, char *p)
+
+int
+matchfn(char *s, char *p)
 {
 	if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
 		return 0;
 	return match(s, p, '/');
 }
-int match(char *s, char *p, int stop)
+
+int
+match(char *s, char *p, int stop)
 {
 	int compl, hit, lo, hi, t, c;
-	for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){
+	for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
 		if(*p!=GLOB){
 			if(!equtf(p, s)) return 0;
 		}
 		else switch(*++p){
 		case GLOB:
-			if(*s!=GLOB) return 0;
+			if(*s!=GLOB)
+				return 0;
 			break;
 		case '*':
 			for(;;){
 				if(match(s, nextutf(p), stop)) return 1;
-				if(!*s) break;
-				s=nextutf(s);
+				if(!*s)
+					break;
+				s = nextutf(s);
 			}
 			return 0;
 		case '?':
-			if(*s=='\0') return 0;
+			if(*s=='\0')
+				return 0;
 			break;
 		case '[':
-			if(*s=='\0') return 0;
-			c=unicode(s);
+			if(*s=='\0')
+				return 0;
+			c = unicode(s);
 			p++;
 			compl=*p=='~';
-			if(compl) p++;
-			hit=0;
+			if(compl)
+				p++;
+			hit = 0;
 			while(*p!=']'){
-				if(*p=='\0') return 0;		/* syntax error */
-				lo=unicode(p);
-				p=nextutf(p);
-				if(*p!='-') hi=lo;
+				if(*p=='\0')
+					return 0;		/* syntax error */
+				lo = unicode(p);
+				p = nextutf(p);
+				if(*p!='-')
+					hi = lo;
 				else{
 					p++;
-					if(*p=='\0') return 0;	/* syntax error */
-					hi=unicode(p);
-					p=nextutf(p);
-					if(hi<lo){ t=lo; lo=hi; hi=t; }
+					if(*p=='\0')
+						return 0;	/* syntax error */
+					hi = unicode(p);
+					p = nextutf(p);
+					if(hi<lo){ t = lo; lo = hi; hi = t; }
 				}
-				if(lo<=c && c<=hi) hit=1;
+				if(lo<=c && c<=hi)
+					hit = 1;
 			}
-			if(compl) hit=!hit;
-			if(!hit) return 0;
+			if(compl)
+				hit=!hit;
+			if(!hit)
+				return 0;
 			break;
 		}
 	}
 	return *s=='\0';
 }
-void globlist1(word *gl)
+
+void
+globlist1(word *gl)
 {
 	if(gl){
 		globlist1(gl->next);
 		glob(gl->word);
 	}
 }
-void globlist(void){
+
+void
+globlist(void)
+{
 	word *a;
-	globv=0;
+	globv = 0;
 	globlist1(runq->argv->words);
 	poplist();
 	pushlist();
 	if(globv){
-		for(a=globv;a->next;a=a->next);
-		a->next=runq->argv->words;
-		runq->argv->words=globv;
+		for(a = globv;a->next;a = a->next);
+		a->next = runq->argv->words;
+		runq->argv->words = globv;
 	}
 }
diff --git a/src/cmd/rc/havefork.c b/src/cmd/rc/havefork.c
index 6e4aa92..e81046d 100644
--- a/src/cmd/rc/havefork.c
+++ b/src/cmd/rc/havefork.c
@@ -1,5 +1,3 @@
-#include <u.h>
-#include <signal.h>
 #include "rc.h"
 #include "getflags.h"
 #include "exec.h"
@@ -13,9 +11,7 @@
 {
 	int null = open("/dev/null", 0);
 	int pid;
-	int tcpgrp, pgrp;
 	char npid[10];
-
 	if(null<0){
 		Xerror("Can't open /dev/null\n");
 		return;
@@ -26,12 +22,6 @@
 		Xerror("try again");
 		break;
 	case 0:
-		/*
-		 * Should make reads of tty fail, writes succeed.
-		 */
-		signal(SIGTTIN, SIG_IGN);
-		signal(SIGTTOU, SIG_IGN);
-
 		pushredir(ROPEN, null, 0);
 		start(runq->code, runq->pc+1, runq->local);
 		runq->ret = 0;
diff --git a/src/cmd/rc/havep9p.c b/src/cmd/rc/havep9p.c
new file mode 100644
index 0000000..29e2272
--- /dev/null
+++ b/src/cmd/rc/havep9p.c
@@ -0,0 +1,246 @@
+#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:
+		/*
+		 * 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:
+		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:
+		start(p->code, pc+2, runq->local);
+		runq->ret=0;
+		close(pfd[PRD]);
+		pushredir(ROPEN, pfd[PWR], lfd);
+		break;
+	default:
+		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;
+	}
+}
+
+void
+Xbackq(void)
+{
+	char wd[8193];
+	int c;
+	char *s, *ewd = &wd[8192], *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;
+	}
+	switch(pid = fork()){
+	case -1: Xerror("try again");
+		close(pfd[PRD]);
+		close(pfd[PWR]);
+		return;
+	case 0:
+		close(pfd[PRD]);
+		start(runq->code, runq->pc+1, runq->local);
+		pushredir(ROPEN, pfd[PWR], 1);
+		return;
+	default:
+		close(pfd[PWR]);
+		f=openfd(pfd[PRD]);
+		s=wd;
+		v=0;
+		while((c=rchr(f))!=EOF){
+			if(strchr(stop, c) || s==ewd){
+				if(s!=wd){
+					*s='\0';
+					v=newword(wd, v);
+					s=wd;
+				}
+			}
+			else *s++=c;
+		}
+		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;
+		}
+		runq->pc=runq->code[runq->pc].i;
+		return;
+	}
+}
+
+/*
+ * Who should wait for the exit from the fork?
+ */
+void
+Xpipefd(void)
+{
+	struct thread *p=runq;
+	int pc=p->pc;
+	char name[40];
+	int pfd[2];
+	int sidefd, mainfd;
+	if(pipe(pfd)<0){
+		Xerror("can't get pipe");
+		return;
+	}
+	if(p->code[pc].i==READ){
+		sidefd=pfd[PWR];
+		mainfd=pfd[PRD];
+	}
+	else{
+		sidefd=pfd[PRD];
+		mainfd=pfd[PWR];
+	}
+	switch(fork()){
+	case -1:
+		Xerror("try again");
+		break;
+	case 0:
+		start(p->code, pc+2, runq->local);
+		close(mainfd);
+		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
+		runq->ret=0;
+		break;
+	default:
+		close(sidefd);
+		pushredir(ROPEN, mainfd, mainfd);	/* isn't this a noop? */
+		strcpy(name, Fdprefix);
+		inttoascii(name+strlen(name), 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:
+		start(runq->code, runq->pc+1, runq->local);
+		runq->ret=0;
+		break;
+	default:
+		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:
+		pushword("exec");
+		execexec();
+		strcpy(buf, "can't exec: ");
+		n = strlen(buf);
+		errstr(buf+n, ERRMAX-n);
+		Exit(buf);
+	}
+	return pid;
+}
diff --git a/src/cmd/rc/here.c b/src/cmd/rc/here.c
index 2a0fe2f..17c6245 100644
--- a/src/cmd/rc/here.c
+++ b/src/cmd/rc/here.c
@@ -3,32 +3,37 @@
 #include "io.h"
 #include "fns.h"
 struct here *here, **ehere;
-int ser=0;
+int ser = 0;
 char tmp[]="/tmp/here0000.0000";
 char hex[]="0123456789abcdef";
 void psubst(io*, char*);
 void pstrs(io*, word*);
-void hexnum(char *p, int n)
+
+void
+hexnum(char *p, int n)
 {
 	*p++=hex[(n>>12)&0xF];
 	*p++=hex[(n>>8)&0xF];
 	*p++=hex[(n>>4)&0xF];
-	*p=hex[n&0xF];
+	*p = hex[n&0xF];
 }
-tree *heredoc(tree *tag)
+
+tree*
+heredoc(tree *tag)
 {
-	struct here *h=new(struct here);
-	if(tag->type!=WORD) yyerror("Bad here tag");
-	h->next=0;
+	struct here *h = new(struct here);
+	if(tag->type!=WORD)
+		yyerror("Bad here tag");
+	h->next = 0;
 	if(here)
-		*ehere=h;
+		*ehere = h;
 	else
-		here=h;
+		here = h;
 	ehere=&h->next;
-	h->tag=tag;
+	h->tag = tag;
 	hexnum(&tmp[9], getpid());
 	hexnum(&tmp[14], ser++);
-	h->name=strdup(tmp);
+	h->name = strdup(tmp);
 	return token(tmp, WORD);
 }
 /*
@@ -36,27 +41,32 @@
  * missubstitution, or a misrecognized EOF marker.
  */
 #define	NLINE	4096
-void readhere(void){
+
+void
+readhere(void)
+{
 	struct here *h, *nexth;
 	io *f;
 	char *s, *tag;
 	int c, subst;
 	char line[NLINE+1];
-	for(h=here;h;h=nexth){
+	for(h = here;h;h = nexth){
 		subst=!h->tag->quoted;
-		tag=h->tag->str;
-		c=Creat(h->name);
-		if(c<0) yyerror("can't create here document");
-		f=openfd(c);
-		s=line;
+		tag = h->tag->str;
+		c = Creat(h->name);
+		if(c<0)
+			yyerror("can't create here document");
+		f = openfd(c);
+		s = line;
 		pprompt();
-		while((c=rchr(runq->cmdfd))!=EOF){
+		while((c = rchr(runq->cmdfd))!=EOF){
 			if(c=='\n' || s==&line[NLINE]){
 				*s='\0';
-				if(strcmp(line, tag)==0) break;
-				if(subst) psubst(f, line);
+				if(tag && strcmp(line, tag)==0) break;
+				if(subst)
+					psubst(f, line);
 				else pstr(f, line);
-				s=line;
+				s = line;
 				if(c=='\n'){
 					pprompt();
 					pchr(f, c);
@@ -68,13 +78,15 @@
 		flush(f);
 		closeio(f);
 		cleanhere(h->name);
-		nexth=h->next;
+		nexth = h->next;
 		efree((char *)h);
 	}
-	here=0;
-	doprompt=1;
+	here = 0;
+	doprompt = 1;
 }
-void psubst(io *f, char *s)
+
+void
+psubst(io *f, char *s)
 {
 	char *t, *u;
 	int savec, n;
@@ -83,48 +95,55 @@
 		if(*s!='$'){
 			if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
 				pchr(f, *s++);
-				if(*s=='\0') break;
+				if(*s=='\0')
+					break;
 			}
 			else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
 				pchr(f, *s++);
-				if(*s=='\0') break;
+				if(*s=='\0')
+					break;
 				pchr(f, *s++);
-				if(*s=='\0') break;
+				if(*s=='\0')
+					break;
 			}
 			pchr(f, *s++);
 		}
 		else{
 			t=++s;
-			if(*t=='$') pchr(f, *t++);
+			if(*t=='$')
+				pchr(f, *t++);
 			else{
 				while(*t && idchr(*t)) t++;
 				savec=*t;
 				*t='\0';
-				n=0;
-				for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0';
+				n = 0;
+				for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
 				if(n && *u=='\0'){
-					star=vlook("*")->val;
+					star = vlook("*")->val;
 					if(star && 1<=n && n<=count(star)){
-						while(--n) star=star->next;
+						while(--n) star = star->next;
 						pstr(f, star->word);
 					}
 				}
 				else
 					pstrs(f, vlook(s)->val);
-				*t=savec;
-				if(savec=='^') t++;
+				*t = savec;
+				if(savec=='^')
+					t++;
 			}
-			s=t;
+			s = t;
 		}
 	}
 }
-void pstrs(io *f, word *a)
+
+void
+pstrs(io *f, word *a)
 {
 	if(a){
 		while(a->next && a->next->word){
 			pstr(f, a->word);
 			pchr(f, ' ');
-			a=a->next;
+			a = a->next;
 		}
 		pstr(f, a->word);
 	}
diff --git a/src/cmd/rc/io.c b/src/cmd/rc/io.c
index c360b4a..3ad1e2d 100644
--- a/src/cmd/rc/io.c
+++ b/src/cmd/rc/io.c
@@ -2,68 +2,121 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-int pfmtnest=0;
-void pfmt(io *f, char *fmt, ...){
+int pfmtnest = 0;
+
+void
+pfmt(io *f, char *fmt, ...)
+{
 	va_list ap;
 	char err[ERRMAX];
 	va_start(ap, fmt);
 	pfmtnest++;
 	for(;*fmt;fmt++)
-		if(*fmt!='%') pchr(f, *fmt);
+		if(*fmt!='%')
+			pchr(f, *fmt);
 		else switch(*++fmt){
-		case '\0': va_end(ap); return;
-		case 'c': pchr(f, va_arg(ap, int)); break;
-		case 'd': pdec(f, va_arg(ap, int)); break;
-		case 'o': poct(f, va_arg(ap, unsigned)); break;
-		case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/
-		case 'Q': pquo(f, va_arg(ap, char *)); break;
-		case 'q': pwrd(f, va_arg(ap, char *)); break;
-		case 'r': errstr(err, sizeof err); pstr(f, err); break;
-		case 's': pstr(f, va_arg(ap, char *)); break;
-		case 't': pcmd(f, va_arg(ap, struct tree *)); break;
-		case 'v': pval(f, va_arg(ap, struct word *)); break;
-		default: pchr(f, *fmt); break;
+		case '\0':
+			va_end(ap);
+			return;
+		case 'c':
+			pchr(f, va_arg(ap, int));
+			break;
+		case 'd':
+			pdec(f, va_arg(ap, int));
+			break;
+		case 'o':
+			poct(f, va_arg(ap, unsigned));
+			break;
+		case 'p':
+			pptr(f, va_arg(ap, void*));
+			break;
+		case 'Q':
+			pquo(f, va_arg(ap, char *));
+			break;
+		case 'q':
+			pwrd(f, va_arg(ap, char *));
+			break;
+		case 'r':
+			errstr(err, sizeof err); pstr(f, err);
+			break;
+		case 's':
+			pstr(f, va_arg(ap, char *));
+			break;
+		case 't':
+			pcmd(f, va_arg(ap, struct tree *));
+			break;
+		case 'v':
+			pval(f, va_arg(ap, struct word *));
+			break;
+		default:
+			pchr(f, *fmt);
+			break;
 		}
 	va_end(ap);
-	if(--pfmtnest==0) flush(f);
+	if(--pfmtnest==0)
+		flush(f);
 }
-void pchr(io *b, int c)
+
+void
+pchr(io *b, int c)
 {
-	if(b->bufp==b->ebuf) fullbuf(b, c);
+	if(b->bufp==b->ebuf)
+		fullbuf(b, c);
 	else *b->bufp++=c;
 }
-int rchr(io *b)
+
+int
+rchr(io *b)
 {
-	if(b->bufp==b->ebuf) return emptybuf(b);
+	if(b->bufp==b->ebuf)
+		return emptybuf(b);
 	return *b->bufp++ & 0xFF;
 }
 
-void pquo(io *f, char *s)
+void
+pquo(io *f, char *s)
 {
 	pchr(f, '\'');
 	for(;*s;s++)
-		if(*s=='\'') pfmt(f, "''");
+		if(*s=='\'')
+			pfmt(f, "''");
 		else pchr(f, *s);
 	pchr(f, '\'');
 }
-void pwrd(io *f, char *s)
+
+void
+pwrd(io *f, char *s)
 {
 	char *t;
-	for(t=s;*t;t++) if(!wordchr(*t)) break;
-	if(t==s || *t) pquo(f, s);
+	for(t = s;*t;t++) if(!wordchr(*t)) break;
+	if(t==s || *t)
+		pquo(f, s);
 	else pstr(f, s);
 }
-void phex(io *f, long p)
+
+void
+pptr(io *f, void *v)
 {
 	int n;
-	for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+	uintptr p;
+
+	p = (uintptr)v;
+	if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
+		for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+
+	for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
 }
-void pstr(io *f, char *s)
+
+void
+pstr(io *f, char *s)
 {
-	if(s==0) s="(null)";
+	if(s==0)
+		s="(null)";
 	while(*s) pchr(f, *s++);
 }
-void pdec(io *f, long n)
+
+void
+pdec(io *f, int n)
 {
 	if(n<0){
 		n=-n;
@@ -73,110 +126,136 @@
 			return;
 		}
 		/* n is two's complement minimum integer */
-		n=1-n;
+		n = 1-n;
 		pchr(f, '-');
 		pdec(f, n/10);
 		pchr(f, n%10+'1');
 		return;
 	}
-	if(n>9) pdec(f, n/10);
+	if(n>9)
+		pdec(f, n/10);
 	pchr(f, n%10+'0');
 }
-void poct(io *f, ulong n)
+
+void
+poct(io *f, unsigned n)
 {
-	if(n>7) poct(f, n>>3);
+	if(n>7)
+		poct(f, n>>3);
 	pchr(f, (n&7)+'0');
 }
-void pval(io *f, word *a)
+
+void
+pval(io *f, word *a)
 {
 	if(a){
 		while(a->next && a->next->word){
 			pwrd(f, a->word);
 			pchr(f, ' ');
-			a=a->next;
+			a = a->next;
 		}
 		pwrd(f, a->word);
 	}
 }
-int fullbuf(io *f, int c)
+
+int
+fullbuf(io *f, int c)
 {
 	flush(f);
 	return *f->bufp++=c;
 }
-void flush(io *f)
+
+void
+flush(io *f)
 {
 	int n;
 	char *s;
 	if(f->strp){
-		n=f->ebuf-f->strp;
-		f->strp=realloc(f->strp, n+101);
-		if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101);
-		f->bufp=f->strp+n;
-		f->ebuf=f->bufp+100;
-		for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+		n = f->ebuf-f->strp;
+		f->strp = realloc(f->strp, n+101);
+		if(f->strp==0)
+			panic("Can't realloc %d bytes in flush!", n+101);
+		f->bufp = f->strp+n;
+		f->ebuf = f->bufp+100;
+		for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
 	}
 	else{
-		n=f->bufp-f->buf;
+		n = f->bufp-f->buf;
 		if(n && Write(f->fd, f->buf, n) < 0){
 			Write(3, "Write error\n", 12);
-			if(ntrap) dotrap();
+			if(ntrap)
+				dotrap();
 		}
-		f->bufp=f->buf;
-		f->ebuf=f->buf+NBUF;
+		f->bufp = f->buf;
+		f->ebuf = f->buf+NBUF;
 	}
 }
-io *openfd(int fd){
-	io *f;
-	f=new(struct io);
-	f->fd=fd;
-	f->bufp=f->ebuf=f->buf;
-	f->strp=0;
+
+io*
+openfd(int fd)
+{
+	io *f = new(struct io);
+	f->fd = fd;
+	f->bufp = f->ebuf = f->buf;
+	f->strp = 0;
 	return f;
 }
-io *openstr(void){
-	io *f=new(struct io);
+
+io*
+openstr(void)
+{
+	io *f = new(struct io);
 	char *s;
 	f->fd=-1;
-	f->bufp=f->strp=emalloc(101);
-	f->ebuf=f->bufp+100;
-	for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+	f->bufp = f->strp = emalloc(101);
+	f->ebuf = f->bufp+100;
+	for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
 	return f;
 }
 /*
  * Open a corebuffer to read.  EOF occurs after reading len
  * characters from buf.
  */
-io *opencore(char *s, int len)
+
+io*
+opencore(char *s, int len)
 {
-	io *f=new(struct io);
-	char *buf=emalloc(len);
+	io *f = new(struct io);
+	char *buf = emalloc(len);
 	f->fd= -1 /*open("/dev/null", 0)*/;
-	f->bufp=f->strp=buf;
-	f->ebuf=buf+len;
+	f->bufp = f->strp = buf;
+	f->ebuf = buf+len;
 	Memcpy(buf, s, len);
 	return f;
 }
-/*
-void rewind(io *io)
+
+void
+rewind(io *io)
 {
-	if(io->fd==-1) io->bufp=io->strp;
+	if(io->fd==-1)
+		io->bufp = io->strp;
 	else{
-		io->bufp=io->ebuf=io->buf;
+		io->bufp = io->ebuf = io->buf;
 		Seek(io->fd, 0L, 0);
 	}
 }
-*/
-void closeio(io *io)
+
+void
+closeio(io *io)
 {
-	if(io->fd>=0) close(io->fd);
-	if(io->strp) efree(io->strp);
+	if(io->fd>=0)
+		close(io->fd);
+	if(io->strp)
+		efree(io->strp);
 	efree((char *)io);
 }
-int emptybuf(io *f)
+
+int
+emptybuf(io *f)
 {
 	int n;
-	if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF;
-	f->bufp=f->buf;
-	f->ebuf=f->buf+n;
+	if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
+	f->bufp = f->buf;
+	f->ebuf = f->buf+n;
 	return *f->bufp++&0xff;
 }
diff --git a/src/cmd/rc/io.h b/src/cmd/rc/io.h
index ec51187..21cc6b8 100644
--- a/src/cmd/rc/io.h
+++ b/src/cmd/rc/io.h
@@ -18,9 +18,9 @@
 void closeio(io*);
 void flush(io*);
 int fullbuf(io*, int);
-void pdec(io*, long);
-void poct(io*, ulong);
-void phex(io*, long);
+void pdec(io*, int);
+void poct(io*, unsigned);
+void pptr(io*, void*);
 void pquo(io*, char*);
 void pwrd(io*, char*);
 void pstr(io*, char*);
diff --git a/src/cmd/rc/lex.c b/src/cmd/rc/lex.c
index b0e27eb..3693483 100644
--- a/src/cmd/rc/lex.c
+++ b/src/cmd/rc/lex.c
@@ -4,11 +4,15 @@
 #include "getflags.h"
 #include "fns.h"
 int getnext(void);
-int wordchr(int c)
+
+int
+wordchr(int c)
 {
 	return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
 }
-int idchr(int c)
+
+int
+idchr(int c)
 {
 	/*
 	 * Formerly:
@@ -17,127 +21,170 @@
 	 */
 	return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
 }
-int future=EOF;
-int doprompt=1;
+int future = EOF;
+int doprompt = 1;
 int inquote;
+int incomm;
 /*
  * Look ahead in the input stream
  */
-int nextc(void){
-	if(future==EOF) future=getnext();
+
+int
+nextc(void)
+{
+	if(future==EOF)
+		future = getnext();
 	return future;
 }
 /*
  * Consume the lookahead character.
  */
-int advance(void){
-	int c=nextc();
-	lastc=future;
-	future=EOF;
+
+int
+advance(void)
+{
+	int c = nextc();
+	lastc = future;
+	future = EOF;
 	return c;
 }
 /*
  * read a character from the input stream
  */	
-int getnext(void){
-	register int c;
-	static int peekc=EOF;
+
+int
+getnext(void)
+{
+	int c;
+	static int peekc = EOF;
 	if(peekc!=EOF){
-		c=peekc;
-		peekc=EOF;
+		c = peekc;
+		peekc = EOF;
 		return c;
 	}
-	if(runq->eof) return EOF;
-	if(doprompt) pprompt();
-	c=rchr(runq->cmdfd);
+	if(runq->eof)
+		return EOF;
+	if(doprompt)
+		pprompt();
+	c = rchr(runq->cmdfd);
 	if(!inquote && c=='\\'){
-		c=rchr(runq->cmdfd);
-		if(c=='\n'){
-			doprompt=1;
+		c = rchr(runq->cmdfd);
+		if(c=='\n' && !incomm){		/* don't continue a comment */
+			doprompt = 1;
 			c=' ';
 		}
 		else{
-			peekc=c;
+			peekc = c;
 			c='\\';
 		}
 	}
-	doprompt=doprompt || c=='\n' || c==EOF;
-	if(c==EOF) runq->eof++;
+	doprompt = doprompt || c=='\n' || c==EOF;
+	if(c==EOF)
+		runq->eof++;
 	else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
 	return c;
 }
-void pprompt(void){
+
+void
+pprompt(void)
+{
 	var *prompt;
 	if(runq->iflag){
 		pstr(err, promptstr);
 		flush(err);
-		prompt=vlook("prompt");
+		prompt = vlook("prompt");
 		if(prompt->val && prompt->val->next)
-			promptstr=prompt->val->next->word;
+			promptstr = prompt->val->next->word;
 		else
 			promptstr="\t";
 	}
 	runq->lineno++;
-	doprompt=0;
+	doprompt = 0;
 }
-void skipwhite(void){
+
+void
+skipwhite(void)
+{
 	int c;
 	for(;;){
-		c=nextc();
-		if(c=='#'){	/* Why did this used to be  if(!inquote && c=='#') ?? */
+		c = nextc();
+		/* Why did this used to be  if(!inquote && c=='#') ?? */
+		if(c=='#'){
+			incomm = 1;
 			for(;;){
-				c=nextc();
-				if(c=='\n' || c==EOF) break;
+				c = nextc();
+				if(c=='\n' || c==EOF) {
+					incomm = 0;
+					break;
+				}
 				advance();
 			}
 		}
-		if(c==' ' || c=='\t') advance();
+		if(c==' ' || c=='\t')
+			advance();
 		else return;
 	}
 }
-void skipnl(void){
-	register int c;
+
+void
+skipnl(void)
+{
+	int c;
 	for(;;){
 		skipwhite();
-		c=nextc();
-		if(c!='\n') return;
+		c = nextc();
+		if(c!='\n')
+			return;
 		advance();
 	}
 }
-int nextis(int c){
+
+int
+nextis(int c)
+{
 	if(nextc()==c){
 		advance();
 		return 1;
 	}
 	return 0;
 }
-char *addtok(char *p, int val){
-	if(p==0) return 0;
+
+char*
+addtok(char *p, int val)
+{
+	if(p==0)
+		return 0;
 	if(p==&tok[NTOK-1]){
-		*p=0;
+		*p = 0;
 		yyerror("token buffer too short");
 		return 0;
 	}
 	*p++=val;
 	return p;
 }
-char *addutf(char *p, int c){
-	p=addtok(p, c);
+
+char*
+addutf(char *p, int c)
+{
+	p = addtok(p, c);
 	if(twobyte(c))	 /* 2-byte escape */
 		return addtok(p, advance());
 	if(threebyte(c)){	/* 3-byte escape */
-		p=addtok(p, advance());
+		p = addtok(p, advance());
 		return addtok(p, advance());
 	}
 	return p;
 }
 int lastdol;	/* was the last token read '$' or '$#' or '"'? */
 int lastword;	/* was the last token read a word or compound word terminator? */
-int yylex(void){
-	register int c, d=nextc();
-	register char *w=tok;
-	register struct tree *t;
-	yylval.tree=0;
+
+int
+yylex(void)
+{
+	int c, d = nextc();
+	char *w = tok;
+	struct tree *t;
+	yylval.tree = 0;
 	/*
 	 * Embarassing sneakiness:  if the last token read was a quoted or unquoted
 	 * WORD then we alter the meaning of what follows.  If the next character
@@ -146,7 +193,7 @@
 	 * we insert a `^' before it.
 	 */
 	if(lastword){
-		lastword=0;
+		lastword = 0;
 		if(d=='('){
 			advance();
 			strcpy(tok, "( [SUB]");
@@ -157,15 +204,15 @@
 			return '^';
 		}
 	}
-	inquote=0;
+	inquote = 0;
 	skipwhite();
-	switch(c=advance()){
+	switch(c = advance()){
 	case EOF:
-		lastdol=0;
+		lastdol = 0;
 		strcpy(tok, "EOF");
 		return EOF;
 	case '$':
-		lastdol=1;
+		lastdol = 1;
 		if(nextis('#')){
 			strcpy(tok, "$#");
 			return COUNT;
@@ -177,7 +224,7 @@
 		strcpy(tok, "$");
 		return '$';
 	case '&':
-		lastdol=0;
+		lastdol = 0;
 		if(nextis('&')){
 			skipnl();
 			strcpy(tok, "&&");
@@ -186,7 +233,7 @@
 		strcpy(tok, "&");
 		return '&';
 	case '|':
-		lastdol=0;
+		lastdol = 0;
 		if(nextis(c)){
 			skipnl();
 			strcpy(tok, "||");
@@ -194,7 +241,7 @@
 		}
 	case '<':
 	case '>':
-		lastdol=0;
+		lastdol = 0;
 		/*
 		 * funny redirection tokens:
 		 *	redir:	arrow | arrow '[' fd ']'
@@ -204,121 +251,128 @@
 		 * some possibilities are nonsensical and get a message.
 		 */
 		*w++=c;
-		t=newtree();
+		t = newtree();
 		switch(c){
 		case '|':
-			t->type=PIPE;
-			t->fd0=1;
-			t->fd1=0;
+			t->type = PIPE;
+			t->fd0 = 1;
+			t->fd1 = 0;
 			break;
 		case '>':
-			t->type=REDIR;
+			t->type = REDIR;
 			if(nextis(c)){
-				t->rtype=APPEND;
+				t->rtype = APPEND;
 				*w++=c;
 			}
-			else t->rtype=WRITE;
-			t->fd0=1;
+			else t->rtype = WRITE;
+			t->fd0 = 1;
 			break;
 		case '<':
-			t->type=REDIR;
+			t->type = REDIR;
 			if(nextis(c)){
-				t->rtype=HERE;
+				t->rtype = HERE;
 				*w++=c;
-			}
-			else t->rtype=READ;
-			t->fd0=0;
+			} else if (nextis('>')){
+				t->rtype = RDWR;
+				*w++=c;
+			} else t->rtype = READ;
+			t->fd0 = 0;
 			break;
 		}
 		if(nextis('[')){
 			*w++='[';
-			c=advance();
+			c = advance();
+			*w++=c;
 			if(c<'0' || '9'<c){
 			RedirErr:
-				*w++ = c;
-				*w=0;
+				*w = 0;
 				yyerror(t->type==PIPE?"pipe syntax"
 						:"redirection syntax");
 				return EOF;
 			}
-			t->fd0=0;
+			t->fd0 = 0;
 			do{
-				t->fd0=t->fd0*10+c-'0';
+				t->fd0 = t->fd0*10+c-'0';
 				*w++=c;
-				c=advance();
+				c = advance();
 			}while('0'<=c && c<='9');
 			if(c=='='){
 				*w++='=';
-				if(t->type==REDIR) t->type=DUP;
-				c=advance();
+				if(t->type==REDIR)
+					t->type = DUP;
+				c = advance();
 				if('0'<=c && c<='9'){
-					t->rtype=DUPFD;
-					t->fd1=t->fd0;
-					t->fd0=0;
+					t->rtype = DUPFD;
+					t->fd1 = t->fd0;
+					t->fd0 = 0;
 					do{
-						t->fd0=t->fd0*10+c-'0';
+						t->fd0 = t->fd0*10+c-'0';
 						*w++=c;
-						c=advance();
+						c = advance();
 					}while('0'<=c && c<='9');
 				}
 				else{
-					if(t->type==PIPE) goto RedirErr;
-					t->rtype=CLOSE;
+					if(t->type==PIPE)
+						goto RedirErr;
+					t->rtype = CLOSE;
 				}
 			}
-			*w=0;
 			if(c!=']'
 			|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
 				goto RedirErr;
 			*w++=']';
 		}
 		*w='\0';
-		yylval.tree=t;
-		if(t->type==PIPE) skipnl();
+		yylval.tree = t;
+		if(t->type==PIPE)
+			skipnl();
 		return t->type;
 	case '\'':
-		lastdol=0;
-		lastword=1;
-		inquote=1;
+		lastdol = 0;
+		lastword = 1;
+		inquote = 1;
 		for(;;){
-			c=advance();
-			if(c==EOF) break;
+			c = advance();
+			if(c==EOF)
+				break;
 			if(c=='\''){
 				if(nextc()!='\'')
 					break;
 				advance();
 			}
-			w=addutf(w, c);
+			w = addutf(w, c);
 		}
-		if(w!=0) *w='\0';
-		t=token(tok, WORD);
-		t->quoted=1;
-		yylval.tree=t;
+		if(w!=0)
+			*w='\0';
+		t = token(tok, WORD);
+		t->quoted = 1;
+		yylval.tree = t;
 		return t->type;
 	}
 	if(!wordchr(c)){
-		lastdol=0;
-		tok[0]=c;
+		lastdol = 0;
+		tok[0] = c;
 		tok[1]='\0';
 		return c;
 	}
 	for(;;){
 		/* next line should have (char)c==GLOB, but ken's compiler is broken */
 		if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
-			w=addtok(w, GLOB);
-		w=addutf(w, c);
-		c=nextc();
+			w = addtok(w, GLOB);
+		w = addutf(w, c);
+		c = nextc();
 		if(lastdol?!idchr(c):!wordchr(c)) break;
 		advance();
 	}
 
-	lastword=1;
-	lastdol=0;
-	if(w!=0) *w='\0';
-	t=klook(tok);
-	if(t->type!=WORD) lastword=0;
-	t->quoted=0;
-	yylval.tree=t;
+	lastword = 1;
+	lastdol = 0;
+	if(w!=0)
+		*w='\0';
+	t = klook(tok);
+	if(t->type!=WORD)
+		lastword = 0;
+	t->quoted = 0;
+	yylval.tree = t;
 	return t->type;
 }
-
diff --git a/src/cmd/rc/mkfile b/src/cmd/rc/mkfile
index b3d8ffd..d1144e8 100644
--- a/src/cmd/rc/mkfile
+++ b/src/cmd/rc/mkfile
@@ -20,6 +20,7 @@
 	var.$O\
 	y.tab.$O\
 	plan9ish.$O\
+	havep9p.$O\
 
 HFILES=\
 	rc.h\
diff --git a/src/cmd/rc/pcmd.c b/src/cmd/rc/pcmd.c
index 0f84298..8caf60a 100644
--- a/src/cmd/rc/pcmd.c
+++ b/src/cmd/rc/pcmd.c
@@ -5,39 +5,66 @@
 #define	c0	t->child[0]
 #define	c1	t->child[1]
 #define	c2	t->child[2]
-void pdeglob(io *f, char *s)
+
+void
+pdeglob(io *f, char *s)
 {
 	while(*s){
-		if(*s==GLOB) s++;
+		if(*s==GLOB)
+			s++;
 		pchr(f, *s++);
 	}
 }
-void pcmd(io *f, tree *t)
+
+void
+pcmd(io *f, tree *t)
 {
-	if(t==0) return;
+	if(t==0)
+		return;
 	switch(t->type){
-	default:	pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break;
-	case '$':	pfmt(f, "$%t", c0); break;
-	case '"':	pfmt(f, "$\"%t", c0); break;
-	case '&':	pfmt(f, "%t&", c0); break;
-	case '^':	pfmt(f, "%t^%t", c0, c1); break;
-	case '`':	pfmt(f, "`%t", c0); break;
-	case ANDAND:	pfmt(f, "%t && %t", c0, c1); break;
-	case BANG:	pfmt(f, "! %t", c0); break;
-	case BRACE:	pfmt(f, "{%t}", c0); break;
-	case COUNT:	pfmt(f, "$#%t", c0); break;
-	case FN:	pfmt(f, "fn %t %t", c0, c1); break;
-	case IF:	pfmt(f, "if%t%t", c0, c1); break;
-	case NOT:	pfmt(f, "if not %t", c0); break;
-	case OROR:	pfmt(f, "%t || %t", c0, c1); break;
+	default:	pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
+	break;
+	case '$':	pfmt(f, "$%t", c0);
+	break;
+	case '"':	pfmt(f, "$\"%t", c0);
+	break;
+	case '&':	pfmt(f, "%t&", c0);
+	break;
+	case '^':	pfmt(f, "%t^%t", c0, c1);
+	break;
+	case '`':	pfmt(f, "`%t", c0);
+	break;
+	case ANDAND:	pfmt(f, "%t && %t", c0, c1);
+	break;
+	case BANG:	pfmt(f, "! %t", c0);
+	break;
+	case BRACE:	pfmt(f, "{%t}", c0);
+	break;
+	case COUNT:	pfmt(f, "$#%t", c0);
+	break;
+	case FN:	pfmt(f, "fn %t %t", c0, c1);
+	break;
+	case IF:	pfmt(f, "if%t%t", c0, c1);
+	break;
+	case NOT:	pfmt(f, "if not %t", c0);
+	break;
+	case OROR:	pfmt(f, "%t || %t", c0, c1);
+	break;
 	case PCMD:
-	case PAREN:	pfmt(f, "(%t)", c0); break;
-	case SUB:	pfmt(f, "$%t(%t)", c0, c1); break;
-	case SIMPLE:	pfmt(f, "%t", c0); break;
-	case SUBSHELL:	pfmt(f, "@ %t", c0); break;
-	case SWITCH:	pfmt(f, "switch %t %t", c0, c1); break;
-	case TWIDDLE:	pfmt(f, "~ %t %t", c0, c1); break;
-	case WHILE:	pfmt(f, "while %t%t", c0, c1); break;
+	case PAREN:	pfmt(f, "(%t)", c0);
+	break;
+	case SUB:	pfmt(f, "$%t(%t)", c0, c1);
+	break;
+	case SIMPLE:	pfmt(f, "%t", c0);
+	break;
+	case SUBSHELL:	pfmt(f, "@ %t", c0);
+	break;
+	case SWITCH:	pfmt(f, "switch %t %t", c0, c1);
+	break;
+	case TWIDDLE:	pfmt(f, "~ %t %t", c0, c1);
+	break;
+	case WHILE:	pfmt(f, "while %t%t", c0, c1);
+	break;
 	case ARGLIST:
 		if(c0==0)
 			pfmt(f, "%t", c1);
@@ -48,22 +75,26 @@
 		break;
 	case ';':
 		if(c0){
-			if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
+			if(c1)
+				pfmt(f, "%t%c%t", c0, nl, c1);
 			else pfmt(f, "%t", c0);
 		}
 		else pfmt(f, "%t", c1);
 		break;
 	case WORDS:
-		if(c0) pfmt(f, "%t ", c0);
+		if(c0)
+			pfmt(f, "%t ", c0);
 		pfmt(f, "%t", c1);
 		break;
 	case FOR:
 		pfmt(f, "for(%t", c0);
-		if(c1) pfmt(f, " in %t", c1);
+		if(c1)
+			pfmt(f, " in %t", c1);
 		pfmt(f, ")%t", c2);
 		break;
 	case WORD:
-		if(t->quoted) pfmt(f, "%Q", t->str);
+		if(t->quoted)
+			pfmt(f, "%Q", t->str);
 		else pdeglob(f, t->str);
 		break;
 	case DUP:
@@ -79,27 +110,35 @@
 		case HERE:
 			pchr(f, '<');
 		case READ:
+		case RDWR:
 			pchr(f, '<');
-			if(t->fd0!=0) pfmt(f, "[%d]", t->fd0);
+			if(t->rtype==RDWR)
+				pchr(f, '>');
+			if(t->fd0!=0)
+				pfmt(f, "[%d]", t->fd0);
 			break;
 		case APPEND:
 			pchr(f, '>');
 		case WRITE:
 			pchr(f, '>');
-			if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+			if(t->fd0!=1)
+				pfmt(f, "[%d]", t->fd0);
 			break;
 		}
 		pfmt(f, "%t", c0);
-		if(c1) pfmt(f, " %t", c1);
+		if(c1)
+			pfmt(f, " %t", c1);
 		break;
 	case '=':
 		pfmt(f, "%t=%t", c0, c1);
-		if(c2) pfmt(f, " %t", c2);
+		if(c2)
+			pfmt(f, " %t", c2);
 		break;
 	case PIPE:
 		pfmt(f, "%t|", c0);
 		if(t->fd1==0){
-			if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+			if(t->fd0!=1)
+				pfmt(f, "[%d]", t->fd0);
 		}
 		else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
 		pfmt(f, "%t", c1);
diff --git a/src/cmd/rc/pfnc.c b/src/cmd/rc/pfnc.c
index a4606e7..3f2b4c9 100644
--- a/src/cmd/rc/pfnc.c
+++ b/src/cmd/rc/pfnc.c
@@ -5,7 +5,7 @@
 struct{
 	void (*f)(void);
 	char *name;
-}fname[]={
+}fname[] = {
 	Xappend, "Xappend",
 	Xasync, "Xasync",
 	Xbang, "Xbang",
@@ -18,6 +18,7 @@
 	Xjump, "Xjump",
 	Xmark, "Xmark",
 	Xpopm, "Xpopm",
+	Xrdwr, "Xrdwr",
 	Xread, "Xread",
 	Xreturn, "Xreturn",
 	Xtrue, "Xtrue",
@@ -50,18 +51,21 @@
 	Xrdfn, "Xrdfn",
 	Xqdol, "Xqdol",
 0};
-void pfnc(io *fd, thread *t)
+
+void
+pfnc(io *fd, thread *t)
 {
 	int i;
-	void (*fn)(void)=t->code[t->pc].f;
+	void (*fn)(void) = t->code[t->pc].f;
 	list *a;
 	pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
-	for(i=0;fname[i].f;i++) if(fname[i].f==fn){
+	for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
 		pstr(fd, fname[i].name);
 		break;
 	}
-	if(!fname[i].f) pfmt(fd, "%p", fn);
-	for(a=t->argv;a;a=a->next) pfmt(fd, " (%v)", a->words);
+	if(!fname[i].f)
+		pfmt(fd, "%p", fn);
+	for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
 	pchr(fd, '\n');
 	flush(fd);
 }
diff --git a/src/cmd/rc/plan9ish.c b/src/cmd/rc/plan9ish.c
index 4e1ab7c..1e89653 100644
--- a/src/cmd/rc/plan9ish.c
+++ b/src/cmd/rc/plan9ish.c
@@ -411,9 +411,11 @@
 	close(f);
 	return -1;
 }
-int Readdir(int f, char *p)
+int Readdir(int f, char *p, int onlydirs)
 {
 	int n;
+	USED(onlydirs);	/* only advisory */
+
 	if(f<0 || f>=NFD)
 		return 0;
 	if(dir[f].i==dir[f].n){	/* read */
diff --git a/src/cmd/rc/rc.h b/src/cmd/rc/rc.h
index 3e79617..f95b528 100644
--- a/src/cmd/rc/rc.h
+++ b/src/cmd/rc/rc.h
@@ -80,6 +80,7 @@
 #define	HERE	4
 #define	DUPFD	5
 #define	CLOSE	6
+#define	RDWR	7
 struct var{
 	char *name;		/* ascii name */
 	word *val;	/* value */
diff --git a/src/cmd/rc/simple.c b/src/cmd/rc/simple.c
index 154678f..15814c5 100644
--- a/src/cmd/rc/simple.c
+++ b/src/cmd/rc/simple.c
@@ -15,22 +15,24 @@
 	while(c->f==Xpopredir) c++;
 	return c->f==Xexit;
 }
-void Xsimple(void){
+
+void
+Xsimple(void)
+{
 	word *a;
-	thread *p=runq;
+	thread *p = runq;
 	var *v;
 	struct builtin *bp;
-	int pid, n;
-	char buf[ERRMAX];
+	int pid;
 	globlist();
-	a=runq->argv->words;
+	a = runq->argv->words;
 	if(a==0){
 		Xerror1("empty argument list");
 		return;
 	}
 	if(flag['x'])
 		pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
-	v=gvlook(a->word);
+	v = gvlook(a->word);
 	if(v->fn)
 		execfunc(v);
 	else{
@@ -41,10 +43,10 @@
 				poplist();
 				return;
 			}
-			a=a->next;
+			a = a->next;
 			popword();
 		}
-		for(bp=Builtin;bp->name;bp++)
+		for(bp = Builtin;bp->name;bp++)
 			if(strcmp(a->word, bp->name)==0){
 				(*bp->fnc)();
 				return;
@@ -58,30 +60,22 @@
 		else{
 			flush(err);
 			Updenv();	/* necessary so changes don't go out again */
-			switch(pid=fork()){
-			case -1:
+			if((pid = execforkexec()) < 0){
 				Xerror("try again");
 				return;
-			case 0:
-				pushword("exec");
-				execexec();
-				strcpy(buf, "can't exec: ");
-				n = strlen(buf);
-				errstr(buf+n, ERRMAX-n);
-				Exit(buf);
-			default:
-				kidpid = pid;
-				poplist();
-				/* interrupts don't get us out */
-				while(Waitfor(pid, 1) < 0)
-					;
-				kidpid = 0;
 			}
+
+			/* interrupts don't get us out */
+			poplist();
+			while(Waitfor(pid, 1) < 0)
+				;
 		}
 	}
 }
-struct word nullpath={ "", 0};
-void doredir(redir *rp)
+struct word nullpath = { "", 0};
+
+void
+doredir(redir *rp)
 {
 	if(rp){
 		doredir(rp->next);
@@ -92,22 +86,32 @@
 				close(rp->from);
 			}
 			break;
-		case RDUP: Dup(rp->from, rp->to); break;
-		case RCLOSE: close(rp->from); break;
+		case RDUP:
+			Dup(rp->from, rp->to);
+			break;
+		case RCLOSE:
+			close(rp->from);
+			break;
 		}
 	}
 }
-word *searchpath(char *w){
+
+word*
+searchpath(char *w)
+{
 	word *path;
 	if(strncmp(w, "/", 1)==0
 /*	|| strncmp(w, "#", 1)==0 */
 	|| strncmp(w, "./", 2)==0
 	|| strncmp(w, "../", 3)==0
-	|| (path=vlook("path")->val)==0)
+	|| (path = vlook("path")->val)==0)
 		path=&nullpath;
 	return path;
 }
-void execexec(void){
+
+void
+execexec(void)
+{
 	popword();	/* "exec" */
 	if(runq->argv->words==0){
 		Xerror1("empty argument list");
@@ -117,19 +121,24 @@
 	Execute(runq->argv->words, searchpath(runq->argv->words->word));
 	poplist();
 }
-void execfunc(var *func)
+
+void
+execfunc(var *func)
 {
 	word *starval;
 	popword();
-	starval=runq->argv->words;
-	runq->argv->words=0;
+	starval = runq->argv->words;
+	runq->argv->words = 0;
 	poplist();
 	start(func->fn, func->pc, (struct var *)0);
-	runq->local=newvar(strdup("*"), runq->local);
-	runq->local->val=starval;
-	runq->local->changed=1;
+	runq->local = newvar(strdup("*"), runq->local);
+	runq->local->val = starval;
+	runq->local->changed = 1;
 }
-int dochdir(char *word){
+
+int
+dochdir(char *word)
+{
 	/* report to /dev/wdir if it exists and we're interactive */
 	static int wdirfd = -2;
 	if(chdir(word)<0) return -1;
@@ -141,21 +150,26 @@
 	}
 	return 1;
 }
-void execcd(void){
-	word *a=runq->argv->words;
+
+void
+execcd(void)
+{
+	word *a = runq->argv->words;
 	word *cdpath;
 	char dir[512];
 	setstatus("can't cd");
-	cdpath=vlook("cdpath")->val;
+	cdpath = vlook("cdpath")->val;
 	switch(count(a)){
 	default:
 		pfmt(err, "Usage: cd [directory]\n");
 		break;
 	case 2:
-		if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
-		for(;cdpath;cdpath=cdpath->next){
+		if(a->next->word[0]=='/' || cdpath==0)
+			cdpath=&nullpath;
+		for(;cdpath;cdpath = cdpath->next){
 			strcpy(dir, cdpath->word);
-			if(dir[0]) strcat(dir, "/");
+			if(dir[0])
+				strcat(dir, "/");
 			strcat(dir, a->next->word);
 			if(dochdir(dir)>=0){
 				if(strlen(cdpath->word)
@@ -165,10 +179,11 @@
 				break;
 			}
 		}
-		if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
+		if(cdpath==0)
+			pfmt(err, "Can't cd %s: %r\n", a->next->word);
 		break;
 	case 1:
-		a=vlook("HOME")->val;
+		a = vlook("home")->val;
 		if(count(a)>=1){
 			if(dochdir(a->word)>=0)
 				setstatus("");
@@ -181,14 +196,22 @@
 	}
 	poplist();
 }
-void execexit(void){
+
+void
+execexit(void)
+{
 	switch(count(runq->argv->words)){
-	default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
-	case 2: setstatus(runq->argv->words->next->word);
+	default:
+		pfmt(err, "Usage: exit [status]\nExiting anyway\n");
+	case 2:
+		setstatus(runq->argv->words->next->word);
 	case 1:	Xexit();
 	}
 }
-void execshift(void){
+
+void
+execshift(void)
+{
 	int n;
 	word *a;
 	var *star;
@@ -198,72 +221,87 @@
 		setstatus("shift usage");
 		poplist();
 		return;
-	case 2: n=atoi(runq->argv->words->next->word); break;
-	case 1: n=1; break;
+	case 2:
+		n = atoi(runq->argv->words->next->word);
+		break;
+	case 1:
+		n = 1;
+		break;
 	}
-	star=vlook("*");
+	star = vlook("*");
 	for(;n && star->val;--n){
-		a=star->val->next;
+		a = star->val->next;
 		efree(star->val->word);
 		efree((char *)star->val);
-		star->val=a;
-		star->changed=1;
+		star->val = a;
+		star->changed = 1;
 	}
 	setstatus("");
 	poplist();
 }
-int octal(char *s)
+
+int
+octal(char *s)
 {
-	int n=0;
+	int n = 0;
 	while(*s==' ' || *s=='\t' || *s=='\n') s++;
-	while('0'<=*s && *s<='7') n=n*8+*s++-'0';
+	while('0'<=*s && *s<='7') n = n*8+*s++-'0';
 	return n;
 }
-int mapfd(int fd)
+
+int
+mapfd(int fd)
 {
 	redir *rp;
-	for(rp=runq->redir;rp;rp=rp->next){
+	for(rp = runq->redir;rp;rp = rp->next){
 		switch(rp->type){
 		case RCLOSE:
-			if(rp->from==fd) fd=-1;
+			if(rp->from==fd)
+				fd=-1;
 			break;
 		case RDUP:
 		case ROPEN:
-			if(rp->to==fd) fd=rp->from;
+			if(rp->to==fd)
+				fd = rp->from;
 			break;
 		}
 	}
 	return fd;
 }
 union code rdcmds[4];
-void execcmds(io *f)
+
+void
+execcmds(io *f)
 {
-	static int first=1;
+	static int first = 1;
 	if(first){
-		rdcmds[0].i=1;
-		rdcmds[1].f=Xrdcmds;
-		rdcmds[2].f=Xreturn;
-		first=0;
+		rdcmds[0].i = 1;
+		rdcmds[1].f = Xrdcmds;
+		rdcmds[2].f = Xreturn;
+		first = 0;
 	}
 	start(rdcmds, 1, runq->local);
-	runq->cmdfd=f;
-	runq->iflast=0;
+	runq->cmdfd = f;
+	runq->iflast = 0;
 }
-void execeval(void){
+
+void
+execeval(void)
+{
 	char *cmdline, *s, *t;
-	int len=0;
+	int len = 0;
 	word *ap;
 	if(count(runq->argv->words)<=1){
 		Xerror1("Usage: eval cmd ...");
 		return;
 	}
-	eflagok=1;
-	for(ap=runq->argv->words->next;ap;ap=ap->next)
+	eflagok = 1;
+	for(ap = runq->argv->words->next;ap;ap = ap->next)
 		len+=1+strlen(ap->word);
-	cmdline=emalloc(len);
-	s=cmdline;
-	for(ap=runq->argv->words->next;ap;ap=ap->next){
-		for(t=ap->word;*t;) *s++=*t++;
+	cmdline = emalloc(len);
+	s = cmdline;
+	for(ap = runq->argv->words->next;ap;ap = ap->next){
+		for(t = ap->word;*t;) *s++=*t++;
 		*s++=' ';
 	}
 	s[-1]='\n';
@@ -272,36 +310,39 @@
 	efree(cmdline);
 }
 union code dotcmds[14];
-void execdot(void){
-	int iflag=0;
+
+void
+execdot(void)
+{
+	int iflag = 0;
 	int fd;
 	list *av;
-	thread *p=runq;
+	thread *p = runq;
 	char *zero;
-	static int first=1;
+	static int first = 1;
 	char file[512];
 	word *path;
 	if(first){
-		dotcmds[0].i=1;
-		dotcmds[1].f=Xmark;
-		dotcmds[2].f=Xword;
+		dotcmds[0].i = 1;
+		dotcmds[1].f = Xmark;
+		dotcmds[2].f = Xword;
 		dotcmds[3].s="0";
-		dotcmds[4].f=Xlocal;
-		dotcmds[5].f=Xmark;
-		dotcmds[6].f=Xword;
+		dotcmds[4].f = Xlocal;
+		dotcmds[5].f = Xmark;
+		dotcmds[6].f = Xword;
 		dotcmds[7].s="*";
-		dotcmds[8].f=Xlocal;
-		dotcmds[9].f=Xrdcmds;
-		dotcmds[10].f=Xunlocal;
-		dotcmds[11].f=Xunlocal;
-		dotcmds[12].f=Xreturn;
-		first=0;
+		dotcmds[8].f = Xlocal;
+		dotcmds[9].f = Xrdcmds;
+		dotcmds[10].f = Xunlocal;
+		dotcmds[11].f = Xunlocal;
+		dotcmds[12].f = Xreturn;
+		first = 0;
 	}
 	else
-		eflagok=1;
+		eflagok = 1;
 	popword();
 	if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
-		iflag=1;
+		iflag = 1;
 		popword();
 	}
 	/* get input file */
@@ -309,18 +350,20 @@
 		Xerror1("Usage: . [-i] file [arg ...]");
 		return;
 	}
-	zero=strdup(p->argv->words->word);
+	zero = strdup(p->argv->words->word);
 	popword();
 	fd=-1;
-	for(path=searchpath(zero);path;path=path->next){
+	for(path = searchpath(zero);path;path = path->next){
 		strcpy(file, path->word);
-		if(file[0]) strcat(file, "/");
+		if(file[0])
+			strcat(file, "/");
 		strcat(file, zero);
+		if((fd = open(file, 0))>=0) break;
 		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */
-			fd=Dup1(0);
-			if(fd>=0) break;
+			fd = Dup1(0);
+			if(fd>=0)
+				break;
 		}
-		if((fd=open(file, 0))>=0) break;
 	}
 	if(fd<0){
 		pfmt(err, "%s: ", zero);
@@ -331,38 +374,41 @@
 	/* set up for a new command loop */
 	start(dotcmds, 1, (struct var *)0);
 	pushredir(RCLOSE, fd, 0);
-	runq->cmdfile=zero;
-	runq->cmdfd=openfd(fd);
-	runq->iflag=iflag;
-	runq->iflast=0;
+	runq->cmdfile = zero;
+	runq->cmdfd = openfd(fd);
+	runq->iflag = iflag;
+	runq->iflast = 0;
 	/* push $* value */
 	pushlist();
-	runq->argv->words=p->argv->words;
+	runq->argv->words = p->argv->words;
 	/* free caller's copy of $* */
-	av=p->argv;
-	p->argv=av->next;
+	av = p->argv;
+	p->argv = av->next;
 	efree((char *)av);
 	/* push $0 value */
 	pushlist();
 	pushword(zero);
 	ndot++;
 }
-void execflag(void){
+
+void
+execflag(void)
+{
 	char *letter, *val;
 	switch(count(runq->argv->words)){
 	case 2:
 		setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
 		break;
 	case 3:
-		letter=runq->argv->words->next->word;
-		val=runq->argv->words->next->next->word;
+		letter = runq->argv->words->next->word;
+		val = runq->argv->words->next->next->word;
 		if(strlen(letter)==1){
 			if(strcmp(val, "+")==0){
-				flag[(uchar)letter[0]]=flagset;
+				flag[(uchar)letter[0]] = flagset;
 				break;
 			}
 			if(strcmp(val, "-")==0){
-				flag[(uchar)letter[0]]=0;
+				flag[(uchar)letter[0]] = 0;
 				break;
 			}
 		}
@@ -372,53 +418,57 @@
 	}
 	poplist();
 }
-void execwhatis(void){	/* mildly wrong -- should fork before writing */
+
+void
+execwhatis(void){	/* mildly wrong -- should fork before writing */
 	word *a, *b, *path;
 	var *v;
 	struct builtin *bp;
 	char file[512];
 	struct io out[1];
 	int found, sep;
-	a=runq->argv->words->next;
+	a = runq->argv->words->next;
 	if(a==0){
 		Xerror1("Usage: whatis name ...");
 		return;
 	}
 	setstatus("");
-	out->fd=mapfd(1);
-	out->bufp=out->buf;
-	out->ebuf=&out->buf[NBUF];
-	out->strp=0;
-	for(;a;a=a->next){
-		v=vlook(a->word);
+	out->fd = mapfd(1);
+	out->bufp = out->buf;
+	out->ebuf = &out->buf[NBUF];
+	out->strp = 0;
+	for(;a;a = a->next){
+		v = vlook(a->word);
 		if(v->val){
 			pfmt(out, "%s=", a->word);
 			if(v->val->next==0)
 				pfmt(out, "%q\n", v->val->word);
 			else{
 				sep='(';
-				for(b=v->val;b && b->word;b=b->next){
+				for(b = v->val;b && b->word;b = b->next){
 					pfmt(out, "%c%q", sep, b->word);
 					sep=' ';
 				}
 				pfmt(out, ")\n");
 			}
-			found=1;
+			found = 1;
 		}
 		else
-			found=0;
-		v=gvlook(a->word);
-		if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
+			found = 0;
+		v = gvlook(a->word);
+		if(v->fn)
+			pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
 		else{
-			for(bp=Builtin;bp->name;bp++)
+			for(bp = Builtin;bp->name;bp++)
 				if(strcmp(a->word, bp->name)==0){
 					pfmt(out, "builtin %s\n", a->word);
 					break;
 				}
 			if(!bp->name){
-				for(path=searchpath(a->word);path;path=path->next){
+				for(path = searchpath(a->word);path;path = path->next){
 					strcpy(file, path->word);
-					if(file[0]) strcat(file, "/");
+					if(file[0])
+						strcat(file, "/");
 					strcat(file, a->word);
 					if(Executable(file)){
 						pfmt(out, "%s\n", file);
@@ -435,11 +485,20 @@
 	poplist();
 	flush(err);
 }
-void execwait(void){
+
+void
+execwait(void)
+{
 	switch(count(runq->argv->words)){
-	default: Xerror1("Usage: wait [pid]"); return;
-	case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
-	case 1: Waitfor(-1, 0); break;
+	default:
+		Xerror1("Usage: wait [pid]");
+		return;
+	case 2:
+		Waitfor(atoi(runq->argv->words->next->word), 0);
+		break;
+	case 1:
+		Waitfor(-1, 0);
+		break;
 	}
 	poplist();
 }
diff --git a/src/cmd/rc/subr.c b/src/cmd/rc/subr.c
index 06a22b2..a6b533b 100644
--- a/src/cmd/rc/subr.c
+++ b/src/cmd/rc/subr.c
@@ -2,20 +2,29 @@
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
-char *emalloc(long n){
-	char *p=(char *)Malloc(n);
-	if(p==0) panic("Can't malloc %d bytes", n);
-/*	if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } */
+
+char*
+emalloc(long n)
+{
+	char *p = (char *)Malloc(n);
+	if(p==0)
+		panic("Can't malloc %d bytes", n);
+/*	if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
 	return p;
 }
-void efree(char *p)
+
+void
+efree(char *p)
 {
-/*	pfmt(err, "free %p\n", p); flush(err); */
-	if(p) free(p);
+/*	pfmt(err, "free %p\n", p); flush(err); /**/
+	if(p)
+		free(p);
 	else pfmt(err, "free 0\n");
 }
 extern int lastword, lastdol;
-void yyerror(char *m)
+
+void
+yyerror(char *m)
 {
 	pfmt(err, "rc: ");
 	if(runq->cmdfile && !runq->iflag)
@@ -24,17 +33,21 @@
 		pfmt(err, "%s: ", runq->cmdfile);
 	else if(!runq->iflag)
 		pfmt(err, "line %d: ", runq->lineno);
-	if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok);
+	if(tok[0] && tok[0]!='\n')
+		pfmt(err, "token %q: ", tok);
 	pfmt(err, "%s\n", m);
 	flush(err);
-	lastword=0;
-	lastdol=0;
+	lastword = 0;
+	lastdol = 0;
 	while(lastc!='\n' && lastc!=EOF) advance();
 	nerror++;
 	setvar("status", newword(m, (word *)0));
 }
 char *bp;
-void iacvt(int n){
+
+static void
+iacvt(int n)
+{
 	if(n<0){
 		*bp++='-';
 		n=-n;	/* doesn't work for n==-inf */
@@ -43,13 +56,17 @@
 		iacvt(n/10);
 	*bp++=n%10+'0';
 }
-void itoa(char *s, long n)
+
+void
+inttoascii(char *s, long n)
 {
-	bp=s;
+	bp = s;
 	iacvt(n);
 	*bp='\0';
 }
-void panic(char *s, int n)
+
+void
+panic(char *s, int n)
 {
 	pfmt(err, "rc: ");
 	pfmt(err, s, n);
diff --git a/src/cmd/rc/syn.y b/src/cmd/rc/syn.y
index 5123ce4..c7de353 100644
--- a/src/cmd/rc/syn.y
+++ b/src/cmd/rc/syn.y
@@ -2,7 +2,6 @@
 %term WORD REDIR DUP PIPE SUB
 %term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
 /* operator priorities -- lowest first */
-%left LOW
 %left IF WHILE FOR SWITCH ')' NOT
 %left ANDAND OROR
 %left BANG SUBSHELL
@@ -10,7 +9,6 @@
 %left '^'
 %right '$' COUNT '"'
 %left SUB
-%left '='
 %{
 #include "rc.h"
 #include "fns.h"
@@ -80,7 +78,6 @@
 word:	keyword			{lastword=1; $1->type=WORD;}
 |	comword
 |	word '^' word		{$$=tree2('^', $1, $3);}
-|	word '=' word %prec LOW		{$$=tree2('^', tree2('^', $1, token("=", WORD)), $3);}
 comword: '$' word		{$$=tree1('$', $2);}
 |	'$' word SUB words ')'	{$$=tree2(SUB, $2, $4);}
 |	'"' word		{$$=tree1('"', $2);}
diff --git a/src/cmd/rc/trap.c b/src/cmd/rc/trap.c
index 96ef364..a572cac 100644
--- a/src/cmd/rc/trap.c
+++ b/src/cmd/rc/trap.c
@@ -3,22 +3,25 @@
 #include "fns.h"
 #include "io.h"
 extern char *Signame[];
-void dotrap(void){
-	register int i;
-	register struct var *trapreq;
-	register struct word *starval;
-	starval=vlook("*")->val;
-	while(ntrap) for(i=0;i!=NSIG;i++) while(trap[i]){
+
+void
+dotrap(void)
+{
+	int i;
+	struct var *trapreq;
+	struct word *starval;
+	starval = vlook("*")->val;
+	while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
 		--trap[i];
 		--ntrap;
 		if(getpid()!=mypid) Exit(getstatus());
-		trapreq=vlook(Signame[i]);
+		trapreq = vlook(Signame[i]);
 		if(trapreq->fn){
 			start(trapreq->fn, trapreq->pc, (struct var *)0);
-			runq->local=newvar(strdup("*"), runq->local);
-			runq->local->val=copywords(starval, (struct word *)0);
-			runq->local->changed=1;
-			runq->redir=runq->startredir=0;
+			runq->local = newvar(strdup("*"), runq->local);
+			runq->local->val = copywords(starval, (struct word *)0);
+			runq->local->changed = 1;
+			runq->redir = runq->startredir = 0;
 		}
 		else if(i==SIGINT || i==SIGQUIT){
 			/*
diff --git a/src/cmd/rc/tree.c b/src/cmd/rc/tree.c
index 9bf76d8..897597e 100644
--- a/src/cmd/rc/tree.c
+++ b/src/cmd/rc/tree.c
@@ -7,108 +7,140 @@
  * create and clear a new tree node, and add it
  * to the node list.
  */
-tree *newtree(void){
-	tree *t=new(tree);
-	t->iskw=0;
-	t->str=0;
-	t->child[0]=t->child[1]=t->child[2]=0;
-	t->next=treenodes;
-	treenodes=t;
+
+tree*
+newtree(void)
+{
+	tree *t = new(tree);
+	t->iskw = 0;
+	t->str = 0;
+	t->child[0] = t->child[1] = t->child[2] = 0;
+	t->next = treenodes;
+	treenodes = t;
 	return t;
 }
-void freenodes(void){
+
+void
+freenodes(void)
+{
 	tree *t, *u;
-	for(t=treenodes;t;t=u){
-		u=t->next;
-		if(t->str) efree(t->str);
+	for(t = treenodes;t;t = u){
+		u = t->next;
+		if(t->str)
+			efree(t->str);
 		efree((char *)t);
 	}
-	treenodes=0;
+	treenodes = 0;
 }
-tree *tree1(int type, tree *c0)
+
+tree*
+tree1(int type, tree *c0)
 {
 	return tree3(type, c0, (tree *)0, (tree *)0);
 }
-tree *tree2(int type, tree *c0, tree *c1)
+
+tree*
+tree2(int type, tree *c0, tree *c1)
 {
 	return tree3(type, c0, c1, (tree *)0);
 }
-tree *tree3(int type, tree *c0, tree *c1, tree *c2)
+
+tree*
+tree3(int type, tree *c0, tree *c1, tree *c2)
 {
 	tree *t;
 	if(type==';'){
-		if(c0==0) return c1;
-		if(c1==0) return c0;
+		if(c0==0)
+			return c1;
+		if(c1==0)
+			return c0;
 	}
-	t=newtree();
-	t->type=type;
-	t->child[0]=c0;
-	t->child[1]=c1;
-	t->child[2]=c2;
+	t = newtree();
+	t->type = type;
+	t->child[0] = c0;
+	t->child[1] = c1;
+	t->child[2] = c2;
 	return t;
 }
-tree *mung1(tree *t, tree *c0)
+
+tree*
+mung1(tree *t, tree *c0)
 {
-	t->child[0]=c0;
+	t->child[0] = c0;
 	return t;
 }
-tree *mung2(tree *t, tree *c0, tree *c1)
+
+tree*
+mung2(tree *t, tree *c0, tree *c1)
 {
-	t->child[0]=c0;
-	t->child[1]=c1;
+	t->child[0] = c0;
+	t->child[1] = c1;
 	return t;
 }
-tree *mung3(tree *t, tree *c0, tree *c1, tree *c2)
+
+tree*
+mung3(tree *t, tree *c0, tree *c1, tree *c2)
 {
-	t->child[0]=c0;
-	t->child[1]=c1;
-	t->child[2]=c2;
+	t->child[0] = c0;
+	t->child[1] = c1;
+	t->child[2] = c2;
 	return t;
 }
-tree *epimung(tree *comp, tree *epi)
+
+tree*
+epimung(tree *comp, tree *epi)
 {
 	tree *p;
-	if(epi==0) return comp;
-	for(p=epi;p->child[1];p=p->child[1]);
-	p->child[1]=comp;
+	if(epi==0)
+		return comp;
+	for(p = epi;p->child[1];p = p->child[1]);
+	p->child[1] = comp;
 	return epi;
 }
 /*
  * Add a SIMPLE node at the root of t and percolate all the redirections
  * up to the root.
  */
-tree *simplemung(tree *t)
+
+tree*
+simplemung(tree *t)
 {
 	tree *u;
 	struct io *s;
-	t=tree1(SIMPLE, t);
-	s=openstr();
+	t = tree1(SIMPLE, t);
+	s = openstr();
 	pfmt(s, "%t", t);
-	t->str=strdup(s->strp);
+	t->str = strdup(s->strp);
 	closeio(s);
-	for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){
+	for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
 		if(u->child[1]->type==DUP
 		|| u->child[1]->type==REDIR){
-			u->child[1]->child[1]=t;
-			t=u->child[1];
-			u->child[1]=0;
+			u->child[1]->child[1] = t;
+			t = u->child[1];
+			u->child[1] = 0;
 		}
 	}
 	return t;
 }
-tree *token(char *str, int type)
+
+tree*
+token(char *str, int type)
 {
-	tree *t=newtree();
-	t->type=type;
-	t->str=strdup(str);
+	tree *t = newtree();
+	t->type = type;
+	t->str = strdup(str);
 	return t;
 }
-void freetree(tree *p)
+
+void
+freetree(tree *p)
 {
-	if(p==0) return;	
+	if(p==0)
+		return;	
 	freetree(p->child[0]);
 	freetree(p->child[1]);
 	freetree(p->child[2]);
-	if(p->str) efree(p->str);
+	if(p->str)
+		efree(p->str);
 	efree((char *)p);
 }
diff --git a/src/cmd/rc/var.c b/src/cmd/rc/var.c
index 8a200ff..2564ba2 100644
--- a/src/cmd/rc/var.c
+++ b/src/cmd/rc/var.c
@@ -1,9 +1,11 @@
 #include "rc.h"
 #include "exec.h"
 #include "fns.h"
-int hash(char *s, int n)
+
+int
+hash(char *s, int n)
 {
-	register int h=0, i=1;
+	int h = 0, i = 1;
 	while(*s) h+=*s++*i++;
 	h%=n;
 	return h<0?h+n:h;
@@ -14,16 +16,21 @@
 	int type;
 	struct kw *next;
 }*kw[NKW];
-void kenter(int type, char *name)
+
+void
+kenter(int type, char *name)
 {
-	register int h=hash(name, NKW);
-	register struct kw *p=new(struct kw);
-	p->type=type;
-	p->name=name;
-	p->next=kw[h];
-	kw[h]=p;
+	int h = hash(name, NKW);
+	struct kw *p = new(struct kw);
+	p->type = type;
+	p->name = name;
+	p->next = kw[h];
+	kw[h] = p;
 }
-void kinit(void){
+
+void
+kinit(void)
+{
 	kenter(FOR, "for");
 	kenter(IN, "in");
 	kenter(WHILE, "while");
@@ -35,47 +42,59 @@
 	kenter(SWITCH, "switch");
 	kenter(FN, "fn");
 }
-tree *klook(char *name)
+
+tree*
+klook(char *name)
 {
 	struct kw *p;
-	tree *t=token(name, WORD);
-	for(p=kw[hash(name, NKW)];p;p=p->next)
+	tree *t = token(name, WORD);
+	for(p = kw[hash(name, NKW)];p;p = p->next)
 		if(strcmp(p->name, name)==0){
-			t->type=p->type;
-			t->iskw=1;
+			t->type = p->type;
+			t->iskw = 1;
 			break;
 		}
 	return t;
 }
-var *gvlook(char *name)
+
+var*
+gvlook(char *name)
 {
-	int h=hash(name, NVAR);
+	int h = hash(name, NVAR);
 	var *v;
-	for(v=gvar[h];v;v=v->next) if(strcmp(v->name, name)==0) return v;
-	return gvar[h]=newvar(strdup(name), gvar[h]);
+	for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
+	return gvar[h] = newvar(strdup(name), gvar[h]);
 }
-var *vlook(char *name)
+
+var*
+vlook(char *name)
 {
 	var *v;
 	if(runq)
-		for(v=runq->local;v;v=v->next)
+		for(v = runq->local;v;v = v->next)
 			if(strcmp(v->name, name)==0) return v;
 	return gvlook(name);
 }
-void _setvar(char *name, word *val, int callfn)
+
+void
+_setvar(char *name, word *val, int callfn)
 {
-	register struct var *v=vlook(name);
+	struct var *v = vlook(name);
 	freewords(v->val);
 	v->val=val;
 	v->changed=1;
 	if(callfn && v->changefn)
 		v->changefn(v);
 }
-void setvar(char *name, word *val)
+
+void
+setvar(char *name, word *val)
 {
 	_setvar(name, val, 1);
 }
-void bigpath(var *v)
+
+void
+bigpath(var *v)
 {
 	/* convert $PATH to $path */
 	char *p, *q;
@@ -107,19 +126,42 @@
 	}
 	_setvar("path", w, 0);
 }
-void littlepath(var *v)
+
+char*
+list2strcolon(word *words)
+{
+	char *value, *s, *t;
+	int len = 0;
+	word *ap;
+	for(ap = words;ap;ap = ap->next)
+		len+=1+strlen(ap->word);
+	value = emalloc(len+1);
+	s = value;
+	for(ap = words;ap;ap = ap->next){
+		for(t = ap->word;*t;) *s++=*t++;
+		*s++=':';
+	}
+	if(s==value)
+		*s='\0';
+	else s[-1]='\0';
+	return value;
+}
+void
+littlepath(var *v)
 {
 	/* convert $path to $PATH */
 	char *p;
 	word *w;
 
-	p = _list2str(v->val, ':');
+	p = list2strcolon(v->val);
 	w = new(word);
 	w->word = p;
 	w->next = nil;
 	_setvar("PATH", w, 1);	/* 1: recompute $path to expose colon problems */
 }
-void pathinit(void)
+
+void
+pathinit(void)
 {
 	var *v;