1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
|
//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_DSYNC = 2
__WASI_FDFLAGS_NONBLOCK = 4
__WASI_FDFLAGS_RSYNC = 8
__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_DSYNC = __WASI_FDFLAGS_DSYNC
O_NONBLOCK = __WASI_FDFLAGS_NONBLOCK
O_RSYNC = __WASI_FDFLAGS_RSYNC
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
// int open(const char *pathname, int flags, mode_t mode);
//
//export open
func libc_open(pathname *byte, flags int32, mode uint32) int32
|