summaryrefslogtreecommitdiff
path: root/libgo/go/syscall
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-15 00:27:56 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2015-01-15 00:27:56 +0000
commitf11c215565ea0c863197b9666581d69c225619c2 (patch)
tree58a1724fee16d2b03c65678c4dd9b50bb97137a9 /libgo/go/syscall
parent2bbc72db3287d2bff87b9640e85830337aac0672 (diff)
downloadgcc-f11c215565ea0c863197b9666581d69c225619c2.tar.gz
libgo, compiler: Upgrade libgo to Go 1.4, except for runtime.
This upgrades all of libgo other than the runtime package to the Go 1.4 release. In Go 1.4 much of the runtime was rewritten into Go. Merging that code will take more time and will not change the API, so I'm putting it off for now. There are a few runtime changes anyhow, to accomodate other packages that rely on minor modifications to the runtime support. The compiler changes slightly to add a one-bit flag to each type descriptor kind that is stored directly in an interface, which for gccgo is currently only pointer types. Another one-bit flag (gcprog) is reserved because it is used by the gc compiler, but gccgo does not currently use it. There is another error check in the compiler since I ran across it during testing. gotools/: * Makefile.am (go_cmd_go_files): Sort entries. Add generate.go. * Makefile.in: Rebuild. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@219627 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'libgo/go/syscall')
-rw-r--r--libgo/go/syscall/env_plan9.go86
-rw-r--r--libgo/go/syscall/env_unix.go60
-rw-r--r--libgo/go/syscall/env_windows.go8
-rw-r--r--libgo/go/syscall/exec_linux.go123
-rw-r--r--libgo/go/syscall/exec_windows.go15
-rw-r--r--libgo/go/syscall/export_test.go7
-rw-r--r--libgo/go/syscall/netlink_linux.go3
-rw-r--r--libgo/go/syscall/route_bsd.go2
-rw-r--r--libgo/go/syscall/str.go6
-rw-r--r--libgo/go/syscall/syscall.go12
-rw-r--r--libgo/go/syscall/syscall_errno.go2
-rw-r--r--libgo/go/syscall/syscall_test.go17
-rw-r--r--libgo/go/syscall/syscall_unix.go2
13 files changed, 244 insertions, 99 deletions
diff --git a/libgo/go/syscall/env_plan9.go b/libgo/go/syscall/env_plan9.go
index 9587ab5af9d..9ea36c886ab 100644
--- a/libgo/go/syscall/env_plan9.go
+++ b/libgo/go/syscall/env_plan9.go
@@ -8,22 +8,9 @@ package syscall
import (
"errors"
- "sync"
)
var (
- // envOnce guards copyenv, which populates env.
- envOnce sync.Once
-
- // envLock guards env and envs.
- envLock sync.RWMutex
-
- // env maps from an environment variable to its value.
- env = make(map[string]string)
-
- // envs contains elements of env in the form "key=value".
- envs []string
-
errZeroLengthKey = errors.New("zero length key")
errShortWrite = errors.New("i/o count too small")
)
@@ -64,46 +51,14 @@ func writeenv(key, value string) error {
return nil
}
-func copyenv() {
- fd, err := Open("/env", O_RDONLY)
- if err != nil {
- return
- }
- defer Close(fd)
- files, err := readdirnames(fd)
- if err != nil {
- return
- }
- envs = make([]string, len(files))
- i := 0
- for _, key := range files {
- v, err := readenv(key)
- if err != nil {
- continue
- }
- env[key] = v
- envs[i] = key + "=" + v
- i++
- }
-}
-
func Getenv(key string) (value string, found bool) {
if len(key) == 0 {
return "", false
}
-
- envLock.RLock()
- defer envLock.RUnlock()
-
- if v, ok := env[key]; ok {
- return v, true
- }
v, err := readenv(key)
if err != nil {
return "", false
}
- env[key] = v
- envs = append(envs, key+"="+v)
return v, true
}
@@ -111,32 +66,43 @@ func Setenv(key, value string) error {
if len(key) == 0 {
return errZeroLengthKey
}
-
- envLock.Lock()
- defer envLock.Unlock()
-
err := writeenv(key, value)
if err != nil {
return err
}
- env[key] = value
- envs = append(envs, key+"="+value)
return nil
}
func Clearenv() {
- envLock.Lock()
- defer envLock.Unlock()
-
- env = make(map[string]string)
- envs = []string{}
RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
}
+func Unsetenv(key string) error {
+ if len(key) == 0 {
+ return errZeroLengthKey
+ }
+ Remove("/env/" + key)
+ return nil
+}
+
func Environ() []string {
- envLock.RLock()
- defer envLock.RUnlock()
+ fd, err := Open("/env", O_RDONLY)
+ if err != nil {
+ return nil
+ }
+ defer Close(fd)
+ files, err := readdirnames(fd)
+ if err != nil {
+ return nil
+ }
+ ret := make([]string, 0, len(files))
- envOnce.Do(copyenv)
- return append([]string(nil), envs...)
+ for _, key := range files {
+ v, err := readenv(key)
+ if err != nil {
+ continue
+ }
+ ret = append(ret, key+"="+v)
+ }
+ return ret
}
diff --git a/libgo/go/syscall/env_unix.go b/libgo/go/syscall/env_unix.go
index 7f39958437c..b5ded9c763c 100644
--- a/libgo/go/syscall/env_unix.go
+++ b/libgo/go/syscall/env_unix.go
@@ -20,23 +20,33 @@ var (
// env maps from an environment variable to its first occurrence in envs.
env map[string]int
- // envs is provided by the runtime. elements are expected to be
- // of the form "key=value".
- Envs []string
+ // envs is provided by the runtime. elements are expected to
+ // be of the form "key=value". An empty string means deleted
+ // (or a duplicate to be ignored).
+ envs []string = runtime_envs()
)
-// setenv_c is provided by the runtime, but is a no-op if cgo isn't
-// loaded.
+func runtime_envs() []string // in package runtime
+
+// setenv_c and unsetenv_c are provided by the runtime but are no-ops
+// if cgo isn't loaded.
func setenv_c(k, v string)
+func unsetenv_c(k string)
func copyenv() {
env = make(map[string]int)
- for i, s := range Envs {
+ for i, s := range envs {
for j := 0; j < len(s); j++ {
if s[j] == '=' {
key := s[:j]
if _, ok := env[key]; !ok {
- env[key] = i
+ env[key] = i // first mention of key
+ } else {
+ // Clear duplicate keys. This permits Unsetenv to
+ // safely delete only the first item without
+ // worrying about unshadowing a later one,
+ // which might be a security problem.
+ envs[i] = ""
}
break
}
@@ -44,6 +54,20 @@ func copyenv() {
}
}
+func Unsetenv(key string) error {
+ envOnce.Do(copyenv)
+
+ envLock.Lock()
+ defer envLock.Unlock()
+
+ if i, ok := env[key]; ok {
+ envs[i] = ""
+ delete(env, key)
+ }
+ unsetenv_c(key)
+ return nil
+}
+
func Getenv(key string) (value string, found bool) {
envOnce.Do(copyenv)
if len(key) == 0 {
@@ -57,7 +81,7 @@ func Getenv(key string) (value string, found bool) {
if !ok {
return "", false
}
- s := Envs[i]
+ s := envs[i]
for i := 0; i < len(s); i++ {
if s[i] == '=' {
return s[i+1:], true
@@ -88,10 +112,10 @@ func Setenv(key, value string) error {
i, ok := env[key]
kv := key + "=" + value
if ok {
- Envs[i] = kv
+ envs[i] = kv
} else {
- i = len(Envs)
- Envs = append(Envs, kv)
+ i = len(envs)
+ envs = append(envs, kv)
}
env[key] = i
setenv_c(key, value)
@@ -104,16 +128,22 @@ func Clearenv() {
envLock.Lock()
defer envLock.Unlock()
+ for k := range env {
+ unsetenv_c(k)
+ }
env = make(map[string]int)
- Envs = []string{}
- // TODO(bradfitz): pass through to C
+ envs = []string{}
}
func Environ() []string {
envOnce.Do(copyenv)
envLock.RLock()
defer envLock.RUnlock()
- a := make([]string, len(Envs))
- copy(a, Envs)
+ a := make([]string, 0, len(envs))
+ for _, env := range envs {
+ if env != "" {
+ a = append(a, env)
+ }
+ }
return a
}
diff --git a/libgo/go/syscall/env_windows.go b/libgo/go/syscall/env_windows.go
index 420b3872464..bc21690d9fd 100644
--- a/libgo/go/syscall/env_windows.go
+++ b/libgo/go/syscall/env_windows.go
@@ -47,6 +47,14 @@ func Setenv(key, value string) error {
return nil
}
+func Unsetenv(key string) error {
+ keyp, err := UTF16PtrFromString(key)
+ if err != nil {
+ return err
+ }
+ return SetEnvironmentVariable(keyp, nil)
+}
+
func Clearenv() {
for _, s := range Environ() {
// Environment variables can begin with =
diff --git a/libgo/go/syscall/exec_linux.go b/libgo/go/syscall/exec_linux.go
index 2371902cbaa..97bde0c4f52 100644
--- a/libgo/go/syscall/exec_linux.go
+++ b/libgo/go/syscall/exec_linux.go
@@ -14,17 +14,27 @@ import (
//sysnb raw_prctl(option int, arg2 int, arg3 int, arg4 int, arg5 int) (ret int, err Errno)
//prctl(option _C_int, arg2 _C_long, arg3 _C_long, arg4 _C_long, arg5 _C_long) _C_int
+// SysProcIDMap holds Container ID to Host ID mappings used for User Namespaces in Linux.
+// See user_namespaces(7).
+type SysProcIDMap struct {
+ ContainerID int // Container ID.
+ HostID int // Host ID.
+ Size int // Size.
+}
+
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 Ctty (only meaningful if Setsid is set)
- Noctty bool // Detach fd 0 from controlling terminal
- Ctty int // Controlling TTY fd (Linux only)
- Pdeathsig Signal // Signal that the process will get when its parent dies (Linux only)
- Cloneflags uintptr // Flags for clone calls (Linux only)
+ 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 Ctty (only meaningful if Setsid is set)
+ Noctty bool // Detach fd 0 from controlling terminal
+ Ctty int // Controlling TTY fd (Linux only)
+ 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.
}
// Implemented in runtime package.
@@ -46,8 +56,10 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
var (
r1 uintptr
err1 Errno
+ err2 Errno
nextfd int
i int
+ p [2]int
)
// Guard against side effects of shuffling fds below.
@@ -63,6 +75,14 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
}
nextfd++
+ // Allocate another pipe for parent to child communication for
+ // synchronizing writing of User ID/Group ID mappings.
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ if err := forkExecPipe(p[:]); err != nil {
+ return 0, err.(Errno)
+ }
+ }
+
// About to call fork.
// No more allocation or calls of non-assembly functions.
runtime_BeforeFork()
@@ -79,11 +99,42 @@ func forkAndExecInChild(argv0 *byte, argv, envv []*byte, chroot, dir *byte, attr
if r1 != 0 {
// parent; return PID
runtime_AfterFork()
- return int(r1), 0
+ pid = int(r1)
+
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ Close(p[0])
+ err := writeUidGidMappings(pid, sys)
+ if err != nil {
+ err2 = err.(Errno)
+ }
+ RawSyscall(SYS_WRITE, uintptr(p[1]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
+ Close(p[1])
+ }
+
+ return pid, 0
}
// Fork succeeded, now in child.
+ // Wait for User ID/Group ID mappings to be written.
+ if sys.UidMappings != nil || sys.GidMappings != nil {
+ if _, _, err1 = RawSyscall(SYS_CLOSE, uintptr(p[1]), 0, 0); err1 != 0 {
+ goto childerror
+ }
+ r1, _, err1 = RawSyscall(SYS_READ, uintptr(p[0]), uintptr(unsafe.Pointer(&err2)), unsafe.Sizeof(err2))
+ if err1 != 0 {
+ goto childerror
+ }
+ if r1 != unsafe.Sizeof(err2) {
+ err1 = EINVAL
+ goto childerror
+ }
+ if err2 != 0 {
+ err1 = err2
+ goto childerror
+ }
+ }
+
// Parent death signal
if sys.Pdeathsig != 0 {
_, err1 = raw_prctl(PR_SET_PDEATHSIG, int(sys.Pdeathsig), 0, 0, 0)
@@ -282,3 +333,53 @@ func forkExecPipe(p []int) (err error) {
}
return
}
+
+// writeIDMappings writes the user namespace User ID or Group ID mappings to the specified path.
+func writeIDMappings(path string, idMap []SysProcIDMap) error {
+ fd, err := Open(path, O_RDWR, 0)
+ if err != nil {
+ return err
+ }
+
+ data := ""
+ for _, im := range idMap {
+ data = data + itoa(im.ContainerID) + " " + itoa(im.HostID) + " " + itoa(im.Size) + "\n"
+ }
+
+ bytes, err := ByteSliceFromString(data)
+ if err != nil {
+ Close(fd)
+ return err
+ }
+
+ if _, err := Write(fd, bytes); err != nil {
+ Close(fd)
+ return err
+ }
+
+ if err := Close(fd); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+// 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 {
+ if sys.UidMappings != nil {
+ uidf := "/proc/" + itoa(pid) + "/uid_map"
+ if err := writeIDMappings(uidf, sys.UidMappings); err != nil {
+ return err
+ }
+ }
+
+ if sys.GidMappings != nil {
+ gidf := "/proc/" + itoa(pid) + "/gid_map"
+ if err := writeIDMappings(gidf, sys.GidMappings); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
diff --git a/libgo/go/syscall/exec_windows.go b/libgo/go/syscall/exec_windows.go
index 82abc0715e5..936aeb577bc 100644
--- a/libgo/go/syscall/exec_windows.go
+++ b/libgo/go/syscall/exec_windows.go
@@ -129,9 +129,8 @@ func SetNonblock(fd Handle, nonblocking bool) (err error) {
return nil
}
-// getFullPath retrieves the full path of the specified file.
-// Just a wrapper for Windows GetFullPathName api.
-func getFullPath(name string) (path string, err error) {
+// FullPath retrieves the full path of the specified file.
+func FullPath(name string) (path string, err error) {
p, err := UTF16PtrFromString(name)
if err != nil {
return "", err
@@ -160,7 +159,7 @@ func isSlash(c uint8) bool {
}
func normalizeDir(dir string) (name string, err error) {
- ndir, err := getFullPath(dir)
+ ndir, err := FullPath(dir)
if err != nil {
return "", err
}
@@ -199,9 +198,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return "", err
}
if volToUpper(int(p[0])) == volToUpper(int(d[0])) {
- return getFullPath(d + "\\" + p[2:])
+ return FullPath(d + "\\" + p[2:])
} else {
- return getFullPath(p)
+ return FullPath(p)
}
}
} else {
@@ -211,9 +210,9 @@ func joinExeDirAndFName(dir, p string) (name string, err error) {
return "", err
}
if isSlash(p[0]) {
- return getFullPath(d[:2] + p)
+ return FullPath(d[:2] + p)
} else {
- return getFullPath(d + "\\" + p)
+ return FullPath(d + "\\" + p)
}
}
// we shouldn't be here
diff --git a/libgo/go/syscall/export_test.go b/libgo/go/syscall/export_test.go
new file mode 100644
index 00000000000..c9774622c87
--- /dev/null
+++ b/libgo/go/syscall/export_test.go
@@ -0,0 +1,7 @@
+// Copyright 2014 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
+
+var Itoa = itoa
diff --git a/libgo/go/syscall/netlink_linux.go b/libgo/go/syscall/netlink_linux.go
index 49550ea2f02..1b73dce8274 100644
--- a/libgo/go/syscall/netlink_linux.go
+++ b/libgo/go/syscall/netlink_linux.go
@@ -64,9 +64,10 @@ func NetlinkRIB(proto, family int) ([]byte, error) {
return nil, err
}
var tab []byte
+ rbNew := make([]byte, Getpagesize())
done:
for {
- rb := make([]byte, Getpagesize())
+ rb := rbNew
nr, _, err := Recvfrom(s, rb, 0)
if err != nil {
return nil, err
diff --git a/libgo/go/syscall/route_bsd.go b/libgo/go/syscall/route_bsd.go
index 48af587450b..1dabe42531b 100644
--- a/libgo/go/syscall/route_bsd.go
+++ b/libgo/go/syscall/route_bsd.go
@@ -153,7 +153,7 @@ func (m *InterfaceAddrMessage) sockaddr() (sas []Sockaddr) {
// RTAX_NETMASK socket address on the FreeBSD kernel.
preferredFamily := uint8(AF_UNSPEC)
for i := uint(0); i < RTAX_MAX; i++ {
- if m.Header.Addrs&rtaIfaMask&(1<<i) == 0 {
+ if m.Header.Addrs&(1<<i) == 0 {
continue
}
rsa := (*RawSockaddr)(unsafe.Pointer(&b[0]))
diff --git a/libgo/go/syscall/str.go b/libgo/go/syscall/str.go
index 0fce842e8c1..2ddf04b2275 100644
--- a/libgo/go/syscall/str.go
+++ b/libgo/go/syscall/str.go
@@ -6,8 +6,12 @@ package syscall
func itoa(val int) string { // do it here rather than with fmt to avoid dependency
if val < 0 {
- return "-" + itoa(-val)
+ return "-" + uitoa(uint(-val))
}
+ return uitoa(uint(val))
+}
+
+func uitoa(val uint) string {
var buf [32]byte // big enough for int64
i := len(buf) - 1
for val >= 10 {
diff --git a/libgo/go/syscall/syscall.go b/libgo/go/syscall/syscall.go
index c4f2125140e..ef9d7d65973 100644
--- a/libgo/go/syscall/syscall.go
+++ b/libgo/go/syscall/syscall.go
@@ -17,6 +17,13 @@
// These calls return err == nil to indicate success; otherwise
// err is an operating system error describing the failure.
// On most systems, that error has type syscall.Errno.
+//
+// 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
+// required by new systems or versions should be applied.
+// See https://golang.org/s/go1.4-syscall for more information.
+//
package syscall
import "unsafe"
@@ -85,3 +92,8 @@ func (ts *Timespec) Nano() int64 {
func (tv *Timeval) Nano() int64 {
return int64(tv.Sec)*1e9 + int64(tv.Usec)*1000
}
+
+// use is a no-op, but the compiler cannot see that it is.
+// Calling use(p) ensures that p is kept live until that point.
+//go:noescape
+func use(p unsafe.Pointer)
diff --git a/libgo/go/syscall/syscall_errno.go b/libgo/go/syscall/syscall_errno.go
index 810572f58a9..01618d173a1 100644
--- a/libgo/go/syscall/syscall_errno.go
+++ b/libgo/go/syscall/syscall_errno.go
@@ -18,7 +18,7 @@ func (e Errno) Error() string {
}
func (e Errno) Temporary() bool {
- return e == EINTR || e == EMFILE || e.Timeout()
+ return e == EINTR || e == EMFILE || e == ECONNRESET || e == ECONNABORTED || e.Timeout()
}
func (e Errno) Timeout() bool {
diff --git a/libgo/go/syscall/syscall_test.go b/libgo/go/syscall/syscall_test.go
index 2a39b54f1b2..846c4873d28 100644
--- a/libgo/go/syscall/syscall_test.go
+++ b/libgo/go/syscall/syscall_test.go
@@ -5,6 +5,7 @@
package syscall_test
import (
+ "fmt"
"syscall"
"testing"
)
@@ -28,3 +29,19 @@ func TestEnv(t *testing.T) {
// make sure TESTENV gets set to "", not deleted
testSetGetenv(t, "TESTENV", "")
}
+
+func TestItoa(t *testing.T) {
+ // Make most negative integer: 0x8000...
+ i := 1
+ for i<<1 != 0 {
+ i <<= 1
+ }
+ if i >= 0 {
+ t.Fatal("bad math")
+ }
+ s := syscall.Itoa(i)
+ f := fmt.Sprint(i)
+ if s != f {
+ t.Fatalf("itoa(%d) = %s, want %s", i, s, f)
+ }
+}
diff --git a/libgo/go/syscall/syscall_unix.go b/libgo/go/syscall/syscall_unix.go
index a64b05fb5cc..74f10c29da5 100644
--- a/libgo/go/syscall/syscall_unix.go
+++ b/libgo/go/syscall/syscall_unix.go
@@ -125,7 +125,7 @@ func (m *mmapper) Mmap(fd int, offset int64, length int, prot int, flags int) (d
cap int
}{addr, length, length}
- // Use unsafeto turn sl into a []byte.
+ // Use unsafe to turn sl into a []byte.
b := *(*[]byte)(unsafe.Pointer(&sl))
// Register mapping in m and return it.