all: DragonFly port.
Fix compilation problems, libdraw still doesn't work right yet.

LGTM=rsc
R=rsc
https://codereview.appspot.com/67820046
diff --git a/INSTALL b/INSTALL
index 9c5592e..f8b8587 100755
--- a/INSTALL
+++ b/INSTALL
@@ -50,6 +50,12 @@
        echo "LDFLAGS='-L/usr/local/lib'" >> $PLAN9/config
 fi
 
+if [ `uname` = DragonFly ]; then
+       echo "* Running on DragonFly BSD, adjusting linker flags"
+       echo "LDFLAGS='-L/usr/local/lib -pthread'" >> $PLAN9/config
+       echo "CFLAGS='-pthread'" >> $PLAN9/config
+fi
+
 if [ `uname` = OpenBSD ]; then
        echo "* Running on OpenBSD, adjusting linker flags"
        echo "LDFLAGS='-L/usr/X11R6/lib -pthread'" >> $PLAN9/config
diff --git a/bin/9c b/bin/9c
index 78ce552..85aa082 100755
--- a/bin/9c
+++ b/bin/9c
@@ -77,7 +77,7 @@
 case "$tag" in
 *FreeBSD*gcc*)	usegcc ;;
 *FreeBSD*clang*)	useclang ;;
-*BSD*)	usegcc ;;
+*DragonFly*|*BSD*)	usegcc ;;
 *Darwin-x86_64*clang*)
 		useclang
 		cflags="$ngflags -g3 -m64"
diff --git a/bin/9l b/bin/9l
index 011da24..d07bd89 100755
--- a/bin/9l
+++ b/bin/9l
@@ -24,7 +24,7 @@
 		;;
 	esac
 	;;
-*BSD*)
+*DragonFly*|*BSD*)
 	ld=${CC9:-gcc}
 	userpath=true
 	extralibs="$extralibs -lutil"
diff --git a/src/cmd/9660srv/main.c b/src/cmd/9660srv/main.c
index cd20570..44fdc51 100644
--- a/src/cmd/9660srv/main.c
+++ b/src/cmd/9660srv/main.c
@@ -2,6 +2,7 @@
 #include <libc.h>
 #include <auth.h>
 #include <fcall.h>
+#include <errno.h>
 #include "dat.h"
 #include "fns.h"
 
@@ -38,7 +39,6 @@
 uchar mdata[Maxiosize];
 char fdata[Maxfdata];
 uchar statbuf[STATMAX];
-int errno;
 
 
 extern Xfsub	*xsublist[];
diff --git a/src/cmd/9term/DragonFly.c b/src/cmd/9term/DragonFly.c
new file mode 100644
index 0000000..eec79c2
--- /dev/null
+++ b/src/cmd/9term/DragonFly.c
@@ -0,0 +1 @@
+#include "bsdpty.c"
diff --git a/src/cmd/9term/mkfile b/src/cmd/9term/mkfile
index e1ef4d6..4546d66 100644
--- a/src/cmd/9term/mkfile
+++ b/src/cmd/9term/mkfile
@@ -10,7 +10,7 @@
 
 <$PLAN9/src/mkmany
 
-Darwin.$O Linux.$O FreeBSD.$O: bsdpty.c
+Darwin.$O Linux.$O FreeBSD.$O DragonFly.$O: bsdpty.c
 
 $O.9term: data.$O scrl.$O time.$O util.$O wind.$O
 
diff --git a/src/cmd/auxstats/DragonFly.c b/src/cmd/auxstats/DragonFly.c
new file mode 100644
index 0000000..ec93104
--- /dev/null
+++ b/src/cmd/auxstats/DragonFly.c
@@ -0,0 +1,10 @@
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include "dat.h"
+
+void (*statfn[])(int) = 
+{
+	0
+};
+
diff --git a/src/cmd/eqn/lex.c b/src/cmd/eqn/lex.c
index 99a716b..2eddb6d 100644
--- a/src/cmd/eqn/lex.c
+++ b/src/cmd/eqn/lex.c
@@ -1,6 +1,7 @@
 #include "e.h"
 #include "y.tab.h"
 #include <ctype.h>
+#include <errno.h>
 
 #define	SSIZE	1000
 char	token[SSIZE];
@@ -19,7 +20,7 @@
 	register int c;
 	tbl *tp;
 
-  begin:
+begin:
 	while ((c = input()) == ' ' || c == '\n' || c == '\t')
 		;
 	yylval = c;
@@ -236,7 +237,6 @@
 	char name[100];
 	FILE *fin;
 	int c;
