syscall_plan9.go

  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)