Home | History | Annotate | Download | only in syscall
      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 }
    150