aboutsummaryrefslogtreecommitdiff
path: root/plugins-scripts/check_disk_smb.pl
blob: 15d163407feda3827f188dbbfe0ae8ec1afc226c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
#!@PERL@ -w
#
#
# check_disk.pl <host> <share> <user> <pass> [warn] [critical] [port]
#
# Monitoring host script to get the disk usage from a SMB share
#
# Changes and Modifications
# =========================
# 7-Aug-1999 - Michael Anthon
#  Created from check_disk.pl script provided with netsaint_statd (basically
#  cause I was too lazy (or is that smart?) to write it from scratch)
# 8-Aug-1999 - Michael Anthon
#  Modified [warn] and [critical] parameters to accept format of nnn[M|G] to
#  allow setting of limits in MBytes or GBytes.  Percentage settings for large
#  drives is a pain in the butt
# 2-May-2002 - SGhosh fix for embedded perl
#
#

require 5.004;
use POSIX qw(setsid);
use strict;
use Getopt::Long;
use vars qw($opt_P $opt_V $opt_h $opt_H $opt_s $opt_W $opt_u $opt_p $opt_w $opt_c $opt_a $opt_C $opt_t $verbose);
use vars qw($PROGNAME);
use FindBin;
use lib "$FindBin::Bin";
use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);

# make us session leader which makes all childs exit if we do
setsid;

sub print_help ();
sub print_usage ();

$PROGNAME = "check_disk_smb";

$ENV{'PATH'}='@TRUSTED_PATH@';
$ENV{'BASH_ENV'}=''; 
$ENV{'ENV'}='';

Getopt::Long::Configure('bundling');
GetOptions
	("v"   => \$verbose, "verbose"    => \$verbose,
   "t=i" => \$opt_t,  "timeout=i"  => \$opt_t,
	 "P=s" => \$opt_P, "port=s"     => \$opt_P,
	 "V"   => \$opt_V, "version"    => \$opt_V,
	 "h"   => \$opt_h, "help"       => \$opt_h,
	 "w=s" => \$opt_w, "warning=s"  => \$opt_w,
	 "c=s" => \$opt_c, "critical=s" => \$opt_c,
	 "p=s" => \$opt_p, "password=s" => \$opt_p,
	 "u=s" => \$opt_u, "username=s" => \$opt_u,
	 "s=s" => \$opt_s, "share=s"    => \$opt_s,
	 "W=s" => \$opt_W, "workgroup=s" => \$opt_W,
	 "H=s" => \$opt_H, "hostname=s" => \$opt_H,
	 "a=s" => \$opt_a, "address=s" => \$opt_a,
	 "C=s" => \$opt_C, "configfile=s" => \$opt_C);

if ($opt_V) {
	print_revision($PROGNAME,'@NP_VERSION@'); #'
	exit $ERRORS{'UNKNOWN'};
}

if ($opt_h) {print_help(); exit $ERRORS{'UNKNOWN'};}

my $smbclient = $utils::PATH_TO_SMBCLIENT;
$smbclient    || usage("check requires smbclient, smbclient not set\n");
-x $smbclient || usage("check requires smbclient, $smbclient: $!\n");

# Options checking

($opt_H) || ($opt_H = shift @ARGV) || usage("Host name not specified\n");
my $host = $1 if ($opt_H =~ /^([-_.A-Za-z0-9 ]+\$?)$/);
($host) || usage("Invalid host: $opt_H\n");

($opt_s) || ($opt_s = shift @ARGV) || usage("Share volume not specified\n");
my $share = $1 if ($opt_s =~ /^([-_.A-Za-z0-9 ]+\$?)$/);
($share) || usage("Invalid share: $opt_s\n");

defined($opt_u) || ($opt_u = shift @ARGV) || ($opt_u = "guest");
my $user = $1 if ($opt_u =~ /^([-_.A-Za-z0-9\\]*)$/);
defined($user) || usage("Invalid user: $opt_u\n");

defined($opt_p) || ($opt_p = shift @ARGV) || ($opt_p = "");
my $pass = $1 if ($opt_p =~ /(.*)/);

($opt_w) || ($opt_w = shift @ARGV) || ($opt_w = 85);
my $warn = $1 if ($opt_w =~ /^([0-9]{1,2}\%?|100\%?|[0-9]+[kMG])$/);
($warn) || usage("Invalid warning threshold: $opt_w\n");

