| // 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 dragonfly freebsd linux nacl netbsd openbsd solaris | |
| // Unix environment variables. | |
| package syscall | |
| import "sync" | |
| var ( | |
| // envOnce guards initialization by copyenv, which populates env. | |
| envOnce sync.Once | |
| // envLock guards env and envs. | |
| envLock sync.RWMutex | |
| // 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 | |
| ) | |
| // setenv_c is provided by the runtime, but is a no-op if cgo isn't | |
| // loaded. | |
| func setenv_c(k, v string) | |
| func copyenv() { | |
| env = make(map[string]int) | |
| 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 | |
| } | |
| break | |
| } | |
| } | |
| } | |
| } | |
| func Getenv(key string) (value string, found bool) { | |
| envOnce.Do(copyenv) | |
| if len(key) == 0 { | |
| return "", false | |
| } | |
| envLock.RLock() | |
| defer envLock.RUnlock() | |
| i, ok := env[key] | |
| if !ok { | |
| return "", false | |
| } | |
| s := envs[i] | |
| for i := 0; i < len(s); i++ { | |
| if s[i] == '=' { | |
| return s[i+1:], true | |
| } | |
| } | |
| return "", false | |
| } | |
| func Setenv(key, value string) error { | |
| envOnce.Do(copyenv) | |
| if len(key) == 0 { | |
| return EINVAL | |
| } | |
| for i := 0; i < len(key); i++ { | |
| if key[i] == '=' || key[i] == 0 { | |
| return EINVAL | |
| } | |
| } | |
| for i := 0; i < len(value); i++ { | |
| if value[i] == 0 { | |
| return EINVAL | |
| } | |
| } | |
| envLock.Lock() | |
| defer envLock.Unlock() | |
| i, ok := env[key] | |
| kv := key + "=" + value | |
| if ok { | |
| envs[i] = kv | |
| } else { | |
| i = len(envs) | |
| envs = append(envs, kv) | |
| } | |
| env[key] = i | |
| setenv_c(key, value) | |
| return nil | |
| } | |
| func Clearenv() { | |
| envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv | |
| envLock.Lock() | |
| defer envLock.Unlock() | |
| 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) | |
| return a | |
| } |