| // Copyright 2011 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. | |
| // Plan 9 environment variables. | |
| package syscall | |
| import ( | |
| "errors" | |
| "sync" | |
| ) | |
| var ( | |
| // envOnce guards initialization by copyenv, which populates env. | |
| envOnce sync.Once | |
| // envLock guards env. | |
| envLock sync.RWMutex | |
| // env maps from an environment variable to its value. | |
| env map[string]string | |
| ) | |
| func readenv(key string) (string, error) { | |
| fd, err := Open("/env/"+key, O_RDONLY) | |
| if err != nil { | |
| return "", err | |
| } | |
| defer Close(fd) | |
| l, _ := Seek(fd, 0, 2) | |
| Seek(fd, 0, 0) | |
| buf := make([]byte, l) | |
| n, err := Read(fd, buf) | |
| if err != nil { | |
| return "", err | |
| } | |
| if n > 0 && buf[n-1] == 0 { | |
| buf = buf[:n-1] | |
| } | |
| return string(buf), nil | |
| } | |
| func writeenv(key, value string) error { | |
| fd, err := Create("/env/"+key, O_RDWR, 0666) | |
| if err != nil { | |
| return err | |
| } | |
| defer Close(fd) | |
| _, err = Write(fd, []byte(value)) | |
| return err | |
| } | |
| func copyenv() { | |
| env = make(map[string]string) | |
| fd, err := Open("/env", O_RDONLY) | |
| if err != nil { | |
| return | |
| } | |
| defer Close(fd) | |
| files, err := readdirnames(fd) | |
| if err != nil { | |
| return | |
| } | |
| for _, key := range files { | |
| v, err := readenv(key) | |
| if err != nil { | |
| continue | |
| } | |
| env[key] = v | |
| } | |
| } | |
| func Getenv(key string) (value string, found bool) { | |
| envOnce.Do(copyenv) | |
| if len(key) == 0 { | |
| return "", false | |
| } | |
| envLock.RLock() | |
| defer envLock.RUnlock() | |
| v, ok := env[key] | |
| if !ok { | |
| return "", false | |
| } | |
| return v, true | |
| } | |
| func Setenv(key, value string) error { | |
| envOnce.Do(copyenv) | |
| if len(key) == 0 { | |
| return errors.New("zero length key") | |
| } | |
| envLock.Lock() | |
| defer envLock.Unlock() | |
| err := writeenv(key, value) | |
| if err != nil { | |
| return err | |
| } | |
| env[key] = value | |
| return nil | |
| } | |
| func Clearenv() { | |
| envOnce.Do(copyenv) // prevent copyenv in Getenv/Setenv | |
| envLock.Lock() | |
| defer envLock.Unlock() | |
| env = make(map[string]string) | |
| RawSyscall(SYS_RFORK, RFCENVG, 0, 0) | |
| } | |
| func Environ() []string { | |
| envOnce.Do(copyenv) | |
| envLock.RLock() | |
| defer envLock.RUnlock() | |
| a := make([]string, len(env)) | |
| i := 0 | |
| for k, v := range env { | |
| a[i] = k + "=" + v | |
| i++ | |
| } | |
| return a | |
| } |