syscall_plan9.mx raw

   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)
 460