hlfw.ca

drawcpu

Download patch

ref: 1e72ca9a502a78a97523c2b79aa558e16ed4d8bd
parent: 4b6f2aacec7b4a9105e1725b7a1b7c9345225607
author: halfwit <michaelmisch1985@gmail.com>
date: Fri Feb 23 10:12:25 PST 2024

More RC work, use our libc where we can

--- a/Makefile
+++ b/Makefile
@@ -17,6 +17,7 @@
 	libauth/libauth.a\
 	libauthsrv/libauthsrv.a\
 	libsec/libsec.a\
+	librc/librc.a\
 	libmp/libmp.a\
 	libmemdraw/libmemdraw.a\
 	libmemlayer/libmemlayer.a\
@@ -24,7 +25,6 @@
 	gui-$(GUI)/libgui.a\
 	libc/libc.a\
 	libip/libip.a\
-	#librc/librc.a\
 
 # stupid gcc
 LIBS=$(LIBS1) $(LIBS1) $(LIBS1) libmachdep.a
@@ -54,11 +54,11 @@
 libmp/libmp.a:
 	(cd libmp; $(MAKE))
 
-libsec/libsec.a:
-	(cd libsec; $(MAKE))
-
 librc/librc.a:
 	(cd librc; $(MAKE))
+
+libsec/libsec.a:
+	(cd libsec; $(MAKE))
 
 libmemdraw/libmemdraw.a:
 	(cd libmemdraw; $(MAKE))
--- a/drawcpu.h
+++ b/drawcpu.h
@@ -6,6 +6,5 @@
 extern int dialfactotum(void);
 extern char *getuser(void);
 extern int session(int);
-extern char *estrdup(char*);
 extern int aanclient(char*, int);
 extern int dbg;
\ No newline at end of file
--- /dev/null
+++ b/include/rc.h
@@ -1,0 +1,159 @@
+/*
+ * Plan9 is defined for plan 9
+ * otherwise its UNIX.
+ * Please don't litter the code with ifdefs.  The three below (and one in
+ * getflags) should be enough.
+ */
+#ifdef Plan9
+#include <u.h>
+#include <libc.h>
+#define NSIG	32
+#define	SIGINT	2
+#define	SIGQUIT	3
+#else
+#include <stdlib.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <string.h>
+#include <signal.h>
+#ifndef NSIG
+#define NSIG 32
+#endif
+#endif
+
+#define	YYMAXDEPTH	500
+typedef struct tree tree;
+typedef struct word word;
+typedef struct io io;
+typedef union code code;
+typedef struct var var;
+typedef struct list list;
+typedef struct lexer lexer;
+typedef struct redir redir;
+typedef struct thread thread;
+typedef struct builtin builtin;
+
+struct tree{
+	int	type;
+	int	rtype, fd0, fd1;	/* details of REDIR PIPE DUP tokens */
+	int	line;
+	char	glob;			/* 0=string, 1=glob, 2=pattern see globprop() and noglobs() */
+	char	quoted;
+	char	iskw;
+	char	*str;
+	tree	*child[3];
+	tree	*next;
+};
+tree *newtree(void);
+tree *token(char*, int), *klook(char*), *tree1(int, tree*);
+tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
+tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
+tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
+tree *simplemung(tree*);
+tree *globprop(tree*);
+char *fnstr(tree*);
+void runscript(int, int, char**);
+/*
+ * The first word of any code vector is a reference count
+ * and the second word is a string for srcfile().
+ * Code starts at pc 2. The last code word must be a zero
+ * terminator for codefree().
+ * Always create a new reference to a code vector by calling codecopy(.).
+ * Always call codefree(.) when deleting a reference.
+ */
+union code{
+	void	(*f)(void);
+	int	i;
+	char	*s;
+};
+
+#define	NTOK	8192
+
+struct lexer{
+	io	*input;
+	char	*file;
+	int	line;
+
+	char	*prolog;
+	char	*epilog;
+
+	int	peekc;
+	int	future;
+	int	lastc;
+
+	char	eof;
+	char	inquote;
+	char	incomm;
+	char	lastword;	/* was the last token read a word or compound word terminator? */
+	char	lastdol;	/* was the last token read '$' or '$#' or '"'? */
+	char	iflast;		/* static `if not' checking */
+
+	char	qflag;
+
+	char	tok[NTOK];
+};
+extern lexer *lex;		/* current lexer */
+lexer *newlexer(io*, char*);
+void freelexer(lexer*);
+
+#define	APPEND	1
+#define	WRITE	2
+#define	READ	3
+#define	HERE	4
+#define	DUPFD	5
+#define	CLOSE	6
+#define RDWR	7
+
+struct var{
+	var	*next;		/* next on hash or local list */
+	word	*val;		/* value */
+	code	*fn;		/* pointer to function's code vector */
+	int	pc;		/* pc of start of function */
+	char	fnchanged;
+	char	changed;
+	char	name[];
+};
+var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
+void setvar(char*, word*), freevar(var*);
+
+#define	NVAR	521
+extern var *gvar[NVAR];		/* hash for globals */
+
+#define	new(type)	((type *)emalloc(sizeof(type)))
+
+void *emalloc(long);
+void *erealloc(void *, long);
+
+/*
+ * Glob character escape in strings:
+ *	In a string, GLOB must be followed by *?[ or GLOB.
+ *	GLOB* matches any string
+ *	GLOB? matches any single character
+ *	GLOB[...] matches anything in the brackets
+ *	GLOBGLOB matches GLOB
+ */
+#define	GLOB	((char)0x01)
+/*
+ * Is c the first character of a utf sequence?
+ */
+#define	onebyte(c)	(((c)&0x80)==0x00)
+#define twobyte(c)	(((c)&0xe0)==0xc0)
+#define threebyte(c)	(((c)&0xf0)==0xe0)
+#define fourbyte(c)	(((c)&0xf8)==0xf0)
+#define xbyte(c)	(((c)&0xc0)==0x80)
+
+extern char *argv0;
+extern int nerror;		/* number of errors encountered during compilation */
+extern int doprompt;		/* is it time for a prompt? */
+extern io *err;
+
+/*
+ * Which fds are the reading/writing end of a pipe?
+ * Unfortunately, this can vary from system to system.
+ * 9th edition Unix doesn't care, the following defines
+ * work on plan 9.
+ */
+#define	PRD	0
+#define	PWR	1
+extern char Rcmain[], Fdprefix[];
+extern char *Signame[];
--- a/include/user.h
+++ b/include/user.h
@@ -85,6 +85,7 @@
 extern	void	setmalloctag(void*, uintptr);
 extern	void	setrealloctag(void*, uintptr);
 extern	int	errstr(char*, uint);
+extern  char *estrdup(char*);
 extern	int	rerrstr(char*, uint);
 extern	int	encrypt(void*, void*, int);
 extern	int	decrypt(void*, void*, int);
--- a/librc/Makefile
+++ b/librc/Makefile
@@ -1,7 +1,7 @@
 ROOT=..
 include ../Make.config
-
 LIB=librc.a
+
 OFILES=\
 	code.$O\
 	exec.$O\
@@ -18,13 +18,14 @@
 	tree.$O\
 	var.$O\
 	havefork.$O\
-	unix.$O\
-	y.tab.c
+	drawcpu.$O\
+	y.tab.$O\
 
 default: $(LIB)
-$(LIB): $(OFILES) $(YFILES)
-	$(AR) r $(LIB) $(OFILES) $(YFILES)
+$(LIB): $(OFILES)
+	$(AR) r $(LIB) $(OFILES)
 	$(RANLIB) $(LIB)
 
 %.$O: %.c
 	$(CC) $(CFLAGS) $*.c
+	
\ No newline at end of file
--- a/librc/code.c
+++ b/librc/code.c
@@ -1,8 +1,11 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
 #include "io.h"
 #include "exec.h"
 #include "fns.h"
 #include "getflags.h"
+#include "y.tab.h"
 #define	c0	t->child[0]
 #define	c1	t->child[1]
 #define	c2	t->child[2]
