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

View as plain text