File Coverage

blib/lib/Sys/GetRandom/PP.pm
Criterion Covered Total %
statement 43 45 95.5
branch 8 14 57.1
condition 3 9 33.3
subroutine 8 8 100.0
pod 2 2 100.0
total 64 78 82.0


line stmt bran cond sub pod time code
1             package Sys::GetRandom::PP;
2 1     1   154125 use strict;
  1         2  
  1         27  
3 1     1   4 use warnings;
  1         5  
  1         37  
4              
5 1     1   4 use Exporter qw(import);
  1         1  
  1         23  
6 1     1   3 use Carp qw(croak);
  1         1  
  1         168  
7              
8 1         1 use constant do {
9 1         8 my %bits_getrandom = (
10             'dragonfly' => 550,
11             'freebsd' => 563,
12             'midnightbsd' => 563,
13             'netbsd' => 91,
14             'openbsd' => 7,
15             'solaris' => 126,
16              
17             'aarch64-linux' => 278,
18             'armv6l-linux' => 384,
19             'i686-linux' => 355,
20             'x86_64-linux' => 318,
21             );
22 1   33     5 my $getrandom = $bits_getrandom{$^O} || do {
23             require Config;
24             my ($arch) = $Config::Config{archname} =~ m{^([^\-]+-[^\-]+)};
25             $bits_getrandom{$arch} || die "Unsupported platform: $arch"
26             };
27             +{
28 1         73 _IS_OPENBSD => $^O eq 'openbsd',
29             _SYS_getrandom => $getrandom,
30             GRND_NONBLOCK => 1,
31             GRND_RANDOM => 2,
32             }
33 1     1   4 };
  1         1  
34             BEGIN {
35 1     1   375 require Errno if _IS_OPENBSD;
36             }
37              
38             our $VERSION = '0.09';
39              
40             our @EXPORT_OK = qw(
41             GRND_RANDOM
42             GRND_NONBLOCK
43             getrandom
44             random_bytes
45             );
46              
47             sub getrandom ($$;$$) {
48 21 50 33 21 1 149052 if (@_ < 2 || @_ > 4) {
49 0         0 croak 'Usage: ' . __PACKAGE__ . '::getrandom($buffer, $length, $flags = 0, $offset = 0)';
50             }
51 21         29 my $bufref = \$_[0];
52 21         38 my (undef, $length, $flags, $offset) = @_;
53 21         26 $length |= 0;
54 21         20 $flags |= 0;
55 21         23 $offset |= 0;
56 21         28 $$bufref .= '';
57              
58 21         30 my $realbuf = "\0" x $length;
59              
60 21         22 my $r;
61 21         17 if (_IS_OPENBSD) {
62             # validate, but ignore
63             if ($flags & ~(GRND_NONBLOCK | GRND_RANDOM)) {
64             $! = Errno::EINVAL;
65             return undef;
66             }
67             $r = syscall _SYS_getrandom, $realbuf, $length;
68             if ($r == -1) {
69             return undef;
70             }
71             $r = $length;
72             } else {
73 21         93 $r = syscall _SYS_getrandom, $realbuf, $length, $flags;
74 21 50       34 if ($r == -1) {
75 0         0 return undef;
76             }
77 21         29 substr($realbuf, $r) = '';
78             }
79              
80              
81 21         25 my $dlen = $offset - length $$bufref;
82 21 100       33 $$bufref .= "\0" x $dlen
83             if $dlen > 0;
84 21         27 substr($$bufref, $offset) = $realbuf;
85              
86 21         52 $r
87             }
88              
89             sub random_bytes {
90 1     1 1 519 my ($n) = @_;
91 1         3 $n |= 0;
92 1 50 33     6 $n >= 0 && $n <= 256
93             or croak "Argument to random_bytes() must be an integer between 0 and 256, not $n";
94 1 50       3 return '' if $n == 0;
95 1 50       3 defined(my $r = getrandom(my $buf, $n))
96             or die "Internal error: getrandom(\$buf, $n) failed: $!";
97 1 50       4 $r == $n
98             or die "Internal error: getrandom(\$buf, $n) returned $r";
99 1         5 $buf
100             }
101              
102             1
103             __END__