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