#! /usr/bin/perl -T # anders@aftenposten.no # Check if network mounts work: if they have any files, have any space used, # and. Script will time out if there is a hang. # # 2008-12-15: Fix for Linux: use POSIX output from df. # 2005-08-15: Initial version. # # This script can also be used to check if local filesystems are mounted and has content. package CKNetMount; use strict; use POSIX; # config: $CKNetMount::filereqnonempty = 2; $CKNetMount::kbreqnonempty = 1; $CKNetMount::okchars = '^([0-9a-zA-ZæøåÆØÅ\-_/\.]+)$'; # end, config $ENV{PATH} = "/sbin:/bin:/usr/sbin:/usr/bin"; $CKNetMount::os = (POSIX::uname)[0]; use Getopt::Std; getopts('d:f:k:X'); use vars qw { $opt_d $opt_f $opt_k $opt_X }; if ($CKNetMount::os eq "Linux") { $CKNetMount::dfcmd = "df -k -P"; } else { $CKNetMount::dfcmd = "df -k"; } if ($opt_f) { $CKNetMount::filereq = $opt_f; $CKNetMount::filetxt = "too few files"; } else { $CKNetMount::filereq = $CKNetMount::filereqnonempty; $CKNetMount::filetxt = "no files"; } if ($opt_k) { $CKNetMount::kbreq = $opt_k; $CKNetMount::kbtxt = "too little space used"; } else { $CKNetMount::kbreq = $CKNetMount::kbreqnonempty; $CKNetMount::kbtxt = "no space used"; } sub dfkbused { # $_[0]: filesys my $ckfs = $_[0]; my $fs; my $blocks; my $used; my $avail; my $capacity; my $mount; open(DF, "$CKNetMount::dfcmd $ckfs 2>/dev/null |"); while () { chomp; ($fs,$blocks,$used,$avail,$capacity,$mount) = split(/\s+/); next if ($fs eq "Filesystem"); if ($opt_X) { print "ckfs=$ckfs fs=$fs mount=$mount used=$used\n"; } if ($ckfs eq $fs || $ckfs eq $mount || ($ckfs =~ /^$mount\//)) { return $used; } elsif ($opt_X) { print "dfkbused failed df check.\n"; } } return 0; close(DF); } sub finish { # $0: text print "$_[0]\n"; exit(3); } sub usage { print "check_netmount is used to check availability of a network filesystem, for\n"; print "example a NFS or Samba mount. Usage:\n\n"; print "check_netmount -d \"\"\n\n"; print "A filesystem/dir pair can either be the path to the filesystem/mount, or the\n"; print "same, a colon, and a directory name. The directory name is an optional\n"; print "directory to scan for files instead of the filesystem itself (which can take a\n"; print "long time if there are many files there).\n\n"; print "An example of usage:\n\n"; print "check_netmount -d \"/data/www /data/bigmount:/data/bigmount/smalldir\"\n\n"; print "This Nagios plugin checks two things:\n\n"; print "1. If there are any files in the filesystem/directory.\n"; print "2. If there is any space used (contrary to check if there is any free space),\n"; print "any functional network filesystem must have some data.\n\n"; print "Check the top of the script for configuration settings.\n"; print "For a little debug info, use -X.\n"; exit(3); } sub dirok { # $_[0]: dirpair $_[1]: part $_[2]: dir my $ckdirpair = $_[0]; my $ckpart = $_[1]; my $ckdir = $_[2]; if ($ckdir) { opendir(DIR, $ckdir); } else { opendir(DIR, $ckpart); } my @files = readdir(DIR); closedir(DIR); my $kb = dfkbused($ckpart); if ($#files < $CKNetMount::filereq && $kb < $CKNetMount::kbreq) { $CKNetMount::baddirs .= " $ckdirpair ($CKNetMount::filetxt, $CKNetMount::kbtxt)"; } elsif ($#files < $CKNetMount::filereq) { $CKNetMount::baddirs .= " $ckdirpair ($CKNetMount::filetxt)"; } elsif ($kb < $CKNetMount::kbreq) { $CKNetMount::baddirs .= " $ckdirpair ($CKNetMount::kbtxt)"; } else { $CKNetMount::okdirs .= " $ckdirpair ($#files files, $kb KB used)"; return(1); } return(0); } usage unless ($opt_d); #finish("ERROR: Must specify directory/directories using -d") unless ($opt_d); $CKNetMount::baddirs = ""; my $part; my $dir; my $dirpair; foreach $dirpair (split / /, $opt_d) { if ($dirpair =~ /:/) { ($part,$dir) = split(/:/); if ($dir =~ /$CKNetMount::okchars/) { $dir = $1; } else { finish("ERROR: $dir is tainted with non-acceptable characters"); } } else { $part = $dirpair; $dir = undef; } if ($part =~ /$CKNetMount::okchars/) { $part = $1; } else { finish("ERROR: $part is tainted with non-acceptable characters"); } finish("ERROR: $part is not a filesystem") unless (-d $part); finish("ERROR: $dir is not a directory") unless ((!$dir) || -d $dir); dirok($dirpair,$part,$dir); } if ($CKNetMount::baddirs) { $CKNetMount::baddirs =~ s@^\s+@@; print "ERROR: $CKNetMount::baddirs\n"; exit(2); } elsif ($CKNetMount::okdirs) { $CKNetMount::okdirs =~ s@^\s+@@; print "OK: $CKNetMount::okdirs\n"; exit(0); } else { print "UNKNOWN: no results?\n"; exit(3); }