[Nagiosplug-devel] Plugin to check SMB shares

Andreas Baetz lac01 at web.de
Mon Jan 13 22:24:02 CET 2003


Hi,

I have written a nagios plugin in Perl that checks for
the availability of shares and printers an Windows 
or Samba Servers using smbclient.

It uses utils.pm from sghosh and is based on an example
plugin code from ??. (If someone knows the author of the example
code, please tell me or include the credits yourself).

I first postet this mail in nagios-devel, but I feel this list
is more appropriate.

There is a plugin called "check_disk_smb", which also 
checks smb shares, but it is aimed at checking
the free space on one share, whereas my check tests the 
existence of multiple shares/printers in one call.

I'm using it for a while now in production.
If you like, you can verify/review/modify/test it, and possibly 
include it in the main plugin distribution, if there is an interest.
License is same as perl.


Andreas Baetz


Here it comes (check_smb_shares.pl):
#######################################################
#!/usr/bin/perl -w

# Copyright 2003 Andreas Baetz (andreas.baetz at herma.de)
# License: same licence as Perl itself

# this script checks for smb shares on a windows server
# the shares to check for are given with parameter "check"
# and can be Disks or Printers, depending on Parameter "type"
# type maybe "Disk" or "Printer"
# Return codes:
# "OK" if all tested shares are there
# "WARNING" if there are smbclient errors
# "CRITICAL"if at least one share is not listed at the queried server
# "UNKNOWN" if it doesn't get a response from the server within timeout

# example:
# check_smbshares.pl -H server -D Domain -U user -P Password -T type -C share1,share2

# Caution:
# smbclient doesn't display share names with a length of more than 12 characters

#$Log: check_smbshares.pl,v $
#Revision 1.1  2003/01/09 13:07:38  baz
#Initial revision
#

#It's the script's exit code that Netsaint interprets as a status, viz (from
# utils.pm):
#       'DEPENDENT'=>4,
#       'UNKNOWN'=>3,
#       'OK'=>0,
#       'WARNING'=>1,
#       'CRITICAL'=>2
# Anything you send to STDOUT (e.g. prints) gets added as explanatory message
# text when run from Netsaint (thus everything except help/usage should be
# short).
#
# If you will ever share your plugin (or just as good coding style, anyway),
# there are a few other conventions to follow though. There is a FAQ about
# this on the website somewhere, but the easiest way is probably to take an
# existing plugin and just modify the "business logic" (and the help text!).
# There is a also a little module, utils.pm, which has a few convenience
# functions but is mainly useful for saying:
#       exit $ERRORS{'CRITICAL'};
# instead of having to memorise the status codes. (Makes for much more
# readable code!)
#


use vars qw($PROGNAME $runtimedir);

BEGIN {
    $PROGNAME=$0;
    $runtimedir='.';
    if ($0 =~ m/^(.*?)[\/\\]([^\/\\]+)$/) {
	$runtimedir = $1;
	$PROGNAME = $2;
    }
}

use strict;
use lib $runtimedir;
use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
use Getopt::Long;

my ($opt_C,$opt_H,$opt_t,$opt_P,$opt_U,$opt_D,$opt_T);

Getopt::Long::Configure('bundling', 'no_ignore_case');
GetOptions
  ("V|version" => \&version,
   "h|help" => \&help,
   "H|host=s" => \$opt_H,
   "U|user=s" => \$opt_U,
   "P|password=s" => \$opt_P,
   "D|domain=s" => \$opt_D,
   "T|type=s" => \$opt_T,
   "C|check=s" => \$opt_C,
   "t|timeout=i" => \$opt_t);

