From e4f2b9c0037a757ccb03fe2c8563e33a55e9901e Mon Sep 17 00:00:00 2001 From: Dan Kegel Date: Sat, 11 Dec 2021 09:55:21 -0800 Subject: [PATCH] os: implement and smoketest os.Unsetenv --- src/os/env.go | 8 ++++++-- src/os/env_test.go | 26 ++++++++++++++++++++++++++ src/runtime/env_linux.go | 14 ++++++++++++++ src/syscall/syscall_libc.go | 13 +++++++++++++ src/syscall/syscall_nonhosted.go | 5 +++++ 5 files changed, 64 insertions(+), 2 deletions(-) diff --git a/src/os/env.go b/src/os/env.go index d7bae9bb..f232e1b4 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -17,8 +17,12 @@ func Setenv(key, value string) error { return nil } -func Unsetenv(_ string) error { - return ErrNotImplemented +func Unsetenv(key string) error { + err := syscall.Unsetenv(key) + if err != nil { + return NewSyscallError("unsetenv", err) + } + return nil } func LookupEnv(key string) (string, bool) { diff --git a/src/os/env_test.go b/src/os/env_test.go index ae7ed718..d2879c34 100644 --- a/src/os/env_test.go +++ b/src/os/env_test.go @@ -7,6 +7,7 @@ package os_test import ( . "os" "reflect" + "strings" "testing" ) @@ -20,6 +21,31 @@ func TestConsistentEnviron(t *testing.T) { } } +func TestUnsetenv(t *testing.T) { + const testKey = "GO_TEST_UNSETENV" + set := func() bool { + prefix := testKey + "=" + for _, key := range Environ() { + if strings.HasPrefix(key, prefix) { + return true + } + } + return false + } + if err := Setenv(testKey, "1"); err != nil { + t.Fatalf("Setenv: %v", err) + } + if !set() { + t.Error("Setenv didn't set TestUnsetenv") + } + if err := Unsetenv(testKey); err != nil { + t.Fatalf("Unsetenv: %v", err) + } + if set() { + t.Fatal("Unsetenv didn't clear TestUnsetenv") + } +} + func TestLookupEnv(t *testing.T) { const smallpox = "SMALLPOX" // No one has smallpox. value, ok := LookupEnv(smallpox) // Should not exist. diff --git a/src/runtime/env_linux.go b/src/runtime/env_linux.go index 3f7a05b4..5d2164e1 100644 --- a/src/runtime/env_linux.go +++ b/src/runtime/env_linux.go @@ -13,6 +13,16 @@ func syscall_setenv_c(key string, val string) { return } +// Update the C environment if cgo is loaded. +// Called from syscall.Unsetenv. +//go:linkname syscall_unsetenv_c syscall.unsetenv_c +func syscall_unsetenv_c(key string) { + keydata := cstring(key) + // ignore any errors + libc_unsetenv(&keydata[0]) + return +} + // cstring converts a Go string to a C string. // borrowed from syscall func cstring(s string) []byte { @@ -25,3 +35,7 @@ func cstring(s string) []byte { // int setenv(const char *name, const char *val, int replace); //export setenv func libc_setenv(name *byte, val *byte, replace int32) int32 + +// int unsetenv(const char *name); +//export unsetenv +func libc_unsetenv(name *byte) int32 diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index fa433f34..05df16fd 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -142,6 +142,15 @@ func Setenv(key, val string) (err error) { return } +func Unsetenv(key string) (err error) { + keydata := cstring(key) + errCode := libc_unsetenv(&keydata[0]) + 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)) { @@ -206,6 +215,10 @@ func libc_getenv(name *byte) *byte //export setenv func libc_setenv(name *byte, val *byte, replace int32) int32 +// int unsetenv(const char *name); +//export unsetenv +func libc_unsetenv(name *byte) 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 21ad3d63..9e5b70fd 100644 --- a/src/syscall/syscall_nonhosted.go +++ b/src/syscall/syscall_nonhosted.go @@ -72,6 +72,11 @@ func Setenv(key, val string) (err error) { return ENOSYS } +func Unsetenv(key string) (err error) { + // stub for now + return ENOSYS +} + func Environ() []string { env := runtime_envs() envCopy := make([]string, len(env))