env_unix.go 2.9 KB

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