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