-	extern int errno;
 
 	while ((c = input()) == ' ')
 		;
@@ -260,7 +260,7 @@
 		ERROR "Bizarre delimiters" FATAL;
 	lefteq = token[0];
 	righteq = token[1];
-        if (!isprint(lefteq) || !isprint(righteq))
+	if (!isprint(lefteq) || !isprint(righteq))
 		ERROR "Bizarre delimiters" FATAL;
 	if (lefteq == 'o' && righteq == 'f')
 		lefteq = righteq = '\0';
diff --git a/src/cmd/tpic/input.c b/src/cmd/tpic/input.c
index a5928ec..6885f65 100644
--- a/src/cmd/tpic/input.c
+++ b/src/cmd/tpic/input.c
@@ -428,8 +428,6 @@
 double
 errcheck(double x, char *s)
 {
-	extern int errno;
-
 	if (errno == EDOM) {
 		errno = 0;
 		ERROR "%s argument out of domain", s WARNING;
diff --git a/src/cmd/vbackup/mount-DragonFly.c b/src/cmd/vbackup/mount-DragonFly.c
new file mode 100644
index 0000000..0379cee
--- /dev/null
+++ b/src/cmd/vbackup/mount-DragonFly.c
@@ -0,0 +1 @@
+#include "mount-BSD.c"
diff --git a/src/lib9/dirread.c b/src/lib9/dirread.c
index 0e38db3..f977d15 100644
--- a/src/lib9/dirread.c
+++ b/src/lib9/dirread.c
@@ -25,7 +25,7 @@
 	long off;
 	return getdirentries(fd, (void*)buf, n, &off);
 }
-#elif defined(__FreeBSD__) || defined(__OpenBSD__)
+#elif defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__DragonFly__)
 static int
 mygetdents(int fd, struct dirent *buf, int n)
 {
@@ -46,6 +46,12 @@
 }
 #endif
 
+#if defined(__DragonFly__)
+static inline int d_reclen(struct dirent *de) { return _DIRENT_DIRSIZ(de); }
+#else
+static inline int d_reclen(struct dirent *de) { return de->d_reclen; }
+#endif
+
 static int
 countde(char *p, int n)
 {
@@ -57,14 +63,14 @@
 	m = 0;
 	while(p < e){
 		de = (struct dirent*)p;
-		if(de->d_reclen <= 4+2+2+1 || p+de->d_reclen > e)
+		if(d_reclen(de) <= 4+2+2+1 || p+d_reclen(de) > e)
 			break;
 		if(de->d_name[0]=='.' && de->d_name[1]==0)
 			de->d_name[0] = 0;
 		else if(de->d_name[0]=='.' && de->d_name[1]=='.' && de->d_name[2]==0)
 			de->d_name[0] = 0;
 		m++;
-		p += de->d_reclen;
+		p += d_reclen(de);
 	}
 	return m;
 }
@@ -104,7 +110,7 @@
 				stat(de->d_name, &st);
 			nstr += _p9dir(&lst, &st, de->d_name, nil, nil, nil);
 		}
-		p += de->d_reclen;
+		p += d_reclen(de);
 	}
 
 	d = malloc(sizeof(Dir)*n+nstr);
@@ -126,7 +132,7 @@
 				stat(de->d_name, &st);
 			_p9dir(&lst, &st, de->d_name, &d[m++], &str, estr);
 		}
-		p += de->d_reclen;
+		p += d_reclen(de);
 	}
 
 	fchdir(oldwd);
diff --git a/src/libip/DragonFly.c b/src/libip/DragonFly.c
new file mode 100644
index 0000000..8710a5f
--- /dev/null
+++ b/src/libip/DragonFly.c
@@ -0,0 +1 @@
+#include "BSD.c"
diff --git a/src/libip/mkfile b/src/libip/mkfile
index d009928..88b0fd9 100644
--- a/src/libip/mkfile
+++ b/src/libip/mkfile
@@ -20,7 +20,7 @@
 
 <$PLAN9/src/mksyslib
 
-Darwin.$O FreeBSD.$O: BSD.c
+Darwin.$O FreeBSD.$O DragonFly.$O: BSD.c
 
 testreadipifc: testreadipifc.o $LIBDIR/$LIB
 	$LD -o testreadipifc testreadipifc.o
