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

View as plain text