diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:14:23 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-28 13:14:23 +0000 |
commit | 73df946d56c74384511a194dd01dbe099584fd1a (patch) | |
tree | fd0bcea490dd81327ddfbb31e215439672c9a068 /src/syscall/env_unix.go | |
parent | Initial commit. (diff) | |
download | golang-1.16-73df946d56c74384511a194dd01dbe099584fd1a.tar.xz golang-1.16-73df946d56c74384511a194dd01dbe099584fd1a.zip |
Adding upstream version 1.16.10.upstream/1.16.10upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/syscall/env_unix.go')
-rw-r--r-- | src/syscall/env_unix.go | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/src/syscall/env_unix.go b/src/syscall/env_unix.go new file mode 100644 index 0000000..a4bb28c --- /dev/null +++ b/src/syscall/env_unix.go @@ -0,0 +1,155 @@ +// Copyright 2010 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// +build aix darwin dragonfly freebsd js,wasm linux netbsd openbsd solaris plan9 + +// Unix environment variables. + +package syscall + +import ( + "runtime" + "sync" +) + +var ( + // envOnce guards initialization by copyenv, which populates env. + envOnce sync.Once + + // envLock guards env and envs. + envLock sync.RWMutex + + // env maps from an environment variable to its first occurrence in envs. + env map[string]int + + // envs is provided by the runtime. elements are expected to + // be of the form "key=value". An empty string means deleted + // (or a duplicate to be ignored). + envs []string = runtime_envs() +) + +func runtime_envs() []string // in package runtime + +// setenv_c and unsetenv_c are provided by the runtime but are no-ops +// if cgo isn't loaded. +func setenv_c(k, v string) +func unsetenv_c(k string) + +func copyenv() { + env = make(map[string]int) + for i, s := range envs { + for j := 0; j < len(s); j++ { + if s[j] == '=' { + key := s[:j] + if _, ok := env[key]; !ok { + env[key] = i // first mention of key + } else { + // Clear duplicate keys. This permits Unsetenv to + // safely delete only the first item without + // worrying about unshadowing a later one, + // which might be a security problem. + envs[i] = "" + } + break + } + } + } +} + +func Unsetenv(key string) error { + envOnce.Do(copyenv) + + envLock.Lock() + defer envLock.Unlock() + + if i, ok := env[key]; ok { + envs[i] = "" + delete(env, key) + } + unsetenv_c(key) + return nil +} + +func Getenv(key string) (value string, found bool) { + envOnce.Do(copyenv) + if len(key) == 0 { + return "", false + } + + envLock.RLock() + defer envLock.RUnlock() + + i, ok := env[key] + if !ok { + return "", false + } + s := envs[i] + for i := 0; i < len(s); i++ { + if s[i] == '=' { + return s[i+1:], true + } + } + return "", false +} + +func Setenv(key, value string) error { + envOnce.Do(copyenv) + if len(key) == 0 { + return EINVAL + } + for i := 0; i < len(key); i++ { + if key[i] == '=' || key[i] == 0 { + return EINVAL + } + } + // On Plan 9, null is used as a separator, eg in $path. + if runtime.GOOS != "plan9" { + for i := 0; i < len(value); i++ { + if value[i] == 0 { + return EINVAL + } + } + } + + envLock.Lock() + defer envLock.Unlock() + + i, ok := env[key] + kv := key + "=" + value + if ok { + envs[i] = kv + } else { + i = len(envs) + envs = append(envs, kv) + } + env[key] = i + setenv_c(key, value) + return nil +} + +func Clearenv() { + envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv + + envLock.Lock() + defer envLock.Unlock() + + for k := range env { + unsetenv_c(k) + } + env = make(map[string]int) + envs = []string{} +} + +func Environ() []string { + envOnce.Do(copyenv) + envLock.RLock() + defer envLock.RUnlock() + a := make([]string, 0, len(envs)) + for _, env := range envs { + if env != "" { + a = append(a, env) + } + } + return a +} |