зеркало из https://github.com/golang/sys.git
1995 строки
53 KiB
Go
1995 строки
53 KiB
Go
// Copyright 2020 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.
|
|
|
|
//go:build zos && s390x
|
|
// +build zos,s390x
|
|
|
|
package unix
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
const (
|
|
O_CLOEXEC = 0 // Dummy value (not supported).
|
|
AF_LOCAL = AF_UNIX // AF_LOCAL is an alias for AF_UNIX
|
|
)
|
|
|
|
func syscall_syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
|
func syscall_rawsyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno)
|
|
func syscall_syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
|
func syscall_rawsyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
|
func syscall_syscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
|
func syscall_rawsyscall9(trap, a1, a2, a3, a4, a5, a6, a7, a8, a9 uintptr) (r1, r2 uintptr, err Errno)
|
|
|
|
func copyStat(stat *Stat_t, statLE *Stat_LE_t) {
|
|
stat.Dev = uint64(statLE.Dev)
|
|
stat.Ino = uint64(statLE.Ino)
|
|
stat.Nlink = uint64(statLE.Nlink)
|
|
stat.Mode = uint32(statLE.Mode)
|
|
stat.Uid = uint32(statLE.Uid)
|
|
stat.Gid = uint32(statLE.Gid)
|
|
stat.Rdev = uint64(statLE.Rdev)
|
|
stat.Size = statLE.Size
|
|
stat.Atim.Sec = int64(statLE.Atim)
|
|
stat.Atim.Nsec = 0 //zos doesn't return nanoseconds
|
|
stat.Mtim.Sec = int64(statLE.Mtim)
|
|
stat.Mtim.Nsec = 0 //zos doesn't return nanoseconds
|
|
stat.Ctim.Sec = int64(statLE.Ctim)
|
|
stat.Ctim.Nsec = 0 //zos doesn't return nanoseconds
|
|
stat.Blksize = int64(statLE.Blksize)
|
|
stat.Blocks = statLE.Blocks
|
|
}
|
|
|
|
func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64)
|
|
func svcLoad(name *byte) unsafe.Pointer
|
|
func svcUnload(name *byte, fnptr unsafe.Pointer) int64
|
|
|
|
func (d *Dirent) NameString() string {
|
|
if d == nil {
|
|
return ""
|
|
}
|
|
s := string(d.Name[:])
|
|
idx := strings.IndexByte(s, 0)
|
|
if idx == -1 {
|
|
return s
|
|
} else {
|
|
return s[:idx]
|
|
}
|
|
}
|
|
|
|
func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
|
return nil, 0, EINVAL
|
|
}
|
|
sa.raw.Len = SizeofSockaddrInet4
|
|
sa.raw.Family = AF_INET
|
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
|
p[0] = byte(sa.Port >> 8)
|
|
p[1] = byte(sa.Port)
|
|
sa.raw.Addr = sa.Addr
|
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
|
}
|
|
|
|
func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
if sa.Port < 0 || sa.Port > 0xFFFF {
|
|
return nil, 0, EINVAL
|
|
}
|
|
sa.raw.Len = SizeofSockaddrInet6
|
|
sa.raw.Family = AF_INET6
|
|
p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
|
|
p[0] = byte(sa.Port >> 8)
|
|
p[1] = byte(sa.Port)
|
|
sa.raw.Scope_id = sa.ZoneId
|
|
sa.raw.Addr = sa.Addr
|
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
|
}
|
|
|
|
func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
name := sa.Name
|
|
n := len(name)
|
|
if n >= len(sa.raw.Path) || n == 0 {
|
|
return nil, 0, EINVAL
|
|
}
|
|
sa.raw.Len = byte(3 + n) // 2 for Family, Len; 1 for NUL
|
|
sa.raw.Family = AF_UNIX
|
|
for i := 0; i < n; i++ {
|
|
sa.raw.Path[i] = int8(name[i])
|
|
}
|
|
return unsafe.Pointer(&sa.raw), _Socklen(sa.raw.Len), nil
|
|
}
|
|
|
|
func anyToSockaddr(_ int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|
// TODO(neeilan): Implement use of first param (fd)
|
|
switch rsa.Addr.Family {
|
|
case AF_UNIX:
|
|
pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
|
|
sa := new(SockaddrUnix)
|
|
// For z/OS, only replace NUL with @ when the
|
|
// length is not zero.
|
|
if pp.Len != 0 && pp.Path[0] == 0 {
|
|
// "Abstract" Unix domain socket.
|
|
// Rewrite leading NUL as @ for textual display.
|
|
// (This is the standard convention.)
|
|
// Not friendly to overwrite in place,
|
|
// but the callers below don't care.
|
|
pp.Path[0] = '@'
|
|
}
|
|
|
|
// Assume path ends at NUL.
|
|
//
|
|
// For z/OS, the length of the name is a field
|
|
// in the structure. To be on the safe side, we
|
|
// will still scan the name for a NUL but only
|
|
// to the length provided in the structure.
|
|
//
|
|
// This is not technically the Linux semantics for
|
|
// abstract Unix domain sockets--they are supposed
|
|
// to be uninterpreted fixed-size binary blobs--but
|
|
// everyone uses this convention.
|
|
n := 0
|
|
for n < int(pp.Len) && pp.Path[n] != 0 {
|
|
n++
|
|
}
|
|
bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
|
sa.Name = string(bytes)
|
|
return sa, nil
|
|
|
|
case AF_INET:
|
|
pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
|
sa := new(SockaddrInet4)
|
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
|
sa.Port = int(p[0])<<8 + int(p[1])
|
|
sa.Addr = pp.Addr
|
|
return sa, nil
|
|
|
|
case AF_INET6:
|
|
pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
|
|
sa := new(SockaddrInet6)
|
|
p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
|
sa.Port = int(p[0])<<8 + int(p[1])
|
|
sa.ZoneId = pp.Scope_id
|
|
sa.Addr = pp.Addr
|
|
return sa, nil
|
|
}
|
|
return nil, EAFNOSUPPORT
|
|
}
|
|
|
|
func Accept(fd int) (nfd int, sa Sockaddr, err error) {
|
|
var rsa RawSockaddrAny
|
|
var len _Socklen = SizeofSockaddrAny
|
|
nfd, err = accept(fd, &rsa, &len)
|
|
if err != nil {
|
|
return
|
|
}
|
|
// TODO(neeilan): Remove 0 in call
|
|
sa, err = anyToSockaddr(0, &rsa)
|
|
if err != nil {
|
|
Close(nfd)
|
|
nfd = 0
|
|
}
|
|
return
|
|
}
|
|
|
|
func (iov *Iovec) SetLen(length int) {
|
|
iov.Len = uint64(length)
|
|
}
|
|
|
|
func (msghdr *Msghdr) SetControllen(length int) {
|
|
msghdr.Controllen = int32(length)
|
|
}
|
|
|
|
func (cmsg *Cmsghdr) SetLen(length int) {
|
|
cmsg.Len = int32(length)
|
|
}
|
|
|
|
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
|
//sys read(fd int, p []byte) (n int, err error)
|
|
//sys readlen(fd int, buf *byte, nbuf int) (n int, err error) = SYS_READ
|
|
//sys write(fd int, p []byte) (n int, err error)
|
|
|
|
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = SYS___ACCEPT_A
|
|
//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = SYS___BIND_A
|
|
//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = SYS___CONNECT_A
|
|
//sysnb getgroups(n int, list *_Gid_t) (nn int, err error)
|
|
//sysnb setgroups(n int, list *_Gid_t) (err error)
|
|
//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)
|
|
//sysnb socket(domain int, typ int, proto int) (fd int, err error)
|
|
//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error)
|
|
//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = SYS___GETPEERNAME_A
|
|
//sysnb getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = SYS___GETSOCKNAME_A
|
|
//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = SYS___RECVFROM_A
|
|
//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = SYS___SENDTO_A
|
|
//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = SYS___RECVMSG_A
|
|
//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = SYS___SENDMSG_A
|
|
//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error) = SYS_MMAP
|
|
//sys munmap(addr uintptr, length uintptr) (err error) = SYS_MUNMAP
|
|
//sys ioctl(fd int, req uint, arg uintptr) (err error) = SYS_IOCTL
|
|
|
|
//sys Access(path string, mode uint32) (err error) = SYS___ACCESS_A
|
|
//sys Chdir(path string) (err error) = SYS___CHDIR_A
|
|
//sys Chown(path string, uid int, gid int) (err error) = SYS___CHOWN_A
|
|
//sys Chmod(path string, mode uint32) (err error) = SYS___CHMOD_A
|
|
//sys Creat(path string, mode uint32) (fd int, err error) = SYS___CREAT_A
|
|
//sys Dup(oldfd int) (fd int, err error)
|
|
//sys Dup2(oldfd int, newfd int) (err error)
|
|
//sys Errno2() (er2 int) = SYS___ERRNO2
|
|
//sys Err2ad() (eadd *int) = SYS___ERR2AD
|
|
//sys Exit(code int)
|
|
//sys Fchdir(fd int) (err error)
|
|
//sys Fchmod(fd int, mode uint32) (err error)
|
|
//sys Fchown(fd int, uid int, gid int) (err error)
|
|
//sys FcntlInt(fd uintptr, cmd int, arg int) (retval int, err error) = SYS_FCNTL
|
|
//sys fstat(fd int, stat *Stat_LE_t) (err error)
|
|
|
|
func Fstat(fd int, stat *Stat_t) (err error) {
|
|
var statLE Stat_LE_t
|
|
err = fstat(fd, &statLE)
|
|
copyStat(stat, &statLE)
|
|
return
|
|
}
|
|
|
|
//sys Fstatvfs(fd int, stat *Statvfs_t) (err error) = SYS_FSTATVFS
|
|
//sys Fsync(fd int) (err error)
|
|
//sys Ftruncate(fd int, length int64) (err error)
|
|
//sys Getpagesize() (pgsize int) = SYS_GETPAGESIZE
|
|
//sys Mprotect(b []byte, prot int) (err error) = SYS_MPROTECT
|
|
//sys Msync(b []byte, flags int) (err error) = SYS_MSYNC
|
|
//sys Poll(fds []PollFd, timeout int) (n int, err error) = SYS_POLL
|
|
//sys Times(tms *Tms) (ticks uintptr, err error) = SYS_TIMES
|
|
//sys W_Getmntent(buff *byte, size int) (lastsys int, err error) = SYS_W_GETMNTENT
|
|
//sys W_Getmntent_A(buff *byte, size int) (lastsys int, err error) = SYS___W_GETMNTENT_A
|
|
|
|
//sys mount_LE(path string, filesystem string, fstype string, mtm uint32, parmlen int32, parm string) (err error) = SYS___MOUNT_A
|
|
//sys unmount(filesystem string, mtm int) (err error) = SYS___UMOUNT_A
|
|
//sys Chroot(path string) (err error) = SYS___CHROOT_A
|
|
//sys Select(nmsgsfds int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (ret int, err error) = SYS_SELECT
|
|
//sysnb Uname(buf *Utsname) (err error) = SYS___UNAME_A
|
|
|
|
func Ptsname(fd int) (name string, err error) {
|
|
r0, _, e1 := syscall_syscall(SYS___PTSNAME_A, uintptr(fd), 0, 0)
|
|
name = u2s(unsafe.Pointer(r0))
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func u2s(cstr unsafe.Pointer) string {
|
|
str := (*[1024]uint8)(cstr)
|
|
i := 0
|
|
for str[i] != 0 {
|
|
i++
|
|
}
|
|
return string(str[:i])
|
|
}
|
|
|
|
func Close(fd int) (err error) {
|
|
_, _, e1 := syscall_syscall(SYS_CLOSE, uintptr(fd), 0, 0)
|
|
for i := 0; e1 == EAGAIN && i < 10; i++ {
|
|
_, _, _ = syscall_syscall(SYS_USLEEP, uintptr(10), 0, 0)
|
|
_, _, e1 = syscall_syscall(SYS_CLOSE, uintptr(fd), 0, 0)
|
|
}
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
var mapper = &mmapper{
|
|
active: make(map[*byte][]byte),
|
|
mmap: mmap,
|
|
munmap: munmap,
|
|
}
|
|
|
|
// Dummy function: there are no semantics for Madvise on z/OS
|
|
func Madvise(b []byte, advice int) (err error) {
|
|
return
|
|
}
|
|
|
|
func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
|
return mapper.Mmap(fd, offset, length, prot, flags)
|
|
}
|
|
|
|
func Munmap(b []byte) (err error) {
|
|
return mapper.Munmap(b)
|
|
}
|
|
|
|
//sys Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A
|
|
//sysnb Getegid() (egid int)
|
|
//sysnb Geteuid() (uid int)
|
|
//sysnb Getgid() (gid int)
|
|
//sysnb Getpid() (pid int)
|
|
//sysnb Getpgid(pid int) (pgid int, err error) = SYS_GETPGID
|
|
|
|
func Getpgrp() (pid int) {
|
|
pid, _ = Getpgid(0)
|
|
return
|
|
}
|
|
|
|
//sysnb Getppid() (pid int)
|
|
//sys Getpriority(which int, who int) (prio int, err error)
|
|
//sysnb Getrlimit(resource int, rlim *Rlimit) (err error) = SYS_GETRLIMIT
|
|
|
|
//sysnb getrusage(who int, rusage *rusage_zos) (err error) = SYS_GETRUSAGE
|
|
|
|
func Getrusage(who int, rusage *Rusage) (err error) {
|
|
var ruz rusage_zos
|
|
err = getrusage(who, &ruz)
|
|
//Only the first two fields of Rusage are set
|
|
rusage.Utime.Sec = ruz.Utime.Sec
|
|
rusage.Utime.Usec = int64(ruz.Utime.Usec)
|
|
rusage.Stime.Sec = ruz.Stime.Sec
|
|
rusage.Stime.Usec = int64(ruz.Stime.Usec)
|
|
return
|
|
}
|
|
|
|
//sysnb Getsid(pid int) (sid int, err error) = SYS_GETSID
|
|
//sysnb Getuid() (uid int)
|
|
//sysnb Kill(pid int, sig Signal) (err error)
|
|
//sys Lchown(path string, uid int, gid int) (err error) = SYS___LCHOWN_A
|
|
//sys Link(path string, link string) (err error) = SYS___LINK_A
|
|
//sys Listen(s int, n int) (err error)
|
|
//sys lstat(path string, stat *Stat_LE_t) (err error) = SYS___LSTAT_A
|
|
|
|
func Lstat(path string, stat *Stat_t) (err error) {
|
|
var statLE Stat_LE_t
|
|
err = lstat(path, &statLE)
|
|
copyStat(stat, &statLE)
|
|
return
|
|
}
|
|
|
|
//sys Mkdir(path string, mode uint32) (err error) = SYS___MKDIR_A
|
|
//sys Mkfifo(path string, mode uint32) (err error) = SYS___MKFIFO_A
|
|
//sys Mknod(path string, mode uint32, dev int) (err error) = SYS___MKNOD_A
|
|
//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 Readlink(path string, buf []byte) (n int, err error) = SYS___READLINK_A
|
|
//sys Rename(from string, to string) (err error) = SYS___RENAME_A
|
|
//sys Rmdir(path string) (err error) = SYS___RMDIR_A
|
|
//sys Seek(fd int, offset int64, whence int) (off int64, err error) = SYS_LSEEK
|
|
//sys Setpriority(which int, who int, prio int) (err error)
|
|
//sysnb Setpgid(pid int, pgid int) (err error) = SYS_SETPGID
|
|
//sysnb Setrlimit(resource int, lim *Rlimit) (err error)
|
|
//sysnb Setregid(rgid int, egid int) (err error) = SYS_SETREGID
|
|
//sysnb Setreuid(ruid int, euid int) (err error) = SYS_SETREUID
|
|
//sysnb Setsid() (pid int, err error) = SYS_SETSID
|
|
//sys Setuid(uid int) (err error) = SYS_SETUID
|
|
//sys Setgid(uid int) (err error) = SYS_SETGID
|
|
//sys Shutdown(fd int, how int) (err error)
|
|
//sys stat(path string, statLE *Stat_LE_t) (err error) = SYS___STAT_A
|
|
|
|
func Stat(path string, sta *Stat_t) (err error) {
|
|
var statLE Stat_LE_t
|
|
err = stat(path, &statLE)
|
|
copyStat(sta, &statLE)
|
|
return
|
|
}
|
|
|
|
//sys Symlink(path string, link string) (err error) = SYS___SYMLINK_A
|
|
//sys Sync() = SYS_SYNC
|
|
//sys Truncate(path string, length int64) (err error) = SYS___TRUNCATE_A
|
|
//sys Tcgetattr(fildes int, termptr *Termios) (err error) = SYS_TCGETATTR
|
|
//sys Tcsetattr(fildes int, when int, termptr *Termios) (err error) = SYS_TCSETATTR
|
|
//sys Umask(mask int) (oldmask int)
|
|
//sys Unlink(path string) (err error) = SYS___UNLINK_A
|
|
//sys Utime(path string, utim *Utimbuf) (err error) = SYS___UTIME_A
|
|
|
|
//sys open(path string, mode int, perm uint32) (fd int, err error) = SYS___OPEN_A
|
|
|
|
func Open(path string, mode int, perm uint32) (fd int, err error) {
|
|
return open(path, mode, perm)
|
|
}
|
|
|
|
func Mkfifoat(dirfd int, path string, mode uint32) (err error) {
|
|
wd, err := Getwd()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := Fchdir(dirfd); err != nil {
|
|
return err
|
|
}
|
|
defer Chdir(wd)
|
|
|
|
return Mkfifo(path, mode)
|
|
}
|
|
|
|
//sys remove(path string) (err error)
|
|
|
|
func Remove(path string) error {
|
|
return remove(path)
|
|
}
|
|
|
|
const ImplementsGetwd = true
|
|
|
|
func Getcwd(buf []byte) (n int, err error) {
|
|
var p unsafe.Pointer
|
|
if len(buf) > 0 {
|
|
p = unsafe.Pointer(&buf[0])
|
|
} else {
|
|
p = unsafe.Pointer(&_zero)
|
|
}
|
|
_, _, e := syscall_syscall(SYS___GETCWD_A, uintptr(p), uintptr(len(buf)), 0)
|
|
n = clen(buf) + 1
|
|
if e != 0 {
|
|
err = errnoErr(e)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Getwd() (wd string, err error) {
|
|
var buf [PathMax]byte
|
|
n, err := Getcwd(buf[0:])
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
// Getcwd returns the number of bytes written to buf, including the NUL.
|
|
if n < 1 || n > len(buf) || buf[n-1] != 0 {
|
|
return "", EINVAL
|
|
}
|
|
return string(buf[0 : n-1]), nil
|
|
}
|
|
|
|
func Getgroups() (gids []int, err error) {
|
|
n, err := getgroups(0, nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if n == 0 {
|
|
return nil, nil
|
|
}
|
|
|
|
// Sanity check group count. Max is 1<<16 on Linux.
|
|
if n < 0 || n > 1<<20 {
|
|
return nil, EINVAL
|
|
}
|
|
|
|
a := make([]_Gid_t, n)
|
|
n, err = getgroups(n, &a[0])
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
gids = make([]int, n)
|
|
for i, v := range a[0:n] {
|
|
gids[i] = int(v)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Setgroups(gids []int) (err error) {
|
|
if len(gids) == 0 {
|
|
return setgroups(0, nil)
|
|
}
|
|
|
|
a := make([]_Gid_t, len(gids))
|
|
for i, v := range gids {
|
|
a[i] = _Gid_t(v)
|
|
}
|
|
return setgroups(len(a), &a[0])
|
|
}
|
|
|
|
func gettid() uint64
|
|
|
|
func Gettid() (tid int) {
|
|
return int(gettid())
|
|
}
|
|
|
|
type WaitStatus uint32
|
|
|
|
// Wait status is 7 bits at bottom, either 0 (exited),
|
|
// 0x7F (stopped), or a signal number that caused an exit.
|
|
// The 0x80 bit is whether there was a core dump.
|
|
// An extra number (exit code, signal causing a stop)
|
|
// is in the high bits. At least that's the idea.
|
|
// There are various irregularities. For example, the
|
|
// "continued" status is 0xFFFF, distinguishing itself
|
|
// from stopped via the core dump bit.
|
|
|
|
const (
|
|
mask = 0x7F
|
|
core = 0x80
|
|
exited = 0x00
|
|
stopped = 0x7F
|
|
shift = 8
|
|
)
|
|
|
|
func (w WaitStatus) Exited() bool { return w&mask == exited }
|
|
|
|
func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != exited }
|
|
|
|
func (w WaitStatus) Stopped() bool { return w&0xFF == stopped }
|
|
|
|
func (w WaitStatus) Continued() bool { return w == 0xFFFF }
|
|
|
|
func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
|
|
|
|
func (w WaitStatus) ExitStatus() int {
|
|
if !w.Exited() {
|
|
return -1
|
|
}
|
|
return int(w>>shift) & 0xFF
|
|
}
|
|
|
|
func (w WaitStatus) Signal() Signal {
|
|
if !w.Signaled() {
|
|
return -1
|
|
}
|
|
return Signal(w & mask)
|
|
}
|
|
|
|
func (w WaitStatus) StopSignal() Signal {
|
|
if !w.Stopped() {
|
|
return -1
|
|
}
|
|
return Signal(w>>shift) & 0xFF
|
|
}
|
|
|
|
func (w WaitStatus) TrapCause() int { return -1 }
|
|
|
|
//sys waitpid(pid int, wstatus *_C_int, options int) (wpid int, err error)
|
|
|
|
func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
|
// TODO(mundaym): z/OS doesn't have wait4. I don't think getrusage does what we want.
|
|
// At the moment rusage will not be touched.
|
|
var status _C_int
|
|
wpid, err = waitpid(pid, &status, options)
|
|
if wstatus != nil {
|
|
*wstatus = WaitStatus(status)
|
|
}
|
|
return
|
|
}
|
|
|
|
//sysnb gettimeofday(tv *timeval_zos) (err error)
|
|
|
|
func Gettimeofday(tv *Timeval) (err error) {
|
|
var tvz timeval_zos
|
|
err = gettimeofday(&tvz)
|
|
tv.Sec = tvz.Sec
|
|
tv.Usec = int64(tvz.Usec)
|
|
return
|
|
}
|
|
|
|
func Time(t *Time_t) (tt Time_t, err error) {
|
|
var tv Timeval
|
|
err = Gettimeofday(&tv)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
if t != nil {
|
|
*t = Time_t(tv.Sec)
|
|
}
|
|
return Time_t(tv.Sec), nil
|
|
}
|
|
|
|
func setTimespec(sec, nsec int64) Timespec {
|
|
return Timespec{Sec: sec, Nsec: nsec}
|
|
}
|
|
|
|
func setTimeval(sec, usec int64) Timeval { //fix
|
|
return Timeval{Sec: sec, Usec: usec}
|
|
}
|
|
|
|
//sysnb pipe(p *[2]_C_int) (err error)
|
|
|
|
func Pipe(p []int) (err error) {
|
|
if len(p) != 2 {
|
|
return EINVAL
|
|
}
|
|
var pp [2]_C_int
|
|
err = pipe(&pp)
|
|
if err == nil {
|
|
p[0] = int(pp[0])
|
|
p[1] = int(pp[1])
|
|
}
|
|
return
|
|
}
|
|
|
|
//sys utimes(path string, timeval *[2]Timeval) (err error) = SYS___UTIMES_A
|
|
|
|
func Utimes(path string, tv []Timeval) (err error) {
|
|
if len(tv) != 2 {
|
|
return EINVAL
|
|
}
|
|
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
|
}
|
|
|
|
func UtimesNano(path string, ts []Timespec) error {
|
|
if len(ts) != 2 {
|
|
return EINVAL
|
|
}
|
|
// Not as efficient as it could be because Timespec and
|
|
// Timeval have different types in the different OSes
|
|
tv := [2]Timeval{
|
|
NsecToTimeval(TimespecToNsec(ts[0])),
|
|
NsecToTimeval(TimespecToNsec(ts[1])),
|
|
}
|
|
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
|
}
|
|
|
|
func Getsockname(fd int) (sa Sockaddr, err error) {
|
|
var rsa RawSockaddrAny
|
|
var len _Socklen = SizeofSockaddrAny
|
|
if err = getsockname(fd, &rsa, &len); err != nil {
|
|
return
|
|
}
|
|
// TODO(neeilan) : Remove this 0 ( added to get sys/unix compiling on z/OS )
|
|
return anyToSockaddr(0, &rsa)
|
|
}
|
|
|
|
const (
|
|
// identifier constants
|
|
nwmHeaderIdentifier = 0xd5e6d4c8
|
|
nwmFilterIdentifier = 0xd5e6d4c6
|
|
nwmTCPConnIdentifier = 0xd5e6d4c3
|
|
nwmRecHeaderIdentifier = 0xd5e6d4d9
|
|
nwmIPStatsIdentifier = 0xd5e6d4c9d7e2e340
|
|
nwmIPGStatsIdentifier = 0xd5e6d4c9d7c7e2e3
|
|
nwmTCPStatsIdentifier = 0xd5e6d4e3c3d7e2e3
|
|
nwmUDPStatsIdentifier = 0xd5e6d4e4c4d7e2e3
|
|
nwmICMPGStatsEntry = 0xd5e6d4c9c3d4d7c7
|
|
nwmICMPTStatsEntry = 0xd5e6d4c9c3d4d7e3
|
|
|
|
// nwmHeader constants
|
|
nwmVersion1 = 1
|
|
nwmVersion2 = 2
|
|
nwmCurrentVer = 2
|
|
|
|
nwmTCPConnType = 1
|
|
nwmGlobalStatsType = 14
|
|
|
|
// nwmFilter constants
|
|
nwmFilterLclAddrMask = 0x20000000 // Local address
|
|
nwmFilterSrcAddrMask = 0x20000000 // Source address
|
|
nwmFilterLclPortMask = 0x10000000 // Local port
|
|
nwmFilterSrcPortMask = 0x10000000 // Source port
|
|
|
|
// nwmConnEntry constants
|
|
nwmTCPStateClosed = 1
|
|
nwmTCPStateListen = 2
|
|
nwmTCPStateSynSent = 3
|
|
nwmTCPStateSynRcvd = 4
|
|
nwmTCPStateEstab = 5
|
|
nwmTCPStateFinWait1 = 6
|
|
nwmTCPStateFinWait2 = 7
|
|
nwmTCPStateClosWait = 8
|
|
nwmTCPStateLastAck = 9
|
|
nwmTCPStateClosing = 10
|
|
nwmTCPStateTimeWait = 11
|
|
nwmTCPStateDeletTCB = 12
|
|
|
|
// Existing constants on linux
|
|
BPF_TCP_CLOSE = 1
|
|
BPF_TCP_LISTEN = 2
|
|
BPF_TCP_SYN_SENT = 3
|
|
BPF_TCP_SYN_RECV = 4
|
|
BPF_TCP_ESTABLISHED = 5
|
|
BPF_TCP_FIN_WAIT1 = 6
|
|
BPF_TCP_FIN_WAIT2 = 7
|
|
BPF_TCP_CLOSE_WAIT = 8
|
|
BPF_TCP_LAST_ACK = 9
|
|
BPF_TCP_CLOSING = 10
|
|
BPF_TCP_TIME_WAIT = 11
|
|
BPF_TCP_NEW_SYN_RECV = -1
|
|
BPF_TCP_MAX_STATES = -2
|
|
)
|
|
|
|
type nwmTriplet struct {
|
|
offset uint32
|
|
length uint32
|
|
number uint32
|
|
}
|
|
|
|
type nwmQuadruplet struct {
|
|
offset uint32
|
|
length uint32
|
|
number uint32
|
|
match uint32
|
|
}
|
|
|
|
type nwmHeader struct {
|
|
ident uint32
|
|
length uint32
|
|
version uint16
|
|
nwmType uint16
|
|
bytesNeeded uint32
|
|
options uint32
|
|
_ [16]byte
|
|
inputDesc nwmTriplet
|
|
outputDesc nwmQuadruplet
|
|
}
|
|
|
|
type nwmFilter struct {
|
|
ident uint32
|
|
flags uint32
|
|
resourceName [8]byte
|
|
resourceId uint32
|
|
listenerId uint32
|
|
local [28]byte // union of sockaddr4 and sockaddr6
|
|
remote [28]byte // union of sockaddr4 and sockaddr6
|
|
_ uint16
|
|
_ uint16
|
|
asid uint16
|
|
_ [2]byte
|
|
tnLuName [8]byte
|
|
tnMonGrp uint32
|
|
tnAppl [8]byte
|
|
applData [40]byte
|
|
nInterface [16]byte
|
|
dVipa [16]byte
|
|
dVipaPfx uint16
|
|
dVipaPort uint16
|
|
dVipaFamily byte
|
|
_ [3]byte
|
|
destXCF [16]byte
|
|
destXCFPfx uint16
|
|
destXCFFamily byte
|
|
_ [1]byte
|
|
targIP [16]byte
|
|
targIPPfx uint16
|
|
targIPFamily byte
|
|
_ [1]byte
|
|
_ [20]byte
|
|
}
|
|
|
|
type nwmRecHeader struct {
|
|
ident uint32
|
|
length uint32
|
|
number byte
|
|
_ [3]byte
|
|
}
|
|
|
|
type nwmTCPStatsEntry struct {
|
|
ident uint64
|
|
currEstab uint32
|
|
activeOpened uint32
|
|
passiveOpened uint32
|
|
connClosed uint32
|
|
estabResets uint32
|
|
attemptFails uint32
|
|
passiveDrops uint32
|
|
timeWaitReused uint32
|
|
inSegs uint64
|
|
predictAck uint32
|
|
predictData uint32
|
|
inDupAck uint32
|
|
inBadSum uint32
|
|
inBadLen uint32
|
|
inShort uint32
|
|
inDiscOldTime uint32
|
|
inAllBeforeWin uint32
|
|
inSomeBeforeWin uint32
|
|
inAllAfterWin uint32
|
|
inSomeAfterWin uint32
|
|
inOutOfOrder uint32
|
|
inAfterClose uint32
|
|
inWinProbes uint32
|
|
inWinUpdates uint32
|
|
outWinUpdates uint32
|
|
outSegs uint64
|
|
outDelayAcks uint32
|
|
outRsts uint32
|
|
retransSegs uint32
|
|
retransTimeouts uint32
|
|
retransDrops uint32
|
|
pmtuRetrans uint32
|
|
pmtuErrors uint32
|
|
outWinProbes uint32
|
|
probeDrops uint32
|
|
keepAliveProbes uint32
|
|
keepAliveDrops uint32
|
|
finwait2Drops uint32
|
|
acceptCount uint64
|
|
inBulkQSegs uint64
|
|
inDiscards uint64
|
|
connFloods uint32
|
|
connStalls uint32
|
|
cfgEphemDef uint16
|
|
ephemInUse uint16
|
|
ephemHiWater uint16
|
|
flags byte
|
|
_ [1]byte
|
|
ephemExhaust uint32
|
|
smcRCurrEstabLnks uint32
|
|
smcRLnkActTimeOut uint32
|
|
smcRActLnkOpened uint32
|
|
smcRPasLnkOpened uint32
|
|
smcRLnksClosed uint32
|
|
smcRCurrEstab uint32
|
|
smcRActiveOpened uint32
|
|
smcRPassiveOpened uint32
|
|
smcRConnClosed uint32
|
|
smcRInSegs uint64
|
|
smcROutSegs uint64
|
|
smcRInRsts uint32
|
|
smcROutRsts uint32
|
|
smcDCurrEstabLnks uint32
|
|
smcDActLnkOpened uint32
|
|
smcDPasLnkOpened uint32
|
|
smcDLnksClosed uint32
|
|
smcDCurrEstab uint32
|
|
smcDActiveOpened uint32
|
|
smcDPassiveOpened uint32
|
|
smcDConnClosed uint32
|
|
smcDInSegs uint64
|
|
smcDOutSegs uint64
|
|
smcDInRsts uint32
|
|
smcDOutRsts uint32
|
|
}
|
|
|
|
type nwmConnEntry struct {
|
|
ident uint32
|
|
local [28]byte // union of sockaddr4 and sockaddr6
|
|
remote [28]byte // union of sockaddr4 and sockaddr6
|
|
startTime [8]byte // uint64, changed to prevent padding from being inserted
|
|
lastActivity [8]byte // uint64
|
|
bytesIn [8]byte // uint64
|
|
bytesOut [8]byte // uint64
|
|
inSegs [8]byte // uint64
|
|
outSegs [8]byte // uint64
|
|
state uint16
|
|
activeOpen byte
|
|
flag01 byte
|
|
outBuffered uint32
|
|
inBuffered uint32
|
|
maxSndWnd uint32
|
|
reXmtCount uint32
|
|
congestionWnd uint32
|
|
ssThresh uint32
|
|
roundTripTime uint32
|
|
roundTripVar uint32
|
|
sendMSS uint32
|
|
sndWnd uint32
|
|
rcvBufSize uint32
|
|
sndBufSize uint32
|
|
outOfOrderCount uint32
|
|
lcl0WindowCount uint32
|
|
rmt0WindowCount uint32
|
|
dupacks uint32
|
|
flag02 byte
|
|
sockOpt6Cont byte
|
|
asid uint16
|
|
resourceName [8]byte
|
|
resourceId uint32
|
|
subtask uint32
|
|
sockOpt byte
|
|
sockOpt6 byte
|
|
clusterConnFlag byte
|
|
proto byte
|
|
targetAppl [8]byte
|
|
luName [8]byte
|
|
clientUserId [8]byte
|
|
logMode [8]byte
|
|
timeStamp uint32
|
|
timeStampAge uint32
|
|
serverResourceId uint32
|
|
intfName [16]byte
|
|
ttlsStatPol byte
|
|
ttlsStatConn byte
|
|
ttlsSSLProt uint16
|
|
ttlsNegCiph [2]byte
|
|
ttlsSecType byte
|
|
ttlsFIPS140Mode byte
|
|
ttlsUserID [8]byte
|
|
applData [40]byte
|
|
inOldestTime [8]byte // uint64
|
|
outOldestTime [8]byte // uint64
|
|
tcpTrustedPartner byte
|
|
_ [3]byte
|
|
bulkDataIntfName [16]byte
|
|
ttlsNegCiph4 [4]byte
|
|
smcReason uint32
|
|
lclSMCLinkId uint32
|
|
rmtSMCLinkId uint32
|
|
smcStatus byte
|
|
smcFlags byte
|
|
_ [2]byte
|
|
rcvWnd uint32
|
|
lclSMCBufSz uint32
|
|
rmtSMCBufSz uint32
|
|
ttlsSessID [32]byte
|
|
ttlsSessIDLen int16
|
|
_ [1]byte
|
|
smcDStatus byte
|
|
smcDReason uint32
|
|
}
|
|
|
|
var svcNameTable [][]byte = [][]byte{
|
|
[]byte("\xc5\xe9\xc2\xd5\xd4\xc9\xc6\xf4"), // svc_EZBNMIF4
|
|
}
|
|
|
|
const (
|
|
svc_EZBNMIF4 = 0
|
|
)
|
|
|
|
func GetsockoptTCPInfo(fd, level, opt int) (*TCPInfo, error) {
|
|
jobname := []byte("\x5c\x40\x40\x40\x40\x40\x40\x40") // "*"
|
|
responseBuffer := [4096]byte{0}
|
|
var bufferAlet, reasonCode uint32 = 0, 0
|
|
var bufferLen, returnValue, returnCode int32 = 4096, 0, 0
|
|
|
|
dsa := [18]uint64{0}
|
|
var argv [7]unsafe.Pointer
|
|
argv[0] = unsafe.Pointer(&jobname[0])
|
|
argv[1] = unsafe.Pointer(&responseBuffer[0])
|
|
argv[2] = unsafe.Pointer(&bufferAlet)
|
|
argv[3] = unsafe.Pointer(&bufferLen)
|
|
argv[4] = unsafe.Pointer(&returnValue)
|
|
argv[5] = unsafe.Pointer(&returnCode)
|
|
argv[6] = unsafe.Pointer(&reasonCode)
|
|
|
|
request := (*struct {
|
|
header nwmHeader
|
|
filter nwmFilter
|
|
})(unsafe.Pointer(&responseBuffer[0]))
|
|
|
|
EZBNMIF4 := svcLoad(&svcNameTable[svc_EZBNMIF4][0])
|
|
if EZBNMIF4 == nil {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// GetGlobalStats EZBNMIF4 call
|
|
request.header.ident = nwmHeaderIdentifier
|
|
request.header.length = uint32(unsafe.Sizeof(request.header))
|
|
request.header.version = nwmCurrentVer
|
|
request.header.nwmType = nwmGlobalStatsType
|
|
request.header.options = 0x80000000
|
|
|
|
svcCall(EZBNMIF4, &argv[0], &dsa[0])
|
|
|
|
// outputDesc field is filled by EZBNMIF4 on success
|
|
if returnCode != 0 || request.header.outputDesc.offset == 0 {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// Check that EZBNMIF4 returned a nwmRecHeader
|
|
recHeader := (*nwmRecHeader)(unsafe.Pointer(&responseBuffer[request.header.outputDesc.offset]))
|
|
if recHeader.ident != nwmRecHeaderIdentifier {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// Parse nwmTriplets to get offsets of returned entries
|
|
var sections []*uint64
|
|
var sectionDesc *nwmTriplet = (*nwmTriplet)(unsafe.Pointer(&responseBuffer[0]))
|
|
for i := uint32(0); i < uint32(recHeader.number); i++ {
|
|
offset := request.header.outputDesc.offset + uint32(unsafe.Sizeof(*recHeader)) + i*uint32(unsafe.Sizeof(*sectionDesc))
|
|
sectionDesc = (*nwmTriplet)(unsafe.Pointer(&responseBuffer[offset]))
|
|
for j := uint32(0); j < sectionDesc.number; j++ {
|
|
offset = request.header.outputDesc.offset + sectionDesc.offset + j*sectionDesc.length
|
|
sections = append(sections, (*uint64)(unsafe.Pointer(&responseBuffer[offset])))
|
|
}
|
|
}
|
|
|
|
// Find nwmTCPStatsEntry in returned entries
|
|
var tcpStats *nwmTCPStatsEntry = nil
|
|
for _, ptr := range sections {
|
|
switch *ptr {
|
|
case nwmTCPStatsIdentifier:
|
|
if tcpStats != nil {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
tcpStats = (*nwmTCPStatsEntry)(unsafe.Pointer(ptr))
|
|
case nwmIPStatsIdentifier:
|
|
case nwmIPGStatsIdentifier:
|
|
case nwmUDPStatsIdentifier:
|
|
case nwmICMPGStatsEntry:
|
|
case nwmICMPTStatsEntry:
|
|
default:
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
}
|
|
if tcpStats == nil {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// GetConnectionDetail EZBNMIF4 call
|
|
responseBuffer = [4096]byte{0}
|
|
dsa = [18]uint64{0}
|
|
bufferAlet, reasonCode = 0, 0
|
|
bufferLen, returnValue, returnCode = 4096, 0, 0
|
|
nameptr := (*uint32)(unsafe.Pointer(uintptr(0x21c))) // Get jobname of current process
|
|
nameptr = (*uint32)(unsafe.Pointer(uintptr(*nameptr + 12)))
|
|
argv[0] = unsafe.Pointer(uintptr(*nameptr))
|
|
|
|
request.header.ident = nwmHeaderIdentifier
|
|
request.header.length = uint32(unsafe.Sizeof(request.header))
|
|
request.header.version = nwmCurrentVer
|
|
request.header.nwmType = nwmTCPConnType
|
|
request.header.options = 0x80000000
|
|
|
|
request.filter.ident = nwmFilterIdentifier
|
|
|
|
var localSockaddr RawSockaddrAny
|
|
socklen := _Socklen(SizeofSockaddrAny)
|
|
err := getsockname(fd, &localSockaddr, &socklen)
|
|
if err != nil {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
if localSockaddr.Addr.Family == AF_INET {
|
|
localSockaddr := (*RawSockaddrInet4)(unsafe.Pointer(&localSockaddr.Addr))
|
|
localSockFilter := (*RawSockaddrInet4)(unsafe.Pointer(&request.filter.local[0]))
|
|
localSockFilter.Family = AF_INET
|
|
var i int
|
|
for i = 0; i < 4; i++ {
|
|
if localSockaddr.Addr[i] != 0 {
|
|
break
|
|
}
|
|
}
|
|
if i != 4 {
|
|
request.filter.flags |= nwmFilterLclAddrMask
|
|
for i = 0; i < 4; i++ {
|
|
localSockFilter.Addr[i] = localSockaddr.Addr[i]
|
|
}
|
|
}
|
|
if localSockaddr.Port != 0 {
|
|
request.filter.flags |= nwmFilterLclPortMask
|
|
localSockFilter.Port = localSockaddr.Port
|
|
}
|
|
} else if localSockaddr.Addr.Family == AF_INET6 {
|
|
localSockaddr := (*RawSockaddrInet6)(unsafe.Pointer(&localSockaddr.Addr))
|
|
localSockFilter := (*RawSockaddrInet6)(unsafe.Pointer(&request.filter.local[0]))
|
|
localSockFilter.Family = AF_INET6
|
|
var i int
|
|
for i = 0; i < 16; i++ {
|
|
if localSockaddr.Addr[i] != 0 {
|
|
break
|
|
}
|
|
}
|
|
if i != 16 {
|
|
request.filter.flags |= nwmFilterLclAddrMask
|
|
for i = 0; i < 16; i++ {
|
|
localSockFilter.Addr[i] = localSockaddr.Addr[i]
|
|
}
|
|
}
|
|
if localSockaddr.Port != 0 {
|
|
request.filter.flags |= nwmFilterLclPortMask
|
|
localSockFilter.Port = localSockaddr.Port
|
|
}
|
|
}
|
|
|
|
svcCall(EZBNMIF4, &argv[0], &dsa[0])
|
|
|
|
// outputDesc field is filled by EZBNMIF4 on success
|
|
if returnCode != 0 || request.header.outputDesc.offset == 0 {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// Check that EZBNMIF4 returned a nwmConnEntry
|
|
conn := (*nwmConnEntry)(unsafe.Pointer(&responseBuffer[request.header.outputDesc.offset]))
|
|
if conn.ident != nwmTCPConnIdentifier {
|
|
return nil, errnoErr(EINVAL)
|
|
}
|
|
|
|
// Copy data from the returned data structures into tcpInfo
|
|
// Stats from nwmConnEntry are specific to that connection.
|
|
// Stats from nwmTCPStatsEntry are global (to the interface?)
|
|
// Fields may not be an exact match. Some fields have no equivalent.
|
|
var tcpinfo TCPInfo
|
|
tcpinfo.State = uint8(conn.state)
|
|
tcpinfo.Ca_state = 0 // dummy
|
|
tcpinfo.Retransmits = uint8(tcpStats.retransSegs)
|
|
tcpinfo.Probes = uint8(tcpStats.outWinProbes)
|
|
tcpinfo.Backoff = 0 // dummy
|
|
tcpinfo.Options = 0 // dummy
|
|
tcpinfo.Rto = tcpStats.retransTimeouts
|
|
tcpinfo.Ato = tcpStats.outDelayAcks
|
|
tcpinfo.Snd_mss = conn.sendMSS
|
|
tcpinfo.Rcv_mss = conn.sendMSS // dummy
|
|
tcpinfo.Unacked = 0 // dummy
|
|
tcpinfo.Sacked = 0 // dummy
|
|
tcpinfo.Lost = 0 // dummy
|
|
tcpinfo.Retrans = conn.reXmtCount
|
|
tcpinfo.Fackets = 0 // dummy
|
|
tcpinfo.Last_data_sent = uint32(*(*uint64)(unsafe.Pointer(&conn.lastActivity[0])))
|
|
tcpinfo.Last_ack_sent = uint32(*(*uint64)(unsafe.Pointer(&conn.outOldestTime[0])))
|
|
tcpinfo.Last_data_recv = uint32(*(*uint64)(unsafe.Pointer(&conn.inOldestTime[0])))
|
|
tcpinfo.Last_ack_recv = uint32(*(*uint64)(unsafe.Pointer(&conn.inOldestTime[0])))
|
|
tcpinfo.Pmtu = conn.sendMSS // dummy, NWMIfRouteMtu is a candidate
|
|
tcpinfo.Rcv_ssthresh = conn.ssThresh
|
|
tcpinfo.Rtt = conn.roundTripTime
|
|
tcpinfo.Rttvar = conn.roundTripVar
|
|
tcpinfo.Snd_ssthresh = conn.ssThresh // dummy
|
|
tcpinfo.Snd_cwnd = conn.congestionWnd
|
|
tcpinfo.Advmss = conn.sendMSS // dummy
|
|
tcpinfo.Reordering = 0 // dummy
|
|
tcpinfo.Rcv_rtt = conn.roundTripTime // dummy
|
|
tcpinfo.Rcv_space = conn.sendMSS // dummy
|
|
tcpinfo.Total_retrans = conn.reXmtCount
|
|
|
|
svcUnload(&svcNameTable[svc_EZBNMIF4][0], EZBNMIF4)
|
|
|
|
return &tcpinfo, nil
|
|
}
|
|
|
|
// GetsockoptString returns the string value of the socket option opt for the
|
|
// socket associated with fd at the given socket level.
|
|
func GetsockoptString(fd, level, opt int) (string, error) {
|
|
buf := make([]byte, 256)
|
|
vallen := _Socklen(len(buf))
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return string(buf[:vallen-1]), nil
|
|
}
|
|
|
|
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
|
|
var msg Msghdr
|
|
var rsa RawSockaddrAny
|
|
msg.Name = (*byte)(unsafe.Pointer(&rsa))
|
|
msg.Namelen = SizeofSockaddrAny
|
|
var iov Iovec
|
|
if len(p) > 0 {
|
|
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
|
|
iov.SetLen(len(p))
|
|
}
|
|
var dummy byte
|
|
if len(oob) > 0 {
|
|
// receive at least one normal byte
|
|
if len(p) == 0 {
|
|
iov.Base = &dummy
|
|
iov.SetLen(1)
|
|
}
|
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
|
msg.SetControllen(len(oob))
|
|
}
|
|
msg.Iov = &iov
|
|
msg.Iovlen = 1
|
|
if n, err = recvmsg(fd, &msg, flags); err != nil {
|
|
return
|
|
}
|
|
oobn = int(msg.Controllen)
|
|
recvflags = int(msg.Flags)
|
|
// source address is only specified if the socket is unconnected
|
|
if rsa.Addr.Family != AF_UNSPEC {
|
|
// TODO(neeilan): Remove 0 arg added to get this compiling on z/OS
|
|
from, err = anyToSockaddr(0, &rsa)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
|
|
_, err = SendmsgN(fd, p, oob, to, flags)
|
|
return
|
|
}
|
|
|
|
func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
|
|
var ptr unsafe.Pointer
|
|
var salen _Socklen
|
|
if to != nil {
|
|
var err error
|
|
ptr, salen, err = to.sockaddr()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
}
|
|
var msg Msghdr
|
|
msg.Name = (*byte)(unsafe.Pointer(ptr))
|
|
msg.Namelen = int32(salen)
|
|
var iov Iovec
|
|
if len(p) > 0 {
|
|
iov.Base = (*byte)(unsafe.Pointer(&p[0]))
|
|
iov.SetLen(len(p))
|
|
}
|
|
var dummy byte
|
|
if len(oob) > 0 {
|
|
// send at least one normal byte
|
|
if len(p) == 0 {
|
|
iov.Base = &dummy
|
|
iov.SetLen(1)
|
|
}
|
|
msg.Control = (*byte)(unsafe.Pointer(&oob[0]))
|
|
msg.SetControllen(len(oob))
|
|
}
|
|
msg.Iov = &iov
|
|
msg.Iovlen = 1
|
|
if n, err = sendmsg(fd, &msg, flags); err != nil {
|
|
return 0, err
|
|
}
|
|
if len(oob) > 0 && len(p) == 0 {
|
|
n = 0
|
|
}
|
|
return n, nil
|
|
}
|
|
|
|
func Opendir(name string) (uintptr, error) {
|
|
p, err := BytePtrFromString(name)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
dir, _, e := syscall_syscall(SYS___OPENDIR_A, uintptr(unsafe.Pointer(p)), 0, 0)
|
|
runtime.KeepAlive(unsafe.Pointer(p))
|
|
if e != 0 {
|
|
err = errnoErr(e)
|
|
}
|
|
return dir, err
|
|
}
|
|
|
|
// clearsyscall.Errno resets the errno value to 0.
|
|
func clearErrno()
|
|
|
|
func Readdir(dir uintptr) (*Dirent, error) {
|
|
var ent Dirent
|
|
var res uintptr
|
|
// __readdir_r_a returns errno at the end of the directory stream, rather than 0.
|
|
// Therefore to avoid false positives we clear errno before calling it.
|
|
|
|
// TODO(neeilan): Commented this out to get sys/unix compiling on z/OS. Uncomment and fix. Error: "undefined: clearsyscall"
|
|
//clearsyscall.Errno() // TODO(mundaym): check pre-emption rules.
|
|
|
|
e, _, _ := syscall_syscall(SYS___READDIR_R_A, dir, uintptr(unsafe.Pointer(&ent)), uintptr(unsafe.Pointer(&res)))
|
|
var err error
|
|
if e != 0 {
|
|
err = errnoErr(Errno(e))
|
|
}
|
|
if res == 0 {
|
|
return nil, err
|
|
}
|
|
return &ent, err
|
|
}
|
|
|
|
func readdir_r(dirp uintptr, entry *direntLE, result **direntLE) (err error) {
|
|
r0, _, e1 := syscall_syscall(SYS___READDIR_R_A, dirp, uintptr(unsafe.Pointer(entry)), uintptr(unsafe.Pointer(result)))
|
|
if int64(r0) == -1 {
|
|
err = errnoErr(Errno(e1))
|
|
}
|
|
return
|
|
}
|
|
|
|
func Closedir(dir uintptr) error {
|
|
_, _, e := syscall_syscall(SYS_CLOSEDIR, dir, 0, 0)
|
|
if e != 0 {
|
|
return errnoErr(e)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Seekdir(dir uintptr, pos int) {
|
|
_, _, _ = syscall_syscall(SYS_SEEKDIR, dir, uintptr(pos), 0)
|
|
}
|
|
|
|
func Telldir(dir uintptr) (int, error) {
|
|
p, _, e := syscall_syscall(SYS_TELLDIR, dir, 0, 0)
|
|
pos := int(p)
|
|
if pos == -1 {
|
|
return pos, errnoErr(e)
|
|
}
|
|
return pos, nil
|
|
}
|
|
|
|
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
|
func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
|
|
// struct flock is packed on z/OS. We can't emulate that in Go so
|
|
// instead we pack it here.
|
|
var flock [24]byte
|
|
*(*int16)(unsafe.Pointer(&flock[0])) = lk.Type
|
|
*(*int16)(unsafe.Pointer(&flock[2])) = lk.Whence
|
|
*(*int64)(unsafe.Pointer(&flock[4])) = lk.Start
|
|
*(*int64)(unsafe.Pointer(&flock[12])) = lk.Len
|
|
*(*int32)(unsafe.Pointer(&flock[20])) = lk.Pid
|
|
_, _, errno := syscall_syscall(SYS_FCNTL, fd, uintptr(cmd), uintptr(unsafe.Pointer(&flock)))
|
|
lk.Type = *(*int16)(unsafe.Pointer(&flock[0]))
|
|
lk.Whence = *(*int16)(unsafe.Pointer(&flock[2]))
|
|
lk.Start = *(*int64)(unsafe.Pointer(&flock[4]))
|
|
lk.Len = *(*int64)(unsafe.Pointer(&flock[12]))
|
|
lk.Pid = *(*int32)(unsafe.Pointer(&flock[20]))
|
|
if errno == 0 {
|
|
return nil
|
|
}
|
|
return errno
|
|
}
|
|
|
|
func Flock(fd int, how int) error {
|
|
|
|
var flock_type int16
|
|
var fcntl_cmd int
|
|
|
|
switch how {
|
|
case LOCK_SH | LOCK_NB:
|
|
flock_type = F_RDLCK
|
|
fcntl_cmd = F_SETLK
|
|
case LOCK_EX | LOCK_NB:
|
|
flock_type = F_WRLCK
|
|
fcntl_cmd = F_SETLK
|
|
case LOCK_EX:
|
|
flock_type = F_WRLCK
|
|
fcntl_cmd = F_SETLKW
|
|
case LOCK_UN:
|
|
flock_type = F_UNLCK
|
|
fcntl_cmd = F_SETLKW
|
|
default:
|
|
}
|
|
|
|
flock := Flock_t{
|
|
Type: int16(flock_type),
|
|
Whence: int16(0),
|
|
Start: int64(0),
|
|
Len: int64(0),
|
|
Pid: int32(Getppid()),
|
|
}
|
|
|
|
err := FcntlFlock(uintptr(fd), fcntl_cmd, &flock)
|
|
return err
|
|
}
|
|
|
|
func Mlock(b []byte) (err error) {
|
|
_, _, e1 := syscall_syscall(SYS___MLOCKALL, _BPX_NONSWAP, 0, 0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Mlock2(b []byte, flags int) (err error) {
|
|
_, _, e1 := syscall_syscall(SYS___MLOCKALL, _BPX_NONSWAP, 0, 0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Mlockall(flags int) (err error) {
|
|
_, _, e1 := syscall_syscall(SYS___MLOCKALL, _BPX_NONSWAP, 0, 0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Munlock(b []byte) (err error) {
|
|
_, _, e1 := syscall_syscall(SYS___MLOCKALL, _BPX_SWAP, 0, 0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Munlockall() (err error) {
|
|
_, _, e1 := syscall_syscall(SYS___MLOCKALL, _BPX_SWAP, 0, 0)
|
|
if e1 != 0 {
|
|
err = errnoErr(e1)
|
|
}
|
|
return
|
|
}
|
|
|
|
func ClockGettime(clockid int32, ts *Timespec) error {
|
|
|
|
var ticks_per_sec uint32 = 100 //TODO(kenan): value is currently hardcoded; need sysconf() call otherwise
|
|
var nsec_per_sec int64 = 1000000000
|
|
|
|
if ts == nil {
|
|
return EFAULT
|
|
}
|
|
if clockid == CLOCK_REALTIME || clockid == CLOCK_MONOTONIC {
|
|
var nanotime int64 = runtime.Nanotime1()
|
|
ts.Sec = nanotime / nsec_per_sec
|
|
ts.Nsec = nanotime % nsec_per_sec
|
|
} else if clockid == CLOCK_PROCESS_CPUTIME_ID || clockid == CLOCK_THREAD_CPUTIME_ID {
|
|
var tm Tms
|
|
_, err := Times(&tm)
|
|
if err != nil {
|
|
return EFAULT
|
|
}
|
|
ts.Sec = int64(tm.Utime / ticks_per_sec)
|
|
ts.Nsec = int64(tm.Utime) * nsec_per_sec / int64(ticks_per_sec)
|
|
} else {
|
|
return EINVAL
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Statfs(path string, stat *Statfs_t) (err error) {
|
|
fd, err := open(path, O_RDONLY, 0)
|
|
defer Close(fd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return Fstatfs(fd, stat)
|
|
}
|
|
|
|
var (
|
|
Stdin = 0
|
|
Stdout = 1
|
|
Stderr = 2
|
|
)
|
|
|
|
// Do the interface allocations only once for common
|
|
// Errno values.
|
|
var (
|
|
errEAGAIN error = syscall.EAGAIN
|
|
errEINVAL error = syscall.EINVAL
|
|
errENOENT error = syscall.ENOENT
|
|
)
|
|
|
|
var (
|
|
signalNameMapOnce sync.Once
|
|
signalNameMap map[string]syscall.Signal
|
|
)
|
|
|
|
// errnoErr returns common boxed Errno values, to prevent
|
|
// allocations at runtime.
|
|
func errnoErr(e Errno) error {
|
|
switch e {
|
|
case 0:
|
|
return nil
|
|
case EAGAIN:
|
|
return errEAGAIN
|
|
case EINVAL:
|
|
return errEINVAL
|
|
case ENOENT:
|
|
return errENOENT
|
|
}
|
|
return e
|
|
}
|
|
|
|
// ErrnoName returns the error name for error number e.
|
|
func ErrnoName(e Errno) string {
|
|
i := sort.Search(len(errorList), func(i int) bool {
|
|
return errorList[i].num >= e
|
|
})
|
|
if i < len(errorList) && errorList[i].num == e {
|
|
return errorList[i].name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// SignalName returns the signal name for signal number s.
|
|
func SignalName(s syscall.Signal) string {
|
|
i := sort.Search(len(signalList), func(i int) bool {
|
|
return signalList[i].num >= s
|
|
})
|
|
if i < len(signalList) && signalList[i].num == s {
|
|
return signalList[i].name
|
|
}
|
|
return ""
|
|
}
|
|
|
|
// SignalNum returns the syscall.Signal for signal named s,
|
|
// or 0 if a signal with such name is not found.
|
|
// The signal name should start with "SIG".
|
|
func SignalNum(s string) syscall.Signal {
|
|
signalNameMapOnce.Do(func() {
|
|
signalNameMap = make(map[string]syscall.Signal, len(signalList))
|
|
for _, signal := range signalList {
|
|
signalNameMap[signal.name] = signal.num
|
|
}
|
|
})
|
|
return signalNameMap[s]
|
|
}
|
|
|
|
// clen returns the index of the first NULL byte in n or len(n) if n contains no NULL byte.
|
|
func clen(n []byte) int {
|
|
i := bytes.IndexByte(n, 0)
|
|
if i == -1 {
|
|
i = len(n)
|
|
}
|
|
return i
|
|
}
|
|
|
|
// Mmap manager, for use by operating system-specific implementations.
|
|
|
|
type mmapper struct {
|
|
sync.Mutex
|
|
active map[*byte][]byte // active mappings; key is last byte in mapping
|
|
mmap func(addr, length uintptr, prot, flags, fd int, offset int64) (uintptr, error)
|
|
munmap func(addr uintptr, length uintptr) error
|
|
}
|
|
|
|
func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
|
|
if length <= 0 {
|
|
return nil, EINVAL
|
|
}
|
|
|
|
// Map the requested memory.
|
|
addr, errno := m.mmap(0, uintptr(length), prot, flags, fd, offset)
|
|
if errno != nil {
|
|
return nil, errno
|
|
}
|
|
|
|
// Slice memory layout
|
|
var sl = struct {
|
|
addr uintptr
|
|
len int
|
|
cap int
|
|
}{addr, length, length}
|
|
|
|
// Use unsafe to turn sl into a []byte.
|
|
b := *(*[]byte)(unsafe.Pointer(&sl))
|
|
|
|
// Register mapping in m and return it.
|
|
p := &b[cap(b)-1]
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
m.active[p] = b
|
|
return b, nil
|
|
}
|
|
|
|
func (m *mmapper) Munmap(data []byte) (err error) {
|
|
if len(data) == 0 || len(data) != cap(data) {
|
|
return EINVAL
|
|
}
|
|
|
|
// Find the base of the mapping.
|
|
p := &data[cap(data)-1]
|
|
m.Lock()
|
|
defer m.Unlock()
|
|
b := m.active[p]
|
|
if b == nil || &b[0] != &data[0] {
|
|
return EINVAL
|
|
}
|
|
|
|
// Unmap the memory and update m.
|
|
if errno := m.munmap(uintptr(unsafe.Pointer(&b[0])), uintptr(len(b))); errno != nil {
|
|
return errno
|
|
}
|
|
delete(m.active, p)
|
|
return nil
|
|
}
|
|
|
|
func Read(fd int, p []byte) (n int, err error) {
|
|
n, err = read(fd, p)
|
|
if raceenabled {
|
|
if n > 0 {
|
|
raceWriteRange(unsafe.Pointer(&p[0]), n)
|
|
}
|
|
if err == nil {
|
|
raceAcquire(unsafe.Pointer(&ioSync))
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func Write(fd int, p []byte) (n int, err error) {
|
|
if raceenabled {
|
|
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
}
|
|
n, err = write(fd, p)
|
|
if raceenabled && n > 0 {
|
|
raceReadRange(unsafe.Pointer(&p[0]), n)
|
|
}
|
|
return
|
|
}
|
|
|
|
// For testing: clients can set this flag to force
|
|
// creation of IPv6 sockets to return EAFNOSUPPORT.
|
|
var SocketDisableIPv6 bool
|
|
|
|
// Sockaddr represents a socket address.
|
|
type Sockaddr interface {
|
|
sockaddr() (ptr unsafe.Pointer, len _Socklen, err error) // lowercase; only we can define Sockaddrs
|
|
}
|
|
|
|
// SockaddrInet4 implements the Sockaddr interface for AF_INET type sockets.
|
|
type SockaddrInet4 struct {
|
|
Port int
|
|
Addr [4]byte
|
|
raw RawSockaddrInet4
|
|
}
|
|
|
|
// SockaddrInet6 implements the Sockaddr interface for AF_INET6 type sockets.
|
|
type SockaddrInet6 struct {
|
|
Port int
|
|
ZoneId uint32
|
|
Addr [16]byte
|
|
raw RawSockaddrInet6
|
|
}
|
|
|
|
// SockaddrUnix implements the Sockaddr interface for AF_UNIX type sockets.
|
|
type SockaddrUnix struct {
|
|
Name string
|
|
raw RawSockaddrUnix
|
|
}
|
|
|
|
func Bind(fd int, sa Sockaddr) (err error) {
|
|
ptr, n, err := sa.sockaddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return bind(fd, ptr, n)
|
|
}
|
|
|
|
func Connect(fd int, sa Sockaddr) (err error) {
|
|
ptr, n, err := sa.sockaddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return connect(fd, ptr, n)
|
|
}
|
|
|
|
func Getpeername(fd int) (sa Sockaddr, err error) {
|
|
var rsa RawSockaddrAny
|
|
var len _Socklen = SizeofSockaddrAny
|
|
if err = getpeername(fd, &rsa, &len); err != nil {
|
|
return
|
|
}
|
|
return anyToSockaddr(fd, &rsa)
|
|
}
|
|
|
|
func GetsockoptByte(fd, level, opt int) (value byte, err error) {
|
|
var n byte
|
|
vallen := _Socklen(1)
|
|
err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
|
|
return n, err
|
|
}
|
|
|
|
func GetsockoptInt(fd, level, opt int) (value int, err error) {
|
|
var n int32
|
|
vallen := _Socklen(4)
|
|
err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
|
|
return int(n), err
|
|
}
|
|
|
|
func GetsockoptInet4Addr(fd, level, opt int) (value [4]byte, err error) {
|
|
vallen := _Socklen(4)
|
|
err = getsockopt(fd, level, opt, unsafe.Pointer(&value[0]), &vallen)
|
|
return value, err
|
|
}
|
|
|
|
func GetsockoptIPMreq(fd, level, opt int) (*IPMreq, error) {
|
|
var value IPMreq
|
|
vallen := _Socklen(SizeofIPMreq)
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
return &value, err
|
|
}
|
|
|
|
func GetsockoptIPv6Mreq(fd, level, opt int) (*IPv6Mreq, error) {
|
|
var value IPv6Mreq
|
|
vallen := _Socklen(SizeofIPv6Mreq)
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
return &value, err
|
|
}
|
|
|
|
func GetsockoptIPv6MTUInfo(fd, level, opt int) (*IPv6MTUInfo, error) {
|
|
var value IPv6MTUInfo
|
|
vallen := _Socklen(SizeofIPv6MTUInfo)
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
return &value, err
|
|
}
|
|
|
|
func GetsockoptICMPv6Filter(fd, level, opt int) (*ICMPv6Filter, error) {
|
|
var value ICMPv6Filter
|
|
vallen := _Socklen(SizeofICMPv6Filter)
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
return &value, err
|
|
}
|
|
|
|
func GetsockoptLinger(fd, level, opt int) (*Linger, error) {
|
|
var linger Linger
|
|
vallen := _Socklen(SizeofLinger)
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&linger), &vallen)
|
|
return &linger, err
|
|
}
|
|
|
|
func GetsockoptTimeval(fd, level, opt int) (*Timeval, error) {
|
|
var tv Timeval
|
|
vallen := _Socklen(unsafe.Sizeof(tv))
|
|
err := getsockopt(fd, level, opt, unsafe.Pointer(&tv), &vallen)
|
|
return &tv, err
|
|
}
|
|
|
|
func GetsockoptUint64(fd, level, opt int) (value uint64, err error) {
|
|
var n uint64
|
|
vallen := _Socklen(8)
|
|
err = getsockopt(fd, level, opt, unsafe.Pointer(&n), &vallen)
|
|
return n, err
|
|
}
|
|
|
|
func Recvfrom(fd int, p []byte, flags int) (n int, from Sockaddr, err error) {
|
|
var rsa RawSockaddrAny
|
|
var len _Socklen = SizeofSockaddrAny
|
|
if n, err = recvfrom(fd, p, flags, &rsa, &len); err != nil {
|
|
return
|
|
}
|
|
if rsa.Addr.Family != AF_UNSPEC {
|
|
from, err = anyToSockaddr(fd, &rsa)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Sendto(fd int, p []byte, flags int, to Sockaddr) (err error) {
|
|
ptr, n, err := to.sockaddr()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return sendto(fd, p, flags, ptr, n)
|
|
}
|
|
|
|
func SetsockoptByte(fd, level, opt int, value byte) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(&value), 1)
|
|
}
|
|
|
|
func SetsockoptInt(fd, level, opt int, value int) (err error) {
|
|
var n = int32(value)
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(&n), 4)
|
|
}
|
|
|
|
func SetsockoptInet4Addr(fd, level, opt int, value [4]byte) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(&value[0]), 4)
|
|
}
|
|
|
|
func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPMreq)
|
|
}
|
|
|
|
func SetsockoptIPv6Mreq(fd, level, opt int, mreq *IPv6Mreq) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), SizeofIPv6Mreq)
|
|
}
|
|
|
|
func SetsockoptICMPv6Filter(fd, level, opt int, filter *ICMPv6Filter) error {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(filter), SizeofICMPv6Filter)
|
|
}
|
|
|
|
func SetsockoptLinger(fd, level, opt int, l *Linger) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(l), SizeofLinger)
|
|
}
|
|
|
|
func SetsockoptString(fd, level, opt int, s string) (err error) {
|
|
var p unsafe.Pointer
|
|
if len(s) > 0 {
|
|
p = unsafe.Pointer(&[]byte(s)[0])
|
|
}
|
|
return setsockopt(fd, level, opt, p, uintptr(len(s)))
|
|
}
|
|
|
|
func SetsockoptTimeval(fd, level, opt int, tv *Timeval) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(tv), unsafe.Sizeof(*tv))
|
|
}
|
|
|
|
func SetsockoptUint64(fd, level, opt int, value uint64) (err error) {
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(&value), 8)
|
|
}
|
|
|
|
func Socket(domain, typ, proto int) (fd int, err error) {
|
|
if domain == AF_INET6 && SocketDisableIPv6 {
|
|
return -1, EAFNOSUPPORT
|
|
}
|
|
fd, err = socket(domain, typ, proto)
|
|
return
|
|
}
|
|
|
|
func Socketpair(domain, typ, proto int) (fd [2]int, err error) {
|
|
var fdx [2]int32
|
|
err = socketpair(domain, typ, proto, &fdx)
|
|
if err == nil {
|
|
fd[0] = int(fdx[0])
|
|
fd[1] = int(fdx[1])
|
|
}
|
|
return
|
|
}
|
|
|
|
var ioSync int64
|
|
|
|
func CloseOnExec(fd int) { fcntl(fd, F_SETFD, FD_CLOEXEC) }
|
|
|
|
func SetNonblock(fd int, nonblocking bool) (err error) {
|
|
flag, err := fcntl(fd, F_GETFL, 0)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if nonblocking {
|
|
flag |= O_NONBLOCK
|
|
} else {
|
|
flag &= ^O_NONBLOCK
|
|
}
|
|
_, err = fcntl(fd, F_SETFL, flag)
|
|
return err
|
|
}
|
|
|
|
// Exec calls execve(2), which replaces the calling executable in the process
|
|
// tree. argv0 should be the full path to an executable ("/bin/ls") and the
|
|
// executable name should also be the first argument in argv (["ls", "-l"]).
|
|
// envv are the environment variables that should be passed to the new
|
|
// process (["USER=go", "PWD=/tmp"]).
|
|
func Exec(argv0 string, argv []string, envv []string) error {
|
|
return syscall.Exec(argv0, argv, envv)
|
|
}
|
|
|
|
func Mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
|
|
if needspace := 8 - len(fstype); needspace <= 0 {
|
|
fstype = fstype[:8]
|
|
} else {
|
|
fstype += " "[:needspace]
|
|
}
|
|
return mount_LE(target, source, fstype, uint32(flags), int32(len(data)), data)
|
|
}
|
|
|
|
func Unmount(name string, mtm int) (err error) {
|
|
// mountpoint is always a full path and starts with a '/'
|
|
// check if input string is not a mountpoint but a filesystem name
|
|
if name[0] != '/' {
|
|
return unmount(name, mtm)
|
|
}
|
|
// treat name as mountpoint
|
|
b2s := func(arr []byte) string {
|
|
nulli := bytes.IndexByte(arr, 0)
|
|
if nulli == -1 {
|
|
return string(arr)
|
|
} else {
|
|
return string(arr[:nulli])
|
|
}
|
|
}
|
|
var buffer struct {
|
|
header W_Mnth
|
|
fsinfo [64]W_Mntent
|
|
}
|
|
fsCount, err := W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer)))
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if fsCount == 0 {
|
|
return EINVAL
|
|
}
|
|
for i := 0; i < fsCount; i++ {
|
|
if b2s(buffer.fsinfo[i].Mountpoint[:]) == name {
|
|
err = unmount(b2s(buffer.fsinfo[i].Fsname[:]), mtm)
|
|
break
|
|
}
|
|
}
|
|
return err
|
|
}
|
|
|
|
func fdToPath(dirfd int) (path string, err error) {
|
|
var buffer [1024]byte
|
|
// w_ctrl()
|
|
ret := runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_W_IOCTL<<4,
|
|
[]uintptr{uintptr(dirfd), 17, 1024, uintptr(unsafe.Pointer(&buffer[0]))})
|
|
if ret == 0 {
|
|
zb := bytes.IndexByte(buffer[:], 0)
|
|
if zb == -1 {
|
|
zb = len(buffer)
|
|
}
|
|
// __e2a_l()
|
|
runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4,
|
|
[]uintptr{uintptr(unsafe.Pointer(&buffer[0])), uintptr(zb)})
|
|
return string(buffer[:zb]), nil
|
|
}
|
|
// __errno()
|
|
errno := int(*(*int32)(unsafe.Pointer(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO<<4,
|
|
[]uintptr{}))))
|
|
// __errno2()
|
|
errno2 := int(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO2<<4,
|
|
[]uintptr{}))
|
|
// strerror_r()
|
|
ret = runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS_STRERROR_R<<4,
|
|
[]uintptr{uintptr(errno), uintptr(unsafe.Pointer(&buffer[0])), 1024})
|
|
if ret == 0 {
|
|
zb := bytes.IndexByte(buffer[:], 0)
|
|
if zb == -1 {
|
|
zb = len(buffer)
|
|
}
|
|
return "", fmt.Errorf("%s (errno2=0x%x)", buffer[:zb], errno2)
|
|
} else {
|
|
return "", fmt.Errorf("fdToPath errno %d (errno2=0x%x)", errno, errno2)
|
|
}
|
|
}
|
|
|
|
func direntLeToDirentUnix(dirent *direntLE, dir uintptr, path string) (Dirent, error) {
|
|
var d Dirent
|
|
|
|
d.Ino = uint64(dirent.Ino)
|
|
offset, err := Telldir(dir)
|
|
if err != nil {
|
|
return d, err
|
|
}
|
|
|
|
d.Off = int64(offset)
|
|
s := string(bytes.Split(dirent.Name[:], []byte{0})[0])
|
|
copy(d.Name[:], s)
|
|
|
|
d.Reclen = uint16(24 + len(d.NameString()))
|
|
var st Stat_t
|
|
path = path + "/" + s
|
|
err = Lstat(path, &st)
|
|
if err != nil {
|
|
return d, err
|
|
}
|
|
|
|
d.Type = uint8(st.Mode >> 24)
|
|
return d, err
|
|
}
|
|
|
|
func Getdirentries(fd int, buf []byte, basep *uintptr) (n int, err error) {
|
|
// Simulation of Getdirentries port from the Darwin implementation.
|
|
// COMMENTS FROM DARWIN:
|
|
// It's not the full required semantics, but should handle the case
|
|
// of calling Getdirentries or ReadDirent repeatedly.
|
|
// It won't handle assigning the results of lseek to *basep, or handle
|
|
// the directory being edited underfoot.
|
|
|
|
skip, err := Seek(fd, 0, 1 /* SEEK_CUR */)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
// Get path from fd to avoid unavailable call (fdopendir)
|
|
path, err := fdToPath(fd)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
d, err := Opendir(path)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
defer Closedir(d)
|
|
|
|
var cnt int64
|
|
for {
|
|
var entryLE direntLE
|
|
var entrypLE *direntLE
|
|
e := readdir_r(d, &entryLE, &entrypLE)
|
|
if e != nil {
|
|
return n, e
|
|
}
|
|
if entrypLE == nil {
|
|
break
|
|
}
|
|
if skip > 0 {
|
|
skip--
|
|
cnt++
|
|
continue
|
|
}
|
|
|
|
// Dirent on zos has a different structure
|
|
entry, e := direntLeToDirentUnix(&entryLE, d, path)
|
|
if e != nil {
|
|
return n, e
|
|
}
|
|
|
|
reclen := int(entry.Reclen)
|
|
if reclen > len(buf) {
|
|
// Not enough room. Return for now.
|
|
// The counter will let us know where we should start up again.
|
|
// Note: this strategy for suspending in the middle and
|
|
// restarting is O(n^2) in the length of the directory. Oh well.
|
|
break
|
|
}
|
|
|
|
// Copy entry into return buffer.
|
|
s := unsafe.Slice((*byte)(unsafe.Pointer(&entry)), reclen)
|
|
copy(buf, s)
|
|
|
|
buf = buf[reclen:]
|
|
n += reclen
|
|
cnt++
|
|
}
|
|
// Set the seek offset of the input fd to record
|
|
// how many files we've already returned.
|
|
_, err = Seek(fd, cnt, 0 /* SEEK_SET */)
|
|
if err != nil {
|
|
return n, err
|
|
}
|
|
|
|
return n, nil
|
|
}
|
|
|
|
func ReadDirent(fd int, buf []byte) (n int, err error) {
|
|
var base = (*uintptr)(unsafe.Pointer(new(uint64)))
|
|
return Getdirentries(fd, buf, base)
|
|
}
|
|
|
|
func direntIno(buf []byte) (uint64, bool) {
|
|
return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
|
|
}
|
|
|
|
func direntReclen(buf []byte) (uint64, bool) {
|
|
return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
|
|
}
|
|
|
|
func direntNamlen(buf []byte) (uint64, bool) {
|
|
reclen, ok := direntReclen(buf)
|
|
if !ok {
|
|
return 0, false
|
|
}
|
|
return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
|
|
}
|