blob: b5ded9c763c2541d02c87b50f652f23503781350 [file] [log] [blame]
Russ Cox0acd8792011-11-14 14:06:50 -05001// 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
Dave Cheney7c8280c2014-02-25 09:47:42 -05005// +build darwin dragonfly freebsd linux nacl netbsd openbsd solaris
Russ Cox0acd8792011-11-14 14:06:50 -05006
7// Unix environment variables.
8
9package syscall
10
11import "sync"
12
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080013var (
14 // envOnce guards initialization by copyenv, which populates env.
15 envOnce sync.Once
Russ Cox0acd8792011-11-14 14:06:50 -050016
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080017 // 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
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -070023 // 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).
Russ Cox193daab2014-09-24 16:55:26 -040026 envs []string = runtime_envs()
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080027)
28
Russ Cox193daab2014-09-24 16:55:26 -040029func runtime_envs() []string // in package runtime
30
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -070031// setenv_c and unsetenv_c are provided by the runtime but are no-ops
32// if cgo isn't loaded.
Russ Cox0acd8792011-11-14 14:06:50 -050033func setenv_c(k, v string)
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -070034func unsetenv_c(k string)
Russ Cox0acd8792011-11-14 14:06:50 -050035
36func copyenv() {
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080037 env = make(map[string]int)
38 for i, s := range envs {
Russ Cox0acd8792011-11-14 14:06:50 -050039 for j := 0; j < len(s); j++ {
40 if s[j] == '=' {
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080041 key := s[:j]
42 if _, ok := env[key]; !ok {
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -070043 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] = ""
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080050 }
Russ Cox0acd8792011-11-14 14:06:50 -050051 break
52 }
53 }
54 }
55}
56
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -070057func 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
Russ Cox0acd8792011-11-14 14:06:50 -050071func 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
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080080 i, ok := env[key]
Russ Cox0acd8792011-11-14 14:06:50 -050081 if !ok {
82 return "", false
83 }
Brad Fitzpatrick024952f2012-01-09 16:51:20 -080084 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
Russ Cox0acd8792011-11-14 14:06:50 -050091}
92
93func Setenv(key, value string) error {
94 envOnce.Do(copyenv)
95 if len(key) == 0 {
96 return EINVAL
97 }
Péter Surányid2252d92013-02-08 10:45:46 -080098 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 }
Russ Cox0acd8792011-11-14 14:06:50 -0500108
109 envLock.Lock()
110 defer envLock.Unlock()
111
Brad Fitzpatrick024952f2012-01-09 16:51:20 -0800112 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)
Russ Cox0acd8792011-11-14 14:06:50 -0500122 return nil
123}
124
125func Clearenv() {
126 envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv
127
128 envLock.Lock()
129 defer envLock.Unlock()
130
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -0700131 for k := range env {
132 unsetenv_c(k)
133 }
Brad Fitzpatrick024952f2012-01-09 16:51:20 -0800134 env = make(map[string]int)
135 envs = []string{}
Russ Cox0acd8792011-11-14 14:06:50 -0500136}
137
138func Environ() []string {
139 envOnce.Do(copyenv)
140 envLock.RLock()
141 defer envLock.RUnlock()
Brad Fitzpatrick85cdc492014-10-01 11:17:15 -0700142 a := make([]string, 0, len(envs))
143 for _, env := range envs {
144 if env != "" {
145 a = append(a, env)
146 }
147 }
Russ Cox0acd8792011-11-14 14:06:50 -0500148 return a
149}