2009-08-18 19:20:33 -07:00
|
|
|
// Copyright 2009 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.
|
|
|
|
|
|
|
|
|
|
package syscall
|
|
|
|
|
|
2012-10-08 00:13:28 +08:00
|
|
|
import "unsafe"
|
|
|
|
|
|
2015-03-09 07:03:00 +11:00
|
|
|
const _SYS_dup = SYS_DUP2
|
|
|
|
|
|
2009-12-15 15:40:16 -08:00
|
|
|
func Getpagesize() int { return 4096 }
|
2009-10-06 16:39:38 -07:00
|
|
|
|
2009-12-15 15:40:16 -08:00
|
|
|
func TimespecToNsec(ts Timespec) int64 { return int64(ts.Sec)*1e9 + int64(ts.Nsec) }
|
2009-10-06 16:39:38 -07:00
|
|
|
|
2009-08-18 19:20:33 -07:00
|
|
|
func NsecToTimespec(nsec int64) (ts Timespec) {
|
2009-12-15 15:40:16 -08:00
|
|
|
ts.Sec = int32(nsec / 1e9)
|
|
|
|
|
ts.Nsec = int32(nsec % 1e9)
|
|
|
|
|
return
|
2009-08-18 19:20:33 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func NsecToTimeval(nsec int64) (tv Timeval) {
|
2009-12-15 15:40:16 -08:00
|
|
|
nsec += 999 // round up to microsecond
|
|
|
|
|
tv.Sec = int32(nsec / 1e9)
|
|
|
|
|
tv.Usec = int32(nsec % 1e9 / 1e3)
|
|
|
|
|
return
|
2009-08-18 19:20:33 -07:00
|
|
|
}
|
|
|
|
|
|
2015-02-25 10:20:13 +11:00
|
|
|
func Pipe(p []int) (err error) {
|
|
|
|
|
if len(p) != 2 {
|
|
|
|
|
return EINVAL
|
|
|
|
|
}
|
|
|
|
|
var pp [2]_C_int
|
|
|
|
|
err = pipe2(&pp, 0)
|
|
|
|
|
p[0] = int(pp[0])
|
|
|
|
|
p[1] = int(pp[1])
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
|
|
|
|
|
|
|
|
|
|
func Pipe2(p []int, flags int) (err error) {
|
|
|
|
|
if len(p) != 2 {
|
|
|
|
|
return EINVAL
|
|
|
|
|
}
|
|
|
|
|
var pp [2]_C_int
|
|
|
|
|
err = pipe2(&pp, flags)
|
|
|
|
|
p[0] = int(pp[0])
|
|
|
|
|
p[1] = int(pp[1])
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2014-05-16 12:15:32 -04:00
|
|
|
// Underlying system call writes to newoffset via pointer.
|
|
|
|
|
// Implemented in assembly to avoid allocation.
|
|
|
|
|
func seek(fd int, offset int64, whence int) (newoffset int64, err Errno)
|
|
|
|
|
|
|
|
|
|
func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
|
|
|
|
|
newoffset, errno := seek(fd, offset, whence)
|
|
|
|
|
if errno != 0 {
|
|
|
|
|
return 0, errno
|
|
|
|
|
}
|
|
|
|
|
return newoffset, nil
|
|
|
|
|
}
|
2011-11-13 22:44:52 -05:00
|
|
|
|
|
|
|
|
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
|
2013-01-28 08:54:15 -08:00
|
|
|
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error)
|
2014-01-21 18:54:49 -08:00
|
|
|
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
|
|
|
|
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error)
|
2011-11-13 22:44:52 -05:00
|
|
|
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error) = SYS_GETGROUPS32
|
|
|
|
|
//sysnb setgroups(n int, list *_Gid_t) (err error) = SYS_SETGROUPS32
|
2014-01-21 18:54:49 -08:00
|
|
|
//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error)
|
|
|
|
|
//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error)
|
2011-11-13 22:44:52 -05:00
|
|
|
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
|
|
|
|
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
|
|
|
|
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error)
|
|
|
|
|
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error)
|
2014-01-21 18:54:49 -08:00
|
|
|
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error)
|
2012-09-24 00:06:22 -04:00
|
|
|
//sysnb socketpair(domain int, typ int, flags int, fd *[2]int32) (err error)
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
2014-03-29 09:28:40 +09:00
|
|
|
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error)
|
2011-11-13 22:44:52 -05:00
|
|
|
|
2012-06-03 06:49:57 +08:00
|
|
|
// 64-bit file system and 32-bit uid calls
|
|
|
|
|
// (16-bit uid calls are not always supported in newer kernels)
|
2015-03-26 08:02:16 -07:00
|
|
|
//sys Dup2(oldfd int, newfd int) (err error)
|
2012-06-03 06:49:57 +08:00
|
|
|
//sys Fchown(fd int, uid int, gid int) (err error) = SYS_FCHOWN32
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys Fstat(fd int, stat *Stat_t) (err error) = SYS_FSTAT64
|
2012-06-03 06:49:57 +08:00
|
|
|
//sysnb Getegid() (egid int) = SYS_GETEGID32
|
|
|
|
|
//sysnb Geteuid() (euid int) = SYS_GETEUID32
|
|
|
|
|
//sysnb Getgid() (gid int) = SYS_GETGID32
|
|
|
|
|
//sysnb Getuid() (uid int) = SYS_GETUID32
|
|
|
|
|
//sys Lchown(path string, uid int, gid int) (err error) = SYS_LCHOWN32
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys Listen(s int, n int) (err error)
|
|
|
|
|
//sys Lstat(path string, stat *Stat_t) (err error) = SYS_LSTAT64
|
2012-10-29 23:15:06 +04:00
|
|
|
//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = SYS_SENDFILE64
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error) = SYS__NEWSELECT
|
2012-06-03 06:49:57 +08:00
|
|
|
//sys Setfsgid(gid int) (err error) = SYS_SETFSGID32
|
|
|
|
|
//sys Setfsuid(uid int) (err error) = SYS_SETFSUID32
|
|
|
|
|
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID32
|
|
|
|
|
//sysnb Setresgid(rgid int, egid int, sgid int) (err error) = SYS_SETRESGID32
|
|
|
|
|
//sysnb Setresuid(ruid int, euid int, suid int) (err error) = SYS_SETRESUID32
|
|
|
|
|
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID32
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys Shutdown(fd int, how int) (err error)
|
|
|
|
|
//sys Splice(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
|
|
|
|
//sys Stat(path string, stat *Stat_t) (err error) = SYS_STAT64
|
2009-10-06 16:39:38 -07:00
|
|
|
|
2010-09-21 06:49:56 -07:00
|
|
|
// Vsyscalls on amd64.
|
2011-11-13 22:44:52 -05:00
|
|
|
//sysnb Gettimeofday(tv *Timeval) (err error)
|
|
|
|
|
//sysnb Time(t *Time_t) (tt Time_t, err error)
|
2010-09-21 06:49:56 -07:00
|
|
|
|
syscall: fix mkall.sh, mksyscall_linux.pl, and regen for Linux/ARM
CL 3075041 says ARM is not little-endian, but my test suggests otherwise.
My test program is:
package main
import ("fmt"; "syscall"; "os")
func main() {
err := syscall.Fallocate(1, 1/*FALLOC_FL_KEEP_SIZE*/, 0, int64(40960));
fmt.Fprintln(os.Stderr, err)
}
Without this CL, ./test > testfile will show: file too large; and strace shows:
fallocate(1, 01, 0, 175921860444160) = -1 EFBIG (File too large)
With this CL, ./test > testfile will show: <nil>; and strace shows:
fallocate(1, 01, 0, 40960) = 0
Quoting rsc:
"[It turns out that] ARM syscall ABI requires 64-bit arguments to use an
(even, odd) register pair, not an (odd, even) pair. Switching to "big-endian"
worked because it ended up using the high 32-bits (always zero in the tests
we had) as the padding word, because the 64-bit argument was the last one,
and because we fill in zeros for the rest of the system call arguments, up to
six. So it happened to work."
I updated mksyscall_linux.pl to accommodate the register pair ABI requirement,
and removed all hand-tweaked syscall routines in favor of the auto-generated
ones. These including: Ftruncate, Truncate, Pread and Pwrite.
Some recent Linux/ARM distributions do not bundle kernel asm headers,
so instead we always get latest asm/unistd.h from git.kernel.org (just like
what we do for FreeBSD).
R=ken, r, rsc, r, dave, iant
CC=golang-dev
https://golang.org/cl/5726051
2012-03-06 03:12:11 +08:00
|
|
|
//sys Pread(fd int, p []byte, offset int64) (n int, err error) = SYS_PREAD64
|
|
|
|
|
//sys Pwrite(fd int, p []byte, offset int64) (n int, err error) = SYS_PWRITE64
|
|
|
|
|
//sys Truncate(path string, length int64) (err error) = SYS_TRUNCATE64
|
|
|
|
|
//sys Ftruncate(fd int, length int64) (err error) = SYS_FTRUNCATE64
|
|
|
|
|
|
2011-11-13 22:44:52 -05:00
|
|
|
//sys mmap2(addr uintptr, length uintptr, prot int, flags int, fd int, pageOffset uintptr) (xaddr uintptr, err error)
|
2011-04-06 17:52:02 -04:00
|
|
|
|
2012-10-08 00:13:28 +08:00
|
|
|
func Fstatfs(fd int, buf *Statfs_t) (err error) {
|
|
|
|
|
_, _, e := Syscall(SYS_FSTATFS64, uintptr(fd), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
|
|
|
|
if e != 0 {
|
|
|
|
|
err = e
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func Statfs(path string, buf *Statfs_t) (err error) {
|
|
|
|
|
pathp, err := BytePtrFromString(path)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
_, _, e := Syscall(SYS_STATFS64, uintptr(unsafe.Pointer(pathp)), unsafe.Sizeof(*buf), uintptr(unsafe.Pointer(buf)))
|
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 16:59:59 -04:00
|
|
|
use(unsafe.Pointer(pathp))
|
2012-10-08 00:13:28 +08:00
|
|
|
if e != 0 {
|
|
|
|
|
err = e
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
2011-11-13 22:44:52 -05:00
|
|
|
func mmap(addr uintptr, length uintptr, prot int, flags int, fd int, offset int64) (xaddr uintptr, err error) {
|
2011-04-06 17:52:02 -04:00
|
|
|
page := uintptr(offset / 4096)
|
|
|
|
|
if offset != int64(page)*4096 {
|
|
|
|
|
return 0, EINVAL
|
|
|
|
|
}
|
|
|
|
|
return mmap2(addr, length, prot, flags, fd, page)
|
|
|
|
|
}
|
|
|
|
|
|
2012-07-02 22:57:32 -07:00
|
|
|
type rlimit32 struct {
|
|
|
|
|
Cur uint32
|
|
|
|
|
Max uint32
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//sysnb getrlimit(resource int, rlim *rlimit32) (err error) = SYS_GETRLIMIT
|
|
|
|
|
|
|
|
|
|
const rlimInf32 = ^uint32(0)
|
|
|
|
|
const rlimInf64 = ^uint64(0)
|
|
|
|
|
|
|
|
|
|
func Getrlimit(resource int, rlim *Rlimit) (err error) {
|
2013-07-25 09:56:06 -04:00
|
|
|
err = prlimit(0, resource, nil, rlim)
|
2012-07-02 22:57:32 -07:00
|
|
|
if err != ENOSYS {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rl := rlimit32{}
|
|
|
|
|
err = getrlimit(resource, &rl)
|
|
|
|
|
if err != nil {
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rl.Cur == rlimInf32 {
|
|
|
|
|
rlim.Cur = rlimInf64
|
|
|
|
|
} else {
|
|
|
|
|
rlim.Cur = uint64(rl.Cur)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if rl.Max == rlimInf32 {
|
|
|
|
|
rlim.Max = rlimInf64
|
|
|
|
|
} else {
|
|
|
|
|
rlim.Max = uint64(rl.Max)
|
|
|
|
|
}
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
//sysnb setrlimit(resource int, rlim *rlimit32) (err error) = SYS_SETRLIMIT
|
|
|
|
|
|
|
|
|
|
func Setrlimit(resource int, rlim *Rlimit) (err error) {
|
2013-07-25 09:56:06 -04:00
|
|
|
err = prlimit(0, resource, rlim, nil)
|
2012-07-02 22:57:32 -07:00
|
|
|
if err != ENOSYS {
|
|
|
|
|
return err
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
rl := rlimit32{}
|
|
|
|
|
if rlim.Cur == rlimInf64 {
|
|
|
|
|
rl.Cur = rlimInf32
|
|
|
|
|
} else if rlim.Cur < uint64(rlimInf32) {
|
|
|
|
|
rl.Cur = uint32(rlim.Cur)
|
|
|
|
|
} else {
|
|
|
|
|
return EINVAL
|
|
|
|
|
}
|
|
|
|
|
if rlim.Max == rlimInf64 {
|
|
|
|
|
rl.Max = rlimInf32
|
|
|
|
|
} else if rlim.Max < uint64(rlimInf32) {
|
|
|
|
|
rl.Max = uint32(rlim.Max)
|
|
|
|
|
} else {
|
|
|
|
|
return EINVAL
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return setrlimit(resource, &rl)
|
|
|
|
|
}
|
|
|
|
|
|
2012-10-25 13:41:04 +08:00
|
|
|
func (r *PtraceRegs) PC() uint64 { return uint64(r.Uregs[15]) }
|
2009-10-06 16:39:38 -07:00
|
|
|
|
2012-10-25 13:41:04 +08:00
|
|
|
func (r *PtraceRegs) SetPC(pc uint64) { r.Uregs[15] = uint32(pc) }
|
2010-12-08 14:31:46 -05:00
|
|
|
|
|
|
|
|
func (iov *Iovec) SetLen(length int) {
|
|
|
|
|
iov.Len = uint32(length)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (msghdr *Msghdr) SetControllen(length int) {
|
|
|
|
|
msghdr.Controllen = uint32(length)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func (cmsg *Cmsghdr) SetLen(length int) {
|
|
|
|
|
cmsg.Len = uint32(length)
|
|
|
|
|
}
|