]> Cypherpunks.ru repositories - gostls13.git/blob - src/syscall/syscall_plan9.go
cmd/compile/internal/inline: score call sites exposed by inlines
[gostls13.git] / src / syscall / 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
12 package syscall
13
14 import (
15         "errors"
16         "internal/oserror"
17         "runtime"
18         "unsafe"
19 )
20
21 const ImplementsGetwd = true
22 const bitSize16 = 2
23
24 // ErrorString implements Error's String method by returning itself.
25 //
26 // ErrorString values can be tested against error values using errors.Is.
27 // For example:
28 //
29 //      _, _, err := syscall.Syscall(...)
30 //      if errors.Is(err, fs.ErrNotExist) ...
31 type ErrorString string
32
33 func (e ErrorString) Error() string { return string(e) }
34
35 // NewError converts s to an ErrorString, which satisfies the Error interface.
36 func NewError(s string) error { return ErrorString(s) }
37
38 func (e ErrorString) Is(target error) bool {
39         switch target {
40         case oserror.ErrPermission:
41                 return checkErrMessageContent(e, "permission denied")
42         case oserror.ErrExist:
43                 return checkErrMessageContent(e, "exists", "is a directory")
44         case oserror.ErrNotExist:
45                 return checkErrMessageContent(e, "does not exist", "not found",
46                         "has been removed", "no parent")
47         case errors.ErrUnsupported:
48                 return checkErrMessageContent(e, "not supported")
49         }
50         return false
51 }
52
53 // checkErrMessageContent checks if err message contains one of msgs.
54 func checkErrMessageContent(e ErrorString, msgs ...string) bool {
55         for _, msg := range msgs {
56                 if contains(string(e), msg) {
57                         return true
58                 }
59         }
60         return false
61 }
62
63 // contains is a local version of strings.Contains. It knows len(sep) > 1.
64 func contains(s, sep string) bool {
65         n := len(sep)
66         c := sep[0]
67         for i := 0; i+n <= len(s); i++ {
68                 if s[i] == c && s[i:i+n] == sep {
69                         return true
70                 }
71         }
72         return false
73 }
74
75 func (e ErrorString) Temporary() bool {
76         return e == EINTR || e == EMFILE || e.Timeout()
77 }
78
79 func (e ErrorString) Timeout() bool {
80         return e == EBUSY || e == ETIMEDOUT
81 }
82
83 var emptystring string
84
85 // A Note is a string describing a process note.
86 // It implements the os.Signal interface.
87 type Note string
88
89 func (n Note) Signal() {}
90
91 func (n Note) String() string {
92         return string(n)
93 }
94
95 var (
96         Stdin  = 0
97         Stdout = 1
98         Stderr = 2
99 )
100
101 // For testing: clients can set this flag to force
102 // creation of IPv6 sockets to return EAFNOSUPPORT.
103 var SocketDisableIPv6 bool
104
105 func Syscall(trap, a1, a2, a3 uintptr) (r1, r2 uintptr, err ErrorString)
106 func Syscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err ErrorString)
107 func RawSyscall(trap, a1, a2, a3 uintptr) (r1, r2, err uintptr)
108 func RawSyscall6(trap, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2, err uintptr)
109
110 //go:nosplit
111 func atoi(b []byte) (n uint) {
112         n = 0
113         for i := 0; i < len(b); i++ {
114                 n = n*10 + uint(b[i]-'0')
115         }
116         return
117 }
118
119 func cstring(s []byte) string {
120         for i := range s {
121                 if s[i] == 0 {
122                         return string(s[0:i])
123                 }
124         }
125         return string(s)
126 }
127
128 func errstr() string {
129         var buf [ERRMAX]byte
130
131         RawSyscall(SYS_ERRSTR, uintptr(unsafe.Pointer(&buf[0])), uintptr(len(buf)), 0)
132
133         buf[len(buf)-1] = 0
134         return cstring(buf[:])
135 }
136
137 func readnum(path string) (uint, error) {
138         var b [12]byte
139
140         fd, e := Open(path, O_RDONLY)
141         if e != nil {
142                 return 0, e
143         }
144         defer Close(fd)
145
146         n, e := Pread(fd, b[:], 0)
147
148         if e != nil {
149                 return 0, e
150         }
151
152         m := 0
153         for ; m < n && b[m] == ' '; m++ {
154         }
155
156         return atoi(b[m : n-1]), nil
157 }
158
159 func Getpid() (pid int) {
160         n, _ := readnum("#c/pid")
161         return int(n)
162 }
163
164 func Getppid() (ppid int) {
165         n, _ := readnum("#c/ppid")
166         return int(n)
167 }
168
169 func Read(fd int, p []byte) (n int, err error) {
170         return Pread(fd, p, -1)
171 }
172
173 func Write(fd int, p []byte) (n int, err error) {
174         if faketime && (fd == 1 || fd == 2) {
175                 n = faketimeWrite(fd, p)
176                 if n < 0 {
177                         return 0, ErrorString("error")
178                 }
179                 return n, nil
180         }
181
182         return Pwrite(fd, p, -1)
183 }
184
185 var ioSync int64
186
187 //sys   fd2path(fd int, buf []byte) (err error)
188
189 func Fd2path(fd int) (path string, err error) {
190         var buf [512]byte
191
192         e := fd2path(fd, buf[:])
193         if e != nil {
194                 return "", e
195         }
196         return cstring(buf[:]), nil
197 }
198
199 //sys   pipe(p *[2]int32) (err error)
200
201 func Pipe(p []int) (err error) {
202         if len(p) != 2 {
203                 return NewError("bad arg in system call")
204         }
205         var pp [2]int32
206         err = pipe(&pp)
207         if err == nil {
208                 p[0] = int(pp[0])
209                 p[1] = int(pp[1])
210         }
211         return
212 }
213
214 // Underlying system call writes to newoffset via pointer.
215 // Implemented in assembly to avoid allocation.
216 func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
217
218 func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
219         newoffset, e := seek(0, fd, offset, whence)
220
221         if newoffset == -1 {
222                 err = NewError(e)
223         }
224         return
225 }
226
227 func Mkdir(path string, mode uint32) (err error) {
228         // If path exists and is not a directory, Create will fail silently.
229         // Work around this by rejecting Mkdir if path exists.
230         statbuf := make([]byte, bitSize16)
231         // Remove any trailing slashes from path, otherwise the Stat will
232         // fail with ENOTDIR.
233         n := len(path)
234         for n > 1 && path[n-1] == '/' {
235                 n--
236         }
237         _, err = Stat(path[0:n], statbuf)
238         if err == nil {
239                 return EEXIST
240         }
241
242         fd, err := Create(path, O_RDONLY, DMDIR|mode)
243
244         if fd != -1 {
245                 Close(fd)
246         }
247
248         return
249 }
250
251 type Waitmsg struct {
252         Pid  int
253         Time [3]uint32
254         Msg  string
255 }
256
257 func (w Waitmsg) Exited() bool   { return true }
258 func (w Waitmsg) Signaled() bool { return false }
259
260 func (w Waitmsg) ExitStatus() int {
261         if len(w.Msg) == 0 {
262                 // a normal exit returns no message
263                 return 0
264         }
265         return 1
266 }
267
268 //sys   await(s []byte) (n int, err error)
269
270 func Await(w *Waitmsg) (err error) {
271         var buf [512]byte
272         var f [5][]byte
273
274         n, err := await(buf[:])
275
276         if err != nil || w == nil {
277                 return
278         }
279
280         nf := 0
281         p := 0
282         for i := 0; i < n && nf < len(f)-1; i++ {
283                 if buf[i] == ' ' {
284                         f[nf] = buf[p:i]
285                         p = i + 1
286                         nf++
287                 }
288         }
289         f[nf] = buf[p:]
290         nf++
291
292         if nf != len(f) {
293                 return NewError("invalid wait message")
294         }
295         w.Pid = int(atoi(f[0]))
296         w.Time[0] = uint32(atoi(f[1]))
297         w.Time[1] = uint32(atoi(f[2]))
298         w.Time[2] = uint32(atoi(f[3]))
299         w.Msg = cstring(f[4])
300         if w.Msg == "''" {
301                 // await() returns '' for no error
302                 w.Msg = ""
303         }
304         return
305 }
306
307 func Unmount(name, old string) (err error) {
308         if fixwd(name, old) {
309                 defer runtime.UnlockOSThread()
310         }
311         oldp, err := BytePtrFromString(old)
312         if err != nil {
313                 return err
314         }
315         oldptr := uintptr(unsafe.Pointer(oldp))
316
317         var r0 uintptr
318         var e ErrorString
319
320         // bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
321         if name == "" {
322                 r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
323         } else {
324                 namep, err := BytePtrFromString(name)
325                 if err != nil {
326                         return err
327                 }
328                 r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
329         }
330
331         if int32(r0) == -1 {
332                 err = e
333         }
334         return
335 }
336
337 func Fchdir(fd int) (err error) {
338         path, err := Fd2path(fd)
339
340         if err != nil {
341                 return
342         }
343
344         return Chdir(path)
345 }
346
347 type Timespec struct {
348         Sec  int32
349         Nsec int32
350 }
351
352 type Timeval struct {
353         Sec  int32
354         Usec int32
355 }
356
357 func NsecToTimeval(nsec int64) (tv Timeval) {
358         nsec += 999 // round up to microsecond
359         tv.Usec = int32(nsec % 1e9 / 1e3)
360         tv.Sec = int32(nsec / 1e9)
361         return
362 }
363
364 func nsec() int64 {
365         var scratch int64
366
367         r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
368         // TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
369         if r0 == 0 {
370                 return scratch
371         }
372         return int64(r0)
373 }
374
375 func Gettimeofday(tv *Timeval) error {
376         nsec := nsec()
377         *tv = NsecToTimeval(nsec)
378         return nil
379 }
380
381 func Getegid() (egid int) { return -1 }
382 func Geteuid() (euid int) { return -1 }
383 func Getgid() (gid int)   { return -1 }
384 func Getuid() (uid int)   { return -1 }
385
386 func Getgroups() (gids []int, err error) {
387         return make([]int, 0), nil
388 }
389
390 //sys   open(path string, mode int) (fd int, err error)
391
392 func Open(path string, mode int) (fd int, err error) {
393         if fixwd(path) {
394                 defer runtime.UnlockOSThread()
395         }
396         return open(path, mode)
397 }
398
399 //sys   create(path string, mode int, perm uint32) (fd int, err error)
400
401 func Create(path string, mode int, perm uint32) (fd int, err error) {
402         if fixwd(path) {
403                 defer runtime.UnlockOSThread()
404         }
405         return create(path, mode, perm)
406 }
407
408 //sys   remove(path string) (err error)
409
410 func Remove(path string) error {
411         if fixwd(path) {
412                 defer runtime.UnlockOSThread()
413         }
414         return remove(path)
415 }
416
417 //sys   stat(path string, edir []byte) (n int, err error)
418
419 func Stat(path string, edir []byte) (n int, err error) {
420         if fixwd(path) {
421                 defer runtime.UnlockOSThread()
422         }
423         return stat(path, edir)
424 }
425
426 //sys   bind(name string, old string, flag int) (err error)
427
428 func Bind(name string, old string, flag int) (err error) {
429         if fixwd(name, old) {
430                 defer runtime.UnlockOSThread()
431         }
432         return bind(name, old, flag)
433 }
434
435 //sys   mount(fd int, afd int, old string, flag int, aname string) (err error)
436
437 func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
438         if fixwd(old) {
439                 defer runtime.UnlockOSThread()
440         }
441         return mount(fd, afd, old, flag, aname)
442 }
443
444 //sys   wstat(path string, edir []byte) (err error)
445
446 func Wstat(path string, edir []byte) (err error) {
447         if fixwd(path) {
448                 defer runtime.UnlockOSThread()
449         }
450         return wstat(path, edir)
451 }
452
453 //sys   chdir(path string) (err error)
454 //sys   Dup(oldfd int, newfd int) (fd int, err error)
455 //sys   Pread(fd int, p []byte, offset int64) (n int, err error)
456 //sys   Pwrite(fd int, p []byte, offset int64) (n int, err error)
457 //sys   Close(fd int) (err error)
458 //sys   Fstat(fd int, edir []byte) (n int, err error)
459 //sys   Fwstat(fd int, edir []byte) (err error)