diff options
Diffstat (limited to 'src/syscall')
-rw-r--r-- | src/syscall/env_plan9.go | 38 | ||||
-rw-r--r-- | src/syscall/env_unix.go | 44 | ||||
-rw-r--r-- | src/syscall/env_windows.go | 8 |
3 files changed, 79 insertions, 11 deletions
diff --git a/src/syscall/env_plan9.go b/src/syscall/env_plan9.go index 9587ab5af..3044b410a 100644 --- a/src/syscall/env_plan9.go +++ b/src/syscall/env_plan9.go @@ -12,16 +12,22 @@ import ( ) var ( - // envOnce guards copyenv, which populates env. + // envOnce guards copyenv, which populates env, envi and envs. envOnce sync.Once - // envLock guards env and envs. + // envLock guards env, envi and envs. envLock sync.RWMutex // env maps from an environment variable to its value. + // TODO: remove this? golang.org/issue/8849 env = make(map[string]string) + // envi maps from an environment variable to its index in envs. + // TODO: remove this? golang.org/issue/8849 + envi = make(map[string]int) + // envs contains elements of env in the form "key=value". + // empty strings mean deleted. envs []string errZeroLengthKey = errors.New("zero length key") @@ -83,6 +89,7 @@ func copyenv() { } env[key] = v envs[i] = key + "=" + v + envi[key] = i i++ } } @@ -129,14 +136,39 @@ func Clearenv() { defer envLock.Unlock() env = make(map[string]string) + envi = make(map[string]int) envs = []string{} RawSyscall(SYS_RFORK, RFCENVG, 0, 0) } +func Unsetenv(key string) error { + if len(key) == 0 { + return errZeroLengthKey + } + + envLock.Lock() + defer envLock.Unlock() + + Remove("/env/" + key) + + if i, ok := envi[key]; ok { + delete(env, key) + delete(envi, key) + envs[i] = "" + } + return nil +} + func Environ() []string { envLock.RLock() defer envLock.RUnlock() envOnce.Do(copyenv) - return append([]string(nil), envs...) + ret := make([]string, 0, len(envs)) + for _, pair := range envs { + if pair != "" { + ret = append(ret, pair) + } + } + return ret } diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go index 01ac38af1..b5ded9c76 100644 --- a/src/syscall/env_unix.go +++ b/src/syscall/env_unix.go @@ -20,16 +20,18 @@ 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 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() ) func runtime_envs() []string // in package runtime -// setenv_c is provided by the runtime, but is a no-op if cgo isn't -// loaded. +// 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) @@ -38,7 +40,13 @@ func copyenv() { 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 } @@ -46,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 { @@ -106,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 } 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/src/syscall/env_windows.go b/src/syscall/env_windows.go index 420b38724..bc21690d9 100644 --- a/src/syscall/env_windows.go +++ b/src/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 = |