github.com/code-reading/golang@v0.0.0-20220303082512-ba5bc0e589a3/go/src/syscall/env_unix.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 //go:build aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris || plan9 6 // +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9 7 8 // Unix environment variables. 9 10 package syscall 11 12 import ( 13 "runtime" 14 "sync" 15 ) 16 17 var ( 18 // envOnce guards initialization by copyenv, which populates env. 19 envOnce sync.Once 20 21 // envLock guards env and envs. 22 envLock sync.RWMutex 23 24 // env maps from an environment variable to its first occurrence in envs. 25 env map[string]int 26 27 // envs is provided by the runtime. elements are expected to 28 // be of the form "key=value". An empty string means deleted 29 // (or a duplicate to be ignored). 30 envs []string = runtime_envs() 31 ) 32 33 func runtime_envs() []string // in package runtime 34 35 // setenv_c and unsetenv_c are provided by the runtime but are no-ops 36 // if cgo isn't loaded. 37 func setenv_c(k, v string) 38 func unsetenv_c(k string) 39 40 func copyenv() { 41 env = make(map[string]int) 42 for i, s := range envs { 43 for j := 0; j < len(s); j++ { 44 if s[j] == '=' { 45 key := s[:j] 46 if _, ok := env[key]; !ok { 47 env[key] = i // first mention of key 48 } else { 49 // Clear duplicate keys. This permits Unsetenv to 50 // safely delete only the first item without 51 // worrying about unshadowing a later one, 52 // which might be a security problem. 53 envs[i] = "" 54 } 55 break 56 } 57 } 58 } 59 } 60 61 func Unsetenv(key string) error { 62 envOnce.Do(copyenv) 63 64 envLock.Lock() 65 defer envLock.Unlock() 66 67 if i, ok := env[key]; ok { 68 envs[i] = "" 69 delete(env, key) 70 } 71 unsetenv_c(key) 72 return nil 73 } 74 75 func Getenv(key string) (value string, found bool) { 76 envOnce.Do(copyenv) 77 if len(key) == 0 { 78 return "", false 79 } 80 81 envLock.RLock() 82 defer envLock.RUnlock() 83 84 i, ok := env[key] 85 if !ok { 86 return "", false 87 } 88 s := envs[i] 89 for i := 0; i < len(s); i++ { 90 if s[i] == '=' { 91 return s[i+1:], true 92 } 93 } 94 return "", false 95 } 96 97 func Setenv(key, value string) error { 98 envOnce.Do(copyenv) 99 if len(key) == 0 { 100 return EINVAL 101 } 102 for i := 0; i < len(key); i++ { 103 if key[i] == '=' || key[i] == 0 { 104 return EINVAL 105 } 106 } 107 // On Plan 9, null is used as a separator, eg in $path. 108 if runtime.GOOS != "plan9" { 109 for i := 0; i < len(value); i++ { 110 if value[i] == 0 { 111 return EINVAL 112 } 113 } 114 } 115 116 envLock.Lock() 117 defer envLock.Unlock() 118 119 i, ok := env[key] 120 kv := key + "=" + value 121 if ok { 122 envs[i] = kv 123 } else { 124 i = len(envs) 125 envs = append(envs, kv) 126 } 127 env[key] = i 128 setenv_c(key, value) 129 return nil 130 } 131 132 func Clearenv() { 133 envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv 134 135 envLock.Lock() 136 defer envLock.Unlock() 137 138 for k := range env { 139 unsetenv_c(k) 140 } 141 env = make(map[string]int) 142 envs = []string{} 143 } 144 145 func Environ() []string { 146 envOnce.Do(copyenv) 147 envLock.RLock() 148 defer envLock.RUnlock() 149 a := make([]string, 0, len(envs)) 150 for _, env := range envs { 151 if env != "" { 152 a = append(a, env) 153 } 154 } 155 return a 156 }