($opt_c) || ($opt_c = shift @ARGV) || ($opt_c = 95);
my $crit = $1 if ($opt_c =~ /^([0-9]{1,2}\%?|100\%?|[0-9]+[kMG])$/);
($crit) || usage("Invalid critical threshold: $opt_c\n");

($opt_C) || ($opt_C = shift @ARGV) || ($opt_C = "");
my $configfile = $opt_C if ($opt_C);
usage("Unable to read config file $configfile\n") if ($configfile) && (! -r $configfile);

if ($opt_t && $opt_t =~ /^([0-9]+)$/) { $TIMEOUT = $1; }

# Execute the given command line and return anything it writes to STDOUT and/or
# STDERR.  (This might be useful for other plugins, too, so it should possibly
# be moved to utils.pm.)
sub output_and_error_of {
	local *CMD;
	local $/ = undef;
	my $pid = open CMD, "-|";
	if (defined($pid)) {
		if ($pid) {
			return <CMD>;
		} else {
			open STDERR, ">&STDOUT" and exec @_;
			exit(1);
		}
	}
	return undef;
}

# split the type from the unit value
#Check $warn and $crit for type (%/M/G) and set up for tests
#P = Percent, K = KBytes
my $warn_type;
my $crit_type;

if ($opt_w =~ /^([0-9]+)\%?$/) {
	$warn = "$1";
	$warn_type = "P";
} elsif ($opt_w =~ /^([0-9]+)k$/) {
	$warn_type = "K";
	$warn = $1;
} elsif ($opt_w =~ /^([0-9]+)M$/) {
	$warn_type = "K";
	$warn = $1 * 1024;
} elsif ($opt_w =~ /^([0-9]+)G$/) {
	$warn_type = "K";
	$warn = $1 * 1048576;
}
if ($opt_c =~ /^([0-9]+)\%?$/) {
	$crit = "$1";
	$crit_type = "P";
} elsif ($opt_c =~ /^([0-9]+)k$/) {
	$crit_type = "K";
	$crit = $1;
} elsif ($opt_c =~ /^([0-9]+)M$/) {
	$crit_type = "K";
	$crit = $1 * 1024;
} elsif ($opt_c =~ /^([0-9]+)G$/) {
	$crit_type = "K";
	$crit = $1 * 1048576;
}

# check if both warning and critical are percentage or size
unless( ( $warn_type eq "P" && $crit_type eq "P" ) || ( $warn_type ne "P" && $crit_type ne "P" ) ){
	$opt_w =~ s/\%/\%\%/g;
	$opt_c =~ s/\%/\%\%/g;
	usage("Both warning and critical should be same type- warning: $opt_w critical: $opt_c \n");
}

# verify warning is less than critical
if ( $warn_type eq "K") {
	unless ( $warn > $crit) {
		usage("Disk size: warning ($opt_w) should be greater than critical ($opt_c) \n");
	}
}else{
	unless ( $warn < $crit) {
		$opt_w =~ s/\%/\%\%/g;
		$opt_c =~ s/\%/\%\%/g;
		usage("Percentage: warning ($opt_w) should be less than critical ($opt_c) \n");
	}
}

my $workgroup = $1 if (defined($opt_W) && $opt_W =~ /(.*)/);

my $address = $1 if (defined($opt_a) && $opt_a =~ /(.*)/);

# end of options checking


my $state = "OK";
my $answer = undef;
my $res = undef;
my $perfdata = "";
my @lines = undef;

# Just in case of problems, let's not hang the monitoring system
$SIG{'ALRM'} = sub { 
	print "No Answer from Client\n";
    $SIG{'INT'} = 'IGNORE';
    kill(-2, $$);
	exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);

# Execute a "du" on the share using smbclient program
# get the results into $res
my @cmd = (
	$smbclient,
	"//$host/$share",
	"-U", "$user%$pass",
	defined($workgroup) ? ("-W", $workgroup) : (),
	defined($address) ? ("-I", $address) : (),
	defined($opt_P) ? ("-p", $opt_P) : (),
	defined($configfile) ? ("-s", $configfile) : (),
	"-c", "du"
);

print join(" ", @cmd) . "\n" if ($verbose);
$res = output_and_error_of(@cmd) or exit $ERRORS{"UNKNOWN"};

#Turn off alarm
alarm(0);

#Split $res into an array of lines
@lines = split /\n/, $res;

