github.com/peggyl/go@v0.0.0-20151008231540-ae315999c2d5/src/syscall/env_unix.go (about)

     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 darwin dragonfly freebsd 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  }