Imported Upstream version 1.32
This commit is contained in:
		
							parent
							
								
									6a47d71615
								
							
						
					
					
						commit
						db065246e2
					
				
					 28 changed files with 6336 additions and 1832 deletions
				
			
		| 
						 | 
				
			
			@ -1,10 +0,0 @@
 | 
			
		|||
Directory contents:
 | 
			
		||||
 | 
			
		||||
-	lograte.sh [OPTIONS] <logfile>
 | 
			
		||||
	generates per minute stats for generic syslog files
 | 
			
		||||
 | 
			
		||||
-	request.sample
 | 
			
		||||
	a sample policy delegation request. you may test your postfwd config with
 | 
			
		||||
 	  postfwd -f <configfile> request.sample
 | 
			
		||||
 | 
			
		||||
by JPK
 | 
			
		||||
							
								
								
									
										342
									
								
								tools/hapolicy/hapolicy
									
										
									
									
									
										Executable file
									
								
							
							
						
						
									
										342
									
								
								tools/hapolicy/hapolicy
									
										
									
									
									
										Executable file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,342 @@
 | 
			
		|||
#!/usr/bin/perl -T -w
 | 
			
		||||
 | 
			
		||||
package hapolicy;
 | 
			
		||||
 | 
			
		||||
use strict;
 | 
			
		||||
use warnings;
 | 
			
		||||
use IO::Socket;
 | 
			
		||||
use Pod::Usage;
 | 
			
		||||
use Sys::Syslog qw(:DEFAULT setlogsock);
 | 
			
		||||
use Getopt::Long 2.25 qw(:config no_ignore_case bundling);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### PARAMETERS ###
 | 
			
		||||
 | 
			
		||||
# Program settings
 | 
			
		||||
our($NAME)                      = 'hapolicy';
 | 
			
		||||
our($VERSION)                   = '1.00';
 | 
			
		||||
our($DEFAULT)			= 'dunno';	# default action if no service available
 | 
			
		||||
our($TIMEOUT)			= '30';		# default service timeout
 | 
			
		||||
 | 
			
		||||
# remote server settings
 | 
			
		||||
# command-line: -s <name>=<ip>:<port>:<prio>:<weight>:<timeout>
 | 
			
		||||
our(%Servers)			= (
 | 
			
		||||
#	"GREY1"		=> {
 | 
			
		||||
#		ip		=> '10.0.0.1',		# ip address
 | 
			
		||||
#		port		=> '10031',		# tcp port
 | 
			
		||||
#		prio		=> '10',		# optional, lower wins
 | 
			
		||||
#		weight		=> '1',			# optional, for items with same prio (weighted round-robin), higher is better
 | 
			
		||||
#		timeout		=> '30',		# optional, query timeout in seconds
 | 
			
		||||
#	},
 | 
			
		||||
);
 | 
			
		||||
 | 
			
		||||
# Environment
 | 
			
		||||
$ENV{PATH}                      = '/bin:/usr/bin:/usr/local/bin';
 | 
			
		||||
$ENV{ENV}                       = '';
 | 
			
		||||
# Syslog options
 | 
			
		||||
our($syslog_name)               = $NAME;
 | 
			
		||||
our($syslog_facility)           = 'mail';
 | 
			
		||||
our($syslog_options)            = 'pid';
 | 
			
		||||
our($syslog_socktype)		= ( (defined $sys::Syslog::VERSION) and ($Sys::Syslog::VERSION ge '0.15') )
 | 
			
		||||
				? 'native'
 | 
			
		||||
				: (($^O eq 'solaris') ? 'inet' : 'unix');
 | 
			
		||||
use vars qw(%opt);
 | 
			
		||||
 | 
			
		||||
### MAIN ###
 | 
			
		||||
 | 
			
		||||
# get command-line
 | 
			
		||||
GetOptions (
 | 
			
		||||
	\%opt, 'service|s=s@', 'verbose|v', 'stdout|L', 'logging|l', 'default|d=s'
 | 
			
		||||
	) or pod2usage (-msg => "\nPlease see \"pod2text ".$NAME."\" for detailed instructions.\n", -verbose => 1);
 | 
			
		||||
setlogsock $syslog_socktype;
 | 
			
		||||
openlog $syslog_name, $syslog_options, $syslog_facility;
 | 
			
		||||
 | 
			
		||||
# check command-line
 | 
			
		||||
$DEFAULT = $opt{default} if defined $opt{default};
 | 
			
		||||
