diff --git a/Makefile b/Makefile index 1a922f87..3ed2a895 100644 --- a/Makefile +++ b/Makefile @@ -200,31 +200,41 @@ test: wasi-libc TEST_PACKAGES = \ compress/bzip2 \ + compress/flate \ + compress/zlib \ container/heap \ container/list \ container/ring \ crypto/des \ crypto/dsa \ + crypto/elliptic/internal/fiat \ + crypto/internal/subtle \ crypto/md5 \ crypto/rc4 \ crypto/sha1 \ crypto/sha256 \ crypto/sha512 \ + debug/macho \ encoding \ encoding/ascii85 \ encoding/base32 \ + encoding/csv \ encoding/hex \ + go/scanner \ hash \ hash/adler32 \ - hash/fnv \ hash/crc64 \ + hash/fnv \ html \ index/suffixarray \ internal/itoa \ + internal/profile \ math \ math/cmplx \ + net/http/internal/ascii \ net/mail \ os \ + path \ reflect \ testing \ testing/iotest \ diff --git a/src/os/env.go b/src/os/env.go index eac3072a..585650e7 100644 --- a/src/os/env.go +++ b/src/os/env.go @@ -12,3 +12,7 @@ func Getenv(key string) string { func LookupEnv(key string) (string, bool) { return syscall.Getenv(key) } + +func Environ() []string { + return syscall.Environ() +} diff --git a/src/os/exec.go b/src/os/exec.go index 8bc544ba..067be0de 100644 --- a/src/os/exec.go +++ b/src/os/exec.go @@ -16,3 +16,36 @@ func Getpid() int { func Getppid() int { return syscall.Getppid() } + +type ProcAttr struct { + Dir string + Env []string + Files []*File + Sys *syscall.SysProcAttr +} + +type ProcessState struct { +} + +func (p *ProcessState) String() string { + return "" // TODO +} +func (p *ProcessState) Success() bool { + return false // TODO +} + +type Process struct { + Pid int +} + +func StartProcess(name string, argv []string, attr *ProcAttr) (*Process, error) { + return nil, &PathError{"fork/exec", name, ErrNotImplemented} +} + +func (p *Process) Wait() (*ProcessState, error) { + return nil, ErrNotImplemented +} + +func (p *Process) Kill() error { + return ErrNotImplemented +} diff --git a/src/os/file.go b/src/os/file.go index 6af6a28f..2af91122 100644 --- a/src/os/file.go +++ b/src/os/file.go @@ -52,6 +52,16 @@ func Remove(path string) error { return nil } +// Symlink is a stub, it is not implemented. +func Symlink(oldname, newname string) error { + return ErrNotImplemented +} + +// RemoveAll is a stub, it is not implemented. +func RemoveAll(path string) error { + return ErrNotImplemented +} + // File represents an open file descriptor. type File struct { handle FileHandle @@ -187,6 +197,27 @@ func (e *PathError) Error() string { return e.Op + " " + e.Path + ": " + e.Err.Error() } +func (e *PathError) Unwrap() error { + return e.Err +} + +// LinkError records an error during a link or symlink or rename system call and +// the paths that caused it. +type LinkError struct { + Op string + Old string + New string + Err error +} + +func (e *LinkError) Error() string { + return e.Op + " " + e.Old + " " + e.New + ": " + e.Err.Error() +} + +func (e *LinkError) Unwrap() error { + return e.Err +} + const ( O_RDONLY int = syscall.O_RDONLY O_WRONLY int = syscall.O_WRONLY diff --git a/src/os/file_anyos.go b/src/os/file_anyos.go index 4cf2a50e..74637a1e 100644 --- a/src/os/file_anyos.go +++ b/src/os/file_anyos.go @@ -21,6 +21,8 @@ var ( Stderr = &File{unixFileHandle(syscall.Stderr), "/dev/stderr"} ) +const DevNull = "/dev/null" + // isOS indicates whether we're running on a real operating system with // filesystem support. const isOS = true diff --git a/src/os/file_other.go b/src/os/file_other.go index af885edd..37f9675d 100644 --- a/src/os/file_other.go +++ b/src/os/file_other.go @@ -48,3 +48,7 @@ func (f stdioFileHandle) Close() error { //go:linkname putchar runtime.putchar func putchar(c byte) + +func Pipe() (r *File, w *File, err error) { + return nil, nil, ErrNotImplemented +} diff --git a/src/os/file_unix.go b/src/os/file_unix.go index 7ead108b..64230fd3 100644 --- a/src/os/file_unix.go +++ b/src/os/file_unix.go @@ -2,4 +2,23 @@ package os +import "syscall" + type syscallFd = int + +func Pipe() (r *File, w *File, err error) { + var p [2]int + err = handleSyscallError(syscall.Pipe2(p[:], syscall.O_CLOEXEC)) + if err != nil { + return + } + r = &File{ + handle: unixFileHandle(p[0]), + name: "|0", + } + w = &File{ + handle: unixFileHandle(p[1]), + name: "|1", + } + return +} diff --git a/src/os/file_windows.go b/src/os/file_windows.go index 11ae1e0d..cf970380 100644 --- a/src/os/file_windows.go +++ b/src/os/file_windows.go @@ -5,3 +5,20 @@ package os import "syscall" type syscallFd = syscall.Handle + +func Pipe() (r *File, w *File, err error) { + var p [2]syscall.Handle + e := handleSyscallError(syscall.Pipe(p[:])) + if e != nil { + return nil, nil, err + } + r = &File{ + handle: unixFileHandle(p[0]), + name: "|0", + } + w = &File{ + handle: unixFileHandle(p[1]), + name: "|1", + } + return +} diff --git a/src/syscall/syscall_libc.go b/src/syscall/syscall_libc.go index f4f3578c..77db38e2 100644 --- a/src/syscall/syscall_libc.go +++ b/src/syscall/syscall_libc.go @@ -81,6 +81,12 @@ func Kill(pid int, sig Signal) (err error) { return ENOSYS // TODO } +type SysProcAttr struct{} + +func Pipe2(p []int, flags int) (err error) { + return ENOSYS // TODO +} + func Getenv(key string) (value string, found bool) { data := cstring(key) raw := libc_getenv(&data[0]) @@ -115,6 +121,26 @@ func Mprotect(b []byte, prot int) (err error) { return } +func Environ() []string { + environ := libc_environ + var envs []string + for *environ != nil { + // Convert the C string to a Go string. + length := libc_strlen(*environ) + var envVar string + rawEnvVar := (*struct { + ptr unsafe.Pointer + length uintptr + })(unsafe.Pointer(&envVar)) + rawEnvVar.ptr = *environ + rawEnvVar.length = length + envs = append(envs, envVar) + // This is the Go equivalent of "environ++" in C. + environ = (*unsafe.Pointer)(unsafe.Pointer(uintptr(unsafe.Pointer(environ)) + unsafe.Sizeof(environ))) + } + return envs +} + // cstring converts a Go string to a C string. func cstring(s string) []byte { data := make([]byte, len(s)+1) @@ -128,6 +154,9 @@ func splitSlice(p []byte) (buf *byte, len uintptr) { return slice.buf, slice.len } +//export strlen +func libc_strlen(ptr unsafe.Pointer) uintptr + // ssize_t write(int fd, const void *buf, size_t count) //export write func libc_write(fd int32, buf *byte, count uint) int @@ -167,3 +196,6 @@ func libc_rmdir(pathname *byte) int32 // int unlink(const char *pathname); //export unlink func libc_unlink(pathname *byte) int32 + +//go:extern environ +var libc_environ *unsafe.Pointer diff --git a/src/syscall/syscall_libc_darwin.go b/src/syscall/syscall_libc_darwin.go index 6ca95f53..481ba383 100644 --- a/src/syscall/syscall_libc_darwin.go +++ b/src/syscall/syscall_libc_darwin.go @@ -36,18 +36,20 @@ func (e Errno) Is(target error) bool { return false } +// Source: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/sys/errno.h.auto.html const ( - EPERM Errno = 0x1 - ENOENT Errno = 0x2 - EACCES Errno = 0xd - EEXIST Errno = 0x11 - EINTR Errno = 0x4 - ENOTDIR Errno = 0x14 - EINVAL Errno = 0x16 - EMFILE Errno = 0x18 - EAGAIN Errno = 0x23 - ETIMEDOUT Errno = 0x3c - ENOSYS Errno = 0x4e + EPERM Errno = 1 + ENOENT Errno = 2 + EACCES Errno = 13 + EEXIST Errno = 17 + EINTR Errno = 4 + ENOTDIR Errno = 20 + EINVAL Errno = 22 + EMFILE Errno = 24 + EPIPE Errno = 32 + EAGAIN Errno = 35 + ETIMEDOUT Errno = 60 + ENOSYS Errno = 78 EWOULDBLOCK Errno = EAGAIN ) @@ -77,6 +79,8 @@ const ( O_CREAT = 0x200 O_TRUNC = 0x400 O_EXCL = 0x800 + + O_CLOEXEC = 0x01000000 ) // Source: https://opensource.apple.com/source/xnu/xnu-7195.81.3/bsd/sys/mman.h.auto.html diff --git a/src/syscall/syscall_nonhosted.go b/src/syscall/syscall_nonhosted.go index 885738e4..0fd7ffc5 100644 --- a/src/syscall/syscall_nonhosted.go +++ b/src/syscall/syscall_nonhosted.go @@ -67,6 +67,13 @@ func Getenv(key string) (value string, found bool) { return "", false } +func Environ() []string { + env := runtime_envs() + envCopy := make([]string, len(env)) + copy(envCopy, env) + return envCopy +} + func Open(path string, mode int, perm uint32) (fd int, err error) { return 0, ENOSYS } diff --git a/testdata/env.go b/testdata/env.go index 115da6d3..79f4885e 100644 --- a/testdata/env.go +++ b/testdata/env.go @@ -13,6 +13,17 @@ func main() { } println("ENV2:", v) + found := false + expected := "ENV1=" + os.Getenv("ENV1") + for _, envVar := range os.Environ() { + if envVar == expected { + found = true + } + } + if !found { + println("could not find " + expected + " in os.Environ()") + } + // Check for command line arguments. // Argument 0 is skipped because it is the program name, which varies by // test run.