1// Copyright 2014 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//go:build dragonfly || freebsd || linux || solaris
6
7package rand
8
9import (
10	"internal/syscall/unix"
11	"runtime"
12	"syscall"
13)
14
15func init() {
16	var maxGetRandomRead int
17	switch runtime.GOOS {
18	case "linux", "android":
19		// Per the manpage:
20		//     When reading from the urandom source, a maximum of 33554431 bytes
21		//     is returned by a single call to getrandom() on systems where int
22		//     has a size of 32 bits.
23		maxGetRandomRead = (1 << 25) - 1
24	case "dragonfly", "freebsd", "illumos", "solaris":
25		maxGetRandomRead = 1 << 8
26	default:
27		panic("no maximum specified for GetRandom")
28	}
29	altGetRandom = batched(getRandom, maxGetRandomRead)
30}
31
32// If the kernel is too old to support the getrandom syscall(),
33// unix.GetRandom will immediately return ENOSYS and we will then fall back to
34// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
35// result so we only suffer the syscall overhead once in this case.
36// If the kernel supports the getrandom() syscall, unix.GetRandom will block
37// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
38// In this case, unix.GetRandom will not return an error.
39func getRandom(p []byte) error {
40	n, err := unix.GetRandom(p, 0)
41	if err != nil {
42		return err
43	}
44	if n != len(p) {
45		return syscall.EIO
46	}
47	return nil
48}
49