--- /dev/null
+++ b/librc/drawcpu.c
@@ -1,0 +1,275 @@
+/*
+ * Unix versions of system-specific functions
+ *	By convention, exported routines herein have names beginning with an
+ *	upper case letter.
+ */
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
+#include <errno.h>
+#include <string.h>
+#include "exec.h"
+#include "io.h"
+#include "fns.h"
+#include "getflags.h"
+
+static void execfinit(void);
+
+// TODO: add bind, mount, etc
+builtin Builtin[] = {
+	"cd",		execcd,
+	"whatis",	execwhatis,
+	"eval",		execeval,
+	"exec",		execexec,	/* but with popword first */
+	"exit",		execexit,
+	"shift",	execshift,
+	"wait",		execwait,
+	".",		execdot,
+	"flag",		execflag,
+	"finit",	execfinit,
+	0
+};
+
+char Rcmain[] = "./librc/rcmain.drawcpu";
+char Fdprefix[] = "/dev/fd/";
+char *Signame[] = {
+	"sigexit",	"sighup",	"sigint",	"sigquit",
+	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
+	0
+};
+
+/*
+ * finit could be removed but is kept for
+ * backwards compatibility, see: rcmain.plan9
+ */
+static void
+execfinit(void)
+{
+	char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
+	int line = runq->line;
+	poplist();
+	execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
+	runq->lex->line = line;
+	runq->lex->qflag = 1;
+}
+
+char*
+Env(char *name, int fn)
+{
+	static char buf[128];
+
+	strcpy(buf, "/env/");
+	if(fn) strcat(buf, "fn#");
+	return strncat(buf, name, sizeof(buf)-1);
+}
+/* TODO: Proper env read
+void
+Vinit(void)
+{
+	int dir, fd, i, n;
+	Dir *ent;
+
+	dir = open(Env("", 0), 0);
+	if(dir<0){
+		pfmt(err, "%s: can't open: %s\n", argv0, strerror(errno));
+		return;
+	}
+	for(;;){
+		ent = 0;
+		n = devdirread(dir, ent, sizeof ent);
+		if(n <= 0)
+			break;
+		for(i = 0; i<n; i++){
+			if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0)
+				continue;
+			if((fd = open(Env(ent[i].name, 0), 0))>=0){
+				io *f = openiofd(fd);
+				word *w = 0, **wp = &w;
+				char *s;
+				while((s = rstr(f, "")) != 0){
+					*wp = Newword(s, (word*)0);
+					wp = &(*wp)->next;
+				}
+				closeio(f);
+				setvar(ent[i].name, w);
+				vlook(ent[i].name)->changed = 0;
+			}
+		}
+		free(ent);
+	}
+	close(dir);
+}
+*/
+
+int
+Waitfor(int pid)
+{
+	thread *p;
+	Waitmsg *w;
+
+	if(pid >= 0 && !havewaitpid(pid))
+		return 0;
+
+	while((w = wait(pid)) != nil){
+		delwaitpid(w->pid);
+		if(w->pid==pid){
+			setstatus(w->msg);
+			free(w);
+			return 0;
+		}
+		for(p = runq->ret;p;p = p->ret)
+			if(p->pid==w->pid){
+				p->pid=-1;
+				p->status = estrdup(w->msg);
+				break;
+			}
+		free(w);
+	}
+
+	if(strcmp(strerror(errno), "interrupted")==0) return -1;
+	return 0;
+}
+
+// TODO: /dev/env integration
+static void
+addenv(var *v)
+{
+	word *w;
+	int fd;
+	io *f;
+
+	if(v->changed){
+		v->changed = 0;
+		if((fd = create(Env(v->name, 0), ORDWR, 0644))<0)
+			pfmt(err, "%s: can't open: %s\n", argv0, strerror(errno));
+		else{
+			f = openiofd(fd);
+			for(w = v->val;w;w = w->next){
+				pstr(f, w->word);
+				pchr(f, '\0');
+			}
+			flushio(f);
+			closeio(f);
+		}
+	}
+	if(v->fnchanged){
+		v->fnchanged = 0;
+		if((fd = create(Env(v->name, 1), ORDWR, 0644))<0)
+			pfmt(err, "%s: can't open: %s\n", argv0, strerror(errno));
+		else{
+			f = openiofd(fd);
+			if(v->fn)
+				pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
+			flushio(f);
+			closeio(f);
+		}
+	}
+}
+
+static void
+updenvlocal(var *v)
+{
+	if(v){
+		updenvlocal(v->next);
+		addenv(v);
+	}
+}
+
+void
+Updenv(void)
+{
+	var *v, **h;
+	for(h = gvar;h!=&gvar[NVAR];h++)
+		for(v=*h;v;v = v->next)
+			addenv(v);
+	if(runq)
+		updenvlocal(runq->local);
+	if(err)
+		flushio(err);
+}
+
+typedef struct rdir rdir;
+struct rdir {
+	Dir	*dbuf;
+	int	i, n;
+	int	fd;
+};
+
+static int
+trimdirs(Dir *d, int nd)
+{
+	int r, w;
+
+	for(r=w=0; r<nd; r++)
+		if(d[r].mode&DMDIR)
+			d[w++] = d[r];
+	return w;
+}
+
+static int interrupted = 0;
+static char *syssigname[] = {
+	"exit",		/* can't happen */
+	"hangup",
+	"interrupt",
+	"quit",		/* can't happen */
+	"alarm",
+	"kill",
+	"sys: fp: ",
+	"term",
+	0
+};
+
+void
+notifyf(void* q, char *s)
+{
+	int i;
+	USED(q);
+	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
+		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
+		goto Out;
+	}
+	// TODO: Handle notes
+	//noted(NDFLT);
+	return;
+Out:
+	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
+		trap[i]++;
+		ntrap++;
+	}
+	// TODO: Handle notes
+	//noted(NCONT);
+}
+
+int
+Executable(char *file)
+{
+	Dir *statbuf;
+	int ret;
+
+	statbuf = dirstat(file);
+	if(statbuf == nil)
+		return 0;
+	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
+	free(statbuf);
+	return ret;
+}
+
+void
+Noerror(void)
+{
+	interrupted = 0;
+}
+
+int
+Isatty(int fd)
+{
+	isatty(fd);
+}
+
+void
+Prompt(char *s)
+{
+	pstr(err, s);
+	flushio(err);
+}
+	
\ No newline at end of file
--- a/librc/exec.c
+++ b/librc/exec.c
@@ -1,4 +1,7 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
+#include <errno.h>
 #include "getflags.h"
 #include "exec.h"
 #include "io.h"
@@ -222,12 +225,11 @@
  * start interpreting code
  */
 void
-rcmain(int argc, char *argv[])
+runscript(int fd, int argc, char **argv)
 {
 	code bootstrap[20];
 	char num[12];
 	char *rcmain=Rcmain;
-
 	int i;
 	argv0 = argv[0];
 	argc = getflags(argc, argv, "srdiIlxebpvVc:1m:1[command]", 1);
@@ -241,8 +243,8 @@
 	if(flag['m']) rcmain = flag['m'][0];
 	err = openiofd(2);
 	kinit();
-	Trapinit();
-	Vinit();
+	notify(notifyf);
+	// Vinit();
 	inttoascii(num, mypid = getpid());
 	setvar("pid", newword(num, (word *)0));
 	setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
@@ -346,11 +348,11 @@
 		break;
 	}
 	file = runq->argv->words->word;
-	if((fd = Open(file, 1))<0 && (fd = Creat(file))<0){
-		Xerror3(">> can't open", file, Errstr());
+	if((fd = open(file, 1))<0 && (fd = create(file, ORDWR, 0644))<0){
+		Xerror3(">> can't open", file, strerror(errno));
 		return;
 	}
-	Seek(fd, 0L, 2);
+	seek(fd, 0L, 2);
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
 	poplist();
 }
@@ -401,7 +403,7 @@
 			return;
 		}
 	}
-	Exit();
+	_exit(0);
 }
 
 void
@@ -468,7 +470,7 @@
 	}
 	s++;
 	for(i='a'; i<'z'; i++){
-		if(access(tmp, 0)!=0 && (fd = Creat(tmp))>=0)
+		if(access(tmp, 0)!=0 && (fd = create(tmp, ORDWR, 0644))>=0)
 			return fd;
 		*s = i;
 	}
@@ -483,7 +485,7 @@
 	io *io;
 
 	if((fd = herefile(file))<0){
-		Xerror3("<< can't get temp file", file, Errstr());
+		Xerror3("<< can't get temp file", file, strerror(errno));
 		return;
 	}
 	io = openiofd(fd);
@@ -492,8 +494,8 @@
 	closeio(io);
 
 	/* open for reading and unlink */
-	if((fd = Open(file, 3))<0){
-		Xerror3("<< can't open", file, Errstr());
+	if((fd = open(file, 3))<0){
+		Xerror3("<< can't open", file, strerror(errno));
 		return;
 	}
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@@ -506,16 +508,16 @@
 	int fd;
 
 	if((fd = herefile(file))<0){
-		Xerror3("<< can't get temp file", file, Errstr());
+		Xerror3("<< can't get temp file", file, strerror(errno));
 		return;
 	}
 	body = runq->code[runq->pc++].s;
-	Write(fd, body, strlen(body));
-	Close(fd);
+	write(fd, body, strlen(body));
+	close(fd);
 
 	/* open for reading and unlink */
-	if((fd = Open(file, 3))<0){
-		Xerror3("<< can't open", file, Errstr());
+	if((fd = open(file, 3))<0){
+		Xerror3("<< can't open", file, strerror(errno));
 		return;
 	}
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@@ -538,8 +540,8 @@
 		break;
 	}
 	file = runq->argv->words->word;
-	if((fd = Open(file, 0))<0){
-		Xerror3("< can't open", file, Errstr());
+	if((fd = open(file, 0))<0){
+		Xerror3("< can't open", file, strerror(errno));
 		return;
 	}
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@@ -563,8 +565,8 @@
 		break;
 	}
 	file = runq->argv->words->word;
-	if((fd = Open(file, 2))<0){
-		Xerror3("<> can't open", file, Errstr());
+	if((fd = open(file, 2))<0){
+		Xerror3("<> can't open", file, strerror(errno));
 		return;
 	}
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@@ -580,7 +582,7 @@
 		panic("Xpopredir null!", 0);
 	runq->redir = rp->next;
 	if(rp->type==ROPEN)
-		Close(rp->from);
+		close(rp->from);
 	free(rp);
 }
 
@@ -591,7 +593,7 @@
 		Xpopredir();
 	popthread();
 	if(runq==0)
-		Exit();
+		_exit(0);
 }
 
 void
