| // Copyright 2023 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. |
| |
| //go:build wasip1 |
| |
| package syscall |
| |
| import ( |
| "errors" |
| "internal/itoa" |
| "internal/oserror" |
| "unsafe" |
| ) |
| |
| type Dircookie = uint64 |
| |
| type Filetype = uint8 |
| |
| const ( |
| FILETYPE_UNKNOWN Filetype = iota |
| FILETYPE_BLOCK_DEVICE |
| FILETYPE_CHARACTER_DEVICE |
| FILETYPE_DIRECTORY |
| FILETYPE_REGULAR_FILE |
| FILETYPE_SOCKET_DGRAM |
| FILETYPE_SOCKET_STREAM |
| FILETYPE_SYMBOLIC_LINK |
| ) |
| |
| type Dirent struct { |
| // The offset of the next directory entry stored in this directory. |
| Next Dircookie |
| // The serial number of the file referred to by this directory entry. |
| Ino uint64 |
| // The length of the name of the directory entry. |
| Namlen uint32 |
| // The type of the file referred to by this directory entry. |
| Type Filetype |
| // Name of the directory entry. |
| Name *byte |
| } |
| |
| func direntIno(buf []byte) (uint64, bool) { |
| return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino)) |
| } |
| |
| func direntReclen(buf []byte) (uint64, bool) { |
| namelen, ok := direntNamlen(buf) |
| return 24 + namelen, ok |
| } |
| |
| func direntNamlen(buf []byte) (uint64, bool) { |
| return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen)) |
| } |
| |
| // An Errno is an unsigned number describing an error condition. |
| // It implements the error interface. The zero Errno is by convention |
| // a non-error, so code to convert from Errno to error should use: |
| // |
| // var err = nil |
| // if errno != 0 { |
| // err = errno |
| // } |
| type Errno uint32 |
| |
| func (e Errno) Error() string { |
| if 0 <= int(e) && int(e) < len(errorstr) { |
| s := errorstr[e] |
| if s != "" { |
| return s |
| } |
| } |
| return "errno " + itoa.Itoa(int(e)) |
| } |
| |
| func (e Errno) Is(target error) bool { |
| switch target { |
| case oserror.ErrPermission: |
| return e == EACCES || e == EPERM |
| case oserror.ErrExist: |
| return e == EEXIST || e == ENOTEMPTY |
| case oserror.ErrNotExist: |
| return e == ENOENT |
| case errors.ErrUnsupported: |
| return e == ENOSYS |
| } |
| return false |
| } |
| |
| func (e Errno) Temporary() bool { |
| return e == EINTR || e == EMFILE || e.Timeout() |
| } |
| |
| func (e Errno) Timeout() bool { |
| return e == EAGAIN || e == ETIMEDOUT |
| } |
| |
| // A Signal is a number describing a process signal. |
| // It implements the [os.Signal] interface. |
| type Signal uint8 |
| |
| const ( |
| SIGNONE Signal = iota |
| SIGHUP |
| SIGINT |
| SIGQUIT |
| SIGILL |
| SIGTRAP |
| SIGABRT |
| SIGBUS |
| SIGFPE |
| SIGKILL |
| SIGUSR1 |
| SIGSEGV |
| SIGUSR2 |
| SIGPIPE |
| SIGALRM |
| SIGTERM |
| SIGCHLD |
| SIGCONT |
| SIGSTOP |
| SIGTSTP |
| SIGTTIN |
| SIGTTOU |
| SIGURG |
| SIGXCPU |
| SIGXFSZ |
| SIGVTARLM |
| SIGPROF |
| SIGWINCH |
| SIGPOLL |
| SIGPWR |
| SIGSYS |
| ) |
| |
| func (s Signal) Signal() {} |
| |
| func (s Signal) String() string { |
| switch s { |
| case SIGNONE: |
| return "no signal" |
| case SIGHUP: |
| return "hangup" |
| case SIGINT: |
| return "interrupt" |
| case SIGQUIT: |
| return "quit" |
| case SIGILL: |
| return "illegal instruction" |
| case SIGTRAP: |
| return "trace/breakpoint trap" |
| case SIGABRT: |
| return "abort" |
| case SIGBUS: |
| return "bus error" |
| case SIGFPE: |
| return "floating point exception" |
| case SIGKILL: |
| return "killed" |
| case SIGUSR1: |
| return "user defined signal 1" |
| case SIGSEGV: |
| return "segmentation fault" |
| case SIGUSR2: |
| return "user defined signal 2" |
| case SIGPIPE: |
| return "broken pipe" |
| case SIGALRM: |
| return "alarm clock" |
| case SIGTERM: |
| return "terminated" |
| case SIGCHLD: |
| return "child exited" |
| case SIGCONT: |
| return "continued" |
| case SIGSTOP: |
| return "stopped (signal)" |
| case SIGTSTP: |
| return "stopped" |
| case SIGTTIN: |
| return "stopped (tty input)" |
| case SIGTTOU: |
| return "stopped (tty output)" |
| case SIGURG: |
| return "urgent I/O condition" |
| case SIGXCPU: |
| return "CPU time limit exceeded" |
| case SIGXFSZ: |
| return "file size limit exceeded" |
| case SIGVTARLM: |
| return "virtual timer expired" |
| case SIGPROF: |
| return "profiling timer expired" |
| case SIGWINCH: |
| return "window changed" |
| case SIGPOLL: |
| return "I/O possible" |
| case SIGPWR: |
| return "power failure" |
| case SIGSYS: |
| return "bad system call" |
| default: |
| return "signal " + itoa.Itoa(int(s)) |
| } |
| } |
| |
| const ( |
| Stdin = 0 |
| Stdout = 1 |
| Stderr = 2 |
| ) |
| |
| const ( |
| O_RDONLY = 0 |
| O_WRONLY = 1 |
| O_RDWR = 2 |
| |
| O_CREAT = 0100 |
| O_CREATE = O_CREAT |
| O_TRUNC = 01000 |
| O_APPEND = 02000 |
| O_EXCL = 0200 |
| O_SYNC = 010000 |
| |
| O_CLOEXEC = 0 |
| ) |
| |
| const ( |
| F_DUPFD = 0 |
| F_GETFD = 1 |
| F_SETFD = 2 |
| F_GETFL = 3 |
| F_SETFL = 4 |
| F_GETOWN = 5 |
| F_SETOWN = 6 |
| F_GETLK = 7 |
| F_SETLK = 8 |
| F_SETLKW = 9 |
| F_RGETLK = 10 |
| F_RSETLK = 11 |
| F_CNVT = 12 |
| F_RSETLKW = 13 |
| |
| F_RDLCK = 1 |
| F_WRLCK = 2 |
| F_UNLCK = 3 |
| F_UNLKSYS = 4 |
| ) |
| |
| const ( |
| S_IFMT = 0000370000 |
| S_IFSHM_SYSV = 0000300000 |
| S_IFSEMA = 0000270000 |
| S_IFCOND = 0000260000 |
| S_IFMUTEX = 0000250000 |
| S_IFSHM = 0000240000 |
| S_IFBOUNDSOCK = 0000230000 |
| S_IFSOCKADDR = 0000220000 |
| S_IFDSOCK = 0000210000 |
| |
| S_IFSOCK = 0000140000 |
| S_IFLNK = 0000120000 |
| S_IFREG = 0000100000 |
| S_IFBLK = 0000060000 |
| S_IFDIR = 0000040000 |
| S_IFCHR = 0000020000 |
| S_IFIFO = 0000010000 |
| |
| S_UNSUP = 0000370000 |
| |
| S_ISUID = 0004000 |
| S_ISGID = 0002000 |
| S_ISVTX = 0001000 |
| |
| S_IREAD = 0400 |
| S_IWRITE = 0200 |
| S_IEXEC = 0100 |
| |
| S_IRWXU = 0700 |
| S_IRUSR = 0400 |
| S_IWUSR = 0200 |
| S_IXUSR = 0100 |
| |
| S_IRWXG = 070 |
| S_IRGRP = 040 |
| S_IWGRP = 020 |
| S_IXGRP = 010 |
| |
| S_IRWXO = 07 |
| S_IROTH = 04 |
| S_IWOTH = 02 |
| S_IXOTH = 01 |
| ) |
| |
| type WaitStatus uint32 |
| |
| func (w WaitStatus) Exited() bool { return false } |
| func (w WaitStatus) ExitStatus() int { return 0 } |
| func (w WaitStatus) Signaled() bool { return false } |
| func (w WaitStatus) Signal() Signal { return 0 } |
| func (w WaitStatus) CoreDump() bool { return false } |
| func (w WaitStatus) Stopped() bool { return false } |
| func (w WaitStatus) Continued() bool { return false } |
| func (w WaitStatus) StopSignal() Signal { return 0 } |
| func (w WaitStatus) TrapCause() int { return 0 } |
| |
| // Rusage is a placeholder to allow compilation of the [os/exec] package |
| // because we need Go programs to be portable across platforms. WASI does |
| // not have a mechanism to to spawn processes so there is no reason for an |
| // application to take a dependency on this type. |
| type Rusage struct { |
| Utime Timeval |
| Stime Timeval |
| } |
| |
| // ProcAttr is a placeholder to allow compilation of the [os/exec] package |
| // because we need Go programs to be portable across platforms. WASI does |
| // not have a mechanism to to spawn processes so there is no reason for an |
| // application to take a dependency on this type. |
| type ProcAttr struct { |
| Dir string |
| Env []string |
| Files []uintptr |
| Sys *SysProcAttr |
| } |
| |
| type SysProcAttr struct { |
| } |
| |
| func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { |
| return 0, 0, ENOSYS |
| } |
| |
| func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { |
| return 0, 0, ENOSYS |
| } |
| |
| func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) { |
| return 0, 0, ENOSYS |
| } |
| |
| func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) { |
| return 0, 0, ENOSYS |
| } |
| |
| func Sysctl(key string) (string, error) { |
| if key == "kern.hostname" { |
| return "wasip1", nil |
| } |
| return "", ENOSYS |
| } |
| |
| func Getuid() int { |
| return 1 |
| } |
| |
| func Getgid() int { |
| return 1 |
| } |
| |
| func Geteuid() int { |
| return 1 |
| } |
| |
| func Getegid() int { |
| return 1 |
| } |
| |
| func Getgroups() ([]int, error) { |
| return []int{1}, nil |
| } |
| |
| func Getpid() int { |
| return 3 |
| } |
| |
| func Getppid() int { |
| return 2 |
| } |
| |
| func Gettimeofday(tv *Timeval) error { |
| var time timestamp |
| if errno := clock_time_get(clockRealtime, 1e3, unsafe.Pointer(&time)); errno != 0 { |
| return errno |
| } |
| tv.setTimestamp(time) |
| return nil |
| } |
| |
| func Kill(pid int, signum Signal) error { |
| // WASI does not have the notion of processes nor signal handlers. |
| // |
| // Any signal that the application raises to the process itself will |
| // be interpreted as being cause for termination. |
| if pid > 0 && pid != Getpid() { |
| return ESRCH |
| } |
| ProcExit(128 + int32(signum)) |
| return nil |
| } |
| |
| func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) { |
| return 0, ENOSYS |
| } |
| |
| func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) { |
| return 0, 0, ENOSYS |
| } |
| |
| func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) { |
| return 0, ENOSYS |
| } |
| |
| func Umask(mask int) int { |
| return 0 |
| } |
| |
| type Timespec struct { |
| Sec int64 |
| Nsec int64 |
| } |
| |
| func (ts *Timespec) timestamp() timestamp { |
| return timestamp(ts.Sec*1e9) + timestamp(ts.Nsec) |
| } |
| |
| func (ts *Timespec) setTimestamp(t timestamp) { |
| ts.Sec = int64(t / 1e9) |
| ts.Nsec = int64(t % 1e9) |
| } |
| |
| type Timeval struct { |
| Sec int64 |
| Usec int64 |
| } |
| |
| func (tv *Timeval) timestamp() timestamp { |
| return timestamp(tv.Sec*1e9) + timestamp(tv.Usec*1e3) |
| } |
| |
| func (tv *Timeval) setTimestamp(t timestamp) { |
| tv.Sec = int64(t / 1e9) |
| tv.Usec = int64((t % 1e9) / 1e3) |
| } |
| |
| func setTimespec(sec, nsec int64) Timespec { |
| return Timespec{Sec: sec, Nsec: nsec} |
| } |
| |
| func setTimeval(sec, usec int64) Timeval { |
| return Timeval{Sec: sec, Usec: usec} |
| } |
| |
| type clockid = uint32 |
| |
| const ( |
| clockRealtime clockid = iota |
| clockMonotonic |
| clockProcessCPUTimeID |
| clockThreadCPUTimeID |
| ) |
| |
| //go:wasmimport wasi_snapshot_preview1 clock_time_get |
| //go:noescape |
| func clock_time_get(id clockid, precision timestamp, time unsafe.Pointer) Errno |
| |
| func SetNonblock(fd int, nonblocking bool) error { |
| flags, err := fd_fdstat_get_flags(fd) |
| if err != nil { |
| return err |
| } |
| if nonblocking { |
| flags |= FDFLAG_NONBLOCK |
| } else { |
| flags &^= FDFLAG_NONBLOCK |
| } |
| errno := fd_fdstat_set_flags(int32(fd), flags) |
| return errnoErr(errno) |
| } |
| |
| type Rlimit struct { |
| Cur uint64 |
| Max uint64 |
| } |
| |
| const ( |
| RLIMIT_NOFILE = iota |
| ) |
| |
| func Getrlimit(which int, lim *Rlimit) error { |
| return ENOSYS |
| } |