blob: 21974af064ddc38e765f3543cda0a9ca29aa44aa [file] [log] [blame]
Rob Pike20acc5c2014-08-11 14:48:46 -07001// 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
Rob Pike8442dd22014-08-11 15:58:26 -070013package unix
Rob Pike20acc5c2014-08-11 14:48:46 -070014
Rob Pikedc3c21c2014-08-15 09:57:24 -070015import (
Nahum Shalman13f9c582021-06-03 01:39:59 +000016 "fmt"
17 "os"
Matt Layher99712362020-10-05 13:07:52 -040018 "runtime"
Nahum Shalman13f9c582021-06-03 01:39:59 +000019 "sync"
Rob Pikedc3c21c2014-08-15 09:57:24 -070020 "syscall"
21 "unsafe"
22)
Rob Pike20acc5c2014-08-11 14:48:46 -070023
Shawn Walker-Salas339fc2c2015-08-06 19:57:13 -070024// 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
Tobias Klauser03467252018-01-25 13:54:57 +010030// SockaddrDatalink implements the Sockaddr interface for AF_LINK type sockets.
Rob Pike20acc5c2014-08-11 14:48:46 -070031type 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
Tobias Klausere07cf5d2019-06-26 12:46:47 +020042func 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
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -070058//sysnb pipe(p *[2]_C_int) (n int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -070059
60func Pipe(p []int) (err error) {
61 if len(p) != 2 {
62 return EINVAL
63 }
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -070064 var pp [2]_C_int
65 n, err := pipe(&pp)
66 if n != 0 {
67 return err
Rob Pike20acc5c2014-08-11 14:48:46 -070068 }
Russ Cox798191b2021-12-09 08:27:52 -050069 if err == nil {
70 p[0] = int(pp[0])
71 p[1] = int(pp[1])
72 }
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -070073 return nil
Rob Pike20acc5c2014-08-11 14:48:46 -070074}
75
Tobias Klauser489259a2021-01-11 16:21:51 +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)
Russ Cox798191b2021-12-09 08:27:52 -050084 if err == nil {
85 p[0] = int(pp[0])
86 p[1] = int(pp[1])
87 }
Tobias Klauser489259a2021-01-11 16:21:51 +010088 return err
89}
90
Rob Pike20acc5c2014-08-11 14:48:46 -070091func (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)
Tobias Klauserc75c4772021-11-05 09:24:00 +010099 sa.raw.Addr = sa.Addr
Rob Pike20acc5c2014-08-11 14:48:46 -0700100 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
Tobias Klauserc75c4772021-11-05 09:24:00 +0100112 sa.raw.Addr = sa.Addr
Rob Pike20acc5c2014-08-11 14:48:46 -0700113 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 }
F Y1e638102023-10-17 10:01:27 +0100131 if sa.raw.Path[0] == '@' || (sa.raw.Path[0] == 0 && sl > 3) {
132 // Check sl > 3 so we don't change unnamed socket behavior.
Rob Pike20acc5c2014-08-11 14:48:46 -0700133 sa.raw.Path[0] = 0
134 // Don't count trailing NUL for abstract address.
135 sl--
136 }
137
138 return unsafe.Pointer(&sa.raw), sl, nil
139}
140
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700141//sys getsockname(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getsockname
142
Rob Pike20acc5c2014-08-11 14:48:46 -0700143func Getsockname(fd int) (sa Sockaddr, err error) {
144 var rsa RawSockaddrAny
145 var len _Socklen = SizeofSockaddrAny
146 if err = getsockname(fd, &rsa, &len); err != nil {
147 return
148 }
Alexander Menzhinsky1b2967e2018-07-06 12:56:39 +0300149 return anyToSockaddr(fd, &rsa)
Rob Pike20acc5c2014-08-11 14:48:46 -0700150}
151
Tobias Klauserd5840ad2017-12-14 15:09:03 +0100152// GetsockoptString returns the string value of the socket option opt for the
153// socket associated with fd at the given socket level.
154func GetsockoptString(fd, level, opt int) (string, error) {
155 buf := make([]byte, 256)
156 vallen := _Socklen(len(buf))
157 err := getsockopt(fd, level, opt, unsafe.Pointer(&buf[0]), &vallen)
158 if err != nil {
159 return "", err
160 }
Konstantin Burkaleve4099bf2023-09-26 16:55:16 +0300161 return ByteSliceToString(buf[:vallen]), nil
Tobias Klauserd5840ad2017-12-14 15:09:03 +0100162}
163
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700164const ImplementsGetwd = true
Rob Pike20acc5c2014-08-11 14:48:46 -0700165
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700166//sys Getcwd(buf []byte) (n int, err error)
167
168func Getwd() (wd string, err error) {
169 var buf [PathMax]byte
170 // Getcwd will return an error if it failed for any reason.
171 _, err = Getcwd(buf[0:])
172 if err != nil {
173 return "", err
174 }
175 n := clen(buf[:])
176 if n < 1 {
177 return "", EINVAL
178 }
179 return string(buf[:n]), nil
180}
Rob Pike20acc5c2014-08-11 14:48:46 -0700181
182/*
183 * Wrapped
184 */
185
186//sysnb getgroups(ngid int, gid *_Gid_t) (n int, err error)
187//sysnb setgroups(ngid int, gid *_Gid_t) (err error)
188
189func Getgroups() (gids []int, err error) {
190 n, err := getgroups(0, nil)
Tobias Klauser9e4fff12017-10-25 22:17:19 +0200191 // Check for error and sanity check group count. Newer versions of
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700192 // Solaris allow up to 1024 (NGROUPS_MAX).
193 if n < 0 || n > 1024 {
194 if err != nil {
195 return nil, err
196 }
Rob Pike20acc5c2014-08-11 14:48:46 -0700197 return nil, EINVAL
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700198 } else if n == 0 {
199 return nil, nil
Rob Pike20acc5c2014-08-11 14:48:46 -0700200 }
201
202 a := make([]_Gid_t, n)
203 n, err = getgroups(n, &a[0])
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700204 if n == -1 {
Rob Pike20acc5c2014-08-11 14:48:46 -0700205 return nil, err
206 }
207 gids = make([]int, n)
208 for i, v := range a[0:n] {
209 gids[i] = int(v)
210 }
211 return
212}
213
214func Setgroups(gids []int) (err error) {
215 if len(gids) == 0 {
216 return setgroups(0, nil)
217 }
218
219 a := make([]_Gid_t, len(gids))
220 for i, v := range gids {
221 a[i] = _Gid_t(v)
222 }
223 return setgroups(len(a), &a[0])
224}
225
Tobias Klauser8f4f9632019-06-18 08:23:06 +0200226// ReadDirent reads directory entries from fd and writes them into buf.
Rob Pike20acc5c2014-08-11 14:48:46 -0700227func ReadDirent(fd int, buf []byte) (n int, err error) {
228 // Final argument is (basep *uintptr) and the syscall doesn't take nil.
229 // TODO(rsc): Can we use a single global basep for all calls?
230 return Getdents(fd, buf, new(uintptr))
231}
232
233// Wait status is 7 bits at bottom, either 0 (exited),
234// 0x7F (stopped), or a signal number that caused an exit.
235// The 0x80 bit is whether there was a core dump.
236// An extra number (exit code, signal causing a stop)
237// is in the high bits.
238
239type WaitStatus uint32
240
241const (
242 mask = 0x7F
243 core = 0x80
244 shift = 8
245
246 exited = 0
247 stopped = 0x7F
248)
249
250func (w WaitStatus) Exited() bool { return w&mask == exited }
251
252func (w WaitStatus) ExitStatus() int {
253 if w&mask != exited {
254 return -1
255 }
256 return int(w >> shift)
257}
258
259func (w WaitStatus) Signaled() bool { return w&mask != stopped && w&mask != 0 }
260
Rob Pikedc3c21c2014-08-15 09:57:24 -0700261func (w WaitStatus) Signal() syscall.Signal {
262 sig := syscall.Signal(w & mask)
Rob Pike20acc5c2014-08-11 14:48:46 -0700263 if sig == stopped || sig == 0 {
264 return -1
265 }
266 return sig
267}
268
269func (w WaitStatus) CoreDump() bool { return w.Signaled() && w&core != 0 }
270
Rob Pikedc3c21c2014-08-15 09:57:24 -0700271func (w WaitStatus) Stopped() bool { return w&mask == stopped && syscall.Signal(w>>shift) != SIGSTOP }
Rob Pike20acc5c2014-08-11 14:48:46 -0700272
Rob Pikedc3c21c2014-08-15 09:57:24 -0700273func (w WaitStatus) Continued() bool { return w&mask == stopped && syscall.Signal(w>>shift) == SIGSTOP }
Rob Pike20acc5c2014-08-11 14:48:46 -0700274
Rob Pikedc3c21c2014-08-15 09:57:24 -0700275func (w WaitStatus) StopSignal() syscall.Signal {
Rob Pike20acc5c2014-08-11 14:48:46 -0700276 if !w.Stopped() {
277 return -1
278 }
Rob Pikedc3c21c2014-08-15 09:57:24 -0700279 return syscall.Signal(w>>shift) & 0xFF
Rob Pike20acc5c2014-08-11 14:48:46 -0700280}
281
282func (w WaitStatus) TrapCause() int { return -1 }
283
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700284//sys wait4(pid int32, statusp *_C_int, options int, rusage *Rusage) (wpid int32, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700285
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700286func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (int, error) {
287 var status _C_int
288 rpid, err := wait4(int32(pid), &status, options, rusage)
289 wpid := int(rpid)
290 if wpid == -1 {
291 return wpid, err
Rob Pike20acc5c2014-08-11 14:48:46 -0700292 }
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700293 if wstatus != nil {
294 *wstatus = WaitStatus(status)
295 }
296 return wpid, nil
Rob Pike20acc5c2014-08-11 14:48:46 -0700297}
298
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700299//sys gethostname(buf []byte) (n int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700300
301func Gethostname() (name string, err error) {
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700302 var buf [MaxHostNameLen]byte
303 n, err := gethostname(buf[:])
304 if n != 0 {
305 return "", err
Rob Pike20acc5c2014-08-11 14:48:46 -0700306 }
Shawn Walker-Salas8f0908a2016-09-14 13:33:16 -0700307 n = clen(buf[:])
308 if n < 1 {
309 return "", EFAULT
310 }
311 return string(buf[:n]), nil
Rob Pike20acc5c2014-08-11 14:48:46 -0700312}
313
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700314//sys utimes(path string, times *[2]Timeval) (err error)
315
316func Utimes(path string, tv []Timeval) (err error) {
317 if tv == nil {
318 return utimes(path, nil)
319 }
320 if len(tv) != 2 {
321 return EINVAL
322 }
323 return utimes(path, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
324}
325
326//sys utimensat(fd int, path string, times *[2]Timespec, flag int) (err error)
327
Rob Pike38267142015-07-27 13:16:35 +1000328func UtimesNano(path string, ts []Timespec) error {
329 if ts == nil {
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700330 return utimensat(AT_FDCWD, path, nil, 0)
Rob Pike38267142015-07-27 13:16:35 +1000331 }
Rob Pike20acc5c2014-08-11 14:48:46 -0700332 if len(ts) != 2 {
333 return EINVAL
334 }
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700335 return utimensat(AT_FDCWD, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), 0)
336}
337
338func UtimesNanoAt(dirfd int, path string, ts []Timespec, flags int) error {
339 if ts == nil {
340 return utimensat(dirfd, path, nil, flags)
Rob Pike20acc5c2014-08-11 14:48:46 -0700341 }
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700342 if len(ts) != 2 {
343 return EINVAL
344 }
345 return utimensat(dirfd, path, (*[2]Timespec)(unsafe.Pointer(&ts[0])), flags)
Rob Pike20acc5c2014-08-11 14:48:46 -0700346}
347
348//sys fcntl(fd int, cmd int, arg int) (val int, err error)
349
Philip Brown1d206c92018-04-04 17:59:11 +0000350// FcntlInt performs a fcntl syscall on fd with the provided command and argument.
351func FcntlInt(fd uintptr, cmd, arg int) (int, error) {
Ian Lance Taylor7138fd32018-06-27 06:57:12 -0700352 valptr, _, errno := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(arg), 0, 0, 0)
353 var err error
354 if errno != 0 {
355 err = errno
356 }
Philip Brown1d206c92018-04-04 17:59:11 +0000357 return int(valptr), err
358}
359
Rob Pike20acc5c2014-08-11 14:48:46 -0700360// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
361func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) error {
Shawn Walker-Salas339fc2c2015-08-06 19:57:13 -0700362 _, _, e1 := sysvicall6(uintptr(unsafe.Pointer(&procfcntl)), 3, uintptr(fd), uintptr(cmd), uintptr(unsafe.Pointer(lk)), 0, 0, 0)
Rob Pike20acc5c2014-08-11 14:48:46 -0700363 if e1 != 0 {
364 return e1
365 }
366 return nil
367}
368
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700369//sys futimesat(fildes int, path *byte, times *[2]Timeval) (err error)
370
371func Futimesat(dirfd int, path string, tv []Timeval) error {
372 pathp, err := BytePtrFromString(path)
373 if err != nil {
374 return err
375 }
376 if tv == nil {
377 return futimesat(dirfd, pathp, nil)
378 }
379 if len(tv) != 2 {
380 return EINVAL
381 }
382 return futimesat(dirfd, pathp, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
383}
384
385// Solaris doesn't have an futimes function because it allows NULL to be
Tobias Klauser9e4fff12017-10-25 22:17:19 +0200386// specified as the path for futimesat. However, Go doesn't like
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700387// NULL-style string interfaces, so this simple wrapper is provided.
388func Futimes(fd int, tv []Timeval) error {
389 if tv == nil {
390 return futimesat(fd, nil, nil)
391 }
392 if len(tv) != 2 {
393 return EINVAL
394 }
395 return futimesat(fd, nil, (*[2]Timeval)(unsafe.Pointer(&tv[0])))
396}
397
Alexander Menzhinsky1b2967e2018-07-06 12:56:39 +0300398func anyToSockaddr(fd int, rsa *RawSockaddrAny) (Sockaddr, error) {
Rob Pike20acc5c2014-08-11 14:48:46 -0700399 switch rsa.Addr.Family {
400 case AF_UNIX:
401 pp := (*RawSockaddrUnix)(unsafe.Pointer(rsa))
402 sa := new(SockaddrUnix)
403 // Assume path ends at NUL.
404 // This is not technically the Solaris semantics for
405 // abstract Unix domain sockets -- they are supposed
406 // to be uninterpreted fixed-size binary blobs -- but
407 // everyone uses this convention.
408 n := 0
409 for n < len(pp.Path) && pp.Path[n] != 0 {
410 n++
411 }
Tobias Klausera6bfb892023-02-28 13:33:57 +0100412 sa.Name = string(unsafe.Slice((*byte)(unsafe.Pointer(&pp.Path[0])), n))
Rob Pike20acc5c2014-08-11 14:48:46 -0700413 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])
Tobias Klauserc75c4772021-11-05 09:24:00 +0100420 sa.Addr = pp.Addr
Rob Pike20acc5c2014-08-11 14:48:46 -0700421 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
Tobias Klauserc75c4772021-11-05 09:24:00 +0100429 sa.Addr = pp.Addr
Rob Pike20acc5c2014-08-11 14:48:46 -0700430 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)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700441 if nfd == -1 {
Rob Pike20acc5c2014-08-11 14:48:46 -0700442 return
443 }
Alexander Menzhinsky1b2967e2018-07-06 12:56:39 +0300444 sa, err = anyToSockaddr(fd, &rsa)
Rob Pike20acc5c2014-08-11 14:48:46 -0700445 if err != nil {
446 Close(nfd)
447 nfd = 0
448 }
449 return
450}
451
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900452//sys recvmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_recvmsg
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700453
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700454func recvmsgRaw(fd int, iov []Iovec, oob []byte, flags int, rsa *RawSockaddrAny) (n, oobn int, recvflags int, err error) {
Rob Pike20acc5c2014-08-11 14:48:46 -0700455 var msg Msghdr
Tobias Klauser51cd9982022-03-16 09:42:01 +0100456 msg.Name = (*byte)(unsafe.Pointer(rsa))
Rob Pike20acc5c2014-08-11 14:48:46 -0700457 msg.Namelen = uint32(SizeofSockaddrAny)
Ian Lance Taylor175b2fd2022-06-15 17:01:07 -0700458 var dummy byte
Rob Pike20acc5c2014-08-11 14:48:46 -0700459 if len(oob) > 0 {
460 // receive at least one normal byte
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700461 if emptyIovecs(iov) {
462 var iova [1]Iovec
463 iova[0].Base = &dummy
464 iova[0].SetLen(1)
465 iov = iova[:]
Rob Pike20acc5c2014-08-11 14:48:46 -0700466 }
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900467 msg.Accrightslen = int32(len(oob))
Rob Pike20acc5c2014-08-11 14:48:46 -0700468 }
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700469 if len(iov) > 0 {
470 msg.Iov = &iov[0]
471 msg.SetIovlen(len(iov))
472 }
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700473 if n, err = recvmsg(fd, &msg, flags); n == -1 {
Rob Pike20acc5c2014-08-11 14:48:46 -0700474 return
475 }
476 oobn = int(msg.Accrightslen)
Rob Pike20acc5c2014-08-11 14:48:46 -0700477 return
478}
479
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900480//sys sendmsg(s int, msg *Msghdr, flags int) (n int, err error) = libsocket.__xnet_sendmsg
Rob Pike20acc5c2014-08-11 14:48:46 -0700481
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700482func sendmsgN(fd int, iov []Iovec, oob []byte, ptr unsafe.Pointer, salen _Socklen, flags int) (n int, err error) {
Rob Pike20acc5c2014-08-11 14:48:46 -0700483 var msg Msghdr
484 msg.Name = (*byte)(unsafe.Pointer(ptr))
485 msg.Namelen = uint32(salen)
Ian Lance Taylor175b2fd2022-06-15 17:01:07 -0700486 var dummy byte
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700487 var empty bool
Rob Pike20acc5c2014-08-11 14:48:46 -0700488 if len(oob) > 0 {
489 // send at least one normal byte
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700490 empty = emptyIovecs(iov)
491 if empty {
492 var iova [1]Iovec
493 iova[0].Base = &dummy
494 iova[0].SetLen(1)
495 iov = iova[:]
Rob Pike20acc5c2014-08-11 14:48:46 -0700496 }
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900497 msg.Accrightslen = int32(len(oob))
Rob Pike20acc5c2014-08-11 14:48:46 -0700498 }
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700499 if len(iov) > 0 {
500 msg.Iov = &iov[0]
501 msg.SetIovlen(len(iov))
502 }
Rob Pike20acc5c2014-08-11 14:48:46 -0700503 if n, err = sendmsg(fd, &msg, flags); err != nil {
504 return 0, err
505 }
Ian Lance Taylor87e55d72022-06-15 17:34:44 -0700506 if len(oob) > 0 && empty {
Rob Pike20acc5c2014-08-11 14:48:46 -0700507 n = 0
508 }
509 return n, nil
510}
511
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700512//sys acct(path *byte) (err error)
513
514func Acct(path string) (err error) {
515 if len(path) == 0 {
516 // Assume caller wants to disable accounting.
517 return acct(nil)
518 }
519
520 pathp, err := BytePtrFromString(path)
521 if err != nil {
522 return err
523 }
524 return acct(pathp)
525}
526
Tobias Klauser1f337fd2017-09-18 16:07:25 +0000527//sys __makedev(version int, major uint, minor uint) (val uint64)
528
529func Mkdev(major, minor uint32) uint64 {
530 return __makedev(NEWDEV, uint(major), uint(minor))
531}
532
533//sys __major(version int, dev uint64) (val uint)
534
535func Major(dev uint64) uint32 {
536 return uint32(__major(NEWDEV, dev))
537}
538
539//sys __minor(version int, dev uint64) (val uint)
540
541func Minor(dev uint64) uint32 {
542 return uint32(__minor(NEWDEV, dev))
543}
544
Rob Pike20acc5c2014-08-11 14:48:46 -0700545/*
Kim Shrier584c5fe2015-09-15 21:24:48 -0600546 * Expose the ioctl function
547 */
548
Jason A. Donenfeld00d80042023-03-15 17:52:25 +0100549//sys ioctlRet(fd int, req int, arg uintptr) (ret int, err error) = libc.ioctl
550//sys ioctlPtrRet(fd int, req int, arg unsafe.Pointer) (ret int, err error) = libc.ioctl
Nahum Shalman193893d2021-03-18 01:16:38 +0000551
Jason A. Donenfeld00d80042023-03-15 17:52:25 +0100552func ioctl(fd int, req int, arg uintptr) (err error) {
Nahum Shalman193893d2021-03-18 01:16:38 +0000553 _, err = ioctlRet(fd, req, arg)
554 return err
555}
Kim Shrier584c5fe2015-09-15 21:24:48 -0600556
Jason A. Donenfeld00d80042023-03-15 17:52:25 +0100557func ioctlPtr(fd int, req int, arg unsafe.Pointer) (err error) {
Dmitri Goutnikb13f40e2023-02-17 16:51:14 -0500558 _, err = ioctlPtrRet(fd, req, arg)
559 return err
560}
561
Jason A. Donenfeld00d80042023-03-15 17:52:25 +0100562func IoctlSetTermio(fd int, req int, value *Termio) error {
Dmitri Goutnik10499f42023-02-24 10:27:54 -0500563 return ioctlPtr(fd, req, unsafe.Pointer(value))
Kim Shrier584c5fe2015-09-15 21:24:48 -0600564}
565
Jason A. Donenfeld00d80042023-03-15 17:52:25 +0100566func IoctlGetTermio(fd int, req int) (*Termio, error) {
Kim Shrier584c5fe2015-09-15 21:24:48 -0600567 var value Termio
Dmitri Goutnik10499f42023-02-24 10:27:54 -0500568 err := ioctlPtr(fd, req, unsafe.Pointer(&value))
Kim Shrier584c5fe2015-09-15 21:24:48 -0600569 return &value, err
570}
571
Tobias Klauser73548a72021-01-13 17:34:12 +0100572//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
Tobias Klauser661970f2017-10-27 12:30:52 +0000573
574func Poll(fds []PollFd, timeout int) (n int, err error) {
575 if len(fds) == 0 {
576 return poll(nil, 0, timeout)
577 }
578 return poll(&fds[0], len(fds), timeout)
579}
580
Keith Randall7c4c9942018-12-17 20:08:14 -0800581func Sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) {
582 if raceenabled {
583 raceReleaseMerge(unsafe.Pointer(&ioSync))
584 }
585 return sendfile(outfd, infd, offset, count)
586}
587
Kim Shrier584c5fe2015-09-15 21:24:48 -0600588/*
Rob Pike20acc5c2014-08-11 14:48:46 -0700589 * Exposed directly
590 */
591//sys Access(path string, mode uint32) (err error)
592//sys Adjtime(delta *Timeval, olddelta *Timeval) (err error)
593//sys Chdir(path string) (err error)
594//sys Chmod(path string, mode uint32) (err error)
595//sys Chown(path string, uid int, gid int) (err error)
596//sys Chroot(path string) (err error)
Tobias Klausercffae8e2022-12-12 16:11:07 +0100597//sys ClockGettime(clockid int32, time *Timespec) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700598//sys Close(fd int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700599//sys Creat(path string, mode uint32) (fd int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700600//sys Dup(fd int) (nfd int, err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700601//sys Dup2(oldfd int, newfd int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700602//sys Exit(code int)
Tobias Klauserf24d3d42018-06-19 07:45:16 +0000603//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700604//sys Fchdir(fd int) (err error)
605//sys Fchmod(fd int, mode uint32) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700606//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700607//sys Fchown(fd int, uid int, gid int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700608//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
609//sys Fdatasync(fd int) (err error)
Tobias Klauser591c1592018-03-14 10:37:40 +0000610//sys Flock(fd int, how int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700611//sys Fpathconf(fd int, name int) (val int, err error)
612//sys Fstat(fd int, stat *Stat_t) (err error)
Tobias Klauser591c1592018-03-14 10:37:40 +0000613//sys Fstatat(fd int, path string, stat *Stat_t, flags int) (err error)
Sean Chittenden1e99a4f2017-05-14 12:20:32 -0700614//sys Fstatvfs(fd int, vfsstat *Statvfs_t) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700615//sys Getdents(fd int, buf []byte, basep *uintptr) (n int, err error)
616//sysnb Getgid() (gid int)
617//sysnb Getpid() (pid int)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700618//sysnb Getpgid(pid int) (pgid int, err error)
619//sysnb Getpgrp() (pgid int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700620//sys Geteuid() (euid int)
621//sys Getegid() (egid int)
622//sys Getppid() (ppid int)
623//sys Getpriority(which int, who int) (n int, err error)
624//sysnb Getrlimit(which int, lim *Rlimit) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700625//sysnb Getrusage(who int, rusage *Rusage) (err error)
Nahum Shalman635b8c92022-06-08 02:17:23 +0000626//sysnb Getsid(pid int) (sid int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700627//sysnb Gettimeofday(tv *Timeval) (err error)
628//sysnb Getuid() (uid int)
Rob Pikedc3c21c2014-08-15 09:57:24 -0700629//sys Kill(pid int, signum syscall.Signal) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700630//sys Lchown(path string, uid int, gid int) (err error)
631//sys Link(path string, link string) (err error)
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900632//sys Listen(s int, backlog int) (err error) = libsocket.__xnet_llisten
Rob Pike20acc5c2014-08-11 14:48:46 -0700633//sys Lstat(path string, stat *Stat_t) (err error)
Ken Sedgwick09d970d2015-08-19 15:02:49 -0700634//sys Madvise(b []byte, advice int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700635//sys Mkdir(path string, mode uint32) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700636//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
637//sys Mkfifo(path string, mode uint32) (err error)
638//sys Mkfifoat(dirfd int, path string, mode uint32) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700639//sys Mknod(path string, mode uint32, dev int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700640//sys Mknodat(dirfd int, path string, mode uint32, dev int) (err error)
641//sys Mlock(b []byte) (err error)
642//sys Mlockall(flags int) (err error)
643//sys Mprotect(b []byte, prot int) (err error)
Tobias Klauserb8ca6dd2017-09-18 15:04:28 +0000644//sys Msync(b []byte, flags int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700645//sys Munlock(b []byte) (err error)
646//sys Munlockall() (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700647//sys Nanosleep(time *Timespec, leftover *Timespec) (err error)
648//sys Open(path string, mode int, perm uint32) (fd int, err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700649//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700650//sys Pathconf(path string, name int) (val int, err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700651//sys Pause() (err error)
Tobias Klauser039c03c2022-03-15 08:41:19 +0100652//sys pread(fd int, p []byte, offset int64) (n int, err error)
653//sys pwrite(fd int, p []byte, offset int64) (n int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700654//sys read(fd int, p []byte) (n int, err error)
655//sys Readlink(path string, buf []byte) (n int, err error)
656//sys Rename(from string, to string) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700657//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700658//sys Rmdir(path string) (err error)
659//sys Seek(fd int, offset int64, whence int) (newoffset int64, err error) = lseek
Tobias Klausere2fefa82019-09-24 09:34:00 +0000660//sys Select(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timeval) (n int, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700661//sysnb Setegid(egid int) (err error)
662//sysnb Seteuid(euid int) (err error)
663//sysnb Setgid(gid int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700664//sys Sethostname(p []byte) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700665//sysnb Setpgid(pid int, pgid int) (err error)
666//sys Setpriority(which int, who int, prio int) (err error)
667//sysnb Setregid(rgid int, egid int) (err error)
668//sysnb Setreuid(ruid int, euid int) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700669//sysnb Setsid() (pid int, err error)
670//sysnb Setuid(uid int) (err error)
671//sys Shutdown(s int, how int) (err error) = libsocket.shutdown
672//sys Stat(path string, stat *Stat_t) (err error)
Sean Chittenden1e99a4f2017-05-14 12:20:32 -0700673//sys Statvfs(path string, vfsstat *Statvfs_t) (err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700674//sys Symlink(path string, link string) (err error)
675//sys Sync() (err error)
Tobias Klauser21e18002021-01-26 12:31:59 +0000676//sys Sysconf(which int) (n int64, err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700677//sysnb Times(tms *Tms) (ticks uintptr, err error)
Rob Pike20acc5c2014-08-11 14:48:46 -0700678//sys Truncate(path string, length int64) (err error)
679//sys Fsync(fd int) (err error)
680//sys Ftruncate(fd int, length int64) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700681//sys Umask(mask int) (oldmask int)
682//sysnb Uname(buf *Utsname) (err error)
683//sys Unmount(target string, flags int) (err error) = libc.umount
Rob Pike20acc5c2014-08-11 14:48:46 -0700684//sys Unlink(path string) (err error)
Ian Lance Tayloreb2c7412016-01-26 17:36:05 -0800685//sys Unlinkat(dirfd int, path string, flags int) (err error)
Shawn Walker-Salas68a71b62015-09-16 13:48:56 -0700686//sys Ustat(dev int, ubuf *Ustat_t) (err error)
687//sys Utime(path string, buf *Utimbuf) (err error)
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900688//sys bind(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_bind
689//sys connect(s int, addr unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_connect
Rob Pike20acc5c2014-08-11 14:48:46 -0700690//sys mmap(addr uintptr, length uintptr, prot int, flag int, fd int, pos int64) (ret uintptr, err error)
691//sys munmap(addr uintptr, length uintptr) (err error)
Tobias Klauser2de20672018-03-29 12:10:40 +0000692//sys sendfile(outfd int, infd int, offset *int64, count int) (written int, err error) = libsendfile.sendfile
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900693//sys sendto(s int, buf []byte, flags int, to unsafe.Pointer, addrlen _Socklen) (err error) = libsocket.__xnet_sendto
694//sys socket(domain int, typ int, proto int) (fd int, err error) = libsocket.__xnet_socket
695//sysnb socketpair(domain int, typ int, proto int, fd *[2]int32) (err error) = libsocket.__xnet_socketpair
Rob Pike20acc5c2014-08-11 14:48:46 -0700696//sys write(fd int, p []byte) (n int, err error)
Mikio Hara9c9d83f2017-05-06 10:47:39 +0900697//sys getsockopt(s int, level int, name int, val unsafe.Pointer, vallen *_Socklen) (err error) = libsocket.__xnet_getsockopt
Rob Pike20acc5c2014-08-11 14:48:46 -0700698//sysnb getpeername(fd int, rsa *RawSockaddrAny, addrlen *_Socklen) (err error) = libsocket.getpeername
Rob Pike20acc5c2014-08-11 14:48:46 -0700699//sys setsockopt(s int, level int, name int, val unsafe.Pointer, vallen uintptr) (err error) = libsocket.setsockopt
700//sys recvfrom(fd int, p []byte, flags int, from *RawSockaddrAny, fromlen *_Socklen) (n int, err error) = libsocket.recvfrom
Rob Pike20acc5c2014-08-11 14:48:46 -0700701
Nahum Shalman13f9c582021-06-03 01:39:59 +0000702// Event Ports
703
704type fileObjCookie struct {
705 fobj *fileObj
706 cookie interface{}
707}
708
709// EventPort provides a safe abstraction on top of Solaris/illumos Event Ports.
710type EventPort struct {
711 port int
712 mu sync.Mutex
Nahum Shalman594fa532022-01-21 02:04:56 +0000713 fds map[uintptr]*fileObjCookie
Nahum Shalman13f9c582021-06-03 01:39:59 +0000714 paths map[string]*fileObjCookie
Nahum Shalman594fa532022-01-21 02:04:56 +0000715 // The user cookie presents an interesting challenge from a memory management perspective.
716 // There are two paths by which we can discover that it is no longer in use:
717 // 1. The user calls port_dissociate before any events fire
718 // 2. An event fires and we return it to the user
719 // The tricky situation is if the event has fired in the kernel but
720 // the user hasn't requested/received it yet.
721 // If the user wants to port_dissociate before the event has been processed,
722 // we should handle things gracefully. To do so, we need to keep an extra
723 // reference to the cookie around until the event is processed
724 // thus the otherwise seemingly extraneous "cookies" map
Nahum Shalman27713092022-08-10 02:07:30 +0000725 // The key of this map is a pointer to the corresponding fCookie
726 cookies map[*fileObjCookie]struct{}
Nahum Shalman13f9c582021-06-03 01:39:59 +0000727}
728
729// PortEvent is an abstraction of the port_event C struct.
730// Compare Source against PORT_SOURCE_FILE or PORT_SOURCE_FD
731// to see if Path or Fd was the event source. The other will be
732// uninitialized.
733type PortEvent struct {
734 Cookie interface{}
735 Events int32
736 Fd uintptr
737 Path string
738 Source uint16
739 fobj *fileObj
740}
741
742// NewEventPort creates a new EventPort including the
743// underlying call to port_create(3c).
744func NewEventPort() (*EventPort, error) {
745 port, err := port_create()
746 if err != nil {
747 return nil, err
748 }
749 e := &EventPort{
Nahum Shalman594fa532022-01-21 02:04:56 +0000750 port: port,
751 fds: make(map[uintptr]*fileObjCookie),
752 paths: make(map[string]*fileObjCookie),
Nahum Shalman27713092022-08-10 02:07:30 +0000753 cookies: make(map[*fileObjCookie]struct{}),
Nahum Shalman13f9c582021-06-03 01:39:59 +0000754 }
755 return e, nil
756}
757
758//sys port_create() (n int, err error)
759//sys port_associate(port int, source int, object uintptr, events int, user *byte) (n int, err error)
760//sys port_dissociate(port int, source int, object uintptr) (n int, err error)
761//sys port_get(port int, pe *portEvent, timeout *Timespec) (n int, err error)
762//sys port_getn(port int, pe *portEvent, max uint32, nget *uint32, timeout *Timespec) (n int, err error)
763
764// Close closes the event port.
765func (e *EventPort) Close() error {
766 e.mu.Lock()
767 defer e.mu.Unlock()
Nahum Shalman594fa532022-01-21 02:04:56 +0000768 err := Close(e.port)
769 if err != nil {
770 return err
771 }
Nahum Shalman13f9c582021-06-03 01:39:59 +0000772 e.fds = nil
773 e.paths = nil
Nahum Shalman27713092022-08-10 02:07:30 +0000774 e.cookies = nil
Nahum Shalman594fa532022-01-21 02:04:56 +0000775 return nil
Nahum Shalman13f9c582021-06-03 01:39:59 +0000776}
777
778// PathIsWatched checks to see if path is associated with this EventPort.
779func (e *EventPort) PathIsWatched(path string) bool {
780 e.mu.Lock()
781 defer e.mu.Unlock()
782 _, found := e.paths[path]
783 return found
784}
785
786// FdIsWatched checks to see if fd is associated with this EventPort.
787func (e *EventPort) FdIsWatched(fd uintptr) bool {
788 e.mu.Lock()
789 defer e.mu.Unlock()
790 _, found := e.fds[fd]
791 return found
792}
793
794// AssociatePath wraps port_associate(3c) for a filesystem path including
795// creating the necessary file_obj from the provided stat information.
796func (e *EventPort) AssociatePath(path string, stat os.FileInfo, events int, cookie interface{}) error {
797 e.mu.Lock()
798 defer e.mu.Unlock()
799 if _, found := e.paths[path]; found {
800 return fmt.Errorf("%v is already associated with this Event Port", path)
801 }
Nahum Shalman27713092022-08-10 02:07:30 +0000802 fCookie, err := createFileObjCookie(path, stat, cookie)
Nahum Shalman13f9c582021-06-03 01:39:59 +0000803 if err != nil {
804 return err
805 }
Nahum Shalman27713092022-08-10 02:07:30 +0000806 _, err = port_associate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(fCookie.fobj)), events, (*byte)(unsafe.Pointer(fCookie)))
Nahum Shalman13f9c582021-06-03 01:39:59 +0000807 if err != nil {
808 return err
809 }
810 e.paths[path] = fCookie
Nahum Shalman27713092022-08-10 02:07:30 +0000811 e.cookies[fCookie] = struct{}{}
Nahum Shalman13f9c582021-06-03 01:39:59 +0000812 return nil
813}
814
815// DissociatePath wraps port_dissociate(3c) for a filesystem path.
816func (e *EventPort) DissociatePath(path string) error {
817 e.mu.Lock()
818 defer e.mu.Unlock()
819 f, ok := e.paths[path]
820 if !ok {
821 return fmt.Errorf("%v is not associated with this Event Port", path)
822 }
823 _, err := port_dissociate(e.port, PORT_SOURCE_FILE, uintptr(unsafe.Pointer(f.fobj)))
Nahum Shalman594fa532022-01-21 02:04:56 +0000824 // If the path is no longer associated with this event port (ENOENT)
825 // we should delete it from our map. We can still return ENOENT to the caller.
826 // But we need to save the cookie
827 if err != nil && err != ENOENT {
Nahum Shalman13f9c582021-06-03 01:39:59 +0000828 return err
829 }
Nahum Shalman594fa532022-01-21 02:04:56 +0000830 if err == nil {
831 // dissociate was successful, safe to delete the cookie
832 fCookie := e.paths[path]
Nahum Shalman27713092022-08-10 02:07:30 +0000833 delete(e.cookies, fCookie)
Nahum Shalman594fa532022-01-21 02:04:56 +0000834 }
Nahum Shalman13f9c582021-06-03 01:39:59 +0000835 delete(e.paths, path)
Nahum Shalman594fa532022-01-21 02:04:56 +0000836 return err
Nahum Shalman13f9c582021-06-03 01:39:59 +0000837}
838
839// AssociateFd wraps calls to port_associate(3c) on file descriptors.
840func (e *EventPort) AssociateFd(fd uintptr, events int, cookie interface{}) error {
841 e.mu.Lock()
842 defer e.mu.Unlock()
843 if _, found := e.fds[fd]; found {
844 return fmt.Errorf("%v is already associated with this Event Port", fd)
845 }
Nahum Shalman27713092022-08-10 02:07:30 +0000846 fCookie, err := createFileObjCookie("", nil, cookie)
847 if err != nil {
848 return err
849 }
850 _, err = port_associate(e.port, PORT_SOURCE_FD, fd, events, (*byte)(unsafe.Pointer(fCookie)))
Nahum Shalman13f9c582021-06-03 01:39:59 +0000851 if err != nil {
852 return err
853 }
Nahum Shalman594fa532022-01-21 02:04:56 +0000854 e.fds[fd] = fCookie
Nahum Shalman27713092022-08-10 02:07:30 +0000855 e.cookies[fCookie] = struct{}{}
Nahum Shalman13f9c582021-06-03 01:39:59 +0000856 return nil
857}
858
859// DissociateFd wraps calls to port_dissociate(3c) on file descriptors.
860func (e *EventPort) DissociateFd(fd uintptr) error {
861 e.mu.Lock()
862 defer e.mu.Unlock()
863 _, ok := e.fds[fd]
864 if !ok {
865 return fmt.Errorf("%v is not associated with this Event Port", fd)
866 }
867 _, err := port_dissociate(e.port, PORT_SOURCE_FD, fd)
Nahum Shalman594fa532022-01-21 02:04:56 +0000868 if err != nil && err != ENOENT {
Nahum Shalman13f9c582021-06-03 01:39:59 +0000869 return err
870 }
Nahum Shalman594fa532022-01-21 02:04:56 +0000871 if err == nil {
872 // dissociate was successful, safe to delete the cookie
873 fCookie := e.fds[fd]
Nahum Shalman27713092022-08-10 02:07:30 +0000874 delete(e.cookies, fCookie)
Nahum Shalman594fa532022-01-21 02:04:56 +0000875 }
Nahum Shalman13f9c582021-06-03 01:39:59 +0000876 delete(e.fds, fd)
Nahum Shalman594fa532022-01-21 02:04:56 +0000877 return err
Nahum Shalman13f9c582021-06-03 01:39:59 +0000878}
879
Nahum Shalman27713092022-08-10 02:07:30 +0000880func createFileObjCookie(name string, stat os.FileInfo, cookie interface{}) (*fileObjCookie, error) {
881 fCookie := new(fileObjCookie)
882 fCookie.cookie = cookie
883 if name != "" && stat != nil {
884 fCookie.fobj = new(fileObj)
885 bs, err := ByteSliceFromString(name)
886 if err != nil {
887 return nil, err
888 }
889 fCookie.fobj.Name = (*int8)(unsafe.Pointer(&bs[0]))
890 s := stat.Sys().(*syscall.Stat_t)
891 fCookie.fobj.Atim.Sec = s.Atim.Sec
892 fCookie.fobj.Atim.Nsec = s.Atim.Nsec
893 fCookie.fobj.Mtim.Sec = s.Mtim.Sec
894 fCookie.fobj.Mtim.Nsec = s.Mtim.Nsec
895 fCookie.fobj.Ctim.Sec = s.Ctim.Sec
896 fCookie.fobj.Ctim.Nsec = s.Ctim.Nsec
Nahum Shalman13f9c582021-06-03 01:39:59 +0000897 }
Nahum Shalman27713092022-08-10 02:07:30 +0000898 return fCookie, nil
Nahum Shalman13f9c582021-06-03 01:39:59 +0000899}
900
901// GetOne wraps port_get(3c) and returns a single PortEvent.
902func (e *EventPort) GetOne(t *Timespec) (*PortEvent, error) {
903 pe := new(portEvent)
904 _, err := port_get(e.port, pe, t)
905 if err != nil {
906 return nil, err
907 }
908 p := new(PortEvent)
Nahum Shalman13f9c582021-06-03 01:39:59 +0000909 e.mu.Lock()
910 defer e.mu.Unlock()
Nahum Shalman27713092022-08-10 02:07:30 +0000911 err = e.peIntToExt(pe, p)
912 if err != nil {
913 return nil, err
914 }
Nahum Shalman13f9c582021-06-03 01:39:59 +0000915 return p, nil
916}
917
Nahum Shalman594fa532022-01-21 02:04:56 +0000918// peIntToExt converts a cgo portEvent struct into the friendlier PortEvent
919// NOTE: Always call this function while holding the e.mu mutex
Nahum Shalman27713092022-08-10 02:07:30 +0000920func (e *EventPort) peIntToExt(peInt *portEvent, peExt *PortEvent) error {
921 if e.cookies == nil {
922 return fmt.Errorf("this EventPort is already closed")
923 }
Nahum Shalman594fa532022-01-21 02:04:56 +0000924 peExt.Events = peInt.Events
925 peExt.Source = peInt.Source
Nahum Shalman27713092022-08-10 02:07:30 +0000926 fCookie := (*fileObjCookie)(unsafe.Pointer(peInt.User))
927 _, found := e.cookies[fCookie]
928
929 if !found {
930 panic("unexpected event port address; may be due to kernel bug; see https://go.dev/issue/54254")
931 }
932 peExt.Cookie = fCookie.cookie
933 delete(e.cookies, fCookie)
934
Nahum Shalman594fa532022-01-21 02:04:56 +0000935 switch peInt.Source {
936 case PORT_SOURCE_FD:
Nahum Shalman594fa532022-01-21 02:04:56 +0000937 peExt.Fd = uintptr(peInt.Object)
938 // Only remove the fds entry if it exists and this cookie matches
939 if fobj, ok := e.fds[peExt.Fd]; ok {
Nahum Shalman27713092022-08-10 02:07:30 +0000940 if fobj == fCookie {
Nahum Shalman594fa532022-01-21 02:04:56 +0000941 delete(e.fds, peExt.Fd)
942 }
943 }
944 case PORT_SOURCE_FILE:
Nahum Shalman27713092022-08-10 02:07:30 +0000945 peExt.fobj = fCookie.fobj
Nahum Shalman594fa532022-01-21 02:04:56 +0000946 peExt.Path = BytePtrToString((*byte)(unsafe.Pointer(peExt.fobj.Name)))
947 // Only remove the paths entry if it exists and this cookie matches
948 if fobj, ok := e.paths[peExt.Path]; ok {
Nahum Shalman27713092022-08-10 02:07:30 +0000949 if fobj == fCookie {
Nahum Shalman594fa532022-01-21 02:04:56 +0000950 delete(e.paths, peExt.Path)
951 }
952 }
953 }
Nahum Shalman27713092022-08-10 02:07:30 +0000954 return nil
Nahum Shalman594fa532022-01-21 02:04:56 +0000955}
956
Nahum Shalman13f9c582021-06-03 01:39:59 +0000957// Pending wraps port_getn(3c) and returns how many events are pending.
958func (e *EventPort) Pending() (int, error) {
959 var n uint32 = 0
960 _, err := port_getn(e.port, nil, 0, &n, nil)
961 return int(n), err
962}
963
964// Get wraps port_getn(3c) and fills a slice of PortEvent.
965// It will block until either min events have been received
966// or the timeout has been exceeded. It will return how many
967// events were actually received along with any error information.
968func (e *EventPort) Get(s []PortEvent, min int, timeout *Timespec) (int, error) {
969 if min == 0 {
970 return 0, fmt.Errorf("need to request at least one event or use Pending() instead")
971 }
972 if len(s) < min {
973 return 0, fmt.Errorf("len(s) (%d) is less than min events requested (%d)", len(s), min)
974 }
975 got := uint32(min)
976 max := uint32(len(s))
977 var err error
Nahum Shalman27713092022-08-10 02:07:30 +0000978 ps := make([]portEvent, max)
Nahum Shalman13f9c582021-06-03 01:39:59 +0000979 _, err = port_getn(e.port, &ps[0], max, &got, timeout)
980 // got will be trustworthy with ETIME, but not any other error.
981 if err != nil && err != ETIME {
982 return 0, err
983 }
984 e.mu.Lock()
985 defer e.mu.Unlock()
Nahum Shalman27713092022-08-10 02:07:30 +0000986 valid := 0
Nahum Shalman13f9c582021-06-03 01:39:59 +0000987 for i := 0; i < int(got); i++ {
Nahum Shalman27713092022-08-10 02:07:30 +0000988 err2 := e.peIntToExt(&ps[i], &s[i])
989 if err2 != nil {
990 if valid == 0 && err == nil {
991 // If err2 is the only error and there are no valid events
992 // to return, return it to the caller.
993 err = err2
994 }
995 break
996 }
997 valid = i + 1
Nahum Shalman13f9c582021-06-03 01:39:59 +0000998 }
Nahum Shalman27713092022-08-10 02:07:30 +0000999 return valid, err
Nahum Shalman13f9c582021-06-03 01:39:59 +00001000}
Nahum Shalman68d869b2022-10-02 15:02:33 +00001001
1002//sys putmsg(fd int, clptr *strbuf, dataptr *strbuf, flags int) (err error)
1003
1004func Putmsg(fd int, cl []byte, data []byte, flags int) (err error) {
1005 var clp, datap *strbuf
1006 if len(cl) > 0 {
1007 clp = &strbuf{
1008 Len: int32(len(cl)),
1009 Buf: (*int8)(unsafe.Pointer(&cl[0])),
1010 }
1011 }
1012 if len(data) > 0 {
1013 datap = &strbuf{
1014 Len: int32(len(data)),
1015 Buf: (*int8)(unsafe.Pointer(&data[0])),
1016 }
1017 }
1018 return putmsg(fd, clp, datap, flags)
1019}
1020
1021//sys getmsg(fd int, clptr *strbuf, dataptr *strbuf, flags *int) (err error)
1022
1023func Getmsg(fd int, cl []byte, data []byte) (retCl []byte, retData []byte, flags int, err error) {
1024 var clp, datap *strbuf
1025 if len(cl) > 0 {
1026 clp = &strbuf{
1027 Maxlen: int32(len(cl)),
1028 Buf: (*int8)(unsafe.Pointer(&cl[0])),
1029 }
1030 }
1031 if len(data) > 0 {
1032 datap = &strbuf{
1033 Maxlen: int32(len(data)),
1034 Buf: (*int8)(unsafe.Pointer(&data[0])),
1035 }
1036 }
1037
1038 if err = getmsg(fd, clp, datap, &flags); err != nil {
1039 return nil, nil, 0, err
1040 }
1041
1042 if len(cl) > 0 {
1043 retCl = cl[:clp.Len]
1044 }
1045 if len(data) > 0 {
1046 retData = data[:datap.Len]
1047 }
1048 return retCl, retData, flags, nil
1049}
1050
Jason A. Donenfeld00d80042023-03-15 17:52:25 +01001051func IoctlSetIntRetInt(fd int, req int, arg int) (int, error) {
Nahum Shalman68d869b2022-10-02 15:02:33 +00001052 return ioctlRet(fd, req, uintptr(arg))
1053}
1054
Jason A. Donenfeld00d80042023-03-15 17:52:25 +01001055func IoctlSetString(fd int, req int, val string) error {
Nahum Shalman68d869b2022-10-02 15:02:33 +00001056 bs := make([]byte, len(val)+1)
1057 copy(bs[:len(bs)-1], val)
Dmitri Goutnik10499f42023-02-24 10:27:54 -05001058 err := ioctlPtr(fd, req, unsafe.Pointer(&bs[0]))
Nahum Shalman68d869b2022-10-02 15:02:33 +00001059 runtime.KeepAlive(&bs[0])
1060 return err
1061}
1062
1063// Lifreq Helpers
1064
1065func (l *Lifreq) SetName(name string) error {
1066 if len(name) >= len(l.Name) {
1067 return fmt.Errorf("name cannot be more than %d characters", len(l.Name)-1)
1068 }
1069 for i := range name {
1070 l.Name[i] = int8(name[i])
1071 }
1072 return nil
1073}
1074
1075func (l *Lifreq) SetLifruInt(d int) {
1076 *(*int)(unsafe.Pointer(&l.Lifru[0])) = d
1077}
1078
1079func (l *Lifreq) GetLifruInt() int {
1080 return *(*int)(unsafe.Pointer(&l.Lifru[0]))
1081}
1082
1083func (l *Lifreq) SetLifruUint(d uint) {
1084 *(*uint)(unsafe.Pointer(&l.Lifru[0])) = d
1085}
1086
1087func (l *Lifreq) GetLifruUint() uint {
1088 return *(*uint)(unsafe.Pointer(&l.Lifru[0]))
1089}
1090
Jason A. Donenfeld00d80042023-03-15 17:52:25 +01001091func IoctlLifreq(fd int, req int, l *Lifreq) error {
Dmitri Goutnik10499f42023-02-24 10:27:54 -05001092 return ioctlPtr(fd, req, unsafe.Pointer(l))
Nahum Shalman68d869b2022-10-02 15:02:33 +00001093}
1094
1095// Strioctl Helpers
1096
1097func (s *Strioctl) SetInt(i int) {
1098 s.Len = int32(unsafe.Sizeof(i))
1099 s.Dp = (*int8)(unsafe.Pointer(&i))
1100}
1101
Jason A. Donenfeld00d80042023-03-15 17:52:25 +01001102func IoctlSetStrioctlRetInt(fd int, req int, s *Strioctl) (int, error) {
Dmitri Goutnik10499f42023-02-24 10:27:54 -05001103 return ioctlPtrRet(fd, req, unsafe.Pointer(s))
Nahum Shalman68d869b2022-10-02 15:02:33 +00001104}