2011-04-02 15:24:03 -06:00
|
|
|
// 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
|
|
|
|
|
2011-11-08 07:06:02 -07:00
|
|
|
func (e ErrorString) Error() string { return string(e) }
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
// NewError converts s to an ErrorString, which satisfies the Error interface.
|
2011-11-16 15:37:54 -07:00
|
|
|
func NewError(s string) error { return ErrorString(s) }
|
2011-04-02 15:24:03 -06:00
|
|
|
|
net, os, syscall: Plan 9: adjust error handling
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
2013-02-27 22:43:21 -07:00
|
|
|
func (e ErrorString) Temporary() bool {
|
|
|
|
return e == EINTR || e == EMFILE || e.Timeout()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (e ErrorString) Timeout() bool {
|
|
|
|
return e == EBUSY || e == ETIMEDOUT
|
|
|
|
}
|
|
|
|
|
2012-05-04 04:44:41 -06:00
|
|
|
// 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)
|
|
|
|
}
|
|
|
|
|
2011-04-02 15:24:03 -06:00
|
|
|
var (
|
|
|
|
Stdin = 0
|
|
|
|
Stdout = 1
|
|
|
|
Stderr = 2
|
|
|
|
)
|
|
|
|
|
2011-08-17 11:28:29 -06:00
|
|
|
// For testing: clients can set this flag to force
|
|
|
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
|
|
|
var SocketDisableIPv6 bool
|
|
|
|
|
2011-11-21 07:55:15 -07:00
|
|
|
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)
|
2011-04-02 15:24:03 -06:00
|
|
|
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 {
|
2011-04-13 16:13:59 -06:00
|
|
|
for i := range s {
|
2011-04-02 15:24:03 -06:00
|
|
|
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[:])
|
|
|
|
}
|
|
|
|
|
2012-04-19 17:31:26 -06:00
|
|
|
// Implemented in assembly to import from runtime.
|
2014-05-15 14:47:53 -06:00
|
|
|
func exit(code int)
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2012-04-19 17:31:26 -06:00
|
|
|
func Exit(code int) { exit(code) }
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func readnum(path string) (uint, error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Read(fd int, p []byte) (n int, err error) {
|
2013-06-10 12:40:35 -06:00
|
|
|
return Pread(fd, p, -1)
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Write(fd int, p []byte) (n int, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
return Pwrite(fd, p, -1)
|
|
|
|
}
|
|
|
|
|
2012-10-09 10:51:58 -06:00
|
|
|
var ioSync int64
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Getwd() (wd string, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
fd, e := Open(".", O_RDONLY)
|
|
|
|
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
defer Close(fd)
|
|
|
|
|
|
|
|
return Fd2path(fd)
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
//sys fd2path(fd int, buf []byte) (err error)
|
|
|
|
func Fd2path(fd int) (path string, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
var buf [512]byte
|
|
|
|
|
|
|
|
e := fd2path(fd, buf[:])
|
|
|
|
if e != nil {
|
|
|
|
return "", e
|
|
|
|
}
|
|
|
|
return cstring(buf[:]), nil
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
//sys pipe(p *[2]_C_int) (err error)
|
|
|
|
func Pipe(p []int) (err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
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)
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
newoffset, e := seek(0, fd, offset, whence)
|
|
|
|
|
|
|
|
if newoffset == -1 {
|
|
|
|
err = NewError(e)
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Mkdir(path string, mode uint32) (err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
fd, err := Create(path, O_RDONLY, DMDIR|mode)
|
|
|
|
|
|
|
|
if fd != -1 {
|
|
|
|
Close(fd)
|
|
|
|
}
|
|
|
|
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
type Waitmsg struct {
|
|
|
|
Pid int
|
|
|
|
Time [3]uint32
|
|
|
|
Msg string
|
|
|
|
}
|
|
|
|
|
2011-06-19 21:34:10 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
//sys await(s []byte) (n int, err error)
|
|
|
|
func Await(w *Waitmsg) (err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
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]))
|
2011-06-19 21:34:10 -06:00
|
|
|
w.Msg = cstring(f[4])
|
2011-10-31 11:34:59 -06:00
|
|
|
if w.Msg == "''" {
|
|
|
|
// await() returns '' for no error
|
|
|
|
w.Msg = ""
|
|
|
|
}
|
2011-04-02 15:24:03 -06:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Unmount(name, old string) (err error) {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
oldp, err := BytePtrFromString(old)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
oldptr := uintptr(unsafe.Pointer(oldp))
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
var r0 uintptr
|
2011-11-21 07:55:15 -07:00
|
|
|
var e ErrorString
|
2011-04-02 15:24:03 -06:00
|
|
|
|
|
|
|
// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
|
|
|
|
if name == "" {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
|
2011-04-02 15:24:03 -06:00
|
|
|
} else {
|
syscall: return EINVAL when string arguments have NUL characters
Since NUL usually terminates strings in underlying syscalls, allowing
it when converting string arguments is a security risk, especially
when dealing with filenames. For example, a program might reason that
filename like "/root/..\x00/" is a subdirectory or "/root/" and allow
access to it, while underlying syscall will treat "\x00" as an end of
that string and the actual filename will be "/root/..", which might
be unexpected. Returning EINVAL when string arguments have NUL in
them makes sure this attack vector is unusable.
R=golang-dev, r, bradfitz, fullung, rsc, minux.ma
CC=golang-dev
https://golang.org/cl/6458050
2012-08-05 15:24:32 -06:00
|
|
|
namep, err := BytePtrFromString(name)
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
|
syscall: keep allocated C string live across call to Syscall
Given:
p := alloc()
fn_taking_ptr(p)
p is NOT recorded as live at the call to fn_taking_ptr:
it's not needed by the code following the call.
p was passed to fn_taking_ptr, and fn_taking_ptr must keep
it alive as long as it needs it.
In practice, fn_taking_ptr will keep its own arguments live
for as long as the function is executing.
But if instead you have:
p := alloc()
i := uintptr(unsafe.Pointer(p))
fn_taking_int(i)
p is STILL NOT recorded as live at the call to fn_taking_int:
it's not needed by the code following the call.
fn_taking_int is responsible for keeping its own arguments
live, but fn_taking_int is written to take an integer, so even
though fn_taking_int does keep its argument live, that argument
does not keep the allocated memory live, because the garbage
collector does not dereference integers.
The shorter form:
p := alloc()
fn_taking_int(uintptr(unsafe.Pointer(p)))
and the even shorter form:
fn_taking_int(uintptr(unsafe.Pointer(alloc())))
are both the same as the 3-line form above.
syscall.Syscall is like fn_taking_int: it is written to take a list
of integers, and yet those integers are sometimes pointers.
If there is no other copy of those pointers being kept live,
the memory they point at may be garbage collected during
the call to syscall.Syscall.
This is happening on Solaris: for whatever reason, the timing
is such that the garbage collector manages to free the string
argument to the open(2) system call before the system call
has been invoked.
Change the system call wrappers to insert explicit references
that will keep the allocations alive in the original frame
(and therefore preserve the memory) until after syscall.Syscall
has returned.
Should fix Solaris flakiness.
This is not a problem for cgo, because cgo wrappers have
correctly typed arguments.
LGTM=iant, khr, aram, rlh
R=iant, khr, bradfitz, aram, rlh
CC=dvyukov, golang-codereviews, r
https://golang.org/cl/139360044
2014-09-08 14:59:59 -06:00
|
|
|
use(unsafe.Pointer(namep))
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
syscall: keep allocated C string live across call to Syscall
Given:
p := alloc()
fn_taking_ptr(p)
p is NOT recorded as live at the call to fn_taking_ptr:
it's not needed by the code following the call.
p was passed to fn_taking_ptr, and fn_taking_ptr must keep
it alive as long as it needs it.
In practice, fn_taking_ptr will keep its own arguments live
for as long as the function is executing.
But if instead you have:
p := alloc()
i := uintptr(unsafe.Pointer(p))
fn_taking_int(i)
p is STILL NOT recorded as live at the call to fn_taking_int:
it's not needed by the code following the call.
fn_taking_int is responsible for keeping its own arguments
live, but fn_taking_int is written to take an integer, so even
though fn_taking_int does keep its argument live, that argument
does not keep the allocated memory live, because the garbage
collector does not dereference integers.
The shorter form:
p := alloc()
fn_taking_int(uintptr(unsafe.Pointer(p)))
and the even shorter form:
fn_taking_int(uintptr(unsafe.Pointer(alloc())))
are both the same as the 3-line form above.
syscall.Syscall is like fn_taking_int: it is written to take a list
of integers, and yet those integers are sometimes pointers.
If there is no other copy of those pointers being kept live,
the memory they point at may be garbage collected during
the call to syscall.Syscall.
This is happening on Solaris: for whatever reason, the timing
is such that the garbage collector manages to free the string
argument to the open(2) system call before the system call
has been invoked.
Change the system call wrappers to insert explicit references
that will keep the allocations alive in the original frame
(and therefore preserve the memory) until after syscall.Syscall
has returned.
Should fix Solaris flakiness.
This is not a problem for cgo, because cgo wrappers have
correctly typed arguments.
LGTM=iant, khr, aram, rlh
R=iant, khr, bradfitz, aram, rlh
CC=dvyukov, golang-codereviews, r
https://golang.org/cl/139360044
2014-09-08 14:59:59 -06:00
|
|
|
use(unsafe.Pointer(oldp))
|
2011-04-02 15:24:03 -06:00
|
|
|
|
2012-09-30 18:09:08 -06:00
|
|
|
if int32(r0) == -1 {
|
2011-11-21 07:55:15 -07:00
|
|
|
err = e
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Fchdir(fd int) (err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
path, err := Fd2path(fd)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
return Chdir(path)
|
|
|
|
}
|
|
|
|
|
2012-01-18 22:52:28 -07:00
|
|
|
type Timespec struct {
|
|
|
|
Sec int32
|
|
|
|
Nsec int32
|
|
|
|
}
|
|
|
|
|
2011-04-02 15:24:03 -06:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2014-07-09 04:34:06 -06:00
|
|
|
func nsec() int64 {
|
|
|
|
var scratch int64
|
|
|
|
|
|
|
|
r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
|
|
|
|
// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
|
|
|
|
if r0 == 0 {
|
|
|
|
return scratch
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
2014-07-09 04:34:06 -06:00
|
|
|
return int64(r0)
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2013-02-25 17:56:08 -07:00
|
|
|
func Gettimeofday(tv *Timeval) error {
|
2014-07-09 04:34:06 -06:00
|
|
|
nsec := nsec()
|
2011-04-02 15:24:03 -06:00
|
|
|
*tv = NsecToTimeval(nsec)
|
2014-07-09 04:34:06 -06:00
|
|
|
return nil
|
2011-04-02 15:24:03 -06:00
|
|
|
}
|
|
|
|
|
2014-07-09 04:34:06 -06:00
|
|
|
func Getpagesize() int { return 0x1000 }
|
|
|
|
|
2011-04-02 15:24:03 -06:00
|
|
|
func Getegid() (egid int) { return -1 }
|
|
|
|
func Geteuid() (euid int) { return -1 }
|
|
|
|
func Getgid() (gid int) { return -1 }
|
|
|
|
func Getuid() (uid int) { return -1 }
|
|
|
|
|
2011-11-16 15:37:54 -07:00
|
|
|
func Getgroups() (gids []int, err error) {
|
2011-04-02 15:24:03 -06:00
|
|
|
return make([]int, 0), nil
|
|
|
|
}
|
|
|
|
|
2011-11-21 07:55:15 -07:00
|
|
|
//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)
|