os: OS-dependent bits to support NetBSD.

R=golang-dev, jsing
CC=golang-dev
https://golang.org/cl/5482068
diff --git a/include/libc.h b/include/libc.h
index 0b50eb3..b464cb4 100644
--- a/include/libc.h
+++ b/include/libc.h
@@ -187,7 +187,7 @@
 #define DMWRITE		0x2		/* mode bit for write permission */
 #define DMEXEC		0x1		/* mode bit for execute permission */
 
-#ifdef RFMEM	/* FreeBSD, OpenBSD */
+#ifdef RFMEM	/* FreeBSD, OpenBSD, NetBSD */
 #undef RFFDG
 #undef RFNOTEG
 #undef RFPROC
diff --git a/src/libmach/netbsd.c b/src/libmach/netbsd.c
new file mode 100644
index 0000000..03e08d9
--- /dev/null
+++ b/src/libmach/netbsd.c
@@ -0,0 +1,46 @@
+// This is stubbed out for the moment. Will revisit when the time comes.
+#include <u.h>
+#include <libc.h>
+#include <bio.h>
+#include <mach.h>
+
+int
+ctlproc(int pid, char *msg)
+{
+	sysfatal("ctlproc unimplemented in NetBSD");
+	return -1;
+}
+
+char*
+proctextfile(int pid)
+{
+	sysfatal("proctextfile unimplemented in NetBSD");
+	return nil;
+}
+
+char*
+procstatus(int pid)
+{
+	sysfatal("procstatus unimplemented in NetBSD");
+	return nil;
+}
+
+Map*
+attachproc(int pid, Fhdr *fp)
+{
+	sysfatal("attachproc unimplemented in NetBSD");
+	return nil;
+}
+
+void
+detachproc(Map *m)
+{
+	sysfatal("detachproc unimplemented in NetBSD");
+}
+
+int
+procthreadpids(int pid, int *p, int np)
+{
+	sysfatal("procthreadpids unimplemented in NetBSD");
+	return -1;
+}
diff --git a/src/pkg/net/fd_netbsd.go b/src/pkg/net/fd_netbsd.go
new file mode 100644
index 0000000..e52ac35
--- /dev/null
+++ b/src/pkg/net/fd_netbsd.go
@@ -0,0 +1,115 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Waiting for FDs via kqueue/kevent.
+
+package net
+
+import (
+	"os"
+	"syscall"
+)
+
+type pollster struct {
+	kq       int
+	eventbuf [10]syscall.Kevent_t
+	events   []syscall.Kevent_t
+
+	// An event buffer for AddFD/DelFD.
+	// Must hold pollServer lock.
+	kbuf [1]syscall.Kevent_t
+}
+
+func newpollster() (p *pollster, err error) {
+	p = new(pollster)
+	if p.kq, err = syscall.Kqueue(); err != nil {
+		return nil, os.NewSyscallError("kqueue", err)
+	}
+	p.events = p.eventbuf[0:0]
+	return p, nil
+}
+
+func (p *pollster) AddFD(fd int, mode int, repeat bool) (bool, error) {
+	// pollServer is locked.
+
+	var kmode int
+	if mode == 'r' {
+		kmode = syscall.EVFILT_READ
+	} else {
+		kmode = syscall.EVFILT_WRITE
+	}
+	ev := &p.kbuf[0]
+	// EV_ADD - add event to kqueue list
+	// EV_ONESHOT - delete the event the first time it triggers
+	flags := syscall.EV_ADD
+	if !repeat {
+		flags |= syscall.EV_ONESHOT
+	}
+	syscall.SetKevent(ev, fd, kmode, flags)
+
+	n, e := syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+	if e != nil {
+		return false, os.NewSyscallError("kevent", e)
+	}
+	if n != 1 || (ev.Flags&syscall.EV_ERROR) == 0 || int(ev.Ident) != fd || int(ev.Filter) != kmode {
+		return false, os.NewSyscallError("kqueue phase error", e)
+	}
+	if ev.Data != 0 {
+		return false, syscall.Errno(int(ev.Data))
+	}
+	return false, nil
+}
+
+func (p *pollster) DelFD(fd int, mode int) {
+	// pollServer is locked.
+
+	var kmode int
+	if mode == 'r' {
+		kmode = syscall.EVFILT_READ
+	} else {
+		kmode = syscall.EVFILT_WRITE
+	}
+	ev := &p.kbuf[0]
+	// EV_DELETE - delete event from kqueue list
+	syscall.SetKevent(ev, fd, kmode, syscall.EV_DELETE)
+	syscall.Kevent(p.kq, p.kbuf[:], nil, nil)
+}
+
+func (p *pollster) WaitFD(s *pollServer, nsec int64) (fd int, mode int, err error) {
+	var t *syscall.Timespec
+	for len(p.events) == 0 {
+		if nsec > 0 {
+			if t == nil {
+				t = new(syscall.Timespec)
+			}
+			*t = syscall.NsecToTimespec(nsec)
+		}
+
+		s.Unlock()
+		nn, e := syscall.Kevent(p.kq, nil, p.eventbuf[:], t)
+		s.Lock()
+
+		if e != nil {
+			if e == syscall.EINTR {
+				continue
+			}
+			return -1, 0, os.NewSyscallError("kevent", e)
+		}
+		if nn == 0 {
+			return -1, 0, nil
+		}
+		p.events = p.eventbuf[0:nn]
+	}
+	ev := &p.events[0]
+	p.events = p.events[1:]
+	fd = int(ev.Ident)
+	if ev.Filter == syscall.EVFILT_READ {
+		mode = 'r'
+	} else {
+		mode = 'w'
+	}
+	return fd, mode, nil
+}
+
+func (p *pollster) Close() error { return os.NewSyscallError("close", syscall.Close(p.kq)) }
diff --git a/src/pkg/net/interface_netbsd.go b/src/pkg/net/interface_netbsd.go
new file mode 100644
index 0000000..4150e9a
--- /dev/null
+++ b/src/pkg/net/interface_netbsd.go
@@ -0,0 +1,14 @@
+// Copyright 2011 The Go Authors.  All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Network interface identification for NetBSD
+
+package net
+
+// If the ifindex is zero, interfaceMulticastAddrTable returns
+// addresses for all network interfaces.  Otherwise it returns
+// addresses for a specific interface.
+func interfaceMulticastAddrTable(ifindex int) ([]Addr, error) {
+	return nil, nil
+}
diff --git a/src/pkg/net/tcpsock_posix.go b/src/pkg/net/tcpsock_posix.go
index 44890ba..a7c09c7 100644
--- a/src/pkg/net/tcpsock_posix.go
+++ b/src/pkg/net/tcpsock_posix.go
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style
 // license that can be found in the LICENSE file.
 
