mirror of
https://github.com/golang/go
synced 2024-10-05 06:11:21 -06:00
f0a8b610e7
syscall: Use NewError for all system errors and introduce some new errors for compatibility with other packages and proper error handling in net. Also introduce Temporary and Timeout methods on ErrorString. net: Make errors from dial, accept, listen functions follow the OpError standard and discern whether the underlying error came from syscall. Since Plan 9 uses a correspondence between file and network operations, all system error reporting happens through the underlying file operation. In Go code, we go through package os for file operations, so there is another level of indirection in error types. This change allows us to compare the errors with those in package syscall, when appropriate. os: Just use the error string already present in package os, instead of calling out to package syscall. R=rsc, ality, rminnich, bradfitz CC=golang-dev https://golang.org/cl/7398054
352 lines
7.1 KiB
Go
352 lines
7.1 KiB
Go
// 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 ImplementsGetwd = true
|
|
|
|
// 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) }
|
|
|
|
func (e ErrorString) Temporary() bool {
|
|
return e == EINTR || e == EMFILE || e.Timeout()
|
|
}
|
|
|
|
func (e ErrorString) Timeout() bool {
|
|
return e == EBUSY || e == ETIMEDOUT
|
|
}
|
|
|
|
// A Note is a string describing a process note.
|
|
// It implements the os.Signal interface.
|
|
type Note string
|
|
|
|
func (n Note) Signal() {}
|
|
|
|
func (n Note) String() string {
|
|
return string(n)
|
|
}
|
|
|
|
var (
|
|
Stdin = 0
|
|
Stdout = 1
|
|
Stderr = 2
|
|
)
|
|
|
|
// 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 ErrorString)
|
|
func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
|
|
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[:])
|
|
}
|
|
|
|
// Implemented in assembly to import from runtime.
|
|
func exit(int)
|
|
|
|
func Exit(code int) { exit(code) }
|
|
|
|
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) {
|
|
n, err = Pread(fd, p, -1)
|
|
if raceenabled && err == nil {
|
|
raceAcquire(unsafe.Pointer(&ioSync))
|
|
}
|
|
return
|
|
}
|
|
|
|
func Write(fd int, p []byte) (n int, err error) {
|
|
if raceenabled {
|
|
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
}
|
|
return Pwrite(fd, p, -1)
|
|
}
|
|
|
|
var ioSync int64
|
|
|
|
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
|
|
}
|
|
|
|
// 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)
|
|
|
|
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, err := BytePtrFromString(old)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
oldptr := uintptr(unsafe.Pointer(oldp))
|
|
|
|
var r0 uintptr
|
|
var e ErrorString
|
|
|
|
// 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, oldptr, 0)
|
|
} else {
|
|
namep, err := BytePtrFromString(name)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
|
|
}
|
|
|
|
if int32(r0) == -1 {
|
|
err = e
|
|
}
|
|
return
|
|
}
|
|
|
|
func Fchdir(fd int) (err error) {
|
|
path, err := Fd2path(fd)
|
|
|
|
if err != nil {
|
|
return
|
|
}
|
|
|
|
return Chdir(path)
|
|
}
|
|
|
|
type Timespec struct {
|
|
Sec int32
|
|
Nsec int32
|
|
}
|
|
|
|
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")
|
|
}
|
|
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) error {
|
|
nsec, e := nanotime()
|
|
if 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)
|