foreach (@{$opt{service}}) {
 | 
			
		||||
    if (/^([^=]+)=([^:]+):([^:]+):(.*)$/) {
 | 
			
		||||
	$Servers{$1}{ip} = $2; $Servers{$1}{port} = $3;
 | 
			
		||||
	($Servers{$1}{prio},$Servers{$1}{weight},$Servers{$1}{timeout}) = split ':', $4 if $4;
 | 
			
		||||
    } else {
 | 
			
		||||
	mylogs ('warning', "ignoring invalid service '$_'");
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# sort servers by prio
 | 
			
		||||
my %ServerPrioHash = ();
 | 
			
		||||
foreach (keys %Servers) {
 | 
			
		||||
    unless ($Servers{$_}{ip} and $Servers{$_}{port}) {
 | 
			
		||||
	mylogs ('warning', "No address or port for '$_'");
 | 
			
		||||
	next;
 | 
			
		||||
    };
 | 
			
		||||
    $Servers{$_}{prio} ||= 10; $Servers{$_}{timeout} ||= $TIMEOUT;
 | 
			
		||||
    $Servers{$_}{weight} = ($Servers{$_}{weight}) ? (1/$Servers{$_}{weight}) : 1;
 | 
			
		||||
    $Servers{$_}{questions} = $Servers{$_}{answers} = $Servers{$_}{failed} = 0;
 | 
			
		||||
    push @{$ServerPrioHash{$Servers{$_}{prio}}}, $_;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# run main loop
 | 
			
		||||
select((select(STDOUT), $| = 1)[0]);
 | 
			
		||||
hapolicy::main();
 | 
			
		||||
 | 
			
		||||
# end program
 | 
			
		||||
exit;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
### FUNCTIONS ###
 | 
			
		||||
 | 
			
		||||
# send log message
 | 
			
		||||
sub mylogs {
 | 
			
		||||
    my($prio,$msg) = @_;
 | 
			
		||||
 | 
			
		||||
    unless ($opt{stdout}) {
 | 
			
		||||
	# escape '%' characters
 | 
			
		||||
	$msg =~ s/\%/%%/g;
 | 
			
		||||
	# Sys::Syslog < 0.15 dies when syslog daemon is temporarily not
 | 
			
		||||
	# present (for example on syslog rotation)
 | 
			
		||||
	if ( (defined $Sys::Syslog::VERSION) or ($Sys::Syslog::VERSION lt '0.15') ) {
 | 
			
		||||
		eval {
 | 
			
		||||
			local $SIG{__DIE__} = sub { };
 | 
			
		||||
			syslog ($prio,$msg);
 | 
			
		||||
		};
 | 
			
		||||
	} else { syslog ($prio,$msg); };
 | 
			
		||||
    } else { printf "[LOG $prio]: $msg\n"; };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# ask remote server
 | 
			
		||||
sub ask {
 | 
			
		||||
    my($srv,$sendstr) = @_;
 | 
			
		||||
    my($action) = '';
 | 
			
		||||
 | 
			
		||||
    eval {
 | 
			
		||||
	# handle timeout
 | 
			
		||||
        local $SIG{__DIE__} = sub { };
 | 
			
		||||
        local $SIG{'ALRM'}  = sub { mylogs ('warning',"Timeout for '$srv' ($Servers{$srv}{ip}:$Servers{$srv}{port})"); die };
 | 
			
		||||
        my $prevaltert = alarm($Servers{$srv}{timeout});
 | 
			
		||||
 | 
			
		||||
	# increase server request-counter and try to open socket
 | 
			
		||||
	$Servers{$srv}{questions}+=$Servers{$srv}{weight};
 | 
			
		||||
	mylogs ('info', "Opening socket to '$srv' ($Servers{$srv}{ip}:$Servers{$srv}{port})") if $opt{verbose};
 | 
			
		||||
	unless ( my $socket = new IO::Socket::INET (
 | 
			
		||||
		PeerAddr => $Servers{$srv}{ip},
 | 
			
		||||
		PeerPort => $Servers{$srv}{port},
 | 
			
		||||
		Proto    => 'tcp',
 | 
			
		||||
		Type     => SOCK_STREAM ) ) {
 | 
			
		||||
		mylogs ('warning', "Could not open socket to '$srv' ($Servers{$srv}{ip}:$Servers{$srv}{port})");
 | 
			
		||||
 | 
			
		||||
	} else {
 | 
			
		||||
		# print request and get answer
 | 
			
		||||
		mylogs ('info', "Connection established to '$srv' ($Servers{$srv}{ip}:$Servers{$srv}{port})") if $opt{verbose};
 | 
			
		||||
		print $socket "$sendstr";
 | 
			
		||||
		$sendstr = <$socket>;
 | 
			
		||||
		chomp($sendstr);
 | 
			
		||||
 | 
			
		||||
		# check answer
 | 
			
		||||
		$sendstr =~ s/^(action=)//;
 | 
			
		||||
		if ($1 and $sendstr) {
 | 
			
		||||
			$Servers{$srv}{answers}++;
 | 
			
		||||
			mylogs ('info', "Answer from '$srv' -> '$sendstr'") if $opt{verbose};
 | 
			
		||||
			$action = $sendstr;
 | 
			
		||||
		} else {
 | 
			
		||||
			mylogs ('warning', "Invalid answer from '$srv' -> '$sendstr'");
 | 
			
		||||
		};
 | 
			
		||||
	};
 | 
			
		||||
	# restore old sig
 | 
			
		||||
	alarm ($prevaltert);
 | 
			
		||||
    };
 | 
			
		||||
    $Servers{$srv}{failed}++ unless ($Servers{$srv}{last} = $action);
 | 
			
		||||
    # return action
 | 
			
		||||
    return $action;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# process policy delegation request
 | 
			
		||||
sub smtpd_access_policy {
 | 
			
		||||
    my(%attr) = @_;
 | 
			
		||||
    my($sendstr,$action,$srv) = '';
 | 
			
		||||
 | 
			
		||||
    my $t1 = time();
 | 
			
		||||
 | 
			
		||||
    # request to str
 | 
			
		||||
    map { $sendstr .= $_."=".$attr{$_}."\n" } (keys %attr); $sendstr .= "\n";
 | 
			
		||||
 | 
			
		||||
    # loop serverlist until someone answers
 | 
			
		||||
    PRIO: foreach my $prio (sort keys %ServerPrioHash) {
 | 
			
		||||
	foreach my $srv ( sort { $Servers{$a}{questions}<=>$Servers{$b}{questions} } @{$ServerPrioHash{$prio}} ) {
 | 
			
		||||
		$action = ask ($srv, $sendstr) || '';
 | 
			
		||||
		mylogs ('info', "[$srv]"
 | 
			
		||||
			." (".$Servers{$srv}{ip}.":".$Servers{$srv}{port}.")"
 | 
			
		||||
			.", prio: $prio, weight: ".(1/$Servers{$srv}{weight})
 | 
			
		||||
			.", queries: ".($Servers{$srv}{questions} * (1/$Servers{$srv}{weight}))
 | 
			
		||||
			.", answers: ".$Servers{$srv}{answers}
 | 
			
		||||
			.", failed: ".$Servers{$srv}{failed}
 | 
			
		||||
			.", delay: ".(time() - $t1)."s"
 | 
			
		||||
			.", client: ".$attr{client_name}."[".$attr{client_address}."]"
 | 
			
		||||
			.", helo: <".$attr{helo_name}.">"
 | 
			
		||||
			.", from: <".$attr{sender}.">"
 | 
			
		||||
			.", to: <".$attr{recipient}.">"
 | 
			
		||||
			.", action: '".$action."'"
 | 
			
		||||
		) if ($opt{verbose} or $opt{logging});
 | 
			
		||||
		last PRIO if $action;
 | 
			
		||||
	};
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    # return action
 | 
			
		||||
    return $action;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
# main loop
 | 
			
		||||
sub main {
 | 
			
		||||
    my($request,$action) = undef;
 | 
			
		||||
    my (%attr) = ();
 | 
			
		||||
 | 
			
		||||
    while (<>) {
 | 
			
		||||
	next unless /^([^\r\n]*)\r?\n/;
 | 
			
		||||
	$request = $1;
 | 
			
		||||
	if ($request =~ /([^=]+)=(.*)/) {
 | 
			
		||||
		$attr{substr($1, 0, 512)} = substr($2, 0, 512);
 | 
			
		||||
	} elsif ($request eq '') {
 | 
			
		||||
		map { mylogs ('info', "Attribute: $_=$attr{$_}") } (keys %attr) if $opt{verbose};
 | 
			
		||||
		unless ((defined $attr{request}) and ($attr{request} eq 'smtpd_access_policy')) {
 | 
			
		||||
			$attr{request} ||='<undef>';
 | 
			
		||||
			mylogs ('notice', "ignoring unrecognized request type: '$attr{request}'");
 | 
			
		||||
		} else {
 | 
			
		||||
			my($action) = smtpd_access_policy(%attr);
 | 
			
		||||
			$action ||= $DEFAULT; %attr = ();
 | 
			
		||||
			mylogs('info', "Action: $action") if $opt{verbose};
 | 
			
		||||
			print "action=$action\n\n";
 | 
			
		||||
		};
 | 
			
		||||
	} else {
 | 
			
		||||
		chop;
 | 
			
		||||
		mylogs ('notice', "error: ignoring garbage \"".$request."\"");
 | 
			
		||||
	};
 | 
			
		||||
    };
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
__END__
 | 
			
		||||
 | 
			
		||||
=head1 NAME
 | 
			
		||||
 | 
			
		||||
hapolicy - policy delegation high availability script
 | 
			
		||||
 | 
			
		||||
=head1 SYNOPSIS
 | 
			
		||||
 | 
			
		||||
B<hapolicy> [OPTIONS] --service=SERVICE1 [--service=SERVICE2 ...]
 | 
			
		||||
 | 
			
		||||
	Services:
 | 
			
		||||
	-s, --service <name>=<address>:<port>[:<prio>:<weight>:<timeout>]
 | 
			
		||||
 | 
			
		||||
	Options:
 | 
			
		||||
	-d, --default <action>	returns <action> if no service was available (default: 'dunno')
 | 
			
		||||
	-l, --logging		log requests
 | 
			
		||||
	-v, --verbose		increase logging verbosity
 | 
			
		||||
	-L, --stdout		log to stdout, for debugging, do NOT use with postfix
 | 
			
		||||
 | 
			
		||||
=head1 DESCRIPTION
 | 
			
		||||
 | 
			
		||||
=head2 INTRODUCTION
 | 
			
		||||
 | 
			
		||||
B<hapolicy> enables high availability, weighted loadbalancing and a fallback action for postfix policy delegation services. Invoked via postfix spawn it acts as a wrapper that queries
 | 
			
		||||
other policy servers via tcp connection. The order of the service queries can be influenced by assigning a specific priority and weight to each service. A service is considered 'failing',
 | 
			
		||||
if the connection is refused or the specified service timeout is reached. If all of the configured policy services were failing, B<hapolicy> returns a default action (e.g. dunno) to postfix.
 | 
			
		||||
 | 
			
		||||
With version 1.00 B<hapolicy> has less than 200 lines of perl code using only standard perl modules. It does not require any disk access nor configuration files and runs under an unpriviledged
 | 
			
		||||
user account. This should allow fast and reliable operation.
 | 
			
		||||
 | 
			
		||||
=head2 CONFIGURATION
 | 
			
		||||
 | 
			
		||||
A service has the following attributes
 | 
			
		||||
 | 
			
		||||
    "servicename"           => {
 | 
			
		||||
               ip              => '127.0.0.1',         # ip address
 | 
			
		||||
               port            => '10040',             # tcp port
 | 
			
		||||
               prio            => '10',                # optional, lower wins
 | 
			
		||||
               weight          => '1',                 # optional, for items with same prio (weighted round-robin), higher is better
 | 
			
		||||
               timeout         => '30',                # optional, query timeout in seconds
 | 
			
		||||
    },
 | 
			
		||||
 | 
			
		||||
You may define multiple services at the command line. Which means that
 | 
			
		||||
 | 
			
		||||
	hapolicy -s "grey1=10.0.0.1:10031:10" -s "grey2=10.0.0.2:10031:20"
 | 
			
		||||
 | 
			
		||||
will always try first service I<grey1> at ip 10.0.0.1 port 10031 and if that service is not available or
 | 
			
		||||
does not answer within the default of 30 seconds the next service I<grey2> at ip 10.0.0.2 port 10031 will
 | 
			
		||||
be queried.
 | 
			
		||||
 | 
			
		||||
If you want to load balance connections you may define
 | 
			
		||||
 | 
			
		||||
	hapolicy -s "polw1=10.0.0.1:12525:10:2" -s "polw2=10.0.0.2:12525:10:1"
 | 
			
		||||
 | 
			
		||||
which queries service I<polw1> at ip 10.0.0.1 twice as much as service I<polw2> at ip 10.0.0.2. Note that this
 | 
			
		||||
setup also ensures high availability for both services. If I<polw1> is not available or does not answer
 | 
			
		||||
within the default of 30 seconds I<polw2> will be queried and vice versa. There is no reason to define a service twice.
 | 
			
		||||
 | 
			
		||||
=head2 INTEGRATION
 | 
			
		||||
 | 
			
		||||
Enter the following at the bottom of your postfix master.cf (usually located at /etc/postfix):
 | 
			
		||||
 | 
			
		||||
	# service description, note the leading blanks at the second line
 | 
			
		||||
	127.0.0.1:10060 inet    n       n       n       -       0       spawn
 | 
			
		||||
	  user=nobody argv=/usr/local/bin/hapolicy -l -s GREY1=10.0.0.1:10031:10 -s GREY2=10.0.0.2:10031:10
 | 
			
		||||
 | 
			
		||||
save the file and open postfix main.cf. Modify it as follows:
 | 
			
		||||
 | 
			
		||||
	127.0.0.1:10060_time_limit   = 3600
 | 
			
		||||
 | 
			
		||||
	smtpd_recipient_restrictions =
 | 
			
		||||
	    permit_mynetworks,
 | 
			
		||||
	    ... other authed permits ...
 | 
			
		||||
	    reject_unauth_destination,
 | 
			
		||||
	    ... other restrictions ...
 | 
			
		||||
	    check_policy_service inet:127.0.0.1:10060	# <- hapolicy query
 | 
			
		||||
 | 
			
		||||
Now issue 'postfix reload' at the command line. Of course you can have more enhanced setups
 | 
			
		||||
using postfix restriction classes. Please see L</LINKS> for further options.
 | 
			
		||||
 | 
			
		||||
=head1 LINKS
 | 
			
		||||
 | 
			
		||||
[1] Postfix SMTP Access Policy Delegation
 | 
			
		||||
L<http://www.postfix.org/SMTPD_POLICY_README.html>
 | 
			
		||||
 | 
			
		||||
[2] Postfix Per-Client/User/etc. Access Control
 | 
			
		||||
L<http://www.postfix.org/RESTRICTION_CLASS_README.html>
 | 
			
		||||
 | 
			
		||||
=head1 LICENSE
 | 
			
		||||
 | 
			
		||||
hapolicy is free software and released under BSD license, which basically means
 | 
			
		||||
that you can do what you want as long as you keep the copyright notice:
 | 
			
		||||
 | 
			
		||||
Copyright (c) 2008, Jan Peter Kessler
 | 
			
		||||
All rights reserved.
 | 
			
		||||
 | 
			
		||||
Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:
 | 
			
		||||
 | 
			
		||||
 * Redistributions of source code must retain the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer in
 | 
			
		||||
   the documentation and/or other materials provided with the
 | 
			
		||||
   distribution.
 | 
			
		||||
 * Neither the name of the authors nor the names of his contributors
 | 
			
		||||
   may be used to endorse or promote products derived from this
 | 
			
		||||
   software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
THIS SOFTWARE IS PROVIDED BY ME ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
=head1 AUTHOR
 | 
			
		||||
 | 
			
		||||
S<Jan Peter Kessler E<lt>info (AT) postfwd (DOT) orgE<gt>>. Let me know, if you have any suggestions.
 | 
			
		||||
 | 
			
		||||
=cut
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										162
									
								
								tools/hapolicy/hapolicy.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										162
									
								
								tools/hapolicy/hapolicy.html
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,162 @@
 | 
			
		|||
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 | 
			
		||||
<html>
 | 
			
		||||
<head>
 | 
			
		||||
<title>hapoliy - HA and LB for policy servers</title>
 | 
			
		||||
<link rel="stylesheet" type="text/css" href="http://www.jpkessler.de/css/postfwd.css">
 | 
			
		||||
<meta http-equiv="Content-Type" content="text/html;charset=utf-8" >
 | 
			
		||||
<meta name="description" content="hapolicy loadbalancing and high availability for postfix policy servers">
 | 
			
		||||
<meta name="author" content="jpk">
 | 
			
		||||
<meta name="keywords" content="hapolicy, policy server loadbalancing, policy server high availability, policy server failure, policy delegation, postfix, Jan, Peter, Kessler">
 | 
			
		||||
</head>
 | 
			
		||||
 | 
			
		||||
<body>
 | 
			
		||||
 | 
			
		||||
<p><a name="__index__"></a></p>
 | 
			
		||||
<!-- INDEX BEGIN -->
 | 
			
		||||
 | 
			
		||||
<ul>
 | 
			
		||||
 | 
			
		||||
	<li><a href="#name">NAME</a></li>
 | 
			
		||||
	<li><a href="#synopsis">SYNOPSIS</a></li>
 | 
			
		||||
	<li><a href="#description">DESCRIPTION</a></li>
 | 
			
		||||
	<ul>
 | 
			
		||||
 | 
			
		||||
		<li><a href="#introduction">INTRODUCTION</a></li>
 | 
			
		||||
		<li><a href="#configuration">CONFIGURATION</a></li>
 | 
			
		||||
		<li><a href="#integration">INTEGRATION</a></li>
 | 
			
		||||
	</ul>
 | 
			
		||||
 | 
			
		||||
	<li><a href="#links">LINKS</a></li>
 | 
			
		||||
	<li><a href="#license">LICENSE</a></li>
 | 
			
		||||
	<li><a href="#author">AUTHOR</a></li>
 | 
			
		||||
</ul>
 | 
			
		||||
<!-- INDEX END -->
 | 
			
		||||
 | 
			
		||||
<hr />
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h1><a name="name">NAME</a></h1>
 | 
			
		||||
<p>hapolicy - policy delegation high availability script</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="synopsis">SYNOPSIS</a></h1>
 | 
			
		||||
<p><strong>hapolicy</strong> [OPTIONS] --service=SERVICE1 [--service=SERVICE2 ...]</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        Services:
 | 
			
		||||
        -s, --service <name>=<address>:<port>[:<prio>:<weight>:<timeout>]</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        Options:
 | 
			
		||||
        -d, --default <action>  returns <action> if no service was available (default: 'dunno')
 | 
			
		||||
        -l, --logging           log requests
 | 
			
		||||
        -v, --verbose           increase logging verbosity
 | 
			
		||||
        -L, --stdout            log to stdout, for debugging, do NOT use with postfix</pre>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="description">DESCRIPTION</a></h1>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="introduction">INTRODUCTION</a></h2>
 | 
			
		||||
<p><strong>hapolicy</strong> enables high availability, weighted loadbalancing and a fallback action for postfix policy delegation services. Invoked via postfix spawn it acts as a wrapper that queries
 | 
			
		||||
other policy servers via tcp connection. The order of the service queries can be influenced by assigning a specific priority and weight to each service. A service is considered 'failing',
 | 
			
		||||
if the connection is refused or the specified service timeout is reached. If all of the configured policy services were failing, <strong>hapolicy</strong> returns a default action (e.g. dunno) to postfix.</p>
 | 
			
		||||
<p>With version 1.00 <strong>hapolicy</strong> has less than 200 lines of perl code using only standard perl modules. It does not require any disk access nor configuration files and runs under an unpriviledged
 | 
			
		||||
user account. This should allow fast and reliable operation.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="configuration">CONFIGURATION</a></h2>
 | 
			
		||||
<p>A service has the following attributes</p>
 | 
			
		||||
<pre>
 | 
			
		||||
    "servicename"           => {
 | 
			
		||||
               ip              => '127.0.0.1',         # ip address
 | 
			
		||||
               port            => '10040',             # tcp port
 | 
			
		||||
               prio            => '10',                # optional, lower wins
 | 
			
		||||
               weight          => '1',                 # optional, for items with same prio (weighted round-robin), higher is better
 | 
			
		||||
               timeout         => '30',                # optional, query timeout in seconds
 | 
			
		||||
    },</pre>
 | 
			
		||||
<p>You may define multiple services at the command line. Which means that</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        hapolicy -s "grey1=10.0.0.1:10031:10" -s "grey2=10.0.0.2:10031:20"</pre>
 | 
			
		||||
<p>will always try first service <em>grey1</em> at ip 10.0.0.1 port 10031 and if that service is not available or
 | 
			
		||||
does not answer within the default of 30 seconds the next service <em>grey2</em> at ip 10.0.0.2 port 10031 will
 | 
			
		||||
be queried.<br><br>
 | 
			
		||||
<img src="hapolicy01.png"><br>
 | 
			
		||||
</p>
 | 
			
		||||
<p>If you want to load balance connections you may define</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        hapolicy -s "polw1=10.0.0.1:12525:10:2" -s "polw2=10.0.0.2:12525:10:1"</pre>
 | 
			
		||||
<p>which queries service <em>polw1</em> at ip 10.0.0.1 twice as much as service <em>polw2</em> at ip 10.0.0.2.<br><br>
 | 
			
		||||
<img src="hapolicy02.png">
 | 
			
		||||
<br><br>
 | 
			
		||||
Note that this
 | 
			
		||||
setup also ensures high availability for both services. If <em>polw1</em> is not available or does not answer
 | 
			
		||||
within the default of 30 seconds <em>polw2</em> will be queried and vice versa. There is no reason to define a service twice.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<h2><a name="integration">INTEGRATION</a></h2>
 | 
			
		||||
<p>Enter the following at the bottom of your postfix master.cf (usually located at /etc/postfix):</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        # service description, note the leading blanks at the second line
 | 
			
		||||
        127.0.0.1:10061 inet    n       n       n       -       0       spawn
 | 
			
		||||
          user=nobody argv=/usr/local/bin/hapolicy -l -s GREY1=10.0.0.1:10031:10 -s GREY2=10.0.0.2:10031:10</pre>
 | 
			
		||||
<p>save the file and open postfix main.cf. Modify it as follows:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
        127.0.0.1:10061_time_limit   = 3600</pre>
 | 
			
		||||
<pre>
 | 
			
		||||
        smtpd_recipient_restrictions =
 | 
			
		||||
            permit_mynetworks,
 | 
			
		||||
            ... other authed permits ...
 | 
			
		||||
            reject_unauth_destination,
 | 
			
		||||
            ... other restrictions ...
 | 
			
		||||
            check_policy_service inet:127.0.0.1:10061   # <- hapolicy query</pre>
 | 
			
		||||
<p>Now issue 'postfix reload' at the command line. Of course you can have more enhanced setups
 | 
			
		||||
using postfix restriction classes. Please see <a href="#links">LINKS</a> for further options.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="links">LINKS</a></h1>
 | 
			
		||||
<p>[1] Get hapolicy<br>
 | 
			
		||||
<a href="http://www.postfwd.org/hapolicy/hapolicy">http://www.postfwd.org/hapolicy/hapolicy</a></p>
 | 
			
		||||
<p>[2] Postfix SMTP Access Policy Delegation<br>
 | 
			
		||||
<a href="http://www.postfix.org/SMTPD_POLICY_README.html">http://www.postfix.org/SMTPD_POLICY_README.html</a></p>
 | 
			
		||||
<p>[3] Postfix Per-Client/User/etc. Access Control<br>
 | 
			
		||||
<a href="http://www.postfix.org/RESTRICTION_CLASS_README.html">http://www.postfix.org/RESTRICTION_CLASS_README.html</a></p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="license">LICENSE</a></h1>
 | 
			
		||||
<p>hapolicy is free software and released under BSD license, which basically means
 | 
			
		||||
that you can do what you want as long as you keep the copyright notice:</p>
 | 
			
		||||
<p>Copyright (c) 2008, Jan Peter Kessler
 | 
			
		||||
All rights reserved.</p>
 | 
			
		||||
<p>Redistribution and use in source and binary forms, with or without modification,
 | 
			
		||||
are permitted provided that the following conditions are met:</p>
 | 
			
		||||
<pre>
 | 
			
		||||
 * Redistributions of source code must retain the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer.
 | 
			
		||||
 * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
   notice, this list of conditions and the following disclaimer in
 | 
			
		||||
   the documentation and/or other materials provided with the
 | 
			
		||||
   distribution.
 | 
			
		||||
 * Neither the name of the authors nor the names of his contributors
 | 
			
		||||
   may be used to endorse or promote products derived from this
 | 
			
		||||
   software without specific prior written permission.</pre>
 | 
			
		||||
<p>THIS SOFTWARE IS PROVIDED BY ME ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 | 
			
		||||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
 | 
			
		||||
FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY DIRECT,
 | 
			
		||||
INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
 | 
			
		||||
NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 | 
			
		||||
WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 | 
			
		||||
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 | 
			
		||||
POSSIBILITY OF SUCH DAMAGE.</p>
 | 
			
		||||
<p>
 | 
			
		||||
</p>
 | 
			
		||||
<hr />
 | 
			
		||||
<h1><a name="author">AUTHOR</a></h1>
 | 
			
		||||
<p>Jan Peter Kessler <info (AT) postfwd (DOT) org>. Let me know, if you have any suggestions.</p>
 | 
			
		||||
 | 
			
		||||
</body>
 | 
			
		||||
 | 
			
		||||
</html>
 | 
			
		||||
							
								
								
									
										127
									
								
								tools/hapolicy/hapolicy.txt
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										127
									
								
								tools/hapolicy/hapolicy.txt
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
				
			
			@ -0,0 +1,127 @@
 | 
			
		|||
NAME
 | 
			
		||||
    hapolicy - policy delegation high availability script
 | 
			
		||||
 | 
			
		||||
SYNOPSIS
 | 
			
		||||
    hapolicy [OPTIONS] --service=SERVICE1 [--service=SERVICE2 ...]
 | 
			
		||||
 | 
			
		||||
            Services:
 | 
			
		||||
            -s, --service <name>=<address>:<port>[:<prio>:<weight>:<timeout>]
 | 
			
		||||
 | 
			
		||||
            Options:
 | 
			
		||||
            -d, --default <action>  returns <action> if no service was available (default: 'dunno')
 | 
			
		||||
            -l, --logging           log requests
 | 
			
		||||
            -v, --verbose           increase logging verbosity
 | 
			
		||||
            -L, --stdout            log to stdout, for debugging, do NOT use with postfix
 | 
			
		||||
 | 
			
		||||
DESCRIPTION
 | 
			
		||||
  INTRODUCTION
 | 
			
		||||
    hapolicy enables high availability, weighted loadbalancing and a
 | 
			
		||||
    fallback action for postfix policy delegation services. Invoked via
 | 
			
		||||
    postfix spawn it acts as a wrapper that queries other policy servers via
 | 
			
		||||
    tcp connection. The order of the service queries can be influenced by
 | 
			
		||||
    assigning a specific priority and weight to each service. A service is
 | 
			
		||||
    considered 'failing', if the connection is refused or the specified
 | 
			
		||||
    service timeout is reached. If all of the configured policy services
 | 
			
		||||
    were failing, hapolicy returns a default action (e.g. dunno) to postfix.
 | 
			
		||||
 | 
			
		||||
    With version 1.00 hapolicy has less than 200 lines of perl code using
 | 
			
		||||
    only standard perl modules. It does not require any disk access nor
 | 
			
		||||
    configuration files and runs under an unpriviledged user account. This
 | 
			
		||||
    should allow fast and reliable operation.
 | 
			
		||||
 | 
			
		||||
  CONFIGURATION
 | 
			
		||||
    A service has the following attributes
 | 
			
		||||
 | 
			
		||||
        "servicename"           => {
 | 
			
		||||
                   ip              => '127.0.0.1',         # ip address
 | 
			
		||||
                   port            => '10040',             # tcp port
 | 
			
		||||
                   prio            => '10',                # optional, lower wins
 | 
			
		||||
                   weight          => '1',                 # optional, for items with same prio (weighted round-robin), higher is better
 | 
			
		||||
                   timeout         => '30',                # optional, query timeout in seconds
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
    You may define multiple services at the command line. Which means that
 | 
			
		||||
 | 
			
		||||
            hapolicy -s "grey1=10.0.0.1:10031:10" -s "grey2=10.0.0.2:10031:20"
 | 
			
		||||
 | 
			
		||||
    will always try first service *grey1* at ip 10.0.0.1 port 10031 and if
 | 
			
		||||
    that service is not available or does not answer within the default of
 | 
			
		||||
    30 seconds the next service *grey2* at ip 10.0.0.2 port 10031 will be
 | 
			
		||||
    queried.
 | 
			
		||||
 | 
			
		||||
    If you want to load balance connections you may define
 | 
			
		||||
 | 
			
		||||
            hapolicy -s "polw1=10.0.0.1:12525:10:2" -s "polw2=10.0.0.2:12525:10:1"
 | 
			
		||||
 | 
			
		||||
    which queries service *polw1* at ip 10.0.0.1 twice as much as service
 | 
			
		||||
    *polw2* at ip 10.0.0.2. Note that this setup also ensures high
 | 
			
		||||
    availability for both services. If *polw1* is not available or does not
 | 
			
		||||
    answer within the default of 30 seconds *polw2* will be queried and vice
 | 
			
		||||
    versa. There is no reason to define a service twice.
 | 
			
		||||
 | 
			
		||||
  INTEGRATION
 | 
			
		||||
    Enter the following at the bottom of your postfix master.cf (usually
 | 
			
		||||
    located at /etc/postfix):
 | 
			
		||||
 | 
			
		||||
            # service description, note the leading blanks at the second line
 | 
			
		||||
            127.0.0.1:10060 inet    n       n       n       -       0       spawn
 | 
			
		||||
              user=nobody argv=/usr/local/bin/hapolicy -l -s GREY1=10.0.0.1:10031:10 -s GREY2=10.0.0.2:10031:10
 | 
			
		||||
 | 
			
		||||
    save the file and open postfix main.cf. Modify it as follows:
 | 
			
		||||
 | 
			
		||||
            127.0.0.1:10060_time_limit   = 3600
 | 
			
		||||
 | 
			
		||||
            smtpd_recipient_restrictions =
 | 
			
		||||
                permit_mynetworks,
 | 
			
		||||
                ... other authed permits ...
 | 
			
		||||
                reject_unauth_destination,
 | 
			
		||||
                ... other restrictions ...
 | 
			
		||||
                check_policy_service inet:127.0.0.1:10060   # <- hapolicy query
 | 
			
		||||
 | 
			
		||||
    Now issue 'postfix reload' at the command line. Of course you can have
 | 
			
		||||
    more enhanced setups using postfix restriction classes. Please see
 | 
			
		||||
    "LINKS" for further options.
 | 
			
		||||
 | 
			
		||||
LINKS
 | 
			
		||||
    [1] Postfix SMTP Access Policy Delegation
 | 
			
		||||
    <http://www.postfix.org/SMTPD_POLICY_README.html>
 | 
			
		||||
 | 
			
		||||
    [2] Postfix Per-Client/User/etc. Access Control
 | 
			
		||||
    <http://www.postfix.org/RESTRICTION_CLASS_README.html>
 | 
			
		||||
 | 
			
		||||
LICENSE
 | 
			
		||||
    hapolicy is free software and released under BSD license, which
 | 
			
		||||
    basically means that you can do what you want as long as you keep the
 | 
			
		||||
    copyright notice:
 | 
			
		||||
 | 
			
		||||
    Copyright (c) 2008, Jan Peter Kessler All rights reserved.
 | 
			
		||||
 | 
			
		||||
    Redistribution and use in source and binary forms, with or without
 | 
			
		||||
    modification, are permitted provided that the following conditions are
 | 
			
		||||
    met:
 | 
			
		||||
 | 
			
		||||
     * Redistributions of source code must retain the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer.
 | 
			
		||||
     * Redistributions in binary form must reproduce the above copyright
 | 
			
		||||
       notice, this list of conditions and the following disclaimer in
 | 
			
		||||
       the documentation and/or other materials provided with the
 | 
			
		||||
       distribution.
 | 
			
		||||
     * Neither the name of the authors nor the names of his contributors
 | 
			
		||||
       may be used to endorse or promote products derived from this
 | 
			
		||||
       software without specific prior written permission.
 | 
			
		||||
 | 
			
		||||
    THIS SOFTWARE IS PROVIDED BY ME ``AS IS'' AND ANY EXPRESS OR IMPLIED
 | 
			
		||||
    WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
 | 
			
		||||
    MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 | 
			
		||||
    NO EVENT SHALL BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 | 
			
		||||
    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 | 
			
		||||
    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 | 
			
		||||
    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 | 
			
		||||
    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 | 
			
		||||
    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 | 
			
		||||
    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 | 
			
		||||
 | 
			
		||||
AUTHOR
 | 
			
		||||
    Jan Peter Kessler <info (AT) postfwd (DOT) org>. Let me know, if you
 | 
			
		||||
    have any suggestions.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										
											BIN
										
									
								
								tools/hapolicy/hapolicy01.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tools/hapolicy/hapolicy01.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 28 KiB  | 
							
								
								
									
										
											BIN
										
									
								
								tools/hapolicy/hapolicy02.png
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								tools/hapolicy/hapolicy02.png
									
										
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| 
		 After Width: | Height: | Size: 30 KiB  | 
| 
						 | 
				
			
			@ -1,90 +0,0 @@
 | 
			
		|||
#!/bin/sh
 | 
			
		||||
#
 | 
			
		||||
# generates per minute stats for generic syslog files
 | 
			
		||||
# call it:
 | 
			
		||||
#
 | 
			
		||||
#	lograte.sh [OPTIONS] <logfile>
 | 
			
		||||
#
 | 
			
		||||
# or for online monitoring
 | 
			
		||||
#
 | 
			
		||||
#	tail -f <logfile> | lograte.sh [OPTIONS]
 | 
			
		||||
#
 | 
			
		||||
# by JPK
 | 
			
		||||
 | 
			
		||||
PATH=/usr/local/bin:/bin:/usr/bin
 | 
			
		||||
 | 
			
		||||
# default values
 | 
			
		||||
PATTERN=".*"
 | 
			
		||||
MINIMUM=1
 | 
			
		||||
TOPLIST=10
 | 
			
		||||
 | 
			
		||||
# show usage
 | 
			
		||||
Usage () {
 | 
			
		||||
	{
 | 
			
		||||
		echo "Usage:   `basename $0` -m <mincount> -t <topcount> -s <filter> <file> <file> ...";
 | 
			
		||||
		echo "	-m 	minimum events to display"
 | 
			
		||||
		echo "	-t 	how many rankings?"
 | 
			
		||||
		echo "	-T 	print rankings only"
 | 
			
		||||
		echo "	-s 	filter input through this regexp"
 | 
			
		||||
		echo "Example: `basename $0` -m 10 -t 5 -s \"(panic|error)\" /var/log/messages"
 | 
			
		||||
	} >&2
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
# parse arguments
 | 
			
		||||
while getopts Tt:m:s: o
 | 
			
		||||
do	case "$o" in
 | 
			
		||||
	s)	PATTERN="$OPTARG";;
 | 
			
		||||
	m)	MINIMUM="$OPTARG";;
 | 
			
		||||
	t)	TOPLIST="$OPTARG";;
 | 
			
		||||
	T)	TOPONLY=1;;
 | 
			
		||||
	*)	Usage;
 | 
			
		||||
		exit 1;;
 | 
			
		||||
	esac
 | 
			
		||||
done
 | 
			
		||||
shift `expr $OPTIND - 1`
 | 
			
		||||
 | 
			
		||||
# a single awk
 | 
			
		||||
awk '	($0 ~ PATTERN) {
 | 
			
		||||
		split($3,TIME,":");
 | 
			
		||||
		CURRTIME=$1 " " $2 " " TIME[1] ":" TIME[2];
 | 
			
		||||
		if (LASTTIME != CURRTIME) {
 | 
			
		||||
			if (COUNT >= MINIMUM) {
 | 
			
		||||
				if (!(TOPONLY == 1)) {
 | 
			
		||||
					printf ( "%s %7d events, %8.2f per sec\n", LASTTIME, COUNT, ( COUNT / 60 ) );
 | 
			
		||||
				};
 | 
			
		||||
				for (i=1;i<=TOPLIST;i++) {
 | 
			
		||||
					if (COUNT > MAXCOUNT[i]) {
 | 
			
		||||
						MAXCOUNT[i+1]=MAXCOUNT[i];
 | 
			
		||||
						MAXCOUNT[i]=COUNT;
 | 
			
		||||
						MAXTIME[i+1]=MAXTIME[i];
 | 
			
		||||
						MAXTIME[i]=LASTTIME;
 | 
			
		||||
						break;
 | 
			
		||||
					};
 | 
			
		||||
				};
 | 
			
		||||
			};
 | 
			
		||||
			COUNT=1;
 | 
			
		||||
		} else {
 | 
			
		||||
			COUNT++;
 | 
			
		||||
		};
 | 
			
		||||
		LASTTIME=CURRTIME;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	END {
 | 
			
		||||
		if (CURRTIME != "") {
 | 
			
		||||
			if ( (COUNT >= MINIMUM) && (!(TOPONLY == 1)) ) {
 | 
			
		||||
				printf ( "%s %7d events, %8.2f per sec\n\n", LASTTIME, COUNT, ( COUNT / 60 ) );
 | 
			
		||||
			};
 | 
			
		||||
			print "###########";
 | 
			
		||||
			printf ("# TOP %3d #\n",TOPLIST);
 | 
			
		||||
			print "###########";
 | 
			
		||||
			for (i=1;i<=TOPLIST;i++) {
 | 
			
		||||
				printf ( "# TOP %3d:\t%s %7d events, %8.2f per sec\n", i, MAXTIME[i], MAXCOUNT[i], ( MAXCOUNT[i] / 60 ) );;
 | 
			
		||||
			};
 | 
			
		||||
			exit 0;
 | 
			
		||||
		} else {
 | 
			
		||||
			exit 1;
 | 
			
		||||
		};
 | 
			
		||||
	}' PATTERN="${PATTERN}" MINIMUM="${MINIMUM}" TOPLIST="${TOPLIST}" TOPONLY="${TOPONLY}" $*
 | 
			
		||||
 | 
			
		||||
# set exitcode=1 if no matching lines found
 | 
			
		||||
exit $?
 | 
			
		||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue