diff --git a/src/pkg/os/Makefile b/src/pkg/os/Makefile
index 8923a8b480237c8ccfae794b1da40c8a8952fa1c..9bb2c0cbf157451bfd791a4787ed2197491a595b 100644
--- a/src/pkg/os/Makefile
+++ b/src/pkg/os/Makefile
@@ -20,7 +20,6 @@ GOFILES=\
 GOFILES_freebsd=\
 	dir_unix.go\
 	error_posix.go\
-	env_unix.go\
 	file_posix.go\
 	file_unix.go\
 	path_unix.go\
@@ -32,7 +31,6 @@ GOFILES_freebsd=\
 GOFILES_darwin=\
 	dir_unix.go\
 	error_posix.go\
-	env_unix.go\
 	file_posix.go\
 	file_unix.go\
 	path_unix.go\
@@ -44,7 +42,6 @@ GOFILES_darwin=\
 GOFILES_linux=\
 	dir_unix.go\
 	error_posix.go\
-	env_unix.go\
 	file_posix.go\
 	file_unix.go\
 	path_unix.go\
@@ -56,7 +53,6 @@ GOFILES_linux=\
 GOFILES_openbsd=\
 	dir_unix.go\
 	error_posix.go\
-	env_unix.go\
 	file_posix.go\
 	file_unix.go\
 	path_unix.go\
@@ -68,7 +64,6 @@ GOFILES_openbsd=\
 GOFILES_windows=\
 	dir_windows.go\
 	error_posix.go\
-	env_windows.go\
 	file_posix.go\
 	file_windows.go\
 	path_windows.go\
@@ -80,7 +75,6 @@ GOFILES_windows=\
 GOFILES_plan9=\
 	dir_plan9.go\
 	error_plan9.go\
-	env_plan9.go\
 	file_plan9.go\
 	path_plan9.go\
 	sys_plan9.go\
diff --git a/src/pkg/os/env.go b/src/pkg/os/env.go
index 4844fa3e26d61280b500c1deaa567f781016730e..7e3f52502e54ef93afec26e75991de666e19c17c 100644
--- a/src/pkg/os/env.go
+++ b/src/pkg/os/env.go
@@ -6,7 +6,10 @@
 
 package os
 
-func setenv_c(k, v string)
+import (
+	"errors"
+	"syscall"
+)
 
 // Expand replaces ${var} or $var in the string based on the mapping function.
 // Invocations of undefined variables are replaced with the empty string.
@@ -73,3 +76,47 @@ func getShellName(s string) (string, int) {
 	}
 	return s[:i], i
 }
+
+// ENOENV is the error indicating that an environment variable does not exist.
+var ENOENV = errors.New("no such environment variable")
+
+// Getenverror retrieves the value of the environment variable named by the key.
+// It returns the value and an error, if any.
+func Getenverror(key string) (value string, err error) {
+	if len(key) == 0 {
+		return "", EINVAL
+	}
+	val, found := syscall.Getenv(key)
+	if !found {
+		return "", ENOENV
+	}
+	return val, nil
+}
+
+// Getenv retrieves the value of the environment variable named by the key.
+// It returns the value, which will be empty if the variable is not present.
+func Getenv(key string) string {
+	v, _ := Getenverror(key)
+	return v
+}
+
+// Setenv sets the value of the environment variable named by the key.
+// It returns an error, if any.
+func Setenv(key, value string) error {
+	err := syscall.Setenv(key, value)
+	if err != nil {
+		return NewSyscallError("setenv", err)
+	}
+	return nil
+}
+
+// Clearenv deletes all environment variables.
+func Clearenv() {
+	syscall.Clearenv()
+}
+
+// Environ returns an array of strings representing the environment,
+// in the form "key=value".
+func Environ() []string {
+	return syscall.Environ()
+}
diff --git a/src/pkg/os/env_plan9.go b/src/pkg/os/env_plan9.go
deleted file mode 100644
index 286a5fe5a2cb840c4022540ec20ea22bcec5dff2..0000000000000000000000000000000000000000
--- a/src/pkg/os/env_plan9.go
+++ /dev/null
@@ -1,99 +0,0 @@
-// 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.
-
-// Plan 9 environment variables.
-
-package os
-
-import (
-	"errors"
-	"syscall"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
-	if len(key) == 0 {
-		return "", EINVAL
-	}
-	f, e := Open("/env/" + key)
-	if e != nil {
-		return "", ENOENV
-	}
-	defer f.Close()
-
-	l, _ := f.Seek(0, 2)
-	f.Seek(0, 0)
-	buf := make([]byte, l)
-	n, e := f.Read(buf)
-	if e != nil {
-		return "", ENOENV
-	}
-
-	if n > 0 && buf[n-1] == 0 {
-		buf = buf[:n-1]
-	}
-	return string(buf), nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
-	v, _ := Getenverror(key)
-	return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
-	if len(key) == 0 {
-		return EINVAL
-	}
-
-	f, e := Create("/env/" + key)
-	if e != nil {
-		return e
-	}
-	defer f.Close()
-
-	_, e = f.Write([]byte(value))
-	return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
-	syscall.RawSyscall(syscall.SYS_RFORK, syscall.RFCENVG, 0, 0)
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
-	env := make([]string, 0, 100)
-
-	f, e := Open("/env")
-	if e != nil {
-		panic(e)
-	}
-	defer f.Close()
-
-	names, e := f.Readdirnames(-1)
-	if e != nil {
-		panic(e)
-	}
-
-	for _, k := range names {
-		if v, e := Getenverror(k); e == nil {
-			env = append(env, k+"="+v)
-		}
-	}
-	return env[0:len(env)]
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
-	return "/tmp"
-}
diff --git a/src/pkg/os/env_unix.go b/src/pkg/os/env_unix.go
deleted file mode 100644
index 01fd9d449f36bd730a95fbc7afb1220ede4f2a9e..0000000000000000000000000000000000000000
--- a/src/pkg/os/env_unix.go
+++ /dev/null
@@ -1,112 +0,0 @@
-// Copyright 2010 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 freebsd linux openbsd
-
-// Unix environment variables.
-
-package os
-
-import (
-	"errors"
-	"sync"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-var env map[string]string
-var once sync.Once
-
-func copyenv() {
-	env = make(map[string]string)
-	for _, s := range Envs {
-		for j := 0; j < len(s); j++ {
-			if s[j] == '=' {
-				env[s[0:j]] = s[j+1:]
-				break
-			}
-		}
-	}
-}
-
-var envLock sync.RWMutex
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
-	once.Do(copyenv)
-
-	if len(key) == 0 {
-		return "", EINVAL
-	}
-
-	envLock.RLock()
-	defer envLock.RUnlock()
-
-	v, ok := env[key]
-	if !ok {
-		return "", ENOENV
-	}
-	return v, nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
-	v, _ := Getenverror(key)
-	return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
-	once.Do(copyenv)
-	if len(key) == 0 {
-		return EINVAL
-	}
-
-	envLock.Lock()
-	defer envLock.Unlock()
-
-	env[key] = value
-	setenv_c(key, value) // is a no-op if cgo isn't loaded
-	return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
-	once.Do(copyenv) // prevent copyenv in Getenv/Setenv
-
-	envLock.Lock()
-	defer envLock.Unlock()
-
-	env = make(map[string]string)
-
-	// TODO(bradfitz): pass through to C
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
-	once.Do(copyenv)
-	envLock.RLock()
-	defer envLock.RUnlock()
-	a := make([]string, len(env))
-	i := 0
-	for k, v := range env {
-		a[i] = k + "=" + v
-		i++
-	}
-	return a
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
-	dir := Getenv("TMPDIR")
-	if dir == "" {
-		dir = "/tmp"
-	}
-	return dir
-}
diff --git a/src/pkg/os/env_windows.go b/src/pkg/os/env_windows.go
deleted file mode 100644
index 88d669731caa4587076e82e75c1fb3a347c56163..0000000000000000000000000000000000000000
--- a/src/pkg/os/env_windows.go
+++ /dev/null
@@ -1,128 +0,0 @@
-// Copyright 2010 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.
-
-// Windows environment variables.
-
-package os
-
-import (
-	"errors"
-	"syscall"
-	"unicode/utf16"
-	"unsafe"
-)
-
-// ENOENV is the error indicating that an environment variable does not exist.
-var ENOENV = errors.New("no such environment variable")
-
-// Getenverror retrieves the value of the environment variable named by the key.
-// It returns the value and an error, if any.
-func Getenverror(key string) (value string, err error) {
-	b := make([]uint16, 100)
-	n, e := syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
-	if n == 0 && e == syscall.ERROR_ENVVAR_NOT_FOUND {
-		return "", ENOENV
-	}
-	if n > uint32(len(b)) {
-		b = make([]uint16, n)
-		n, e = syscall.GetEnvironmentVariable(syscall.StringToUTF16Ptr(key), &b[0], uint32(len(b)))
-		if n > uint32(len(b)) {
-			n = 0
-		}
-	}
-	if n == 0 {
-		return "", NewSyscallError("GetEnvironmentVariable", e)
-	}
-	return string(utf16.Decode(b[0:n])), nil
-}
-
-// Getenv retrieves the value of the environment variable named by the key.
-// It returns the value, which will be empty if the variable is not present.
-func Getenv(key string) string {
-	v, _ := Getenverror(key)
-	return v
-}
-
-// Setenv sets the value of the environment variable named by the key.
-// It returns an error, if any.
-func Setenv(key, value string) error {
-	var v *uint16
-	if len(value) > 0 {
-		v = syscall.StringToUTF16Ptr(value)
-	}
-	e := syscall.SetEnvironmentVariable(syscall.StringToUTF16Ptr(key), v)
-	if e != nil {
-		return NewSyscallError("SetEnvironmentVariable", e)
-	}
-	return nil
-}
-
-// Clearenv deletes all environment variables.
-func Clearenv() {
-	for _, s := range Environ() {
-		// Environment variables can begin with =
-		// so start looking for the separator = at j=1.
-		// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
-		for j := 1; j < len(s); j++ {
-			if s[j] == '=' {
-				Setenv(s[0:j], "")
-				break
-			}
-		}
-	}
-}
-
-// Environ returns an array of strings representing the environment,
-// in the form "key=value".
-func Environ() []string {
-	s, e := syscall.GetEnvironmentStrings()
-	if e != nil {
-		return nil
-	}
-	defer syscall.FreeEnvironmentStrings(s)
-	r := make([]string, 0, 50) // Empty with room to grow.
-	for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
-		if p[i] == 0 {
-			// empty string marks the end
-			if i <= from {
-				break
-			}
-			r = append(r, string(utf16.Decode(p[from:i])))
-			from = i + 1
-		}
-	}
-	return r
-}
-
-// TempDir returns the default directory to use for temporary files.
-func TempDir() string {
-	const pathSep = '\\'
-	dirw := make([]uint16, syscall.MAX_PATH)
-	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-	if n > uint32(len(dirw)) {
-		dirw = make([]uint16, n)
-		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
-		if n > uint32(len(dirw)) {
-			n = 0
-		}
-	}
-	if n > 0 && dirw[n-1] == pathSep {
-		n--
-	}
-	return string(utf16.Decode(dirw[0:n]))
-}
-
-func init() {
-	var argc int32
-	cmd := syscall.GetCommandLine()
-	argv, e := syscall.CommandLineToArgv(cmd, &argc)
-	if e != nil {
-		return
-	}
-	defer syscall.LocalFree(syscall.Handle(uintptr(unsafe.Pointer(argv))))
-	Args = make([]string, argc)
-	for i, v := range (*argv)[:argc] {
-		Args[i] = string(syscall.UTF16ToString((*v)[:]))
-	}
-}
diff --git a/src/pkg/os/exec_windows.go b/src/pkg/os/exec_windows.go
index f24580d15c9df29cec9c1b64ff899e08b253f516..46adb050d8b272b62c7cde3c2509bb300074c5de 100644
--- a/src/pkg/os/exec_windows.go
+++ b/src/pkg/os/exec_windows.go
@@ -65,3 +65,17 @@ func FindProcess(pid int) (p *Process, err error) {
 	}
 	return newProcess(pid, int(h)), nil
 }