#Get the last line into $_
$_ = $lines[$#lines-1];
#print "$_\n";

#Process the last line to get free space.  
#If line does not match required regexp, return an UNKNOWN error
if (/\s*(\d*) blocks of size (\d*)\. (\d*) blocks available/) {

	my ($avail_bytes) = $3 * $2;
	my ($total_bytes) = $1 * $2;
	my ($occupied_bytes) = $1 * $2 - $avail_bytes;
	my ($avail) = $avail_bytes/1024;
	my ($capper) = int(($3/$1)*100);
	my ($mountpt) = "\\\\$host\\$share";

	# TODO : why is the kB the standard unit for args ?
	my ($warn_bytes) = $total_bytes - $warn * 1024;
	if ($warn_type eq "P") {
		$warn_bytes = $warn * $1 * $2 / 100;
	}
	my ($crit_bytes) = $total_bytes - $crit * 1024;
	if ($crit_type eq "P") {
		$crit_bytes = $crit * $1 * $2 / 100;
	}


	if (int($avail / 1024) > 0) {
		$avail = int($avail / 1024);
		if (int($avail /1024) > 0) {
			$avail = (int(($avail / 1024)*100))/100;
			$avail = $avail ."G";
		} else {
			$avail = $avail ."M";
		}
	} else {
		$avail = $avail ."K";
	}

#print ":$warn:$warn_type:\n";
#print ":$crit:$crit_type:\n";
#print ":$avail:$avail_bytes:$capper:$mountpt:\n";
	$perfdata = "'" . $share . "'=" . $occupied_bytes . 'B;'
		. $warn_bytes . ';'
		. $crit_bytes . ';'
		. '0;'
		. $total_bytes;

	if ($occupied_bytes > $crit_bytes) {
		$state = "CRITICAL";
		$answer = "CRITICAL: Only $avail ($capper%) free on $mountpt";
	} elsif ( $occupied_bytes > $warn_bytes ) {
		$state = "WARNING";
		$answer = "WARNING: Only $avail ($capper%) free on $mountpt";
	} else {
		$answer = "Disk ok - $avail ($capper%) free on $mountpt";
	}
} else {
	$answer = "Result from smbclient not suitable";
	$state = "UNKNOWN";
	foreach (@lines) {
		if (/(Access denied|NT_STATUS_LOGON_FAILURE|NT_STATUS_ACCESS_DENIED)/) {
			$answer = "Access Denied";
			$state = "CRITICAL";
			last;
		}
		if (/(Unknown host \w*|Connection.*failed)/) {
			$answer = "$1";
			$state = "CRITICAL";
			last;
		}
		if (/(You specified an invalid share name|NT_STATUS_BAD_NETWORK_NAME)/) {
			$answer = "Invalid share name \\\\$host\\$share";
			$state = "CRITICAL";
			last;
		}
	}
}


print $answer;
print " | " . $perfdata if ($perfdata);
print "\n";
print "$state\n" if ($verbose);
exit $ERRORS{$state};

sub print_usage () {
	print "Usage: $PROGNAME -H <host> -s <share> -u <user> -p <password> 
      -w <warn> -c <crit> [-W <workgroup>] [-P <port>] [-a <IP>] [-t timeout]
      [-C <configfile>]\n";
}

sub print_help () {
	print_revision($PROGNAME,'@NP_VERSION@');
	print "Copyright (c) 2000 Michael Anthon/Karl DeBisschop

Perl Check SMB Disk plugin for monitoring

";
	print_usage();
	print "
-H, --hostname=HOST
   NetBIOS name of the server
-s, --share=STRING
   Share name to be tested
-W, --workgroup=STRING
   Workgroup or Domain used (Defaults to \"WORKGROUP\")
-a, --address=IP
   IP-address of HOST (only necessary if HOST is in another network)
-u, --user=STRING
   Username to log in to server. (Defaults to \"guest\")
-p, --password=STRING
   Password to log in to server. (Defaults to an empty password)
-w, --warning=INTEGER or INTEGER[kMG]
   Percent of used space at which a warning will be generated (Default: 85%)
-c, --critical=INTEGER or INTEGER[kMG]
   Percent of used space at which a critical will be generated (Defaults: 95%)
-t, --timeout=INTEGER
   Seconds before connection times out (Default: 15)
-P, --port=INTEGER
   Port to be used to connect to. Some Windows boxes use 139, others 445 (Defaults to smbclient default)
-C, --configfile=STRING
   Path to configfile which should be used by smbclient (Defaults to smb.conf of your smb installation)
   
   If thresholds are followed by either a k, M, or G then check to see if that
   much disk space is available (kilobytes, Megabytes, Gigabytes)

   Warning percentage should be less than critical
   Warning (remaining) disk space should be greater than critical.

";
	support();
}