| // 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 { | |
| error | |
| } | |
| // ErrorString implements Error's String method by returning itself. | |
| type ErrorString string | |
| func (e ErrorString) Error() 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 | |
| EAFNOSUPPORT = NewError("address family not supported by protocol") | |
| EISDIR = NewError("file is a directory") | |
| ) | |
| // For testing: clients can set this flag to force | |
| // creation of IPv6 sockets to return EAFNOSUPPORT. | |
| var SocketDisableIPv6 bool | |
| 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 | |
| } | |
| func (w Waitmsg) Exited() bool { return true } | |
| func (w Waitmsg) Signaled() bool { return false } | |
| func (w Waitmsg) ExitStatus() int { | |
| if len(w.Msg) == 0 { | |
| // a normal exit returns no message | |
| return 0 | |
| } | |
| return 1 | |
| } | |
| //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 = cstring(f[4]) | |
| if w.Msg == "''" { | |
| // await() returns '' for no error | |
| w.Msg = "" | |
| } | |
| 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) |