+
+func init() {
+	var argc int32
+	cmd := GetCommandLine()
+	argv, e := CommandLineToArgv(cmd, &argc)
+	if e != nil {
+		return
+	}
+	defer LocalFree(Handle(uintptr(unsafe.Pointer(argv))))
+	Args = make([]string, argc)
+	for i, v := range (*argv)[:argc] {
+		Args[i] = string(UTF16ToString((*v)[:]))
+	}
+}
diff --git a/src/pkg/os/file_plan9.go b/src/pkg/os/file_plan9.go
index ecdd5d51efa342da437afa206de87a6932257506..15d66813a207ceb10a9fccaba52acabf5c167b90 100644
--- a/src/pkg/os/file_plan9.go
+++ b/src/pkg/os/file_plan9.go
@@ -329,3 +329,8 @@ func Lchown(name string, uid, gid int) error {
 func (f *File) Chown(uid, gid int) error {
 	return EPLAN9
 }
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+	return "/tmp"
+}
diff --git a/src/pkg/os/file_unix.go b/src/pkg/os/file_unix.go
index 140c93d8f24038357bb715fccd6b945d82891e71..d8fcb22ae1be955ef4af6abdd4e8f888faf85193 100644
--- a/src/pkg/os/file_unix.go
+++ b/src/pkg/os/file_unix.go
@@ -241,3 +241,12 @@ func Pipe() (r *File, w *File, err error) {
 
 	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
 }
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+	dir := Getenv("TMPDIR")
+	if dir == "" {
+		dir = "/tmp"
+	}
+	return dir
+}
diff --git a/src/pkg/os/file_windows.go b/src/pkg/os/file_windows.go
index 7dae46b212249273971541b6f044c6dd2e1a1935..fef868c68e62361ebae392cf5670019f7ff44dd3 100644
--- a/src/pkg/os/file_windows.go
+++ b/src/pkg/os/file_windows.go
@@ -283,3 +283,21 @@ func Pipe() (r *File, w *File, err error) {
 
 	return NewFile(p[0], "|0"), NewFile(p[1], "|1"), nil
 }