# ??? Maybe do some bounds checking on params here, with
# exit $ERRORS{'UNKNOWN'} if they don't make sense.
$opt_t = 10 unless defined $opt_t;		  # Set a default
$opt_T = 'Disk' unless defined $opt_T;		  # Set a default
$opt_D = '' unless defined $opt_D;		  # Set a default
$opt_C = '' unless defined $opt_C;		  # Set a default
$opt_U = 'nagios' unless defined $opt_U;	  # Set a default
$opt_P = '' unless defined $opt_P;		  # Set a default
help() unless $opt_H;				  # Required param
help() unless $opt_D;				  # Required param
help() unless $opt_P;				  # Required param
help() unless $opt_C;				  # Required param

#Just in case of problems, let's not hang NetSaint
$SIG{'ALRM'} = sub {
    print "No Answer from Host\n";
    exit $ERRORS{"UNKNOWN"};
};
alarm $opt_t;

&queryserver($opt_H,$opt_U,$opt_P,$opt_D,$opt_T,$opt_C);

alarm 0;

######################################################################
############## This subroutine does the actual checking ##############
######################################################################
sub queryserver
   {
       # asks a server about it's shares and returns the nagios status
       # arg1: server
       # arg2: user
       # arg3: password
       # arg4: domain
       # arg5: Type
       # arg5: checks

       my @found;
       my $server=shift;
       my $user=shift;
       my $password=shift;
       my $domain=shift;
       my $type=shift;
       my $checks=shift;

       if (!$checks) {
	   print "Error: to few parameters: Host, Password, Checks needed";
	   exit $ERRORS{'UNKNOWN'};
       }
       my @checks=split(',',$checks);
       my $cmd="/usr/bin/smbclient -L $server -U $user%$password -W $domain";

       my $res=open IN,"$cmd 2>&1 |";

       if (!$res) {
	   print "Error: cannot run command $cmd\n";
	   exit $ERRORS{'UNKNOWN'};
       }

       while (<IN>) {
	   s/\n//g;
	   # something wrong:
	   if ((/session setup failed/i) || (/Connection to .* failed/i)) {
	       close IN;
	       print "$_\n";
	       exit $ERRORS{'WARNING'};
	   }
	   #	   print ">$_<\n";
	   if (/^\s+(\S+)\s+$type/g) {
	       push (@found,$1);
	   }
       }
       close IN;

       my $problem=0;
       my $next=0;
       foreach (@checks) {
	   my $check=$_;
	   my $ok=0;
	   foreach (@found) {
	       my $found=$_;
	       my $lookfor=$found;
	       my $checkfor=$check;
	       $lookfor=~s/\$/#/g;
	       $checkfor=~s/\$/#/g;
	       if ($checkfor=~/^$lookfor$/i) {
		   print " - " if ($next++);
		   print "$found: exists";
		   $ok=1;
	       }
	   }
	   if (!$ok) {
	       print " - " if ($next++);
	       print "$check: missing";
	       $problem=1;
	   }
       }
       print "\n";

       if ($problem) {
	   exit $ERRORS{'CRITICAL'};
       } else {
	   exit $ERRORS{'OK'};
       }
   }

######################################################################
sub print_help() {
    print_revision($PROGNAME,'$Revision: 1.1 $ ');
    print_usage();
    print <<END_HELP;
-h, --help            Display this message.
-V, --version         Print version numbers and license information
-H, --host            Host to connect to
-t, --timeout         timeout
-U, --user            user to connect as
-P, --password        password to use
-D, --domain          Domain
-P, --password        Type of query (Disk or Printer)
-C, --check           checked shares or printers
END_HELP
}

######################################################################
sub print_usage  {
    print "$PROGNAME -H host [-U user] -P password -D Domain -T type (Disk|Printer) -C check1[,check2] [-t timeout]\n";
    print "$PROGNAME [-h | --help]\n";
    print "$PROGNAME [-V | --version]\n";
}

######################################################################
sub version {
    print_revision($PROGNAME,'$Revision: 1.1 $ ');
    exit $ERRORS{'OK'};
}

######################################################################
sub help {
    print_help();
    # The example had exit OK, but that hides mangled parameters
    exit $ERRORS{'UNKNOWN'};
}






More information about the Devel mailing list