The following code snippet provides a crude timer mechanism for file read failures, somewhat along the lines of what
Re: Redirecting stdout/stderr to pipe achieves for commands. The real code will run on
many systems and I deem the timeout as necessary, although I know read failures are uncommon.
I eliminated the use of sysread+select due to the fact that I need @$outref populated line-by-line (whereas sysread uses buffers). I also do not have any real ideas on encoding. Can anyone make any improvement suggestions or is this ok?
Niel
UPDATE: fixed an endless loop in the example.
#!/usr/bin/perl -w
use strict;
use IO::Select;
use Symbol qw(gensym);
my $g_verbose = 1;
my $g_pid;
my $g_stop;
my $g_timeout = 2; #for test purposes
my $g_did_run;
my $g_max_cmd_size = 2_000_000;
my $g_max_file_size = 2_000_000;
my %g_pids;
sub read_stat($$$) {
my ($file,$rcref,$statref) = @_;
@$statref = stat($file);
if ( $#$statref < 0 ) {
print "Stat of file '$file' failed: $!\n";
$$rcref = 1;
} else {
$$rcref = 0;
}
return $$rcref;
}
sub read_file($$$$$) {
my ($file,$encoding,$rcref,$outref,$statref) = @_;
@$outref = ();
my $outbytes = 0;
$g_stop = 0;
# die if timeout occurs!
local $SIG{ALRM} = sub {
print "File \'$file\' collection reached deadline after $g_timeo
+ut secs.\n";
die "Exiting - a read operation timed out!\n";
$g_stop = 1;
};
alarm($g_timeout);
if ( !defined($encoding) ) {
$encoding = 'text/plain';
}
if ( $encoding ne 'text/plain' ) {
print "Error: Can't collect file '$file' - '$encoding' encoding
+is not supported.\n";
$$rcref = -2;
return $$rcref;
}
if ( $g_verbose ) {
print "Collecting '$file'.\n";
}
read_stat($file,$rcref,$statref);
if ( $$rcref != 0 ) {
return undef;
}
if ( !open(IFILE,"<$file") ) {
print "Open of file '$file' failed: $!\n";
return undef;
}
# read data into @$outref (line by line). alarm prevents timeout.
while (!$g_stop) {
last if (eof(IFILE));
my $line = <IFILE>;
chomp $line;
push @$outref, $line;
# for test purposes - make it timeout!
sleep 5;
$outbytes += length($line);
if ($outbytes >= $g_max_file_size) {
print "Maximum file size reached after $outbytes bytes\n";
last;
alarm(0);
close(IFILE);
if (!$g_stop) {
$$rcref = 0;
} else {
$$rcref = -1;
}
return $$rcref;
}
#MAIN
my $file = '/etc/hosts';
my $encoding = 'text/plain';
my $rc;
my (@cmdout,@stat);
$rc = read_file($file,$encoding,\$rc,\@cmdout,\@stat);
print "Collected $file (rc=$rc)\n";