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

View as plain text