diff --git a/src/libmach/DragonFly.c b/src/libmach/DragonFly.c
new file mode 100644
index 0000000..92ffdb9
--- /dev/null
+++ b/src/libmach/DragonFly.c
@@ -0,0 +1,318 @@
+/*
+ * process interface for DragonFly BSD
+ *
+ * we could be a little more careful about not using
+ * ptrace unless absolutely necessary.  this would let us
+ * look at processes without stopping them.
+ *
+ * I'd like to make this a bit more generic (there's too much
+ * duplication with Linux and presumably other systems),
+ * but ptrace is too damn system-specific.
+ */
+
+#include <u.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <machine/reg.h>
+#include <signal.h>
+#include <errno.h>
+#include <libc.h>
+#include <mach.h>
+#include "ureg386.h"
+
+Mach *machcpu = &mach386;
+
+typedef struct PtraceRegs PtraceRegs;
+struct PtraceRegs
+{
+	Regs r;
+	int pid;
+};
+
+static int ptracerw(Map*, Seg*, ulong, void*, uint, int);
+static int ptraceregrw(Regs*, char*, ulong*, int);
+
+void
+unmapproc(Map *map)
+{
+	int i;
+
+	if(map == nil)
+		return;
+	for(i=0; i<map->nseg; i++)
+		while(i<map->nseg && map->seg[i].pid){
+			map->nseg--;
+			memmove(&map->seg[i], &map->seg[i+1], 
+				(map->nseg-i)*sizeof(map->seg[0]));
+		}
+}
+
+int
+mapproc(int pid, Map *map, Regs **rp)
+{
+	Seg s;
+	PtraceRegs *r;
+
+	if(ptrace(PT_ATTACH, pid, 0, 0) < 0)
+	if(ptrace(PT_READ_I, pid, 0, 0)<0 && errno!=EINVAL)
+	if(ptrace(PT_ATTACH, pid, 0, 0) < 0){
+		werrstr("ptrace attach %d: %r", pid);
+		return -1;
+	}
+
+	if(ctlproc(pid, "waitanyway") < 0){
+		ptrace(PT_DETACH, pid, 0, 0);
+		return -1;
+	}
+
+	memset(&s, 0, sizeof s);
+	s.base = 0;
+	s.size = 0xFFFFFFFF;
+	s.offset = 0;
+	s.name = "data";
+	s.file = nil;
+	s.rw = ptracerw;
+	s.pid = pid;
+	if(addseg(map, s) < 0)
+		return -1;
+
+	if((r = mallocz(sizeof(PtraceRegs), 1)) == nil)
+		return -1;
+	r->r.rw = ptraceregrw;
+	r->pid = pid;
+	*rp = (Regs*)r;
+	return 0;
+}
+
+int
+detachproc(int pid)
+{
+	return ptrace(PT_DETACH, pid, 0, 0);
+}
+
+static int
+ptracerw(Map *map, Seg *seg, ulong addr, void *v, uint n, int isr)
+{
+	int i;
+	u32int u;
+	uchar buf[4];
+
+	addr += seg->base;
+	for(i=0; i<n; i+=4){
+		if(isr){
+			errno = 0;
+			u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
+			if(errno)
+				goto ptraceerr;
+			if(n-i >= 4)
+				*(u32int*)((char*)v+i) = u;
+			else{
+				*(u32int*)buf = u;
+				memmove((char*)v+i, buf, n-i);
+			}
+		}else{
+			if(n-i >= 4)
+				u = *(u32int*)((char*)v+i);
+			else{
+				errno = 0;
+				u = ptrace(PT_READ_D, seg->pid, (char*)addr+i, 0);
+				if(errno)
+					return -1;
+				*(u32int*)buf = u;
+				memmove(buf, (char*)v+i, n-i);
+				u = *(u32int*)buf;
+			}
+			if(ptrace(PT_WRITE_D, seg->pid, (char*)addr+i, u) < 0)
+				goto ptraceerr;
+		}
+	}
+	return 0;
+
+ptraceerr:
+	werrstr("ptrace: %r");
+	return -1;
+}
+
+static char *freebsdregs[] = {
+	"FS",
+	"ES",
+	"DS",
+	"DI",
+	"SI",
+	"BP",
+	"SP",
+	"BX",
+	"DX",
+	"CX",
+	"AX",
+	"TRAP",
+	"PC",
+	"CS",
+	"EFLAGS",
+	"SP",
+	"SS",
+	"GS",
+};
+
+static ulong
+reg2freebsd(char *reg)
+{
+	int i;
+
+	for(i=0; i<nelem(freebsdregs); i++)
+		if(strcmp(freebsdregs[i], reg) == 0)
+			return 4*i;
+	return ~(ulong)0;
+}
+
+static int
+ptraceregrw(Regs *regs, char *name, ulong *val, int isr)
+{
+	int pid;
+	ulong addr;
+	struct reg mregs;
+
+	addr = reg2freebsd(name);
+	if(~addr == 0){
+		if(isr){
+			*val = ~(ulong)0;
+			return 0;
+		}
+		werrstr("register not available");
+		return -1;
+	}
+
+	pid = ((PtraceRegs*)regs)->pid;
+	if(ptrace(PT_GETREGS, pid, (char*)&mregs, 0) < 0)
+		return -1;
+	if(isr)
+		*val = *(u32int*)((char*)&mregs+addr);
+	else{
+		*(u32int*)((char*)&mregs+addr) = *val;
+		if(ptrace(PT_SETREGS, pid, (char*)&mregs, 0) < 0)
+			return -1;
+	}
+	return 0;
+}
+
+char*
+proctextfile(int pid)
+{
+	static char buf[1024], pbuf[128];
+
+	snprint(pbuf, sizeof pbuf, "/proc/%d/file", pid);
+	if(readlink(pbuf, buf, sizeof buf) >= 0)
+		return buf;
+	if(access(pbuf, AEXIST) >= 0)
+		return pbuf;
+	return nil;
+}
+
+/*
+
+  status  The process status.  This file is read-only and returns a single
+	     line containing multiple space-separated fields as follows:
+
+	     o	 command name
+	     o	 process id
+	     o	 parent process id
+	     o	 process group id
+	     o	 session id
+	     o	 major,minor of the controlling terminal, or -1,-1 if there is
+		 no controlling terminal.
+	     o	 a list of process flags: ctty if there is a controlling ter-
+		 minal, sldr if the process is a session leader, noflags if
+		 neither of the other two flags are set.
+	     o	 the process start time in seconds and microseconds, comma
+		 separated.
+	     o	 the user time in seconds and microseconds, comma separated.
+	     o	 the system time in seconds and microseconds, comma separated.
+	     o	 the wait channel message
+	     o	 the process credentials consisting of the effective user id
+		 and the list of groups (whose first member is the effective
+		 group id) all comma separated.
+*/
+
+int
+procnotes(int pid, char ***pnotes)
+{
+	/* figure out the set of pending notes - how? */
+	*pnotes = nil;
+	return 0;
+}
+
+static int
+isstopped(int pid)
+{
+	char buf[1024], *f[12];
+	int fd, n, nf;
+
+	snprint(buf, sizeof buf, "/proc/%d/status", pid);
+	if((fd = open(buf, OREAD)) < 0)
+		return 0;
+	n = read(fd, buf, sizeof buf-1);
+	close(fd);
+	if(n <= 0)
+		return 0;
+	buf[n] = 0;
+
+	if((nf = tokenize(buf, f, nelem(f))) < 11)
+		return 0;
+	if(strcmp(f[10], "nochan") == 0)
+		return 1;
+	return 0;
+}
+
+#undef waitpid
+
+int
+ctlproc(int pid, char *msg)
+{
+	int p, status;
+
+	if(strcmp(msg, "hang") == 0){
+		if(pid == getpid())
+			return ptrace(PT_TRACE_ME, 0, 0, 0);
+		werrstr("can only hang self");
+		return -1;
+	}
+	if(strcmp(msg, "kill") == 0)
+		return ptrace(PT_KILL, pid, 0, 0);
+	if(strcmp(msg, "startstop") == 0){
+		if(ptrace(PT_CONTINUE, pid, 0, 0) < 0)
+			return -1;
+		goto waitstop;
+	}
+/*
+	if(strcmp(msg, "sysstop") == 0){
+		if(ptrace(PTRACE_SYSCALL, pid, 0, 0) < 0)
+			return -1;
+		goto waitstop;
+	}
+*/
+	if(strcmp(msg, "stop") == 0){
+		if(kill(pid, SIGSTOP) < 0)
+			return -1;
+		goto waitstop;
+	}
+	if(strcmp(msg, "waitanyway") == 0)
+		goto waitanyway;
+	if(strcmp(msg, "waitstop") == 0){
+	waitstop:
+		if(isstopped(pid))
+			return 0;
+	waitanyway:
+		for(;;){
+			p = waitpid(pid, &status, WUNTRACED);
+			if(p <= 0)
+				return -1;
+			if(WIFEXITED(status) || WIFSTOPPED(status))
+				return 0;
+		}
+	}
+	if(strcmp(msg, "start") == 0)
+		return ptrace(PT_CONTINUE, pid, 0, 0);
+	werrstr("unknown control message '%s'", msg);
+	return -1;
+}