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)
118
119func Fd2path(fd int) (path string, err error) {
120 var buf [512]byte
121
122 e := fd2path(fd, buf[:])
123 if e != nil {
124 return "", e
125 }
126 return cstring(buf[:]), nil
127}
128
129//sys pipe(p *[2]int32) (err error)
130
131func Pipe(p []int) (err error) {
132 if len(p) != 2 {
133 return syscall.ErrorString("bad arg in system call")
134 }
135 var pp [2]int32
136 err = pipe(&pp)
137 if err == nil {
138 p[0] = int(pp[0])
139 p[1] = int(pp[1])
140 }
141 return
142}
143
144// Underlying system call writes to newoffset via pointer.
145// Implemented in assembly to avoid allocation.
146func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
147
148func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
149 newoffset, e := seek(0, fd, offset, whence)
150
151 if newoffset == -1 {
152 err = syscall.ErrorString(e)
153 }
154 return
155}
156
157func Mkdir(path string, mode uint32) (err error) {
158 fd, err := Create(path, O_RDONLY, DMDIR|mode)
159
160 if fd != -1 {
161 Close(fd)
162 }
163
164 return
165}
166
167type Waitmsg struct {
168 Pid int
169 Time [3]uint32
170 Msg string
171}
172
173func (w Waitmsg) Exited() bool { return true }
174func (w Waitmsg) Signaled() bool { return false }
175
176func (w Waitmsg) ExitStatus() int {
177 if len(w.Msg) == 0 {
178 // a normal exit returns no message
179 return 0
180 }
181 return 1
182}
183
184//sys await(s []byte) (n int, err error)
185
186func Await(w *Waitmsg) (err error) {
187 var buf [512]byte
188 var f [5][]byte
189
190 n, err := await(buf[:])
191
192 if err != nil || w == nil {
193 return
194 }
195
196 nf := 0
197 p := 0
198 for i := 0; i < n && nf < len(f)-1; i++ {
199 if buf[i] == ' ' {
200 f[nf] = buf[p:i]
201 p = i + 1
202 nf++
203 }
204 }
205 f[nf] = buf[p:]
206 nf++
207
208 if nf != len(f) {
209 return syscall.ErrorString("invalid wait message")
210 }
211 w.Pid = int(atoi(f[0]))
212 w.Time[0] = uint32(atoi(f[1]))
213 w.Time[1] = uint32(atoi(f[2]))
214 w.Time[2] = uint32(atoi(f[3]))
215 w.Msg = cstring(f[4])
216 if w.Msg == "''" {
217 // await() returns '' for no error
218 w.Msg = ""
219 }
220 return
221}
222
223func Unmount(name, old string) (err error) {
224 fixwd()
225 oldp, err := BytePtrFromString(old)
226 if err != nil {
227 return err
228 }
229 oldptr := uintptr(unsafe.Pointer(oldp))
230
231 var r0 uintptr
232 var e syscall.ErrorString
233
234 // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
235 if name == "" {
236 r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
237 } else {
238 namep, err := BytePtrFromString(name)
239 if err != nil {
240 return err
241 }
242 r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
243 }
244
245 if int32(r0) == -1 {
246 err = e
247 }
248 return
249}
250
251func Fchdir(fd int) (err error) {
252 path, err := Fd2path(fd)
253
254 if err != nil {
255 return
256 }
257
258 return Chdir(path)
259}
260
261type Timespec struct {
262 Sec int32
263 Nsec int32
264}
265
266type Timeval struct {
267 Sec int32
268 Usec int32
269}
270
271func NsecToTimeval(nsec int64) (tv Timeval) {
272 nsec += 999 // round up to microsecond
273 tv.Usec = int32(nsec % 1e9 / 1e3)
274 tv.Sec = int32(nsec / 1e9)
275 return
276}
277
278func nsec() int64 {
279 var scratch int64
280
281 r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
282 // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
283 if r0 == 0 {
284 return scratch
285 }
286 return int64(r0)
287}
288
289func Gettimeofday(tv *Timeval) error {
290 nsec := nsec()
291 *tv = NsecToTimeval(nsec)
292 return nil
293}
294
295func Getpagesize() int { return 0x1000 }
296
297func Getegid() (egid int) { return -1 }
298func Geteuid() (euid int) { return -1 }
299func Getgid() (gid int) { return -1 }
300func Getuid() (uid int) { return -1 }
301
302func Getgroups() (gids []int, err error) {
303 return make([]int, 0), nil
304}
305
306//sys open(path string, mode int) (fd int, err error)
307
308func Open(path string, mode int) (fd int, err error) {
309 fixwd()
310 return open(path, mode)
311}
312
313//sys create(path string, mode int, perm uint32) (fd int, err error)
314
315func Create(path string, mode int, perm uint32) (fd int, err error) {
316 fixwd()
317 return create(path, mode, perm)
318}
319
320//sys remove(path string) (err error)
321
322func Remove(path string) error {
323 fixwd()
324 return remove(path)
325}
326
327//sys stat(path string, edir []byte) (n int, err error)
328
329func Stat(path string, edir []byte) (n int, err error) {
330 fixwd()
331 return stat(path, edir)
332}
333
334//sys bind(name string, old string, flag int) (err error)
335
336func Bind(name string, old string, flag int) (err error) {
337 fixwd()
338 return bind(name, old, flag)
339}
340
341//sys mount(fd int, afd int, old string, flag int, aname string) (err error)
342
343func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
344 fixwd()
345 return mount(fd, afd, old, flag, aname)
346}
347
348//sys wstat(path string, edir []byte) (err error)
349
350func Wstat(path string, edir []byte) (err error) {
351 fixwd()
352 return wstat(path, edir)
353}
354
355//sys chdir(path string) (err error)
356//sys Dup(oldfd int, newfd int) (fd int, err error)
357//sys Pread(fd int, p []byte, offset int64) (n int, err error)
358//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
359//sys Close(fd int) (err error)
360//sys Fstat(fd int, edir []byte) (n int, err error)
361//sys Fwstat(fd int, edir []byte) (err error)