blob: 5c813921e855c77a95293b2a444ce4eca4f5cc43 [file] [log] [blame]
kesavand2cde6582020-06-22 04:56:23 -04001// 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 (
kesavandc71914f2022-03-25 11:19:03 +053016 "fmt"
17 "os"
Andrea Campanella764f1ed2022-03-24 11:46:38 +010018 "runtime"
kesavandc71914f2022-03-25 11:19:03 +053019 "sync"
kesavand2cde6582020-06-22 04:56:23 -040020 "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 }
kesavandc71914f2022-03-25 11:19:03 +053069 if err == nil {
70 p[0] = int(pp[0])
71 p[1] = int(pp[1])
72 }
kesavand2cde6582020-06-22 04:56:23 -040073 return nil
74}
75
Andrea Campanella764f1ed2022-03-24 11:46:38 +010076//sysnb pipe2(p *[2]_C_int, flags int) (err error)
77
78func 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)
kesavandc71914f2022-03-25 11:19:03 +053084 if err == nil {
85 p[0] = int(pp[0])
86 p[1] = int(pp[1])
87 }
Andrea Campanella764f1ed2022-03-24 11:46:38 +010088 return err
89}
90
kesavand2cde6582020-06-22 04:56:23 -040091func (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)
kesavandc71914f2022-03-25 11:19:03 +053099 sa.raw.Addr = sa.Addr
kesavand2cde6582020-06-22 04:56:23 -0400100 return unsafe.Pointer(&sa.raw), SizeofSockaddrInet4, nil
101}
102
103func (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
kesavandc71914f2022-03-25 11:19:03 +0530112 sa.raw.Addr = sa.Addr
kesavand2cde6582020-06-22 04:56:23 -0400113 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 }
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100411 bytes := (*[len(pp.Path)]byte)(unsafe.Pointer(&pp.Path[0]))[0:n]
kesavand2cde6582020-06-22 04:56:23 -0400412 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])
kesavandc71914f2022-03-25 11:19:03 +0530420 sa.Addr = pp.Addr
kesavand2cde6582020-06-22 04:56:23 -0400421 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
kesavandc71914f2022-03-25 11:19:03 +0530429 sa.Addr = pp.Addr
kesavand2cde6582020-06-22 04:56:23 -0400430 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
437func 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
454func Recvmsg(fd int, p, oob []byte, flags int) (n, oobn int, recvflags int, from Sockaddr, err error) {
455 var msg Msghdr
456 var rsa RawSockaddrAny
457 msg.Name = (*byte)(unsafe.Pointer(&rsa))
458 msg.Namelen = uint32(SizeofSockaddrAny)
459 var iov Iovec
460 if len(p) > 0 {
461 iov.Base = (*int8)(unsafe.Pointer(&p[0]))
462 iov.SetLen(len(p))
463 }
464 var dummy int8
465 if len(oob) > 0 {
466 // receive at least one normal byte
467 if len(p) == 0 {
468 iov.Base = &dummy
469 iov.SetLen(1)
470 }
471 msg.Accrightslen = int32(len(oob))
472 }
473 msg.Iov = &iov
474 msg.Iovlen = 1
475 if n, err = recvmsg(fd, &msg, flags); n == -1 {
476 return
477 }
478 oobn = int(msg.Accrightslen)
479 // source address is only specified if the socket is unconnected
480 if rsa.Addr.Family != AF_UNSPEC {
481 from, err = anyToSockaddr(fd, &rsa)
482 }
483 return
484}
485
486func Sendmsg(fd int, p, oob []byte, to Sockaddr, flags int) (err error) {
487 _, err = SendmsgN(fd, p, oob, to, flags)
488 return
489}
490
491//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
492
493func SendmsgN(fd int, p, oob []byte, to Sockaddr, flags int) (n int, err error) {
494 var ptr unsafe.Pointer
495 var salen _Socklen
496 if to != nil {
497 ptr, salen, err = to.sockaddr()
498 if err != nil {
499 return 0, err
500 }
501 }
502 var msg Msghdr
503 msg.Name = (*byte)(unsafe.Pointer(ptr))
504 msg.Namelen = uint32(salen)
505 var iov Iovec
506 if len(p) > 0 {
507 iov.Base = (*int8)(unsafe.Pointer(&p[0]))
508 iov.SetLen(len(p))
509 }
510 var dummy int8
511 if len(oob) > 0 {
512 // send at least one normal byte
513 if len(p) == 0 {
514 iov.Base = &dummy
515 iov.SetLen(1)
516 }
517 msg.Accrightslen = int32(len(oob))
518 }
519 msg.Iov = &iov
520 msg.Iovlen = 1
521 if n, err = sendmsg(fd, &msg, flags); err != nil {
522 return 0, err
523 }
524 if len(oob) > 0 && len(p) == 0 {
525 n = 0
526 }
527 return n, nil
528}
529
530//sys acct(path *byte) (err error)
531
532func Acct(path string) (err error) {
533 if len(path) == 0 {
534 // Assume caller wants to disable accounting.
535 return acct(nil)
536 }
537
538 pathp, err := BytePtrFromString(path)
539 if err != nil {
540 return err
541 }
542 return acct(pathp)
543}
544
545//sys __makedev(version int, major uint, minor uint) (val uint64)
546
547func Mkdev(major, minor uint32) uint64 {
548 return __makedev(NEWDEV, uint(major), uint(minor))
549}
550
551//sys __major(version int, dev uint64) (val uint)
552
553func Major(dev uint64) uint32 {
554 return uint32(__major(NEWDEV, dev))
555}
556
557//sys __minor(version int, dev uint64) (val uint)
558
559func Minor(dev uint64) uint32 {
560 return uint32(__minor(NEWDEV, dev))
561}
562
563/*
564 * Expose the ioctl function
565 */
566
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100567//sys ioctlRet(fd int, req uint, arg uintptr) (ret int, err error) = libc.ioctl
kesavand2cde6582020-06-22 04:56:23 -0400568
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100569func ioctl(fd int, req uint, arg uintptr) (err error) {
570 _, err = ioctlRet(fd, req, arg)
571 return err
kesavand2cde6582020-06-22 04:56:23 -0400572}
573
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100574func IoctlSetTermio(fd int, req uint, value *Termio) error {
575 err := ioctl(fd, req, uintptr(unsafe.Pointer(value)))
576 runtime.KeepAlive(value)
577 return err
kesavand2cde6582020-06-22 04:56:23 -0400578}
579
580func IoctlGetTermio(fd int, req uint) (*Termio, error) {
581 var value Termio
582 err := ioctl(fd, req, uintptr(unsafe.Pointer(&value)))
583 return &value, err
584}
585
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100586//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
kesavand2cde6582020-06-22 04:56:23 -0400587
588func Poll(fds []PollFd, timeout int) (n int, err error) {
589 if len(fds) == 0 {
590 return poll(nil, 0, timeout)
591 }
592 return poll(&fds[0], len(fds), timeout)
593}
594
595func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
596 if raceenabled {
597 raceReleaseMerge(unsafe.Pointer(&ioSync))
598 }
599 return sendfile(outfd, infd, offset, count)
600}
601
602/*
603 * Exposed directly
604 */
605//sys Access(path string, mode uint32) (err error)
606//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
607//sys Chdir(path string) (err error)
608//sys Chmod(path string, mode uint32) (err error)
609//sys Chown(path string, uid int, gid int) (err error)
610//sys Chroot(path string) (err error)
611//sys Close(fd int) (err error)
612//sys Creat(path string, mode uint32) (fd int, err error)
613//sys Dup(fd int) (nfd int, err error)
614//sys Dup2(oldfd int, newfd int) (err error)
615//sys Exit(code int)
616//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
617//sys Fchdir(fd int) (err error)
618//sys Fchmod(fd int, mode uint32) (err error)
619//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
620//sys Fchown(fd int, uid int, gid int) (err error)
621//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
622//sys Fdatasync(fd int) (err error)
623//sys Flock(fd int, how int) (err error)
624//sys Fpathconf(fd int, name int) (val int, err error)
625//sys Fstat(fd int, stat *Stat_t) (err error)
626//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
627//sys Fstatvfs(fd int, vfsstat *Statvfs_t) (err error)
628//sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
629//sysnb Getgid() (gid int)
630//sysnb Getpid() (pid int)
631//sysnb Getpgid(pid int) (pgid int, err error)
632//sysnb Getpgrp() (pgid int, err error)
633//sys Geteuid() (euid int)
634//sys Getegid() (egid int)
635//sys Getppid() (ppid int)
636//sys Getpriority(which int, who int) (n int, err error)
637//sysnb Getrlimit(which int, lim *Rlimit) (err error)
638//sysnb Getrusage(who int, rusage *Rusage) (err error)
639//sysnb Gettimeofday(tv *Timeval) (err error)
640//sysnb Getuid() (uid int)
641//sys Kill(pid int, signum syscall.Signal) (err error)
642//sys Lchown(path string, uid int, gid int) (err error)
643//sys Link(path string, link string) (err error)
644//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten
645//sys Lstat(path string, stat *Stat_t) (err error)
646//sys Madvise(b []byte, advice int) (err error)
647//sys Mkdir(path string, mode uint32) (err error)
648//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
649//sys Mkfifo(path string, mode uint32) (err error)
650//sys Mkfifoat(dirfd int, path string, mode uint32) (err error)
651//sys Mknod(path string, mode uint32, dev int) (err error)
652//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
653//sys Mlock(b []byte) (err error)
654//sys Mlockall(flags int) (err error)
655//sys Mprotect(b []byte, prot int) (err error)
656//sys Msync(b []byte, flags int) (err error)
657//sys Munlock(b []byte) (err error)
658//sys Munlockall() (err error)
659//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
660//sys Open(path string, mode int, perm uint32) (fd int, err error)
661//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
662//sys Pathconf(path string, name int) (val int, err error)
663//sys Pause() (err error)
664//sys Pread(fd int, p []byte, offset int64) (n int, err error)
665//sys Pwrite(fd int, p []byte, offset int64) (n int, err error)
666//sys read(fd int, p []byte) (n int, err error)
667//sys Readlink(path string, buf []byte) (n int, err error)
668//sys Rename(from string, to string) (err error)
669//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
670//sys Rmdir(path string) (err error)
671//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100672//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
kesavand2cde6582020-06-22 04:56:23 -0400673//sysnb Setegid(egid int) (err error)
674//sysnb Seteuid(euid int) (err error)
675//sysnb Setgid(gid int) (err error)
676//sys Sethostname(p []byte) (err error)
677//sysnb Setpgid(pid int, pgid int) (err error)
678//sys Setpriority(which int, who int, prio int) (err error)
679//sysnb Setregid(rgid int, egid int) (err error)
680//sysnb Setreuid(ruid int, euid int) (err error)
681//sysnb Setrlimit(which int, lim *Rlimit) (err error)
682//sysnb Setsid() (pid int, err error)
683//sysnb Setuid(uid int) (err error)
684//sys Shutdown(s int, how int) (err error) = libsocket.shutdown
685//sys Stat(path string, stat *Stat_t) (err error)
686//sys Statvfs(path string, vfsstat *Statvfs_t) (err error)
687//sys Symlink(path string, link string) (err error)
688//sys Sync() (err error)
Andrea Campanella764f1ed2022-03-24 11:46:38 +0100689//sys Sysconf(which int) (n int64, err error)
kesavand2cde6582020-06-22 04:56:23 -0400690//sysnb Times(tms *Tms) (ticks uintptr, err error)
691//sys Truncate(path string, length int64) (err error)
692//sys Fsync(fd int) (err error)
693//sys Ftruncate(fd int, length int64) (err error)
694//sys Umask(mask int) (oldmask int)
695//sysnb Uname(buf *Utsname) (err error)
696//sys Unmount(target string, flags int) (err error) = libc.umount
697//sys Unlink(path string) (err error)
698//sys Unlinkat(dirfd int, path string, flags int) (err error)
699//sys Ustat(dev int, ubuf *Ustat_t) (err error)
700//sys Utime(path string, buf *Utimbuf) (err error)
701//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_bind
702//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
703//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
704//sys munmap(addr uintptr, length uintptr) (err error)
705//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
706//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
707//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
708//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
709//sys write(fd int, p []byte) (n int, err error)
710//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.__xnet_getsockopt
711//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
712//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
713//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
714
715func readlen(fd int, buf *byte, nbuf int) (n int, err error) {
716 r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procread)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
717 n = int(r0)
718 if e1 != 0 {
719 err = e1
720 }
721 return
722}
723
724func writelen(fd int, buf *byte, nbuf int) (n int, err error) {
725 r0, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procwrite)), 3, uintptr(fd), uintptr(unsafe.Pointer(buf)), uintptr(nbuf), 0, 0, 0)
726 n = int(r0)
727 if e1 != 0 {
728 err = e1
729 }
730 return
731}
732
733var mapper = &mmapper{
734 active: make(map[*byte][]byte),
735 mmap: mmap,
736 munmap: munmap,
737}
738
739func Mmap(fd int, offset int64, length int, prot int, flags int) (data []byte, err error) {
740 return mapper.Mmap(fd, offset, length, prot, flags)
741}
742
743func Munmap(b []byte) (err error) {
744 return mapper.Munmap(b)
745}
kesavandc71914f2022-03-25 11:19:03 +0530746
747// Event Ports
748
749type fileObjCookie struct {
750 fobj *fileObj
751 cookie interface{}
752}
753
754// EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
755type EventPort struct {
756 port int
757 mu sync.Mutex
758 fds map[uintptr]interface{}
759 paths map[string]*fileObjCookie
760}
761
762// PortEvent is an abstraction of the port_event C struct.
763// Compare Source against PORT_SOURCE_FILE or PORT_SOURCE_FD
764// to see if Path or Fd was the event source. The other will be
765// uninitialized.
766type PortEvent struct {
767 Cookie interface{}
768 Events int32
769 Fd uintptr
770 Path string
771 Source uint16
772 fobj *fileObj
773}
774
775// NewEventPort creates a new EventPort including the
776// underlying call to port_create(3c).
777func NewEventPort() (*EventPort, error) {
778 port, err := port_create()
779 if err != nil {
780 return nil, err
781 }
782 e := &EventPort{
783 port: port,
784 fds: make(map[uintptr]interface{}),
785 paths: make(map[string]*fileObjCookie),
786 }
787 return e, nil
788}
789
790//sys port_create() (n int, err error)
791//sys port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error)
792//sys port_dissociate(port int, source int, object uintptr) (n int, err error)
793//sys port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error)
794//sys port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error)
795
796// Close closes the event port.
797func (e *EventPort) Close() error {
798 e.mu.Lock()
799 defer e.mu.Unlock()
800 e.fds = nil
801 e.paths = nil
802 return Close(e.port)
803}
804
805// PathIsWatched checks to see if path is associated with this EventPort.
806func (e *EventPort) PathIsWatched(path string) bool {
807 e.mu.Lock()
808 defer e.mu.Unlock()
809 _, found := e.paths[path]
810 return found
811}
812
813// FdIsWatched checks to see if fd is associated with this EventPort.
814func (e *EventPort) FdIsWatched(fd uintptr) bool {
815 e.mu.Lock()
816 defer e.mu.Unlock()
817 _, found := e.fds[fd]
818 return found
819}
820
821// AssociatePath wraps port_associate(3c) for a filesystem path including
822// creating the necessary file_obj from the provided stat information.
823func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, cookie interface{}) error {
824 e.mu.Lock()
825 defer e.mu.Unlock()
826 if _, found := e.paths[path]; found {
827 return fmt.Errorf("%v is already associated with this Event Port", path)
828 }
829 fobj, err := createFileObj(path, stat)
830 if err != nil {
831 return err
832 }
833 fCookie := &fileObjCookie{fobj, cookie}
834 _, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fobj)), events, (*byte)(unsafe.Pointer(&fCookie.cookie)))
835 if err != nil {
836 return err
837 }
838 e.paths[path] = fCookie
839 return nil
840}
841
842// DissociatePath wraps port_dissociate(3c) for a filesystem path.
843func (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 err != nil {
852 return err
853 }
854 delete(e.paths, path)
855 return nil
856}
857
858// AssociateFd wraps calls to port_associate(3c) on file descriptors.
859func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error {
860 e.mu.Lock()
861 defer e.mu.Unlock()
862 if _, found := e.fds[fd]; found {
863 return fmt.Errorf("%v is already associated with this Event Port", fd)
864 }
865 pcookie := &cookie
866 _, err := port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(pcookie)))
867 if err != nil {
868 return err
869 }
870 e.fds[fd] = pcookie
871 return nil
872}
873
874// DissociateFd wraps calls to port_dissociate(3c) on file descriptors.
875func (e *EventPort) DissociateFd(fd uintptr) error {
876 e.mu.Lock()
877 defer e.mu.Unlock()
878 _, ok := e.fds[fd]
879 if !ok {
880 return fmt.Errorf("%v is not associated with this Event Port", fd)
881 }
882 _, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)
883 if err != nil {
884 return err
885 }
886 delete(e.fds, fd)
887 return nil
888}
889
890func createFileObj(name string, stat os.FileInfo) (*fileObj, error) {
891 fobj := new(fileObj)
892 bs, err := ByteSliceFromString(name)
893 if err != nil {
894 return nil, err
895 }
896 fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
897 s := stat.Sys().(*syscall.Stat_t)
898 fobj.Atim.Sec = s.Atim.Sec
899 fobj.Atim.Nsec = s.Atim.Nsec
900 fobj.Mtim.Sec = s.Mtim.Sec
901 fobj.Mtim.Nsec = s.Mtim.Nsec
902 fobj.Ctim.Sec = s.Ctim.Sec
903 fobj.Ctim.Nsec = s.Ctim.Nsec
904 return fobj, nil
905}
906
907// GetOne wraps port_get(3c) and returns a single PortEvent.
908func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
909 pe := new(portEvent)
910 _, err := port_get(e.port, pe, t)
911 if err != nil {
912 return nil, err
913 }
914 p := new(PortEvent)
915 p.Events = pe.Events
916 p.Source = pe.Source
917 e.mu.Lock()
918 defer e.mu.Unlock()
919 switch pe.Source {
920 case PORT_SOURCE_FD:
921 p.Fd = uintptr(pe.Object)
922 cookie := (*interface{})(unsafe.Pointer(pe.User))
923 p.Cookie = *cookie
924 delete(e.fds, p.Fd)
925 case PORT_SOURCE_FILE:
926 p.fobj = (*fileObj)(unsafe.Pointer(uintptr(pe.Object)))
927 p.Path = BytePtrToString((*byte)(unsafe.Pointer(p.fobj.Name)))
928 cookie := (*interface{})(unsafe.Pointer(pe.User))
929 p.Cookie = *cookie
930 delete(e.paths, p.Path)
931 }
932 return p, nil
933}
934
935// Pending wraps port_getn(3c) and returns how many events are pending.
936func (e *EventPort) Pending() (int, error) {
937 var n uint32 = 0
938 _, err := port_getn(e.port, nil, 0, &n, nil)
939 return int(n), err
940}
941
942// Get wraps port_getn(3c) and fills a slice of PortEvent.
943// It will block until either min events have been received
944// or the timeout has been exceeded. It will return how many
945// events were actually received along with any error information.
946func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error) {
947 if min == 0 {
948 return 0, fmt.Errorf("need to request at least one event or use Pending() instead")
949 }
950 if len(s) < min {
951 return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min)
952 }
953 got := uint32(min)
954 max := uint32(len(s))
955 var err error
956 ps := make([]portEvent, max, max)
957 _, err = port_getn(e.port, &ps[0], max, &got, timeout)
958 // got will be trustworthy with ETIME, but not any other error.
959 if err != nil && err != ETIME {
960 return 0, err
961 }
962 e.mu.Lock()
963 defer e.mu.Unlock()
964 for i := 0; i < int(got); i++ {
965 s[i].Events = ps[i].Events
966 s[i].Source = ps[i].Source
967 switch ps[i].Source {
968 case PORT_SOURCE_FD:
969 s[i].Fd = uintptr(ps[i].Object)
970 cookie := (*interface{})(unsafe.Pointer(ps[i].User))
971 s[i].Cookie = *cookie
972 delete(e.fds, s[i].Fd)
973 case PORT_SOURCE_FILE:
974 s[i].fobj = (*fileObj)(unsafe.Pointer(uintptr(ps[i].Object)))
975 s[i].Path = BytePtrToString((*byte)(unsafe.Pointer(s[i].fobj.Name)))
976 cookie := (*interface{})(unsafe.Pointer(ps[i].User))
977 s[i].Cookie = *cookie
978 delete(e.paths, s[i].Path)
979 }
980 }
981 return int(got), err
982}