diff options
Diffstat (limited to 'src/pkg/syscall/syscall_plan9.go')
-rw-r--r-- | src/pkg/syscall/syscall_plan9.go | 343 |
1 files changed, 343 insertions, 0 deletions
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go new file mode 100644 index 000000000..831cbddb2 --- /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) |