1// Copyright 2011 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// Plan 9 system calls.
6// This file is compiled as ordinary Go code,
7// but it is also input to mksyscall,
8// which parses the //sys lines and generates system call stubs.
9// Note that sometimes we use a lowercase //sys name and
10// wrap it in our own nicer implementation.
11
12package plan9
13
14import (
15	"bytes"
16	"syscall"
17	"unsafe"
18)
19
20// A Note is a string describing a process note.
21// It implements the os.Signal interface.
22type Note string
23
24func (n Note) Signal() {}
25
26func (n Note) String() string {
27	return string(n)
28}
29
30var (
31	Stdin  = 0
32	Stdout = 1
33	Stderr = 2
34)
35
36// For testing: clients can set this flag to force
37// creation of IPv6 sockets to return EAFNOSUPPORT.
38var SocketDisableIPv6 bool
39
40func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
41func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.ErrorString)
42func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
43func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
44
45func atoi(b []byte) (n uint) {
46	n = 0
47	for i := 0; i < len(b); i++ {
48		n = n*10 + uint(b[i]-'0')
49	}
50	return
51}
52
53func cstring(s []byte) string {
54	i := bytes.IndexByte(s, 0)
55	if i == -1 {
56		i = len(s)
57	}
58	return string(s[:i])
59}
60
61func errstr() string {
62	var buf [ERRMAX]byte
63
64	RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
65
66	buf[len(buf)-1] = 0
67	return cstring(buf[:])
68}
69
70// Implemented in assembly to import from runtime.
71func exit(code int)
72
73func Exit(code int) { exit(code) }
74
75func readnum(path string) (uint, error) {
76	var b [12]byte
77
78	fd, e := Open(path, O_RDONLY)
79	if e != nil {
80		return 0, e
81	}
82	defer Close(fd)
83
84	n, e := Pread(fd, b[:], 0)
85
86	if e != nil {
87		return 0, e
88	}
89
90	m := 0
91	for ; m < n && b[m] == ' '; m++ {
92	}
93
94	return atoi(b[m : n-1]), nil
95}
96
97func Getpid() (pid int) {
98	n, _ := readnum("#c/pid")
99	return int(n)
100}
101
102func Getppid() (ppid int) {
103	n, _ := readnum("#c/ppid")
104	return int(n)
105}
106
107func Read(fd int, p []byte) (n int, err error) {
108	return Pread(fd, p, -1)
109}
110
111func Write(fd int, p []byte) (n int, err error) {
112	return Pwrite(fd, p, -1)
113}
114
115var ioSync int64
116
117//sys	fd2path(fd int, buf []byte) (err error)
118func Fd2path(fd int) (path string, err error) {
119	var buf [512]byte
120
121	e := fd2path(fd, buf[:])
122	if e != nil {
123		return "", e
124	}
125	return cstring(buf[:]), nil
126}
127
128//sys	pipe(p *[2]int32) (err error)
129func Pipe(p []int) (err error) {
130	if len(p) != 2 {
131		return syscall.ErrorString("bad arg in system call")
132	}
133	var pp [2]int32
134	err = pipe(&pp)
135	p[0] = int(pp[0])
136	p[1] = int(pp[1])
137	return
138}
139
140// Underlying system call writes to newoffset via pointer.
141// Implemented in assembly to avoid allocation.
142func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
143
144func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
145	newoffset, e := seek(0, fd, offset, whence)
146
147	if newoffset == -1 {
148		err = syscall.ErrorString(e)
149	}
150	return
151}
152
153func Mkdir(path string, mode uint32) (err error) {
154	fd, err := Create(path, O_RDONLY, DMDIR|mode)
155
156	if fd != -1 {
157		Close(fd)
158	}
159
160	return
161}
162
163type Waitmsg struct {
164	Pid  int
165	Time [3]uint32
166	Msg  string
167}
168
169func (w Waitmsg) Exited() bool   { return true }
170func (w Waitmsg) Signaled() bool { return false }
171
172func (w Waitmsg) ExitStatus() int {
173	if len(w.Msg) == 0 {
174		// a normal exit returns no message
175		return 0
176	}
177	return 1
178}
179
180//sys	await(s []byte) (n int, err error)
181func Await(w *Waitmsg) (err error) {
182	var buf [512]byte
183	var f [5][]byte
184
185	n, err := await(buf[:])
186
187	if err != nil || w == nil {
188		return
189	}
190
191	nf := 0
192	p := 0
193	for i := 0; i < n && nf < len(f)-1; i++ {
194		if buf[i] == ' ' {
195			f[nf] = buf[p:i]
196			p = i + 1
197			nf++
198		}
199	}
200	f[nf] = buf[p:]
201	nf++
202
203	if nf != len(f) {
204		return syscall.ErrorString("invalid wait message")
205	}
206	w.Pid = int(atoi(f[0]))
207	w.Time[0] = uint32(atoi(f[1]))
208	w.Time[1] = uint32(atoi(f[2]))
209	w.Time[2] = uint32(atoi(f[3]))
210	w.Msg = cstring(f[4])
211	if w.Msg == "''" {
212		// await() returns '' for no error
213		w.Msg = ""
214	}
215	return
216}
217
218func Unmount(name, old string) (err error) {
219	fixwd()
220	oldp, err := BytePtrFromString(old)
221	if err != nil {
222		return err
223	}
224	oldptr := uintptr(unsafe.Pointer(oldp))
225
226	var r0 uintptr
227	var e syscall.ErrorString
228
229	// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
230	if name == "" {
231		r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
232	} else {
233		namep, err := BytePtrFromString(name)
234		if err != nil {
235			return err
236		}
237		r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
238	}
239
240	if int32(r0) == -1 {
241		err = e
242	}
243	return
244}
245
246func Fchdir(fd int) (err error) {
247	path, err := Fd2path(fd)
248
249	if err != nil {
250		return
251	}
252
253	return Chdir(path)
254}
255
256type Timespec struct {
257	Sec  int32
258	Nsec int32
259}
260
261type Timeval struct {
262	Sec  int32
263	Usec int32
264}
265
266func NsecToTimeval(nsec int64) (tv Timeval) {
267	nsec += 999 // round up to microsecond
268	tv.Usec = int32(nsec % 1e9 / 1e3)
269	tv.Sec = int32(nsec / 1e9)
270	return
271}
272
273func nsec() int64 {
274	var scratch int64
275
276	r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
277	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
278	if r0 == 0 {
279		return scratch
280	}
281	return int64(r0)
282}
283
284func Gettimeofday(tv *Timeval) error {
285	nsec := nsec()
286	*tv = NsecToTimeval(nsec)
287	return nil
288}
289
290func Getpagesize() int { return 0x1000 }
291
292func Getegid() (egid int) { return -1 }
293func Geteuid() (euid int) { return -1 }
294func Getgid() (gid int)   { return -1 }
295func Getuid() (uid int)   { return -1 }
296
297func Getgroups() (gids []int, err error) {
298	return make([]int, 0), nil
299}
300
301//sys	open(path string, mode int) (fd int, err error)
302func Open(path string, mode int) (fd int, err error) {
303	fixwd()
304	return open(path, mode)
305}
306
307//sys	create(path string, mode int, perm uint32) (fd int, err error)
308func Create(path string, mode int, perm uint32) (fd int, err error) {
309	fixwd()
310	return create(path, mode, perm)
311}
312
313//sys	remove(path string) (err error)
314func Remove(path string) error {
315	fixwd()
316	return remove(path)
317}
318
319//sys	stat(path string, edir []byte) (n int, err error)
320func Stat(path string, edir []byte) (n int, err error) {
321	fixwd()
322	return stat(path, edir)
323}
324
325//sys	bind(name string, old string, flag int) (err error)
326func Bind(name string, old string, flag int) (err error) {
327	fixwd()
328	return bind(name, old, flag)
329}
330
331//sys	mount(fd int, afd int, old string, flag int, aname string) (err error)
332func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
333	fixwd()
334	return mount(fd, afd, old, flag, aname)
335}
336
337//sys	wstat(path string, edir []byte) (err error)
338func Wstat(path string, edir []byte) (err error) {
339	fixwd()
340	return wstat(path, edir)
341}
342
343//sys	chdir(path string) (err error)
344//sys	Dup(oldfd int, newfd int) (fd int, err error)
345//sys	Pread(fd int, p []byte, offset int64) (n int, err error)
346//sys	Pwrite(fd int, p []byte, offset int64) (n int, err error)
347//sys	Close(fd int) (err error)
348//sys	Fstat(fd int, edir []byte) (n int, err error)
349//sys	Fwstat(fd int, edir []byte) (err error)
350