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