|
@@ -13,7 +13,6 @@ package unix
|
|
|
|
|
|
import (
|
|
|
"encoding/binary"
|
|
|
- "net"
|
|
|
"runtime"
|
|
|
"syscall"
|
|
|
"unsafe"
|
|
@@ -39,6 +38,20 @@ func Creat(path string, mode uint32) (fd int, err error) {
|
|
|
return Open(path, O_CREAT|O_WRONLY|O_TRUNC, mode)
|
|
|
}
|
|
|
|
|
|
+//sys FanotifyInit(flags uint, event_f_flags uint) (fd int, err error)
|
|
|
+//sys fanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname *byte) (err error)
|
|
|
+
|
|
|
+func FanotifyMark(fd int, flags uint, mask uint64, dirFd int, pathname string) (err error) {
|
|
|
+ if pathname == "" {
|
|
|
+ return fanotifyMark(fd, flags, mask, dirFd, nil)
|
|
|
+ }
|
|
|
+ p, err := BytePtrFromString(pathname)
|
|
|
+ if err != nil {
|
|
|
+ return err
|
|
|
+ }
|
|
|
+ return fanotifyMark(fd, flags, mask, dirFd, p)
|
|
|
+}
|
|
|
+
|
|
|
//sys fchmodat(dirfd int, path string, mode uint32) (err error)
|
|
|
|
|
|
func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
@@ -58,6 +71,17 @@ func Fchmodat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
|
// ioctl itself should not be exposed directly, but additional get/set
|
|
|
// functions for specific types are permissible.
|
|
|
|
|
|
+// IoctlRetInt performs an ioctl operation specified by req on a device
|
|
|
+// associated with opened file descriptor fd, and returns a non-negative
|
|
|
+// integer that is returned by the ioctl syscall.
|
|
|
+func IoctlRetInt(fd int, req uint) (int, error) {
|
|
|
+ ret, _, err := Syscall(SYS_IOCTL, uintptr(fd), uintptr(req), 0)
|
|
|
+ if err != 0 {
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ return int(ret), nil
|
|
|
+}
|
|
|
+
|
|
|
// IoctlSetPointerInt performs an ioctl operation which sets an
|
|
|
// integer value on fd, using the specified request number. The ioctl
|
|
|
// argument is called with a pointer to the integer value, rather than
|
|
@@ -67,44 +91,22 @@ func IoctlSetPointerInt(fd int, req uint, value int) error {
|
|
|
return ioctl(fd, req, uintptr(unsafe.Pointer(&v)))
|
|
|
}
|
|
|
|
|
|
-// IoctlSetInt performs an ioctl operation which sets an integer value
|
|
|
-// on fd, using the specified request number.
|
|
|
-func IoctlSetInt(fd int, req uint, value int) error {
|
|
|
- return ioctl(fd, req, uintptr(value))
|
|
|
-}
|
|
|
-
|
|
|
-func ioctlSetWinsize(fd int, req uint, value *Winsize) error {
|
|
|
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
|
|
-}
|
|
|
-
|
|
|
-func ioctlSetTermios(fd int, req uint, value *Termios) error {
|
|
|
- return ioctl(fd, req, uintptr(unsafe.Pointer(value)))
|
|
|
-}
|
|
|
-
|
|
|
func IoctlSetRTCTime(fd int, value *RTCTime) error {
|
|
|
err := ioctl(fd, RTC_SET_TIME, uintptr(unsafe.Pointer(value)))
|
|
|
runtime.KeepAlive(value)
|
|
|
return err
|
|
|
}
|
|
|
|
|
|
-// IoctlGetInt performs an ioctl operation which gets an integer value
|
|
|
-// from fd, using the specified request number.
|
|
|
-func IoctlGetInt(fd int, req uint) (int, error) {
|
|
|
- var value int
|
|
|
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
|
|
- return value, err
|
|
|
-}
|
|
|
-
|
|
|
-func IoctlGetWinsize(fd int, req uint) (*Winsize, error) {
|
|
|
- var value Winsize
|
|
|
- err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
|
|
- return &value, err
|
|
|
+func IoctlSetRTCWkAlrm(fd int, value *RTCWkAlrm) error {
|
|
|
+ err := ioctl(fd, RTC_WKALM_SET, uintptr(unsafe.Pointer(value)))
|
|
|
+ runtime.KeepAlive(value)
|
|
|
+ return err
|
|
|
}
|
|
|
|
|
|
-func IoctlGetTermios(fd int, req uint) (*Termios, error) {
|
|
|
- var value Termios
|
|
|
+func IoctlGetUint32(fd int, req uint) (uint32, error) {
|
|
|
+ var value uint32
|
|
|
err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
|
|
|
- return &value, err
|
|
|
+ return value, err
|
|
|
}
|
|
|
|
|
|
func IoctlGetRTCTime(fd int) (*RTCTime, error) {
|
|
@@ -113,6 +115,12 @@ func IoctlGetRTCTime(fd int) (*RTCTime, error) {
|
|
|
return &value, err
|
|
|
}
|
|
|
|
|
|
+func IoctlGetRTCWkAlrm(fd int) (*RTCWkAlrm, error) {
|
|
|
+ var value RTCWkAlrm
|
|
|
+ err := ioctl(fd, RTC_WKALM_RD, uintptr(unsafe.Pointer(&value)))
|
|
|
+ return &value, err
|
|
|
+}
|
|
|
+
|
|
|
//sys Linkat(olddirfd int, oldpath string, newdirfd int, newpath string, flags int) (err error)
|
|
|
|
|
|
func Link(oldpath string, newpath string) (err error) {
|
|
@@ -745,7 +753,7 @@ const px_proto_oe = 0
|
|
|
|
|
|
type SockaddrPPPoE struct {
|
|
|
SID uint16
|
|
|
- Remote net.HardwareAddr
|
|
|
+ Remote []byte
|
|
|
Dev string
|
|
|
raw RawSockaddrPPPoX
|
|
|
}
|
|
@@ -779,6 +787,104 @@ func (sa *SockaddrPPPoE) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
|
return unsafe.Pointer(&sa.raw), SizeofSockaddrPPPoX, nil
|
|
|
}
|
|
|
|
|
|
+// SockaddrTIPC implements the Sockaddr interface for AF_TIPC type sockets.
|
|
|
+// For more information on TIPC, see: http://tipc.sourceforge.net/.
|
|
|
+type SockaddrTIPC struct {
|
|
|
+ // Scope is the publication scopes when binding service/service range.
|
|
|
+ // Should be set to TIPC_CLUSTER_SCOPE or TIPC_NODE_SCOPE.
|
|
|
+ Scope int
|
|
|
+
|
|
|
+ // Addr is the type of address used to manipulate a socket. Addr must be
|
|
|
+ // one of:
|
|
|
+ // - *TIPCSocketAddr: "id" variant in the C addr union
|
|
|
+ // - *TIPCServiceRange: "nameseq" variant in the C addr union
|
|
|
+ // - *TIPCServiceName: "name" variant in the C addr union
|
|
|
+ //
|
|
|
+ // If nil, EINVAL will be returned when the structure is used.
|
|
|
+ Addr TIPCAddr
|
|
|
+
|
|
|
+ raw RawSockaddrTIPC
|
|
|
+}
|
|
|
+
|
|
|
+// TIPCAddr is implemented by types that can be used as an address for
|
|
|
+// SockaddrTIPC. It is only implemented by *TIPCSocketAddr, *TIPCServiceRange,
|
|
|
+// and *TIPCServiceName.
|
|
|
+type TIPCAddr interface {
|
|
|
+ tipcAddrtype() uint8
|
|
|
+ tipcAddr() [12]byte
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *TIPCSocketAddr) tipcAddr() [12]byte {
|
|
|
+ var out [12]byte
|
|
|
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCSocketAddr{})]byte)(unsafe.Pointer(sa)))[:])
|
|
|
+ return out
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *TIPCSocketAddr) tipcAddrtype() uint8 { return TIPC_SOCKET_ADDR }
|
|
|
+
|
|
|
+func (sa *TIPCServiceRange) tipcAddr() [12]byte {
|
|
|
+ var out [12]byte
|
|
|
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCServiceRange{})]byte)(unsafe.Pointer(sa)))[:])
|
|
|
+ return out
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *TIPCServiceRange) tipcAddrtype() uint8 { return TIPC_SERVICE_RANGE }
|
|
|
+
|
|
|
+func (sa *TIPCServiceName) tipcAddr() [12]byte {
|
|
|
+ var out [12]byte
|
|
|
+ copy(out[:], (*(*[unsafe.Sizeof(TIPCServiceName{})]byte)(unsafe.Pointer(sa)))[:])
|
|
|
+ return out
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *TIPCServiceName) tipcAddrtype() uint8 { return TIPC_SERVICE_ADDR }
|
|
|
+
|
|
|
+func (sa *SockaddrTIPC) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
|
+ if sa.Addr == nil {
|
|
|
+ return nil, 0, EINVAL
|
|
|
+ }
|
|
|
+
|
|
|
+ sa.raw.Family = AF_TIPC
|
|
|
+ sa.raw.Scope = int8(sa.Scope)
|
|
|
+ sa.raw.Addrtype = sa.Addr.tipcAddrtype()
|
|
|
+ sa.raw.Addr = sa.Addr.tipcAddr()
|
|
|
+
|
|
|
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrTIPC, nil
|
|
|
+}
|
|
|
+
|
|
|
+// SockaddrL2TPIP implements the Sockaddr interface for IPPROTO_L2TP/AF_INET sockets.
|
|
|
+type SockaddrL2TPIP struct {
|
|
|
+ Addr [4]byte
|
|
|
+ ConnId uint32
|
|
|
+ raw RawSockaddrL2TPIP
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *SockaddrL2TPIP) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
|
+ sa.raw.Family = AF_INET
|
|
|
+ sa.raw.Conn_id = sa.ConnId
|
|
|
+ for i := 0; i < len(sa.Addr); i++ {
|
|
|
+ sa.raw.Addr[i] = sa.Addr[i]
|
|
|
+ }
|
|
|
+ return unsafe.Pointer(&sa.raw), SizeofSockaddrL2TPIP, nil
|
|
|
+}
|
|
|
+
|
|
|
+// SockaddrL2TPIP6 implements the Sockaddr interface for IPPROTO_L2TP/AF_INET6 sockets.
|
|
|
+type SockaddrL2TPIP6 struct {
|
|
|
+ Addr [16]byte
|
|
|
+ ZoneId uint32
|
|
|
+ ConnId uint32
|
|
|
+ raw RawSockaddrL2TPIP6
|
|
|
+}
|
|
|
+
|
|
|
+func (sa *SockaddrL2TPIP6) sockaddr() (unsafe.Pointer, _Socklen, error) {
|
|
|
+ sa.raw.Family = AF_INET6
|
|
|
+ sa.raw.Conn_id = sa.ConnId
|
|
|
+ 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), SizeofSockaddrL2TPIP6, nil
|
|
|
+}
|
|
|
+
|
|
|
func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|
|
switch rsa.Addr.Family {
|
|
|
case AF_NETLINK:
|
|
@@ -824,30 +930,63 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|
|
for n < len(pp.Path) && pp.Path[n] != 0 {
|
|
|
n++
|
|
|
}
|
|
|
- bytes := (*[10000]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
|
|
+ bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
|
|
|
sa.Name = string(bytes)
|
|
|
return sa, nil
|
|
|
|
|
|
case AF_INET:
|
|
|
- pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
|
|
|
- sa := new(SockaddrInet4)
|
|
|
- p := (*[2]byte)(unsafe.Pointer(&pp.Port))
|
|
|
- sa.Port = int(p[0])<<8 + int(p[1])
|
|
|
- for i := 0; i < len(sa.Addr); i++ {
|
|
|
- sa.Addr[i] = pp.Addr[i]
|
|
|
+ proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ switch proto {
|
|
|
+ case IPPROTO_L2TP:
|
|
|
+ pp := (*RawSockaddrL2TPIP)(unsafe.Pointer(rsa))
|
|
|
+ sa := new(SockaddrL2TPIP)
|
|
|
+ sa.ConnId = pp.Conn_id
|
|
|
+ for i := 0; i < len(sa.Addr); i++ {
|
|
|
+ sa.Addr[i] = pp.Addr[i]
|
|
|
+ }
|
|
|
+ return sa, nil
|
|
|
+ default:
|
|
|
+ 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
|
|
|
}
|
|
|
- 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]
|
|
|
+ proto, err := GetsockoptInt(fd, SOL_SOCKET, SO_PROTOCOL)
|
|
|
+ if err != nil {
|
|
|
+ return nil, err
|
|
|
+ }
|
|
|
+
|
|
|
+ switch proto {
|
|
|
+ case IPPROTO_L2TP:
|
|
|
+ pp := (*RawSockaddrL2TPIP6)(unsafe.Pointer(rsa))
|
|
|
+ sa := new(SockaddrL2TPIP6)
|
|
|
+ sa.ConnId = pp.Conn_id
|
|
|
+ sa.ZoneId = pp.Scope_id
|
|
|
+ for i := 0; i < len(sa.Addr); i++ {
|
|
|
+ sa.Addr[i] = pp.Addr[i]
|
|
|
+ }
|
|
|
+ return sa, nil
|
|
|
+ default:
|
|
|
+ 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 sa, nil
|
|
|
|
|
|
case AF_VSOCK:
|
|
|
pp := (*RawSockaddrVM)(unsafe.Pointer(rsa))
|
|
@@ -896,7 +1035,7 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|
|
}
|
|
|
sa := &SockaddrPPPoE{
|
|
|
SID: binary.BigEndian.Uint16(pp[6:8]),
|
|
|
- Remote: net.HardwareAddr(pp[8:14]),
|
|
|
+ Remote: pp[8:14],
|
|
|
}
|
|
|
for i := 14; i < 14+IFNAMSIZ; i++ {
|
|
|
if pp[i] == 0 {
|
|
@@ -904,6 +1043,27 @@ func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
|
|
|
break
|
|
|
}
|
|
|
}
|
|
|
+ return sa, nil
|
|
|
+ case AF_TIPC:
|
|
|
+ pp := (*RawSockaddrTIPC)(unsafe.Pointer(rsa))
|
|
|
+
|
|
|
+ sa := &SockaddrTIPC{
|
|
|
+ Scope: int(pp.Scope),
|
|
|
+ }
|
|
|
+
|
|
|
+ // Determine which union variant is present in pp.Addr by checking
|
|
|
+ // pp.Addrtype.
|
|
|
+ switch pp.Addrtype {
|
|
|
+ case TIPC_SERVICE_RANGE:
|
|
|
+ sa.Addr = (*TIPCServiceRange)(unsafe.Pointer(&pp.Addr))
|
|
|
+ case TIPC_SERVICE_ADDR:
|
|
|
+ sa.Addr = (*TIPCServiceName)(unsafe.Pointer(&pp.Addr))
|
|
|
+ case TIPC_SOCKET_ADDR:
|
|
|
+ sa.Addr = (*TIPCSocketAddr)(unsafe.Pointer(&pp.Addr))
|
|
|
+ default:
|
|
|
+ return nil, EINVAL
|
|
|
+ }
|
|
|
+
|
|
|
return sa, nil
|
|
|
}
|
|
|
return nil, EAFNOSUPPORT
|
|
@@ -990,10 +1150,28 @@ func GetsockoptString(fd, level, opt int) (string, error) {
|
|
|
return string(buf[:vallen-1]), nil
|
|
|
}
|
|
|
|
|
|
+func GetsockoptTpacketStats(fd, level, opt int) (*TpacketStats, error) {
|
|
|
+ var value TpacketStats
|
|
|
+ vallen := _Socklen(SizeofTpacketStats)
|
|
|
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
|
+ return &value, err
|
|
|
+}
|
|
|
+
|
|
|
+func GetsockoptTpacketStatsV3(fd, level, opt int) (*TpacketStatsV3, error) {
|
|
|
+ var value TpacketStatsV3
|
|
|
+ vallen := _Socklen(SizeofTpacketStatsV3)
|
|
|
+ err := getsockopt(fd, level, opt, unsafe.Pointer(&value), &vallen)
|
|
|
+ return &value, err
|
|
|
+}
|
|
|
+
|
|
|
func SetsockoptIPMreqn(fd, level, opt int, mreq *IPMreqn) (err error) {
|
|
|
return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
|
|
}
|
|
|
|
|
|
+func SetsockoptPacketMreq(fd, level, opt int, mreq *PacketMreq) error {
|
|
|
+ return setsockopt(fd, level, opt, unsafe.Pointer(mreq), unsafe.Sizeof(*mreq))
|
|
|
+}
|
|
|
+
|
|
|
// SetsockoptSockFprog attaches a classic BPF or an extended BPF program to a
|
|
|
// socket to filter incoming packets. See 'man 7 socket' for usage information.
|
|
|
func SetsockoptSockFprog(fd, level, opt int, fprog *SockFprog) error {
|
|
@@ -1008,6 +1186,14 @@ func SetsockoptCanRawFilter(fd, level, opt int, filter []CanFilter) error {
|
|
|
return setsockopt(fd, level, opt, p, uintptr(len(filter)*SizeofCanFilter))
|
|
|
}
|
|
|
|
|
|
+func SetsockoptTpacketReq(fd, level, opt int, tp *TpacketReq) error {
|
|
|
+ return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
|
|
|
+}
|
|
|
+
|
|
|
+func SetsockoptTpacketReq3(fd, level, opt int, tp *TpacketReq3) error {
|
|
|
+ return setsockopt(fd, level, opt, unsafe.Pointer(tp), unsafe.Sizeof(*tp))
|
|
|
+}
|
|
|
+
|
|
|
// Keyctl Commands (http://man7.org/linux/man-pages/man2/keyctl.2.html)
|
|
|
|
|
|
// KeyctlInt calls keyctl commands in which each argument is an int.
|
|
@@ -1115,6 +1301,34 @@ func KeyctlDHCompute(params *KeyctlDHParams, buffer []byte) (size int, err error
|
|
|
return keyctlDH(KEYCTL_DH_COMPUTE, params, buffer)
|
|
|
}
|
|
|
|
|
|
+// KeyctlRestrictKeyring implements the KEYCTL_RESTRICT_KEYRING command. This
|
|
|
+// command limits the set of keys that can be linked to the keyring, regardless
|
|
|
+// of keyring permissions. The command requires the "setattr" permission.
|
|
|
+//
|
|
|
+// When called with an empty keyType the command locks the keyring, preventing
|
|
|
+// any further keys from being linked to the keyring.
|
|
|
+//
|
|
|
+// The "asymmetric" keyType defines restrictions requiring key payloads to be
|
|
|
+// DER encoded X.509 certificates signed by keys in another keyring. Restrictions
|
|
|
+// for "asymmetric" include "builtin_trusted", "builtin_and_secondary_trusted",
|
|
|
+// "key_or_keyring:<key>", and "key_or_keyring:<key>:chain".
|
|
|
+//
|
|
|
+// As of Linux 4.12, only the "asymmetric" keyType defines type-specific
|
|
|
+// restrictions.
|
|
|
+//
|
|
|
+// See the full documentation at:
|
|
|
+// http://man7.org/linux/man-pages/man3/keyctl_restrict_keyring.3.html
|
|
|
+// http://man7.org/linux/man-pages/man2/keyctl.2.html
|
|
|
+func KeyctlRestrictKeyring(ringid int, keyType string, restriction string) error {
|
|
|
+ if keyType == "" {
|
|
|
+ return keyctlRestrictKeyring(KEYCTL_RESTRICT_KEYRING, ringid)
|
|
|
+ }
|
|
|
+ return keyctlRestrictKeyringByType(KEYCTL_RESTRICT_KEYRING, ringid, keyType, restriction)
|
|
|
+}
|
|
|
+
|
|
|
+//sys keyctlRestrictKeyringByType(cmd int, arg2 int, keyType string, restriction string) (err error) = SYS_KEYCTL
|
|
|
+//sys keyctlRestrictKeyring(cmd int, arg2 int) (err error) = SYS_KEYCTL
|
|
|
+
|
|
|
func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
|
|
|
var msg Msghdr
|
|
|
var rsa RawSockaddrAny
|
|
@@ -1358,8 +1572,12 @@ func PtraceSyscall(pid int, signal int) (err error) {
|
|
|
|
|
|
func PtraceSingleStep(pid int) (err error) { return ptrace(PTRACE_SINGLESTEP, pid, 0, 0) }
|
|
|
|
|
|
+func PtraceInterrupt(pid int) (err error) { return ptrace(PTRACE_INTERRUPT, pid, 0, 0) }
|
|
|
+
|
|
|
func PtraceAttach(pid int) (err error) { return ptrace(PTRACE_ATTACH, pid, 0, 0) }
|
|
|
|
|
|
+func PtraceSeize(pid int) (err error) { return ptrace(PTRACE_SEIZE, pid, 0, 0) }
|
|
|
+
|
|
|
func PtraceDetach(pid int) (err error) { return ptrace(PTRACE_DETACH, pid, 0, 0) }
|
|
|
|
|
|
//sys reboot(magic1 uint, magic2 uint, cmd int, arg string) (err error)
|
|
@@ -1368,8 +1586,20 @@ func Reboot(cmd int) (err error) {
|
|
|
return reboot(LINUX_REBOOT_MAGIC1, LINUX_REBOOT_MAGIC2, cmd, "")
|
|
|
}
|
|
|
|
|
|
-func ReadDirent(fd int, buf []byte) (n int, err error) {
|
|
|
- return Getdents(fd, buf)
|
|
|
+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
|
|
|
}
|
|
|
|
|
|
//sys mount(source string, target string, fstype string, flags uintptr, data *byte) (err error)
|
|
@@ -1404,6 +1634,8 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|
|
//sys Acct(path string) (err error)
|
|
|
//sys AddKey(keyType string, description string, payload []byte, ringid int) (id int, err error)
|
|
|
//sys Adjtimex(buf *Timex) (state int, err error)
|
|
|
+//sysnb Capget(hdr *CapUserHeader, data *CapUserData) (err error)
|
|
|
+//sysnb Capset(hdr *CapUserHeader, data *CapUserData) (err error)
|
|
|
//sys Chdir(path string) (err error)
|
|
|
//sys Chroot(path string) (err error)
|
|
|
//sys ClockGetres(clockid int32, res *Timespec) (err error)
|
|
@@ -1413,6 +1645,15 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|
|
//sys CopyFileRange(rfd int, roff *int64, wfd int, woff *int64, len int, flags int) (n int, err error)
|
|
|
//sys DeleteModule(name string, flags int) (err error)
|
|
|
//sys Dup(oldfd int) (fd int, err error)
|
|
|
+
|
|
|
+func Dup2(oldfd, newfd int) error {
|
|
|
+ // Android O and newer blocks dup2; riscv and arm64 don't implement dup2.
|
|
|
+ if runtime.GOOS == "android" || runtime.GOARCH == "riscv64" || runtime.GOARCH == "arm64" {
|
|
|
+ return Dup3(oldfd, newfd, 0)
|
|
|
+ }
|
|
|
+ return dup2(oldfd, newfd)
|
|
|
+}
|
|
|
+
|
|
|
//sys Dup3(oldfd int, newfd int, flags int) (err error)
|
|
|
//sysnb EpollCreate1(flag int) (fd int, err error)
|
|
|
//sysnb EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error)
|
|
@@ -1422,7 +1663,6 @@ func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err e
|
|
|
//sys Fchdir(fd int) (err error)
|
|
|
//sys Fchmod(fd int, mode uint32) (err error)
|
|
|
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
|
|
|
-//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
|
|
//sys Fdatasync(fd int) (err error)
|
|
|
//sys Fgetxattr(fd int, attr string, dest []byte) (sz int, err error)
|
|
|
//sys FinitModule(fd int, params string, flags int) (err error)
|
|
@@ -1478,6 +1718,17 @@ func Getpgrp() (pid int) {
|
|
|
//sysnb Settimeofday(tv *Timeval) (err error)
|
|
|
//sys Setns(fd int, nstype int) (err error)
|
|
|
|
|
|
+// PrctlRetInt performs a prctl operation specified by option and further
|
|
|
+// optional arguments arg2 through arg5 depending on option. It returns a
|
|
|
+// non-negative integer that is returned by the prctl syscall.
|
|
|
+func PrctlRetInt(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (int, error) {
|
|
|
+ ret, _, err := Syscall6(SYS_PRCTL, uintptr(option), uintptr(arg2), uintptr(arg3), uintptr(arg4), uintptr(arg5), 0)
|
|
|
+ if err != 0 {
|
|
|
+ return 0, err
|
|
|
+ }
|
|
|
+ return int(ret), nil
|
|
|
+}
|
|
|
+
|
|
|
// issue 1435.
|
|
|
// On linux Setuid and Setgid only affects the current thread, not the process.
|
|
|
// This does not match what most callers expect so we must return an error
|
|
@@ -1491,14 +1742,45 @@ func Setgid(uid int) (err error) {
|
|
|
return EOPNOTSUPP
|
|
|
}
|
|
|
|
|
|
+// SetfsgidRetGid sets fsgid for current thread and returns previous fsgid set.
|
|
|
+// setfsgid(2) will return a non-nil error only if its caller lacks CAP_SETUID capability.
|
|
|
+// If the call fails due to other reasons, current fsgid will be returned.
|
|
|
+func SetfsgidRetGid(gid int) (int, error) {
|
|
|
+ return setfsgid(gid)
|
|
|
+}
|
|
|
+
|
|
|
+// SetfsuidRetUid sets fsuid for current thread and returns previous fsuid set.
|
|
|
+// setfsgid(2) will return a non-nil error only if its caller lacks CAP_SETUID capability
|
|
|
+// If the call fails due to other reasons, current fsuid will be returned.
|
|
|
+func SetfsuidRetUid(uid int) (int, error) {
|
|
|
+ return setfsuid(uid)
|
|
|
+}
|
|
|
+
|
|
|
+func Setfsgid(gid int) error {
|
|
|
+ _, err := setfsgid(gid)
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func Setfsuid(uid int) error {
|
|
|
+ _, err := setfsuid(uid)
|
|
|
+ return err
|
|
|
+}
|
|
|
+
|
|
|
+func Signalfd(fd int, sigmask *Sigset_t, flags int) (newfd int, err error) {
|
|
|
+ return signalfd(fd, sigmask, _C__NSIG/8, flags)
|
|
|
+}
|
|
|
+
|
|
|
//sys Setpriority(which int, who int, prio int) (err error)
|
|
|
//sys Setxattr(path string, attr string, data []byte, flags int) (err error)
|
|
|
-//sys Signalfd(fd int, mask *Sigset_t, flags int) = SYS_SIGNALFD4
|
|
|
+//sys signalfd(fd int, sigmask *Sigset_t, maskSize uintptr, flags int) (newfd int, err error) = SYS_SIGNALFD4
|
|
|
//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error)
|
|
|
//sys Sync()
|
|
|
//sys Syncfs(fd int) (err error)
|
|
|
//sysnb Sysinfo(info *Sysinfo_t) (err error)
|
|
|
//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
|
|
|
+//sysnb TimerfdCreate(clockid int, flags int) (fd int, err error)
|
|
|
+//sysnb TimerfdGettime(fd int, currValue *ItimerSpec) (err error)
|
|
|
+//sysnb TimerfdSettime(fd int, flags int, newValue *ItimerSpec, oldValue *ItimerSpec) (err error)
|
|
|
//sysnb Tgkill(tgid int, tid int, sig syscall.Signal) (err error)
|
|
|
//sysnb Times(tms *Tms) (ticks uintptr, err error)
|
|
|
//sysnb Umask(mask int) (oldmask int)
|
|
@@ -1509,6 +1791,123 @@ func Setgid(uid int) (err error) {
|
|
|
//sys exitThread(code int) (err error) = SYS_EXIT
|
|
|
//sys readlen(fd int, p *byte, np int) (n int, err error) = SYS_READ
|
|
|
//sys writelen(fd int, p *byte, np int) (n int, err error) = SYS_WRITE
|
|
|
+//sys readv(fd int, iovs []Iovec) (n int, err error) = SYS_READV
|
|
|
+//sys writev(fd int, iovs []Iovec) (n int, err error) = SYS_WRITEV
|
|
|
+//sys preadv(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PREADV
|
|
|
+//sys pwritev(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr) (n int, err error) = SYS_PWRITEV
|
|
|
+//sys preadv2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PREADV2
|
|
|
+//sys pwritev2(fd int, iovs []Iovec, offs_l uintptr, offs_h uintptr, flags int) (n int, err error) = SYS_PWRITEV2
|
|
|
+
|
|
|
+func bytes2iovec(bs [][]byte) []Iovec {
|
|
|
+ iovecs := make([]Iovec, len(bs))
|
|
|
+ for i, b := range bs {
|
|
|
+ iovecs[i].SetLen(len(b))
|
|
|
+ if len(b) > 0 {
|
|
|
+ iovecs[i].Base = &b[0]
|
|
|
+ } else {
|
|
|
+ iovecs[i].Base = (*byte)(unsafe.Pointer(&_zero))
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return iovecs
|
|
|
+}
|
|
|
+
|
|
|
+// offs2lohi splits offs into its lower and upper unsigned long. On 64-bit
|
|
|
+// systems, hi will always be 0. On 32-bit systems, offs will be split in half.
|
|
|
+// preadv/pwritev chose this calling convention so they don't need to add a
|
|
|
+// padding-register for alignment on ARM.
|
|
|
+func offs2lohi(offs int64) (lo, hi uintptr) {
|
|
|
+ return uintptr(offs), uintptr(uint64(offs) >> SizeofLong)
|
|
|
+}
|
|
|
+
|
|
|
+func Readv(fd int, iovs [][]byte) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ n, err = readv(fd, iovecs)
|
|
|
+ readvRacedetect(iovecs, n, err)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func Preadv(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ lo, hi := offs2lohi(offset)
|
|
|
+ n, err = preadv(fd, iovecs, lo, hi)
|
|
|
+ readvRacedetect(iovecs, n, err)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func Preadv2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ lo, hi := offs2lohi(offset)
|
|
|
+ n, err = preadv2(fd, iovecs, lo, hi, flags)
|
|
|
+ readvRacedetect(iovecs, n, err)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func readvRacedetect(iovecs []Iovec, n int, err error) {
|
|
|
+ if !raceenabled {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for i := 0; n > 0 && i < len(iovecs); i++ {
|
|
|
+ m := int(iovecs[i].Len)
|
|
|
+ if m > n {
|
|
|
+ m = n
|
|
|
+ }
|
|
|
+ n -= m
|
|
|
+ if m > 0 {
|
|
|
+ raceWriteRange(unsafe.Pointer(iovecs[i].Base), m)
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if err == nil {
|
|
|
+ raceAcquire(unsafe.Pointer(&ioSync))
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+func Writev(fd int, iovs [][]byte) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ if raceenabled {
|
|
|
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
|
+ }
|
|
|
+ n, err = writev(fd, iovecs)
|
|
|
+ writevRacedetect(iovecs, n)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func Pwritev(fd int, iovs [][]byte, offset int64) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ if raceenabled {
|
|
|
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
|
+ }
|
|
|
+ lo, hi := offs2lohi(offset)
|
|
|
+ n, err = pwritev(fd, iovecs, lo, hi)
|
|
|
+ writevRacedetect(iovecs, n)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func Pwritev2(fd int, iovs [][]byte, offset int64, flags int) (n int, err error) {
|
|
|
+ iovecs := bytes2iovec(iovs)
|
|
|
+ if raceenabled {
|
|
|
+ raceReleaseMerge(unsafe.Pointer(&ioSync))
|
|
|
+ }
|
|
|
+ lo, hi := offs2lohi(offset)
|
|
|
+ n, err = pwritev2(fd, iovecs, lo, hi, flags)
|
|
|
+ writevRacedetect(iovecs, n)
|
|
|
+ return n, err
|
|
|
+}
|
|
|
+
|
|
|
+func writevRacedetect(iovecs []Iovec, n int) {
|
|
|
+ if !raceenabled {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ for i := 0; n > 0 && i < len(iovecs); i++ {
|
|
|
+ m := int(iovecs[i].Len)
|
|
|
+ if m > n {
|
|
|
+ m = n
|
|
|
+ }
|
|
|
+ n -= m
|
|
|
+ if m > 0 {
|
|
|
+ raceReadRange(unsafe.Pointer(iovecs[i].Base), m)
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|
|
|
|
|
|
// mmap varies by architecture; see syscall_linux_*.go.
|
|
|
//sys munmap(addr uintptr, length uintptr) (err error)
|
|
@@ -1551,6 +1950,20 @@ func Vmsplice(fd int, iovs []Iovec, flags int) (int, error) {
|
|
|
return int(n), nil
|
|
|
}
|
|
|
|
|
|
+func isGroupMember(gid int) bool {
|
|
|
+ groups, err := Getgroups()
|
|
|
+ if err != nil {
|
|
|
+ return false
|
|
|
+ }
|
|
|
+
|
|
|
+ for _, g := range groups {
|
|
|
+ if g == gid {
|
|
|
+ return true
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false
|
|
|
+}
|
|
|
+
|
|
|
//sys faccessat(dirfd int, path string, mode uint32) (err error)
|
|
|
|
|
|
func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
@@ -1608,7 +2021,7 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
|
gid = Getgid()
|
|
|
}
|
|
|
|
|
|
- if uint32(gid) == st.Gid {
|
|
|
+ if uint32(gid) == st.Gid || isGroupMember(gid) {
|
|
|
fmode = (st.Mode >> 3) & 7
|
|
|
} else {
|
|
|
fmode = st.Mode & 7
|
|
@@ -1622,6 +2035,93 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
|
return EACCES
|
|
|
}
|
|
|
|
|
|
+//sys nameToHandleAt(dirFD int, pathname string, fh *fileHandle, mountID *_C_int, flags int) (err error) = SYS_NAME_TO_HANDLE_AT
|
|
|
+//sys openByHandleAt(mountFD int, fh *fileHandle, flags int) (fd int, err error) = SYS_OPEN_BY_HANDLE_AT
|
|
|
+
|
|
|
+// fileHandle is the argument to nameToHandleAt and openByHandleAt. We
|
|
|
+// originally tried to generate it via unix/linux/types.go with "type
|
|
|
+// fileHandle C.struct_file_handle" but that generated empty structs
|
|
|
+// for mips64 and mips64le. Instead, hard code it for now (it's the
|
|
|
+// same everywhere else) until the mips64 generator issue is fixed.
|
|
|
+type fileHandle struct {
|
|
|
+ Bytes uint32
|
|
|
+ Type int32
|
|
|
+}
|
|
|
+
|
|
|
+// FileHandle represents the C struct file_handle used by
|
|
|
+// name_to_handle_at (see NameToHandleAt) and open_by_handle_at (see
|
|
|
+// OpenByHandleAt).
|
|
|
+type FileHandle struct {
|
|
|
+ *fileHandle
|
|
|
+}
|
|
|
+
|
|
|
+// NewFileHandle constructs a FileHandle.
|
|
|
+func NewFileHandle(handleType int32, handle []byte) FileHandle {
|
|
|
+ const hdrSize = unsafe.Sizeof(fileHandle{})
|
|
|
+ buf := make([]byte, hdrSize+uintptr(len(handle)))
|
|
|
+ copy(buf[hdrSize:], handle)
|
|
|
+ fh := (*fileHandle)(unsafe.Pointer(&buf[0]))
|
|
|
+ fh.Type = handleType
|
|
|
+ fh.Bytes = uint32(len(handle))
|
|
|
+ return FileHandle{fh}
|
|
|
+}
|
|
|
+
|
|
|
+func (fh *FileHandle) Size() int { return int(fh.fileHandle.Bytes) }
|
|
|
+func (fh *FileHandle) Type() int32 { return fh.fileHandle.Type }
|
|
|
+func (fh *FileHandle) Bytes() []byte {
|
|
|
+ n := fh.Size()
|
|
|
+ if n == 0 {
|
|
|
+ return nil
|
|
|
+ }
|
|
|
+ return (*[1 << 30]byte)(unsafe.Pointer(uintptr(unsafe.Pointer(&fh.fileHandle.Type)) + 4))[:n:n]
|
|
|
+}
|
|
|
+
|
|
|
+// NameToHandleAt wraps the name_to_handle_at system call; it obtains
|
|
|
+// a handle for a path name.
|
|
|
+func NameToHandleAt(dirfd int, path string, flags int) (handle FileHandle, mountID int, err error) {
|
|
|
+ var mid _C_int
|
|
|
+ // Try first with a small buffer, assuming the handle will
|
|
|
+ // only be 32 bytes.
|
|
|
+ size := uint32(32 + unsafe.Sizeof(fileHandle{}))
|
|
|
+ didResize := false
|
|
|
+ for {
|
|
|
+ buf := make([]byte, size)
|
|
|
+ fh := (*fileHandle)(unsafe.Pointer(&buf[0]))
|
|
|
+ fh.Bytes = size - uint32(unsafe.Sizeof(fileHandle{}))
|
|
|
+ err = nameToHandleAt(dirfd, path, fh, &mid, flags)
|
|
|
+ if err == EOVERFLOW {
|
|
|
+ if didResize {
|
|
|
+ // We shouldn't need to resize more than once
|
|
|
+ return
|
|
|
+ }
|
|
|
+ didResize = true
|
|
|
+ size = fh.Bytes + uint32(unsafe.Sizeof(fileHandle{}))
|
|
|
+ continue
|
|
|
+ }
|
|
|
+ if err != nil {
|
|
|
+ return
|
|
|
+ }
|
|
|
+ return FileHandle{fh}, int(mid), nil
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+// OpenByHandleAt wraps the open_by_handle_at system call; it opens a
|
|
|
+// file via a handle as previously returned by NameToHandleAt.
|
|
|
+func OpenByHandleAt(mountFD int, handle FileHandle, flags int) (fd int, err error) {
|
|
|
+ return openByHandleAt(mountFD, handle.fileHandle, flags)
|
|
|
+}
|
|
|
+
|
|
|
+// Klogset wraps the sys_syslog system call; it sets console_loglevel to
|
|
|
+// the value specified by arg and passes a dummy pointer to bufp.
|
|
|
+func Klogset(typ int, arg int) (err error) {
|
|
|
+ var p unsafe.Pointer
|
|
|
+ _, _, errno := Syscall(SYS_SYSLOG, uintptr(typ), uintptr(p), uintptr(arg))
|
|
|
+ if errno != 0 {
|
|
|
+ return errnoErr(errno)
|
|
|
+ }
|
|
|
+ return nil
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Unimplemented
|
|
|
*/
|
|
@@ -1629,8 +2129,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
|
// Alarm
|
|
|
// ArchPrctl
|
|
|
// Brk
|
|
|
-// Capget
|
|
|
-// Capset
|
|
|
// ClockNanosleep
|
|
|
// ClockSettime
|
|
|
// Clone
|
|
@@ -1718,7 +2216,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
|
|
// TimerGetoverrun
|
|
|
// TimerGettime
|
|
|
// TimerSettime
|
|
|
-// Timerfd
|
|
|
// Tkill (obsolete)
|
|
|
// Tuxcall
|
|
|
// Umount2
|