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

View as plain text