123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155 |
- // 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.
- //go:build aix || darwin || dragonfly || freebsd || hurd || (js && wasm) || linux || netbsd || openbsd || solaris || plan9
- // Unix environment variables.
- package syscall
- import (
- "runtime"
- "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". An empty string means deleted
- // (or a duplicate to be ignored).
- envs []string = runtime_envs()
- )
- 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 j := 0; j < len(s); j++ {
- if s[j] == '=' {
- key := s[:j]
- if _, ok := env[key]; !ok {
- 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
- }
- }
- }
- }
- 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 {
- 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
- }
- }
- // On Plan 9, null is used as a separator, eg in $path.
- if runtime.GOOS != "plan9" {
- 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()
- for k := range env {
- unsetenv_c(k)
- }
- env = make(map[string]int)
- envs = []string{}
- }
- func Environ() []string {
- envOnce.Do(copyenv)
- envLock.RLock()
- defer envLock.RUnlock()
- a := make([]string, 0, len(envs))
- for _, env := range envs {
- if env != "" {
- a = append(a, env)
- }
- }
- return a
- }
|