Black Lives Matter. Support the Equal Justice Initiative.

Source file src/syscall/syscall_plan9.go

Documentation: syscall

     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  func Fd2path(fd int) (path string, err error) {
   185  	var buf [512]byte
   186  
   187  	e := fd2path(fd, buf[:])
   188  	if e != nil {
   189  		return "", e
   190  	}
   191  	return cstring(buf[:]), nil
   192  }
   193  
   194  //sys	pipe(p *[2]int32) (err error)
   195  func Pipe(p []int) (err error) {
   196  	if len(p) != 2 {
   197  		return NewError("bad arg in system call")
   198  	}
   199  	var pp [2]int32
   200  	err = pipe(&pp)
   201  	p[0] = int(pp[0])
   202  	p[1] = int(pp[1])
   203  	return
   204  }
   205  
   206  // Underlying system call writes to newoffset via pointer.
   207  // Implemented in assembly to avoid allocation.
   208  func seek(placeholder uintptr, fd int, offset int64, whence int) (newoffset int64, err string)
   209  
   210  func Seek(fd int, offset int64, whence int) (newoffset int64, err error) {
   211  	newoffset, e := seek(0, fd, offset, whence)
   212  
   213  	if newoffset == -1 {
   214  		err = NewError(e)
   215  	}
   216  	return
   217  }
   218  
   219  func Mkdir(path string, mode uint32) (err error) {
   220  	// If path exists and is not a directory, Create will fail silently.
   221  	// Work around this by rejecting Mkdir if path exists.
   222  	statbuf := make([]byte, bitSize16)
   223  	// Remove any trailing slashes from path, otherwise the Stat will
   224  	// fail with ENOTDIR.
   225  	n := len(path)
   226  	for n > 1 && path[n-1] == '/' {
   227  		n--
   228  	}
   229  	_, err = Stat(path[0:n], statbuf)
   230  	if err == nil {
   231  		return EEXIST
   232  	}
   233  
   234  	fd, err := Create(path, O_RDONLY, DMDIR|mode)
   235  
   236  	if fd != -1 {
   237  		Close(fd)
   238  	}
   239  
   240  	return
   241  }
   242  
   243  type Waitmsg struct {
   244  	Pid  int
   245  	Time [3]uint32
   246  	Msg  string
   247  }
   248  
   249  func (w Waitmsg) Exited() bool   { return true }
   250  func (w Waitmsg) Signaled() bool { return false }
   251  
   252  func (w Waitmsg) ExitStatus() int {
   253  	if len(w.Msg) == 0 {
   254  		// a normal exit returns no message
   255  		return 0
   256  	}
   257  	return 1
   258  }
   259  
   260  //sys	await(s []byte) (n int, err error)
   261  func Await(w *Waitmsg) (err error) {
   262  	var buf [512]byte
   263  	var f [5][]byte
   264  
   265  	n, err := await(buf[:])
   266  
   267  	if err != nil || w == nil {
   268  		return
   269  	}
   270  
   271  	nf := 0
   272  	p := 0
   273  	for i := 0; i < n && nf < len(f)-1; i++ {
   274  		if buf[i] == ' ' {
   275  			f[nf] = buf[p:i]
   276  			p = i + 1
   277  			nf++
   278  		}
   279  	}
   280  	f[nf] = buf[p:]
   281  	nf++
   282  
   283  	if nf != len(f) {
   284  		return NewError("invalid wait message")
   285  	}
   286  	w.Pid = int(atoi(f[0]))
   287  	w.Time[0] = uint32(atoi(f[1]))
   288  	w.Time[1] = uint32(atoi(f[2]))
   289  	w.Time[2] = uint32(atoi(f[3]))
   290  	w.Msg = cstring(f[4])
   291  	if w.Msg == "''" {
   292  		// await() returns '' for no error
   293  		w.Msg = ""
   294  	}
   295  	return
   296  }
   297  
   298  func Unmount(name, old string) (err error) {
   299  	fixwd(name, old)
   300  	oldp, err := BytePtrFromString(old)
   301  	if err != nil {
   302  		return err
   303  	}
   304  	oldptr := uintptr(unsafe.Pointer(oldp))
   305  
   306  	var r0 uintptr
   307  	var e ErrorString
   308  
   309  	// bind(2) man page: If name is zero, everything bound or mounted upon old is unbound or unmounted.
   310  	if name == "" {
   311  		r0, _, e = Syscall(SYS_UNMOUNT, _zero, oldptr, 0)
   312  	} else {
   313  		namep, err := BytePtrFromString(name)
   314  		if err != nil {
   315  			return err
   316  		}
   317  		r0, _, e = Syscall(SYS_UNMOUNT, uintptr(unsafe.Pointer(namep)), oldptr, 0)
   318  	}
   319  
   320  	if int32(r0) == -1 {
   321  		err = e
   322  	}
   323  	return
   324  }
   325  
   326  func Fchdir(fd int) (err error) {
   327  	path, err := Fd2path(fd)
   328  
   329  	if err != nil {
   330  		return
   331  	}
   332  
   333  	return Chdir(path)
   334  }
   335  
   336  type Timespec struct {
   337  	Sec  int32
   338  	Nsec int32
   339  }
   340  
   341  type Timeval struct {
   342  	Sec  int32
   343  	Usec int32
   344  }
   345  
   346  func NsecToTimeval(nsec int64) (tv Timeval) {
   347  	nsec += 999 // round up to microsecond
   348  	tv.Usec = int32(nsec % 1e9 / 1e3)
   349  	tv.Sec = int32(nsec / 1e9)
   350  	return
   351  }
   352  
   353  func nsec() int64 {
   354  	var scratch int64
   355  
   356  	r0, _, _ := Syscall(SYS_NSEC, uintptr(unsafe.Pointer(&scratch)), 0, 0)
   357  	// TODO(aram): remove hack after I fix _nsec in the pc64 kernel.
   358  	if r0 == 0 {
   359  		return scratch
   360  	}
   361  	return int64(r0)
   362  }
   363  
   364  func Gettimeofday(tv *Timeval) error {
   365  	nsec := nsec()
   366  	*tv = NsecToTimeval(nsec)
   367  	return nil
   368  }
   369  
   370  func Getegid() (egid int) { return -1 }
   371  func Geteuid() (euid int) { return -1 }
   372  func Getgid() (gid int)   { return -1 }
   373  func Getuid() (uid int)   { return -1 }
   374  
   375  func Getgroups() (gids []int, err error) {
   376  	return make([]int, 0), nil
   377  }
   378  
   379  //sys	open(path string, mode int) (fd int, err error)
   380  func Open(path string, mode int) (fd int, err error) {
   381  	fixwd(path)
   382  	return open(path, mode)
   383  }
   384  
   385  //sys	create(path string, mode int, perm uint32) (fd int, err error)
   386  func Create(path string, mode int, perm uint32) (fd int, err error) {
   387  	fixwd(path)
   388  	return create(path, mode, perm)
   389  }
   390  
   391  //sys	remove(path string) (err error)
   392  func Remove(path string) error {
   393  	fixwd(path)
   394  	return remove(path)
   395  }
   396  
   397  //sys	stat(path string, edir []byte) (n int, err error)
   398  func Stat(path string, edir []byte) (n int, err error) {
   399  	fixwd(path)
   400  	return stat(path, edir)
   401  }
   402  
   403  //sys	bind(name string, old string, flag int) (err error)
   404  func Bind(name string, old string, flag int) (err error) {
   405  	fixwd(name, old)
   406  	return bind(name, old, flag)
   407  }
   408  
   409  //sys	mount(fd int, afd int, old string, flag int, aname string) (err error)
   410  func Mount(fd int, afd int, old string, flag int, aname string) (err error) {
   411  	fixwd(old)
   412  	return mount(fd, afd, old, flag, aname)
   413  }
   414  
   415  //sys	wstat(path string, edir []byte) (err error)
   416  func Wstat(path string, edir []byte) (err error) {
   417  	fixwd(path)
   418  	return wstat(path, edir)
   419  }
   420  
   421  //sys	chdir(path string) (err error)
   422  //sys	Dup(oldfd int, newfd int) (fd int, err error)
   423  //sys	Pread(fd int, p []byte, offset int64) (n int, err error)
   424  //sys	Pwrite(fd int, p []byte, offset int64) (n int, err error)
   425  //sys	Close(fd int) (err error)
   426  //sys	Fstat(fd int, edir []byte) (n int, err error)
   427  //sys	Fwstat(fd int, edir []byte) (err error)
   428  

View as plain text