From cff4493ca0ff7435a533be27b89ea0fe7daf9877 Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Sun, 5 Dec 2021 13:24:00 -0800 Subject: [PATCH] os: implement and smoketest os.Setenv --- src/os/env.go | 12 ++++++++++ src/os/env_test.go | 38 ++++++++++++++++++++++++++++++++ src/runtime/env_linux.go | 27 +++++++++++++++++++++++ src/syscall/syscall_libc.go | 14 ++++++++++++ src/syscall/syscall_nonhosted.go | 5 +++++ 5 files changed, 96 insertions(+) create mode 100644 src/os/env_test.go create mode 100644 src/runtime/env_linux.go diff --git a/src/os/env.go b/src/os/env.go index 585650e7..d7bae9bb 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -9,6 +9,18 @@ func Getenv(key string) string { return v } +func Setenv(key, value string) error { + err := syscall.Setenv(key, value) + if err != nil { + return NewSyscallError("setenv", err) + } + return nil +} + +func Unsetenv(_ string) error { + return ErrNotImplemented +} + func LookupEnv(key string) (string, bool) { return syscall.Getenv(key) } diff --git a/src/os/env_test.go b/src/os/env_test.go new file mode 100644 index 00000000..ae7ed718 --- /dev/null +++ b/src/os/env_test.go @@ -0,0 +1,38 @@ +// Copyright 2010 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. + +package os_test + +import ( + . "os" + "reflect" + "testing" +) + +func TestConsistentEnviron(t *testing.T) { + e0 := Environ() + for i := 0; i < 10; i++ { + e1 := Environ() + if !reflect.DeepEqual(e0, e1) { + t.Fatalf("environment changed") + } + } +} + +func TestLookupEnv(t *testing.T) { + const smallpox = "SMALLPOX" // No one has smallpox. + value, ok := LookupEnv(smallpox) // Should not exist. + if ok || value != "" { + t.Fatalf("%s=%q", smallpox, value) + } + defer Unsetenv(smallpox) + err := Setenv(smallpox, "virus") + if err != nil { + t.Fatalf("failed to release smallpox virus") + } + _, ok = LookupEnv(smallpox) + if !ok { + t.Errorf("smallpox release failed; world remains safe but LookupEnv is broken") + } +} diff --git a/src/runtime/env_linux.go b/src/runtime/env_linux.go new file mode 100644 index 00000000..3f7a05b4 --- /dev/null +++ b/src/runtime/env_linux.go @@ -0,0 +1,27 @@ +// +build linux + +package runtime + +// Update the C environment if cgo is loaded. +// Called from syscall.Setenv. +//go:linkname syscall_setenv_c syscall.setenv_c +func syscall_setenv_c(key string, val string) { + keydata := cstring(key) + valdata := cstring(val) + // ignore any errors + libc_setenv(&keydata[0], &valdata[0], 1) + return +} + +// cstring converts a Go string to a C string. +// borrowed from syscall +func cstring(s string) []byte { + data := make([]byte, len(s)+1) + copy(data, s) + // final byte should be zero from the initial allocation + return data +} + +// int setenv(const char *name, const char *val, int replace); +//export setenv +func libc_setenv(name *byte, val *byte, replace int32) int32 diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index 4451cf76..fa433f34 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -132,6 +132,16 @@ func Getenv(key string) (value string, found bool) { } } +func Setenv(key, val string) (err error) { + keydata := cstring(key) + valdata := cstring(val) + errCode := libc_setenv(&keydata[0], &valdata[0], 1) + if errCode != 0 { + err = getErrno() + } + return +} + func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) { addr := libc_mmap(nil, uintptr(length), int32(prot), int32(flags), int32(fd), uintptr(offset)) if addr == unsafe.Pointer(^uintptr(0)) { @@ -192,6 +202,10 @@ func libc_write(fd int32, buf *byte, count uint) int //export getenv func libc_getenv(name *byte) *byte +// int setenv(const char *name, const char *val, int replace); +//export setenv +func libc_setenv(name *byte, val *byte, replace int32) int32 + // ssize_t read(int fd, void *buf, size_t count); //export read func libc_read(fd int32, buf *byte, count uint) int diff --git a/src/syscall/syscall_nonhosted.go b/src/syscall/syscall_nonhosted.go index 0fd7ffc5..21ad3d63 100644 --- a/src/syscall/syscall_nonhosted.go +++ b/src/syscall/syscall_nonhosted.go @@ -67,6 +67,11 @@ func Getenv(key string) (value string, found bool) { return "", false } +func Setenv(key, val string) (err error) { + // stub for now + return ENOSYS +} + func Environ() []string { env := runtime_envs() envCopy := make([]string, len(env))