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