#! /usr/bin/perl -w
#
# check_rpc plugin for nagios
#
# usage:
#    check_rpc host service
#
# Check if an rpc serice is registered and running
# using rpcinfo - $proto $host $prognum 2>&1 |";
#
# Use these hosts.cfg entries as examples
#
# command[check_nfs]=/some/path/libexec/check_rpc $HOSTADDRESS$ nfs
# service[check_nfs]=NFS;24x7;3;5;5;unix-admin;60;24x7;1;1;1;;check_rpc
#
# initial version: 3 May 2000 by Truongchinh Nguyen and Karl DeBisschop
# Modified May 2002 Subhendu Ghosh - support for ePN and patches
#
# Copyright Notice: GPL
#

use strict;
use lib "/usr/lib/nagios/plugins";
use utils qw($TIMEOUT %ERRORS &print_revision &support);
use vars qw($PROGNAME);
my ($verbose,@proto,%prognum,$host,$response,$prognum,$port,$cmd,$progver,$state);
my ($array_ref,$test,$element,@progkeys,$proto,$a,$b);
my ($opt_V,$opt_h,$opt_C,$opt_p,$opt_H,$opt_c,$opt_u,$opt_t);
my ($line, @progvers, $response2,$response3);
$opt_V = $opt_h = $opt_C = $opt_p = $opt_H =  $opt_u = $opt_t ='';
$state = 'UNKNOWN';
$progver = $response=$response2= $response3 ='';

$PROGNAME = "check_rpc";
sub print_help ();
sub print_usage ();
sub in ($$);

$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
$ENV{'PATH'}='';
$ENV{'LC_ALL'}='C';

#Initialise protocol for each progname number
# 'u' for UDP, 't' for TCP
$proto[10003]='u';
$proto[10004]='u';
$proto[10007]='u';

use Getopt::Long;
Getopt::Long::Configure('bundling');
GetOptions(
	"V"   => \$opt_V,   "version"    => \$opt_V,
	"h"   => \$opt_h,   "help"       => \$opt_h,
	"C=s" => \$opt_C,   "command=s"  => \$opt_C,
	"p=i" => \$opt_p,   "port=i"     => \$opt_p,
 	"H=s" => \$opt_H,   "hostname=s" => \$opt_H,
 	"c=s" => \$opt_c,   "progver=s"  => \$opt_c,
 	"v+"  => \$verbose, "verbose+"   => \$verbose,
 	"u"   => \$opt_u,   "udp"        => \$opt_u,
 	"t"   => \$opt_t,   "tcp"        => \$opt_t
);

# -h means display verbose help screen
if ($opt_h) { print_help(); exit $ERRORS{'OK'}; }

# -V means display version number
if ($opt_V) {
	print_revision($PROGNAME,'1.4.16');
	exit $ERRORS{'OK'};
}

# Hash containing all RPC program names and numbers
# Add to the hash if support for new RPC program is required

