github.com/mvdan/u-root-coreutils@v0.0.0-20230122170626-c2eef2898555/pkg/rand/random_urandom.go (about) 1 // Copyright 2019 the u-root 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 aix || darwin || dragonfly || freebsd || nacl || netbsd || openbsd || solaris || linux 6 // +build aix darwin dragonfly freebsd nacl netbsd openbsd solaris linux 7 8 package rand 9 10 import ( 11 "context" 12 "fmt" 13 "sync" 14 "syscall" 15 16 "golang.org/x/sys/unix" 17 ) 18 19 // urandomReader is a contextReader. 20 type urandomReader struct { 21 once sync.Once 22 23 // fd is expected to be non-blocking. 24 fd int 25 } 26 27 func (r *urandomReader) init() error { 28 var realErr error 29 r.once.Do(func() { 30 fd, err := unix.Open("/dev/urandom", unix.O_RDONLY, 0) 31 if err != nil { 32 realErr = fmt.Errorf("open(/dev/urandom): %v", err) 33 return 34 } 35 r.fd = fd 36 }) 37 return realErr 38 } 39 40 // ReadContext implements a cancelable read from /dev/urandom. 41 func (r *urandomReader) ReadContext(ctx context.Context, b []byte) (int, error) { 42 if err := r.init(); err != nil { 43 return 0, err 44 } 45 for { 46 n, err := unix.Read(r.fd, b) 47 if err == nil { 48 return n, err 49 } 50 select { 51 case <-ctx.Done(): 52 return 0, ctx.Err() 53 54 default: 55 if err != nil && err != syscall.EAGAIN && err != syscall.EINTR { 56 return n, err 57 } 58 } 59 } 60 }