зеркало из https://github.com/golang/sys.git
3214 строки
87 KiB
Go
3214 строки
87 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
|
|
|
|
// Many of the following syscalls are not available on all versions of z/OS.
|
|
// Some missing calls have legacy implementations/simulations but others
|
|
// will be missing completely. To achieve consistent failing behaviour on
|
|
// legacy systems, we first test the function pointer via a safeloading
|
|
// mechanism to see if the function exists on a given system. Then execution
|
|
// is branched to either continue the function call, or return an error.
|
|
|
|
package unix
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"os"
|
|
"reflect"
|
|
"regexp"
|
|
"runtime"
|
|
"sort"
|
|
"strings"
|
|
"sync"
|
|
"syscall"
|
|
"unsafe"
|
|
)
|
|
|
|
//go:noescape
|
|
func initZosLibVec()
|
|
|
|
//go:noescape
|
|
func GetZosLibVec() uintptr
|
|
|
|
func init() {
|
|
initZosLibVec()
|
|
r0, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS_____GETENV_A<<4, uintptr(unsafe.Pointer(&([]byte("__ZOS_XSYSTRACE\x00"))[0])))
|
|
if r0 != 0 {
|
|
n, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___ATOI_A<<4, r0)
|
|
ZosTraceLevel = int(n)
|
|
r0, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS_____GETENV_A<<4, uintptr(unsafe.Pointer(&([]byte("__ZOS_XSYSTRACEFD\x00"))[0])))
|
|
if r0 != 0 {
|
|
fd, _, _ := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___ATOI_A<<4, r0)
|
|
f := os.NewFile(fd, "zostracefile")
|
|
if f != nil {
|
|
ZosTracefile = f
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
//go:noescape
|
|
func CallLeFuncWithErr(funcdesc uintptr, parms ...uintptr) (ret, errno2 uintptr, err Errno)
|
|
|
|
//go:noescape
|
|
func CallLeFuncWithPtrReturn(funcdesc uintptr, parms ...uintptr) (ret, errno2 uintptr, err Errno)
|
|
|
|
// -------------------------------
|
|
// pointer validity test
|
|
// good pointer returns 0
|
|
// bad pointer returns 1
|
|
//
|
|
//go:nosplit
|
|
func ptrtest(uintptr) uint64
|
|
|
|
// Load memory at ptr location with error handling if the location is invalid
|
|
//
|
|
//go:noescape
|
|
func safeload(ptr uintptr) (value uintptr, error uintptr)
|
|
|
|
const (
|
|
entrypointLocationOffset = 8 // From function descriptor
|
|
|
|
xplinkEyecatcher = 0x00c300c500c500f1 // ".C.E.E.1"
|
|
eyecatcherOffset = 16 // From function entrypoint (negative)
|
|
ppa1LocationOffset = 8 // From function entrypoint (negative)
|
|
|
|
nameLenOffset = 0x14 // From PPA1 start
|
|
nameOffset = 0x16 // From PPA1 start
|
|
)
|
|
|
|
func getPpaOffset(funcptr uintptr) int64 {
|
|
entrypoint, err := safeload(funcptr + entrypointLocationOffset)
|
|
if err != 0 {
|
|
return -1
|
|
}
|
|
|
|
// XPLink functions have ".C.E.E.1" as the first 8 bytes (EBCDIC)
|
|
val, err := safeload(entrypoint - eyecatcherOffset)
|
|
if err != 0 {
|
|
return -1
|
|
}
|
|
if val != xplinkEyecatcher {
|
|
return -1
|
|
}
|
|
|
|
ppaoff, err := safeload(entrypoint - ppa1LocationOffset)
|
|
if err != 0 {
|
|
return -1
|
|
}
|
|
|
|
ppaoff >>= 32
|
|
return int64(ppaoff)
|
|
}
|
|
|
|
//-------------------------------
|
|
// function descriptor pointer validity test
|
|
// good pointer returns 0
|
|
// bad pointer returns 1
|
|
|
|
// TODO: currently mksyscall_zos_s390x.go generate empty string for funcName
|
|
// have correct funcName pass to the funcptrtest function
|
|
func funcptrtest(funcptr uintptr, funcName string) uint64 {
|
|
entrypoint, err := safeload(funcptr + entrypointLocationOffset)
|
|
if err != 0 {
|
|
return 1
|
|
}
|
|
|
|
ppaoff := getPpaOffset(funcptr)
|
|
if ppaoff == -1 {
|
|
return 1
|
|
}
|
|
|
|
// PPA1 offset value is from the start of the entire function block, not the entrypoint
|
|
ppa1 := (entrypoint - eyecatcherOffset) + uintptr(ppaoff)
|
|
|
|
nameLen, err := safeload(ppa1 + nameLenOffset)
|
|
if err != 0 {
|
|
return 1
|
|
}
|
|
|
|
nameLen >>= 48
|
|
if nameLen > 128 {
|
|
return 1
|
|
}
|
|
|
|
// no function name input to argument end here
|
|
if funcName == "" {
|
|
return 0
|
|
}
|
|
|
|
var funcname [128]byte
|
|
for i := 0; i < int(nameLen); i += 8 {
|
|
v, err := safeload(ppa1 + nameOffset + uintptr(i))
|
|
if err != 0 {
|
|
return 1
|
|
}
|
|
funcname[i] = byte(v >> 56)
|
|
funcname[i+1] = byte(v >> 48)
|
|
funcname[i+2] = byte(v >> 40)
|
|
funcname[i+3] = byte(v >> 32)
|
|
funcname[i+4] = byte(v >> 24)
|
|
funcname[i+5] = byte(v >> 16)
|
|
funcname[i+6] = byte(v >> 8)
|
|
funcname[i+7] = byte(v)
|
|
}
|
|
|
|
runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4, // __e2a_l
|
|
[]uintptr{uintptr(unsafe.Pointer(&funcname[0])), nameLen})
|
|
|
|
name := string(funcname[:nameLen])
|
|
if name != funcName {
|
|
return 1
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
// For detection of capabilities on a system.
|
|
// Is function descriptor f a valid function?
|
|
func isValidLeFunc(f uintptr) error {
|
|
ret := funcptrtest(f, "")
|
|
if ret != 0 {
|
|
return fmt.Errorf("Bad pointer, not an LE function ")
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Retrieve function name from descriptor
|
|
func getLeFuncName(f uintptr) (string, error) {
|
|
// assume it has been checked, only check ppa1 validity here
|
|
entry := ((*[2]uintptr)(unsafe.Pointer(f)))[1]
|
|
preamp := ((*[4]uint32)(unsafe.Pointer(entry - eyecatcherOffset)))
|
|
|
|
offsetPpa1 := preamp[2]
|
|
if offsetPpa1 > 0x0ffff {
|
|
return "", fmt.Errorf("PPA1 offset seems too big 0x%x\n", offsetPpa1)
|
|
}
|
|
|
|
ppa1 := uintptr(unsafe.Pointer(preamp)) + uintptr(offsetPpa1)
|
|
res := ptrtest(ppa1)
|
|
if res != 0 {
|
|
return "", fmt.Errorf("PPA1 address not valid")
|
|
}
|
|
|
|
size := *(*uint16)(unsafe.Pointer(ppa1 + nameLenOffset))
|
|
if size > 128 {
|
|
return "", fmt.Errorf("Function name seems too long, length=%d\n", size)
|
|
}
|
|
|
|
var name [128]byte
|
|
funcname := (*[128]byte)(unsafe.Pointer(ppa1 + nameOffset))
|
|
copy(name[0:size], funcname[0:size])
|
|
|
|
runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___E2A_L<<4, // __e2a_l
|
|
[]uintptr{uintptr(unsafe.Pointer(&name[0])), uintptr(size)})
|
|
|
|
return string(name[:size]), nil
|
|
}
|
|
|
|
// Check z/OS version
|
|
func zosLeVersion() (version, release uint32) {
|
|
p1 := (*(*uintptr)(unsafe.Pointer(uintptr(1208)))) >> 32
|
|
p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 88)))
|
|
p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 8)))
|
|
p1 = *(*uintptr)(unsafe.Pointer(uintptr(p1 + 984)))
|
|
vrm := *(*uint32)(unsafe.Pointer(p1 + 80))
|
|
version = (vrm & 0x00ff0000) >> 16
|
|
release = (vrm & 0x0000ff00) >> 8
|
|
return
|
|
}
|
|
|
|
// returns a zos C FILE * for stdio fd 0, 1, 2
|
|
func ZosStdioFilep(fd int32) uintptr {
|
|
return uintptr(*(*uint64)(unsafe.Pointer(uintptr(*(*uint64)(unsafe.Pointer(uintptr(*(*uint64)(unsafe.Pointer(uintptr(uint64(*(*uint32)(unsafe.Pointer(uintptr(1208)))) + 80))) + uint64((fd+2)<<3))))))))
|
|
}
|
|
|
|
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 DecodeData(dest []byte, sz int, val uint64) {
|
|
for i := 0; i < sz; i++ {
|
|
dest[sz-1-i] = byte((val >> (uint64(i * 8))) & 0xff)
|
|
}
|
|
}
|
|
|
|
func EncodeData(data []byte) uint64 {
|
|
var value uint64
|
|
sz := len(data)
|
|
for i := 0; i < sz; i++ {
|
|
value |= uint64(data[i]) << uint64(((sz - i - 1) * 8))
|
|
}
|
|
return value
|
|
}
|
|
|
|
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)
|
|
for i := 0; i < len(sa.Addr); i++ {
|
|
sa.raw.Addr[i] = sa.Addr[i]
|
|
}
|
|
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
|
|
for i := 0; i < len(sa.Addr); i++ {
|
|
sa.raw.Addr[i] = sa.Addr[i]
|
|
}
|
|
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++
|
|
}
|
|
sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
|
|
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])
|
|
for i := 0; i < len(sa.Addr); i++ {
|
|
sa.Addr[i] = pp.Addr[i]
|
|
}
|
|
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
|
|
for i := 0; i < len(sa.Addr); i++ {
|
|
sa.Addr[i] = pp.Addr[i]
|
|
}
|
|
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 Accept4(fd int, flags int) (nfd int, sa Sockaddr, err error) {
|
|
var rsa RawSockaddrAny
|
|
var len _Socklen = SizeofSockaddrAny
|
|
nfd, err = accept4(fd, &rsa, &len, flags)
|
|
if err != nil {
|
|
return
|
|
}
|
|
if len > SizeofSockaddrAny {
|
|
panic("RawSockaddrAny too small")
|
|
}
|
|
// TODO(neeilan): Remove 0 in call
|
|
sa, err = anyToSockaddr(0, &rsa)
|
|
if err != nil {
|
|
Close(nfd)
|
|
nfd = 0
|
|
}
|
|
return
|
|
}
|
|
|
|
func Ctermid() (tty string, err error) {
|
|
var termdev [1025]byte
|
|
runtime.EnterSyscall()
|
|
r0, err2, err1 := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___CTERMID_A<<4, uintptr(unsafe.Pointer(&termdev[0])))
|
|
runtime.ExitSyscall()
|
|
if r0 == 0 {
|
|
return "", fmt.Errorf("%s (errno2=0x%x)\n", err1.Error(), err2)
|
|
}
|
|
s := string(termdev[:])
|
|
idx := strings.Index(s, string(rune(0)))
|
|
if idx == -1 {
|
|
tty = s
|
|
} else {
|
|
tty = s[:idx]
|
|
}
|
|
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 Flistxattr(fd int, dest []byte) (sz int, err error) = SYS___FLISTXATTR_A
|
|
//sys Fremovexattr(fd int, attr string) (err error) = SYS___FREMOVEXATTR_A
|
|
//sys read(fd int, p []byte) (n int, err error)
|
|
//sys write(fd int, p []byte) (n int, err error)
|
|
|
|
//sys Fgetxattr(fd int, attr string, dest []byte) (sz int, err error) = SYS___FGETXATTR_A
|
|
//sys Fsetxattr(fd int, attr string, data []byte, flag int) (err error) = SYS___FSETXATTR_A
|
|
|
|
//sys accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = SYS___ACCEPT_A
|
|
//sys accept4(s int, rsa *RawSockaddrAny, addrlen *_Socklen, flags int) (fd int, err error) = SYS___ACCEPT4_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 Removexattr(path string, attr string) (err error) = SYS___REMOVEXATTR_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 int, arg uintptr) (err error) = SYS_IOCTL
|
|
//sys ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) = SYS_IOCTL
|
|
//sys shmat(id int, addr uintptr, flag int) (ret uintptr, err error) = SYS_SHMAT
|
|
//sys shmctl(id int, cmd int, buf *SysvShmDesc) (result int, err error) = SYS_SHMCTL64
|
|
//sys shmdt(addr uintptr) (err error) = SYS_SHMDT
|
|
//sys shmget(key int, size int, flag int) (id int, err error) = SYS_SHMGET
|
|
|
|
//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 Dup3(oldfd int, newfd int, flags int) (err error) = SYS_DUP3
|
|
//sys Dirfd(dirp uintptr) (fd int, err error) = SYS_DIRFD
|
|
//sys EpollCreate(size int) (fd int, err error) = SYS_EPOLL_CREATE
|
|
//sys EpollCreate1(flags int) (fd int, err error) = SYS_EPOLL_CREATE1
|
|
//sys EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) = SYS_EPOLL_CTL
|
|
//sys EpollPwait(epfd int, events []EpollEvent, msec int, sigmask *int) (n int, err error) = SYS_EPOLL_PWAIT
|
|
//sys EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) = SYS_EPOLL_WAIT
|
|
//sys Errno2() (er2 int) = SYS___ERRNO2
|
|
//sys Eventfd(initval uint, flags int) (fd int, err error) = SYS_EVENTFD
|
|
//sys Exit(code int)
|
|
//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error) = SYS___FACCESSAT_A
|
|
|
|
func Faccessat2(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
return Faccessat(dirfd, path, mode, flags)
|
|
}
|
|
|
|
//sys Fchdir(fd int) (err error)
|
|
//sys Fchmod(fd int, mode uint32) (err error)
|
|
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) = SYS___FCHMODAT_A
|
|
//sys Fchown(fd int, uid int, gid int) (err error)
|
|
//sys Fchownat(fd int, path string, uid int, gid int, flags int) (err error) = SYS___FCHOWNAT_A
|
|
//sys FcntlInt(fd uintptr, cmd int, arg int) (retval int, err error) = SYS_FCNTL
|
|
//sys Fdatasync(fd int) (err error) = SYS_FDATASYNC
|
|
//sys fstat(fd int, stat *Stat_LE_t) (err error)
|
|
//sys fstatat(dirfd int, path string, stat *Stat_LE_t, flags int) (err error) = SYS___FSTATAT_A
|
|
|
|
func Fstat(fd int, stat *Stat_t) (err error) {
|
|
var statLE Stat_LE_t
|
|
err = fstat(fd, &statLE)
|
|
copyStat(stat, &statLE)
|
|
return
|
|
}
|
|
|
|
func Fstatat(dirfd int, path string, stat *Stat_t, flags int) (err error) {
|
|
var statLE Stat_LE_t
|
|
err = fstatat(dirfd, path, &statLE, flags)
|
|
copyStat(stat, &statLE)
|
|
return
|
|
}
|
|
|
|
func impl_Getxattr(path string, attr string, dest []byte) (sz int, err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p1 *byte
|
|
_p1, err = BytePtrFromString(attr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p2 unsafe.Pointer
|
|
if len(dest) > 0 {
|
|
_p2 = unsafe.Pointer(&dest[0])
|
|
} else {
|
|
_p2 = unsafe.Pointer(&_zero)
|
|
}
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___GETXATTR_A<<4, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(dest)))
|
|
sz = int(r0)
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_GetxattrAddr() *(func(path string, attr string, dest []byte) (sz int, err error))
|
|
|
|
var Getxattr = enter_Getxattr
|
|
|
|
func enter_Getxattr(path string, attr string, dest []byte) (sz int, err error) {
|
|
funcref := get_GetxattrAddr()
|
|
if validGetxattr() {
|
|
*funcref = impl_Getxattr
|
|
} else {
|
|
*funcref = error_Getxattr
|
|
}
|
|
return (*funcref)(path, attr, dest)
|
|
}
|
|
|
|
func error_Getxattr(path string, attr string, dest []byte) (sz int, err error) {
|
|
return -1, ENOSYS
|
|
}
|
|
|
|
func validGetxattr() bool {
|
|
if funcptrtest(GetZosLibVec()+SYS___GETXATTR_A<<4, "") == 0 {
|
|
if name, err := getLeFuncName(GetZosLibVec() + SYS___GETXATTR_A<<4); err == nil {
|
|
return name == "__getxattr_a"
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
//sys Lgetxattr(link string, attr string, dest []byte) (sz int, err error) = SYS___LGETXATTR_A
|
|
//sys Lsetxattr(path string, attr string, data []byte, flags int) (err error) = SYS___LSETXATTR_A
|
|
|
|
func impl_Setxattr(path string, attr string, data []byte, flags int) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p1 *byte
|
|
_p1, err = BytePtrFromString(attr)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p2 unsafe.Pointer
|
|
if len(data) > 0 {
|
|
_p2 = unsafe.Pointer(&data[0])
|
|
} else {
|
|
_p2 = unsafe.Pointer(&_zero)
|
|
}
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___SETXATTR_A<<4, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(_p2), uintptr(len(data)), uintptr(flags))
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_SetxattrAddr() *(func(path string, attr string, data []byte, flags int) (err error))
|
|
|
|
var Setxattr = enter_Setxattr
|
|
|
|
func enter_Setxattr(path string, attr string, data []byte, flags int) (err error) {
|
|
funcref := get_SetxattrAddr()
|
|
if validSetxattr() {
|
|
*funcref = impl_Setxattr
|
|
} else {
|
|
*funcref = error_Setxattr
|
|
}
|
|
return (*funcref)(path, attr, data, flags)
|
|
}
|
|
|
|
func error_Setxattr(path string, attr string, data []byte, flags int) (err error) {
|
|
return ENOSYS
|
|
}
|
|
|
|
func validSetxattr() bool {
|
|
if funcptrtest(GetZosLibVec()+SYS___SETXATTR_A<<4, "") == 0 {
|
|
if name, err := getLeFuncName(GetZosLibVec() + SYS___SETXATTR_A<<4); err == nil {
|
|
return name == "__setxattr_a"
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
//sys Fstatfs(fd int, buf *Statfs_t) (err error) = SYS_FSTATFS
|
|
//sys Fstatvfs(fd int, stat *Statvfs_t) (err error) = SYS_FSTATVFS
|
|
//sys Fsync(fd int) (err error)
|
|
//sys Futimes(fd int, tv []Timeval) (err error) = SYS_FUTIMES
|
|
//sys Futimesat(dirfd int, path string, tv []Timeval) (err error) = SYS___FUTIMESAT_A
|
|
//sys Ftruncate(fd int, length int64) (err error)
|
|
//sys Getrandom(buf []byte, flags int) (n int, err error) = SYS_GETRANDOM
|
|
//sys InotifyInit() (fd int, err error) = SYS_INOTIFY_INIT
|
|
//sys InotifyInit1(flags int) (fd int, err error) = SYS_INOTIFY_INIT1
|
|
//sys InotifyAddWatch(fd int, pathname string, mask uint32) (watchdesc int, err error) = SYS___INOTIFY_ADD_WATCH_A
|
|
//sys InotifyRmWatch(fd int, watchdesc uint32) (success int, err error) = SYS_INOTIFY_RM_WATCH
|
|
//sys Listxattr(path string, dest []byte) (sz int, err error) = SYS___LISTXATTR_A
|
|
//sys Llistxattr(path string, dest []byte) (sz int, err error) = SYS___LLISTXATTR_A
|
|
//sys Lremovexattr(path string, attr string) (err error) = SYS___LREMOVEXATTR_A
|
|
//sys Lutimes(path string, tv []Timeval) (err error) = SYS___LUTIMES_A
|
|
//sys Mprotect(b []byte, prot int) (err error) = SYS_MPROTECT
|
|
//sys Msync(b []byte, flags int) (err error) = SYS_MSYNC
|
|
//sys Console2(cmsg *ConsMsg2, modstr *byte, concmd *uint32) (err error) = SYS___CONSOLE2
|
|
|
|
// Pipe2 begin
|
|
|
|
//go:nosplit
|
|
func getPipe2Addr() *(func([]int, int) error)
|
|
|
|
var Pipe2 = pipe2Enter
|
|
|
|
func pipe2Enter(p []int, flags int) (err error) {
|
|
if funcptrtest(GetZosLibVec()+SYS_PIPE2<<4, "") == 0 {
|
|
*getPipe2Addr() = pipe2Impl
|
|
} else {
|
|
*getPipe2Addr() = pipe2Error
|
|
}
|
|
return (*getPipe2Addr())(p, flags)
|
|
}
|
|
|
|
func pipe2Impl(p []int, flags int) (err error) {
|
|
var pp [2]_C_int
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_PIPE2<<4, uintptr(unsafe.Pointer(&pp[0])), uintptr(flags))
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
} else {
|
|
p[0] = int(pp[0])
|
|
p[1] = int(pp[1])
|
|
}
|
|
return
|
|
}
|
|
func pipe2Error(p []int, flags int) (err error) {
|
|
return fmt.Errorf("Pipe2 is not available on this system")
|
|
}
|
|
|
|
// Pipe2 end
|
|
|
|
//sys Poll(fds []PollFd, timeout int) (n int, err error) = SYS_POLL
|
|
|
|
func Readdir(dir uintptr) (dirent *Dirent, err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___READDIR_A<<4, uintptr(dir))
|
|
runtime.ExitSyscall()
|
|
dirent = (*Dirent)(unsafe.Pointer(r0))
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//sys Readdir_r(dirp uintptr, entry *direntLE, result **direntLE) (err error) = SYS___READDIR_R_A
|
|
//sys Statfs(path string, buf *Statfs_t) (err error) = SYS___STATFS_A
|
|
//sys Syncfs(fd int) (err error) = SYS_SYNCFS
|
|
//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_LE(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_____OSNAME_A
|
|
//sys Unshare(flags int) (err error) = SYS_UNSHARE
|
|
|
|
func Ptsname(fd int) (name string, err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___PTSNAME_A<<4, uintptr(fd))
|
|
runtime.ExitSyscall()
|
|
if r0 == 0 {
|
|
err = errnoErr2(e1, e2)
|
|
} else {
|
|
name = u2s(unsafe.Pointer(r0))
|
|
}
|
|
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) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_CLOSE<<4, uintptr(fd))
|
|
runtime.ExitSyscall()
|
|
for i := 0; e1 == EAGAIN && i < 10; i++ {
|
|
runtime.EnterSyscall()
|
|
CallLeFuncWithErr(GetZosLibVec()+SYS_USLEEP<<4, uintptr(10))
|
|
runtime.ExitSyscall()
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 = CallLeFuncWithErr(GetZosLibVec()+SYS_CLOSE<<4, uintptr(fd))
|
|
runtime.ExitSyscall()
|
|
}
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
// 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)
|
|
}
|
|
|
|
func MmapPtr(fd int, offset int64, addr unsafe.Pointer, length uintptr, prot int, flags int) (ret unsafe.Pointer, err error) {
|
|
xaddr, err := mapper.mmap(uintptr(addr), length, prot, flags, fd, offset)
|
|
return unsafe.Pointer(xaddr), err
|
|
}
|
|
|
|
func MunmapPtr(addr unsafe.Pointer, length uintptr) (err error) {
|
|
return mapper.munmap(uintptr(addr), length)
|
|
}
|
|
|
|
//sys Gethostname(buf []byte) (err error) = SYS___GETHOSTNAME_A
|
|
//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
|
|
}
|
|
|
|
//sys Getegid() (egid int) = SYS_GETEGID
|
|
//sys Geteuid() (euid int) = SYS_GETEUID
|
|
//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 Linkat(oldDirFd int, oldPath string, newDirFd int, newPath string, flags int) (err error) = SYS___LINKAT_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
|
|
}
|
|
|
|
// for checking symlinks begins with $VERSION/ $SYSNAME/ $SYSSYMR/ $SYSSYMA/
|
|
func isSpecialPath(path []byte) (v bool) {
|
|
var special = [4][8]byte{
|
|
{'V', 'E', 'R', 'S', 'I', 'O', 'N', '/'},
|
|
{'S', 'Y', 'S', 'N', 'A', 'M', 'E', '/'},
|
|
{'S', 'Y', 'S', 'S', 'Y', 'M', 'R', '/'},
|
|
{'S', 'Y', 'S', 'S', 'Y', 'M', 'A', '/'}}
|
|
|
|
var i, j int
|
|
for i = 0; i < len(special); i++ {
|
|
for j = 0; j < len(special[i]); j++ {
|
|
if path[j] != special[i][j] {
|
|
break
|
|
}
|
|
}
|
|
if j == len(special[i]) {
|
|
return true
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func realpath(srcpath string, abspath []byte) (pathlen int, errno int) {
|
|
var source [1024]byte
|
|
copy(source[:], srcpath)
|
|
source[len(srcpath)] = 0
|
|
ret := runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___REALPATH_A<<4, //__realpath_a()
|
|
[]uintptr{uintptr(unsafe.Pointer(&source[0])),
|
|
uintptr(unsafe.Pointer(&abspath[0]))})
|
|
if ret != 0 {
|
|
index := bytes.IndexByte(abspath[:], byte(0))
|
|
if index != -1 {
|
|
return index, 0
|
|
}
|
|
} else {
|
|
errptr := (*int)(unsafe.Pointer(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO<<4, []uintptr{}))) //__errno()
|
|
return 0, *errptr
|
|
}
|
|
return 0, 245 // EBADDATA 245
|
|
}
|
|
|
|
func Readlink(path string, buf []byte) (n int, err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p1 unsafe.Pointer
|
|
if len(buf) > 0 {
|
|
_p1 = unsafe.Pointer(&buf[0])
|
|
} else {
|
|
_p1 = unsafe.Pointer(&_zero)
|
|
}
|
|
n = int(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___READLINK_A<<4,
|
|
[]uintptr{uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf))}))
|
|
runtime.KeepAlive(unsafe.Pointer(_p0))
|
|
if n == -1 {
|
|
value := *(*int32)(unsafe.Pointer(runtime.CallLeFuncByPtr(runtime.XplinkLibvec+SYS___ERRNO<<4, []uintptr{})))
|
|
err = errnoErr(Errno(value))
|
|
} else {
|
|
if buf[0] == '$' {
|
|
if isSpecialPath(buf[1:9]) {
|
|
cnt, err1 := realpath(path, buf)
|
|
if err1 == 0 {
|
|
n = cnt
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
func impl_Readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p1 unsafe.Pointer
|
|
if len(buf) > 0 {
|
|
_p1 = unsafe.Pointer(&buf[0])
|
|
} else {
|
|
_p1 = unsafe.Pointer(&_zero)
|
|
}
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___READLINKAT_A<<4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(_p1), uintptr(len(buf)))
|
|
runtime.ExitSyscall()
|
|
n = int(r0)
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
return n, err
|
|
} else {
|
|
if buf[0] == '$' {
|
|
if isSpecialPath(buf[1:9]) {
|
|
cnt, err1 := realpath(path, buf)
|
|
if err1 == 0 {
|
|
n = cnt
|
|
}
|
|
}
|
|
}
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_ReadlinkatAddr() *(func(dirfd int, path string, buf []byte) (n int, err error))
|
|
|
|
var Readlinkat = enter_Readlinkat
|
|
|
|
func enter_Readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
|
|
funcref := get_ReadlinkatAddr()
|
|
if funcptrtest(GetZosLibVec()+SYS___READLINKAT_A<<4, "") == 0 {
|
|
*funcref = impl_Readlinkat
|
|
} else {
|
|
*funcref = error_Readlinkat
|
|
}
|
|
return (*funcref)(dirfd, path, buf)
|
|
}
|
|
|
|
func error_Readlinkat(dirfd int, path string, buf []byte) (n int, err error) {
|
|
n = -1
|
|
err = ENOSYS
|
|
return
|
|
}
|
|
|
|
//sys Mkdir(path string, mode uint32) (err error) = SYS___MKDIR_A
|
|
//sys Mkdirat(dirfd int, path string, mode uint32) (err error) = SYS___MKDIRAT_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 Mknodat(dirfd int, path string, mode uint32, dev int) (err error) = SYS___MKNODAT_A
|
|
//sys PivotRoot(newroot string, oldroot string) (err error) = SYS___PIVOT_ROOT_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 Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (err error) = SYS___PRCTL_A
|
|
//sysnb Prlimit(pid int, resource int, newlimit *Rlimit, old *Rlimit) (err error) = SYS_PRLIMIT
|
|
//sys Rename(from string, to string) (err error) = SYS___RENAME_A
|
|
//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) = SYS___RENAMEAT_A
|
|
//sys Renameat2(olddirfd int, oldpath string, newdirfd int, newpath string, flags uint) (err error) = SYS___RENAMEAT2_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 Setegid(egid int) (err error) = SYS_SETEGID
|
|
//sys Seteuid(euid int) (err error) = SYS_SETEUID
|
|
//sys Sethostname(p []byte) (err error) = SYS___SETHOSTNAME_A
|
|
//sys Setns(fd int, nstype int) (err error) = SYS_SETNS
|
|
//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 Symlinkat(oldPath string, dirfd int, newPath string) (err error) = SYS___SYMLINKAT_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 Unlinkat(dirfd int, path string, flags int) (err error) = SYS___UNLINKAT_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) {
|
|
if mode&O_ACCMODE == 0 {
|
|
mode |= O_RDONLY
|
|
}
|
|
return open(path, mode, perm)
|
|
}
|
|
|
|
//sys openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) = SYS___OPENAT_A
|
|
|
|
func Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error) {
|
|
if flags&O_ACCMODE == 0 {
|
|
flags |= O_RDONLY
|
|
}
|
|
return openat(dirfd, path, flags, mode)
|
|
}
|
|
|
|
//sys openat2(dirfd int, path string, open_how *OpenHow, size int) (fd int, err error) = SYS___OPENAT2_A
|
|
|
|
func Openat2(dirfd int, path string, how *OpenHow) (fd int, err error) {
|
|
if how.Flags&O_ACCMODE == 0 {
|
|
how.Flags |= O_RDONLY
|
|
}
|
|
return openat2(dirfd, path, how, SizeofOpenHow)
|
|
}
|
|
|
|
func ZosFdToPath(dirfd int) (path string, err error) {
|
|
var buffer [1024]byte
|
|
runtime.EnterSyscall()
|
|
ret, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_W_IOCTL<<4, uintptr(dirfd), 17, 1024, uintptr(unsafe.Pointer(&buffer[0])))
|
|
runtime.ExitSyscall()
|
|
if ret == 0 {
|
|
zb := bytes.IndexByte(buffer[:], 0)
|
|
if zb == -1 {
|
|
zb = len(buffer)
|
|
}
|
|
CallLeFuncWithErr(GetZosLibVec()+SYS___E2A_L<<4, uintptr(unsafe.Pointer(&buffer[0])), uintptr(zb))
|
|
return string(buffer[:zb]), nil
|
|
}
|
|
return "", errnoErr2(e1, e2)
|
|
}
|
|
|
|
//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)
|
|
}
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___GETCWD_A<<4, uintptr(p), uintptr(len(buf)))
|
|
runtime.ExitSyscall()
|
|
n = clen(buf) + 1
|
|
if r0 == 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
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 waitid(idType int, id int, info *Siginfo, options int) (err error)
|
|
|
|
func Waitid(idType int, id int, info *Siginfo, options int, rusage *Rusage) (err error) {
|
|
return waitid(idType, id, info, options)
|
|
}
|
|
|
|
//sys waitpid(pid int, wstatus *_C_int, options int) (wpid int, err error)
|
|
|
|
func impl_Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_WAIT4<<4, uintptr(pid), uintptr(unsafe.Pointer(wstatus)), uintptr(options), uintptr(unsafe.Pointer(rusage)))
|
|
runtime.ExitSyscall()
|
|
wpid = int(r0)
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_Wait4Addr() *(func(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error))
|
|
|
|
var Wait4 = enter_Wait4
|
|
|
|
func enter_Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
|
|
funcref := get_Wait4Addr()
|
|
if funcptrtest(GetZosLibVec()+SYS_WAIT4<<4, "") == 0 {
|
|
*funcref = impl_Wait4
|
|
} else {
|
|
*funcref = legacyWait4
|
|
}
|
|
return (*funcref)(pid, wstatus, options, rusage)
|
|
}
|
|
|
|
func legacyWait4(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)
|
|
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 tv == nil {
|
|
return utimes(path, nil)
|
|
}
|
|
if len(tv) != 2 {
|
|
return EINVAL
|
|
}
|
|
return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
|
|
}
|
|
|
|
//sys utimensat(dirfd int, path string, ts *[2]Timespec, flags int) (err error) = SYS___UTIMENSAT_A
|
|
|
|
func validUtimensat() bool {
|
|
if funcptrtest(GetZosLibVec()+SYS___UTIMENSAT_A<<4, "") == 0 {
|
|
if name, err := getLeFuncName(GetZosLibVec() + SYS___UTIMENSAT_A<<4); err == nil {
|
|
return name == "__utimensat_a"
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Begin UtimesNano
|
|
|
|
//go:nosplit
|
|
func get_UtimesNanoAddr() *(func(path string, ts []Timespec) (err error))
|
|
|
|
var UtimesNano = enter_UtimesNano
|
|
|
|
func enter_UtimesNano(path string, ts []Timespec) (err error) {
|
|
funcref := get_UtimesNanoAddr()
|
|
if validUtimensat() {
|
|
*funcref = utimesNanoImpl
|
|
} else {
|
|
*funcref = legacyUtimesNano
|
|
}
|
|
return (*funcref)(path, ts)
|
|
}
|
|
|
|
func utimesNanoImpl(path string, ts []Timespec) (err error) {
|
|
if ts == nil {
|
|
return utimensat(AT_FDCWD, path, nil, 0)
|
|
}
|
|
if len(ts) != 2 {
|
|
return EINVAL
|
|
}
|
|
return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
|
|
}
|
|
|
|
func legacyUtimesNano(path string, ts []Timespec) (err 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])))
|
|
}
|
|
|
|
// End UtimesNano
|
|
|
|
// Begin UtimesNanoAt
|
|
|
|
//go:nosplit
|
|
func get_UtimesNanoAtAddr() *(func(dirfd int, path string, ts []Timespec, flags int) (err error))
|
|
|
|
var UtimesNanoAt = enter_UtimesNanoAt
|
|
|
|
func enter_UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) (err error) {
|
|
funcref := get_UtimesNanoAtAddr()
|
|
if validUtimensat() {
|
|
*funcref = utimesNanoAtImpl
|
|
} else {
|
|
*funcref = legacyUtimesNanoAt
|
|
}
|
|
return (*funcref)(dirfd, path, ts, flags)
|
|
}
|
|
|
|
func utimesNanoAtImpl(dirfd int, path string, ts []Timespec, flags int) (err error) {
|
|
if ts == nil {
|
|
return utimensat(dirfd, path, nil, flags)
|
|
}
|
|
if len(ts) != 2 {
|
|
return EINVAL
|
|
}
|
|
return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
|
|
}
|
|
|
|
func legacyUtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) (err error) {
|
|
if path[0] != '/' {
|
|
dirPath, err := ZosFdToPath(dirfd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
path = dirPath + "/" + path
|
|
}
|
|
if flags == AT_SYMLINK_NOFOLLOW {
|
|
if len(ts) != 2 {
|
|
return EINVAL
|
|
}
|
|
|
|
if ts[0].Nsec >= 5e8 {
|
|
ts[0].Sec++
|
|
}
|
|
ts[0].Nsec = 0
|
|
if ts[1].Nsec >= 5e8 {
|
|
ts[1].Sec++
|
|
}
|
|
ts[1].Nsec = 0
|
|
|
|
// Not as efficient as it could be because Timespec and
|
|
// Timeval have different types in the different OSes
|
|
tv := []Timeval{
|
|
NsecToTimeval(TimespecToNsec(ts[0])),
|
|
NsecToTimeval(TimespecToNsec(ts[1])),
|
|
}
|
|
return Lutimes(path, tv)
|
|
}
|
|
return UtimesNano(path, ts)
|
|
}
|
|
|
|
// End UtimesNanoAt
|
|
|
|
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 ByteSliceToString(buf[:vallen]), 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
|
|
}
|
|
err = nil
|
|
runtime.EnterSyscall()
|
|
dir, e2, e1 := CallLeFuncWithPtrReturn(GetZosLibVec()+SYS___OPENDIR_A<<4, uintptr(unsafe.Pointer(p)))
|
|
runtime.ExitSyscall()
|
|
runtime.KeepAlive(unsafe.Pointer(p))
|
|
if dir == 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return dir, err
|
|
}
|
|
|
|
// clearsyscall.Errno resets the errno value to 0.
|
|
func clearErrno()
|
|
|
|
func Closedir(dir uintptr) error {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_CLOSEDIR<<4, dir)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
return errnoErr2(e1, e2)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func Seekdir(dir uintptr, pos int) {
|
|
runtime.EnterSyscall()
|
|
CallLeFuncWithErr(GetZosLibVec()+SYS_SEEKDIR<<4, dir, uintptr(pos))
|
|
runtime.ExitSyscall()
|
|
}
|
|
|
|
func Telldir(dir uintptr) (int, error) {
|
|
p, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_TELLDIR<<4, dir)
|
|
pos := int(p)
|
|
if int64(p) == -1 {
|
|
return pos, errnoErr2(e1, e2)
|
|
}
|
|
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
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FCNTL<<4, fd, uintptr(cmd), uintptr(unsafe.Pointer(&flock)))
|
|
runtime.ExitSyscall()
|
|
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 r0 == 0 {
|
|
return nil
|
|
}
|
|
return errnoErr2(e1, e2)
|
|
}
|
|
|
|
func impl_Flock(fd int, how int) (err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FLOCK<<4, uintptr(fd), uintptr(how))
|
|
runtime.ExitSyscall()
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_FlockAddr() *(func(fd int, how int) (err error))
|
|
|
|
var Flock = enter_Flock
|
|
|
|
func validFlock(fp uintptr) bool {
|
|
if funcptrtest(GetZosLibVec()+SYS_FLOCK<<4, "") == 0 {
|
|
if name, err := getLeFuncName(GetZosLibVec() + SYS_FLOCK<<4); err == nil {
|
|
return name == "flock"
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
func enter_Flock(fd int, how int) (err error) {
|
|
funcref := get_FlockAddr()
|
|
if validFlock(GetZosLibVec() + SYS_FLOCK<<4) {
|
|
*funcref = impl_Flock
|
|
} else {
|
|
*funcref = legacyFlock
|
|
}
|
|
return (*funcref)(fd, how)
|
|
}
|
|
|
|
func legacyFlock(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) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MLOCKALL<<4, _BPX_NONSWAP)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Mlock2(b []byte, flags int) (err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MLOCKALL<<4, _BPX_NONSWAP)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Mlockall(flags int) (err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MLOCKALL<<4, _BPX_NONSWAP)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Munlock(b []byte) (err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MLOCKALL<<4, _BPX_SWAP)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Munlockall() (err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MLOCKALL<<4, _BPX_SWAP)
|
|
runtime.ExitSyscall()
|
|
if r0 != 0 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
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
|
|
}
|
|
|
|
// Chtag
|
|
|
|
//go:nosplit
|
|
func get_ChtagAddr() *(func(path string, ccsid uint64, textbit uint64) error)
|
|
|
|
var Chtag = enter_Chtag
|
|
|
|
func enter_Chtag(path string, ccsid uint64, textbit uint64) error {
|
|
funcref := get_ChtagAddr()
|
|
if validSetxattr() {
|
|
*funcref = impl_Chtag
|
|
} else {
|
|
*funcref = legacy_Chtag
|
|
}
|
|
return (*funcref)(path, ccsid, textbit)
|
|
}
|
|
|
|
func legacy_Chtag(path string, ccsid uint64, textbit uint64) error {
|
|
tag := ccsid<<16 | textbit<<15
|
|
var tag_buff [8]byte
|
|
DecodeData(tag_buff[:], 8, tag)
|
|
return Setxattr(path, "filetag", tag_buff[:], XATTR_REPLACE)
|
|
}
|
|
|
|
func impl_Chtag(path string, ccsid uint64, textbit uint64) error {
|
|
tag := ccsid<<16 | textbit<<15
|
|
var tag_buff [4]byte
|
|
DecodeData(tag_buff[:], 4, tag)
|
|
return Setxattr(path, "system.filetag", tag_buff[:], XATTR_REPLACE)
|
|
}
|
|
|
|
// End of Chtag
|
|
|
|
// Nanosleep
|
|
|
|
//go:nosplit
|
|
func get_NanosleepAddr() *(func(time *Timespec, leftover *Timespec) error)
|
|
|
|
var Nanosleep = enter_Nanosleep
|
|
|
|
func enter_Nanosleep(time *Timespec, leftover *Timespec) error {
|
|
funcref := get_NanosleepAddr()
|
|
if funcptrtest(GetZosLibVec()+SYS_NANOSLEEP<<4, "") == 0 {
|
|
*funcref = impl_Nanosleep
|
|
} else {
|
|
*funcref = legacyNanosleep
|
|
}
|
|
return (*funcref)(time, leftover)
|
|
}
|
|
|
|
func impl_Nanosleep(time *Timespec, leftover *Timespec) error {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_NANOSLEEP<<4, uintptr(unsafe.Pointer(time)), uintptr(unsafe.Pointer(leftover)))
|
|
runtime.ExitSyscall()
|
|
if int64(r0) == -1 {
|
|
return errnoErr2(e1, e2)
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func legacyNanosleep(time *Timespec, leftover *Timespec) error {
|
|
t0 := runtime.Nanotime1()
|
|
var secrem uint32
|
|
var nsecrem uint32
|
|
total := time.Sec*1000000000 + time.Nsec
|
|
elapsed := runtime.Nanotime1() - t0
|
|
var rv int32
|
|
var rc int32
|
|
var err error
|
|
// repeatedly sleep for 1 second until less than 1 second left
|
|
for total-elapsed > 1000000000 {
|
|
rv, rc, _ = BpxCondTimedWait(uint32(1), uint32(0), uint32(CW_CONDVAR), &secrem, &nsecrem)
|
|
if rv != 0 && rc != 112 { // 112 is EAGAIN
|
|
if leftover != nil && rc == 120 { // 120 is EINTR
|
|
leftover.Sec = int64(secrem)
|
|
leftover.Nsec = int64(nsecrem)
|
|
}
|
|
err = Errno(rc)
|
|
return err
|
|
}
|
|
elapsed = runtime.Nanotime1() - t0
|
|
}
|
|
// sleep the remainder
|
|
if total > elapsed {
|
|
rv, rc, _ = BpxCondTimedWait(uint32(0), uint32(total-elapsed), uint32(CW_CONDVAR), &secrem, &nsecrem)
|
|
}
|
|
if leftover != nil && rc == 120 {
|
|
leftover.Sec = int64(secrem)
|
|
leftover.Nsec = int64(nsecrem)
|
|
}
|
|
if rv != 0 && rc != 112 {
|
|
err = Errno(rc)
|
|
}
|
|
return err
|
|
}
|
|
|
|
// End of Nanosleep
|
|
|
|
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 ZosTraceLevel int
|
|
var ZosTracefile *os.File
|
|
|
|
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
|
|
}
|
|
|
|
var reg *regexp.Regexp
|
|
|
|
// enhanced with zos specific errno2
|
|
func errnoErr2(e Errno, e2 uintptr) error {
|
|
switch e {
|
|
case 0:
|
|
return nil
|
|
case EAGAIN:
|
|
return errEAGAIN
|
|
/*
|
|
Allow the retrieval of errno2 for EINVAL and ENOENT on zos
|
|
case EINVAL:
|
|
return errEINVAL
|
|
case ENOENT:
|
|
return errENOENT
|
|
*/
|
|
}
|
|
if ZosTraceLevel > 0 {
|
|
var name string
|
|
if reg == nil {
|
|
reg = regexp.MustCompile("(^unix\\.[^/]+$|.*\\/unix\\.[^/]+$)")
|
|
}
|
|
i := 1
|
|
pc, file, line, ok := runtime.Caller(i)
|
|
if ok {
|
|
name = runtime.FuncForPC(pc).Name()
|
|
}
|
|
for ok && reg.MatchString(runtime.FuncForPC(pc).Name()) {
|
|
i += 1
|
|
pc, file, line, ok = runtime.Caller(i)
|
|
}
|
|
if ok {
|
|
if ZosTracefile == nil {
|
|
ZosConsolePrintf("From %s:%d\n", file, line)
|
|
ZosConsolePrintf("%s: %s (errno2=0x%x)\n", name, e.Error(), e2)
|
|
} else {
|
|
fmt.Fprintf(ZosTracefile, "From %s:%d\n", file, line)
|
|
fmt.Fprintf(ZosTracefile, "%s: %s (errno2=0x%x)\n", name, e.Error(), e2)
|
|
}
|
|
} else {
|
|
if ZosTracefile == nil {
|
|
ZosConsolePrintf("%s (errno2=0x%x)\n", e.Error(), e2)
|
|
} else {
|
|
fmt.Fprintf(ZosTracefile, "%s (errno2=0x%x)\n", e.Error(), e2)
|
|
}
|
|
}
|
|
}
|
|
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
|
|
}
|
|
|
|
// Set __MAP_64 by default
|
|
flags |= __MAP_64
|
|
|
|
// 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 Getag(path string) (ccsid uint16, flag uint16, err error) {
|
|
var val [8]byte
|
|
sz, err := Getxattr(path, "ccsid", val[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
ccsid = uint16(EncodeData(val[0:sz]))
|
|
sz, err = Getxattr(path, "flags", val[:])
|
|
if err != nil {
|
|
return
|
|
}
|
|
flag = uint16(EncodeData(val[0:sz]) >> 15)
|
|
return
|
|
}
|
|
|
|
// Mount begin
|
|
func impl_Mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(source)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p1 *byte
|
|
_p1, err = BytePtrFromString(target)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p2 *byte
|
|
_p2, err = BytePtrFromString(fstype)
|
|
if err != nil {
|
|
return
|
|
}
|
|
var _p3 *byte
|
|
_p3, err = BytePtrFromString(data)
|
|
if err != nil {
|
|
return
|
|
}
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MOUNT1_A<<4, uintptr(unsafe.Pointer(_p0)), uintptr(unsafe.Pointer(_p1)), uintptr(unsafe.Pointer(_p2)), uintptr(flags), uintptr(unsafe.Pointer(_p3)))
|
|
runtime.ExitSyscall()
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_MountAddr() *(func(source string, target string, fstype string, flags uintptr, data string) (err error))
|
|
|
|
var Mount = enter_Mount
|
|
|
|
func enter_Mount(source string, target string, fstype string, flags uintptr, data string) (err error) {
|
|
funcref := get_MountAddr()
|
|
if validMount() {
|
|
*funcref = impl_Mount
|
|
} else {
|
|
*funcref = legacyMount
|
|
}
|
|
return (*funcref)(source, target, fstype, flags, data)
|
|
}
|
|
|
|
func legacyMount(source string, target string, fstype string, flags uintptr, data string) (err error) {
|
|
if needspace := 8 - len(fstype); needspace <= 0 {
|
|
fstype = fstype[0:8]
|
|
} else {
|
|
fstype += " "[0:needspace]
|
|
}
|
|
return mount_LE(target, source, fstype, uint32(flags), int32(len(data)), data)
|
|
}
|
|
|
|
func validMount() bool {
|
|
if funcptrtest(GetZosLibVec()+SYS___MOUNT1_A<<4, "") == 0 {
|
|
if name, err := getLeFuncName(GetZosLibVec() + SYS___MOUNT1_A<<4); err == nil {
|
|
return name == "__mount1_a"
|
|
}
|
|
}
|
|
return false
|
|
}
|
|
|
|
// Mount end
|
|
|
|
// Unmount begin
|
|
func impl_Unmount(target string, flags int) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(target)
|
|
if err != nil {
|
|
return
|
|
}
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___UMOUNT2_A<<4, uintptr(unsafe.Pointer(_p0)), uintptr(flags))
|
|
runtime.ExitSyscall()
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_UnmountAddr() *(func(target string, flags int) (err error))
|
|
|
|
var Unmount = enter_Unmount
|
|
|
|
func enter_Unmount(target string, flags int) (err error) {
|
|
funcref := get_UnmountAddr()
|
|
if funcptrtest(GetZosLibVec()+SYS___UMOUNT2_A<<4, "") == 0 {
|
|
*funcref = impl_Unmount
|
|
} else {
|
|
*funcref = legacyUnmount
|
|
}
|
|
return (*funcref)(target, flags)
|
|
}
|
|
|
|
func legacyUnmount(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_LE(name, mtm)
|
|
}
|
|
// treat name as mountpoint
|
|
b2s := func(arr []byte) string {
|
|
var str string
|
|
for i := 0; i < len(arr); i++ {
|
|
if arr[i] == 0 {
|
|
str = string(arr[:i])
|
|
break
|
|
}
|
|
}
|
|
return str
|
|
}
|
|
var buffer struct {
|
|
header W_Mnth
|
|
fsinfo [64]W_Mntent
|
|
}
|
|
fs_count, err := W_Getmntent_A((*byte)(unsafe.Pointer(&buffer)), int(unsafe.Sizeof(buffer)))
|
|
if err == nil {
|
|
err = EINVAL
|
|
for i := 0; i < fs_count; i++ {
|
|
if b2s(buffer.fsinfo[i].Mountpoint[:]) == name {
|
|
err = unmount_LE(b2s(buffer.fsinfo[i].Fsname[:]), mtm)
|
|
break
|
|
}
|
|
}
|
|
} else if fs_count == 0 {
|
|
err = EINVAL
|
|
}
|
|
return err
|
|
}
|
|
|
|
// Unmount end
|
|
|
|
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
|
|
}
|
|
|
|
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 := ZosFdToPath(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 Err2ad() (eadd *int) {
|
|
r0, _, _ := CallLeFuncWithErr(GetZosLibVec() + SYS___ERR2AD<<4)
|
|
eadd = (*int)(unsafe.Pointer(r0))
|
|
return
|
|
}
|
|
|
|
func ZosConsolePrintf(format string, v ...interface{}) (int, error) {
|
|
type __cmsg struct {
|
|
_ uint16
|
|
_ [2]uint8
|
|
__msg_length uint32
|
|
__msg uintptr
|
|
_ [4]uint8
|
|
}
|
|
msg := fmt.Sprintf(format, v...)
|
|
strptr := unsafe.Pointer((*reflect.StringHeader)(unsafe.Pointer(&msg)).Data)
|
|
len := (*reflect.StringHeader)(unsafe.Pointer(&msg)).Len
|
|
cmsg := __cmsg{__msg_length: uint32(len), __msg: uintptr(strptr)}
|
|
cmd := uint32(0)
|
|
runtime.EnterSyscall()
|
|
rc, err2, err1 := CallLeFuncWithErr(GetZosLibVec()+SYS_____CONSOLE_A<<4, uintptr(unsafe.Pointer(&cmsg)), 0, uintptr(unsafe.Pointer(&cmd)))
|
|
runtime.ExitSyscall()
|
|
if rc != 0 {
|
|
return 0, fmt.Errorf("%s (errno2=0x%x)\n", err1.Error(), err2)
|
|
}
|
|
return 0, nil
|
|
}
|
|
func ZosStringToEbcdicBytes(str string, nullterm bool) (ebcdicBytes []byte) {
|
|
if nullterm {
|
|
ebcdicBytes = []byte(str + "\x00")
|
|
} else {
|
|
ebcdicBytes = []byte(str)
|
|
}
|
|
A2e(ebcdicBytes)
|
|
return
|
|
}
|
|
func ZosEbcdicBytesToString(b []byte, trimRight bool) (str string) {
|
|
res := make([]byte, len(b))
|
|
copy(res, b)
|
|
E2a(res)
|
|
if trimRight {
|
|
str = string(bytes.TrimRight(res, " \x00"))
|
|
} else {
|
|
str = string(res)
|
|
}
|
|
return
|
|
}
|
|
|
|
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 impl_Mkfifoat(dirfd int, path string, mode uint32) (err error) {
|
|
var _p0 *byte
|
|
_p0, err = BytePtrFromString(path)
|
|
if err != nil {
|
|
return
|
|
}
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS___MKFIFOAT_A<<4, uintptr(dirfd), uintptr(unsafe.Pointer(_p0)), uintptr(mode))
|
|
runtime.ExitSyscall()
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
//go:nosplit
|
|
func get_MkfifoatAddr() *(func(dirfd int, path string, mode uint32) (err error))
|
|
|
|
var Mkfifoat = enter_Mkfifoat
|
|
|
|
func enter_Mkfifoat(dirfd int, path string, mode uint32) (err error) {
|
|
funcref := get_MkfifoatAddr()
|
|
if funcptrtest(GetZosLibVec()+SYS___MKFIFOAT_A<<4, "") == 0 {
|
|
*funcref = impl_Mkfifoat
|
|
} else {
|
|
*funcref = legacy_Mkfifoat
|
|
}
|
|
return (*funcref)(dirfd, path, mode)
|
|
}
|
|
|
|
func legacy_Mkfifoat(dirfd int, path string, mode uint32) (err error) {
|
|
dirname, err := ZosFdToPath(dirfd)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return Mkfifo(dirname+"/"+path, mode)
|
|
}
|
|
|
|
//sys Posix_openpt(oflag int) (fd int, err error) = SYS_POSIX_OPENPT
|
|
//sys Grantpt(fildes int) (rc int, err error) = SYS_GRANTPT
|
|
//sys Unlockpt(fildes int) (rc int, err error) = SYS_UNLOCKPT
|
|
|
|
func fcntlAsIs(fd uintptr, cmd int, arg uintptr) (val int, err error) {
|
|
runtime.EnterSyscall()
|
|
r0, e2, e1 := CallLeFuncWithErr(GetZosLibVec()+SYS_FCNTL<<4, uintptr(fd), uintptr(cmd), arg)
|
|
runtime.ExitSyscall()
|
|
val = int(r0)
|
|
if int64(r0) == -1 {
|
|
err = errnoErr2(e1, e2)
|
|
}
|
|
return
|
|
}
|
|
|
|
func Fcntl(fd uintptr, cmd int, op interface{}) (ret int, err error) {
|
|
switch op.(type) {
|
|
case *Flock_t:
|
|
err = FcntlFlock(fd, cmd, op.(*Flock_t))
|
|
if err != nil {
|
|
ret = -1
|
|
}
|
|
return
|
|
case int:
|
|
return FcntlInt(fd, cmd, op.(int))
|
|
case *F_cnvrt:
|
|
return fcntlAsIs(fd, cmd, uintptr(unsafe.Pointer(op.(*F_cnvrt))))
|
|
case unsafe.Pointer:
|
|
return fcntlAsIs(fd, cmd, uintptr(op.(unsafe.Pointer)))
|
|
default:
|
|
return -1, EINVAL
|
|
}
|
|
return
|
|
}
|
|
|
|
func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
|
if raceenabled {
|
|
raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
}
|
|
return sendfile(outfd, infd, offset, count)
|
|
}
|
|
|
|
func sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
|
|
// TODO: use LE call instead if the call is implemented
|
|
originalOffset, err := Seek(infd, 0, SEEK_CUR)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
//start reading data from in_fd
|
|
if offset != nil {
|
|
_, err := Seek(infd, *offset, SEEK_SET)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
}
|
|
|
|
buf := make([]byte, count)
|
|
readBuf := make([]byte, 0)
|
|
var n int = 0
|
|
for i := 0; i < count; i += n {
|
|
n, err := Read(infd, buf)
|
|
if n == 0 {
|
|
if err != nil {
|
|
return -1, err
|
|
} else { // EOF
|
|
break
|
|
}
|
|
}
|
|
readBuf = append(readBuf, buf...)
|
|
buf = buf[0:0]
|
|
}
|
|
|
|
n2, err := Write(outfd, readBuf)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
|
|
//When sendfile() returns, this variable will be set to the
|
|
// offset of the byte following the last byte that was read.
|
|
if offset != nil {
|
|
*offset = *offset + int64(n)
|
|
// If offset is not NULL, then sendfile() does not modify the file
|
|
// offset of in_fd
|
|
_, err := Seek(infd, originalOffset, SEEK_SET)
|
|
if err != nil {
|
|
return -1, err
|
|
}
|
|
}
|
|
return n2, nil
|
|
}
|