#!/usr/bin/perl
#
# Monitor file system mount state.
#
# Written by Xueshan Feng <sfeng@stanford.edu>
#
# Copyright 2012, Board of Trustees, Leland Stanford Jr. University

use strict;
use warnings;
use Getopt::Long qw(GetOptions);
use vars qw(%ERRORS $VERBOSE $MOUNTFILE);

$ENV{'PATH'} = '/usr/sbin:/sbin:/usr/bin:/bin';

# Return code
%ERRORS=('OK'=>0,'WARNING'=>1,'CRITICAL'=>2,'UNKNOWN'=>3,'DEPENDENT'=>4);

# If show mounted file systems, default no.
$VERBOSE = 0;

# flush output
$| = 1;
# Clean up the program name for error reporting.
$0 =~ s%.*/%%;

# mount point file
$MOUNTFILE = "/proc/mounts";

##############
# Main process
##############
{
    my $rc = $ERRORS{'OK'};
    my $dirtyoutput;
    my $cleanoutput;
    parseOps();

    my $id=getpwuid($<);

    if ( $id ne "root" ) {
        print "Must be run as root!\n";
        exit $ERRORS{'WARNING'};
    }

    open(DATAFILE, $MOUNTFILE) or die "Cannot open $MOUNTFILE: $!\n";
    while (my $m = <DATAFILE>) {
        my ($dev, $mpt) = (split(/\s+/, $m))[0,1];
        # Run dumpe2fs, close stderr to get rid of version info, keep stdout.
        my @results = `/sbin/dumpe2fs -h $dev 2>&- | grep 'Filesystem state:'`;
        foreach my $i (@results) {
            chomp $i;
            $i =~ s/Filesystem state://;
            $i =~ s/\s+/ /;
            if ( $i =~ /error/ ) {
                $dirtyoutput .= "$mpt $i ";
                $rc = $ERRORS{'CRITICAL'};
            } else {
                $cleanoutput .= "$mpt ";
            }
        }
    }
    if ( $rc ) {
        print "CRITICAL - $dirtyoutput\n";
    } else {
        $VERBOSE ? print "OK - Filesystem state clean: $cleanoutput\n" : 
                   print "OK - Filesystem state clean\n";
    }
    exit $rc;
}

##############
# Sub routines
##############

# Get command line options
sub parseOps {
    # Parse command line options.
    my ($help);
    Getopt::Long::config ('bundling', 'no_ignore_case');
    GetOptions (
            'verbose|v' => \$VERBOSE,
            'help|h'    => \$help,
    ) or exit 3;
    if ($help) {
        help();
        exit 0;
   }
}

# Perldoc
sub help {
    my ($msg) = @_;

    print "$msg\n\n" if $msg;
    print "Feeding myself to perldoc, please wait....\n";
    exec( 'perldoc', '-t', $0 );
}

# Documentation.

=for stopwords
Xueshan Feng

=head1 NAME

check-filesystem-state - check file system mount state. 

=head1 SYNOPSIS

check-filesystem-state [--help] [--verbose]

Show file system mount state. Return 0 if all file systems are mounted clean. 
Return 2 if any mounted file system is not clean, along with the file system 
mount point for the dirty file system(s). If --verbose is given, show mount 
points as well even when all file systems are mounted clean.

=head1 AUTHOR

Xueshan Feng <sfeng@stanford.edu>

=cut
