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