| // Copyright 2023 The Go Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style |
| // license that can be found in the LICENSE file. |
| |
| package unix |
| |
| import ( |
| "sync" |
| "sync/atomic" |
| "syscall" |
| "unsafe" |
| ) |
| |
| // NetBSD getrandom system call number. |
| const getrandomTrap uintptr = 91 |
| |
| var getrandomUnsupported atomic.Bool |
| |
| // GetRandomFlag is a flag supported by the getrandom system call. |
| type GetRandomFlag uintptr |
| |
| // GetRandom calls the getrandom system call. |
| func GetRandom(p []byte, flags GetRandomFlag) (n int, err error) { |
| if len(p) == 0 { |
| return 0, nil |
| } |
| if getrandomUnsupported.Load() { |
| return 0, syscall.ENOSYS |
| } |
| // getrandom(2) was added in NetBSD 10.0 |
| if getOSRevision() < 1000000000 { |
| getrandomUnsupported.Store(true) |
| return 0, syscall.ENOSYS |
| } |
| r1, _, errno := syscall.Syscall(getrandomTrap, |
| uintptr(unsafe.Pointer(&p[0])), |
| uintptr(len(p)), |
| uintptr(flags)) |
| if errno != 0 { |
| if errno == syscall.ENOSYS { |
| getrandomUnsupported.Store(true) |
| } |
| return 0, errno |
| } |
| return int(r1), nil |
| } |
| |
| var ( |
| osrevisionOnce sync.Once |
| osrevision uint32 |
| ) |
| |
| func getOSRevision() uint32 { |
| osrevisionOnce.Do(func() { osrevision, _ = syscall.SysctlUint32("kern.osrevision") }) |
| return osrevision |
| } |