cubefs
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 unix14
15import (16"fmt"17"os"18"runtime"19"sync"20"syscall"21"unsafe"22)
23
24// Implemented in runtime/syscall_solaris.go.
25type syscallFunc uintptr26
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 {32Family uint1633Index uint1634Type uint835Nlen uint836Alen uint837Slen uint838Data [244]int839raw RawSockaddrDatalink
40}
41
42func direntIno(buf []byte) (uint64, bool) {43return readInt(buf, unsafe.Offsetof(Dirent{}.Ino), unsafe.Sizeof(Dirent{}.Ino))44}
45
46func direntReclen(buf []byte) (uint64, bool) {47return readInt(buf, unsafe.Offsetof(Dirent{}.Reclen), unsafe.Sizeof(Dirent{}.Reclen))48}
49
50func direntNamlen(buf []byte) (uint64, bool) {51reclen, ok := direntReclen(buf)52if !ok {53return 0, false54}55return reclen - uint64(unsafe.Offsetof(Dirent{}.Name)), true56}
57
58//sysnb pipe(p *[2]_C_int) (n int, err error)
59
60func Pipe(p []int) (err error) {61if len(p) != 2 {62return EINVAL63}64var pp [2]_C_int65n, err := pipe(&pp)66if n != 0 {67return err68}69if err == nil {70p[0] = int(pp[0])71p[1] = int(pp[1])72}73return nil74}
75
76//sysnb pipe2(p *[2]_C_int, flags int) (err error)
77
78func Pipe2(p []int, flags int) error {79if len(p) != 2 {80return EINVAL81}82var pp [2]_C_int83err := pipe2(&pp, flags)84if err == nil {85p[0] = int(pp[0])86p[1] = int(pp[1])87}88return err89}
90
91func (sa *SockaddrInet4) sockaddr() (unsafe.Pointer, _Socklen, error) {92if sa.Port < 0 || sa.Port > 0xFFFF {93return nil, 0, EINVAL94}95sa.raw.Family = AF_INET96p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))97p[0] = byte(sa.Port >> 8)98p[1] = byte(sa.Port)99sa.raw.Addr = sa.Addr100return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil101}
102
103func (sa *SockaddrInet6) sockaddr() (unsafe.Pointer, _Socklen, error) {104if sa.Port < 0 || sa.Port > 0xFFFF {105return nil, 0, EINVAL106}107sa.raw.Family = AF_INET6108p := (*[2]byte)(unsafe.Pointer(&sa.raw.Port))109p[0] = byte(sa.Port >> 8)110p[1] = byte(sa.Port)111sa.raw.Scope_id = sa.ZoneId112sa.raw.Addr = sa.Addr113return unsafe.Pointer(&sa.raw), SizeofSockaddrInet6, nil114}
115
116func (sa *SockaddrUnix) sockaddr() (unsafe.Pointer, _Socklen, error) {117name := sa.Name118n := len(name)119if n >= len(sa.raw.Path) {120return nil, 0, EINVAL121}122sa.raw.Family = AF_UNIX123for i := 0; i < n; i++ {124sa.raw.Path[i] = int8(name[i])125}126// length is family (uint16), name, NUL.127sl := _Socklen(2)128if n > 0 {129sl += _Socklen(n) + 1130}131if sa.raw.Path[0] == '@' {132sa.raw.Path[0] = 0133// Don't count trailing NUL for abstract address.134sl--135}136
137return unsafe.Pointer(&sa.raw), sl, nil138}
139
140//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
141
142func Getsockname(fd int) (sa Sockaddr, err error) {143var rsa RawSockaddrAny144var len _Socklen = SizeofSockaddrAny145if err = getsockname(fd, &rsa, &len); err != nil {146return147}148return 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) {154buf := make([]byte, 256)155vallen := _Socklen(len(buf))156err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)157if err != nil {158return "", err159}160return string(buf[:vallen-1]), nil161}
162
163const ImplementsGetwd = true164
165//sys Getcwd(buf []byte) (n int, err error)
166
167func Getwd() (wd string, err error) {168var buf [PathMax]byte169// Getcwd will return an error if it failed for any reason.170_, err = Getcwd(buf[0:])171if err != nil {172return "", err173}174n := clen(buf[:])175if n < 1 {176return "", EINVAL177}178return string(buf[:n]), nil179}
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) {189n, err := getgroups(0, nil)190// Check for error and sanity check group count. Newer versions of191// Solaris allow up to 1024 (NGROUPS_MAX).192if n < 0 || n > 1024 {193if err != nil {194return nil, err195}196return nil, EINVAL197} else if n == 0 {198return nil, nil199}200
201a := make([]_Gid_t, n)202n, err = getgroups(n, &a[0])203if n == -1 {204return nil, err205}206gids = make([]int, n)207for i, v := range a[0:n] {208gids[i] = int(v)209}210return211}
212
213func Setgroups(gids []int) (err error) {214if len(gids) == 0 {215return setgroups(0, nil)216}217
218a := make([]_Gid_t, len(gids))219for i, v := range gids {220a[i] = _Gid_t(v)221}222return 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?229return 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 uint32239
240const (241mask = 0x7F242core = 0x80243shift = 8244
245exited = 0246stopped = 0x7F247)
248
249func (w WaitStatus) Exited() bool { return w&mask == exited }250
251func (w WaitStatus) ExitStatus() int {252if w&mask != exited {253return -1254}255return int(w >> shift)256}
257
258func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }259
260func (w WaitStatus) Signal() syscall.Signal {261sig := syscall.Signal(w & mask)262if sig == stopped || sig == 0 {263return -1264}265return sig266}
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 {275if !w.Stopped() {276return -1277}278return syscall.Signal(w>>shift) & 0xFF279}
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) {286var status _C_int287rpid, err := wait4(int32(pid), &status, options, rusage)288wpid := int(rpid)289if wpid == -1 {290return wpid, err291}292if wstatus != nil {293*wstatus = WaitStatus(status)294}295return wpid, nil296}
297
298//sys gethostname(buf []byte) (n int, err error)
299
300func Gethostname() (name string, err error) {301var buf [MaxHostNameLen]byte302n, err := gethostname(buf[:])303if n != 0 {304return "", err305}306n = clen(buf[:])307if n < 1 {308return "", EFAULT309}310return string(buf[:n]), nil311}
312
313//sys utimes(path string, times *[2]Timeval) (err error)
314
315func Utimes(path string, tv []Timeval) (err error) {316if tv == nil {317return utimes(path, nil)318}319if len(tv) != 2 {320return EINVAL321}322return 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 {328if ts == nil {329return utimensat(AT_FDCWD, path, nil, 0)330}331if len(ts) != 2 {332return EINVAL333}334return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)335}
336
337func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {338if ts == nil {339return utimensat(dirfd, path, nil, flags)340}341if len(ts) != 2 {342return EINVAL343}344return 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) {351valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)352var err error353if errno != 0 {354err = errno355}356return int(valptr), err357}
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)362if e1 != 0 {363return e1364}365return nil366}
367
368//sys futimesat(fildes int, path *byte, times *[2]Timeval) (err error)
369
370func Futimesat(dirfd int, path string, tv []Timeval) error {371pathp, err := BytePtrFromString(path)372if err != nil {373return err374}375if tv == nil {376return futimesat(dirfd, pathp, nil)377}378if len(tv) != 2 {379return EINVAL380}381return 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 {388if tv == nil {389return futimesat(fd, nil, nil)390}391if len(tv) != 2 {392return EINVAL393}394return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))395}
396
397func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {398switch rsa.Addr.Family {399case AF_UNIX:400pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))401sa := new(SockaddrUnix)402// Assume path ends at NUL.403// This is not technically the Solaris semantics for404// abstract Unix domain sockets -- they are supposed405// to be uninterpreted fixed-size binary blobs -- but406// everyone uses this convention.407n := 0408for n < len(pp.Path) && pp.Path[n] != 0 {409n++410}411sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))412return sa, nil413
414case AF_INET:415pp := (*RawSockaddrInet4)(unsafe.Pointer(rsa))416sa := new(SockaddrInet4)417p := (*[2]byte)(unsafe.Pointer(&pp.Port))418sa.Port = int(p[0])<<8 + int(p[1])419sa.Addr = pp.Addr420return sa, nil421
422case AF_INET6:423pp := (*RawSockaddrInet6)(unsafe.Pointer(rsa))424sa := new(SockaddrInet6)425p := (*[2]byte)(unsafe.Pointer(&pp.Port))426sa.Port = int(p[0])<<8 + int(p[1])427sa.ZoneId = pp.Scope_id428sa.Addr = pp.Addr429return sa, nil430}431return nil, EAFNOSUPPORT432}
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) {437var rsa RawSockaddrAny438var len _Socklen = SizeofSockaddrAny439nfd, err = accept(fd, &rsa, &len)440if nfd == -1 {441return442}443sa, err = anyToSockaddr(fd, &rsa)444if err != nil {445Close(nfd)446nfd = 0447}448return449}
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) {454var msg Msghdr455msg.Name = (*byte)(unsafe.Pointer(rsa))456msg.Namelen = uint32(SizeofSockaddrAny)457var dummy byte458if len(oob) > 0 {459// receive at least one normal byte460if emptyIovecs(iov) {461var iova [1]Iovec462iova[0].Base = &dummy463iova[0].SetLen(1)464iov = iova[:]465}466msg.Accrightslen = int32(len(oob))467}468if len(iov) > 0 {469msg.Iov = &iov[0]470msg.SetIovlen(len(iov))471}472if n, err = recvmsg(fd, &msg, flags); n == -1 {473return474}475oobn = int(msg.Accrightslen)476return477}
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) {482var msg Msghdr483msg.Name = (*byte)(unsafe.Pointer(ptr))484msg.Namelen = uint32(salen)485var dummy byte486var empty bool487if len(oob) > 0 {488// send at least one normal byte489empty = emptyIovecs(iov)490if empty {491var iova [1]Iovec492iova[0].Base = &dummy493iova[0].SetLen(1)494iov = iova[:]495}496msg.Accrightslen = int32(len(oob))497}498if len(iov) > 0 {499msg.Iov = &iov[0]500msg.SetIovlen(len(iov))501}502if n, err = sendmsg(fd, &msg, flags); err != nil {503return 0, err504}505if len(oob) > 0 && empty {506n = 0507}508return n, nil509}
510
511//sys acct(path *byte) (err error)
512
513func Acct(path string) (err error) {514if len(path) == 0 {515// Assume caller wants to disable accounting.516return acct(nil)517}518
519pathp, err := BytePtrFromString(path)520if err != nil {521return err522}523return acct(pathp)524}
525
526//sys __makedev(version int, major uint, minor uint) (val uint64)
527
528func Mkdev(major, minor uint32) uint64 {529return __makedev(NEWDEV, uint(major), uint(minor))530}
531
532//sys __major(version int, dev uint64) (val uint)
533
534func Major(dev uint64) uint32 {535return uint32(__major(NEWDEV, dev))536}
537
538//sys __minor(version int, dev uint64) (val uint)
539
540func Minor(dev uint64) uint32 {541return 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)553return err554}
555
556func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {557_, err = ioctlPtrRet(fd, req, arg)558return err559}
560
561func IoctlSetTermio(fd int, req int, value *Termio) error {562return ioctlPtr(fd, req, unsafe.Pointer(value))563}
564
565func IoctlGetTermio(fd int, req int) (*Termio, error) {566var value Termio567err := ioctlPtr(fd, req, unsafe.Pointer(&value))568return &value, err569}
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) {574if len(fds) == 0 {575return poll(nil, 0, timeout)576}577return poll(&fds[0], len(fds), timeout)578}
579
580func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {581if raceenabled {582raceReleaseMerge(unsafe.Pointer(&ioSync))583}584return 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) {702r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procread)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)703n = int(r0)704if e1 != 0 {705err = e1706}707return708}
709
710func writelen(fd int, buf *byte, nbuf int) (n int, err error) {711r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procwrite)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)712n = int(r0)713if e1 != 0 {714err = e1715}716return717}
718
719var mapper = &mmapper{720active: make(map[*byte][]byte),721mmap: mmap,722munmap: munmap,723}
724
725func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {726return mapper.Mmap(fd, offset, length, prot, flags)727}
728
729func Munmap(b []byte) (err error) {730return mapper.Munmap(b)731}
732
733// Event Ports
734
735type fileObjCookie struct {736fobj *fileObj737cookie interface{}738}
739
740// EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
741type EventPort struct {742port int743mu sync.Mutex744fds map[uintptr]*fileObjCookie745paths map[string]*fileObjCookie746// 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 fire749// 2. An event fires and we return it to the user750// The tricky situation is if the event has fired in the kernel but751// 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 extra754// reference to the cookie around until the event is processed755// thus the otherwise seemingly extraneous "cookies" map756// The key of this map is a pointer to the corresponding fCookie757cookies 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 {765Cookie interface{}766Events int32767Fd uintptr768Path string769Source uint16770fobj *fileObj771}
772
773// NewEventPort creates a new EventPort including the
774// underlying call to port_create(3c).
775func NewEventPort() (*EventPort, error) {776port, err := port_create()777if err != nil {778return nil, err779}780e := &EventPort{781port: port,782fds: make(map[uintptr]*fileObjCookie),783paths: make(map[string]*fileObjCookie),784cookies: make(map[*fileObjCookie]struct{}),785}786return e, nil787}
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 {797e.mu.Lock()798defer e.mu.Unlock()799err := Close(e.port)800if err != nil {801return err802}803e.fds = nil804e.paths = nil805e.cookies = nil806return nil807}
808
809// PathIsWatched checks to see if path is associated with this EventPort.
810func (e *EventPort) PathIsWatched(path string) bool {811e.mu.Lock()812defer e.mu.Unlock()813_, found := e.paths[path]814return found815}
816
817// FdIsWatched checks to see if fd is associated with this EventPort.
818func (e *EventPort) FdIsWatched(fd uintptr) bool {819e.mu.Lock()820defer e.mu.Unlock()821_, found := e.fds[fd]822return found823}
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 {828e.mu.Lock()829defer e.mu.Unlock()830if _, found := e.paths[path]; found {831return fmt.Errorf("%v is already associated with this Event Port", path)832}833fCookie, err := createFileObjCookie(path, stat, cookie)834if err != nil {835return err836}837_, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fCookie.fobj)), events, (*byte)(unsafe.Pointer(fCookie)))838if err != nil {839return err840}841e.paths[path] = fCookie842e.cookies[fCookie] = struct{}{}843return nil844}
845
846// DissociatePath wraps port_dissociate(3c) for a filesystem path.
847func (e *EventPort) DissociatePath(path string) error {848e.mu.Lock()849defer e.mu.Unlock()850f, ok := e.paths[path]851if !ok {852return 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 cookie858if err != nil && err != ENOENT {859return err860}861if err == nil {862// dissociate was successful, safe to delete the cookie863fCookie := e.paths[path]864delete(e.cookies, fCookie)865}866delete(e.paths, path)867return err868}
869
870// AssociateFd wraps calls to port_associate(3c) on file descriptors.
871func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error {872e.mu.Lock()873defer e.mu.Unlock()874if _, found := e.fds[fd]; found {875return fmt.Errorf("%v is already associated with this Event Port", fd)876}877fCookie, err := createFileObjCookie("", nil, cookie)878if err != nil {879return err880}881_, err = port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(fCookie)))882if err != nil {883return err884}885e.fds[fd] = fCookie886e.cookies[fCookie] = struct{}{}887return nil888}
889
890// DissociateFd wraps calls to port_dissociate(3c) on file descriptors.
891func (e *EventPort) DissociateFd(fd uintptr) error {892e.mu.Lock()893defer e.mu.Unlock()894_, ok := e.fds[fd]895if !ok {896return fmt.Errorf("%v is not associated with this Event Port", fd)897}898_, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)899if err != nil && err != ENOENT {900return err901}902if err == nil {903// dissociate was successful, safe to delete the cookie904fCookie := e.fds[fd]905delete(e.cookies, fCookie)906}907delete(e.fds, fd)908return err909}
910
911func createFileObjCookie(name string, stat os.FileInfo, cookie interface{}) (*fileObjCookie, error) {912fCookie := new(fileObjCookie)913fCookie.cookie = cookie914if name != "" && stat != nil {915fCookie.fobj = new(fileObj)916bs, err := ByteSliceFromString(name)917if err != nil {918return nil, err919}920fCookie.fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))921s := stat.Sys().(*syscall.Stat_t)922fCookie.fobj.Atim.Sec = s.Atim.Sec923fCookie.fobj.Atim.Nsec = s.Atim.Nsec924fCookie.fobj.Mtim.Sec = s.Mtim.Sec925fCookie.fobj.Mtim.Nsec = s.Mtim.Nsec926fCookie.fobj.Ctim.Sec = s.Ctim.Sec927fCookie.fobj.Ctim.Nsec = s.Ctim.Nsec928}929return fCookie, nil930}
931
932// GetOne wraps port_get(3c) and returns a single PortEvent.
933func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {934pe := new(portEvent)935_, err := port_get(e.port, pe, t)936if err != nil {937return nil, err938}939p := new(PortEvent)940e.mu.Lock()941defer e.mu.Unlock()942err = e.peIntToExt(pe, p)943if err != nil {944return nil, err945}946return p, nil947}
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 {952if e.cookies == nil {953return fmt.Errorf("this EventPort is already closed")954}955peExt.Events = peInt.Events956peExt.Source = peInt.Source957fCookie := (*fileObjCookie)(unsafe.Pointer(peInt.User))958_, found := e.cookies[fCookie]959
960if !found {961panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")962}963peExt.Cookie = fCookie.cookie964delete(e.cookies, fCookie)965
966switch peInt.Source {967case PORT_SOURCE_FD:968peExt.Fd = uintptr(peInt.Object)969// Only remove the fds entry if it exists and this cookie matches970if fobj, ok := e.fds[peExt.Fd]; ok {971if fobj == fCookie {972delete(e.fds, peExt.Fd)973}974}975case PORT_SOURCE_FILE:976peExt.fobj = fCookie.fobj977peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))978// Only remove the paths entry if it exists and this cookie matches979if fobj, ok := e.paths[peExt.Path]; ok {980if fobj == fCookie {981delete(e.paths, peExt.Path)982}983}984}985return nil986}
987
988// Pending wraps port_getn(3c) and returns how many events are pending.
989func (e *EventPort) Pending() (int, error) {990var n uint32 = 0991_, err := port_getn(e.port, nil, 0, &n, nil)992return int(n), err993}
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) {1000if min == 0 {1001return 0, fmt.Errorf("need to request at least one event or use Pending() instead")1002}1003if len(s) < min {1004return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min)1005}1006got := uint32(min)1007max := uint32(len(s))1008var err error1009ps := 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.1012if err != nil && err != ETIME {1013return 0, err1014}1015e.mu.Lock()1016defer e.mu.Unlock()1017valid := 01018for i := 0; i < int(got); i++ {1019err2 := e.peIntToExt(&ps[i], &s[i])1020if err2 != nil {1021if valid == 0 && err == nil {1022// If err2 is the only error and there are no valid events1023// to return, return it to the caller.1024err = err21025}1026break1027}1028valid = i + 11029}1030return valid, err1031}
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) {1036var clp, datap *strbuf1037if len(cl) > 0 {1038clp = &strbuf{1039Len: int32(len(cl)),1040Buf: (*int8)(unsafe.Pointer(&cl[0])),1041}1042}1043if len(data) > 0 {1044datap = &strbuf{1045Len: int32(len(data)),1046Buf: (*int8)(unsafe.Pointer(&data[0])),1047}1048}1049return 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) {1055var clp, datap *strbuf1056if len(cl) > 0 {1057clp = &strbuf{1058Maxlen: int32(len(cl)),1059Buf: (*int8)(unsafe.Pointer(&cl[0])),1060}1061}1062if len(data) > 0 {1063datap = &strbuf{1064Maxlen: int32(len(data)),1065Buf: (*int8)(unsafe.Pointer(&data[0])),1066}1067}1068
1069if err = getmsg(fd, clp, datap, &flags); err != nil {1070return nil, nil, 0, err1071}1072
1073if len(cl) > 0 {1074retCl = cl[:clp.Len]1075}1076if len(data) > 0 {1077retData = data[:datap.Len]1078}1079return retCl, retData, flags, nil1080}
1081
1082func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {1083return ioctlRet(fd, req, uintptr(arg))1084}
1085
1086func IoctlSetString(fd int, req int, val string) error {1087bs := make([]byte, len(val)+1)1088copy(bs[:len(bs)-1], val)1089err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))1090runtime.KeepAlive(&bs[0])1091return err1092}
1093
1094// Lifreq Helpers
1095
1096func (l *Lifreq) SetName(name string) error {1097if len(name) >= len(l.Name) {1098return fmt.Errorf("name cannot be more than %d characters", len(l.Name)-1)1099}1100for i := range name {1101l.Name[i] = int8(name[i])1102}1103return nil1104}
1105
1106func (l *Lifreq) SetLifruInt(d int) {1107*(*int)(unsafe.Pointer(&l.Lifru[0])) = d1108}
1109
1110func (l *Lifreq) GetLifruInt() int {1111return *(*int)(unsafe.Pointer(&l.Lifru[0]))1112}
1113
1114func (l *Lifreq) SetLifruUint(d uint) {1115*(*uint)(unsafe.Pointer(&l.Lifru[0])) = d1116}
1117
1118func (l *Lifreq) GetLifruUint() uint {1119return *(*uint)(unsafe.Pointer(&l.Lifru[0]))1120}
1121
1122func IoctlLifreq(fd int, req int, l *Lifreq) error {1123return ioctlPtr(fd, req, unsafe.Pointer(l))1124}
1125
1126// Strioctl Helpers
1127
1128func (s *Strioctl) SetInt(i int) {1129s.Len = int32(unsafe.Sizeof(i))1130s.Dp = (*int8)(unsafe.Pointer(&i))1131}
1132
1133func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {1134return ioctlPtrRet(fd, req, unsafe.Pointer(s))1135}
1136