R=rsc, brainman, ality, r2, r
CC=golang-dev
https://golang.org/cl/3816043
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
new file mode 100644
index 0000000..b889940
--- /dev/null
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -0,0 +1,343 @@
+// 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.
+
+// Plan 9 system calls.
+// This file is compiled as ordinary Go code,
+// but it is also input to mksyscall,
+// which parses the //sys lines and generates system call stubs.
+// Note that sometimes we use a lowercase //sys name and
+// wrap it in our own nicer implementation.
+
+package syscall
+
+import "unsafe"
+
+const OS = "plan9"
+
+const ImplementsGetwd = true
+
+// An Error can represent any printable error condition.
+type Error interface {
+	String() string
+}
+
+// ErrorString implements Error's String method by returning itself.
+type ErrorString string
+
+func (e ErrorString) String() string { return string(e) }
+
+// NewError converts s to an ErrorString, which satisfies the Error interface.
+func NewError(s string) Error { return ErrorString(s) }
+
+var (
+	Stdin  = 0
+	Stdout = 1
+	Stderr = 2
+
+	EISDIR Error = NewError("file is a directory")
+)
+
+func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err string)
+func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err string)
+func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
+func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
+
+func atoi(b []byte) (n uint) {
+	n = 0
+	for i := 0; i < len(b); i++ {
+		n = n*10 + uint(b[i]-'0')
+	}
+	return
+}
+
+func cstring(s []byte) string {
+	for i, _ := range s {
+		if s[i] == 0 {
+			return string(s[0:i])
+		}
+	}
+	return string(s)
+}
+
+func errstr() string {
+	var buf [ERRMAX]byte
+
+	RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
+
+	buf[len(buf)-1] = 0
+	return cstring(buf[:])
+}
+
+func Getpagesize() int { return 4096 }
+
+//sys	exits(msg *byte)
+func Exits(msg *string) {
+	if msg == nil {
+		exits(nil)
+	}
+
+	exits(StringBytePtr(*msg))
+}
+
+func Exit(code int) {
+	if code == 0 {
+		Exits(nil)
+	}
+
+	msg := itoa(code)
+	Exits(&msg)
+}
+
+func readnum(path string) (uint, Error) {
+	var b [12]byte
+
+	fd, e := Open(path, O_RDONLY)
+	if e != nil {
+		return 0, e
+	}
+	defer Close(fd)
+
+	n, e := Pread(fd, b[:], 0)
+
+	if e != nil {
+		return 0, e
+	}
+
+	m := 0
+	for ; m < n && b[m] == ' '; m++ {
+	}
+
+	return atoi(b[m : n-1]), nil
+}
+
+func Getpid() (pid int) {
+	n, _ := readnum("#c/pid")
+	return int(n)
+}
+
+func Getppid() (ppid int) {
+	n, _ := readnum("#c/ppid")
+	return int(n)
+}
+
+
+func Read(fd int, p []byte) (n int, err Error) {
+	return Pread(fd, p, -1)
+}
+
+func Write(fd int, p []byte) (n int, err Error) {
+	return Pwrite(fd, p, -1)
+}
+
+func Getwd() (wd string, err Error) {
+	fd, e := Open(".", O_RDONLY)
+
+	if e != nil {
+		return "", e
+	}
+	defer Close(fd)
+
+	return Fd2path(fd)
+}
+
+//sys	fd2path(fd int, buf []byte) (err Error)
+func Fd2path(fd int) (path string, err Error) {
+	var buf [512]byte
+
+	e := fd2path(fd, buf[:])
+	if e != nil {
+		return "", e
+	}
+	return cstring(buf[:]), nil
+}
+
+//sys	pipe(p *[2]_C_int) (err Error)
+func Pipe(p []int) (err Error) {
+	if len(p) != 2 {
+		return NewError("bad arg in system call")
+	}
+	var pp [2]_C_int
+	err = pipe(&pp)
+	p[0] = int(pp[0])
+	p[1] = int(pp[1])
+	return
+}
+
+
+//sys	sleep(millisecs int32) (err Error)
+func Sleep(nsec int64) (err Error) {
+	return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
+}
+
+// Underlying system call writes to newoffset via pointer.
+// Implemented in assembly to avoid allocation.
+func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
+
+func Seek(fd int, offset int64, whence int) (newoffset int64, err Error) {
+	newoffset, e := seek(0, fd, offset, whence)
+
+	err = nil
+	if newoffset == -1 {
+		err = NewError(e)
+	}
+	return
+}
+
+func Mkdir(path string, mode uint32) (err Error) {
+	fd, err := Create(path, O_RDONLY, DMDIR|mode)
+
+	if fd != -1 {
+		Close(fd)
+	}
+
+	return
+}
+
+type Waitmsg struct {
+	Pid  int
+	Time [3]uint32
+	Msg  string
+}
+
+//sys	await(s []byte) (n int, err Error)
+func Await(w *Waitmsg) (err Error) {
+	var buf [512]byte
+	var f [5][]byte
+
+	n, err := await(buf[:])
+
+	if err != nil || w == nil {
+		return
+	}
+
+	nf := 0
+	p := 0
+	for i := 0; i < n && nf < len(f)-1; i++ {
+		if buf[i] == ' ' {
+			f[nf] = buf[p:i]
+			p = i + 1
+			nf++
+		}
+	}
+	f[nf] = buf[p:]
+	nf++
+
+	if nf != len(f) {
+		return NewError("invalid wait message")
+	}
+	w.Pid = int(atoi(f[0]))
+	w.Time[0] = uint32(atoi(f[1]))
+	w.Time[1] = uint32(atoi(f[2]))
+	w.Time[2] = uint32(atoi(f[3]))
+	w.Msg = string(f[4])
+	return
+}
+
+func Unmount(name, old string) (err Error) {
+	oldp := uintptr(unsafe.Pointer(StringBytePtr(old)))
+
+	var r0 uintptr
+	var e string
+
+	// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
+	if name == "" {
+		r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldp, 0)
+	} else {
+		r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(StringBytePtr(name))), oldp, 0)
+	}
+
+	err = nil
+	if int(r0) == -1 {
+		err = NewError(e)
+	}
+	return
+}
+
+func Fchdir(fd int) (err Error) {
+	path, err := Fd2path(fd)
+
+	if err != nil {
+		return
+	}
+
+	return Chdir(path)
+}
+
+type Timeval struct {
+	Sec  int32
+	Usec int32
+}
+
+func NsecToTimeval(nsec int64) (tv Timeval) {
+	nsec += 999 // round up to microsecond
+	tv.Usec = int32(nsec % 1e9 / 1e3)
+	tv.Sec = int32(nsec / 1e9)
+	return
+}
+
+func DecodeBintime(b []byte) (nsec int64, err Error) {
+	if len(b) != 8 {
+		return -1, NewError("bad /dev/bintime format")
+	}
+	err = nil
+	nsec = int64(b[0])<<56 |
+		int64(b[1])<<48 |
+		int64(b[2])<<40 |
+		int64(b[3])<<32 |
+		int64(b[4])<<24 |
+		int64(b[5])<<16 |
+		int64(b[6])<<8 |
+		int64(b[7])
+	return
+}
+
+func Gettimeofday(tv *Timeval) (err Error) {
+	// TODO(paulzhol): 
+	// avoid reopening a file descriptor for /dev/bintime on each call,
+	// use lower-level calls to avoid allocation.
+
+	var b [8]byte
+	var nsec int64
+
+	fd, e := Open("/dev/bintime", O_RDONLY)
+	if e != nil {
+		return e
+	}
+	defer Close(fd)
+
+	if _, e = Pread(fd, b[:], 0); e != nil {
+		return e
+	}
+
+	if nsec, e = DecodeBintime(b[:]); e != nil {
+		return e
+	}
+	*tv = NsecToTimeval(nsec)
+
+	return e
+}
+
+func Getegid() (egid int) { return -1 }
+func Geteuid() (euid int) { return -1 }
+func Getgid() (gid int)   { return -1 }
+func Getuid() (uid int)   { return -1 }
+
+func Getgroups() (gids []int, err Error) {
+	return make([]int, 0), nil
+}
+
+//sys	Dup(oldfd int, newfd int) (fd int, err Error)
+//sys	Open(path string, mode int) (fd int, err Error)
+//sys	Create(path string, mode int, perm uint32) (fd int, err Error)
+//sys	Remove(path string) (err Error)
+//sys	Pread(fd int, p []byte, offset int64) (n int, err Error)
+//sys	Pwrite(fd int, p []byte, offset int64) (n int, err Error)
+//sys	Close(fd int) (err Error)
+//sys	Chdir(path string) (err Error)
+//sys	Bind(name string, old string, flag int) (err Error)
+//sys	Mount(fd int, afd int, old string, flag int, aname string) (err Error)
+//sys	Stat(path string, edir []byte) (n int, err Error)
+//sys	Fstat(fd int, edir []byte) (n int, err Error)
+//sys	Wstat(path string, edir []byte) (err Error)
+//sys	Fwstat(fd int, edir []byte) (err Error)