...

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