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