@@ -638,8 +640,8 @@
 		break;
 	}
 	file = runq->argv->words->word;
-	if((fd = Creat(file))<0){
-		Xerror3("> can't create", file, Errstr());
+	if((fd = create(file, ORDWR, 0644))<0){
+		Xerror3("> can't create", file, strerror(errno));
 		return;
 	}
 	pushredir(ROPEN, fd, runq->code[runq->pc++].i);
@@ -1020,8 +1022,8 @@
 	Noerror();
 	nerror = 0;
 	if(yyparse()){
-		if(p->iflag && (!lex->eof || Eintr())){
-			if(Eintr()){
+		if(p->iflag && (!lex->eof || errno == EINTR)){
+			if(errno == EINTR){
 				pchr(err, '\n');
 				lex->eof = 0;
 			}
--- a/librc/fns.h
+++ b/librc/fns.h
@@ -1,35 +1,17 @@
-void	Abort(void);
-int	Chdir(char*);
-void	Close(int);
-void	Closedir(void*);
-int	Creat(char*);
-int	Dup(int, int);
-int	Dup1(int);
-int	Eintr(void);
+
 int	Executable(char*);
-void	Exec(char**);
-void	Exit(void);
-char*	Errstr(void);
 char*	Freeword(word*);
-int	Fork(void);
 char*	Getstatus(void);
 int	Isatty(int);
 word*	Newword(char*,word*);
 void	Noerror(void);
-int	Open(char*, int);
-void*	Opendir(char*);
 word*	Poplist(void);
 char*	Popword(void);
 word*	Pushword(char*);
-long	Read(int, void*, long);
-char*	Readdir(void*, int);
-long	Seek(int, long, long);
 void	Setstatus(char*);
-void	Trapinit(void);
 void	Updenv(void);
 void	Vinit(void);
 int	Waitfor(int);
-long	Write(int, void*, long);
 void	addwaitpid(int);
 void	clearwaitpids(void);
 void	codefree(code*);
@@ -39,6 +21,7 @@
 void	delwaitpid(int);
 void	dotrap(void);
 void	freenodes(void);
+void    notifyf(void*, char*);
 void	freewords(word*);
 void	globword(word*);
 int	havewaitpid(int);
@@ -47,8 +30,7 @@
 void	kinit(void);
 int	mapfd(int);
 int	match(char*, char*, int);
-char*	makepath(char*, char*);
-void	panic(char*, int);
+char*	rcmakepath(char*, char*);
 void	pfln(io*, char*, int);
 void	poplist(void);
 void	popword(void);
@@ -58,7 +40,6 @@
 void	pushlist(void);
 void	pushredir(int, int, int);
 word*	pushword(char*);
-void    rcmain(int, char*[]);
 void	readhere(io*);
 void	heredoc(tree*);
 void	setstatus(char*);
@@ -70,3 +51,4 @@
 void	yyerror(char*);
 int	yylex(void);
 int	yyparse(void);
+#define notify(x)
\ No newline at end of file
--- a/librc/getflags.c
+++ b/librc/getflags.c
@@ -1,4 +1,4 @@
-#include "rc.h"
+#include <rc.h>
 #include "getflags.h"
 #include "fns.h"
 char *flagset[] = {"<flag>"};
@@ -206,7 +206,7 @@
 	}
 	errs("\n");
 	setstatus("bad flags");
-	Exit();
+	_exit(0);
 }
 
 static void
@@ -228,7 +228,7 @@
 {
 	*bufp++=c;
 	if(bufp==&buf[NBUF] || c=='\n'){
-		Write(2, buf, bufp-buf);
+		write(2, buf, bufp-buf);
 		bufp = buf;
 	}
 }
--- a/librc/glob.c
+++ b/librc/glob.c
@@ -1,4 +1,7 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <dirent.h>
+#include <rc.h>
 #include "exec.h"
 #include "fns.h"
 
@@ -59,11 +62,21 @@
 static void
 pappend(char **pdir, char *name)
 {
-	char *path = makepath(*pdir, name);
+	char *path = rcmakepath(*pdir, name);
 	free(*pdir);
 	*pdir = path;
 }
 
+char*
+nextdirent(void *arg)
+{
+	DIR *rd = arg;
+	struct dirent *ent = readdir(rd);
+	if(ent == NULL)
+		return 0;
+	return ent->d_name;
+}
+
 static word*
 globdir(word *list, char *pattern, char *name)
 {
@@ -71,7 +84,7 @@
 	void *dir;
 
 #ifdef Plan9
-	/* append slashes, Readdir() already filtered directories */
+	/* append slashes, readdir() already filtered directories */
 	while(*pattern=='/'){
 		pappend(&name, "/");
 		pattern++;
@@ -102,15 +115,15 @@
 	*glob=GLOB;
 
 	/* read the directory and recur for any entry that matches */
-	dir = Opendir(name[0]?name:".");
+	dir = opendir(name[0]?name:".");
 	if(dir==0)
 		goto out;
 	slash=strchr(glob, '/');
-	while((entry=Readdir(dir, slash!=0)) != 0){
+	while((entry=nextdirent(dir)) != 0){
 		if(matchfn(entry, pattern))
-			list = globdir(list, slash?slash:"", makepath(name, entry));
+			list = globdir(list, slash?slash:"", rcmakepath(name, entry));
 	}
-	Closedir(dir);
+	closedir(dir);
 out:
 	free(name);
 	return list;
--- a/librc/havefork.c
+++ b/librc/havefork.c
@@ -1,4 +1,7 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
+#include <errno.h>
 #include "getflags.h"
 #include "exec.h"
 #include "io.h"
@@ -48,9 +51,9 @@
 	int pid;
 	char npid[10];
 
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
-		Xerror2("try again", Errstr());
+		Xerror2("try again", strerror(errno));
 		break;
 	case 0:
 		clearwaitpids();
@@ -76,16 +79,16 @@
 	int pfd[2];
 
 	if(pipe(pfd)<0){
-		Xerror2("can't get pipe", Errstr());
+		Xerror2("can't get pipe", strerror(errno));
 		return;
 	}
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
-		Xerror2("try again", Errstr());
+		Xerror2("try again", strerror(errno));
 		break;
 	case 0:
 		clearwaitpids();
-		Close(pfd[PRD]);
+		close(pfd[PRD]);
 		start(p->code, pc+2, runq->local, runq->redir);
 		runq->ret = 0;
 		pushredir(ROPEN, pfd[PWR], lfd);
@@ -92,7 +95,7 @@
 		break;
 	default:
 		addwaitpid(pid);
-		Close(pfd[PWR]);
+		close(pfd[PWR]);
 		start(p->code, p->code[pc].i, runq->local, runq->redir);
 		pushredir(ROPEN, pfd[PRD], rfd);
 		p->pc = p->code[pc+1].i;
@@ -114,24 +117,24 @@
 	io *f;
 
 	if(pipe(pfd)<0){
-		Xerror2("can't make pipe", Errstr());
+		Xerror2("can't make pipe", strerror(errno));
 		return;
 	}
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
-		Xerror2("try again", Errstr());
-		Close(pfd[PRD]);
-		Close(pfd[PWR]);
+		Xerror2("try again", strerror(errno));
+		close(pfd[PRD]);
+		close(pfd[PWR]);
 		return;
 	case 0:
 		clearwaitpids();
-		Close(pfd[PRD]);
+		close(pfd[PRD]);
 		start(runq->code, runq->pc+1, runq->local, runq->redir);
 		pushredir(ROPEN, pfd[PWR], 1);
 		return;
 	default:
 		addwaitpid(pid);
-		Close(pfd[PWR]);
+		close(pfd[PWR]);
 
 		split = Popword();
 		poplist();
@@ -163,7 +166,7 @@
 	int sidefd, mainfd;
 
 	if(pipe(pfd)<0){
-		Xerror2("can't get pipe", Errstr());
+		Xerror2("can't get pipe", strerror(errno));
 		return;
 	}
 	if(p->code[pc].i==READ){
@@ -174,13 +177,13 @@
 		sidefd = pfd[PRD];
 		mainfd = pfd[PWR];
 	}
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
-		Xerror2("try again", Errstr());
+		Xerror2("try again", strerror(errno));
 		break;
 	case 0:
 		clearwaitpids();
-		Close(mainfd);
+		close(mainfd);
 		start(p->code, pc+2, runq->local, runq->redir);
 		pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
 		runq->ret = 0;
@@ -187,7 +190,7 @@
 		break;
 	default:
 		addwaitpid(pid);
-		Close(sidefd);
+		close(sidefd);
 		pushredir(ROPEN, mainfd, mainfd);
 		shuffleredir();	/* shuffle redir to bottom of stack for Xpopredir() */
 		strcpy(name, Fdprefix);
@@ -203,9 +206,9 @@
 {
 	int pid;
 
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
-		Xerror2("try again", Errstr());
+		Xerror2("try again", strerror(errno));
 		break;
 	case 0:
 		clearwaitpids();
@@ -226,7 +229,7 @@
 {
 	int pid;
 
-	switch(pid = Fork()){
+	switch(pid = fork()){
 	case -1:
 		return -1;
 	case 0:
--- a/librc/here.c
+++ b/librc/here.c
@@ -1,7 +1,8 @@
-#include "rc.h"
+#include <rc.h>
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
+#include "y.tab.h"
 
 void psubst(io*, unsigned char*);
 void pstrs(io*, word*);
--- a/librc/io.c
+++ b/librc/io.c
@@ -1,4 +1,6 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
@@ -148,10 +150,10 @@
 pptr(io *f, void *p)
 {
 	static char hex[] = "0123456789ABCDEF";
-	unsigned long long v;
+	unsigned long v;
 	int n;
 
-	v = (unsigned long long)p;
+	v = (unsigned long)p;
 	if(sizeof(v) == sizeof(p) && v>>32)
 		for(n = 60;n>=32;n-=4) pchr(f, hex[(v>>n)&0xF]);
 	for(n = 28;n>=0;n-=4) pchr(f, hex[(v>>n)&0xF]);
@@ -274,8 +276,8 @@
 	}
 	else{
 		n = f->bufp - f->buf;
-		if(n && Write(f->fd, f->buf, n) != n){
-			Write(2, "Write error\n", 12);
+		if(n && write(f->fd, f->buf, n) != n){
+			write(2, "Write error\n", 12);
 			if(ntrap)
 				dotrap();
 		}
@@ -287,7 +289,7 @@
 void
 closeio(io *f)
 {
-	if(f->fd>=0) Close(f->fd);
+	if(f->fd>=0) close(f->fd);
 	free(closeiostr(f));
 }
 
@@ -295,7 +297,7 @@
 emptyiobuf(io *f)
 {
 	int n;
-	if(f->fd<0 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
+	if(f->fd<0 || (n = read(f->fd, f->buf, NBUF))<=0) return EOF;
 	f->bufp = f->buf;
 	f->ebuf = f->buf + n;
 	return *f->bufp++;
--- a/librc/lex.c
+++ b/librc/lex.c
@@ -1,7 +1,8 @@
-#include "rc.h"
+#include <rc.h>
 #include "io.h"
 #include "getflags.h"
 #include "fns.h"
+#include "y.tab.h"
 
 lexer *lex;
 
--- a/librc/mkfile
+++ /dev/null
@@ -1,46 +1,0 @@
-</$objtype/mkfile
-
-TARG=rc
-OFILES=\
-	code.$O\
-	exec.$O\
-	getflags.$O\
-	glob.$O\
-	here.$O\
-	io.$O\
-	lex.$O\
-	pcmd.$O\
-	pfnc.$O\
-	simple.$O\
-	subr.$O\
-	trap.$O\
-	tree.$O\
-	var.$O\
-	havefork.$O\
-	plan9.$O\
-	y.tab.$O\
-
-HFILES=rc.h\
-	y.tab.h\
-	io.h\
-	exec.h\
-	fns.h\
-	getflags.h\
-
-YFILES=syn.y
-
-BIN=/$objtype/bin
-
-UPDATE=\
-	mkfile\
-	$HFILES\
-	${OFILES:%.$O=%.c}\
-	$YFILES\
-	${TARG:%=/386/bin/%}\
-
-CFLAGS=$CFLAGS -DPlan9
-
-</sys/src/cmd/mkone
-
-clean:V:
-	rm -f [$OS].out *.[$OS] y.tab.? y.debug $TARG
--- a/librc/pcmd.c
+++ b/librc/pcmd.c
@@ -1,6 +1,7 @@
-#include "rc.h"
+#include <rc.h>
 #include "io.h"
 #include "fns.h"
+#include "y.tab.h"
 
 #define	c0	t->child[0]
 #define	c1	t->child[1]
--- a/librc/pfnc.c
+++ b/librc/pfnc.c
@@ -1,4 +1,4 @@
-#include "rc.h"
+#include <rc.h>
 #include "exec.h"
 #include "io.h"
 #include "fns.h"
--- a/librc/plan9.c
+++ /dev/null
@@ -1,494 +1,0 @@
-/*
- * Plan 9 versions of system-specific functions
- *	By convention, exported routines herein have names beginning with an
- *	upper case letter.
- */
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-#include "getflags.h"
-
-static void execrfork(void);
-static void execfinit(void);
-
-builtin Builtin[] = {
-	"cd",		execcd,
-	"whatis",	execwhatis,
-	"eval",		execeval,
-	"exec",		execexec,	/* but with popword first */
-	"exit",		execexit,
-	"shift",	execshift,
-	"wait",		execwait,
-	".",		execdot,
-	"flag",		execflag,
-	"finit",	execfinit,
-	"rfork",	execrfork,
-	0
-};
-
-char Rcmain[]="/rc/lib/rcmain";
-char Fdprefix[]="/fd/";
-
-char *Signame[] = {
-	"sigexit",	"sighup",	"sigint",	"sigquit",
-	"sigalrm",	"sigkill",	"sigfpe",	"sigterm",
-	0
-};
-static char *syssigname[] = {
-	"exit",		/* can't happen */
-	"hangup",
-	"interrupt",
-	"quit",		/* can't happen */
-	"alarm",
-	"kill",
-	"sys: fp: ",
-	"term",
-	0
-};
-
-/*
- * finit could be removed but is kept for
- * backwards compatibility, see: rcmain.plan9
- */
-static void
-execfinit(void)
-{
-	char *cmds = estrdup("for(i in '/env/fn#'*){. -bq $i}\n");
-	int line = runq->line;
-	poplist();
-	execcmds(openiocore(cmds, strlen(cmds)), estrdup(srcfile(runq)), runq->local, runq->redir);
-	runq->lex->line = line;
-	runq->lex->qflag = 1;
-}
-
-static void
-execrfork(void)
-{
-	int arg;
-	char *s;
-
-	switch(count(runq->argv->words)){
-	case 1:
-		arg = RFENVG|RFNAMEG|RFNOTEG;
-		break;
-	case 2:
-		arg = 0;
-		for(s = runq->argv->words->next->word;*s;s++) switch(*s){
-		default:
-			goto Usage;
-		case 'n':
-			arg|=RFNAMEG;  break;
-		case 'N':
-			arg|=RFCNAMEG;
-			break;
-		case 'm':
-			arg|=RFNOMNT;  break;
-		case 'e':
-			arg|=RFENVG;   break;
-		case 'E':
-			arg|=RFCENVG;  break;
-		case 's':
-			arg|=RFNOTEG;  break;
-		case 'f':
-			arg|=RFFDG;    break;
-		case 'F':
-			arg|=RFCFDG;   break;
-		}
-		break;
-	default:
-	Usage:
-		pfmt(err, "Usage: %s [fnesFNEm]\n", runq->argv->words->word);
-		setstatus("rfork usage");
-		poplist();
-		return;
-	}
-	if(rfork(arg)==-1){
-		pfmt(err, "%s: %s failed\n", argv0, runq->argv->words->word);
-		setstatus("rfork failed");
-	} else {
-		if(arg & RFCFDG){
-			redir *rp;
-			for(rp = runq->redir; rp; rp = rp->next)
-				rp->type = 0;
-		}
-		setstatus("");
-	}
-	poplist();
-}
-
-char*
-Env(char *name, int fn)
-{
-	static char buf[128];
-
-	strcpy(buf, "/env/");
-	if(fn) strcat(buf, "fn#");
-	return strncat(buf, name, sizeof(buf)-1);
-}
-
-void
-Vinit(void)
-{
-	int dir, fd, i, n;
-	Dir *ent;
-
-	dir = Open(Env("", 0), 0);
-	if(dir<0){
-		pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		return;
-	}
-	for(;;){
-		ent = 0;
-		n = dirread(dir, &ent);
-		if(n <= 0)
-			break;
-		for(i = 0; i<n; i++){
-			if(ent[i].length<=0 || strncmp(ent[i].name, "fn#", 3)==0)
-				continue;
-			if((fd = Open(Env(ent[i].name, 0), 0))>=0){
-				io *f = openiofd(fd);
-				word *w = 0, **wp = &w;
-				char *s;
-				while((s = rstr(f, "")) != 0){
-					*wp = Newword(s, (word*)0);
-					wp = &(*wp)->next;
-				}
-				closeio(f);
-				setvar(ent[i].name, w);
-				vlook(ent[i].name)->changed = 0;
-			}
-		}
-		free(ent);
-	}
-	Close(dir);
-}
-
-char*
-Errstr(void)
-{
-	static char err[ERRMAX];
-	rerrstr(err, sizeof err);
-	return err;
-}
-
-int
-Waitfor(int pid)
-{
-	thread *p;
-	Waitmsg *w;
-
-	if(pid >= 0 && !havewaitpid(pid))
-		return 0;
-
-	while((w = wait()) != nil){
-		delwaitpid(w->pid);
-		if(w->pid==pid){
-			setstatus(w->msg);
-			free(w);
-			return 0;
-		}
-		for(p = runq->ret;p;p = p->ret)
-			if(p->pid==w->pid){
-				p->pid=-1;
-				p->status = estrdup(w->msg);
-				break;
-			}
-		free(w);
-	}
-
-	if(strcmp(Errstr(), "interrupted")==0) return -1;
-	return 0;
-}
-
-static void
-addenv(var *v)
-{
-	word *w;
-	int fd;
-	io *f;
-
-	if(v->changed){
-		v->changed = 0;
-		if((fd = Creat(Env(v->name, 0)))<0)
-			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		else{
-			f = openiofd(fd);
-			for(w = v->val;w;w = w->next){
-				pstr(f, w->word);
-				pchr(f, '\0');
-			}
-			flushio(f);
-			closeio(f);
-		}
-	}
-	if(v->fnchanged){
-		v->fnchanged = 0;
-		if((fd = Creat(Env(v->name, 1)))<0)
-			pfmt(err, "%s: can't open: %s\n", argv0, Errstr());
-		else{
-			f = openiofd(fd);
-			if(v->fn)
-				pfmt(f, "fn %q %s\n", v->name, v->fn[v->pc-1].s);
-			flushio(f);
-			closeio(f);
-		}
-	}
-}
-
-static void
-updenvlocal(var *v)
-{
-	if(v){
-		updenvlocal(v->next);
-		addenv(v);
-	}
-}
-
-void
-Updenv(void)
-{
-	var *v, **h;
-	for(h = gvar;h!=&gvar[NVAR];h++)
-		for(v=*h;v;v = v->next)
-			addenv(v);
-	if(runq)
-		updenvlocal(runq->local);
-	if(err)
-		flushio(err);
-}
-
-void
-Exec(char **argv)
-{
-	exec(argv[0], argv+1);
-}
-
-int
-Fork(void)
-{
-	Updenv();
-	return rfork(RFPROC|RFFDG|RFREND);
-}
-
-
-typedef struct readdir readdir;
-struct readdir {
-	Dir	*dbuf;
-	int	i, n;
-	int	fd;
-};
-
-void*
-Opendir(char *name)
-{
-	readdir *rd;
-	int fd;
-	if((fd = Open(name, 0))<0)
-		return 0;
-	rd = new(readdir);
-	rd->dbuf = 0;
-	rd->i = 0;
-	rd->n = 0;
-	rd->fd = fd;
-	return rd;
-}
-
-static int
-trimdirs(Dir *d, int nd)
-{
-	int r, w;
-
-	for(r=w=0; r<nd; r++)
-		if(d[r].mode&DMDIR)
-			d[w++] = d[r];
-	return w;
-}
-
-char*
-Readdir(void *arg, int onlydirs)
-{
-	readdir *rd = arg;
-	int n;
-Again:
-	if(rd->i>=rd->n){	/* read */
-		free(rd->dbuf);
-		rd->dbuf = 0;
-		n = dirread(rd->fd, &rd->dbuf);
-		if(n>0){
-			if(onlydirs){
-				n = trimdirs(rd->dbuf, n);
-				if(n == 0)
-					goto Again;
-			}	
-			rd->n = n;
-		}else
-			rd->n = 0;
-		rd->i = 0;
-	}
-	if(rd->i>=rd->n)
-		return 0;
-	return rd->dbuf[rd->i++].name;
-}
-
-void
-Closedir(void *arg)
-{
-	readdir *rd = arg;
-	Close(rd->fd);
-	free(rd->dbuf);
-	free(rd);
-}
-
-static int interrupted = 0;
-
-static void
-notifyf(void*, char *s)
-{
-	int i;
-
-	for(i = 0;syssigname[i];i++) if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
-		if(strncmp(s, "sys: ", 5)!=0) interrupted = 1;
-		goto Out;
-	}
-	noted(NDFLT);
-	return;
-Out:
-	if(strcmp(s, "interrupt")!=0 || trap[i]==0){
-		trap[i]++;
-		ntrap++;
-	}
-	noted(NCONT);
-}
-
-void
-Trapinit(void)
-{
-	notify(notifyf);
-}
-
-long
-Write(int fd, void *buf, long cnt)
-{
-	return write(fd, buf, cnt);
-}
-
-long
-Read(int fd, void *buf, long cnt)
-{
-	return read(fd, buf, cnt);
-}
-
-long
-Seek(int fd, long cnt, long whence)
-{
-	return seek(fd, cnt, whence);
-}
-
-int
-Executable(char *file)
-{
-	Dir *statbuf;
-	int ret;
-
-	statbuf = dirstat(file);
-	if(statbuf == nil)
-		return 0;
-	ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
-	free(statbuf);
-	return ret;
-}
-
-int
-Open(char *file, int mode)
-{
-	static int tab[] = {OREAD,OWRITE,ORDWR,OREAD|ORCLOSE};
-	return open(file, tab[mode&3]);
-}
-
-void
-Close(int fd)
-{
-	close(fd);
-}
-
-int
-Creat(char *file)
-{
-	return create(file, OWRITE, 0666L);
-}
-
-int
-Dup(int a, int b)
-{
-	return dup(a, b);
-}
-
-int
-Dup1(int a)
-{
-	return dup(a, -1);
-}
-
-void
-Exit(void)
-{
-	Updenv();
-	exits(truestatus()?"":getstatus());
-}
-
-int
-Eintr(void)
-{
-	return interrupted;
-}
-
-void
-Noerror(void)
-{
-	interrupted = 0;
-}
-
-int
-Isatty(int fd)
-{
-	char buf[64];
-
-	if(fd2path(fd, buf, sizeof buf) != 0)
-		return 0;
-	/* might be /mnt/term/dev/cons */
-	return strlen(buf) >= 9 && strcmp(buf+strlen(buf)-9, "/dev/cons") == 0;
-}
-
-void
-Abort(void)
-{
-	abort();
-}
-
-static int newwdir;
-
-int
-Chdir(char *dir)
-{
-	newwdir = 1;
-	return chdir(dir);
-}
-
-void
-Prompt(char *s)
-{
-	pstr(err, s);
-	flushio(err);
-
-	if(newwdir){
-		char dir[4096];
-		int fd;
-		if((fd=Creat("/dev/wdir"))>=0){
-			getwd(dir, sizeof(dir));
-			Write(fd, dir, strlen(dir));
-			Close(fd);
-		}
-		newwdir = 0;
-	}
-}
--- a/librc/rc.h
+++ /dev/null
@@ -1,166 +1,0 @@
-/*
- * Plan9 is defined for plan 9
- * otherwise its UNIX.
- * Please don't litter the code with ifdefs.  The three below (and one in
- * getflags) should be enough.
- */
-#ifdef Plan9
-#include <u.h>
-#include <libc.h>
-#define NSIG	32
-#define	SIGINT	2
-#define	SIGQUIT	3
-#else
-#include <stdlib.h>
-#include <stdarg.h>
-#include <unistd.h>
-#include <string.h>
-#include <signal.h>
-#ifndef NSIG
-#define NSIG 32
-#endif
-#endif
-
-#define	YYMAXDEPTH	500
-#ifndef PAREN
-#include "y.tab.h"
-#endif
-typedef struct tree tree;
-typedef struct word word;
-typedef struct io io;
-typedef union code code;
-typedef struct var var;
-typedef struct list list;
-typedef struct lexer lexer;
-typedef struct redir redir;
-typedef struct thread thread;
-typedef struct builtin builtin;
-
-#pragma incomplete word
-#pragma incomplete io
-
-struct tree{
-	int	type;
-	int	rtype, fd0, fd1;	/* details of REDIR PIPE DUP tokens */
-	int	line;
-	char	glob;			/* 0=string, 1=glob, 2=pattern see globprop() and noglobs() */
-	char	quoted;
-	char	iskw;
-	char	*str;
-	tree	*child[3];
-	tree	*next;
-};
-tree *newtree(void);
-tree *token(char*, int), *klook(char*), *tree1(int, tree*);
-tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
-tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
-tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
-tree *simplemung(tree*);
-tree *globprop(tree*);
-char *fnstr(tree*);
-
-/*
- * The first word of any code vector is a reference count
- * and the second word is a string for srcfile().
- * Code starts at pc 2. The last code word must be a zero
- * terminator for codefree().
- * Always create a new reference to a code vector by calling codecopy(.).
- * Always call codefree(.) when deleting a reference.
- */
-union code{
-	void	(*f)(void);
-	int	i;
-	char	*s;
-};
-
-#define	NTOK	8192
-
-struct lexer{
-	io	*input;
-	char	*file;
-	int	line;
-
-	char	*prolog;
-	char	*epilog;
-
-	int	peekc;
-	int	future;
-	int	lastc;
-
-	char	eof;
-	char	inquote;
-	char	incomm;
-	char	lastword;	/* was the last token read a word or compound word terminator? */
-	char	lastdol;	/* was the last token read '$' or '$#' or '"'? */
-	char	iflast;		/* static `if not' checking */
-
-	char	qflag;
-
-	char	tok[NTOK];
-};
-extern lexer *lex;		/* current lexer */
-lexer *newlexer(io*, char*);
-void freelexer(lexer*);
-
-#define	APPEND	1
-#define	WRITE	2
-#define	READ	3
-#define	HERE	4
-#define	DUPFD	5
-#define	CLOSE	6
-#define RDWR	7
-
-struct var{
-	var	*next;		/* next on hash or local list */
-	word	*val;		/* value */
-	code	*fn;		/* pointer to function's code vector */
-	int	pc;		/* pc of start of function */
-	char	fnchanged;
-	char	changed;
-	char	name[];
-};
-var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
-void setvar(char*, word*), freevar(var*);
-
-#define	NVAR	521
-extern var *gvar[NVAR];		/* hash for globals */
-
-#define	new(type)	((type *)emalloc(sizeof(type)))
-
-void *emalloc(long);
-void *erealloc(void *, long);
-char *estrdup(char*);
-
-/*
- * Glob character escape in strings:
- *	In a string, GLOB must be followed by *?[ or GLOB.
- *	GLOB* matches any string
- *	GLOB? matches any single character
- *	GLOB[...] matches anything in the brackets
- *	GLOBGLOB matches GLOB
- */
-#define	GLOB	((char)0x01)
-/*
- * Is c the first character of a utf sequence?
- */
-#define	onebyte(c)	(((c)&0x80)==0x00)
-#define twobyte(c)	(((c)&0xe0)==0xc0)
-#define threebyte(c)	(((c)&0xf0)==0xe0)
-#define fourbyte(c)	(((c)&0xf8)==0xf0)
-#define xbyte(c)	(((c)&0xc0)==0x80)
-
-extern char *argv0;
-extern int nerror;		/* number of errors encountered during compilation */
-extern int doprompt;		/* is it time for a prompt? */
-extern io *err;
-
-/*
- * Which fds are the reading/writing end of a pipe?
- * Unfortunately, this can vary from system to system.
- * 9th edition Unix doesn't care, the following defines
- * work on plan 9.
- */
-#define	PRD	0
-#define	PWR	1
-extern char Rcmain[], Fdprefix[];
-extern char *Signame[];
--- /dev/null
+++ b/librc/rcmain.drawcpu
@@ -1,0 +1,38 @@
+# rcmain: drawcpu version
+if(~ $#home 0) home=$HOME
+if(~ $#ifs 0) ifs=' 	
+'
+profile=$home/.rcrc
+switch($#prompt){
+case 0
+	prompt=('% ' '	')
+case 1
+	prompt=($prompt '	')
+}
+if(~ $rcname ?.out) prompt=('broken! ' '	')
+if(flag p) path=/bin
+if not {
+	finit
+	if(~ $#path 0) path=(. /bin /usr/bin /usr/local/bin)
+}
+fn sigexit
+if(! ~ $#cflag 0){
+	if(flag l) {
+		. -q $profile
+	}
+	status=''
+	eval $cflag
+}
+if not if(flag i){
+	if(flag l) {
+		. -q $profile
+	}
+	status=''
+	if(! ~ $#* 0) . $*
+	. -i /dev/fd/0
+}
+if not if(~ $#* 0) . /dev/fd/0
+if not{
+	status=''
+	. $*
+}
--- a/librc/rcmain.plan9
+++ /dev/null
@@ -1,41 +1,0 @@
-# rcmain: Plan 9 version
-if(~ $#home 0) home=/
-if(~ $#ifs 0) ifs=' 	
-'
-switch($#prompt){
-case 0
-	prompt=('% ' '	')
-case 1
-	prompt=($prompt '	')
-}
-if(~ $rcname ?.out) prompt=('broken! ' '	')
-if(flag p) path=/bin
-if not{
-	for(i in '/env/fn#'*){
-		. -bq $i
-	}
-	if(~ $#path 0) path=(/bin .)
-}
-fn sigexit
-if(! ~ $#cflag 0){
-	if(flag l){
-		. -q /rc/lib/rcmain.local
-		. -q $home/lib/profile
-	}
-	status=''
-	eval $cflag
-}
-if not if(flag i){
-	if(flag l){
-		. -q /rc/lib/rcmain.local
-		. -q $home/lib/profile
-	}
-	status=''
-	if(! ~ $#* 0) . $*
-	. -i '#d/0'
-}
-if not if(~ $#* 0) . '#d/0'
-if not{
-	status=''
-	. $*
-}
--- a/librc/rcmain.unix
+++ /dev/null
@@ -1,38 +1,0 @@
-# rcmain: unix version
-if(~ $#home 0) home=$HOME
-if(~ $#ifs 0) ifs=' 	
-'
-profile=$home/.rcrc
-switch($#prompt){
-case 0
-	prompt=('% ' '	')
-case 1
-	prompt=($prompt '	')
-}
-if(~ $rcname ?.out) prompt=('broken! ' '	')
-if(flag p) path=/bin
-if not {
-	finit
-	if(~ $#path 0) path=(. /bin /usr/bin /usr/local/bin)
-}
-fn sigexit
-if(! ~ $#cflag 0){
-	if(flag l) {
-		. -q $profile
-	}
-	status=''
-	eval $cflag
-}
-if not if(flag i){
-	if(flag l) {
-		. -q $profile
-	}
-	status=''
-	if(! ~ $#* 0) . $*
-	. -i /dev/fd/0
-}
-if not if(~ $#* 0) . /dev/fd/0
-if not{
-	status=''
-	. $*
-}
--- a/librc/simple.c
+++ b/librc/simple.c
@@ -1,7 +1,10 @@
 /*
  * Maybe `simple' is a misnomer.
  */
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
+#include <errno.h>
 #include "getflags.h"
 #include "exec.h"
 #include "io.h"
@@ -94,7 +97,7 @@
 		}
 		else{
 			if((pid = execforkexec()) < 0){
-				Xerror2("try again", Errstr());
+				Xerror2("try again", strerror(errno));
 				return;
 			}
 			poplist();
@@ -114,15 +117,15 @@
 		switch(rp->type){
 		case ROPEN:
 			if(rp->from!=rp->to){
-				Dup(rp->from, rp->to);
-				Close(rp->from);
+				dup2(rp->from, rp->to);
+				close(rp->from);
 			}
 			break;
 		case RDUP:
-			Dup(rp->from, rp->to);
+			dup2(rp->from, rp->to);
 			break;
 		case RCLOSE:
-			Close(rp->from);
+			close(rp->from);
 			break;
 		}
 	}
@@ -144,7 +147,7 @@
 }
 
 char*
-makepath(char *dir, char *file)
+rcmakepath(char *dir, char *file)
 {
 	char *path;
 	int m, n = strlen(dir);
@@ -184,10 +187,11 @@
 	Updenv();
 	doredir(runq->redir);
 	for(path = searchpath(argv[1], "path"); path; path = path->next){
-		argv[0] = makepath(path->word, argv[1]);
-		Exec(argv);
+		argv[0] = rcmakepath(path->word, argv[1]);
+		// TODO: execve + env from our fs
+		execv(argv[0], argv+1);
 	}
-	setstatus(Errstr());
+	setstatus(strerror(errno));
 	pfln(err, srcfile(runq), runq->line);
 	pfmt(err, ": %s: %s\n", argv[1], getstatus());
 	Xexit();
@@ -215,8 +219,8 @@
 	case 2:
 		a = a->next;
 		for(cdpath = searchpath(a->word, "cdpath"); cdpath; cdpath = cdpath->next){
-			dir = makepath(cdpath->word, a->word);
-			if(Chdir(dir)>=0){
+			dir = rcmakepath(cdpath->word, a->word);
+			if(chdir(dir)>=0){
 				if(cdpath->word[0] != '\0' && strcmp(cdpath->word, ".") != 0)
 					pfmt(err, "%s\n", dir);
 				free(dir);
@@ -226,15 +230,15 @@
 			free(dir);
 		}
 		if(cdpath==0)
-			pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
+			pfmt(err, "Can't cd %s: %s\n", a->word, strerror(errno));
 		break;
 	case 1:
 		a = vlook("home")->val;
 		if(a){
-			if(Chdir(a->word)>=0)
+			if(chdir(a->word)>=0)
 				setstatus("");
 			else
-				pfmt(err, "Can't cd %s: %s\n", a->word, Errstr());
+				pfmt(err, "Can't cd %s: %s\n", a->word, strerror(errno));
 		}
 		else
 			pfmt(err, "Can't cd -- $home empty\n");
@@ -394,20 +398,15 @@
 	file = 0;
 	fd = -1;
 	for(path = searchpath(argv->word, "path"); path; path = path->next){
-		file = makepath(path->word, argv->word);
-		fd = Open(file, 0);
+		file = rcmakepath(path->word, argv->word);
+		fd = open(file, 0);
 		if(fd >= 0)
 			break;
-		if(strcmp(file, "/dev/stdin")==0){	/* for sun & ucb */
-			fd = Dup1(0);
-			if(fd>=0)
-				break;
-		}
 		free(file);
 	}
 	if(fd<0){
 		if(!qflag)
-			Xerror3(". can't open", argv->word, Errstr());
+			Xerror3(". can't open", argv->word, strerror(errno));
 		freewords(argv);
 		return;
 	}
@@ -501,7 +500,7 @@
 				pfmt(out, "builtin %s\n", a->word);
 			else {
 				for(path = searchpath(a->word, "path"); path; path = path->next){
-					file = makepath(path->word, a->word);
+					file = rcmakepath(path->word, a->word);
 					if(Executable(file)){
 						pfmt(out, "%s\n", file);
 						free(file);
--- a/librc/subr.c
+++ b/librc/subr.c
@@ -1,4 +1,6 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
 #include "io.h"
 #include "fns.h"
 
@@ -20,15 +22,6 @@
 	return p;
 }
 
-char*
-estrdup(char *s)
-{
-	int n = strlen(s)+1;
-	char *d = emalloc(n);
-	memmove(d, s, n);
-	return d;
-}
-
 void
 pfln(io *fd, char *file, int line)
 {
@@ -60,15 +53,4 @@
 	bp = s;
 	iacvt(n);
 	*bp='\0';
-}
-
-void
-panic(char *s, int n)
-{
-	pfmt(err, "%s: ", argv0);
-	pfmt(err, s, n);
-	pchr(err, '\n');
-	flushio(err);
-
-	Abort();
 }
--- /dev/null
+++ b/librc/syn.y
@@ -1,0 +1,92 @@
+%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
+%term WORD REDIR DUP PIPE SUB
+%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
+/* operator priorities -- lowest first */
+%left IF WHILE FOR SWITCH ')' NOT
+%left ANDAND OROR
+%left BANG SUBSHELL
+%left PIPE
+%left '^'
+%right '$' COUNT '"'
+%left SUB
+%{
+#include <rc.h>
+#include "fns.h"
+%}
+%union{
+	struct tree *tree;
+};
+%type<tree> line paren brace body cmdsa cmdsan assign epilog redir
+%type<tree> cmd simple first word comword keyword words
+%type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN
+%type<tree> WORD REDIR DUP PIPE
+%%
+rc:				{ return 1;}
+|	line '\n'		{readhere(lex->input); return !compile($1);}
+line:	cmd
+|	cmdsa line		{$$=tree2(';', $1, $2);}
+body:	cmd
+|	cmdsan body		{$$=tree2(';', $1, $2);}
+cmdsa:	cmd ';'
+|	cmd '&'			{$$=tree1('&', $1);}
+cmdsan:	cmdsa
+|	cmd '\n'		{readhere(lex->input);}
+brace:	'{' body '}'		{$$=tree1(BRACE, $2);}
+paren:	'(' body ')'		{$$=tree1(PCMD, $2);}
+assign:	first '=' word		{$$=tree2('=', $1, $3);}
+epilog:				{$$=0;}
+|	redir epilog		{$$=mung2($1, $1->child[0], $2);}
+redir:	REDIR word		{$$=mung1($1, $2); if($$->rtype==HERE) heredoc($$);}
+|	DUP
+cmd:				{$$=0;}
+|	brace epilog		{$$=epimung($1, $2);}
+|	IF paren {skipnl();} cmd
+				{$$=mung2($1, $2, $4);}
+|	IF NOT {skipnl();} cmd	{$$=mung1($2, $4);}
+|	FOR '(' word IN words ')' {skipnl();} cmd
+	/*
+	 * if ``words'' is nil, we need a tree element to distinguish between 
+	 * for(i in ) and for(i), the former being a loop over the empty set
+	 * and the latter being the implicit argument loop.  so if $5 is nil
+	 * (the empty set), we represent it as "()".  don't parenthesize non-nil
+	 * functions, to avoid growing parentheses every time we reread the
+	 * definition.
+	 */
+				{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
+|	FOR '(' word ')' {skipnl();} cmd
+				{$$=mung3($1, $3, (tree*)0, $6);}
+|	WHILE paren {skipnl();} cmd
+				{$$=mung2($1, $2, $4);}
+|	SWITCH word {skipnl();} brace
+				{$$=tree2(SWITCH, $2, $4);}
+|	simple			{$$=simplemung($1);}
+|	TWIDDLE word words	{$$=mung2($1, $2, $3);}
+|	cmd ANDAND cmd		{$$=tree2(ANDAND, $1, $3);}
+|	cmd OROR cmd		{$$=tree2(OROR, $1, $3);}
+|	cmd PIPE cmd		{$$=mung2($2, $1, $3);}
+|	redir cmd  %prec BANG	{$$=mung2($1, $1->child[0], $2);}
+|	assign cmd %prec BANG	{$$=mung3($1, $1->child[0], $1->child[1], $2);}
+|	BANG cmd		{$$=mung1($1, $2);}
+|	SUBSHELL cmd		{$$=mung1($1, $2);}
+|	FN words brace		{$$=tree2(FN, $2, $3);}
+|	FN words		{$$=tree1(FN, $2);}
+simple:	first
+|	simple word		{$$=globprop(tree2(ARGLIST, $1, $2));}
+|	simple redir		{$$=globprop(tree2(ARGLIST, $1, $2));}
+first:	comword	
+|	first '^' word		{$$=globprop(tree2('^', $1, $3));}
+word:	keyword			{lex->lastword=1; $1->type=WORD;}
+|	comword
+|	word '^' word		{$$=globprop(tree2('^', $1, $3));}
+comword: '$' word		{$$=tree1('$', $2);}
+|	'$' word SUB words ')'	{$$=tree2(SUB, $2, $4);}
+|	'"' word		{$$=tree1('"', $2);}
+|	COUNT word		{$$=tree1(COUNT, $2);}
+|	WORD
+|	'`' brace		{$$=tree2('`', (tree*)0, $2);}
+|	'`' word brace		{$$=tree2('`', $2, $3);}
+|	'(' words ')'		{$$=globprop(tree1(PAREN, $2));}
+|	REDIR brace		{$$=mung1($1, $2); $$->type=PIPEFD;}
+keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
+words:				{$$=(tree*)0;}
+|	words word		{$$=tree2(WORDS, $1, $2);}
--- a/librc/trap.c
+++ b/librc/trap.c
@@ -1,7 +1,8 @@
-#include "rc.h"
+#include <rc.h>
 #include "exec.h"
 #include "fns.h"
 #include "io.h"
+#include "y.tab.h"
 
 int ntrap;
 int trap[NSIG];
@@ -16,7 +17,7 @@
 	while(ntrap) for(i = 0;i<NSIG;i++) while(trap[i]){
 		--trap[i];
 		--ntrap;
-		if(getpid()!=mypid) Exit();
+		if(getpid()!=mypid) _exit(0);
 		trapreq = vlook(Signame[i]);
 		if(trapreq->fn)
 			startfunc(trapreq, copywords(starval, (word*)0), (var*)0, (redir*)0);
@@ -29,6 +30,6 @@
 			 */
 			while(!runq->iflag) Xreturn();
 		}
-		else Exit();
+		else _exit(0);
 	}
 }
--- a/librc/tree.c
+++ b/librc/tree.c
@@ -1,7 +1,9 @@
-#include "rc.h"
+#include <u.h>
+#include <libc.h>
+#include <rc.h>
 #include "io.h"
 #include "fns.h"
-
+#include "y.tab.h"
 /*
  * create and clear a new tree node, and add it
  * to the node list.
--- a/librc/unix.c
+++ /dev/null
@@ -1,420 +1,0 @@
-/*
- * Unix versions of system-specific functions
- *	By convention, exported routines herein have names beginning with an
- *	upper case letter.
- */
-#include "rc.h"
-#include "exec.h"
-#include "io.h"
-#include "fns.h"
-#include "getflags.h"
-
-#include <errno.h>
-#include <fcntl.h>
-#include <dirent.h>
-#include <sys/wait.h>
-
-static void execfinit(void);
-
-builtin Builtin[] = {
-	"cd",		execcd,
-	"whatis",	execwhatis,
-	"eval",		execeval,
-	"exec",		execexec,	/* but with popword first */
-	"exit",		execexit,
-	"shift",	execshift,
-	"wait",		execwait,
-	".",		execdot,
-	"flag",		execflag,
-	"finit",	execfinit,
-	0
-};
-
-char Rcmain[] = PREFIX "/lib/rcmain";
-char Fdprefix[] = "/dev/fd/";
-
-char *Signame[NSIG];
-
-#define SEP '\1'
-extern char **environ;
-static char **envp;
-
-static void
-Xrdfn(void)
-{
-	char *s;
-	int len;
-
-	for(;*envp;envp++){
-		for(s=*envp;*s && *s!='(' && *s!='=';s++);
-		switch(*s){
-		case '(':		/* Bourne again */
-			if(strncmp(s, "()fn ", 5)!=0)
-				continue;
-			s=estrdup(s+2);
-			len=strlen(s);
-			s[len++]='\n';
-			envp++;
-			runq->pc--;	/* re-execute */
-			execcmds(openiocore(s, len), estrdup("*environ*"), runq->local, runq->redir);
-			runq->lex->qflag = 1;
-			return;
-		default:
-			continue;
-		}
-	}
-}
-
-static void
-execfinit(void)
-{
-	static union code rdfns[5];
-	if(rdfns[0].i==0){
-		rdfns[0].i = 1;
-		rdfns[1].s = "*rdfns*";
-		rdfns[2].f = Xrdfn;
-		rdfns[3].f = Xreturn;
-		rdfns[4].f = 0;
-	}
-	poplist();
-	envp=environ;
-	start(rdfns, 2, runq->local, runq->redir);
-}
-
-static int
-cmpenv(const void *aa, const void *ab)
-{
-	return strcmp(*(char**)aa, *(char**)ab);
-}
-
-static char**
-mkenv(void)
-{
-	char **env, **ep, *p, *q;
-	struct var **h, *v;
-	struct word *a;
-	int nvar = 0, nchr = 0, sep;
-
-	/*
-	 * Slightly kludgy loops look at locals then globals.
-	 * locals no longer exist - geoff
-	 */
-	for(h = gvar-1; h != &gvar[NVAR]; h++)
-	for(v = h >= gvar? *h: runq->local; v ;v = v->next){
-		if((v==vlook(v->name)) && v->val){
-			nvar++;
-			nchr+=strlen(v->name)+1;
-			for(a = v->val;a;a = a->next)
-				nchr+=strlen(a->word)+1;
-		}
-		if(v->fn){
-			nvar++;
-			nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
-		}
-	}
-	env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
-	ep = env;
-	p = (char *)&env[nvar+1];
-	for(h = gvar-1; h != &gvar[NVAR]; h++)
-	for(v = h >= gvar? *h: runq->local;v;v = v->next){
-		if((v==vlook(v->name)) && v->val){
-			*ep++=p;
-			q = v->name;
-			while(*q) *p++=*q++;
-			sep='=';
-			for(a = v->val;a;a = a->next){
-				*p++=sep;
-				sep = SEP;
-				q = a->word;
-				while(*q) *p++=*q++;
-			}
-			*p++='\0';
-		}
-		if(v->fn){
-			*ep++=p;
-			*p++='#'; *p++='('; *p++=')';	/* to fool Bourne */
-			*p++='f'; *p++='n'; *p++=' ';
-			q = v->name;
-			while(*q) *p++=*q++;
-			*p++=' ';
-			q = v->fn[v->pc-1].s;
-			while(*q) *p++=*q++;
-			*p++='\0';
-		}
-	}
-	*ep = 0;
-	qsort((void *)env, nvar, sizeof ep[0], cmpenv);
-	return env;	
-}
-
-static word*
-envval(char *s)
-{
-	char *t, c;
-	word *v;
-	for(t=s;*t&&*t!=SEP;t++);
-	c=*t;
-	*t='\0';
-	v=newword(s, c=='\0'?(word*)0:envval(t+1));
-	*t=c;
-	return v;
-}
-
-void
-Vinit(void)
-{
-	char *s;
-
-	for(envp=environ;*envp;envp++){
-		for(s=*envp;*s && *s!='(' && *s!='=';s++);
-		switch(*s){
-		case '=':
-			*s='\0';
-			setvar(*envp, envval(s+1));
-			*s='=';
-			break;
-		default: continue;
-		}
-	}
-}
-
-static void
-sighandler(int sig)
-{
-	trap[sig]++;
-	ntrap++;
-}
-
-void
-Trapinit(void)
-{
-	int i;
-
-	Signame[0] = "sigexit";
-
-#ifdef SIGINT
-	Signame[SIGINT] = "sigint";
-#endif
-#ifdef SIGTERM
-	Signame[SIGTERM] = "sigterm";
-#endif
-#ifdef SIGHUP
-	Signame[SIGHUP] = "sighup";
-#endif
-#ifdef SIGQUIT
-	Signame[SIGQUIT] = "sigquit";
-#endif
-#ifdef SIGPIPE
-	Signame[SIGPIPE] = "sigpipe";
-#endif
-#ifdef SIGUSR1
-	Signame[SIGUSR1] = "sigusr1";
-#endif
-#ifdef SIGUSR2
-	Signame[SIGUSR2] = "sigusr2";
-#endif
-#ifdef SIGBUS
-	Signame[SIGBUS] = "sigbus";
-#endif
-#ifdef SIGWINCH
-	Signame[SIGWINCH] = "sigwinch";
-#endif
-
-	for(i=1; i<NSIG; i++) if(Signame[i]){
-#ifdef SA_RESTART
-		struct sigaction a;
-
-		sigaction(i, NULL, &a);
-		a.sa_flags &= ~SA_RESTART;
-		a.sa_handler = sighandler;
-		sigaction(i, &a, NULL);
-#else
-		signal(i, sighandler);
-#endif
-	}
-}
-
-char*
-Errstr(void)
-{
-	return strerror(errno);
-}
-
-int
-Waitfor(int pid)
-{
-	thread *p;
-	char num[12];
-	int wpid, status;
-
-	if(pid >= 0 && !havewaitpid(pid))
-		return 0;
-	while((wpid = wait(&status))!=-1){
-		delwaitpid(wpid);
-		inttoascii(num, WIFSIGNALED(status)?WTERMSIG(status)+1000:WEXITSTATUS(status));
-		if(wpid==pid){
-			setstatus(num);
-			return 0;
-		}
-		for(p = runq->ret;p;p = p->ret)
-			if(p->pid==wpid){
-				p->pid=-1;
-				p->status = estrdup(num);
-				break;
-			}
-	}
-	if(Eintr()) return -1;
-	return 0;
-}
-
-static char **nextenv;
-
-void
-Updenv(void)
-{
-	if(nextenv){
-		free(nextenv);
-		nextenv = NULL;
-	}
-	if(err)
-		flushio(err);
-}
-
-void
-Exec(char **argv)
-{
-	if(nextenv==NULL) nextenv=mkenv();
-	execve(argv[0], argv+1, nextenv);
-}
-
-int
-Fork(void)
-{
-	Updenv();
-	return fork();
-}
-
-void*
-Opendir(char *name)
-{
-	return opendir(name);
-}
-
-char*
-Readdir(void *arg, int onlydirs)
-{
-	DIR *rd = arg;
-	struct dirent *ent = readdir(rd);
-	if(ent == NULL)
-		return 0;
-	return ent->d_name;
-}
-
-void
-Closedir(void *arg)
-{
-	DIR *rd = arg;
-	closedir(rd);
-}
-
-long
-Write(int fd, void *buf, long cnt)
-{
-	return write(fd, buf, cnt);
-}
-
-long
-Read(int fd, void *buf, long cnt)
-{
-	return read(fd, buf, cnt);
-}
-
-long
-Seek(int fd, long cnt, long whence)
-{
-	return lseek(fd, cnt, whence);
-}
-
-int
-Executable(char *file)
-{
-	return access(file, 01)==0;
-}
-
-int
-Open(char *file, int mode)
-{
-	static int tab[] = {O_RDONLY,O_WRONLY,O_RDWR,O_RDONLY};
-	int fd = open(file, tab[mode&3]);
-	if(fd >= 0 && mode == 3)
-		unlink(file);
-	return fd;
-}
-
-void
-Close(int fd)
-{
-	close(fd);
-}
-
-int
-Creat(char *file)
-{
-	return creat(file, 0666L);
-}
-
-int
-Dup(int a, int b)
-{
-	return dup2(a, b);
-}
-
-int
-Dup1(int a)
-{
-	return dup(a);
-}
-
-void
-Exit(void)
-{
-	Updenv();
-	exit(truestatus()?0:1);
-}
-
-int
-Eintr(void)
-{
-	return errno==EINTR;
-}
-
-void
-Noerror(void)
-{
-	errno=0;
-}
-
-int
-Isatty(int fd)
-{
-	return isatty(fd);
-}
-
-void
-Abort(void)
-{
-	abort();
-}
-
-int
-Chdir(char *dir)
-{
-	return chdir(dir);
-}
-
-void
-Prompt(char *s)
-{
-	pstr(err, s);
-	flushio(err);
-}
--- a/librc/var.c
+++ b/librc/var.c
@@ -1,6 +1,7 @@
-#include "rc.h"
+#include <rc.h>
 #include "exec.h"
 #include "fns.h"
+#include "y.tab.h"
 
 var *gvar[NVAR];
 
--- a/librc/y.tab.c
+++ b/librc/y.tab.c
@@ -126,7 +126,7 @@
 /* Copy the first part of user declarations.  */
 #line 12 "syn.y"
 
-#include "rc.h"
+#include <rc.h>
 #include "fns.h"
 
 
--- a/libsec/x509.c
+++ b/libsec/x509.c
@@ -168,19 +168,6 @@
 	return p;
 }
 
-static char*
-estrdup(char *s)
-{
-	char *d;
-	int n;
-
-	n = strlen(s)+1;
-	d = emalloc(n);
-	memmove(d, s, n);
-	return d;
-}
-
-
 /*
  * Decode a[0..len] as a BER encoding of an ASN1 type.
  * The return value is one of ASN_OK, etc.
--- a/main.c
+++ b/main.c
@@ -9,6 +9,7 @@
 
 char *argv0;
 char *authserver = "";
+char *dbgfile = "./debug.log";
 
 void
 sizebug(void)
@@ -72,7 +73,9 @@
 	bind("#N", "/dev", MAFTER);
 	bind("#C", "/", MAFTER);
 
+	/* TODO: flag for debug */
 	fd = open("/dev/cons", ORDWR);
+	dbg = open(dbgfile, OWRITE);
 	if(session(fd) < 0)
 		fprint(dbg, "session failed: %r\n");
 	close(fd);
--- a/session.c
+++ b/session.c
@@ -1,10 +1,6 @@
 #include <u.h>
 #include <libc.h>
-#include <auth.h>
-#include <fcall.h>
-#include <authsrv.h>
-#include <libsec.h>
-#include "drawcpu.h"
+#include <rc.h>
 
 // TODO: aanserver
 static void
@@ -18,13 +14,14 @@
 int
 session(int fd)
 {
-    int n;
     char buf[1024];
-    //while (1) {
-        n = read(fd, buf, sizeof buf);
-        
-    //}
-        //return rcmain(buf, fd);
-    // sed out any line that says 'service=cpu' and put 'service=unix'
+    read(fd, buf, sizeof buf);
+    char *cmd[] = {
+        "rc",
+        "-c",
+        buf
+    };
+
+    runscript(fd, 1, cmd);
     return -1;
 }