-// +build darwin freebsd linux openbsd windows
+// +build darwin freebsd linux netbsd openbsd windows
 
 // TCP sockets
 
diff --git a/src/pkg/os/stat_netbsd.go b/src/pkg/os/stat_netbsd.go
new file mode 100644
index 0000000..66189a6
--- /dev/null
+++ b/src/pkg/os/stat_netbsd.go
@@ -0,0 +1,56 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package os
+
+import (
+	"syscall"
+	"time"
+)
+
+func sameFile(fs1, fs2 *FileStat) bool {
+	sys1 := fs1.Sys.(*syscall.Stat_t)
+	sys2 := fs2.Sys.(*syscall.Stat_t)
+	return sys1.Dev == sys2.Dev && sys1.Ino == sys2.Ino
+}
+
+func fileInfoFromStat(st *syscall.Stat_t, name string) FileInfo {
+	fs := &FileStat{
+		name:    basename(name),
+		size:    int64(st.Size),
+		modTime: timespecToTime(st.Mtim),
+		Sys:     st,
+	}
+	fs.mode = FileMode(st.Mode & 0777)
+	switch st.Mode & syscall.S_IFMT {
+	case syscall.S_IFBLK, syscall.S_IFCHR:
+		fs.mode |= ModeDevice
+	case syscall.S_IFDIR:
+		fs.mode |= ModeDir
+	case syscall.S_IFIFO:
+		fs.mode |= ModeNamedPipe
+	case syscall.S_IFLNK:
+		fs.mode |= ModeSymlink
+	case syscall.S_IFREG:
+		// nothing to do
+	case syscall.S_IFSOCK:
+		fs.mode |= ModeSocket
+	}
+	if st.Mode&syscall.S_ISGID != 0 {
+		fs.mode |= ModeSetgid
+	}
+	if st.Mode&syscall.S_ISUID != 0 {
+		fs.mode |= ModeSetuid
+	}
+	return fs
+}
+
+func timespecToTime(ts syscall.Timespec) time.Time {
+	return time.Unix(int64(ts.Sec), int64(ts.Nsec))
+}
+
+// For testing.
+func atime(fi FileInfo) time.Time {
+	return timespecToTime(fi.(*FileStat).Sys.(*syscall.Stat_t).Atim)
+}