aboutsummaryrefslogtreecommitdiff
path: root/libexec/check_mount
diff options
context:
space:
mode:
Diffstat (limited to 'libexec/check_mount')
-rw-r--r--libexec/check_mount152
1 files changed, 152 insertions, 0 deletions
diff --git a/libexec/check_mount b/libexec/check_mount
new file mode 100644
index 0000000..31481c1
--- /dev/null
+++ b/libexec/check_mount
@@ -0,0 +1,152 @@
+#!perl
+#
+# This plugin takes a mountpoint and checks that a filesystem is mounted
+# thereupon, once and once only.
+#
+# Author: Tom Ryder <tom@sanctum.geek.nz>
+# License: MIT
+#
+package main;
+
+# Force me to write this properly
+use strict;
+use warnings;
+use utf8;
+
+# Require at least this Perl version
+use 5.010_001;
+
+# Import required modules
+use English qw(-no_match_vars);
+use Exception::Class ( PluginException => { alias => 'throw' } );
+use Monitoring::Plugin qw(%ERRORS);
+use Path::Tiny;
+use Quota;
+use Try::Tiny;
+
+# Decree package version
+our $VERSION = '1.00';
+
+# Add description and license package variables
+our $DESCRIPTION = <<'EOF';
+This plugin takes a mountpoint and checks that a filesystem is mounted
+thereupon, once and once only.
+EOF
+our $LICENSE = <<'EOF';
+MIT License <https://opensource.org/licenses/MIT>
+EOF
+
+# Custom plugin options
+our @OPTS = (
+ {
+ spec => 'mountpoint|m=s',
+ help => 'Path to mountpoint',
+ label => 'PATH',
+ required => 1,
+ },
+);
+
+# Build Monitoring::Plugin object
+my $mp = Monitoring::Plugin->new(
+ usage => 'Usage: %s --mountpoint|-m PATH',
+ version => $VERSION,
+ blurb => $DESCRIPTION,
+ license => $LICENSE,
+);
+
+# Anything that dies in here raises ->plugin_die()
+try {
+
+ # Add and read custom options
+ for my $opt (@OPTS) {
+ $mp->add_arg( %{$opt} );
+ }
+ $mp->getopts();
+
+ # Start counting down to timeout
+ alarm $mp->opts->timeout();
+
+ # Get a cleaned-up and absolute path for the mountpoint
+ length $mp->opts->mountpoint
+ or throw 'Empty mountpoint path';
+ my $point = path( $mp->opts->mountpoint )->realpath();
+ $point->exists()
+ or throw "$point does not exist";
+ $point->is_dir()
+ or throw "$point is not a directory";
+
+ # Read the mount table row by row and collect any entries that correspond
+ # to our mountpoint
+ my @mounts = grep { $_->{path} eq $point } mounts();
+
+ # Make a string for the message that describes the device and type for each
+ # of the matching mounts, comma-separated
+ my $devs = join q(, ), map { "$_->{dev} ($_->{type})" } @mounts;
+
+ # One mount is ideal; exit OK, describing the mounted devices and the
+ # filesytem types
+ if ( @mounts == 1 ) {
+ $mp->add_message( $ERRORS{OK}, "Mounted on $point: $devs\n" );
+ }
+
+ # More than one mount is not ideal; exit WARNING, describing the mounted
+ # devices and the filesystem types
+ elsif ( @mounts > 1 ) {
+ $mp->add_message( $ERRORS{WARNING}, "Multi mounts on $point: $devs\n" );
+ }
+
+ # No matching mount at all is bad
+ else {
+ $mp->add_message( $ERRORS{CRITICAL}, "No mounts found on $point\n" );
+ }
+
+ # Exit with the selected code and message
+ $mp->plugin_exit( $mp->check_messages );
+}
+catch {
+ $mp->plugin_die($_);
+};
+
+# Return a listref of hashrefs describing every mount table entry
+sub mounts {
+
+ # Open mount table for reading, throw on error (return great than zero)
+ Quota::setmntent() == 0
+ or throw Quota::strerr();
+
+ # Iterate through each mount table entry to collect a list. The
+ # getmntent() function here returns an empty list when it's read the whole
+ # table, and undef on error in place of what would normally be the device,
+ # so this may seem a bit awkward on first reading.
+ #
+ my @mounts;
+ while ( my @mnt = Quota::getmntent() ) {
+
+ # Check the first element; if it's undefined, there was an error, and
+ # we should bail out
+ defined $mnt[0]
+ or throw Quota::strerr();
+
+ # Otherwise, this really is a mountpoint entry; extract the device,
+ # mountpoint, and filesystem type
+ my ( $dev, $path, $type ) = @mnt;
+ length $path or next;
+
+ # Build a hash structure including canonicalising and resolving the
+ # path, and add it as a reference to the mounts collection
+ my %mount = (
+ dev => $dev || 'unknown',
+ path => path($path)->realpath(),
+ type => $type || 'unknown',
+ );
+ push @mounts, \%mount;
+ }
+
+ # Close mount table
+ Quota::endmntent();
+
+ # Return collected mounts
+ return @mounts;
+}
+
+1;