diff --git a/Changes b/Changes index 509dbf0..41dd7a1 100644 --- a/Changes +++ b/Changes @@ -1,3 +1,11 @@ +0.08 + - Fix Proc handles on Perl 5.8. +0.07 + - Switch to using Capture::Tiny for Proc.pm, for Windows + support. + - Prevent a warning from Handle.pm during global destruction. + - Make Crypt::Random::Source work properly in taint mode. + 0.06 - Use Any::Moose to allow either Moose or Mouse. - Switch to dzil. diff --git a/dist.ini b/dist.ini index cc1702f..bd68487 100644 --- a/dist.ini +++ b/dist.ini @@ -1,5 +1,5 @@ name = Crypt-Random-Source -version = 0.06 +version = 0.08 author = Yuval Kogman license = Perl_5 copyright_holder = Yuval Kogman @@ -16,3 +16,4 @@ repository_at = github [Prereqs] Any::Moose = 0.11 namespace::clean = 0.08 +Capture::Tiny = 0.08 diff --git a/lib/Crypt/Random/Source/Base/Handle.pm b/lib/Crypt/Random/Source/Base/Handle.pm index 5f4d981..f6fd780 100644 --- a/lib/Crypt/Random/Source/Base/Handle.pm +++ b/lib/Crypt/Random/Source/Base/Handle.pm @@ -85,8 +85,10 @@ sub _read_too_short { sub close { my $self = shift; - if ( $self->has_handle ) { - $self->handle->close; # or die "close: $!"; # open "-|" returns exit status on close + # During global destruction, $self->handle can be undef already, + # so we need to also check if it is defined. + if ( $self->has_handle and $self->handle ) { + $self->handle->close or die "close: $!"; $self->clear_handle; } } diff --git a/lib/Crypt/Random/Source/Base/Proc.pm b/lib/Crypt/Random/Source/Base/Proc.pm index 41f261f..2041e50 100644 --- a/lib/Crypt/Random/Source/Base/Proc.pm +++ b/lib/Crypt/Random/Source/Base/Proc.pm @@ -5,22 +5,47 @@ use Any::Moose; extends qw(Crypt::Random::Source::Base::Handle); -use IO::Handle; +use Capture::Tiny qw(capture); +use File::Spec; +use IO::File; use 5.008; has command => ( is => "rw", required => 1 ); +has search_path => ( is => 'rw', isa => 'Str', lazy_build => 1 ); + +# This is a scalar so that people can customize it (which they would +# particularly need to do on Windows). +our $TAINT_PATH = + '/usr/local/bin:/usr/bin:/bin:/usr/local/sbin:/usr/sbin:/sbin'; + +sub _build_search_path { + # In taint mode it's not safe to use $ENV{PATH}. + if (${^TAINT}) { + return $TAINT_PATH; + } + return $ENV{PATH}; +} sub open_handle { my $self = shift; my $cmd = $self->command; my @cmd = ref $cmd ? @$cmd : $cmd; - - open my $fh, "-|", @cmd - or die "open(@cmd|): $!"; - - bless $fh, "IO::Handle"; + my $retval; + local $ENV{PATH} = $self->search_path; + my ($stdout, $stderr) = capture { $retval = system(@cmd) }; + chomp($stderr); + if ($retval) { + my $err = join(' ', @cmd) . ": $! ($?)"; + if ($stderr) { + $err .= "\n$stderr"; + } + die $err; + } + warn $stderr if $stderr; + + open(my $fh, '<', \$stdout) || die $!; return $fh; } diff --git a/lib/Crypt/Random/Source/Factory.pm b/lib/Crypt/Random/Source/Factory.pm index ee3ae0c..e4723bc 100644 --- a/lib/Crypt/Random/Source/Factory.pm +++ b/lib/Crypt/Random/Source/Factory.pm @@ -146,7 +146,11 @@ sub first_available { sub locate_sources { my ( $self, $category ) = @_; - [ findsubmod "Crypt::Random::Source::$category" ]; + my @sources = findsubmod "Crypt::Random::Source::$category"; + # Untaint class names (which are tainted in taint mode because + # they came from the disk). + ($_) = $_ =~ /^(.*)$/ foreach @sources; + return \@sources; } 1; diff --git a/t/blocking.t b/t/blocking.t index 415c483..4808bbe 100644 --- a/t/blocking.t +++ b/t/blocking.t @@ -3,7 +3,7 @@ use strict; use warnings; -use Test::More 'no_plan'; +use Test::More tests => 3; use 5.008; @@ -12,9 +12,8 @@ use IO::Select; use ok 'Crypt::Random::Source::Base::Handle'; -{ - my ( $reader, $writer ) = map { IO::Handle->new } 1 .. 2; - +SKIP: { + skip "Windows can't open a blocking child pipe", 2 if $^O =~ /Win32/i; defined ( my $child = open my $fh, "-|" ) or die "open: $!"; if ($child) {