319 строки
9 КиБ
Go
319 строки
9 КиБ
Go
//go:build wasi
|
|
// +build wasi
|
|
|
|
package syscall
|
|
|
|
import (
|
|
"internal/itoa"
|
|
"unsafe"
|
|
)
|
|
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/expected/wasm32-wasi/predefined-macros.txt
|
|
// disagrees with ../../lib/wasi-libc/libc-top-half/musl/arch/wasm32/bits/signal.h for SIGCHLD?
|
|
// https://github.com/WebAssembly/wasi-libc/issues/271
|
|
|
|
type Signal int
|
|
|
|
const (
|
|
SIGINT Signal = 2
|
|
SIGQUIT Signal = 3
|
|
SIGILL Signal = 4
|
|
SIGTRAP Signal = 5
|
|
SIGABRT Signal = 6
|
|
SIGBUS Signal = 7
|
|
SIGFPE Signal = 8
|
|
SIGKILL Signal = 9
|
|
SIGSEGV Signal = 11
|
|
SIGPIPE Signal = 13
|
|
SIGTERM Signal = 15
|
|
SIGCHLD Signal = 17
|
|
)
|
|
|
|
func (s Signal) Signal() {}
|
|
|
|
func (s Signal) String() string {
|
|
if 0 <= s && int(s) < len(signals) {
|
|
str := signals[s]
|
|
if str != "" {
|
|
return str
|
|
}
|
|
}
|
|
return "signal " + itoa.Itoa(int(s))
|
|
}
|
|
|
|
var signals = [...]string{}
|
|
|
|
const (
|
|
Stdin = 0
|
|
Stdout = 1
|
|
Stderr = 2
|
|
)
|
|
|
|
const (
|
|
__WASI_OFLAGS_CREAT = 1
|
|
__WASI_OFLAGS_EXCL = 4
|
|
__WASI_OFLAGS_TRUNC = 8
|
|
|
|
__WASI_FDFLAGS_APPEND = 1
|
|
__WASI_FDFLAGS_SYNC = 16
|
|
|
|
O_RDONLY = 0x04000000
|
|
O_WRONLY = 0x10000000
|
|
O_RDWR = O_RDONLY | O_WRONLY
|
|
|
|
O_CREAT = __WASI_OFLAGS_CREAT << 12
|
|
O_TRUNC = __WASI_OFLAGS_TRUNC << 12
|
|
O_EXCL = __WASI_OFLAGS_EXCL << 12
|
|
|
|
O_APPEND = __WASI_FDFLAGS_APPEND
|
|
O_SYNC = __WASI_FDFLAGS_SYNC
|
|
|
|
O_CLOEXEC = 0
|
|
|
|
// ../../lib/wasi-libc/sysroot/include/sys/mman.h
|
|
MAP_FILE = 0
|
|
MAP_SHARED = 0x01
|
|
MAP_PRIVATE = 0x02
|
|
MAP_ANON = 0x20
|
|
MAP_ANONYMOUS = MAP_ANON
|
|
|
|
// ../../lib/wasi-libc/sysroot/include/sys/mman.h
|
|
PROT_NONE = 0
|
|
PROT_READ = 1
|
|
PROT_WRITE = 2
|
|
PROT_EXEC = 4
|
|
)
|
|
|
|
//go:extern errno
|
|
var libcErrno uintptr
|
|
|
|
func getErrno() error {
|
|
return Errno(libcErrno)
|
|
}
|
|
|
|
func (e Errno) Is(target error) bool {
|
|
switch target.Error() {
|
|
case "permission denied":
|
|
return e == EACCES || e == EPERM || e == ENOTCAPABLE // ENOTCAPABLE is unique in WASI
|
|
case "file already exists":
|
|
return e == EEXIST || e == ENOTEMPTY
|
|
case "file does not exist":
|
|
return e == ENOENT
|
|
}
|
|
return false
|
|
}
|
|
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__errno.h
|
|
const (
|
|
E2BIG Errno = 1 /* Argument list too long */
|
|
EACCES Errno = 2 /* Permission denied */
|
|
EADDRINUSE Errno = 3 /* Address already in use */
|
|
EADDRNOTAVAIL Errno = 4 /* Address not available */
|
|
EAFNOSUPPORT Errno = 5 /* Address family not supported by protocol family */
|
|
EAGAIN Errno = 6 /* Try again */
|
|
EWOULDBLOCK Errno = EAGAIN /* Operation would block */
|
|
EALREADY Errno = 7 /* Socket already connected */
|
|
EBADF Errno = 8 /* Bad file number */
|
|
EBADMSG Errno = 9 /* Trying to read unreadable message */
|
|
EBUSY Errno = 10 /* Device or resource busy */
|
|
ECANCELED Errno = 11 /* Operation canceled. */
|
|
ECHILD Errno = 12 /* No child processes */
|
|
ECONNABORTED Errno = 13 /* Connection aborted */
|
|
ECONNREFUSED Errno = 14 /* Connection refused */
|
|
ECONNRESET Errno = 15 /* Connection reset by peer */
|
|
EDEADLK Errno = 16 /* Deadlock condition */
|
|
EDESTADDRREQ Errno = 17 /* Destination address required */
|
|
EDOM Errno = 18 /* Math arg out of domain of func */
|
|
EDQUOT Errno = 19 /* Quota exceeded */
|
|
EEXIST Errno = 20 /* File exists */
|
|
EFAULT Errno = 21 /* Bad address */
|
|
EFBIG Errno = 22 /* File too large */
|
|
EHOSTUNREACH Errno = 23 /* Host is unreachable */
|
|
EIDRM Errno = 24 /* Identifier removed */
|
|
EILSEQ Errno = 25
|
|
EINPROGRESS Errno = 26 /* Connection already in progress */
|
|
EINTR Errno = 27 /* Interrupted system call */
|
|
EINVAL Errno = 28 /* Invalid argument */
|
|
EIO Errno = 29 /* I/O error */
|
|
EISCONN Errno = 30 /* Socket is already connected */
|
|
EISDIR Errno = 31 /* Is a directory */
|
|
ELOOP Errno = 32 /* Too many symbolic links */
|
|
EMFILE Errno = 33 /* Too many open files */
|
|
EMLINK Errno = 34 /* Too many links */
|
|
EMSGSIZE Errno = 35 /* Message too long */
|
|
EMULTIHOP Errno = 36 /* Multihop attempted */
|
|
ENAMETOOLONG Errno = 37 /* File name too long */
|
|
ENETDOWN Errno = 38 /* Network interface is not configured */
|
|
ENETRESET Errno = 39
|
|
ENETUNREACH Errno = 40 /* Network is unreachable */
|
|
ENFILE Errno = 41 /* File table overflow */
|
|
ENOBUFS Errno = 42 /* No buffer space available */
|
|
ENODEV Errno = 43 /* No such device */
|
|
ENOENT Errno = 44 /* No such file or directory */
|
|
ENOEXEC Errno = 45 /* Exec format error */
|
|
ENOLCK Errno = 46 /* No record locks available */
|
|
ENOLINK Errno = 47 /* The link has been severed */
|
|
ENOMEM Errno = 48 /* Out of memory */
|
|
ENOMSG Errno = 49 /* No message of desired type */
|
|
ENOPROTOOPT Errno = 50 /* Protocol not available */
|
|
ENOSPC Errno = 51 /* No space left on device */
|
|
ENOSYS Errno = 52 /* Function not implemented */
|
|
ENOTCONN Errno = 53 /* Socket is not connected */
|
|
ENOTDIR Errno = 54 /* Not a directory */
|
|
ENOTEMPTY Errno = 55 /* Directory not empty */
|
|
ENOTSOCK Errno = 57 /* Socket operation on non-socket */
|
|
ESOCKTNOSUPPORT Errno = 58 /* Socket type not supported */
|
|
EOPNOTSUPP Errno = 58 /* Operation not supported on transport endpoint */
|
|
ENOTSUP Errno = EOPNOTSUPP /* Not supported */
|
|
ENOTTY Errno = 59 /* Not a typewriter */
|
|
ENXIO Errno = 60 /* No such device or address */
|
|
EOVERFLOW Errno = 61 /* Value too large for defined data type */
|
|
EPERM Errno = 63 /* Operation not permitted */
|
|
EPIPE Errno = 64 /* Broken pipe */
|
|
EPROTO Errno = 65 /* Protocol error */
|
|
EPROTONOSUPPORT Errno = 66 /* Unknown protocol */
|
|
EPROTOTYPE Errno = 67 /* Protocol wrong type for socket */
|
|
ERANGE Errno = 68 /* Math result not representable */
|
|
EROFS Errno = 69 /* Read-only file system */
|
|
ESPIPE Errno = 70 /* Illegal seek */
|
|
ESRCH Errno = 71 /* No such process */
|
|
ESTALE Errno = 72
|
|
ETIMEDOUT Errno = 73 /* Connection timed out */
|
|
EXDEV Errno = 75 /* Cross-device link */
|
|
ENOTCAPABLE Errno = 76 /* Extension: Capabilities insufficient. */
|
|
)
|
|
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__struct_timespec.h
|
|
type Timespec struct {
|
|
Sec int32
|
|
Nsec int64
|
|
}
|
|
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__struct_stat.h
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-bottom-half/headers/public/__typedef_ino_t.h
|
|
// etc.
|
|
// Go chose Linux's field names for Stat_t, see https://github.com/golang/go/issues/31735
|
|
type Stat_t struct {
|
|
Dev uint64
|
|
Ino uint64
|
|
Nlink uint64
|
|
Mode uint32
|
|
Uid uint32
|
|
Gid uint32
|
|
Pad_cgo_0 [4]byte
|
|
Rdev uint64
|
|
Size int64
|
|
Blksize int32
|
|
Blocks int64
|
|
|
|
Atim Timespec
|
|
Mtim Timespec
|
|
Ctim Timespec
|
|
Qspare [3]int64
|
|
}
|
|
|
|
// https://github.com/WebAssembly/wasi-libc/blob/main/libc-top-half/musl/include/sys/stat.h
|
|
const (
|
|
S_IFBLK = 0x6000
|
|
S_IFCHR = 0x2000
|
|
S_IFDIR = 0x4000
|
|
S_IFIFO = 0x1000
|
|
S_IFLNK = 0xa000
|
|
S_IFMT = 0xf000
|
|
S_IFREG = 0x8000
|
|
S_IFSOCK = 0xc000
|
|
S_IREAD = 0x100
|
|
S_IRGRP = 0x20
|
|
S_IROTH = 0x4
|
|
S_IRUSR = 0x100
|
|
S_IRWXG = 0x38
|
|
S_IRWXO = 0x7
|
|
S_IRWXU = 0x1c0
|
|
S_ISGID = 0x400
|
|
S_ISUID = 0x800
|
|
S_ISVTX = 0x200
|
|
S_IWGRP = 0x10
|
|
S_IWOTH = 0x2
|
|
S_IWRITE = 0x80
|
|
S_IWUSR = 0x80
|
|
S_IXGRP = 0x8
|
|
S_IXOTH = 0x1
|
|
S_IXUSR = 0x40
|
|
)
|
|
|
|
// dummy
|
|
const (
|
|
DT_BLK = 0x6
|
|
DT_CHR = 0x2
|
|
DT_DIR = 0x4
|
|
DT_FIFO = 0x1
|
|
DT_LNK = 0xa
|
|
DT_REG = 0x8
|
|
DT_SOCK = 0xc
|
|
DT_UNKNOWN = 0x0
|
|
DT_WHT = 0xe
|
|
)
|
|
|
|
// dummy
|
|
type Dirent struct {
|
|
Ino uint64
|
|
Reclen uint16
|
|
Type uint8
|
|
Name [1024]int8
|
|
}
|
|
|
|
func ReadDirent(fd int, buf []byte) (n int, err error) {
|
|
return -1, ENOSYS
|
|
}
|
|
|
|
func Stat(path string, p *Stat_t) (err error) {
|
|
data := cstring(path)
|
|
n := libc_stat(&data[0], unsafe.Pointer(p))
|
|
|
|
if n < 0 {
|
|
err = getErrno()
|
|
}
|
|
return
|
|
}
|
|
|
|
func Fstat(fd int, p *Stat_t) (err error) {
|
|
n := libc_fstat(int32(fd), unsafe.Pointer(p))
|
|
|
|
if n < 0 {
|
|
err = getErrno()
|
|
}
|
|
return
|
|
}
|
|
|
|
func Lstat(path string, p *Stat_t) (err error) {
|
|
data := cstring(path)
|
|
n := libc_lstat(&data[0], unsafe.Pointer(p))
|
|
if n < 0 {
|
|
err = getErrno()
|
|
}
|
|
return
|
|
}
|
|
|
|
func Pipe2(p []int, flags int) (err error) {
|
|
return ENOSYS // TODO
|
|
}
|
|
|
|
func Getpagesize() int {
|
|
// per upstream
|
|
return 65536
|
|
}
|
|
|
|
// int stat(const char *path, struct stat * buf);
|
|
//
|
|
//export stat
|
|
func libc_stat(pathname *byte, ptr unsafe.Pointer) int32
|
|
|
|
// int fstat(int fd, struct stat * buf);
|
|
//
|
|
//export fstat
|
|
func libc_fstat(fd int32, ptr unsafe.Pointer) int32
|
|
|
|
// int lstat(const char *path, struct stat * buf);
|
|
//
|
|
//export lstat
|
|
func libc_lstat(pathname *byte, ptr unsafe.Pointer) int32
|