Source file src/cmd/vendor/golang.org/x/sys/unix/syscall_solaris.go

     1  // Copyright 2009 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  // Solaris 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 wrap
    10  // it in our own nicer implementation, either here or in
    11  // syscall_solaris.go or syscall_unix.go.
    12  
    13  package unix
    14  
    15  import (
    16  	"fmt"
    17  	"os"
    18  	"runtime"
    19  	"sync"
    20  	"syscall"
    21  	"unsafe"
    22  )
    23  
    24  // Implemented in runtime/syscall_solaris.go.
    25  type syscallFunc uintptr
    26  
    27  func rawSysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
    28  func sysvicall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err syscall.Errno)
    29  
    30  // SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
    31  type SockaddrDatalink struct {
    32  	Family uint16
    33  	Index  uint16
    34  	Type   uint8
    35  	Nlen   uint8
    36  	Alen   uint8
    37  	Slen   uint8
    38  	Data   [244]int8
    39  	raw    RawSockaddrDatalink
    40  }
    41  
    42  func direntIno(buf []byte) (uint64, bool) {
    43  	return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))
    44  }
    45  
    46  func direntReclen(buf []byte) (uint64, bool) {
    47  	return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))
    48  }
    49  
    50  func direntNamlen(buf []byte) (uint64, bool) {
    51  	reclen, ok := direntReclen(buf)
    52  	if !ok {
    53  		return 0, false
    54  	}
    55  	return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true
    56  }
    57  
    58  //sysnb	pipe(p *[2]_C_int) (n int, err error)
    59  
    60  func Pipe(p []int) (err error) {
    61  	if len(p) != 2 {
    62  		return EINVAL
    63  	}
    64  	var pp [2]_C_int
    65  	n, err := pipe(&pp)
    66  	if n != 0 {
    67  		return err
    68  	}
    69  	if err == nil {
    70  		p[0] = int(pp[0])
    71  		p[1] = int(pp[1])
    72  	}
    73  	return nil
    74  }
    75  
    76  //sysnb	pipe2(p *[2]_C_int, flags int) (err error)
    77  
    78  func Pipe2(p []int, flags int) error {
    79  	if len(p) != 2 {
    80  		return EINVAL
    81  	}
    82  	var pp [2]_C_int
    83  	err := pipe2(&pp, flags)
    84  	if err == nil {
    85  		p[0] = int(pp[0])
    86  		p[1] = int(pp[1])
    87  	}
    88  	return err
    89  }
    90  
    91  func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {
    92  	if sa.Port < 0 || sa.Port > 0xFFFF {
    93  		return nil, 0, EINVAL
    94  	}
    95  	sa.raw.Family = AF_INET
    96  	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
    97  	p[0] = byte(sa.Port >> 8)
    98  	p[1] = byte(sa.Port)
    99  	sa.raw.Addr = sa.Addr
   100  	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
   101  }
   102  
   103  func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {
   104  	if sa.Port < 0 || sa.Port > 0xFFFF {
   105  		return nil, 0, EINVAL
   106  	}
   107  	sa.raw.Family = AF_INET6
   108  	p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))
   109  	p[0] = byte(sa.Port >> 8)
   110  	p[1] = byte(sa.Port)
   111  	sa.raw.Scope_id = sa.ZoneId
   112  	sa.raw.Addr = sa.Addr
   113  	return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil
   114  }
   115  
   116  func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {
   117  	name := sa.Name
   118  	n := len(name)
   119  	if n >= len(sa.raw.Path) {
   120  		return nil, 0, EINVAL
   121  	}
   122  	sa.raw.Family = AF_UNIX
   123  	for i := 0; i < n; i++ {
   124  		sa.raw.Path[i] = int8(name[i])
   125  	}
   126  	// length is family (uint16), name, NUL.
   127  	sl := _Socklen(2)
   128  	if n > 0 {
   129  		sl += _Socklen(n) + 1
   130  	}
   131  	if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) {
   132  		// Check sl > 3 so we don't change unnamed socket behavior.
   133  		sa.raw.Path[0] = 0
   134  		// Don't count trailing NUL for abstract address.
   135  		sl--
   136  	}
   137  
   138  	return unsafe.Pointer(&sa.raw), sl, nil
   139  }
   140  
   141  //sys	getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
   142  
   143  func Getsockname(fd int) (sa Sockaddr, err error) {
   144  	var rsa RawSockaddrAny
   145  	var len _Socklen = SizeofSockaddrAny
   146  	if err = getsockname(fd, &rsa, &len); err != nil {
   147  		return
   148  	}
   149  	return anyToSockaddr(fd, &rsa)
   150  }
   151  
   152  // GetsockoptString returns the string value of the socket option opt for the
   153  // socket associated with fd at the given socket level.
   154  func GetsockoptString(fd, level, opt int) (string, error) {
   155  	buf := make([]byte, 256)
   156  	vallen := _Socklen(len(buf))
   157  	err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
   158  	if err != nil {
   159  		return "", err
   160  	}
   161  	return ByteSliceToString(buf[:vallen]), nil
   162  }
   163  
   164  const ImplementsGetwd = true
   165  
   166  //sys	Getcwd(buf []byte) (n int, err error)
   167  
   168  func Getwd() (wd string, err error) {
   169  	var buf [PathMax]byte
   170  	// Getcwd will return an error if it failed for any reason.
   171  	_, err = Getcwd(buf[0:])
   172  	if err != nil {
   173  		return "", err
   174  	}
   175  	n := clen(buf[:])
   176  	if n < 1 {
   177  		return "", EINVAL
   178  	}
   179  	return string(buf[:n]), nil
   180  }
   181  
   182  /*
   183   * Wrapped
   184   */
   185  
   186  //sysnb	getgroups(ngid int, gid *_Gid_t) (n int, err error)
   187  //sysnb	setgroups(ngid int, gid *_Gid_t) (err error)
   188  
   189  func Getgroups() (gids []int, err error) {
   190  	n, err := getgroups(0, nil)
   191  	// Check for error and sanity check group count. Newer versions of
   192  	// Solaris allow up to 1024 (NGROUPS_MAX).
   193  	if n < 0 || n > 1024 {
   194  		if err != nil {
   195  			return nil, err
   196  		}
   197  		return nil, EINVAL
   198  	} else if n == 0 {
   199  		return nil, nil
   200  	}
   201  
   202  	a := make([]_Gid_t, n)
   203  	n, err = getgroups(n, &a[0])
   204  	if n == -1 {
   205  		return nil, err
   206  	}
   207  	gids = make([]int, n)
   208  	for i, v := range a[0:n] {
   209  		gids[i] = int(v)
   210  	}
   211  	return
   212  }
   213  
   214  func Setgroups(gids []int) (err error) {
   215  	if len(gids) == 0 {
   216  		return setgroups(0, nil)
   217  	}
   218  
   219  	a := make([]_Gid_t, len(gids))
   220  	for i, v := range gids {
   221  		a[i] = _Gid_t(v)
   222  	}
   223  	return setgroups(len(a), &a[0])
   224  }
   225  
   226  // ReadDirent reads directory entries from fd and writes them into buf.
   227  func ReadDirent(fd int, buf []byte) (n int, err error) {
   228  	// Final argument is (basep *uintptr) and the syscall doesn't take nil.
   229  	// TODO(rsc): Can we use a single global basep for all calls?
   230  	return Getdents(fd, buf, new(uintptr))
   231  }
   232  
   233  // Wait status is 7 bits at bottom, either 0 (exited),
   234  // 0x7F (stopped), or a signal number that caused an exit.
   235  // The 0x80 bit is whether there was a core dump.
   236  // An extra number (exit code, signal causing a stop)
   237  // is in the high bits.
   238  
   239  type WaitStatus uint32
   240  
   241  const (
   242  	mask  = 0x7F
   243  	core  = 0x80
   244  	shift = 8
   245  
   246  	exited  = 0
   247  	stopped = 0x7F
   248  )
   249  
   250  func (w WaitStatus) Exited() bool { return w&mask == exited }
   251  
   252  func (w WaitStatus) ExitStatus() int {
   253  	if w&mask != exited {
   254  		return -1
   255  	}
   256  	return int(w >> shift)
   257  }
   258  
   259  func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
   260  
   261  func (w WaitStatus) Signal() syscall.Signal {
   262  	sig := syscall.Signal(w & mask)
   263  	if sig == stopped || sig == 0 {
   264  		return -1
   265  	}
   266  	return sig
   267  }
   268  
   269  func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
   270  
   271  func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP }
   272  
   273  func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP }
   274  
   275  func (w WaitStatus) StopSignal() syscall.Signal {
   276  	if !w.Stopped() {
   277  		return -1
   278  	}
   279  	return syscall.Signal(w>>shift) & 0xFF
   280  }
   281  
   282  func (w WaitStatus) TrapCause() int { return -1 }
   283  
   284  //sys	wait4(pid int32, statusp *_C_int, options int, rusage *Rusage) (wpid int32, err error)
   285  
   286  func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (int, error) {
   287  	var status _C_int
   288  	rpid, err := wait4(int32(pid), &status, options, rusage)
   289  	wpid := int(rpid)
   290  	if wpid == -1 {
   291  		return wpid, err
   292  	}
   293  	if wstatus != nil {
   294  		*wstatus = WaitStatus(status)
   295  	}
   296  	return wpid, nil
   297  }
   298  
   299  //sys	gethostname(buf []byte) (n int, err error)
   300  
   301  func Gethostname() (name string, err error) {
   302  	var buf [MaxHostNameLen]byte
   303  	n, err := gethostname(buf[:])
   304  	if n != 0 {
   305  		return "", err
   306  	}
   307  	n = clen(buf[:])
   308  	if n < 1 {
   309  		return "", EFAULT
   310  	}
   311  	return string(buf[:n]), nil
   312  }
   313  
   314  //sys	utimes(path string, times *[2]Timeval) (err error)
   315  
   316  func Utimes(path string, tv []Timeval) (err error) {
   317  	if tv == nil {
   318  		return utimes(path, nil)
   319  	}
   320  	if len(tv) != 2 {
   321  		return EINVAL
   322  	}
   323  	return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
   324  }
   325  
   326  //sys	utimensat(fd int, path string, times *[2]Timespec, flag int) (err error)
   327  
   328  func UtimesNano(path string, ts []Timespec) error {
   329  	if ts == nil {
   330  		return utimensat(AT_FDCWD, path, nil, 0)
   331  	}
   332  	if len(ts) != 2 {
   333  		return EINVAL
   334  	}
   335  	return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
   336  }
   337  
   338  func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
   339  	if ts == nil {
   340  		return utimensat(dirfd, path, nil, flags)
   341  	}
   342  	if len(ts) != 2 {
   343  		return EINVAL
   344  	}
   345  	return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
   346  }
   347  
   348  //sys	fcntl(fd int, cmd int, arg int) (val int, err error)
   349  
   350  // FcntlInt performs a fcntl syscall on fd with the provided command and argument.
   351  func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
   352  	valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
   353  	var err error
   354  	if errno != 0 {
   355  		err = errno
   356  	}
   357  	return int(valptr), err
   358  }
   359  
   360  // FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
   361  func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
   362  	_, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
   363  	if e1 != 0 {
   364  		return e1
   365  	}
   366  	return nil
   367  }
   368  
   369  //sys	futimesat(fildes int, path *byte, times *[2]Timeval) (err error)
   370  
   371  func Futimesat(dirfd int, path string, tv []Timeval) error {
   372  	pathp, err := BytePtrFromString(path)
   373  	if err != nil {
   374  		return err
   375  	}
   376  	if tv == nil {
   377  		return futimesat(dirfd, pathp, nil)
   378  	}
   379  	if len(tv) != 2 {
   380  		return EINVAL
   381  	}
   382  	return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
   383  }
   384  
   385  // Solaris doesn't have an futimes function because it allows NULL to be
   386  // specified as the path for futimesat. However, Go doesn't like
   387  // NULL-style string interfaces, so this simple wrapper is provided.
   388  func Futimes(fd int, tv []Timeval) error {
   389  	if tv == nil {
   390  		return futimesat(fd, nil, nil)
   391  	}
   392  	if len(tv) != 2 {
   393  		return EINVAL
   394  	}
   395  	return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
   396  }
   397  
   398  func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
   399  	switch rsa.Addr.Family {
   400  	case AF_UNIX:
   401  		pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
   402  		sa := new(SockaddrUnix)
   403  		// Assume path ends at NUL.
   404  		// This is not technically the Solaris semantics for
   405  		// abstract Unix domain sockets -- they are supposed
   406  		// to be uninterpreted fixed-size binary blobs -- but
   407  		// everyone uses this convention.
   408  		n := 0
   409  		for n < len(pp.Path) && pp.Path[n] != 0 {
   410  			n++
   411  		}
   412  		sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
   413  		return sa, nil
   414  
   415  	case AF_INET:
   416  		pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))
   417  		sa := new(SockaddrInet4)
   418  		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
   419  		sa.Port = int(p[0])<<8 + int(p[1])
   420  		sa.Addr = pp.Addr
   421  		return sa, nil
   422  
   423  	case AF_INET6:
   424  		pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))
   425  		sa := new(SockaddrInet6)
   426  		p := (*[2]byte)(unsafe.Pointer(&pp.Port))
   427  		sa.Port = int(p[0])<<8 + int(p[1])
   428  		sa.ZoneId = pp.Scope_id
   429  		sa.Addr = pp.Addr
   430  		return sa, nil
   431  	}
   432  	return nil, EAFNOSUPPORT
   433  }
   434  
   435  //sys	accept(s int, rsa *RawSockaddrAny, addrlen *_Socklen) (fd int, err error) = libsocket.accept
   436  
   437  func Accept(fd int) (nfd int, sa Sockaddr, err error) {
   438  	var rsa RawSockaddrAny
   439  	var len _Socklen = SizeofSockaddrAny
   440  	nfd, err = accept(fd, &rsa, &len)
   441  	if nfd == -1 {
   442  		return
   443  	}
   444  	sa, err = anyToSockaddr(fd, &rsa)
   445  	if err != nil {
   446  		Close(nfd)
   447  		nfd = 0
   448  	}
   449  	return
   450  }
   451  
   452  //sys	recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg
   453  
   454  func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
   455  	var msg Msghdr
   456  	msg.Name = (*byte)(unsafe.Pointer(rsa))
   457  	msg.Namelen = uint32(SizeofSockaddrAny)
   458  	var dummy byte
   459  	if len(oob) > 0 {
   460  		// receive at least one normal byte
   461  		if emptyIovecs(iov) {
   462  			var iova [1]Iovec
   463  			iova[0].Base = &dummy
   464  			iova[0].SetLen(1)
   465  			iov = iova[:]
   466  		}
   467  		msg.Accrightslen = int32(len(oob))
   468  	}
   469  	if len(iov) > 0 {
   470  		msg.Iov = &iov[0]
   471  		msg.SetIovlen(len(iov))
   472  	}
   473  	if n, err = recvmsg(fd, &msg, flags); n == -1 {
   474  		return
   475  	}
   476  	oobn = int(msg.Accrightslen)
   477  	return
   478  }
   479  
   480  //sys	sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
   481  
   482  func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
   483  	var msg Msghdr
   484  	msg.Name = (*byte)(unsafe.Pointer(ptr))
   485  	msg.Namelen = uint32(salen)
   486  	var dummy byte
   487  	var empty bool
   488  	if len(oob) > 0 {
   489  		// send at least one normal byte
   490  		empty = emptyIovecs(iov)
   491  		if empty {
   492  			var iova [1]Iovec
   493  			iova[0].Base = &dummy
   494  			iova[0].SetLen(1)
   495  			iov = iova[:]
   496  		}
   497  		msg.Accrightslen = int32(len(oob))
   498  	}
   499  	if len(iov) > 0 {
   500  		msg.Iov = &iov[0]
   501  		msg.SetIovlen(len(iov))
   502  	}
   503  	if n, err = sendmsg(fd, &msg, flags); err != nil {
   504  		return 0, err
   505  	}
   506  	if len(oob) > 0 && empty {
   507  		n = 0
   508  	}
   509  	return n, nil
   510  }
   511  
   512  //sys	acct(path *byte) (err error)
   513  
   514  func Acct(path string) (err error) {
   515  	if len(path) == 0 {
   516  		// Assume caller wants to disable accounting.
   517  		return acct(nil)
   518  	}
   519  
   520  	pathp, err := BytePtrFromString(path)
   521  	if err != nil {
   522  		return err
   523  	}
   524  	return acct(pathp)
   525  }
   526  
   527  //sys	__makedev(version int, major uint, minor uint) (val uint64)
   528  
   529  func Mkdev(major, minor uint32) uint64 {
   530  	return __makedev(NEWDEV, uint(major), uint(minor))
   531  }
   532  
   533  //sys	__major(version int, dev uint64) (val uint)
   534  
   535  func Major(dev uint64) uint32 {
   536  	return uint32(__major(NEWDEV, dev))
   537  }
   538  
   539  //sys	__minor(version int, dev uint64) (val uint)
   540  
   541  func Minor(dev uint64) uint32 {
   542  	return uint32(__minor(NEWDEV, dev))
   543  }
   544  
   545  /*
   546   * Expose the ioctl function
   547   */
   548  
   549  //sys	ioctlRet(fd int, req int, arg uintptr) (ret int, err error) = libc.ioctl
   550  //sys	ioctlPtrRet(fd int, req int, arg unsafe.Pointer) (ret int, err error) = libc.ioctl
   551  
   552  func ioctl(fd int, req int, arg uintptr) (err error) {
   553  	_, err = ioctlRet(fd, req, arg)
   554  	return err
   555  }
   556  
   557  func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
   558  	_, err = ioctlPtrRet(fd, req, arg)
   559  	return err
   560  }
   561  
   562  func IoctlSetTermio(fd int, req int, value *Termio) error {
   563  	return ioctlPtr(fd, req, unsafe.Pointer(value))
   564  }
   565  
   566  func IoctlGetTermio(fd int, req int) (*Termio, error) {
   567  	var value Termio
   568  	err := ioctlPtr(fd, req, unsafe.Pointer(&value))
   569  	return &value, err
   570  }
   571  
   572  //sys	poll(fds *PollFd, nfds int, timeout int) (n int, err error)
   573  
   574  func Poll(fds []PollFd, timeout int) (n int, err error) {
   575  	if len(fds) == 0 {
   576  		return poll(nil, 0, timeout)
   577  	}
   578  	return poll(&fds[0], len(fds), timeout)
   579  }
   580  
   581  func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
   582  	if raceenabled {
   583  		raceReleaseMerge(unsafe.Pointer(&ioSync))
   584  	}
   585  	return sendfile(outfd, infd, offset, count)
   586  }
   587  
   588  /*
   589   * Exposed directly
   590   */
   591  //sys	Access(path string, mode uint32) (err error)
   592  //sys	Adjtime(delta *Timeval, olddelta *Timeval) (err error)
   593  //sys	Chdir(path string) (err error)
   594  //sys	Chmod(path string, mode uint32) (err error)
   595  //sys	Chown(path string, uid int, gid int) (err error)
   596  //sys	Chroot(path string) (err error)
   597  //sys	ClockGettime(clockid int32, time *Timespec) (err error)
   598  //sys	Close(fd int) (err error)
   599  //sys	Creat(path string, mode uint32) (fd int, err error)
   600  //sys	Dup(fd int) (nfd int, err error)
   601  //sys	Dup2(oldfd int, newfd int) (err error)
   602  //sys	Exit(code int)
   603  //sys	Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
   604  //sys	Fchdir(fd int) (err error)
   605  //sys	Fchmod(fd int, mode uint32) (err error)
   606  //sys	Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
   607  //sys	Fchown(fd int, uid int, gid int) (err error)
   608  //sys	Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
   609  //sys	Fdatasync(fd int) (err error)
   610  //sys	Flock(fd int, how int) (err error)
   611  //sys	Fpathconf(fd int, name int) (val int, err error)
   612  //sys	Fstat(fd int, stat *Stat_t) (err error)
   613  //sys	Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
   614  //sys	Fstatvfs(fd int, vfsstat *Statvfs_t) (err error)
   615  //sys	Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
   616  //sysnb	Getgid() (gid int)
   617  //sysnb	Getpid() (pid int)
   618  //sysnb	Getpgid(pid int) (pgid int, err error)
   619  //sysnb	Getpgrp() (pgid int, err error)
   620  //sys	Geteuid() (euid int)
   621  //sys	Getegid() (egid int)
   622  //sys	Getppid() (ppid int)
   623  //sys	Getpriority(which int, who int) (n int, err error)
   624  //sysnb	Getrlimit(which int, lim *Rlimit) (err error)
   625  //sysnb	Getrusage(who int, rusage *Rusage) (err error)
   626  //sysnb	Getsid(pid int) (sid int, err error)
   627  //sysnb	Gettimeofday(tv *Timeval) (err error)
   628  //sysnb	Getuid() (uid int)
   629  //sys	Kill(pid int, signum syscall.Signal) (err error)
   630  //sys	Lchown(path string, uid int, gid int) (err error)
   631  //sys	Link(path string, link string) (err error)
   632  //sys	Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten
   633  //sys	Lstat(path string, stat *Stat_t) (err error)
   634  //sys	Madvise(b []byte, advice int) (err error)
   635  //sys	Mkdir(path string, mode uint32) (err error)
   636  //sys	Mkdirat(dirfd int, path string, mode uint32) (err error)
   637  //sys	Mkfifo(path string, mode uint32) (err error)
   638  //sys	Mkfifoat(dirfd int, path string, mode uint32) (err error)
   639  //sys	Mknod(path string, mode uint32, dev int) (err error)
   640  //sys	Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
   641  //sys	Mlock(b []byte) (err error)
   642  //sys	Mlockall(flags int) (err error)
   643  //sys	Mprotect(b []byte, prot int) (err error)
   644  //sys	Msync(b []byte, flags int) (err error)
   645  //sys	Munlock(b []byte) (err error)
   646  //sys	Munlockall() (err error)
   647  //sys	Nanosleep(time *Timespec, leftover *Timespec) (err error)
   648  //sys	Open(path string, mode int, perm uint32) (fd int, err error)
   649  //sys	Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
   650  //sys	Pathconf(path string, name int) (val int, err error)
   651  //sys	Pause() (err error)
   652  //sys	pread(fd int, p []byte, offset int64) (n int, err error)
   653  //sys	pwrite(fd int, p []byte, offset int64) (n int, err error)
   654  //sys	read(fd int, p []byte) (n int, err error)
   655  //sys	Readlink(path string, buf []byte) (n int, err error)
   656  //sys	Rename(from string, to string) (err error)
   657  //sys	Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
   658  //sys	Rmdir(path string) (err error)
   659  //sys	Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
   660  //sys	Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
   661  //sysnb	Setegid(egid int) (err error)
   662  //sysnb	Seteuid(euid int) (err error)
   663  //sysnb	Setgid(gid int) (err error)
   664  //sys	Sethostname(p []byte) (err error)
   665  //sysnb	Setpgid(pid int, pgid int) (err error)
   666  //sys	Setpriority(which int, who int, prio int) (err error)
   667  //sysnb	Setregid(rgid int, egid int) (err error)
   668  //sysnb	Setreuid(ruid int, euid int) (err error)
   669  //sysnb	Setsid() (pid int, err error)
   670  //sysnb	Setuid(uid int) (err error)
   671  //sys	Shutdown(s int, how int) (err error) = libsocket.shutdown
   672  //sys	Stat(path string, stat *Stat_t) (err error)
   673  //sys	Statvfs(path string, vfsstat *Statvfs_t) (err error)
   674  //sys	Symlink(path string, link string) (err error)
   675  //sys	Sync() (err error)
   676  //sys	Sysconf(which int) (n int64, err error)
   677  //sysnb	Times(tms *Tms) (ticks uintptr, err error)
   678  //sys	Truncate(path string, length int64) (err error)
   679  //sys	Fsync(fd int) (err error)
   680  //sys	Ftruncate(fd int, length int64) (err error)
   681  //sys	Umask(mask int) (oldmask int)
   682  //sysnb	Uname(buf *Utsname) (err error)
   683  //sys	Unmount(target string, flags int) (err error) = libc.umount
   684  //sys	Unlink(path string) (err error)
   685  //sys	Unlinkat(dirfd int, path string, flags int) (err error)
   686  //sys	Ustat(dev int, ubuf *Ustat_t) (err error)
   687  //sys	Utime(path string, buf *Utimbuf) (err error)
   688  //sys	bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_bind
   689  //sys	connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
   690  //sys	mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
   691  //sys	munmap(addr uintptr, length uintptr) (err error)
   692  //sys	sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
   693  //sys	sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
   694  //sys	socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
   695  //sysnb	socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
   696  //sys	write(fd int, p []byte) (n int, err error)
   697  //sys	getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.__xnet_getsockopt
   698  //sysnb	getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
   699  //sys	setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
   700  //sys	recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
   701  
   702  // Event Ports
   703  
   704  type fileObjCookie struct {
   705  	fobj   *fileObj
   706  	cookie interface{}
   707  }
   708  
   709  // EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
   710  type EventPort struct {
   711  	port  int
   712  	mu    sync.Mutex
   713  	fds   map[uintptr]*fileObjCookie
   714  	paths map[string]*fileObjCookie
   715  	// The user cookie presents an interesting challenge from a memory management perspective.
   716  	// There are two paths by which we can discover that it is no longer in use:
   717  	// 1. The user calls port_dissociate before any events fire
   718  	// 2. An event fires and we return it to the user
   719  	// The tricky situation is if the event has fired in the kernel but
   720  	// the user hasn't requested/received it yet.
   721  	// If the user wants to port_dissociate before the event has been processed,
   722  	// we should handle things gracefully. To do so, we need to keep an extra
   723  	// reference to the cookie around until the event is processed
   724  	// thus the otherwise seemingly extraneous "cookies" map
   725  	// The key of this map is a pointer to the corresponding fCookie
   726  	cookies map[*fileObjCookie]struct{}
   727  }
   728  
   729  // PortEvent is an abstraction of the port_event C struct.
   730  // Compare Source against PORT_SOURCE_FILE or PORT_SOURCE_FD
   731  // to see if Path or Fd was the event source. The other will be
   732  // uninitialized.
   733  type PortEvent struct {
   734  	Cookie interface{}
   735  	Events int32
   736  	Fd     uintptr
   737  	Path   string
   738  	Source uint16
   739  	fobj   *fileObj
   740  }
   741  
   742  // NewEventPort creates a new EventPort including the
   743  // underlying call to port_create(3c).
   744  func NewEventPort() (*EventPort, error) {
   745  	port, err := port_create()
   746  	if err != nil {
   747  		return nil, err
   748  	}
   749  	e := &EventPort{
   750  		port:    port,
   751  		fds:     make(map[uintptr]*fileObjCookie),
   752  		paths:   make(map[string]*fileObjCookie),
   753  		cookies: make(map[*fileObjCookie]struct{}),
   754  	}
   755  	return e, nil
   756  }
   757  
   758  //sys	port_create() (n int, err error)
   759  //sys	port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error)
   760  //sys	port_dissociate(port int, source int, object uintptr) (n int, err error)
   761  //sys	port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error)
   762  //sys	port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error)
   763  
   764  // Close closes the event port.
   765  func (e *EventPort) Close() error {
   766  	e.mu.Lock()
   767  	defer e.mu.Unlock()
   768  	err := Close(e.port)
   769  	if err != nil {
   770  		return err
   771  	}
   772  	e.fds = nil
   773  	e.paths = nil
   774  	e.cookies = nil
   775  	return nil
   776  }
   777  
   778  // PathIsWatched checks to see if path is associated with this EventPort.
   779  func (e *EventPort) PathIsWatched(path string) bool {
   780  	e.mu.Lock()
   781  	defer e.mu.Unlock()
   782  	_, found := e.paths[path]
   783  	return found
   784  }
   785  
   786  // FdIsWatched checks to see if fd is associated with this EventPort.
   787  func (e *EventPort) FdIsWatched(fd uintptr) bool {
   788  	e.mu.Lock()
   789  	defer e.mu.Unlock()
   790  	_, found := e.fds[fd]
   791  	return found
   792  }
   793  
   794  // AssociatePath wraps port_associate(3c) for a filesystem path including
   795  // creating the necessary file_obj from the provided stat information.
   796  func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, cookie interface{}) error {
   797  	e.mu.Lock()
   798  	defer e.mu.Unlock()
   799  	if _, found := e.paths[path]; found {
   800  		return fmt.Errorf("%v is already associated with this Event Port", path)
   801  	}
   802  	fCookie, err := createFileObjCookie(path, stat, cookie)
   803  	if err != nil {
   804  		return err
   805  	}
   806  	_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fCookie.fobj)), events, (*byte)(unsafe.Pointer(fCookie)))
   807  	if err != nil {
   808  		return err
   809  	}
   810  	e.paths[path] = fCookie
   811  	e.cookies[fCookie] = struct{}{}
   812  	return nil
   813  }
   814  
   815  // DissociatePath wraps port_dissociate(3c) for a filesystem path.
   816  func (e *EventPort) DissociatePath(path string) error {
   817  	e.mu.Lock()
   818  	defer e.mu.Unlock()
   819  	f, ok := e.paths[path]
   820  	if !ok {
   821  		return fmt.Errorf("%v is not associated with this Event Port", path)
   822  	}
   823  	_, err := port_dissociate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f.fobj)))
   824  	// If the path is no longer associated with this event port (ENOENT)
   825  	// we should delete it from our map. We can still return ENOENT to the caller.
   826  	// But we need to save the cookie
   827  	if err != nil && err != ENOENT {
   828  		return err
   829  	}
   830  	if err == nil {
   831  		// dissociate was successful, safe to delete the cookie
   832  		fCookie := e.paths[path]
   833  		delete(e.cookies, fCookie)
   834  	}
   835  	delete(e.paths, path)
   836  	return err
   837  }
   838  
   839  // AssociateFd wraps calls to port_associate(3c) on file descriptors.
   840  func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error {
   841  	e.mu.Lock()
   842  	defer e.mu.Unlock()
   843  	if _, found := e.fds[fd]; found {
   844  		return fmt.Errorf("%v is already associated with this Event Port", fd)
   845  	}
   846  	fCookie, err := createFileObjCookie("", nil, cookie)
   847  	if err != nil {
   848  		return err
   849  	}
   850  	_, err = port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(fCookie)))
   851  	if err != nil {
   852  		return err
   853  	}
   854  	e.fds[fd] = fCookie
   855  	e.cookies[fCookie] = struct{}{}
   856  	return nil
   857  }
   858  
   859  // DissociateFd wraps calls to port_dissociate(3c) on file descriptors.
   860  func (e *EventPort) DissociateFd(fd uintptr) error {
   861  	e.mu.Lock()
   862  	defer e.mu.Unlock()
   863  	_, ok := e.fds[fd]
   864  	if !ok {
   865  		return fmt.Errorf("%v is not associated with this Event Port", fd)
   866  	}
   867  	_, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)
   868  	if err != nil && err != ENOENT {
   869  		return err
   870  	}
   871  	if err == nil {
   872  		// dissociate was successful, safe to delete the cookie
   873  		fCookie := e.fds[fd]
   874  		delete(e.cookies, fCookie)
   875  	}
   876  	delete(e.fds, fd)
   877  	return err
   878  }
   879  
   880  func createFileObjCookie(name string, stat os.FileInfo, cookie interface{}) (*fileObjCookie, error) {
   881  	fCookie := new(fileObjCookie)
   882  	fCookie.cookie = cookie
   883  	if name != "" && stat != nil {
   884  		fCookie.fobj = new(fileObj)
   885  		bs, err := ByteSliceFromString(name)
   886  		if err != nil {
   887  			return nil, err
   888  		}
   889  		fCookie.fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
   890  		s := stat.Sys().(*syscall.Stat_t)
   891  		fCookie.fobj.Atim.Sec = s.Atim.Sec
   892  		fCookie.fobj.Atim.Nsec = s.Atim.Nsec
   893  		fCookie.fobj.Mtim.Sec = s.Mtim.Sec
   894  		fCookie.fobj.Mtim.Nsec = s.Mtim.Nsec
   895  		fCookie.fobj.Ctim.Sec = s.Ctim.Sec
   896  		fCookie.fobj.Ctim.Nsec = s.Ctim.Nsec
   897  	}
   898  	return fCookie, nil
   899  }
   900  
   901  // GetOne wraps port_get(3c) and returns a single PortEvent.
   902  func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
   903  	pe := new(portEvent)
   904  	_, err := port_get(e.port, pe, t)
   905  	if err != nil {
   906  		return nil, err
   907  	}
   908  	p := new(PortEvent)
   909  	e.mu.Lock()
   910  	defer e.mu.Unlock()
   911  	err = e.peIntToExt(pe, p)
   912  	if err != nil {
   913  		return nil, err
   914  	}
   915  	return p, nil
   916  }
   917  
   918  // peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
   919  // NOTE: Always call this function while holding the e.mu mutex
   920  func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) error {
   921  	if e.cookies == nil {
   922  		return fmt.Errorf("this EventPort is already closed")
   923  	}
   924  	peExt.Events = peInt.Events
   925  	peExt.Source = peInt.Source
   926  	fCookie := (*fileObjCookie)(unsafe.Pointer(peInt.User))
   927  	_, found := e.cookies[fCookie]
   928  
   929  	if !found {
   930  		panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")
   931  	}
   932  	peExt.Cookie = fCookie.cookie
   933  	delete(e.cookies, fCookie)
   934  
   935  	switch peInt.Source {
   936  	case PORT_SOURCE_FD:
   937  		peExt.Fd = uintptr(peInt.Object)
   938  		// Only remove the fds entry if it exists and this cookie matches
   939  		if fobj, ok := e.fds[peExt.Fd]; ok {
   940  			if fobj == fCookie {
   941  				delete(e.fds, peExt.Fd)
   942  			}
   943  		}
   944  	case PORT_SOURCE_FILE:
   945  		peExt.fobj = fCookie.fobj
   946  		peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
   947  		// Only remove the paths entry if it exists and this cookie matches
   948  		if fobj, ok := e.paths[peExt.Path]; ok {
   949  			if fobj == fCookie {
   950  				delete(e.paths, peExt.Path)
   951  			}
   952  		}
   953  	}
   954  	return nil
   955  }
   956  
   957  // Pending wraps port_getn(3c) and returns how many events are pending.
   958  func (e *EventPort) Pending() (int, error) {
   959  	var n uint32 = 0
   960  	_, err := port_getn(e.port, nil, 0, &n, nil)
   961  	return int(n), err
   962  }
   963  
   964  // Get wraps port_getn(3c) and fills a slice of PortEvent.
   965  // It will block until either min events have been received
   966  // or the timeout has been exceeded. It will return how many
   967  // events were actually received along with any error information.
   968  func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error) {
   969  	if min == 0 {
   970  		return 0, fmt.Errorf("need to request at least one event or use Pending() instead")
   971  	}
   972  	if len(s) < min {
   973  		return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min)
   974  	}
   975  	got := uint32(min)
   976  	max := uint32(len(s))
   977  	var err error
   978  	ps := make([]portEvent, max)
   979  	_, err = port_getn(e.port, &ps[0], max, &got, timeout)
   980  	// got will be trustworthy with ETIME, but not any other error.
   981  	if err != nil && err != ETIME {
   982  		return 0, err
   983  	}
   984  	e.mu.Lock()
   985  	defer e.mu.Unlock()
   986  	valid := 0
   987  	for i := 0; i < int(got); i++ {
   988  		err2 := e.peIntToExt(&ps[i], &s[i])
   989  		if err2 != nil {
   990  			if valid == 0 && err == nil {
   991  				// If err2 is the only error and there are no valid events
   992  				// to return, return it to the caller.
   993  				err = err2
   994  			}
   995  			break
   996  		}
   997  		valid = i + 1
   998  	}
   999  	return valid, err
  1000  }
  1001  
  1002  //sys	putmsg(fd int, clptr *strbuf, dataptr *strbuf, flags int) (err error)
  1003  
  1004  func Putmsg(fd int, cl []byte, data []byte, flags int) (err error) {
  1005  	var clp, datap *strbuf
  1006  	if len(cl) > 0 {
  1007  		clp = &strbuf{
  1008  			Len: int32(len(cl)),
  1009  			Buf: (*int8)(unsafe.Pointer(&cl[0])),
  1010  		}
  1011  	}
  1012  	if len(data) > 0 {
  1013  		datap = &strbuf{
  1014  			Len: int32(len(data)),
  1015  			Buf: (*int8)(unsafe.Pointer(&data[0])),
  1016  		}
  1017  	}
  1018  	return putmsg(fd, clp, datap, flags)
  1019  }
  1020  
  1021  //sys	getmsg(fd int, clptr *strbuf, dataptr *strbuf, flags *int) (err error)
  1022  
  1023  func Getmsg(fd int, cl []byte, data []byte) (retCl []byte, retData []byte, flags int, err error) {
  1024  	var clp, datap *strbuf
  1025  	if len(cl) > 0 {
  1026  		clp = &strbuf{
  1027  			Maxlen: int32(len(cl)),
  1028  			Buf:    (*int8)(unsafe.Pointer(&cl[0])),
  1029  		}
  1030  	}
  1031  	if len(data) > 0 {
  1032  		datap = &strbuf{
  1033  			Maxlen: int32(len(data)),
  1034  			Buf:    (*int8)(unsafe.Pointer(&data[0])),
  1035  		}
  1036  	}
  1037  
  1038  	if err = getmsg(fd, clp, datap, &flags); err != nil {
  1039  		return nil, nil, 0, err
  1040  	}
  1041  
  1042  	if len(cl) > 0 {
  1043  		retCl = cl[:clp.Len]
  1044  	}
  1045  	if len(data) > 0 {
  1046  		retData = data[:datap.Len]
  1047  	}
  1048  	return retCl, retData, flags, nil
  1049  }
  1050  
  1051  func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
  1052  	return ioctlRet(fd, req, uintptr(arg))
  1053  }
  1054  
  1055  func IoctlSetString(fd int, req int, val string) error {
  1056  	bs := make([]byte, len(val)+1)
  1057  	copy(bs[:len(bs)-1], val)
  1058  	err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
  1059  	runtime.KeepAlive(&bs[0])
  1060  	return err
  1061  }
  1062  
  1063  // Lifreq Helpers
  1064  
  1065  func (l *Lifreq) SetName(name string) error {
  1066  	if len(name) >= len(l.Name) {
  1067  		return fmt.Errorf("name cannot be more than %d characters", len(l.Name)-1)
  1068  	}
  1069  	for i := range name {
  1070  		l.Name[i] = int8(name[i])
  1071  	}
  1072  	return nil
  1073  }
  1074  
  1075  func (l *Lifreq) SetLifruInt(d int) {
  1076  	*(*int)(unsafe.Pointer(&l.Lifru[0])) = d
  1077  }
  1078  
  1079  func (l *Lifreq) GetLifruInt() int {
  1080  	return *(*int)(unsafe.Pointer(&l.Lifru[0]))
  1081  }
  1082  
  1083  func (l *Lifreq) SetLifruUint(d uint) {
  1084  	*(*uint)(unsafe.Pointer(&l.Lifru[0])) = d
  1085  }
  1086  
  1087  func (l *Lifreq) GetLifruUint() uint {
  1088  	return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
  1089  }
  1090  
  1091  func IoctlLifreq(fd int, req int, l *Lifreq) error {
  1092  	return ioctlPtr(fd, req, unsafe.Pointer(l))
  1093  }
  1094  
  1095  // Strioctl Helpers
  1096  
  1097  func (s *Strioctl) SetInt(i int) {
  1098  	s.Len = int32(unsafe.Sizeof(i))
  1099  	s.Dp = (*int8)(unsafe.Pointer(&i))
  1100  }
  1101  
  1102  func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {
  1103  	return ioctlPtrRet(fd, req, unsafe.Pointer(s))
  1104  }
  1105  

View as plain text