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

View as plain text