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