summaryrefslogtreecommitdiff
path: root/regress/sys/net/pf_divert/Proc.pm
diff options
context:
space:
mode:
Diffstat (limited to 'regress/sys/net/pf_divert/Proc.pm')
-rw-r--r--regress/sys/net/pf_divert/Proc.pm160
1 files changed, 160 insertions, 0 deletions
diff --git a/regress/sys/net/pf_divert/Proc.pm b/regress/sys/net/pf_divert/Proc.pm
new file mode 100644
index 00000000000..e2a4b20e5fd
--- /dev/null
+++ b/regress/sys/net/pf_divert/Proc.pm
@@ -0,0 +1,160 @@
+# $OpenBSD: Proc.pm,v 1.1.1.1 2013/06/03 05:06:38 bluhm Exp $
+
+# Copyright (c) 2010-2013 Alexander Bluhm <bluhm@openbsd.org>
+#
+# Permission to use, copy, modify, and distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+use strict;
+use warnings;
+
+package Proc;
+use Carp;
+use IO::File;
+use List::Util qw(first);
+use POSIX;
+use Time::HiRes qw(time alarm sleep);
+
+my %CHILDREN;
+
+BEGIN {
+ $SIG{TERM} = $SIG{INT} = sub {
+ my $sig = shift;
+ kill TERM => keys %CHILDREN;
+ $SIG{TERM} = $SIG{INT} = 'DEFAULT';
+ POSIX::raise($sig);
+ };
+}
+
+END {
+ kill TERM => keys %CHILDREN;
+ $SIG{TERM} = $SIG{INT} = 'DEFAULT';
+}
+
+sub new {
+ my $class = shift;
+ my $self = { @_ };
+ $self->{down} ||= $self->{alarm} ? "Alarm" : "Shutdown";
+ $self->{func} && ref($self->{func}) eq 'CODE'
+ or croak "$class func not given";
+ $self->{logfile}
+ or croak "$class log file not given";
+ open(my $fh, '>', $self->{logfile})
+ or die "$class log file $self->{logfile} create failed: $!";
+ $fh->autoflush;
+ $self->{log} = $fh;
+ return bless $self, $class;
+}
+
+sub run {
+ my $self = shift;
+
+ defined(my $pid = fork())
+ or die ref($self), " fork child failed";
+ if ($pid) {
+ $CHILDREN{$pid} = 1;
+ $self->{pid} = $pid;
+ return $self;
+ }
+ %CHILDREN = ();
+ $SIG{TERM} = $SIG{INT} = 'DEFAULT';
+ $SIG{__DIE__} = sub {
+ die @_ if $^S;
+ warn @_;
+ IO::Handle::flush(\*STDERR);
+ POSIX::_exit(255);
+ };
+ open(STDERR, '>&', $self->{log})
+ or die ref($self), " dup STDERR failed: $!";
+
+ $self->child();
+ print STDERR $self->{up}, "\n";
+ alarm($self->{alarm}) if $self->{alarm};
+ $self->{func}->($self);
+ print STDERR "Shutdown", "\n";
+ IO::Handle::flush(\*STDOUT);
+ IO::Handle::flush(\*STDERR);
+
+ POSIX::_exit(0);
+}
+
+sub wait {
+ my $self = shift;
+ my $flags = shift;
+
+ my $pid = $self->{pid}
+ or croak ref($self), " no child pid";
+ my $kid = waitpid($pid, $flags);
+ if ($kid > 0) {
+ my $status = $?;
+ my $code;
+ $code = "exit: ". WEXITSTATUS($?) if WIFEXITED($?);
+ $code = "signal: ". WTERMSIG($?) if WIFSIGNALED($?);
+ $code = "stop: ". WSTOPSIG($?) if WIFSTOPPED($?);
+ return wantarray ? ($kid, $status, $code) : $kid;
+ }
+ return $kid;
+}
+
+sub loggrep {
+ my $self = shift;
+ my($regex, $timeout) = @_;
+
+ my $end = time() + $timeout if $timeout;
+
+ do {
+ my($kid, $status, $code) = $self->wait(WNOHANG);
+ if ($self->{alarm} && $kid > 0 &&
+ WIFSIGNALED($status) && WTERMSIG($status) == 14 ) {
+ # child killed by SIGALRM as expected
+ print {$self->{log}} "Alarm", "\n";
+ } elsif ($kid > 0 && $status != 0) {
+ # child terminated with failure
+ die ref($self), " child status: $status $code";
+ }
+ open(my $fh, '<', $self->{logfile})
+ or die ref($self), " log file open failed: $!";
+ my $match = first { /$regex/ } <$fh>;
+ return $match if $match;
+ close($fh);
+ # pattern not found
+ if ($kid == 0) {
+ # child still running, wait for log data
+ sleep .1;
+ } else {
+ # child terminated, no new log data possible
+ return;
+ }
+ } while ($timeout and time() < $end);
+
+ return;
+}
+
+sub up {
+ my $self = shift;
+ my $timeout = shift || 10;
+ $self->loggrep(qr/$self->{up}/, $timeout)
+ or croak ref($self), " no $self->{up} in $self->{logfile} ".
+ "after $timeout seconds";
+ return $self;
+}
+
+sub down {
+ my $self = shift;
+ my $timeout = shift || 30;
+ $self->loggrep(qr/$self->{down}/, $timeout)
+ or croak ref($self), " no $self->{down} in $self->{logfile} ".
+ "after $timeout seconds";
+ return $self;
+}
+
+1;