66
|
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 }
|