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
  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] == '@' || (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
 143func 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.
 154func 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
 164const ImplementsGetwd = true
 165
 166//sys	Getcwd(buf []byte) (n int, err error)
 167
 168func 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
 189func 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
 214func 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.
 227func 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
 239type WaitStatus uint32
 240
 241const (
 242	mask  = 0x7F
 243	core  = 0x80
 244	shift = 8
 245
 246	exited  = 0
 247	stopped = 0x7F
 248)
 249
 250func (w WaitStatus) Exited() bool { return w&mask == exited }
 251
 252func (w WaitStatus) ExitStatus() int {
 253	if w&mask != exited {
 254		return -1
 255	}
 256	return int(w >> shift)
 257}
 258
 259func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
 260
 261func (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
 269func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
 270
 271func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP }
 272
 273func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP }
 274
 275func (w WaitStatus) StopSignal() syscall.Signal {
 276	if !w.Stopped() {
 277		return -1
 278	}
 279	return syscall.Signal(w>>shift) & 0xFF
 280}
 281
 282func (w WaitStatus) TrapCause() int { return -1 }
 283
 284//sys	wait4(pid int32, statusp *_C_int, options int, rusage *Rusage) (wpid int32, err error)
 285
 286func 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
 301func 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
 316func 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
 328func 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
 338func 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.
 351func 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.
 361func 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
 371func 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.
 388func 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
 398func 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
 437func 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
 454func 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
 482func 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
 514func 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
 529func 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
 535func Major(dev uint64) uint32 {
 536	return uint32(__major(NEWDEV, dev))
 537}
 538
 539//sys	__minor(version int, dev uint64) (val uint)
 540
 541func 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
 552func ioctl(fd int, req int, arg uintptr) (err error) {
 553	_, err = ioctlRet(fd, req, arg)
 554	return err
 555}
 556
 557func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
 558	_, err = ioctlPtrRet(fd, req, arg)
 559	return err
 560}
 561
 562func IoctlSetTermio(fd int, req int, value *Termio) error {
 563	return ioctlPtr(fd, req, unsafe.Pointer(value))
 564}
 565
 566func 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
 574func 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
 581func 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
 704type fileObjCookie struct {
 705	fobj   *fileObj
 706	cookie interface{}
 707}
 708
 709// EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
 710type 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.
 733type 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).
 744func 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.
 765func (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.
 779func (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.
 787func (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.
 796func (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.
 816func (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.
 840func (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.
 860func (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
 880func 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.
 902func (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
 920func (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.
 958func (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.
 968func (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
1004func 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
1023func 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
1051func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
1052	return ioctlRet(fd, req, uintptr(arg))
1053}
1054
1055func 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
1065func (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
1075func (l *Lifreq) SetLifruInt(d int) {
1076	*(*int)(unsafe.Pointer(&l.Lifru[0])) = d
1077}
1078
1079func (l *Lifreq) GetLifruInt() int {
1080	return *(*int)(unsafe.Pointer(&l.Lifru[0]))
1081}
1082
1083func (l *Lifreq) SetLifruUint(d uint) {
1084	*(*uint)(unsafe.Pointer(&l.Lifru[0])) = d
1085}
1086
1087func (l *Lifreq) GetLifruUint() uint {
1088	return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
1089}
1090
1091func IoctlLifreq(fd int, req int, l *Lifreq) error {
1092	return ioctlPtr(fd, req, unsafe.Pointer(l))
1093}
1094
1095// Strioctl Helpers
1096
1097func (s *Strioctl) SetInt(i int) {
1098	s.Len = int32(unsafe.Sizeof(i))
1099	s.Dp = (*int8)(unsafe.Pointer(&i))
1100}
1101
1102func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {
1103	return ioctlPtrRet(fd, req, unsafe.Pointer(s))
1104}
1105
1106// Ucred Helpers
1107// See ucred(3c) and getpeerucred(3c)
1108
1109//sys	getpeerucred(fd uintptr, ucred *uintptr) (err error)
1110//sys	ucredFree(ucred uintptr) = ucred_free
1111//sys	ucredGet(pid int) (ucred uintptr, err error) = ucred_get
1112//sys	ucredGeteuid(ucred uintptr) (uid int) = ucred_geteuid
1113//sys	ucredGetegid(ucred uintptr) (gid int) = ucred_getegid
1114//sys	ucredGetruid(ucred uintptr) (uid int) = ucred_getruid
1115//sys	ucredGetrgid(ucred uintptr) (gid int) = ucred_getrgid
1116//sys	ucredGetsuid(ucred uintptr) (uid int) = ucred_getsuid
1117//sys	ucredGetsgid(ucred uintptr) (gid int) = ucred_getsgid
1118//sys	ucredGetpid(ucred uintptr) (pid int) = ucred_getpid
1119
1120// Ucred is an opaque struct that holds user credentials.
1121type Ucred struct {
1122	ucred uintptr
1123}
1124
1125// We need to ensure that ucredFree is called on the underlying ucred
1126// when the Ucred is garbage collected.
1127func ucredFinalizer(u *Ucred) {
1128	ucredFree(u.ucred)
1129}
1130
1131func GetPeerUcred(fd uintptr) (*Ucred, error) {
1132	var ucred uintptr
1133	err := getpeerucred(fd, &ucred)
1134	if err != nil {
1135		return nil, err
1136	}
1137	result := &Ucred{
1138		ucred: ucred,
1139	}
1140	// set the finalizer on the result so that the ucred will be freed
1141	runtime.SetFinalizer(result, ucredFinalizer)
1142	return result, nil
1143}
1144
1145func UcredGet(pid int) (*Ucred, error) {
1146	ucred, err := ucredGet(pid)
1147	if err != nil {
1148		return nil, err
1149	}
1150	result := &Ucred{
1151		ucred: ucred,
1152	}
1153	// set the finalizer on the result so that the ucred will be freed
1154	runtime.SetFinalizer(result, ucredFinalizer)
1155	return result, nil
1156}
1157
1158func (u *Ucred) Geteuid() int {
1159	defer runtime.KeepAlive(u)
1160	return ucredGeteuid(u.ucred)
1161}
1162
1163func (u *Ucred) Getruid() int {
1164	defer runtime.KeepAlive(u)
1165	return ucredGetruid(u.ucred)
1166}
1167
1168func (u *Ucred) Getsuid() int {
1169	defer runtime.KeepAlive(u)
1170	return ucredGetsuid(u.ucred)
1171}
1172
1173func (u *Ucred) Getegid() int {
1174	defer runtime.KeepAlive(u)
1175	return ucredGetegid(u.ucred)
1176}
1177
1178func (u *Ucred) Getrgid() int {
1179	defer runtime.KeepAlive(u)
1180	return ucredGetrgid(u.ucred)
1181}
1182
1183func (u *Ucred) Getsgid() int {
1184	defer runtime.KeepAlive(u)
1185	return ucredGetsgid(u.ucred)
1186}
1187
1188func (u *Ucred) Getpid() int {
1189	defer runtime.KeepAlive(u)
1190	return ucredGetpid(u.ucred)
1191}