1// Copyright 2023 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5//go:build wasip1
6
7package syscall
8
9import (
10	"errors"
11	"internal/itoa"
12	"internal/oserror"
13	"unsafe"
14)
15
16type Dircookie = uint64
17
18type Filetype = uint8
19
20const (
21	FILETYPE_UNKNOWN Filetype = iota
22	FILETYPE_BLOCK_DEVICE
23	FILETYPE_CHARACTER_DEVICE
24	FILETYPE_DIRECTORY
25	FILETYPE_REGULAR_FILE
26	FILETYPE_SOCKET_DGRAM
27	FILETYPE_SOCKET_STREAM
28	FILETYPE_SYMBOLIC_LINK
29)
30
31type Dirent struct {
32	// The offset of the next directory entry stored in this directory.
33	Next Dircookie
34	// The serial number of the file referred to by this directory entry.
35	Ino uint64
36	// The length of the name of the directory entry.
37	Namlen uint32
38	// The type of the file referred to by this directory entry.
39	Type Filetype
40	// Name of the directory entry.
41	Name *byte
42}
43
44func direntIno(buf []byte) (uint64, bool) {
45	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
46}
47
48func direntReclen(buf []byte) (uint64, bool) {
49	namelen, ok := direntNamlen(buf)
50	return 24 + namelen, ok
51}
52
53func direntNamlen(buf []byte) (uint64, bool) {
54	return readInt(buf, unsafe.Offsetof(Dirent{}.Namlen), unsafe.Sizeof(Dirent{}.Namlen))
55}
56
57// An Errno is an unsigned number describing an error condition.
58// It implements the error interface. The zero Errno is by convention
59// a non-error, so code to convert from Errno to error should use:
60//
61//	var err = nil
62//	if errno != 0 {
63//		err = errno
64//	}
65type Errno uint32
66
67func (e Errno) Error() string {
68	if 0 <= int(e) && int(e) < len(errorstr) {
69		s := errorstr[e]
70		if s != "" {
71			return s
72		}
73	}
74	return "errno " + itoa.Itoa(int(e))
75}
76
77func (e Errno) Is(target error) bool {
78	switch target {
79	case oserror.ErrPermission:
80		return e == EACCES || e == EPERM
81	case oserror.ErrExist:
82		return e == EEXIST || e == ENOTEMPTY
83	case oserror.ErrNotExist:
84		return e == ENOENT
85	case errors.ErrUnsupported:
86		return e == ENOSYS
87	}
88	return false
89}
90
91func (e Errno) Temporary() bool {
92	return e == EINTR || e == EMFILE || e.Timeout()
93}
94
95func (e Errno) Timeout() bool {
96	return e == EAGAIN || e == ETIMEDOUT
97}
98
99// A Signal is a number describing a process signal.
100// It implements the [os.Signal] interface.
101type Signal uint8
102
103const (
104	SIGNONE Signal = iota
105	SIGHUP
106	SIGINT
107	SIGQUIT
108	SIGILL
109	SIGTRAP
110	SIGABRT
111	SIGBUS
112	SIGFPE
113	SIGKILL
114	SIGUSR1
115	SIGSEGV
116	SIGUSR2
117	SIGPIPE
118	SIGALRM
119	SIGTERM
120	SIGCHLD
121	SIGCONT
122	SIGSTOP
123	SIGTSTP
124	SIGTTIN
125	SIGTTOU
126	SIGURG
127	SIGXCPU
128	SIGXFSZ
129	SIGVTARLM
130	SIGPROF
131	SIGWINCH
132	SIGPOLL
133	SIGPWR
134	SIGSYS
135)
136
137func (s Signal) Signal() {}
138
139func (s Signal) String() string {
140	switch s {
141	case SIGNONE:
142		return "no signal"
143	case SIGHUP:
144		return "hangup"
145	case SIGINT:
146		return "interrupt"
147	case SIGQUIT:
148		return "quit"
149	case SIGILL:
150		return "illegal instruction"
151	case SIGTRAP:
152		return "trace/breakpoint trap"
153	case SIGABRT:
154		return "abort"
155	case SIGBUS:
156		return "bus error"
157	case SIGFPE:
158		return "floating point exception"
159	case SIGKILL:
160		return "killed"
161	case SIGUSR1:
162		return "user defined signal 1"
163	case SIGSEGV:
164		return "segmentation fault"
165	case SIGUSR2:
166		return "user defined signal 2"
167	case SIGPIPE:
168		return "broken pipe"
169	case SIGALRM:
170		return "alarm clock"
171	case SIGTERM:
172		return "terminated"
173	case SIGCHLD:
174		return "child exited"
175	case SIGCONT:
176		return "continued"
177	case SIGSTOP:
178		return "stopped (signal)"
179	case SIGTSTP:
180		return "stopped"
181	case SIGTTIN:
182		return "stopped (tty input)"
183	case SIGTTOU:
184		return "stopped (tty output)"
185	case SIGURG:
186		return "urgent I/O condition"
187	case SIGXCPU:
188		return "CPU time limit exceeded"
189	case SIGXFSZ:
190		return "file size limit exceeded"
191	case SIGVTARLM:
192		return "virtual timer expired"
193	case SIGPROF:
194		return "profiling timer expired"
195	case SIGWINCH:
196		return "window changed"
197	case SIGPOLL:
198		return "I/O possible"
199	case SIGPWR:
200		return "power failure"
201	case SIGSYS:
202		return "bad system call"
203	default:
204		return "signal " + itoa.Itoa(int(s))
205	}
206}
207
208const (
209	Stdin  = 0
210	Stdout = 1
211	Stderr = 2
212)
213
214const (
215	O_RDONLY = 0
216	O_WRONLY = 1
217	O_RDWR   = 2
218
219	O_CREAT  = 0100
220	O_CREATE = O_CREAT
221	O_TRUNC  = 01000
222	O_APPEND = 02000
223	O_EXCL   = 0200
224	O_SYNC   = 010000
225
226	O_CLOEXEC = 0
227)
228
229const (
230	F_DUPFD   = 0
231	F_GETFD   = 1
232	F_SETFD   = 2
233	F_GETFL   = 3
234	F_SETFL   = 4
235	F_GETOWN  = 5
236	F_SETOWN  = 6
237	F_GETLK   = 7
238	F_SETLK   = 8
239	F_SETLKW  = 9
240	F_RGETLK  = 10
241	F_RSETLK  = 11
242	F_CNVT    = 12
243	F_RSETLKW = 13
244
245	F_RDLCK   = 1
246	F_WRLCK   = 2
247	F_UNLCK   = 3
248	F_UNLKSYS = 4
249)
250
251const (
252	S_IFMT        = 0000370000
253	S_IFSHM_SYSV  = 0000300000
254	S_IFSEMA      = 0000270000
255	S_IFCOND      = 0000260000
256	S_IFMUTEX     = 0000250000
257	S_IFSHM       = 0000240000
258	S_IFBOUNDSOCK = 0000230000
259	S_IFSOCKADDR  = 0000220000
260	S_IFDSOCK     = 0000210000
261
262	S_IFSOCK = 0000140000
263	S_IFLNK  = 0000120000
264	S_IFREG  = 0000100000
265	S_IFBLK  = 0000060000
266	S_IFDIR  = 0000040000
267	S_IFCHR  = 0000020000
268	S_IFIFO  = 0000010000
269
270	S_UNSUP = 0000370000
271
272	S_ISUID = 0004000
273	S_ISGID = 0002000
274	S_ISVTX = 0001000
275
276	S_IREAD  = 0400
277	S_IWRITE = 0200
278	S_IEXEC  = 0100
279
280	S_IRWXU = 0700
281	S_IRUSR = 0400
282	S_IWUSR = 0200
283	S_IXUSR = 0100
284
285	S_IRWXG = 070
286	S_IRGRP = 040
287	S_IWGRP = 020
288	S_IXGRP = 010
289
290	S_IRWXO = 07
291	S_IROTH = 04
292	S_IWOTH = 02
293	S_IXOTH = 01
294)
295
296type WaitStatus uint32
297
298func (w WaitStatus) Exited() bool       { return false }
299func (w WaitStatus) ExitStatus() int    { return 0 }
300func (w WaitStatus) Signaled() bool     { return false }
301func (w WaitStatus) Signal() Signal     { return 0 }
302func (w WaitStatus) CoreDump() bool     { return false }
303func (w WaitStatus) Stopped() bool      { return false }
304func (w WaitStatus) Continued() bool    { return false }
305func (w WaitStatus) StopSignal() Signal { return 0 }
306func (w WaitStatus) TrapCause() int     { return 0 }
307
308// Rusage is a placeholder to allow compilation of the [os/exec] package
309// because we need Go programs to be portable across platforms. WASI does
310// not have a mechanism to to spawn processes so there is no reason for an
311// application to take a dependency on this type.
312type Rusage struct {
313	Utime Timeval
314	Stime Timeval
315}
316
317// ProcAttr is a placeholder to allow compilation of the [os/exec] package
318// because we need Go programs to be portable across platforms. WASI does
319// not have a mechanism to to spawn processes so there is no reason for an
320// application to take a dependency on this type.
321type ProcAttr struct {
322	Dir   string
323	Env   []string
324	Files []uintptr
325	Sys   *SysProcAttr
326}
327
328type SysProcAttr struct {
329}
330
331func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
332	return 0, 0, ENOSYS
333}
334
335func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
336	return 0, 0, ENOSYS
337}
338
339func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err Errno) {
340	return 0, 0, ENOSYS
341}
342
343func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno) {
344	return 0, 0, ENOSYS
345}
346
347func Sysctl(key string) (string, error) {
348	if key == "kern.hostname" {
349		return "wasip1", nil
350	}
351	return "", ENOSYS
352}
353
354func Getuid() int {
355	return 1
356}
357
358func Getgid() int {
359	return 1
360}
361
362func Geteuid() int {
363	return 1
364}
365
366func Getegid() int {
367	return 1
368}
369
370func Getgroups() ([]int, error) {
371	return []int{1}, nil
372}
373
374func Getpid() int {
375	return 3
376}
377
378func Getppid() int {
379	return 2
380}
381
382func Gettimeofday(tv *Timeval) error {
383	var time timestamp
384	if errno := clock_time_get(clockRealtime, 1e3, unsafe.Pointer(&time)); errno != 0 {
385		return errno
386	}
387	tv.setTimestamp(time)
388	return nil
389}
390
391func Kill(pid int, signum Signal) error {
392	// WASI does not have the notion of processes nor signal handlers.
393	//
394	// Any signal that the application raises to the process itself will
395	// be interpreted as being cause for termination.
396	if pid > 0 && pid != Getpid() {
397		return ESRCH
398	}
399	ProcExit(128 + int32(signum))
400	return nil
401}
402
403func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
404	return 0, ENOSYS
405}
406
407func StartProcess(argv0 string, argv []string, attr *ProcAttr) (pid int, handle uintptr, err error) {
408	return 0, 0, ENOSYS
409}
410
411func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int, err error) {
412	return 0, ENOSYS
413}
414
415func Umask(mask int) int {
416	return 0
417}
418
419type Timespec struct {
420	Sec  int64
421	Nsec int64
422}
423
424func (ts *Timespec) timestamp() timestamp {
425	return timestamp(ts.Sec*1e9) + timestamp(ts.Nsec)
426}
427
428func (ts *Timespec) setTimestamp(t timestamp) {
429	ts.Sec = int64(t / 1e9)
430	ts.Nsec = int64(t % 1e9)
431}
432
433type Timeval struct {
434	Sec  int64
435	Usec int64
436}
437
438func (tv *Timeval) timestamp() timestamp {
439	return timestamp(tv.Sec*1e9) + timestamp(tv.Usec*1e3)
440}
441
442func (tv *Timeval) setTimestamp(t timestamp) {
443	tv.Sec = int64(t / 1e9)
444	tv.Usec = int64((t % 1e9) / 1e3)
445}
446
447func setTimespec(sec, nsec int64) Timespec {
448	return Timespec{Sec: sec, Nsec: nsec}
449}
450
451func setTimeval(sec, usec int64) Timeval {
452	return Timeval{Sec: sec, Usec: usec}
453}
454
455type clockid = uint32
456
457const (
458	clockRealtime clockid = iota
459	clockMonotonic
460	clockProcessCPUTimeID
461	clockThreadCPUTimeID
462)
463
464//go:wasmimport wasi_snapshot_preview1 clock_time_get
465//go:noescape
466func clock_time_get(id clockid, precision timestamp, time unsafe.Pointer) Errno
467
468func SetNonblock(fd int, nonblocking bool) error {
469	flags, err := fd_fdstat_get_flags(fd)
470	if err != nil {
471		return err
472	}
473	if nonblocking {
474		flags |= FDFLAG_NONBLOCK
475	} else {
476		flags &^= FDFLAG_NONBLOCK
477	}
478	errno := fd_fdstat_set_flags(int32(fd), flags)
479	return errnoErr(errno)
480}
481
482type Rlimit struct {
483	Cur uint64
484	Max uint64
485}
486
487const (
488	RLIMIT_NOFILE = iota
489)
490
491func Getrlimit(which int, lim *Rlimit) error {
492	return ENOSYS
493}
494