aboutsummaryrefslogtreecommitdiff
path: root/libgo/syscalls
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2011-09-16 15:47:21 +0000
commitadb0401dac41c81571722312d4586b2693f95aa6 (patch)
treeea2b52e3c258d6b6d9356977c683c7f72a4a5fd5 /libgo/syscalls
parent5548ca3540bccbc908a45942896d635ea5f1c23f (diff)
downloadgcc-adb0401dac41c81571722312d4586b2693f95aa6.zip
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.gz
gcc-adb0401dac41c81571722312d4586b2693f95aa6.tar.bz2
Update Go library to r60.
From-SVN: r178910
Diffstat (limited to 'libgo/syscalls')
-rw-r--r--libgo/syscalls/exec.go101
-rw-r--r--libgo/syscalls/netlink_linux.go227
-rw-r--r--libgo/syscalls/socket.go4
-rw-r--r--libgo/syscalls/socket_bsd.go4
-rw-r--r--libgo/syscalls/socket_irix.go6
-rw-r--r--libgo/syscalls/socket_linux.go90
-rw-r--r--libgo/syscalls/socket_solaris.go4
-rw-r--r--libgo/syscalls/syscall_linux.go18
8 files changed, 440 insertions, 14 deletions
diff --git a/libgo/syscalls/exec.go b/libgo/syscalls/exec.go
index 450c7e5..04d0ef8 100644
--- a/libgo/syscalls/exec.go
+++ b/libgo/syscalls/exec.go
@@ -13,8 +13,14 @@ import "unsafe"
func libc_fcntl(fd int, cmd int, arg int) int __asm__ ("fcntl")
func libc_fork() Pid_t __asm__ ("fork")
func libc_setsid() Pid_t __asm__ ("setsid")
+func libc_setpgid(Pid_t, Pid_t) int __asm__ ("setpgid")
+func libc_chroot(path *byte) int __asm__ ("chroot")
+func libc_setuid(Uid_t) int __asm__ ("setuid")
+func libc_setgid(Gid_t) int __asm__ ("setgid")
+func libc_setgroups(Size_t, *Gid_t) int __asm__ ("setgroups")
func libc_chdir(name *byte) int __asm__ ("chdir")
func libc_dup2(int, int) int __asm__ ("dup2")
+func libc_ioctl(int, int) int __asm__ ("ioctl")
func libc_execve(*byte, **byte, **byte) int __asm__ ("execve")
func libc_sysexit(int) __asm__ ("_exit")
@@ -24,7 +30,7 @@ func libc_sysexit(int) __asm__ ("_exit")
// In the child, this function must not acquire any locks, because
// they might have been locked at the time of the fork. This means
// no rescheduling, no malloc calls, and no new stack segments.
-func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAttr, pipe int) (pid int, err int) {
+func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr *ProcAttr, sys *SysProcAttr, pipe int) (pid int, err int) {
// Declare all variables at top in case any
// declarations require heap allocation (e.g., err1).
var r1, r2, err1 uintptr
@@ -51,19 +57,51 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt
// Fork succeeded, now in child.
// Enable tracing if requested.
- if attr.Ptrace {
+ if sys.Ptrace {
if libc_ptrace(_PTRACE_TRACEME, 0, 0, nil) < 0 {
goto childerror
}
}
// Session ID
- if attr.Setsid {
+ if sys.Setsid {
if libc_setsid() == Pid_t(-1) {
goto childerror
}
}
+ // Set process group
+ if sys.Setpgid {
+ if libc_setpgid(0, 0) < 0 {
+ goto childerror
+ }
+ }
+
+ // Chroot
+ if chroot != nil {
+ if libc_chroot(chroot) < 0 {
+ goto childerror
+ }
+ }
+
+ // User and groups
+ if cred := sys.Credential; cred != nil {
+ ngroups := uintptr(len(cred.Groups))
+ var groups *Gid_t
+ if ngroups > 0 {
+ groups = (*Gid_t)(unsafe.Pointer(&cred.Groups[0]))
+ }
+ if libc_setgroups(Size_t(ngroups), groups) < 0 {
+ goto childerror
+ }
+ if libc_setgid(Gid_t(cred.Gid)) < 0 {
+ goto childerror
+ }
+ if libc_setuid(Uid_t(cred.Uid)) < 0 {
+ goto childerror
+ }
+ }
+
// Chdir
if dir != nil {
if libc_chdir(dir) < 0 {
@@ -129,6 +167,20 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, dir *byte, attr *ProcAt
libc_close(i)
}
+ // Detach fd 0 from tty
+ if sys.Noctty {
+ if libc_ioctl(0, TIOCNOTTY) < 0 {
+ goto childerror
+ }
+ }
+
+ // Make fd 0 the tty
+ if sys.Setctty {
+ if libc_ioctl(0, TIOCSCTTY) < 0 {
+ goto childerror
+ }
+ }
+
// Time to exec.
libc_execve(argv0, &argv[0], &envv[0])
@@ -147,16 +199,35 @@ childerror:
panic("unreached")
}
+// Credential holds user and group identities to be assumed
+// by a child process started by StartProcess.
+type Credential struct {
+ Uid uint32 // User ID.
+ Gid uint32 // Group ID.
+ Groups []uint32 // Supplementary group IDs.
+}
+// ProcAttr holds attributes that will be applied to a new process started
+// by StartProcess.
type ProcAttr struct {
- Setsid bool // Create session.
- Ptrace bool // Enable tracing.
- Dir string // Current working directory.
- Env []string // Environment.
- Files []int // File descriptors.
+ Dir string // Current working directory.
+ Env []string // Environment.
+ Files []int // File descriptors.
+ Sys *SysProcAttr
}
-var zeroAttributes ProcAttr
+type SysProcAttr struct {
+ Chroot string // Chroot.
+ Credential *Credential // Credential.
+ Ptrace bool // Enable tracing.
+ Setsid bool // Create session.
+ Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setctty bool // Set controlling terminal to fd 0
+ Noctty bool // Detach fd 0 from controlling terminal
+}
+
+var zeroProcAttr ProcAttr
+var zeroSysProcAttr SysProcAttr
func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var p [2]int
@@ -165,7 +236,11 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
var wstatus WaitStatus
if attr == nil {
- attr = &zeroAttributes
+ attr = &zeroProcAttr
+ }
+ sys := attr.Sys
+ if sys == nil {
+ sys = &zeroSysProcAttr
}
p[0] = -1
@@ -180,6 +255,10 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
argvp[0] = argv0p
}
+ var chroot *byte
+ if sys.Chroot != "" {
+ chroot = StringBytePtr(sys.Chroot)
+ }
var dir *byte
if attr.Dir != "" {
dir = StringBytePtr(attr.Dir)
@@ -202,7 +281,7 @@ func forkExec(argv0 string, argv []string, attr *ProcAttr) (pid int, err int) {
}
// Kick off child.
- pid, err = forkAndExecInChild(argv0p, argvp, envvp, dir, attr, p[1])
+ pid, err = forkAndExecInChild(argv0p, argvp, envvp, chroot, dir, attr, sys, p[1])
if err != 0 {
error:
if p[0] >= 0 {
diff --git a/libgo/syscalls/netlink_linux.go b/libgo/syscalls/netlink_linux.go
new file mode 100644
index 0000000..6f621ce
--- /dev/null
+++ b/libgo/syscalls/netlink_linux.go
@@ -0,0 +1,227 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Netlink sockets and messages
+
+package syscall
+
+import (
+ "unsafe"
+)
+
+// Round the length of a netlink message up to align it properly.
+func nlmAlignOf(msglen int) int {
+ return (msglen + NLMSG_ALIGNTO - 1) & ^(NLMSG_ALIGNTO - 1)
+}
+
+// Round the length of a netlink route attribute up to align it
+// properly.
+func rtaAlignOf(attrlen int) int {
+ return (attrlen + RTA_ALIGNTO - 1) & ^(RTA_ALIGNTO - 1)
+}
+
+// NetlinkRouteRequest represents the request message to receive
+// routing and link states from the kernel.
+type NetlinkRouteRequest struct {
+ Header NlMsghdr
+ Data RtGenmsg
+}
+
+func (rr *NetlinkRouteRequest) toWireFormat() []byte {
+ b := make([]byte, rr.Header.Len)
+ b[0] = byte(rr.Header.Len)
+ b[1] = byte(rr.Header.Len >> 8)
+ b[2] = byte(rr.Header.Len >> 16)
+ b[3] = byte(rr.Header.Len >> 24)
+ b[4] = byte(rr.Header.Type)
+ b[5] = byte(rr.Header.Type >> 8)
+ b[6] = byte(rr.Header.Flags)
+ b[7] = byte(rr.Header.Flags >> 8)
+ b[8] = byte(rr.Header.Seq)
+ b[9] = byte(rr.Header.Seq >> 8)
+ b[10] = byte(rr.Header.Seq >> 16)
+ b[11] = byte(rr.Header.Seq >> 24)
+ b[12] = byte(rr.Header.Pid)
+ b[13] = byte(rr.Header.Pid >> 8)
+ b[14] = byte(rr.Header.Pid >> 16)
+ b[15] = byte(rr.Header.Pid >> 24)
+ b[16] = byte(rr.Data.Family)
+ return b
+}
+
+func newNetlinkRouteRequest(proto, seq, family int) []byte {
+ rr := &NetlinkRouteRequest{}
+ rr.Header.Len = uint32(NLMSG_HDRLEN + SizeofRtGenmsg)
+ rr.Header.Type = uint16(proto)
+ rr.Header.Flags = NLM_F_DUMP | NLM_F_REQUEST
+ rr.Header.Seq = uint32(seq)
+ rr.Data.Family = uint8(family)
+ return rr.toWireFormat()
+}
+
+// NetlinkRIB returns routing information base, as known as RIB,
+// which consists of network facility information, states and
+// parameters.
+func NetlinkRIB(proto, family int) ([]byte, int) {
+ var (
+ s int
+ e int
+ lsanl SockaddrNetlink
+ seq int
+ tab []byte
+ )
+
+ s, e = Socket(AF_NETLINK, SOCK_RAW, 0)
+ if e != 0 {
+ return nil, e
+ }
+ defer Close(s)
+
+ lsanl.Family = AF_NETLINK
+ e = Bind(s, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ seq++
+ wb := newNetlinkRouteRequest(proto, seq, family)
+ e = Sendto(s, wb, 0, &lsanl)
+ if e != 0 {
+ return nil, e
+ }
+
+ for {
+ var (
+ rb []byte
+ nr int
+ lsa Sockaddr
+ )
+
+ rb = make([]byte, Getpagesize())
+ nr, _, e = Recvfrom(s, rb, 0)
+ if e != 0 {
+ return nil, e
+ }
+ if nr < NLMSG_HDRLEN {
+ return nil, EINVAL
+ }
+ rb = rb[:nr]
+ tab = append(tab, rb...)
+
+ msgs, _ := ParseNetlinkMessage(rb)
+ for _, m := range msgs {
+ if lsa, e = Getsockname(s); e != 0 {
+ return nil, e
+ }
+ switch v := lsa.(type) {
+ case *SockaddrNetlink:
+ if m.Header.Seq != uint32(seq) || m.Header.Pid != v.Pid {
+ return nil, EINVAL
+ }
+ default:
+ return nil, EINVAL
+ }
+ if m.Header.Type == NLMSG_DONE {
+ goto done
+ }
+ if m.Header.Type == NLMSG_ERROR {
+ return nil, EINVAL
+ }
+ }
+ }
+
+done:
+ return tab, 0
+}
+
+// NetlinkMessage represents the netlink message.
+type NetlinkMessage struct {
+ Header NlMsghdr
+ Data []byte
+}
+
+// ParseNetlinkMessage parses buf as netlink messages and returns
+// the slice containing the NetlinkMessage structs.
+func ParseNetlinkMessage(buf []byte) ([]NetlinkMessage, int) {
+ var (
+ h *NlMsghdr
+ dbuf []byte
+ dlen int
+ e int
+ msgs []NetlinkMessage
+ )
+
+ for len(buf) >= NLMSG_HDRLEN {
+ h, dbuf, dlen, e = netlinkMessageHeaderAndData(buf)
+ if e != 0 {
+ break
+ }
+ m := NetlinkMessage{}
+ m.Header = *h
+ m.Data = dbuf[:int(h.Len)-NLMSG_HDRLEN]
+ msgs = append(msgs, m)
+ buf = buf[dlen:]
+ }
+
+ return msgs, e
+}
+
+func netlinkMessageHeaderAndData(buf []byte) (*NlMsghdr, []byte, int, int) {
+ h := (*NlMsghdr)(unsafe.Pointer(&buf[0]))
+ if int(h.Len) < NLMSG_HDRLEN || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[NLMSG_HDRLEN:], nlmAlignOf(int(h.Len)), 0
+}
+
+// NetlinkRouteAttr represents the netlink route attribute.
+type NetlinkRouteAttr struct {
+ Attr RtAttr
+ Value []byte
+}
+
+// ParseNetlinkRouteAttr parses msg's payload as netlink route
+// attributes and returns the slice containing the NetlinkRouteAttr
+// structs.
+func ParseNetlinkRouteAttr(msg *NetlinkMessage) ([]NetlinkRouteAttr, int) {
+ var (
+ buf []byte
+ a *RtAttr
+ alen int
+ vbuf []byte
+ e int
+ attrs []NetlinkRouteAttr
+ )
+
+ switch msg.Header.Type {
+ case RTM_NEWLINK:
+ buf = msg.Data[SizeofIfInfomsg:]
+ case RTM_NEWADDR:
+ buf = msg.Data[SizeofIfAddrmsg:]
+ default:
+ return nil, EINVAL
+ }
+
+ for len(buf) >= SizeofRtAttr {
+ a, vbuf, alen, e = netlinkRouteAttrAndValue(buf)
+ if e != 0 {
+ break
+ }
+ ra := NetlinkRouteAttr{}
+ ra.Attr = *a
+ ra.Value = vbuf[:int(a.Len)-SizeofRtAttr]
+ attrs = append(attrs, ra)
+ buf = buf[alen:]
+ }
+
+ return attrs, 0
+}
+
+func netlinkRouteAttrAndValue(buf []byte) (*RtAttr, []byte, int, int) {
+ h := (*RtAttr)(unsafe.Pointer(&buf[0]))
+ if int(h.Len) < SizeofRtAttr || int(h.Len) > len(buf) {
+ return nil, nil, 0, EINVAL
+ }
+ return h, buf[SizeofRtAttr:], rtaAlignOf(int(h.Len)), 0
+}
diff --git a/libgo/syscalls/socket.go b/libgo/syscalls/socket.go
index 28581a5..be7a89b 100644
--- a/libgo/syscalls/socket.go
+++ b/libgo/syscalls/socket.go
@@ -131,7 +131,7 @@ func anyToSockaddr(rsa *RawSockaddrAny) (Sockaddr, int) {
}
return sa, 0;
}
- return nil, EAFNOSUPPORT;
+ return anyToSockaddrOS(rsa)
}
func libc_accept(fd int, sa *RawSockaddrAny, len *Socklen_t) int __asm__ ("accept");
@@ -239,7 +239,7 @@ func SetsockoptString(fd, level, opt int, s string) (errno int) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(&[]byte(s)[0])), Socklen_t(len(s)))
}
-func SetsockoptIpMreq(fd, level, opt int, mreq *IpMreq) (errno int) {
+func SetsockoptIPMreq(fd, level, opt int, mreq *IPMreq) (errno int) {
return setsockopt(fd, level, opt, uintptr(unsafe.Pointer(mreq)), unsafe.Sizeof(*mreq))
}
diff --git a/libgo/syscalls/socket_bsd.go b/libgo/syscalls/socket_bsd.go
index f4d06b4..735baf9 100644
--- a/libgo/syscalls/socket_bsd.go
+++ b/libgo/syscalls/socket_bsd.go
@@ -72,3 +72,7 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return ENOSYS
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_irix.go b/libgo/syscalls/socket_irix.go
index e17f164..6f2aaaf 100644
--- a/libgo/syscalls/socket_irix.go
+++ b/libgo/syscalls/socket_irix.go
@@ -78,7 +78,7 @@ func BindToDevice(fd int, device string) (errno int) {
// This could be enabled with -D_SGI_SOURCE, but conflicts with
// -D_XOPEN_SOURCE=500 required for msg_control etc. in struct msghgr, so
// simply provide it here.
-type IpMreq struct {
+type IPMreq struct {
Multiaddr [4]byte
Interface [4]byte
}
@@ -123,3 +123,7 @@ const (
EAI_OVERFLOW = 13
EAI_MAX = 14
)
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_linux.go b/libgo/syscalls/socket_linux.go
index cdcdf4f..57ea7c3 100644
--- a/libgo/syscalls/socket_linux.go
+++ b/libgo/syscalls/socket_linux.go
@@ -6,9 +6,55 @@
package syscall
+import "unsafe"
+
const SizeofSockaddrInet4 = 16
const SizeofSockaddrInet6 = 28
const SizeofSockaddrUnix = 110
+const SizeofSockaddrLinklayer = 20
+const SizeofSockaddrNetlink = 12
+
+type SockaddrLinklayer struct {
+ Protocol uint16
+ Ifindex int
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]byte
+ raw RawSockaddrLinklayer
+}
+
+func (sa *SockaddrLinklayer) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ if sa.Ifindex < 0 || sa.Ifindex > 0x7fffffff {
+ return nil, 0, EINVAL
+ }
+ sa.raw.Family = AF_PACKET
+ sa.raw.Protocol = sa.Protocol
+ sa.raw.Ifindex = int32(sa.Ifindex)
+ sa.raw.Hatype = sa.Hatype
+ sa.raw.Pkttype = sa.Pkttype
+ sa.raw.Halen = sa.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.raw.Addr[i] = sa.Addr[i]
+ }
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrLinklayer, 0
+}
+
+type SockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+ raw RawSockaddrNetlink
+}
+
+func (sa *SockaddrNetlink) sockaddr() (*RawSockaddrAny, Socklen_t, int) {
+ sa.raw.Family = AF_NETLINK
+ sa.raw.Pad = sa.Pad
+ sa.raw.Pid = sa.Pid
+ sa.raw.Groups = sa.Groups
+ return (*RawSockaddrAny)(unsafe.Pointer(&sa.raw)), SizeofSockaddrNetlink, 0
+}
type RawSockaddrInet4 struct {
Family uint16;
@@ -64,6 +110,23 @@ func (sa *RawSockaddrUnix) getLen() (int, int) {
return n, 0
}
+type RawSockaddrLinklayer struct {
+ Family uint16
+ Protocol uint16
+ Ifindex int32
+ Hatype uint16
+ Pkttype uint8
+ Halen uint8
+ Addr [8]uint8
+}
+
+type RawSockaddrNetlink struct {
+ Family uint16
+ Pad uint16
+ Pid uint32
+ Groups uint32
+}
+
type RawSockaddr struct {
Family uint16;
Data [14]int8;
@@ -73,3 +136,30 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return SetsockoptString(fd, SOL_SOCKET, SO_BINDTODEVICE, device)
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ switch rsa.Addr.Family {
+ case AF_NETLINK:
+ pp := (*RawSockaddrNetlink)(unsafe.Pointer(rsa))
+ sa := new(SockaddrNetlink)
+ sa.Family = pp.Family
+ sa.Pad = pp.Pad
+ sa.Pid = pp.Pid
+ sa.Groups = pp.Groups
+ return sa, 0
+
+ case AF_PACKET:
+ pp := (*RawSockaddrLinklayer)(unsafe.Pointer(rsa))
+ sa := new(SockaddrLinklayer)
+ sa.Protocol = pp.Protocol
+ sa.Ifindex = int(pp.Ifindex)
+ sa.Hatype = pp.Hatype
+ sa.Pkttype = pp.Pkttype
+ sa.Halen = pp.Halen
+ for i := 0; i < len(sa.Addr); i++ {
+ sa.Addr[i] = pp.Addr[i]
+ }
+ return sa, 0
+ }
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/socket_solaris.go b/libgo/syscalls/socket_solaris.go
index 13fe727..3767078 100644
--- a/libgo/syscalls/socket_solaris.go
+++ b/libgo/syscalls/socket_solaris.go
@@ -74,3 +74,7 @@ type RawSockaddr struct {
func BindToDevice(fd int, device string) (errno int) {
return ENOSYS
}
+
+func anyToSockaddrOS(rsa *RawSockaddrAny) (Sockaddr, int) {
+ return nil, EAFNOSUPPORT;
+}
diff --git a/libgo/syscalls/syscall_linux.go b/libgo/syscalls/syscall_linux.go
index bdb92c5..29c8b62 100644
--- a/libgo/syscalls/syscall_linux.go
+++ b/libgo/syscalls/syscall_linux.go
@@ -9,6 +9,7 @@ package syscall
import "unsafe"
func libc_ptrace(request int, pid Pid_t, addr uintptr, data *byte) _C_long __asm__ ("ptrace")
+func libc_sendfile(int, int, *Offset_t, Size_t) Ssize_t __asm__ ("sendfile")
var dummy *byte
const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy))
@@ -186,3 +187,20 @@ func Tgkill(tgid int, tid int, sig int) (errno int) {
uintptr(sig));
return int(err);
}
+
+func Sendfile(outfd int, infd int, offset *int64, count int) (written int, errno int) {
+ var o Offset_t
+ var po *Offset_t
+ if offset != nil {
+ o = Offset_t(*offset)
+ po = &o
+ }
+ w := libc_sendfile(outfd, infd, po, Size_t(count))
+ if offset != nil {
+ *offset = int64(o)
+ }
+ if w < 0 {
+ return 0, GetErrno()
+ }
+ return int(w), 0
+}