+
+// TempDir returns the default directory to use for temporary files.
+func TempDir() string {
+	const pathSep = '\\'
+	dirw := make([]uint16, MAX_PATH)
+	n, _ := syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+	if n > uint32(len(dirw)) {
+		dirw = make([]uint16, n)
+		n, _ = syscall.GetTempPath(uint32(len(dirw)), &dirw[0])
+		if n > uint32(len(dirw)) {
+			n = 0
+		}
+	}
+	if n > 0 && dirw[n-1] == pathSep {
+		n--
+	}
+	return string(utf16.Decode(dirw[0:n]))
+}
diff --git a/src/pkg/os/os_test.go b/src/pkg/os/os_test.go
index 16b41f7b6659c97912cd025e99477a053c4edbca..1b6cb8028c2532e3ecf0597b8db6ef9f76abaf75 100644
--- a/src/pkg/os/os_test.go
+++ b/src/pkg/os/os_test.go
@@ -18,7 +18,7 @@ import (
 
 var dot = []string{
 	"dir_unix.go",
-	"env_unix.go",
+	"env.go",
 	"error.go",
 	"file.go",
 	"os_test.go",
diff --git a/src/pkg/os/proc.go b/src/pkg/os/proc.go
index d21f849f21085d12106f0278507f739be2faf6e2..0ef6e411c314e48e9d87f6dfc3290a447e52a798 100644
--- a/src/pkg/os/proc.go
+++ b/src/pkg/os/proc.go
@@ -8,8 +8,8 @@ package os
 
 import "syscall"
 
-var Args []string // provided by runtime
-var Envs []string // provided by runtime
+// Args is the command-line arguments, starting with the program name.
+var Args []string
 
 // Getuid returns the numeric user id of the caller.
 func Getuid() int { return syscall.Getuid() }
diff --git a/src/pkg/runtime/proc.c b/src/pkg/runtime/proc.c
index 0b925fd52527683bd7be55a26799ff4d1e22ea75..8f4d1ffb4c6f94786094a2346072420dd1ebec4c 100644
--- a/src/pkg/runtime/proc.c
+++ b/src/pkg/runtime/proc.c
@@ -1723,9 +1723,9 @@ runtime·setcpuprofilerate(void (*fn)(uintptr*, int32), int32 hz)
 void (*libcgo_setenv)(byte**);
 
 // Update the C environment if cgo is loaded.
-// Called from os.Setenv.
+// Called from syscall.Setenv.
 void
-os·setenv_c(String k, String v)
+syscall·setenv_c(String k, String v)
 {
 	byte *arg[2];
 
diff --git a/src/pkg/runtime/runtime.c b/src/pkg/runtime/runtime.c
index a82e8b6b4908685939c103b4c889a3c93b6dbecc..a609a26f80f4ec4a0097780aeca40c08012bcb51 100644
--- a/src/pkg/runtime/runtime.c
+++ b/src/pkg/runtime/runtime.c
@@ -172,7 +172,7 @@ static int32	argc;
 static uint8**	argv;
 
 Slice os·Args;
-Slice os·Envs;
+Slice syscall·envs;
 
 void
 runtime·args(int32 c, uint8 **v)
@@ -214,9 +214,9 @@ runtime·goenvs_unix(void)
 	s = runtime·malloc(n*sizeof s[0]);
 	for(i=0; i<n; i++)
 		s[i] = runtime·gostringnocopy(argv[argc+1+i]);
-	os·Envs.array = (byte*)s;
-	os·Envs.len = n;
-	os·Envs.cap = n;
+	syscall·envs.array = (byte*)s;
+	syscall·envs.len = n;
+	syscall·envs.cap = n;
 }
 
 byte*
@@ -229,8 +229,8 @@ runtime·getenv(int8 *s)
 
 	bs = (byte*)s;
 	len = runtime·findnull(bs);
-	envv = (String*)os·Envs.array;
-	envc = os·Envs.len;
+	envv = (String*)syscall·envs.array;
+	envc = syscall·envs.len;
 	for(i=0; i<envc; i++){
 		if(envv[i].len <= len)
 			continue;
diff --git a/src/pkg/syscall/Makefile b/src/pkg/syscall/Makefile
index 2c4579ff082adb77bf5abb1d58680a9754186554..3b4bbedf131b366e7e1ff57852bf9db408b9b547 100644
--- a/src/pkg/syscall/Makefile
+++ b/src/pkg/syscall/Makefile
@@ -18,6 +18,7 @@ GOFILES=\
 
 GOFILES_freebsd=\
 	bpf_bsd.go\
+	env_unix.go\
 	exec_unix.go\
 	route_bsd.go\
 	route_freebsd.go\
@@ -27,6 +28,7 @@ GOFILES_freebsd=\
 
 GOFILES_darwin=\
 	bpf_bsd.go\
+	env_unix.go\
 	exec_unix.go\
 	route_bsd.go\
 	route_darwin.go\
@@ -35,6 +37,7 @@ GOFILES_darwin=\
 	syscall_unix.go\
 
 GOFILES_linux=\
+	env_unix.go\
 	exec_unix.go\
 	lsf_linux.go\
 	netlink_linux.go\
@@ -44,6 +47,7 @@ GOFILES_linux=\
 
 GOFILES_openbsd=\
 	bpf_bsd.go\
+	env_unix.go\
 	exec_unix.go\
 	route_bsd.go\
 	route_openbsd.go\
@@ -52,12 +56,14 @@ GOFILES_openbsd=\
 	syscall_unix.go\
 
 GOFILES_windows=\
+	env_windows.go\
 	exec_windows.go\
 	dll_windows.go\
 	zerrors_windows.go\
 	ztypes_windows.go\
 
 GOFILES_plan9=\
+	env_plan9.go\
 	exec_plan9.go\
 
 OFILES=\
diff --git a/src/pkg/syscall/env_plan9.go b/src/pkg/syscall/env_plan9.go
new file mode 100644
index 0000000000000000000000000000000000000000..7a6ea90bf13a5a5db79753d3c5d301b50f075547
--- /dev/null
+++ b/src/pkg/syscall/env_plan9.go
@@ -0,0 +1,74 @@
+// 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.
+
+// Plan 9 environment variables.
+
+package syscall
+
+import "errors"
+
+func Getenv(key string) (value string, found bool) {
+	if len(key) == 0 {
+		return "", EINVAL
+	}
+	f, e := Open("/env/" + key)
+	if e != nil {
+		return "", ENOENV
+	}
+	defer f.Close()
+
+	l, _ := f.Seek(0, 2)
+	f.Seek(0, 0)
+	buf := make([]byte, l)
+	n, e := f.Read(buf)
+	if e != nil {
+		return "", ENOENV
+	}
+
+	if n > 0 && buf[n-1] == 0 {
+		buf = buf[:n-1]
+	}
+	return string(buf), nil
+}
+
+func Setenv(key, value string) error {
+	if len(key) == 0 {
+		return EINVAL
+	}
+
+	f, e := Create("/env/" + key)
+	if e != nil {
+		return e
+	}
+	defer f.Close()
+
+	_, e = f.Write([]byte(value))
+	return nil
+}
+
+func Clearenv() {
+	RawSyscall(SYS_RFORK, RFCENVG, 0, 0)
+}
+
+func Environ() []string {
+	env := make([]string, 0, 100)
+
+	f, e := Open("/env")
+	if e != nil {
+		panic(e)
+	}
+	defer f.Close()
+
+	names, e := f.Readdirnames(-1)
+	if e != nil {
+		panic(e)
+	}
+
+	for _, k := range names {
+		if v, ok := Getenv(k); ok {
+			env = append(env, k+"="+v)
+		}
+	}
+	return env[0:len(env)]
+}
diff --git a/src/pkg/syscall/env_unix.go b/src/pkg/syscall/env_unix.go
new file mode 100644
index 0000000000000000000000000000000000000000..94a64713072ec6a1374ccc93fa243e992df7a200
--- /dev/null
+++ b/src/pkg/syscall/env_unix.go
@@ -0,0 +1,85 @@
+// Copyright 2010 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 freebsd linux openbsd
+
+// Unix environment variables.
+
+package syscall
+
+import "sync"
+
+var env map[string]string
+var envOnce sync.Once
+var envs []string // provided by runtime
+
+func setenv_c(k, v string)
+
+func copyenv() {
+	env = make(map[string]string)
+	for _, s := range envs {
+		for j := 0; j < len(s); j++ {
+			if s[j] == '=' {
+				env[s[0:j]] = s[j+1:]
+				break
+			}
+		}
+	}
+}
+
+var envLock sync.RWMutex
+
+func Getenv(key string) (value string, found bool) {
+	envOnce.Do(copyenv)
+	if len(key) == 0 {
+		return "", false
+	}
+
+	envLock.RLock()
+	defer envLock.RUnlock()
+
+	v, ok := env[key]
+	if !ok {
+		return "", false
+	}
+	return v, true
+}
+
+func Setenv(key, value string) error {
+	envOnce.Do(copyenv)
+	if len(key) == 0 {
+		return EINVAL
+	}
+
+	envLock.Lock()
+	defer envLock.Unlock()
+
+	env[key] = value
+	setenv_c(key, value) // is a no-op if cgo isn't loaded
+	return nil
+}
+
+func Clearenv() {
+	envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
+
+	envLock.Lock()
+	defer envLock.Unlock()
+
+	env = make(map[string]string)
+
+	// TODO(bradfitz): pass through to C
+}
+
+func Environ() []string {
+	envOnce.Do(copyenv)
+	envLock.RLock()
+	defer envLock.RUnlock()
+	a := make([]string, len(env))
+	i := 0
+	for k, v := range env {
+		a[i] = k + "=" + v
+		i++
+	}
+	return a
+}
diff --git a/src/pkg/syscall/env_windows.go b/src/pkg/syscall/env_windows.go
new file mode 100644
index 0000000000000000000000000000000000000000..8c1c4271a28319e4c4ec88f92a05f450f0c88e45
--- /dev/null
+++ b/src/pkg/syscall/env_windows.go
@@ -0,0 +1,78 @@
+// Copyright 2010 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.
+
+// Windows environment variables.
+
+package syscall
+
+import (
+	"errors"
+	"unicode/utf16"
+	"unsafe"
+)
+
+func Getenv(key string) (value string, found bool) {
+	b := make([]uint16, 100)
+	n, e := GetEnvironmentVariable(StringToUTF16Ptr(key), &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(StringToUTF16Ptr(key), &b[0], uint32(len(b)))
+		if n > uint32(len(b)) {
+			n = 0
+		}
+	}
+	if n == 0 {
+		return "", false
+	}
+	return string(utf16.Decode(b[0:n])), true
+}
+
+func Setenv(key, value string) error {
+	var v *uint16
+	if len(value) > 0 {
+		v = StringToUTF16Ptr(value)
+	}
+	e := SetEnvironmentVariable(StringToUTF16Ptr(key), v)
+	if e != nil {
+		return e
+	}
+	return nil
+}
+
+func Clearenv() {
+	for _, s := range Environ() {
+		// Environment variables can begin with =
+		// so start looking for the separator = at j=1.
+		// http://blogs.msdn.com/b/oldnewthing/archive/2010/05/06/10008132.aspx
+		for j := 1; j < len(s); j++ {
+			if s[j] == '=' {
+				Setenv(s[0:j], "")
+				break
+			}
+		}
+	}
+}
+
+func Environ() []string {
+	s, e := GetEnvironmentStrings()
+	if e != nil {
+		return nil
+	}
+	defer FreeEnvironmentStrings(s)
+	r := make([]string, 0, 50) // Empty with room to grow.
+	for from, i, p := 0, 0, (*[1 << 24]uint16)(unsafe.Pointer(s)); true; i++ {
+		if p[i] == 0 {
+			// empty string marks the end
+			if i <= from {
+				break
+			}
+			r = append(r, string(utf16.Decode(p[from:i])))
+			from = i + 1
+		}
+	}
+	return r
+}
diff --git a/src/pkg/syscall/syscall_bsd.go b/src/pkg/syscall/syscall_bsd.go
index 9d02d127f21e046435011b40e7b1fe01e10a4fe0..c8ffd09d588b5a96b8be73d75bc23b1e1a413187 100644
--- a/src/pkg/syscall/syscall_bsd.go
+++ b/src/pkg/syscall/syscall_bsd.go
@@ -137,11 +137,6 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
 	return
 }
 
-func Sleep(ns int64) (err error) {
-	tv := NsecToTimeval(ns)
-	return Select(0, nil, nil, nil, &tv)
-}
-
 //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error)
 //sys	bind(s int, addr uintptr, addrlen _Socklen) (err error)
 //sys	connect(s int, addr uintptr, addrlen _Socklen) (err error)
diff --git a/src/pkg/syscall/syscall_linux.go b/src/pkg/syscall/syscall_linux.go
index 52a7dc26bfb50268ec03463c108c2fbd6e3aa1b1..bae7f20e1ccabff532e75b71128c635945ae30ba 100644
--- a/src/pkg/syscall/syscall_linux.go
+++ b/src/pkg/syscall/syscall_linux.go
@@ -184,12 +184,6 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
 	return
 }
 
-func Sleep(nsec int64) (err error) {
-	tv := NsecToTimeval(nsec)
-	_, err = Select(0, nil, nil, nil, &tv)
-	return err
-}
-
 func Mkfifo(path string, mode uint32) (err error) {
 	return Mknod(path, mode|S_IFIFO, 0)
 }
diff --git a/src/pkg/syscall/syscall_plan9.go b/src/pkg/syscall/syscall_plan9.go
index 0409a040d936e56587c0f8956af54ba48d79163d..2005d812a5262b0741d908e1c6525202a55ec369 100644
--- a/src/pkg/syscall/syscall_plan9.go
+++ b/src/pkg/syscall/syscall_plan9.go
@@ -163,11 +163,6 @@ func Pipe(p []int) (err Error) {
 	return
 }
 
-//sys	sleep(millisecs int32) (err Error)
-func Sleep(nsec int64) (err Error) {
-	return sleep(int32((nsec + 999) / 1e6)) // round up to microsecond
-}
-
 // Underlying system call writes to newoffset via pointer.
 // Implemented in assembly to avoid allocation.
 func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
diff --git a/src/pkg/syscall/syscall_windows.go b/src/pkg/syscall/syscall_windows.go
index db8d3bc21efcc1c389ac5deac1236d978314e839..2c0cc5401f69f1ca9691a206d28410b6a027dd1f 100644
--- a/src/pkg/syscall/syscall_windows.go
+++ b/src/pkg/syscall/syscall_windows.go
@@ -110,7 +110,6 @@ func NewCallback(fn interface{}) uintptr
 //sys	GetComputerName(buf *uint16, n *uint32) (err error) = GetComputerNameW
 //sys	SetEndOfFile(handle Handle) (err error)
 //sys	GetSystemTimeAsFileTime(time *Filetime)
-//sys	sleep(msec uint32) = Sleep
 //sys	GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) [failretval==0xffffffff]
 //sys	CreateIoCompletionPort(filehandle Handle, cphandle Handle, key uint32, threadcnt uint32) (handle Handle, err error)
 //sys	GetQueuedCompletionStatus(cphandle Handle, qty *uint32, key *uint32, overlapped **Overlapped, timeout uint32) (err error)
diff --git a/src/pkg/syscall/zsyscall_windows_386.go b/src/pkg/syscall/zsyscall_windows_386.go
index 57010243e7445276972f4cd2db2e953db39fffd8..7970d3e050d4030f8d2d870df36afce6f5b7ddc2 100644
--- a/src/pkg/syscall/zsyscall_windows_386.go
+++ b/src/pkg/syscall/zsyscall_windows_386.go
@@ -41,7 +41,6 @@ var (
 	procGetComputerNameW            = modkernel32.NewProc("GetComputerNameW")
 	procSetEndOfFile                = modkernel32.NewProc("SetEndOfFile")
 	procGetSystemTimeAsFileTime     = modkernel32.NewProc("GetSystemTimeAsFileTime")
-	procSleep                       = modkernel32.NewProc("Sleep")
 	procGetTimeZoneInformation      = modkernel32.NewProc("GetTimeZoneInformation")
 	procCreateIoCompletionPort      = modkernel32.NewProc("CreateIoCompletionPort")
 	procGetQueuedCompletionStatus   = modkernel32.NewProc("GetQueuedCompletionStatus")
@@ -427,11 +426,6 @@ func GetSystemTimeAsFileTime(time *Filetime) {
 	return
 }
 
-func sleep(msec uint32) {
-	Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
-	return
-}
-
 func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
 	r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
 	rc = uint32(r0)
diff --git a/src/pkg/syscall/zsyscall_windows_amd64.go b/src/pkg/syscall/zsyscall_windows_amd64.go
index 56d4399158a03c5cd3f3cf3c1ab263d3afb04c1d..49c5fb0fe95347bf511a547253b251f6bd675ec1 100644
--- a/src/pkg/syscall/zsyscall_windows_amd64.go
+++ b/src/pkg/syscall/zsyscall_windows_amd64.go
@@ -41,7 +41,6 @@ var (
 	procGetComputerNameW            = modkernel32.NewProc("GetComputerNameW")
 	procSetEndOfFile                = modkernel32.NewProc("SetEndOfFile")
 	procGetSystemTimeAsFileTime     = modkernel32.NewProc("GetSystemTimeAsFileTime")
-	procSleep                       = modkernel32.NewProc("Sleep")
 	procGetTimeZoneInformation      = modkernel32.NewProc("GetTimeZoneInformation")
 	procCreateIoCompletionPort      = modkernel32.NewProc("CreateIoCompletionPort")
 	procGetQueuedCompletionStatus   = modkernel32.NewProc("GetQueuedCompletionStatus")
@@ -427,11 +426,6 @@ func GetSystemTimeAsFileTime(time *Filetime) {
 	return
 }
 
-func sleep(msec uint32) {
-	Syscall(procSleep.Addr(), 1, uintptr(msec), 0, 0)
-	return
-}
-
 func GetTimeZoneInformation(tzi *Timezoneinformation) (rc uint32, err error) {
 	r0, _, e1 := Syscall(procGetTimeZoneInformation.Addr(), 1, uintptr(unsafe.Pointer(tzi)), 0, 0)
 	rc = uint32(r0)