summaryrefslogtreecommitdiff
path: root/libgo/go/syscall
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-10-31 00:59:47 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-10-31 00:59:47 +0000
commit4a3da3a8a45d5496118798146de1fa4e5798ed5a (patch)
tree13beeaed3698c61903fe93fb1ce70bd9b18d4e7f /libgo/go/syscall
parentcd529f4d86a17a3e8959f2cb5ac7132a841ab6f1 (diff)
downloadgcc-4a3da3a8a45d5496118798146de1fa4e5798ed5a.tar.gz
runtime: Remove now unnecessary pad field from ParFor.
It is not needed due to the removal of the ctx field. Reviewed-on: https://go-review.googlesource.com/16525 git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@229616 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r--libgo/go/syscall/const_plan9.go59
-rw-r--r--libgo/go/syscall/creds_test.go8
-rw-r--r--libgo/go/syscall/env_plan9.go6
-rw-r--r--libgo/go/syscall/env_windows.go20
-rw-r--r--libgo/go/syscall/errors_plan9.go48
-rw-r--r--libgo/go/syscall/exec_bsd.go31
-rw-r--r--libgo/go/syscall/exec_linux.go147
-rw-r--r--libgo/go/syscall/exec_linux_test.go111
-rw-r--r--libgo/go/syscall/exec_solaris_test.go37
-rw-r--r--libgo/go/syscall/exec_unix.go33
-rw-r--r--libgo/go/syscall/exec_unix_test.go215
-rw-r--r--libgo/go/syscall/exec_windows.go19
-rw-r--r--libgo/go/syscall/export_unix_test.go12
-rw-r--r--libgo/go/syscall/pwd_plan9.go83
-rw-r--r--libgo/go/syscall/route_bsd.go313
-rw-r--r--libgo/go/syscall/route_bsd_test.go225
-rw-r--r--libgo/go/syscall/route_darwin.go46
-rw-r--r--libgo/go/syscall/route_dragonfly.go50
-rw-r--r--libgo/go/syscall/route_freebsd.go70
-rw-r--r--libgo/go/syscall/route_freebsd_32bit.go13
-rw-r--r--libgo/go/syscall/route_freebsd_64bit.go7
-rw-r--r--libgo/go/syscall/route_ifma_test.go74
-rw-r--r--libgo/go/syscall/route_netbsd.go6
-rw-r--r--libgo/go/syscall/route_noifma_test.go63
-rw-r--r--libgo/go/syscall/route_openbsd.go6
-rw-r--r--libgo/go/syscall/security_windows.go98
-rw-r--r--libgo/go/syscall/syscall.go14
-rw-r--r--libgo/go/syscall/syscall_linux_test.go140
-rw-r--r--libgo/go/syscall/syscall_unix.go24
-rw-r--r--libgo/go/syscall/syscall_unix_test.go70
30 files changed, 1716 insertions, 332 deletions
diff --git a/libgo/go/syscall/const_plan9.go b/libgo/go/syscall/const_plan9.go
new file mode 100644
index 00000000000..ba26f123dea
--- /dev/null
+++ b/libgo/go/syscall/const_plan9.go
@@ -0,0 +1,59 @@
+package syscall
+
+// Plan 9 Constants
+
+// Open modes
+const (
+ O_RDONLY = 0
+ O_WRONLY = 1
+ O_RDWR = 2
+ O_TRUNC = 16
+ O_CLOEXEC = 32
+ O_EXCL = 0x1000
+)
+
+// Rfork flags
+const (
+ RFNAMEG = 1 << 0
+ RFENVG = 1 << 1
+ RFFDG = 1 << 2
+ RFNOTEG = 1 << 3
+ RFPROC = 1 << 4
+ RFMEM = 1 << 5
+ RFNOWAIT = 1 << 6
+ RFCNAMEG = 1 << 10
+ RFCENVG = 1 << 11
+ RFCFDG = 1 << 12
+ RFREND = 1 << 13
+ RFNOMNT = 1 << 14
+)
+
+// Qid.Type bits
+const (
+ QTDIR = 0x80
+ QTAPPEND = 0x40
+ QTEXCL = 0x20
+ QTMOUNT = 0x10
+ QTAUTH = 0x08
+ QTTMP = 0x04
+ QTFILE = 0x00
+)
+
+// Dir.Mode bits
+const (
+ DMDIR = 0x80000000
+ DMAPPEND = 0x40000000
+ DMEXCL = 0x20000000
+ DMMOUNT = 0x10000000
+ DMAUTH = 0x08000000
+ DMTMP = 0x04000000
+ DMREAD = 0x4
+ DMWRITE = 0x2
+ DMEXEC = 0x1
+)
+
+const (
+ STATMAX = 65535
+ ERRMAX = 128
+ STATFIXLEN = 49
+)
diff --git a/libgo/go/syscall/creds_test.go b/libgo/go/syscall/creds_test.go
index b1894c66b07..b4a14ff4dd9 100644
--- a/libgo/go/syscall/creds_test.go
+++ b/libgo/go/syscall/creds_test.go
@@ -56,7 +56,13 @@ func TestSCMCredentials(t *testing.T) {
ucred.Gid = 0
oob := syscall.UnixCredentials(&ucred)
_, _, err := cli.(*net.UnixConn).WriteMsgUnix(nil, oob, nil)
- if err.(*net.OpError).Err != syscall.EPERM {
+ if op, ok := err.(*net.OpError); ok {
+ err = op.Err
+ }
+ if sys, ok := err.(*os.SyscallError); ok {
+ err = sys.Err
+ }
+ if err != syscall.EPERM {
t.Fatalf("WriteMsgUnix failed with %v, want EPERM", err)
}
}
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
index 9ea36c886ab..cbf7f410925 100644
--- a/libgo/go/syscall/env_plan9.go
+++ b/libgo/go/syscall/env_plan9.go
@@ -16,7 +16,7 @@ var (
)
func readenv(key string) (string, error) {
- fd, err := Open("/env/"+key, O_RDONLY)
+ fd, err := open("/env/"+key, O_RDONLY)
if err != nil {
return "", err
}
@@ -35,7 +35,7 @@ func readenv(key string) (string, error) {
}
func writeenv(key, value string) error {
- fd, err := Create("/env/"+key, O_RDWR, 0666)
+ fd, err := create("/env/"+key, O_RDWR, 0666)
if err != nil {
return err
}
@@ -86,7 +86,7 @@ func Unsetenv(key string) error {
}
func Environ() []string {
- fd, err := Open("/env", O_RDONLY)
+ fd, err := open("/env", O_RDONLY)
if err != nil {
return nil
}
diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go
index bc21690d9fd..1cb475428d7 100644
--- a/libgo/go/syscall/env_windows.go
+++ b/libgo/go/syscall/env_windows.go
@@ -16,19 +16,17 @@ func Getenv(key string) (value string, found bool) {
if err != nil {
return "", false
}
- b := make([]uint16, 100)
- n, e := GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
- if n == 0 && e == ERROR_ENVVAR_NOT_FOUND {
- return "", false
- }
- if n > uint32(len(b)) {
- b = make([]uint16, n)
- n, e = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
- if n > uint32(len(b)) {
- n = 0
+ n := uint32(100)
+ for {
+ b := make([]uint16, n)
+ n, err = GetEnvironmentVariable(keyp, &b[0], uint32(len(b)))
+ if n == 0 && err == ERROR_ENVVAR_NOT_FOUND {
+ return "", false
+ }
+ if n <= uint32(len(b)) {
+ return string(utf16.Decode(b[:n])), true
}
}
- return string(utf16.Decode(b[0:n])), true
}
func Setenv(key, value string) error {
diff --git a/libgo/go/syscall/errors_plan9.go b/libgo/go/syscall/errors_plan9.go
new file mode 100644
index 00000000000..ede3d6a329e
--- /dev/null
+++ b/libgo/go/syscall/errors_plan9.go
@@ -0,0 +1,48 @@
+// 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.
+
+package syscall
+
+// Constants
+const (
+ // Invented values to support what package os expects.
+ O_CREAT = 0x02000
+ O_APPEND = 0x00400
+ O_NOCTTY = 0x00000
+ O_NONBLOCK = 0x00000
+ O_SYNC = 0x00000
+ O_ASYNC = 0x00000
+
+ S_IFMT = 0x1f000
+ S_IFIFO = 0x1000
+ S_IFCHR = 0x2000
+ S_IFDIR = 0x4000
+ S_IFBLK = 0x6000
+ S_IFREG = 0x8000
+ S_IFLNK = 0xa000
+ S_IFSOCK = 0xc000
+)
+
+// Errors
+var (
+ EINVAL = NewError("bad arg in system call")
+ ENOTDIR = NewError("not a directory")
+ EISDIR = NewError("file is a directory")
+ ENOENT = NewError("file does not exist")
+ EEXIST = NewError("file already exists")
+ EMFILE = NewError("no free file descriptors")
+ EIO = NewError("i/o error")
+ ENAMETOOLONG = NewError("file name too long")
+ EINTR = NewError("interrupted")
+ EPERM = NewError("permission denied")
+ EBUSY = NewError("no free devices")
+ ETIMEDOUT = NewError("connection timed out")
+ EPLAN9 = NewError("not supported by plan 9")
+
+ // The following errors do not correspond to any
+ // Plan 9 system messages. Invented to support
+ // what package os and others expect.
+ EACCES = NewError("access permission denied")
+ EAFNOSUPPORT = NewError("address family not supported by protocol")
+)
diff --git a/libgo/go/syscall/exec_bsd.go b/libgo/go/syscall/exec_bsd.go
index 217e0c842df..f44e897f39b 100644
--- a/libgo/go/syscall/exec_bsd.go
+++ b/libgo/go/syscall/exec_bsd.go
@@ -15,9 +15,12 @@ type SysProcAttr struct {
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
+ Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
+ Setctty bool // Set controlling terminal to fd Ctty
Noctty bool // Detach fd 0 from controlling terminal
+ Ctty int // Controlling TTY fd
+ Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+ Pgid int // Child's process group ID if Setpgid.
}
// Implemented in runtime package.
@@ -90,8 +93,24 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// Set process group
- if sys.Setpgid {
- err1 = raw_setpgid(0, 0)
+ if sys.Setpgid || sys.Foreground {
+ // Place child in process group.
+ err1 = raw_setpgid(0, sys.Pgid)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ if sys.Foreground {
+ pgrp := sys.Pgid
+ if pgrp == 0 {
+ r1 = raw_getpid()
+
+ pgrp = int(r1)
+ }
+
+ // Place process group in foreground.
+ _, err1 = raw_ioctl_ptr(sys.Ctty, TIOCSPGRP, unsafe.Pointer(&pgrp))
if err1 != 0 {
goto childerror
}
@@ -215,9 +234,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
- // Make fd 0 the tty
+ // Set the controlling TTY to Ctty
if sys.Setctty {
- _, err1 = raw_ioctl(0, TIOCSCTTY, 0)
+ _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
if err1 != 0 {
goto childerror
}
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 97bde0c4f52..d9600a142ae 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -27,14 +27,21 @@ type SysProcAttr struct {
Credential *Credential // Credential.
Ptrace bool // Enable tracing.
Setsid bool // Create session.
- Setpgid bool // Set process group ID to new pid (SYSV setpgrp)
+ Setpgid bool // Set process group ID to Pgid, or, if Pgid == 0, to new pid.
Setctty bool // Set controlling terminal to fd Ctty (only meaningful if Setsid is set)
Noctty bool // Detach fd 0 from controlling terminal
- Ctty int // Controlling TTY fd (Linux only)
+ Ctty int // Controlling TTY fd
+ Foreground bool // Place child's process group in foreground. (Implies Setpgid. Uses Ctty as fd of controlling TTY)
+ Pgid int // Child's process group ID if Setpgid.
Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
Cloneflags uintptr // Flags for clone calls (Linux only)
UidMappings []SysProcIDMap // User ID mappings for user namespaces.
GidMappings []SysProcIDMap // Group ID mappings for user namespaces.
+ // GidMappingsEnableSetgroups enabling setgroups syscall.
+ // If false, then setgroups syscall will be disabled for the child process.
+ // This parameter is no-op if GidMappings == nil. Otherwise for unprivileged
+ // users this should be set to false for mappings work.
+ GidMappingsEnableSetgroups bool
}
// Implemented in runtime package.
@@ -62,6 +69,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
p [2]int
)
+ // Record parent PID so child can test if it has died.
+ ppid := raw_getpid()
+
// Guard against side effects of shuffling fds below.
// Make sure that nextfd is beyond any currently open files so
// that we can't run the risk of overwriting any of them.
@@ -135,27 +145,6 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
- // Parent death signal
- if sys.Pdeathsig != 0 {
- _, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0)
- if err1 != 0 {
- goto childerror
- }
-
- // Signal self if parent is already dead. This might cause a
- // duplicate signal in rare cases, but it won't matter when
- // using SIGKILL.
- ppid := Getppid()
- if ppid == 1 {
- pid = Getpid()
- err2 := Kill(pid, sys.Pdeathsig)
- if err2 != nil {
- err1 = err2.(Errno)
- goto childerror
- }
- }
- }
-
// Enable tracing if requested.
if sys.Ptrace {
err1 = raw_ptrace(_PTRACE_TRACEME, 0, nil, nil)
@@ -173,8 +162,27 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
// Set process group
- if sys.Setpgid {
- err1 = raw_setpgid(0, 0)
+ if sys.Setpgid || sys.Foreground {
+ // Place child in process group.
+ err1 = raw_setpgid(0, sys.Pgid)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+
+ if sys.Foreground {
+ pgrp := int32(sys.Pgid)
+ if pgrp == 0 {
+ r1 = uintptr(raw_getpid())
+ if err1 != 0 {
+ goto childerror
+ }
+
+ pgrp = int32(r1)
+ }
+
+ // Place process group in foreground.
+ _, err1 = raw_ioctl_ptr(sys.Ctty, TIOCSPGRP, unsafe.Pointer(&pgrp))
if err1 != 0 {
goto childerror
}
@@ -191,36 +199,19 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
// User and groups
if cred := sys.Credential; cred != nil {
ngroups := len(cred.Groups)
- if ngroups == 0 {
- err2 := setgroups(0, nil)
- if err2 == nil {
- err1 = 0
- } else {
- err1 = err2.(Errno)
- }
- } else {
- groups := make([]Gid_t, ngroups)
- for i, v := range cred.Groups {
- groups[i] = Gid_t(v)
- }
- err2 := setgroups(ngroups, &groups[0])
- if err2 == nil {
- err1 = 0
- } else {
- err1 = err2.(Errno)
+ if ngroups > 0 {
+ groups := unsafe.Pointer(&cred.Groups[0])
+ err1 = raw_setgroups(ngroups, groups)
+ if err1 != 0 {
+ goto childerror
}
}
+ err1 = raw_setgid(int(cred.Gid))
if err1 != 0 {
goto childerror
}
- err2 := Setgid(int(cred.Gid))
- if err2 != nil {
- err1 = err2.(Errno)
- goto childerror
- }
- err2 = Setuid(int(cred.Uid))
- if err2 != nil {
- err1 = err2.(Errno)
+ err1 = raw_setuid(int(cred.Uid))
+ if err1 != 0 {
goto childerror
}
}
@@ -233,6 +224,26 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
+ // Parent death signal
+ if sys.Pdeathsig != 0 {
+ _, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0)
+ if err1 != 0 {
+ goto childerror
+ }
+
+ // Signal self if parent is already dead. This might cause a
+ // duplicate signal in rare cases, but it won't matter when
+ // using SIGKILL.
+ r1 := raw_getppid()
+ if r1 != ppid {
+ pid = raw_getpid()
+ err1 = raw_kill(pid, sys.Pdeathsig)
+ if err1 != 0 {
+ goto childerror
+ }
+ }
+ }
+
// Pass 1: look for fd[i] < i and move those up above len(fd)
// so that pass 2 won't stomp on an fd it needs later.
if pipe < nextfd {
@@ -298,9 +309,9 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
}
- // Make fd 0 the tty
- if sys.Setctty && sys.Ctty >= 0 {
- _, err1 = raw_ioctl(0, TIOCSCTTY, sys.Ctty)
+ // Set the controlling TTY to Ctty
+ if sys.Setctty {
+ _, err1 = raw_ioctl(sys.Ctty, TIOCSCTTY, 0)
if err1 != 0 {
goto childerror
}
@@ -364,6 +375,32 @@ func writeIDMappings(path string, idMap []SysProcIDMap) error {
return nil
}
+// writeSetgroups writes to /proc/PID/setgroups "deny" if enable is false
+// and "allow" if enable is true.
+// This is needed since kernel 3.19, because you can't write gid_map without
+// disabling setgroups() system call.
+func writeSetgroups(pid int, enable bool) error {
+ sgf := "/proc/" + itoa(pid) + "/setgroups"
+ fd, err := Open(sgf, O_RDWR, 0)
+ if err != nil {
+ return err
+ }
+
+ var data []byte
+ if enable {
+ data = []byte("allow")
+ } else {
+ data = []byte("deny")
+ }
+
+ if _, err := Write(fd, data); err != nil {
+ Close(fd)
+ return err
+ }
+
+ return Close(fd)
+}
+
// writeUidGidMappings writes User ID and Group ID mappings for user namespaces
// for a process and it is called from the parent process.
func writeUidGidMappings(pid int, sys *SysProcAttr) error {
@@ -375,6 +412,10 @@ func writeUidGidMappings(pid int, sys *SysProcAttr) error {
}
if sys.GidMappings != nil {
+ // If the kernel is too old to support /proc/PID/setgroups, writeSetGroups will return ENOENT; this is OK.
+ if err := writeSetgroups(pid, sys.GidMappingsEnableSetgroups); err != nil && err != ENOENT {
+ return err
+ }
gidf := "/proc/" + itoa(pid) + "/gid_map"
if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
return err
diff --git a/libgo/go/syscall/exec_linux_test.go b/libgo/go/syscall/exec_linux_test.go
new file mode 100644
index 00000000000..60d2734f66a
--- /dev/null
+++ b/libgo/go/syscall/exec_linux_test.go
@@ -0,0 +1,111 @@
+// Copyright 2015 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.
+
+// +build linux
+
+package syscall_test
+
+import (
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "regexp"
+ "strconv"
+ "strings"
+ "syscall"
+ "testing"
+)
+
+func whoamiCmd(t *testing.T, uid, gid int, setgroups bool) *exec.Cmd {
+ if _, err := os.Stat("/proc/self/ns/user"); err != nil {
+ if os.IsNotExist(err) {
+ t.Skip("kernel doesn't support user namespaces")
+ }
+ t.Fatalf("Failed to stat /proc/self/ns/user: %v", err)
+ }
+ cmd := exec.Command("whoami")
+ cmd.SysProcAttr = &syscall.SysProcAttr{
+ Cloneflags: syscall.CLONE_NEWUSER,
+ UidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: uid, Size: 1},
+ },
+ GidMappings: []syscall.SysProcIDMap{
+ {ContainerID: 0, HostID: gid, Size: 1},
+ },
+ GidMappingsEnableSetgroups: setgroups,
+ }
+ return cmd
+}
+
+func testNEWUSERRemap(t *testing.T, uid, gid int, setgroups bool) {
+ cmd := whoamiCmd(t, uid, gid, setgroups)
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ // On some systems, there is a sysctl setting.
+ if os.IsPermission(err) && os.Getuid() != 0 {
+ data, errRead := ioutil.ReadFile("/proc/sys/kernel/unprivileged_userns_clone")
+ if errRead == nil && data[0] == '0' {
+ t.Skip("kernel prohibits user namespace in unprivileged process")
+ }
+ }
+
+ t.Fatalf("Cmd failed with err %v, output: %s", err, out)
+ }
+ sout := strings.TrimSpace(string(out))
+ want := "root"
+ if sout != want {
+ t.Fatalf("whoami = %q; want %q", out, want)
+ }
+}
+
+func TestCloneNEWUSERAndRemapRootDisableSetgroups(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("skipping root only test")
+ }
+ testNEWUSERRemap(t, 0, 0, false)
+}
+
+func TestCloneNEWUSERAndRemapRootEnableSetgroups(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("skipping root only test")
+ }
+ testNEWUSERRemap(t, 0, 0, false)
+}
+
+// kernelVersion returns the major and minor versions of the Linux
+// kernel version. It calls t.Skip if it can't figure it out.
+func kernelVersion(t *testing.T) (int, int) {
+ bytes, err := ioutil.ReadFile("/proc/version")
+ if err != nil {
+ t.Skipf("can't get kernel version: %v", err)
+ }
+ matches := regexp.MustCompile("([0-9]+).([0-9]+)").FindSubmatch(bytes)
+ if len(matches) < 3 {
+ t.Skipf("can't get kernel version from %s", bytes)
+ }
+ major, _ := strconv.Atoi(string(matches[1]))
+ minor, _ := strconv.Atoi(string(matches[2]))
+ return major, minor
+}
+
+func TestCloneNEWUSERAndRemapNoRootDisableSetgroups(t *testing.T) {
+ if os.Getuid() == 0 {
+ t.Skip("skipping unprivileged user only test")
+ }
+ testNEWUSERRemap(t, os.Getuid(), os.Getgid(), false)
+}
+
+func TestCloneNEWUSERAndRemapNoRootSetgroupsEnableSetgroups(t *testing.T) {
+ if os.Getuid() == 0 {
+ t.Skip("skipping unprivileged user only test")
+ }
+ cmd := whoamiCmd(t, os.Getuid(), os.Getgid(), true)
+ err := cmd.Run()
+ if err == nil {
+ t.Skip("probably old kernel without security fix")
+ }
+ if !os.IsPermission(err) {
+ t.Fatalf("Unprivileged gid_map rewriting with GidMappingsEnableSetgroups must fail")
+ }
+}
diff --git a/libgo/go/syscall/exec_solaris_test.go b/libgo/go/syscall/exec_solaris_test.go
new file mode 100644
index 00000000000..6b8f1ad3837
--- /dev/null
+++ b/libgo/go/syscall/exec_solaris_test.go
@@ -0,0 +1,37 @@
+// Copyright 2015 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.
+
+// +build solaris
+
+package syscall
+
+import "unsafe"
+
+//go:cgo_import_dynamic libc_Getpgid getpgid "libc.so"
+//go:cgo_import_dynamic libc_Getpgrp getpgrp "libc.so"
+
+//go:linkname libc_Getpgid libc_Getpgid
+//go:linkname libc_Getpgrp libc_Getpgrp
+
+var (
+ libc_Getpgid,
+ libc_Getpgrp libcFunc
+)
+
+func Getpgid(pid int) (pgid int, err error) {
+ r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgid)), 1, uintptr(pid), 0, 0, 0, 0, 0)
+ pgid = int(r0)
+ if e1 != 0 {
+ err = e1
+ }
+ return
+}
+
+func Getpgrp() (pgrp int) {
+ r0, _, _ := sysvicall6(uintptr(unsafe.Pointer(&libc_Getpgrp)), 0, 0, 0, 0, 0, 0, 0)
+ pgrp = int(r0)
+ return
+}
+
+var Ioctl = ioctl
diff --git a/libgo/go/syscall/exec_unix.go b/libgo/go/syscall/exec_unix.go
index a49d95bc94c..7427c57b703 100644
--- a/libgo/go/syscall/exec_unix.go
+++ b/libgo/go/syscall/exec_unix.go
@@ -17,6 +17,12 @@ import (
//sysnb raw_fork() (pid Pid_t, err Errno)
//fork() Pid_t
+//sysnb raw_getpid() (pid int)
+//getpid() Pid_t
+
+//sysnb raw_getppid() (pid int)
+//getppid() Pid_t
+
//sysnb raw_setsid() (err Errno)
//setsid() Pid_t
@@ -36,7 +42,10 @@ import (
//close(fd _C_int) _C_int
//sysnb raw_ioctl(fd int, cmd int, val int) (rval int, err Errno)
-//ioctl(fd _C_int, cmd _C_int, val _C_int) _C_int
+//__go_ioctl(fd _C_int, cmd _C_int, val _C_int) _C_int
+
+//sysnb raw_ioctl_ptr(fd int, cmd int, val unsafe.Pointer) (rval int, err Errno)
+//__go_ioctl_ptr(fd _C_int, cmd _C_int, val unsafe.Pointer) _C_int
//sysnb raw_execve(argv0 *byte, argv **byte, envv **byte) (err Errno)
//execve(argv0 *byte, argv **byte, envv **byte) _C_int
@@ -50,6 +59,18 @@ import (
//sysnb raw_dup2(oldfd int, newfd int) (err Errno)
//dup2(oldfd _C_int, newfd _C_int) _C_int
+//sysnb raw_kill(pid int, sig Signal) (err Errno)
+//kill(pid Pid_t, sig _C_int) _C_int
+
+//sysnb raw_setgroups(size int, list unsafe.Pointer) (err Errno)
+//setgroups(size Size_t, list *Gid_t) _C_int
+
+//sysnb raw_setuid(uid int) (err Errno)
+//setuid(uid Uid_t) _C_int
+
+//sysnb raw_setgid(gid int) (err Errno)
+//setgid(gid Gid_t) _C_int
+
// Lock synchronizing creation of new file descriptors with fork.
//
// We want the child in a fork/exec sequence to inherit only the
@@ -99,9 +120,11 @@ import (
var ForkLock sync.RWMutex
-// StringSlicePtr is deprecated. Use SlicePtrFromStrings instead.
-// If any string contains a NUL byte this function panics instead
-// of returning an error.
+// StringSlicePtr converts a slice of strings to a slice of pointers
+// to NUL-terminated byte arrays. If any string contains a NUL byte
+// this function panics instead of returning an error.
+//
+// Deprecated: Use SlicePtrFromStrings instead.
func StringSlicePtr(ss []string) []*byte {
bb := make([]*byte, len(ss)+1)
for i := 0; i < len(ss); i++ {
@@ -112,7 +135,7 @@ func StringSlicePtr(ss []string) []*byte {
}
// SlicePtrFromStrings converts a slice of strings to a slice of
-// pointers to NUL-terminated byte slices. If any string contains
+// pointers to NUL-terminated byte arrays. If any string contains
// a NUL byte, it returns (nil, EINVAL).
func SlicePtrFromStrings(ss []string) ([]*byte, error) {
var err error
diff --git a/libgo/go/syscall/exec_unix_test.go b/libgo/go/syscall/exec_unix_test.go
new file mode 100644
index 00000000000..9bb95c0f395
--- /dev/null
+++ b/libgo/go/syscall/exec_unix_test.go
@@ -0,0 +1,215 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd solaris
+
+package syscall_test
+
+import (
+ "internal/testenv"
+ "io"
+ "os"
+ "os/exec"
+ "os/signal"
+ "syscall"
+ "testing"
+ "unsafe"
+)
+
+type command struct {
+ pipe io.WriteCloser
+ proc *exec.Cmd
+ test *testing.T
+}
+
+func (c *command) Info() (pid, pgrp int) {
+ pid = c.proc.Process.Pid
+
+ pgrp, err := syscall.Getpgid(pid)
+ if err != nil {
+ c.test.Fatal(err)
+ }
+
+ return
+}
+
+func (c *command) Start() {
+ if err := c.proc.Start(); err != nil {
+ c.test.Fatal(err)
+ }
+}
+
+func (c *command) Stop() {
+ c.pipe.Close()
+ if err := c.proc.Wait(); err != nil {
+ c.test.Fatal(err)
+ }
+}
+
+func create(t *testing.T) *command {
+ testenv.MustHaveExec(t)
+
+ proc := exec.Command("cat")
+ stdin, err := proc.StdinPipe()
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return &command{stdin, proc, t}
+}
+
+func parent() (pid, pgrp int) {
+ return syscall.Getpid(), syscall.Getpgrp()
+}
+
+func TestZeroSysProcAttr(t *testing.T) {
+ ppid, ppgrp := parent()
+
+ cmd := create(t)
+
+ cmd.Start()
+ defer cmd.Stop()
+
+ cpid, cpgrp := cmd.Info()
+
+ if cpid == ppid {
+ t.Fatalf("Parent and child have the same process ID")
+ }
+
+ if cpgrp != ppgrp {
+ t.Fatalf("Child is not in parent's process group")
+ }
+}
+
+func TestSetpgid(t *testing.T) {
+ ppid, ppgrp := parent()
+
+ cmd := create(t)
+
+ cmd.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+ cmd.Start()
+ defer cmd.Stop()
+
+ cpid, cpgrp := cmd.Info()
+
+ if cpid == ppid {
+ t.Fatalf("Parent and child have the same process ID")
+ }
+
+ if cpgrp == ppgrp {
+ t.Fatalf("Parent and child are in the same process group")
+ }
+
+ if cpid != cpgrp {
+ t.Fatalf("Child's process group is not the child's process ID")
+ }
+}
+
+func TestPgid(t *testing.T) {
+ ppid, ppgrp := parent()
+
+ cmd1 := create(t)
+
+ cmd1.proc.SysProcAttr = &syscall.SysProcAttr{Setpgid: true}
+ cmd1.Start()
+ defer cmd1.Stop()
+
+ cpid1, cpgrp1 := cmd1.Info()
+
+ if cpid1 == ppid {
+ t.Fatalf("Parent and child 1 have the same process ID")
+ }
+
+ if cpgrp1 == ppgrp {
+ t.Fatalf("Parent and child 1 are in the same process group")
+ }
+
+ if cpid1 != cpgrp1 {
+ t.Fatalf("Child 1's process group is not its process ID")
+ }
+
+ cmd2 := create(t)
+
+ cmd2.proc.SysProcAttr = &syscall.SysProcAttr{
+ Setpgid: true,
+ Pgid: cpgrp1,
+ }
+ cmd2.Start()
+ defer cmd2.Stop()
+
+ cpid2, cpgrp2 := cmd2.Info()
+
+ if cpid2 == ppid {
+ t.Fatalf("Parent and child 2 have the same process ID")
+ }
+
+ if cpgrp2 == ppgrp {
+ t.Fatalf("Parent and child 2 are in the same process group")
+ }
+
+ if cpid2 == cpgrp2 {
+ t.Fatalf("Child 2's process group is its process ID")
+ }
+
+ if cpid1 == cpid2 {
+ t.Fatalf("Child 1 and 2 have the same process ID")
+ }
+
+ if cpgrp1 != cpgrp2 {
+ t.Fatalf("Child 1 and 2 are not in the same process group")
+ }
+}
+
+func TestForeground(t *testing.T) {
+ signal.Ignore(syscall.SIGTTIN, syscall.SIGTTOU)
+
+ tty, err := os.OpenFile("/dev/tty", os.O_RDWR, 0)
+ if err != nil {
+ t.Skipf("Can't test Foreground. Couldn't open /dev/tty: %s", err)
+ }
+
+ fpgrp := 0
+
+ errno := syscall.Ioctl(tty.Fd(), syscall.TIOCGPGRP, uintptr(unsafe.Pointer(&fpgrp)))
+ if errno != 0 {
+ t.Fatalf("TIOCGPGRP failed with error code: %s", errno)
+ }
+
+ if fpgrp == 0 {
+ t.Fatalf("Foreground process group is zero")
+ }
+
+ ppid, ppgrp := parent()
+
+ cmd := create(t)
+
+ cmd.proc.SysProcAttr = &syscall.SysProcAttr{
+ Ctty: int(tty.Fd()),
+ Foreground: true,
+ }
+ cmd.Start()
+
+ cpid, cpgrp := cmd.Info()
+
+ if cpid == ppid {
+ t.Fatalf("Parent and child have the same process ID")
+ }
+
+ if cpgrp == ppgrp {
+ t.Fatalf("Parent and child are in the same process group")
+ }
+
+ if cpid != cpgrp {
+ t.Fatalf("Child's process group is not the child's process ID")
+ }
+
+ cmd.Stop()
+
+ errno = syscall.Ioctl(tty.Fd(), syscall.TIOCSPGRP, uintptr(unsafe.Pointer(&fpgrp)))
+ if errno != 0 {
+ t.Fatalf("TIOCSPGRP failed with error code: %s", errno)
+ }
+
+ signal.Reset()
+}
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 936aeb577bc..5a01843d2be 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -135,23 +135,17 @@ func FullPath(name string) (path string, err error) {
if err != nil {
return "", err
}
- buf := make([]uint16, 100)
- n, err := GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
- if err != nil {
- return "", err
- }
- if n > uint32(len(buf)) {
- // Windows is asking for bigger buffer.
- buf = make([]uint16, n)
+ n := uint32(100)
+ for {
+ buf := make([]uint16, n)
n, err = GetFullPathName(p, uint32(len(buf)), &buf[0], nil)
if err != nil {
return "", err
}
- if n > uint32(len(buf)) {
- return "", EINVAL
+ if n <= uint32(len(buf)) {
+ return UTF16ToString(buf[:n]), nil
}
}
- return UTF16ToString(buf[:n]), nil
}
func isSlash(c uint8) bool {
@@ -250,6 +244,9 @@ func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle
if len(attr.Files) > 3 {
return 0, 0, EWINDOWS
}
+ if len(attr.Files) < 3 {
+ return 0, 0, EINVAL
+ }
if len(attr.Dir) != 0 {
// StartProcess assumes that argv0 is relative to attr.Dir,
diff --git a/libgo/go/syscall/export_unix_test.go b/libgo/go/syscall/export_unix_test.go
new file mode 100644
index 00000000000..b41fe2f86b3
--- /dev/null
+++ b/libgo/go/syscall/export_unix_test.go
@@ -0,0 +1,12 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd linux netbsd openbsd
+
+package syscall
+
+func Ioctl(fd, req, arg uintptr) (err Errno) {
+ _, _, err = Syscall(SYS_IOCTL, fd, req, arg)
+ return err
+}
diff --git a/libgo/go/syscall/pwd_plan9.go b/libgo/go/syscall/pwd_plan9.go
new file mode 100644
index 00000000000..12486135f0d
--- /dev/null
+++ b/libgo/go/syscall/pwd_plan9.go
@@ -0,0 +1,83 @@
+// Copyright 2015 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.
+
+// The working directory in Plan 9 is effectively per P, so different
+// goroutines and even the same goroutine as it's rescheduled on
+// different Ps can see different working directories.
+//
+// Instead, track a Go process-wide intent of the current working directory,
+// and switch to it at important points.
+
+package syscall
+
+import "sync"
+
+var (
+ wdmu sync.Mutex // guards following
+ wdSet bool
+ wdStr string
+)
+
+func Fixwd() {
+ wdmu.Lock()
+ defer wdmu.Unlock()
+ fixwdLocked()
+}
+
+func fixwdLocked() {
+ if !wdSet {
+ return
+ }
+ // always call chdir when getwd returns an error
+ wd, _ := getwd()
+ if wd == wdStr {
+ return
+ }
+ if err := chdir(wdStr); err != nil {
+ return
+ }
+}
+
+// goroutine-specific getwd
+func getwd() (wd string, err error) {
+ fd, err := open(".", O_RDONLY)
+ if err != nil {
+ return "", err
+ }
+ defer Close(fd)
+ return Fd2path(fd)
+}
+
+func Getwd() (wd string, err error) {
+ wdmu.Lock()
+ defer wdmu.Unlock()
+
+ if wdSet {
+ return wdStr, nil
+ }
+ wd, err = getwd()
+ if err != nil {
+ return
+ }
+ wdSet = true
+ wdStr = wd
+ return wd, nil
+}
+
+func Chdir(path string) error {
+ wdmu.Lock()
+ defer wdmu.Unlock()
+
+ if err := chdir(path); err != nil {
+ return err
+ }
+
+ wd, err := getwd()
+ if err != nil {
+ return err
+ }
+ wdSet = true
+ wdStr = wd
+ return nil
+}
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index 1dabe42531b..c62fdc3c81d 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.go
@@ -4,23 +4,37 @@
// +build darwin dragonfly freebsd netbsd openbsd
-// Routing sockets and messages
-
package syscall
-import "unsafe"
+import (
+ "runtime"
+ "unsafe"
+)
+
+var (
+ freebsdConfArch string // "machine $arch" line in kern.conftxt on freebsd
+ minRoutingSockaddrLen = rsaAlignOf(0)
+)
// Round the length of a raw sockaddr up to align it properly.
func rsaAlignOf(salen int) int {
salign := sizeofPtr
- // NOTE: It seems like 64-bit Darwin kernel still requires
- // 32-bit aligned access to BSD subsystem. Also NetBSD 6
- // kernel and beyond require 64-bit aligned access to routing
- // facilities.
if darwin64Bit {
+ // Darwin kernels require 32-bit aligned access to
+ // routing facilities.
salign = 4
} else if netbsd32Bit {
+ // NetBSD 6 and beyond kernels require 64-bit aligned
+ // access to routing facilities.
salign = 8
+ } else if runtime.GOOS == "freebsd" {
+ // In the case of kern.supported_archs="amd64 i386",
+ // we need to know the underlying kernel's
+ // architecture because the alignment for routing
+ // facilities are set at the build time of the kernel.
+ if freebsdConfArch == "amd64" {
+ salign = 8
+ }
}
if salen == 0 {
return salign
@@ -28,6 +42,134 @@ func rsaAlignOf(salen int) int {
return (salen + salign - 1) & ^(salign - 1)
}
+// parseSockaddrLink parses b as a datalink socket address.
+func parseSockaddrLink(b []byte) (*SockaddrDatalink, error) {
+ sa, _, err := parseLinkLayerAddr(b[4:])
+ if err != nil {
+ return nil, err
+ }
+ rsa := (*RawSockaddrDatalink)(unsafe.Pointer(&b[0]))
+ sa.Len = rsa.Len
+ sa.Family = rsa.Family
+ sa.Index = rsa.Index
+ return sa, nil
+}
+
+// parseLinkLayerAddr parses b as a datalink socket address in
+// conventional BSD kernel form.
+func parseLinkLayerAddr(b []byte) (*SockaddrDatalink, int, error) {
+ // The encoding looks like the following:
+ // +----------------------------+
+ // | Type (1 octet) |
+ // +----------------------------+
+ // | Name length (1 octet) |
+ // +----------------------------+
+ // | Address length (1 octet) |
+ // +----------------------------+
+ // | Selector length (1 octet) |
+ // +----------------------------+
+ // | Data (variable) |
+ // +----------------------------+
+ type linkLayerAddr struct {
+ Type byte
+ Nlen byte
+ Alen byte
+ Slen byte
+ }
+ lla := (*linkLayerAddr)(unsafe.Pointer(&b[0]))
+ l := rsaAlignOf(int(4 + lla.Nlen + lla.Alen + lla.Slen))
+ if len(b) < l {
+ return nil, 0, EINVAL
+ }
+ b = b[4:]
+ sa := &SockaddrDatalink{Type: lla.Type, Nlen: lla.Nlen, Alen: lla.Alen, Slen: lla.Slen}
+ for i := 0; len(sa.Data) > i && i < int(lla.Nlen+lla.Alen+lla.Slen); i++ {
+ sa.Data[i] = int8(b[i])
+ }
+ return sa, l, nil
+}
+
+// parseSockaddrInet parses b as an internet socket address.
+func parseSockaddrInet(b []byte, family byte) (Sockaddr, error) {
+ switch family {
+ case AF_INET:
+ if len(b) < SizeofSockaddrInet4 {
+ return nil, EINVAL
+ }
+ rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
+ return anyToSockaddr(rsa)
+ case AF_INET6:
+ if len(b) < SizeofSockaddrInet6 {
+ return nil, EINVAL
+ }
+ rsa := (*RawSockaddrAny)(unsafe.Pointer(&b[0]))
+ return anyToSockaddr(rsa)
+ default:
+ return nil, EINVAL
+ }
+}
+
+const (
+ offsetofInet4 = int(unsafe.Offsetof(RawSockaddrInet4{}.Addr))
+ offsetofInet6 = int(unsafe.Offsetof(RawSockaddrInet6{}.Addr))
+)
+
+// parseNetworkLayerAddr parses b as an internet socket address in
+// conventional BSD kernel form.
+func parseNetworkLayerAddr(b []byte, family byte) (Sockaddr, error) {
+ // The encoding looks similar to the NLRI encoding.
+ // +----------------------------+
+ // | Length (1 octet) |
+ // +----------------------------+
+ // | Address prefix (variable) |
+ // +----------------------------+
+ //
+ // The differences between the kernel form and the NLRI
+ // encoding are:
+ //
+ // - The length field of the kernel form indicates the prefix
+ // length in bytes, not in bits
+ //
+ // - In the kernel form, zero value of the length field
+ // doesn't mean 0.0.0.0/0 or ::/0
+ //
+ // - The kernel form appends leading bytes to the prefix field
+ // to make the <length, prefix> tuple to be conformed with
+ // the routing messeage boundary
+ l := int(rsaAlignOf(int(b[0])))
+ if len(b) < l {
+ return nil, EINVAL
+ }
+ // Don't reorder case expressions.
+ // The case expressions for IPv6 must come first.
+ switch {
+ case b[0] == SizeofSockaddrInet6:
+ sa := &SockaddrInet6{}
+ copy(sa.Addr[:], b[offsetofInet6:])
+ return sa, nil
+ case family == AF_INET6:
+ sa := &SockaddrInet6{}
+ if l-1 < offsetofInet6 {
+ copy(sa.Addr[:], b[1:l])
+ } else {
+ copy(sa.Addr[:], b[l-offsetofInet6:l])
+ }
+ return sa, nil
+ case b[0] == SizeofSockaddrInet4:
+ sa := &SockaddrInet4{}
+ copy(sa.Addr[:], b[offsetofInet4:])
+ return sa, nil
+ default: // an old fashion, AF_UNSPEC or unknown means AF_INET
+ sa := &SockaddrInet4{}
+ if l-1 < offsetofInet4 {
+ copy(sa.Addr[:], b[1:l])
+ } else {
+ copy(sa.Addr[:], b[l-offsetofInet4:l])
+ }
+ return sa, nil
+ }
+}
+
// RouteRIB returns routing information base, as known as RIB,
// which consists of network facility information, states and
// parameters.
@@ -50,7 +192,7 @@ func RouteRIB(facility, param int) ([]byte, error) {
// RoutingMessage represents a routing message.
type RoutingMessage interface {
- sockaddr() []Sockaddr
+ sockaddr() ([]Sockaddr, error)
}
const anyMessageLen = int(unsafe.Sizeof(anyMessage{}))
@@ -68,50 +210,41 @@ type RouteMessage struct {
Data []byte
}
-const rtaRtMask = RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK
-
-func (m *RouteMessage) sockaddr() []Sockaddr {
- var (
- af int
- sas [4]Sockaddr
- )
+func (m *RouteMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
b := m.Data[:]
- for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaRtMask&(1<<i) == 0 {
+ family := uint8(AF_UNSPEC)
+ for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
- switch i {
- case RTAX_DST, RTAX_GATEWAY:
- sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ switch rsa.Family {
+ case AF_LINK:
+ sa, err := parseSockaddrLink(b)
if err != nil {
- return nil
+ return nil, err
}
- if i == RTAX_DST {
- af = int(rsa.Family)
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ case AF_INET, AF_INET6:
+ sa, err := parseSockaddrInet(b, rsa.Family)
+ if err != nil {
+ return nil, err
}
sas[i] = sa
- case RTAX_NETMASK, RTAX_GENMASK:
- switch af {
- case AF_INET:
- rsa4 := (*RawSockaddrInet4)(unsafe.Pointer(&b[0]))
- sa := new(SockaddrInet4)
- for j := 0; rsa4.Len > 0 && j < int(rsa4.Len)-int(unsafe.Offsetof(rsa4.Addr)); j++ {
- sa.Addr[j] = rsa4.Addr[j]
- }
- sas[i] = sa
- case AF_INET6:
- rsa6 := (*RawSockaddrInet6)(unsafe.Pointer(&b[0]))
- sa := new(SockaddrInet6)
- for j := 0; rsa6.Len > 0 && j < int(rsa6.Len)-int(unsafe.Offsetof(rsa6.Addr)); j++ {
- sa.Addr[j] = rsa6.Addr[j]
- }
- sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ family = rsa.Family
+ default:
+ sa, err := parseNetworkLayerAddr(b, family)
+ if err != nil {
+ return nil, err
}
+ sas[i] = sa
+ b = b[rsaAlignOf(int(b[0])):]
}
- b = b[rsaAlignOf(int(rsa.Len)):]
}
- return sas[:]
+ return sas[:], nil
}
// InterfaceMessage represents a routing message containing
@@ -121,15 +254,17 @@ type InterfaceMessage struct {
Data []byte
}
-func (m *InterfaceMessage) sockaddr() (sas []Sockaddr) {
+func (m *InterfaceMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
if m.Header.Addrs&RTA_IFP == 0 {
- return nil
+ return nil, nil
}
- sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(&m.Data[0])))
+ sa, err := parseSockaddrLink(m.Data[:])
if err != nil {
- return nil
+ return nil, err
}
- return append(sas, sa)
+ sas[RTAX_IFP] = sa
+ return sas[:], nil
}
// InterfaceAddrMessage represents a routing message containing
@@ -139,79 +274,63 @@ type InterfaceAddrMessage struct {
Data []byte
}
-const rtaIfaMask = RTA_IFA | RTA_NETMASK | RTA_BRD
-
-func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
- if m.Header.Addrs&rtaIfaMask == 0 {
- return nil
- }
+func (m *InterfaceAddrMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
b := m.Data[:]
- // We still see AF_UNSPEC in socket addresses on some
- // platforms. To identify each address family correctly, we
- // will use the address family of RTAX_NETMASK as a preferred
- // one on the 32-bit NetBSD kernel, also use the length of
- // RTAX_NETMASK socket address on the FreeBSD kernel.
- preferredFamily := uint8(AF_UNSPEC)
- for i := uint(0); i < RTAX_MAX; i++ {
+ family := uint8(AF_UNSPEC)
+ for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
- switch i {
- case RTAX_IFA:
- if rsa.Family == AF_UNSPEC {
- rsa.Family = preferredFamily
- }
- sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ switch rsa.Family {
+ case AF_LINK:
+ sa, err := parseSockaddrLink(b)
if err != nil {
- return nil
+ return nil, err
}
- sas = append(sas, sa)
- case RTAX_NETMASK:
- switch rsa.Family {
- case AF_UNSPEC:
- switch rsa.Len {
- case SizeofSockaddrInet4:
- rsa.Family = AF_INET
- case SizeofSockaddrInet6:
- rsa.Family = AF_INET6
- default:
- rsa.Family = AF_INET // an old fashion, AF_UNSPEC means AF_INET
- }
- case AF_INET, AF_INET6:
- preferredFamily = rsa.Family
- default:
- return nil
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ case AF_INET, AF_INET6:
+ sa, err := parseSockaddrInet(b, rsa.Family)
+ if err != nil {
+ return nil, err
}
- sa, err := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ family = rsa.Family
+ default:
+ sa, err := parseNetworkLayerAddr(b, family)
if err != nil {
- return nil
+ return nil, err
}
- sas = append(sas, sa)
- case RTAX_BRD:
- // nothing to do
+ sas[i] = sa
+ b = b[rsaAlignOf(int(b[0])):]
}
- b = b[rsaAlignOf(int(rsa.Len)):]
}
- return sas
+ return sas[:], nil
}
// ParseRoutingMessage parses b as routing messages and returns the
// slice containing the RoutingMessage interfaces.
func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
- msgCount := 0
+ nmsgs, nskips := 0, 0
for len(b) >= anyMessageLen {
- msgCount++
+ nmsgs++
any := (*anyMessage)(unsafe.Pointer(&b[0]))
if any.Version != RTM_VERSION {
b = b[any.Msglen:]
continue
}
- msgs = append(msgs, any.toRoutingMessage(b))
+ if m := any.toRoutingMessage(b); m == nil {
+ nskips++
+ } else {
+ msgs = append(msgs, m)
+ }
b = b[any.Msglen:]
}
// We failed to parse any of the messages - version mismatch?
- if msgCount > 0 && len(msgs) == 0 {
+ if nmsgs != len(msgs)+nskips {
return nil, EINVAL
}
return msgs, nil
@@ -219,6 +338,10 @@ func ParseRoutingMessage(b []byte) (msgs []RoutingMessage, err error) {
// ParseRoutingMessage parses msg's payload as raw sockaddrs and
// returns the slice containing the Sockaddr interfaces.
-func ParseRoutingSockaddr(msg RoutingMessage) (sas []Sockaddr, err error) {
- return append(sas, msg.sockaddr()...), nil
+func ParseRoutingSockaddr(msg RoutingMessage) ([]Sockaddr, error) {
+ sas, err := msg.sockaddr()
+ if err != nil {
+ return nil, err
+ }
+ return sas, nil
}
diff --git a/libgo/go/syscall/route_bsd_test.go b/libgo/go/syscall/route_bsd_test.go
new file mode 100644
index 00000000000..8617663d43a
--- /dev/null
+++ b/libgo/go/syscall/route_bsd_test.go
@@ -0,0 +1,225 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd netbsd openbsd
+
+package syscall_test
+
+import (
+ "fmt"
+ "net"
+ "os"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestRouteRIB(t *testing.T) {
+ for _, facility := range []int{syscall.NET_RT_DUMP, syscall.NET_RT_IFLIST} {
+ for _, param := range []int{syscall.AF_UNSPEC, syscall.AF_INET, syscall.AF_INET6} {
+ var err error
+ var b []byte
+ // The VM allocator wrapper functions can
+ // return ENOMEM easily.
+ for i := 0; i < 3; i++ {
+ b, err = syscall.RouteRIB(facility, param)
+ if err != nil {
+ time.Sleep(5 * time.Millisecond)
+ continue
+ }
+ break
+ }
+ if err != nil {
+ t.Error(facility, param, err)
+ continue
+ }
+ msgs, err := syscall.ParseRoutingMessage(b)
+ if err != nil {
+ t.Error(facility, param, err)
+ continue
+ }
+ var ipv4loopback, ipv6loopback bool
+ for _, m := range msgs {
+ flags, err := parseRoutingMessageHeader(m)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ sas, err := parseRoutingSockaddrs(m)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ if flags&(syscall.RTA_DST|syscall.RTA_IFA) != 0 {
+ sa := sas[syscall.RTAX_DST]
+ if sa == nil {
+ sa = sas[syscall.RTAX_IFA]
+ }
+ switch sa := sa.(type) {
+ case *syscall.SockaddrInet4:
+ if net.IP(sa.Addr[:]).IsLoopback() {
+ ipv4loopback = true
+ }
+ case *syscall.SockaddrInet6:
+ if net.IP(sa.Addr[:]).IsLoopback() {
+ ipv6loopback = true
+ }
+ }
+ }
+ t.Log(facility, param, flags, sockaddrs(sas))
+ }
+ if param == syscall.AF_UNSPEC && len(msgs) > 0 && !ipv4loopback && !ipv6loopback {
+ t.Errorf("no loopback facility found: ipv4/ipv6=%v/%v, %v", ipv4loopback, ipv6loopback, len(msgs))
+ continue
+ }
+ }
+ }
+}
+
+func TestRouteMonitor(t *testing.T) {
+ if testing.Short() || os.Getuid() != 0 {
+ t.Skip("must be root")
+ }
+
+ s, err := syscall.Socket(syscall.AF_ROUTE, syscall.SOCK_RAW, syscall.AF_UNSPEC)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer syscall.Close(s)
+
+ tmo := time.After(30 * time.Second)
+ go func() {
+ b := make([]byte, os.Getpagesize())
+ for {
+ n, err := syscall.Read(s, b)
+ if err != nil {
+ return
+ }
+ msgs, err := syscall.ParseRoutingMessage(b[:n])
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ for _, m := range msgs {
+ flags, err := parseRoutingMessageHeader(m)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ sas, err := parseRoutingSockaddrs(m)
+ if err != nil {
+ t.Error(err)
+ continue
+ }
+ t.Log(flags, sockaddrs(sas))
+ }
+ }
+ }()
+ <-tmo
+}
+
+type addrFamily byte
+
+func (f addrFamily) String() string {
+ switch f {
+ case syscall.AF_UNSPEC:
+ return "unspec"
+ case syscall.AF_LINK:
+ return "link"
+ case syscall.AF_INET:
+ return "inet4"
+ case syscall.AF_INET6:
+ return "inet6"
+ default:
+ return fmt.Sprintf("unknown %d", f)
+ }
+}
+
+type addrFlags uint32
+
+var addrFlagNames = [...]string{
+ "dst",
+ "gateway",
+ "netmask",
+ "genmask",
+ "ifp",
+ "ifa",
+ "author",
+ "brd",
+ "mpls1,tag,src", // sockaddr_mpls=dragonfly,netbsd, sockaddr_in/in6=openbsd
+ "mpls2,srcmask", // sockaddr_mpls=dragonfly, sockaddr_in/in6=openbsd
+ "mpls3,label", // sockaddr_mpls=dragonfly, sockaddr_rtlabel=openbsd
+}
+
+func (f addrFlags) String() string {
+ var s string
+ for i, name := range addrFlagNames {
+ if f&(1<<uint(i)) != 0 {
+ if s != "" {
+ s += "|"
+ }
+ s += name
+ }
+ }
+ if s == "" {
+ return "<nil>"
+ }
+ return s
+}
+
+type sockaddrs []syscall.Sockaddr
+
+func (sas sockaddrs) String() string {
+ var s string
+ for _, sa := range sas {
+ if sa == nil {
+ continue
+ }
+ if len(s) > 0 {
+ s += " "
+ }
+ switch sa := sa.(type) {
+ case *syscall.SockaddrDatalink:
+ s += fmt.Sprintf("[%v/%v/%v t/n/a/s=%v/%v/%v/%v]", sa.Len, addrFamily(sa.Family), sa.Index, sa.Type, sa.Nlen, sa.Alen, sa.Slen)
+ case *syscall.SockaddrInet4:
+ s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To4())
+ case *syscall.SockaddrInet6:
+ s += fmt.Sprintf("%v", net.IP(sa.Addr[:]).To16())
+ }
+ }
+ if s == "" {
+ return "<nil>"
+ }
+ return s
+}
+
+func (sas sockaddrs) match(flags addrFlags) error {
+ var f addrFlags
+ family := syscall.AF_UNSPEC
+ for i := range sas {
+ if sas[i] != nil {
+ f |= 1 << uint(i)
+ }
+ switch sas[i].(type) {
+ case *syscall.SockaddrInet4:
+ if family == syscall.AF_UNSPEC {
+ family = syscall.AF_INET
+ }
+ if family != syscall.AF_INET {
+ return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
+ }
+ case *syscall.SockaddrInet6:
+ if family == syscall.AF_UNSPEC {
+ family = syscall.AF_INET6
+ }
+ if family != syscall.AF_INET6 {
+ return fmt.Errorf("got %v; want %v", sockaddrs(sas), family)
+ }
+ }
+ }
+ if f != flags {
+ return fmt.Errorf("got %v; want %v", f, flags)
+ }
+ return nil
+}
diff --git a/libgo/go/syscall/route_darwin.go b/libgo/go/syscall/route_darwin.go
index ad279072305..89bca12f3e1 100644
--- a/libgo/go/syscall/route_darwin.go
+++ b/libgo/go/syscall/route_darwin.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Routing sockets and messages for Darwin
-
package syscall
import "unsafe"
@@ -33,29 +31,37 @@ type InterfaceMulticastAddrMessage struct {
Data []byte
}
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
- if m.Header.Addrs&rtaIfmaMask == 0 {
- return nil
- }
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
b := m.Data[:]
- for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+ for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
- switch i {
- case RTAX_IFA:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != nil {
- return nil
+ switch rsa.Family {
+ case AF_LINK:
+ sa, err := parseSockaddrLink(b)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ case AF_INET, AF_INET6:
+ sa, err := parseSockaddrInet(b, rsa.Family)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ default:
+ sa, l, err := parseLinkLayerAddr(b)
+ if err != nil {
+ return nil, err
}
- sas = append(sas, sa)
- case RTAX_GATEWAY, RTAX_IFP:
- // nothing to do
+ sas[i] = sa
+ b = b[l:]
}
- b = b[rsaAlignOf(int(rsa.Len)):]
}
- return sas
+ return sas[:], nil
}
diff --git a/libgo/go/syscall/route_dragonfly.go b/libgo/go/syscall/route_dragonfly.go
index 79190d2b01b..5226f7f2e4c 100644
--- a/libgo/go/syscall/route_dragonfly.go
+++ b/libgo/go/syscall/route_dragonfly.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Routing sockets and messages for Dragonfly
-
package syscall
import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
switch any.Type {
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
p := (*RouteMessage)(unsafe.Pointer(any))
+ // We don't support sockaddr_mpls for now.
+ p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
case RTM_IFINFO:
p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -35,7 +35,7 @@ type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
@@ -44,29 +44,37 @@ type InterfaceMulticastAddrMessage struct {
Data []byte
}
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
- if m.Header.Addrs&rtaIfmaMask == 0 {
- return nil
- }
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
b := m.Data[:]
- for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+ for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
- switch i {
- case RTAX_IFA:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != nil {
- return nil
+ switch rsa.Family {
+ case AF_LINK:
+ sa, err := parseSockaddrLink(b)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ case AF_INET, AF_INET6:
+ sa, err := parseSockaddrInet(b, rsa.Family)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ default:
+ sa, l, err := parseLinkLayerAddr(b)
+ if err != nil {
+ return nil, err
}
- sas = append(sas, sa)
- case RTAX_GATEWAY, RTAX_IFP:
- // nothing to do
+ sas[i] = sa
+ b = b[l:]
}
- b = b[rsaAlignOf(int(rsa.Len)):]
}
- return sas
+ return sas[:], nil
}
diff --git a/libgo/go/syscall/route_freebsd.go b/libgo/go/syscall/route_freebsd.go
index 15897b1aca9..0e181038555 100644
--- a/libgo/go/syscall/route_freebsd.go
+++ b/libgo/go/syscall/route_freebsd.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Routing sockets and messages for FreeBSD
-
package syscall
import "unsafe"
@@ -13,13 +11,31 @@ var freebsdVersion uint32
func init() {
freebsdVersion, _ = SysctlUint32("kern.osreldate")
+ conf, _ := Sysctl("kern.conftxt")
+ for i, j := 0, 0; j < len(conf); j++ {
+ if conf[j] != '\n' {
+ continue
+ }
+ s := conf[i:j]
+ i = j + 1
+ if len(s) > len("machine") && s[:len("machine")] == "machine" {
+ s = s[len("machine"):]
+ for k := 0; k < len(s); k++ {
+ if s[k] == ' ' || s[k] == '\t' {
+ s = s[1:]
+ }
+ break
+ }
+ freebsdConfArch = s
+ break
+ }
+ }
}
func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
switch any.Type {
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
- p := (*RouteMessage)(unsafe.Pointer(any))
- return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
+ return any.parseRouteMessage(b)
case RTM_IFINFO:
return any.parseInterfaceMessage(b)
case RTM_IFANNOUNCE:
@@ -41,7 +57,7 @@ type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
// InterfaceMulticastAddrMessage represents a routing message
// containing network interface address entries.
@@ -50,29 +66,37 @@ type InterfaceMulticastAddrMessage struct {
Data []byte
}
-const rtaIfmaMask = RTA_GATEWAY | RTA_IFP | RTA_IFA
-
-func (m *InterfaceMulticastAddrMessage) sockaddr() (sas []Sockaddr) {
- if m.Header.Addrs&rtaIfmaMask == 0 {
- return nil
- }
+func (m *InterfaceMulticastAddrMessage) sockaddr() ([]Sockaddr, error) {
+ var sas [RTAX_MAX]Sockaddr
b := m.Data[:]
- for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaIfmaMask&(1<<i) == 0 {
+ for i := uint(0); i < RTAX_MAX && len(b) >= minRoutingSockaddrLen; i++ {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
- switch i {
- case RTAX_IFA:
- sa, e := anyToSockaddr((*RawSockaddrAny)(unsafe.Pointer(rsa)))
- if e != nil {
- return nil
+ switch rsa.Family {
+ case AF_LINK:
+ sa, err := parseSockaddrLink(b)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ case AF_INET, AF_INET6:
+ sa, err := parseSockaddrInet(b, rsa.Family)
+ if err != nil {
+ return nil, err
+ }
+ sas[i] = sa
+ b = b[rsaAlignOf(int(rsa.Len)):]
+ default:
+ sa, l, err := parseLinkLayerAddr(b)
+ if err != nil {
+ return nil, err
}
- sas = append(sas, sa)
- case RTAX_GATEWAY, RTAX_IFP:
- // nothing to do
+ sas[i] = sa
+ b = b[l:]
}
- b = b[rsaAlignOf(int(rsa.Len)):]
}
- return sas
+ return sas[:], nil
}
diff --git a/libgo/go/syscall/route_freebsd_32bit.go b/libgo/go/syscall/route_freebsd_32bit.go
index 93efdddb3bb..5c10b05e24d 100644
--- a/libgo/go/syscall/route_freebsd_32bit.go
+++ b/libgo/go/syscall/route_freebsd_32bit.go
@@ -8,6 +8,15 @@ package syscall
import "unsafe"
+func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ off := int(unsafe.Offsetof(p.Header.Rmx)) + SizeofRtMetrics
+ if freebsdConfArch == "amd64" {
+ off += SizeofRtMetrics // rt_metrics on amd64 is simply doubled
+ }
+ return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(off):any.Msglen]}
+}
+
func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
p := (*InterfaceMessage)(unsafe.Pointer(any))
// FreeBSD 10 and beyond have a restructured mbuf
@@ -18,7 +27,7 @@ func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
p.Header.Data.Hwassist = uint32(m.Data.Hwassist)
p.Header.Data.Epoch = m.Data.Epoch
p.Header.Data.Lastchange = m.Data.Lastchange
- return &InterfaceMessage{Header: p.Header, Data: b[sizeofIfMsghdr:any.Msglen]}
+ return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
}
- return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+ return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
}
diff --git a/libgo/go/syscall/route_freebsd_64bit.go b/libgo/go/syscall/route_freebsd_64bit.go
index 9377f2fedca..728837ebb5a 100644
--- a/libgo/go/syscall/route_freebsd_64bit.go
+++ b/libgo/go/syscall/route_freebsd_64bit.go
@@ -8,7 +8,12 @@ package syscall
import "unsafe"
+func (any *anyMessage) parseRouteMessage(b []byte) *RouteMessage {
+ p := (*RouteMessage)(unsafe.Pointer(any))
+ return &RouteMessage{Header: p.Header, Data: b[rsaAlignOf(int(unsafe.Offsetof(p.Header.Rmx))+SizeofRtMetrics):any.Msglen]}
+}
+
func (any *anyMessage) parseInterfaceMessage(b []byte) *InterfaceMessage {
p := (*InterfaceMessage)(unsafe.Pointer(any))
- return &InterfaceMessage{Header: p.Header, Data: b[SizeofIfMsghdr:any.Msglen]}
+ return &InterfaceMessage{Header: p.Header, Data: b[int(unsafe.Offsetof(p.Header.Data))+int(p.Header.Data.Datalen) : any.Msglen]}
}
diff --git a/libgo/go/syscall/route_ifma_test.go b/libgo/go/syscall/route_ifma_test.go
new file mode 100644
index 00000000000..af2b67dc244
--- /dev/null
+++ b/libgo/go/syscall/route_ifma_test.go
@@ -0,0 +1,74 @@
+// Copyright 2015 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.
+
+// +build darwin dragonfly freebsd
+
+package syscall_test
+
+import (
+ "fmt"
+ "syscall"
+)
+
+func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
+ switch m := m.(type) {
+ case *syscall.RouteMessage:
+ errno := syscall.Errno(uintptr(m.Header.Errno))
+ if errno != 0 {
+ return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
+ }
+ return addrFlags(m.Header.Addrs), nil
+ case *syscall.InterfaceMessage:
+ return addrFlags(m.Header.Addrs), nil
+ case *syscall.InterfaceAddrMessage:
+ return addrFlags(m.Header.Addrs), nil
+ case *syscall.InterfaceMulticastAddrMessage:
+ return addrFlags(m.Header.Addrs), nil
+ default:
+ panic(fmt.Sprintf("unknown routing message type: %T", m))
+ }
+}
+
+func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
+ switch m := m.(type) {
+ case *syscall.RouteMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ case *syscall.InterfaceMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ case *syscall.InterfaceAddrMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ case *syscall.InterfaceMulticastAddrMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ default:
+ panic(fmt.Sprintf("unknown routing message type: %T", m))
+ }
+}
diff --git a/libgo/go/syscall/route_netbsd.go b/libgo/go/syscall/route_netbsd.go
index 9883aebaf5f..d605ffa30f8 100644
--- a/libgo/go/syscall/route_netbsd.go
+++ b/libgo/go/syscall/route_netbsd.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Routing sockets and messages for NetBSD
-
package syscall
import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
switch any.Type {
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
p := (*RouteMessage)(unsafe.Pointer(any))
+ // We don't support sockaddr_mpls for now.
+ p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR
return &RouteMessage{Header: p.Header, Data: b[SizeofRtMsghdr:any.Msglen]}
case RTM_IFINFO:
p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
diff --git a/libgo/go/syscall/route_noifma_test.go b/libgo/go/syscall/route_noifma_test.go
new file mode 100644
index 00000000000..19d5d8ebbf2
--- /dev/null
+++ b/libgo/go/syscall/route_noifma_test.go
@@ -0,0 +1,63 @@
+// Copyright 2015 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.
+
+// +build netbsd openbsd
+
+package syscall_test
+
+import (
+ "fmt"
+ "syscall"
+)
+
+func parseRoutingMessageHeader(m syscall.RoutingMessage) (addrFlags, error) {
+ switch m := m.(type) {
+ case *syscall.RouteMessage:
+ errno := syscall.Errno(uintptr(m.Header.Errno))
+ if errno != 0 {
+ return 0, fmt.Errorf("%T: %v, %#v", m, errno, m.Header)
+ }
+ return addrFlags(m.Header.Addrs), nil
+ case *syscall.InterfaceMessage:
+ return addrFlags(m.Header.Addrs), nil
+ case *syscall.InterfaceAddrMessage:
+ return addrFlags(m.Header.Addrs), nil
+ default:
+ panic(fmt.Sprintf("unknown routing message type: %T", m))
+ }
+}
+
+func parseRoutingSockaddrs(m syscall.RoutingMessage) ([]syscall.Sockaddr, error) {
+ switch m := m.(type) {
+ case *syscall.RouteMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ case *syscall.InterfaceMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ case *syscall.InterfaceAddrMessage:
+ sas, err := syscall.ParseRoutingSockaddr(m)
+ if err != nil {
+ return nil, fmt.Errorf("%T: %v, %#v", m, err, m.Data)
+ }
+ if err = sockaddrs(sas).match(addrFlags(m.Header.Addrs)); err != nil {
+ return nil, err
+ }
+ return sas, nil
+ default:
+ panic(fmt.Sprintf("unknown routing message type: %T", m))
+ }
+}
diff --git a/libgo/go/syscall/route_openbsd.go b/libgo/go/syscall/route_openbsd.go
index e5086400c5d..7804a08910e 100644
--- a/libgo/go/syscall/route_openbsd.go
+++ b/libgo/go/syscall/route_openbsd.go
@@ -2,8 +2,6 @@
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Routing sockets and messages for OpenBSD
-
package syscall
import "unsafe"
@@ -12,6 +10,8 @@ func (any *anyMessage) toRoutingMessage(b []byte) RoutingMessage {
switch any.Type {
case RTM_ADD, RTM_DELETE, RTM_CHANGE, RTM_GET, RTM_LOSING, RTM_REDIRECT, RTM_MISS, RTM_LOCK, RTM_RESOLVE:
p := (*RouteMessage)(unsafe.Pointer(any))
+ // We don't support sockaddr_rtlabel for now.
+ p.Header.Addrs &= RTA_DST | RTA_GATEWAY | RTA_NETMASK | RTA_GENMASK | RTA_IFA | RTA_IFP | RTA_BRD | RTA_AUTHOR | RTA_SRC | RTA_SRCMASK
return &RouteMessage{Header: p.Header, Data: b[p.Header.Hdrlen:any.Msglen]}
case RTM_IFINFO:
p := (*InterfaceMessage)(unsafe.Pointer(any))
@@ -32,4 +32,4 @@ type InterfaceAnnounceMessage struct {
Header IfAnnounceMsghdr
}
-func (m *InterfaceAnnounceMessage) sockaddr() (sas []Sockaddr) { return nil }
+func (m *InterfaceAnnounceMessage) sockaddr() ([]Sockaddr, error) { return nil, nil }
diff --git a/libgo/go/syscall/security_windows.go b/libgo/go/syscall/security_windows.go
index b22ecf578e0..1625b07ae4b 100644
--- a/libgo/go/syscall/security_windows.go
+++ b/libgo/go/syscall/security_windows.go
@@ -41,21 +41,20 @@ func TranslateAccountName(username string, from, to uint32, initSize int) (strin
if e != nil {
return "", e
}
- b := make([]uint16, 50)
- n := uint32(len(b))
- e = TranslateName(u, from, to, &b[0], &n)
- if e != nil {
+ n := uint32(50)
+ for {
+ b := make([]uint16, n)
+ e = TranslateName(u, from, to, &b[0], &n)
+ if e == nil {
+ return UTF16ToString(b[:n]), nil
+ }
if e != ERROR_INSUFFICIENT_BUFFER {
return "", e
}
- // make receive buffers of requested size and try again
- b = make([]uint16, n)
- e = TranslateName(u, from, to, &b[0], &n)
- if e != nil {
+ if n <= uint32(len(b)) {
return "", e
}
}
- return UTF16ToString(b), nil
}
const (
@@ -136,26 +135,23 @@ func LookupSID(system, account string) (sid *SID, domain string, accType uint32,
return nil, "", 0, e
}
}
- db := make([]uint16, 50)
- dn := uint32(len(db))
- b := make([]byte, 50)
- n := uint32(len(b))
- sid = (*SID)(unsafe.Pointer(&b[0]))
- e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
- if e != nil {
+ n := uint32(50)
+ dn := uint32(50)
+ for {
+ b := make([]byte, n)
+ db := make([]uint16, dn)
+ sid = (*SID)(unsafe.Pointer(&b[0]))
+ e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
+ if e == nil {
+ return sid, UTF16ToString(db), accType, nil
+ }
if e != ERROR_INSUFFICIENT_BUFFER {
return nil, "", 0, e
}
- // make receive buffers of requested size and try again
- b = make([]byte, n)
- sid = (*SID)(unsafe.Pointer(&b[0]))
- db = make([]uint16, dn)
- e = LookupAccountName(sys, acc, sid, &n, &db[0], &dn, &accType)
- if e != nil {
+ if n <= uint32(len(b)) {
return nil, "", 0, e
}
}
- return sid, UTF16ToString(db), accType, nil
}
// String converts sid to a string format
@@ -197,24 +193,22 @@ func (sid *SID) LookupAccount(system string) (account, domain string, accType ui
return "", "", 0, err
}
}
- b := make([]uint16, 50)
- n := uint32(len(b))
- db := make([]uint16, 50)
- dn := uint32(len(db))
- e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
- if e != nil {
+ n := uint32(50)
+ dn := uint32(50)
+ for {
+ b := make([]uint16, n)
+ db := make([]uint16, dn)
+ e := LookupAccountSid(sys, sid, &b[0], &n, &db[0], &dn, &accType)
+ if e == nil {
+ return UTF16ToString(b), UTF16ToString(db), accType, nil
+ }
if e != ERROR_INSUFFICIENT_BUFFER {
return "", "", 0, e
}
- // make receive buffers of requested size and try again
- b = make([]uint16, n)
- db = make([]uint16, dn)
- e = LookupAccountSid(nil, sid, &b[0], &n, &db[0], &dn, &accType)
- if e != nil {
+ if n <= uint32(len(b)) {
return "", "", 0, e
}
}
- return UTF16ToString(b), UTF16ToString(db), accType, nil
}
const (
@@ -326,21 +320,20 @@ func (t Token) Close() error {
// getInfo retrieves a specified type of information about an access token.
func (t Token) getInfo(class uint32, initSize int) (unsafe.Pointer, error) {
- b := make([]byte, initSize)
- var n uint32
- e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
- if e != nil {
+ n := uint32(initSize)
+ for {
+ b := make([]byte, n)
+ e := GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
+ if e == nil {
+ return unsafe.Pointer(&b[0]), nil
+ }
if e != ERROR_INSUFFICIENT_BUFFER {
return nil, e
}
- // make receive buffers of requested size and try again
- b = make([]byte, n)
- e = GetTokenInformation(t, class, &b[0], uint32(len(b)), &n)
- if e != nil {
+ if n <= uint32(len(b)) {
return nil, e
}
}
- return unsafe.Pointer(&b[0]), nil
}
// GetTokenUser retrieves access token t user account information.
@@ -366,19 +359,18 @@ func (t Token) GetTokenPrimaryGroup() (*Tokenprimarygroup, error) {
// GetUserProfileDirectory retrieves path to the
// root directory of the access token t user's profile.
func (t Token) GetUserProfileDirectory() (string, error) {
- b := make([]uint16, 100)
- n := uint32(len(b))
- e := GetUserProfileDirectory(t, &b[0], &n)
- if e != nil {
+ n := uint32(100)
+ for {
+ b := make([]uint16, n)
+ e := GetUserProfileDirectory(t, &b[0], &n)
+ if e == nil {
+ return UTF16ToString(b), nil
+ }
if e != ERROR_INSUFFICIENT_BUFFER {
return "", e
}
- // make receive buffers of requested size and try again
- b = make([]uint16, n)
- e = GetUserProfileDirectory(t, &b[0], &n)
- if e != nil {
+ if n <= uint32(len(b)) {
return "", e
}
}
- return UTF16ToString(b), nil
}
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index ef9d7d65973..ff09711ae04 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -20,7 +20,7 @@
//
// NOTE: This package is locked down. Code outside the standard
// Go repository should be migrated to use the corresponding
-// package in the go.sys subrepository. That is also where updates
+// package in the golang.org/x/sys repository. That is also where updates
// required by new systems or versions should be applied.
// See https://golang.org/s/go1.4-syscall for more information.
//
@@ -28,9 +28,11 @@ package syscall
import "unsafe"
-// StringByteSlice is deprecated. Use ByteSliceFromString instead.
+// StringByteSlice converts a string to a NUL-terminated []byte,
// If s contains a NUL byte this function panics instead of
// returning an error.
+//
+// Deprecated: Use ByteSliceFromString instead.
func StringByteSlice(s string) []byte {
a, err := ByteSliceFromString(s)
if err != nil {
@@ -53,9 +55,11 @@ func ByteSliceFromString(s string) ([]byte, error) {
return a, nil
}
-// StringBytePtr is deprecated. Use BytePtrFromString instead.
-// If s contains a NUL byte this function panics instead of
-// returning an error.
+// StringBytePtr returns a pointer to a NUL-terminated array of bytes.
+// If s contains a NUL byte this function panics instead of returning
+// an error.
+//
+// Deprecated: Use BytePtrFromString instead.
func StringBytePtr(s string) *byte { return &StringByteSlice(s)[0] }
// BytePtrFromString returns a pointer to a NUL-terminated array of
diff --git a/libgo/go/syscall/syscall_linux_test.go b/libgo/go/syscall/syscall_linux_test.go
new file mode 100644
index 00000000000..40fce6d68c6
--- /dev/null
+++ b/libgo/go/syscall/syscall_linux_test.go
@@ -0,0 +1,140 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package syscall_test
+
+import (
+ "bufio"
+ "fmt"
+ "io"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "os/signal"
+ "path/filepath"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestMain(m *testing.M) {
+ if os.Getenv("GO_DEATHSIG_PARENT") == "1" {
+ deathSignalParent()
+ } else if os.Getenv("GO_DEATHSIG_CHILD") == "1" {
+ deathSignalChild()
+ }
+
+ os.Exit(m.Run())
+}
+
+func TestLinuxDeathSignal(t *testing.T) {
+ if os.Getuid() != 0 {
+ t.Skip("skipping root only test")
+ }
+
+ // Copy the test binary to a location that a non-root user can read/execute
+ // after we drop privileges
+ tempDir, err := ioutil.TempDir("", "TestDeathSignal")
+ if err != nil {
+ t.Fatalf("cannot create temporary directory: %v", err)
+ }
+ defer os.RemoveAll(tempDir)
+ os.Chmod(tempDir, 0755)
+
+ tmpBinary := filepath.Join(tempDir, filepath.Base(os.Args[0]))
+
+ src, err := os.Open(os.Args[0])
+ if err != nil {
+ t.Fatalf("cannot open binary %q, %v", os.Args[0], err)
+ }
+ defer src.Close()
+
+ dst, err := os.OpenFile(tmpBinary, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0755)
+ if err != nil {
+ t.Fatalf("cannot create temporary binary %q, %v", tmpBinary, err)
+ }
+ if _, err := io.Copy(dst, src); err != nil {
+ t.Fatalf("failed to copy test binary to %q, %v", tmpBinary, err)
+ }
+ err = dst.Close()
+ if err != nil {
+ t.Fatalf("failed to close test binary %q, %v", tmpBinary, err)
+ }
+
+ cmd := exec.Command(tmpBinary)
+ cmd.Env = []string{"GO_DEATHSIG_PARENT=1"}
+ chldStdin, err := cmd.StdinPipe()
+ if err != nil {
+ t.Fatal("failed to create new stdin pipe: %v", err)
+ }
+ chldStdout, err := cmd.StdoutPipe()
+ if err != nil {
+ t.Fatal("failed to create new stdout pipe: %v", err)
+ }
+ cmd.Stderr = os.Stderr
+
+ err = cmd.Start()
+ defer cmd.Wait()
+ if err != nil {
+ t.Fatalf("failed to start first child process: %v", err)
+ }
+
+ chldPipe := bufio.NewReader(chldStdout)
+
+ if got, err := chldPipe.ReadString('\n'); got == "start\n" {
+ syscall.Kill(cmd.Process.Pid, syscall.SIGTERM)
+
+ go func() {
+ time.Sleep(5 * time.Second)
+ chldStdin.Close()
+ }()
+
+ want := "ok\n"
+ if got, err = chldPipe.ReadString('\n'); got != want {
+ t.Fatalf("expected %q, received %q, %v", want, got, err)
+ }
+ } else {
+ t.Fatalf("did not receive start from child, received %q, %v", got, err)
+ }
+}
+
+func deathSignalParent() {
+ cmd := exec.Command(os.Args[0])
+ cmd.Env = []string{"GO_DEATHSIG_CHILD=1"}
+ cmd.Stdin = os.Stdin
+ cmd.Stdout = os.Stdout
+ attrs := syscall.SysProcAttr{
+ Pdeathsig: syscall.SIGUSR1,
+ // UID/GID 99 is the user/group "nobody" on RHEL/Fedora and is
+ // unused on Ubuntu
+ Credential: &syscall.Credential{Uid: 99, Gid: 99},
+ }
+ cmd.SysProcAttr = &attrs
+
+ err := cmd.Start()
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "death signal parent error: %v\n")
+ os.Exit(1)
+ }
+ cmd.Wait()
+ os.Exit(0)
+}
+
+func deathSignalChild() {
+ c := make(chan os.Signal, 1)
+ signal.Notify(c, syscall.SIGUSR1)
+ go func() {
+ <-c
+ fmt.Println("ok")
+ os.Exit(0)
+ }()
+ fmt.Println("start")
+
+ buf := make([]byte, 32)
+ os.Stdin.Read(buf)
+
+ // We expected to be signaled before stdin closed
+ fmt.Println("not ok")
+ os.Exit(1)
+}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index 74f10c29da5..21bf6eafb11 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -172,6 +172,30 @@ func Munmap(b []byte) (err error) {
return mapper.Munmap(b)
}
+// Do the interface allocations only once for common
+// Errno values.
+var (
+ errEAGAIN error = EAGAIN
+ errEINVAL error = EINVAL
+ errENOENT error = ENOENT
+)
+
+// 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
+}
+
// A Signal is a number describing a process signal.
// It implements the os.Signal interface.
type Signal int
diff --git a/libgo/go/syscall/syscall_unix_test.go b/libgo/go/syscall/syscall_unix_test.go
index 897ad18a974..c7b4560b76b 100644
--- a/libgo/go/syscall/syscall_unix_test.go
+++ b/libgo/go/syscall/syscall_unix_test.go
@@ -9,6 +9,7 @@ package syscall_test
import (
"flag"
"fmt"
+ "internal/testenv"
"io/ioutil"
"net"
"os"
@@ -60,20 +61,58 @@ func _() {
// TestFcntlFlock tests whether the file locking structure matches
// the calling convention of each kernel.
+// On some Linux systems, glibc uses another set of values for the
+// commands and translates them to the correct value that the kernel
+// expects just before the actual fcntl syscall. As Go uses raw
+// syscalls directly, it must use the real value, not the glibc value.
+// Thus this test also verifies that the Flock_t structure can be
+// roundtripped with F_SETLK and F_GETLK.
func TestFcntlFlock(t *testing.T) {
- name := filepath.Join(os.TempDir(), "TestFcntlFlock")
- fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
- if err != nil {
- t.Fatalf("Open failed: %v", err)
+ if runtime.GOOS == "darwin" && (runtime.GOARCH == "arm" || runtime.GOARCH == "arm64") {
+ t.Skip("skipping; no child processes allowed on iOS")
}
- defer syscall.Unlink(name)
- defer syscall.Close(fd)
flock := syscall.Flock_t{
- Type: syscall.F_RDLCK,
- Start: 0, Len: 0, Whence: 1,
+ Type: syscall.F_WRLCK,
+ Start: 31415, Len: 271828, Whence: 1,
}
- if err := syscall.FcntlFlock(uintptr(fd), syscall.F_GETLK, &flock); err != nil {
- t.Fatalf("FcntlFlock failed: %v", err)
+ if os.Getenv("GO_WANT_HELPER_PROCESS") == "" {
+ // parent
+ name := filepath.Join(os.TempDir(), "TestFcntlFlock")
+ fd, err := syscall.Open(name, syscall.O_CREAT|syscall.O_RDWR|syscall.O_CLOEXEC, 0)
+ if err != nil {
+ t.Fatalf("Open failed: %v", err)
+ }
+ defer syscall.Unlink(name)
+ defer syscall.Close(fd)
+ if err := syscall.Ftruncate(fd, 1<<20); err != nil {
+ t.Fatalf("Ftruncate(1<<20) failed: %v", err)
+ }
+ if err := syscall.FcntlFlock(uintptr(fd), syscall.F_SETLK, &flock); err != nil {
+ t.Fatalf("FcntlFlock(F_SETLK) failed: %v", err)
+ }
+ cmd := exec.Command(os.Args[0], "-test.run=^TestFcntlFlock$")
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
+ cmd.ExtraFiles = []*os.File{os.NewFile(uintptr(fd), name)}
+ out, err := cmd.CombinedOutput()
+ if len(out) > 0 || err != nil {
+ t.Fatalf("child process: %q, %v", out, err)
+ }
+ } else {
+ // child
+ got := flock
+ // make sure the child lock is conflicting with the parent lock
+ got.Start--
+ got.Len++
+ if err := syscall.FcntlFlock(3, syscall.F_GETLK, &got); err != nil {
+ t.Fatalf("FcntlFlock(F_GETLK) failed: %v", err)
+ }
+ flock.Pid = int32(syscall.Getppid())
+ // Linux kernel always set Whence to 0
+ flock.Whence = 0
+ if got.Type == flock.Type && got.Start == flock.Start && got.Len == flock.Len && got.Pid == flock.Pid && got.Whence == flock.Whence {
+ os.Exit(0)
+ }
+ t.Fatalf("FcntlFlock got %v, want %v", got, flock)
}
}
@@ -93,6 +132,9 @@ func TestPassFD(t *testing.T) {
// TODO(aram): Figure out why ReadMsgUnix is returning empty message.
t.Skip("skipping test on solaris, see issue 7402")
}
+
+ testenv.MustHaveExec(t)
+
if os.Getenv("GO_WANT_HELPER_PROCESS") == "1" {
passFDChild()
return
@@ -116,11 +158,7 @@ func TestPassFD(t *testing.T) {
defer readFile.Close()
cmd := exec.Command(os.Args[0], "-test.run=^TestPassFD$", "--", tempDir)
- cmd.Env = []string{"GO_WANT_HELPER_PROCESS=1"}
- path := os.Getenv("LD_LIBRARY_PATH")
- if path != "" {
- cmd.Env = append(cmd.Env, "LD_LIBRARY_PATH="+path)
- }
+ cmd.Env = append(os.Environ(), "GO_WANT_HELPER_PROCESS=1")
cmd.ExtraFiles = []*os.File{writeFile}
out, err := cmd.CombinedOutput()
@@ -179,7 +217,7 @@ func passFDChild() {
defer os.Exit(0)
// Look for our fd. It should be fd 3, but we work around an fd leak
- // bug here (http://golang.org/issue/2603) to let it be elsewhere.
+ // bug here (https://golang.org/issue/2603) to let it be elsewhere.
var uc *net.UnixConn
for fd := uintptr(3); fd <= 10; fd++ {
f := os.NewFile(fd, "unix-conn")