%prognum  = (
	"portmapper"  => 100000 ,
	"portmap"  => 100000 ,
	"sunrpc"  => 100000 ,
	"rpcbind"  => 100000 ,
	"rstatd"  => 100001 ,
	"rstat"  => 100001 ,
	"rup"  => 100001 ,
	"perfmeter"  => 100001 ,
	"rstat_svc"  => 100001 ,
	"rusersd"  => 100002 ,
	"rusers"  => 100002 ,
	"nfs"  => 100003 ,
	"nfsprog"  => 100003 ,
	"ypserv"  => 100004 ,
	"ypprog"  => 100004 ,
	"mountd"  => 100005 ,
	"mount"  => 100005 ,
	"showmount"  => 100005 ,
	"ypbind"  => 100007 ,
	"walld"  => 100008 ,
	"rwall"  => 100008 ,
	"shutdown"  => 100008 ,
	"yppasswdd"  => 100009 ,
	"yppasswd"  => 100009 ,
	"etherstatd"  => 100010 ,
	"etherstat"  => 100010 ,
	"rquotad"  => 100011 ,
	"rquotaprog"  => 100011 ,
	"quota"  => 100011 ,
	"rquota"  => 100011 ,
	"sprayd"  => 100012 ,
	"spray"  => 100012 ,
	"3270_mapper"  => 100013 ,
	"rje_mapper"  => 100014 ,
	"selection_svc"  => 100015 ,
	"selnsvc"  => 100015 ,
	"database_svc"  => 100016 ,
	"rexd"  => 100017 ,
	"rex"  => 100017 ,
	"alis"  => 100018 ,
	"sched"  => 100019 ,
	"llockmgr"  => 100020 ,
	"nlockmgr"  => 100021 ,
	"x25_inr"  => 100022 ,
	"statmon"  => 100023 ,
	"status"  => 100024 ,
	"bootparam"  => 100026 ,
	"ypupdated"  => 100028 ,
	"ypupdate"  => 100028 ,
	"keyserv"  => 100029 ,
	"keyserver"  => 100029 ,
	"sunlink_mapper"  => 100033 ,
	"tfsd"  => 100037 ,
	"nsed"  => 100038 ,
	"nsemntd"  => 100039 ,
	"showfhd"  => 100043 ,
	"showfh"  => 100043 ,
	"ioadmd"  => 100055 ,
	"rpc.ioadmd"  => 100055 ,
	"NETlicense"  => 100062 ,
	"sunisamd"  => 100065 ,
	"debug_svc"  => 100066 ,
	"dbsrv"  => 100066 ,
	"ypxfrd"  => 100069 ,
	"rpc.ypxfrd"  => 100069 ,
	"bugtraqd"  => 100071 ,
	"kerbd"  => 100078 ,
	"event"  => 100101 ,
	"na.event"  => 100101 ,
	"logger"  => 100102 ,
	"na.logger"  => 100102 ,
	"sync"  => 100104 ,
	"na.sync"  => 100104 ,
	"hostperf"  => 100107 ,
	"na.hostperf"  => 100107 ,
	"activity"  => 100109 ,
	"na.activity"  => 100109 ,
	"hostmem"  => 100112 ,
	"na.hostmem"  => 100112 ,
	"sample"  => 100113 ,
	"na.sample"  => 100113 ,
	"x25"  => 100114 ,
	"na.x25"  => 100114 ,
	"ping"  => 100115 ,
	"na.ping"  => 100115 ,
	"rpcnfs"  => 100116 ,
	"na.rpcnfs"  => 100116 ,
	"hostif"  => 100117 ,
	"na.hostif"  => 100117 ,
	"etherif"  => 100118 ,
	"na.etherif"  => 100118 ,
	"iproutes"  => 100120 ,
	"na.iproutes"  => 100120 ,
	"layers"  => 100121 ,
	"na.layers"  => 100121 ,
	"snmp"  => 100122 ,
	"na.snmp"  => 100122 ,
	"snmp-cmc"  => 100122 ,
	"snmp-synoptics"  => 100122 ,
	"snmp-unisys"  => 100122 ,
	"snmp-utk"  => 100122 ,
	"traffic"  => 100123 ,
	"na.traffic"  => 100123 ,
	"nfs_acl"  => 100227 ,
	"sadmind"  => 100232 ,
	"nisd"  => 100300 ,
	"rpc.nisd"  => 100300 ,
	"nispasswd"  => 100303 ,
	"rpc.nispasswdd"  => 100303 ,
	"ufsd"  => 100233 ,
	"ufsd"  => 100233 ,
	"pcnfsd"  => 150001 ,
	"pcnfs"  => 150001 ,
	"amd"  => 300019 ,
	"amq"  => 300019 ,
	"bwnfsd"  => 545580417 ,
	"fypxfrd"  => 600100069 ,
	"freebsd-ypxfrd"  => 600100069 ,
);

# -v means verbose, -v-v means verbose twice = print above hash
if (defined $verbose && ($verbose > 1) ){
	my $key;
	print "Supported programs:\n";
	print "    name\t=>\tnumber\n";
	print " ===============================\n";
	foreach $key (sort keys %prognum) {
		print "   $key \t=>\t$prognum{$key} \n";
	}
	print "\n\n";
	print_usage();
	exit $ERRORS{'OK'};
}

# -H means host name
unless ($opt_H) { print_usage(); exit $ERRORS{'UNKNOWN'}; }

if (! utils::is_hostname($opt_H)){
	print "$opt_H is not a valid host name\n";
	print_usage();
	exit $ERRORS{"UNKNOWN"};
}else{
	$host = $opt_H;
}

if ($opt_t && $opt_u) {
	print "Cannot define tcp AND udp\n";
	print_usage();
	exit $ERRORS{'UNKNOWN'};
}


# -C means command name or number
$opt_C = shift unless ($opt_C);
unless ($opt_C) { print_usage(); exit -1; }
@progkeys = keys %prognum;
if ($opt_C =~ m/^([0-9]+)$/){
#    $response = "RPC ok: program $opt_C (version ";
    $prognum = $1;
} elsif ( in( \@progkeys, $opt_C)) {
#    $response = "RPC ok: $opt_C (version ";
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $prognum{$opt_C;
    $prognum = $pro