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