check_disk_smb.pl 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. #!@PERL@ -w
  2. #
  3. #
  4. # check_disk.pl <host> <share> <user> <pass> [warn] [critical] [port]
  5. #
  6. # Nagios host script to get the disk usage from a SMB share
  7. #
  8. # Changes and Modifications
  9. # =========================
  10. # 7-Aug-1999 - Michael Anthon
  11. # Created from check_disk.pl script provided with netsaint_statd (basically
  12. # cause I was too lazy (or is that smart?) to write it from scratch)
  13. # 8-Aug-1999 - Michael Anthon
  14. # Modified [warn] and [critical] parameters to accept format of nnn[M|G] to
  15. # allow setting of limits in MBytes or GBytes. Percentage settings for large
  16. # drives is a pain in the butt
  17. # 2-May-2002 - SGhosh fix for embedded perl
  18. #
  19. #
  20. require 5.004;
  21. eval "use utf8::all";
  22. if ( $@ ) {
  23. use utf8::all;
  24. }
  25. use POSIX;
  26. use strict;
  27. use Getopt::Long;
  28. use vars qw($opt_P $opt_V $opt_m $opt_h $opt_H $opt_k $opt_s $opt_W $opt_u $opt_p $opt_w $opt_c $opt_a $opt_C $verbose);
  29. use vars qw($PROGNAME);
  30. use FindBin;
  31. use lib "$FindBin::Bin";
  32. use lib '@libexecdir@';
  33. use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
  34. sub print_help ();
  35. sub print_usage ();
  36. $PROGNAME = "check_disk_smb";
  37. $ENV{'PATH'}='@TRUSTED_PATH@';
  38. $ENV{'BASH_ENV'}='';
  39. $ENV{'ENV'}='';
  40. Getopt::Long::Configure('bundling');
  41. GetOptions
  42. ("v" => \$verbose, "verbose" => \$verbose,
  43. "P=s" => \$opt_P, "port=s" => \$opt_P,
  44. "V" => \$opt_V, "version" => \$opt_V,
  45. "h" => \$opt_h, "help" => \$opt_h,
  46. "k" => \$opt_k, "kerberos" => \$opt_k,
  47. "m=s" => \$opt_m, "maxprotocol=s" => \$opt_m,
  48. "w=s" => \$opt_w, "warning=s" => \$opt_w,
  49. "c=s" => \$opt_c, "critical=s" => \$opt_c,
  50. "p=s" => \$opt_p, "password=s" => \$opt_p,
  51. "u=s" => \$opt_u, "username=s" => \$opt_u,
  52. "s=s" => \$opt_s, "share=s" => \$opt_s,
  53. "W=s" => \$opt_W, "workgroup=s" => \$opt_W,
  54. "H=s" => \$opt_H, "hostname=s" => \$opt_H,
  55. "a=s" => \$opt_a, "address=s" => \$opt_a,
  56. "C=s" => \$opt_C, "configfile=s" => \$opt_C);
  57. if ($opt_V) {
  58. print_revision($PROGNAME,'@NP_VERSION@'); #'
  59. exit $ERRORS{'OK'};
  60. }
  61. if ($opt_h) {print_help(); exit $ERRORS{'OK'};}
  62. my $smbclient = $utils::PATH_TO_SMBCLIENT;
  63. $smbclient || usage("check requires smbclient, smbclient not set\n");
  64. -x $smbclient || usage("check requires smbclient, $smbclient: $!\n");
  65. # Options checking
  66. ($opt_H) || ($opt_H = shift @ARGV) || usage("Host name not specified\n");
  67. my $host = $1 if ($opt_H =~ /^([^":|<>\*\?\\\/]+)$/);
  68. ($host) || usage("Invalid host: $opt_H\n");
  69. ($opt_s) || ($opt_s = shift @ARGV) || usage("Share volume not specified\n");
  70. my $share = $1 if ($opt_s =~ /^([^":|<>\*\?\\\/]+\$?)$/);
  71. ($share) || usage("Invalid share: $opt_s\n");
  72. defined($opt_u) || ($opt_u = shift @ARGV) || ($opt_u = "guest");
  73. my $user = $1 if ($opt_u =~ /^([^":|<>\*\?\/(?<!\)]+)$/);
  74. defined($user) || usage("Invalid user: $opt_u\n");
  75. defined($opt_p) || ($opt_p = shift @ARGV) || ($opt_p = "");
  76. my $pass = $1 if ($opt_p =~ /(.*)/);
  77. defined($opt_m) || ($opt_m = shift @ARGV) || ($opt_m = "");
  78. my $maxprotocol = $1 if ($opt_m =~ /(.*)/);
  79. ($opt_w) || ($opt_w = shift @ARGV) || ($opt_w = 85);
  80. my $warn = $1 if ($opt_w =~ /^([0-9]{1,2}\%?|100\%?|[0-9]+[kMG])$/);
  81. ($warn) || usage("Invalid warning threshold: $opt_w\n");
  82. ($opt_c) || ($opt_c = shift @ARGV) || ($opt_c = 95);
  83. my $crit = $1 if ($opt_c =~ /^([0-9]{1,2}\%?|100\%?|[0-9]+[kMG])$/);
  84. ($crit) || usage("Invalid critical threshold: $opt_c\n");
  85. ($opt_C) || ($opt_C = shift @ARGV) || ($opt_C = "");
  86. my $configfile = $opt_C if ($opt_C);
  87. usage("Unable to read config file $configfile\n") if ($configfile) && (! -r $configfile);
  88. # Execute the given command line and return anything it writes to STDOUT and/or
  89. # STDERR. (This might be useful for other plugins, too, so it should possibly
  90. # be moved to utils.pm.)
  91. sub output_and_error_of {
  92. local *CMD;
  93. local $/ = undef;
  94. my $pid = open CMD, "-|";
  95. if (defined($pid)) {
  96. if ($pid) {
  97. return <CMD>;
  98. } else {
  99. open STDERR, ">&STDOUT" and exec @_;
  100. exit(1);
  101. }
  102. }
  103. return undef;
  104. }
  105. # split the type from the unit value
  106. #Check $warn and $crit for type (%/M/G) and set up for tests
  107. #P = Percent, K = KBytes
  108. my $warn_type;
  109. my $crit_type;
  110. if ($opt_w =~ /^([0-9]+)\%?$/) {
  111. $warn = "$1";
  112. $warn_type = "P";
  113. } elsif ($opt_w =~ /^([0-9]+)k$/) {
  114. $warn_type = "K";
  115. $warn = $1;
  116. } elsif ($opt_w =~ /^([0-9]+)M$/) {
  117. $warn_type = "K";
  118. $warn = $1 * 1024;
  119. } elsif ($opt_w =~ /^([0-9]+)G$/) {
  120. $warn_type = "K";
  121. $warn = $1 * 1048576;
  122. }
  123. if ($opt_c =~ /^([0-9]+)\%?$/) {
  124. $crit = "$1";
  125. $crit_type = "P";
  126. } elsif ($opt_c =~ /^([0-9]+)k$/) {
  127. $crit_type = "K";
  128. $crit = $1;
  129. } elsif ($opt_c =~ /^([0-9]+)M$/) {
  130. $crit_type = "K";
  131. $crit = $1 * 1024;
  132. } elsif ($opt_c =~ /^([0-9]+)G$/) {
  133. $crit_type = "K";
  134. $crit = $1 * 1048576;
  135. }
  136. # check if both warning and critical are percentage or size
  137. unless( ( $warn_type eq "P" && $crit_type eq "P" ) || ( $warn_type ne "P" && $crit_type ne "P" ) ){
  138. $opt_w =~ s/\%/\%\%/g;
  139. $opt_c =~ s/\%/\%\%/g;
  140. usage("Both warning and critical should be same type- warning: $opt_w critical: $opt_c \n");
  141. }
  142. # verify warning is less than critical
  143. if ( $warn_type eq "K") {
  144. unless ( $warn > $crit) {
  145. usage("Disk size: warning ($opt_w) should be greater than critical ($opt_c) \n");
  146. }
  147. }else{
  148. unless ( $warn < $crit) {
  149. $opt_w =~ s/\%/\%\%/g;
  150. $opt_c =~ s/\%/\%\%/g;
  151. usage("Percentage: warning ($opt_w) should be less than critical ($opt_c) \n");
  152. }
  153. }
  154. my $workgroup = $1 if (defined($opt_W) && $opt_W =~ /(.*)/);
  155. my $address = $1 if (defined($opt_a) && $opt_a =~ /(.*)/);
  156. # end of options checking
  157. my $state = "OK";
  158. my $answer = undef;
  159. my $res = undef;
  160. my $perfdata = "";
  161. my @lines = undef;
  162. # Just in case of problems, let's not hang Nagios
  163. $SIG{'ALRM'} = sub {
  164. print "No Answer from Client\n";
  165. exit $ERRORS{"UNKNOWN"};
  166. };
  167. alarm($TIMEOUT);
  168. # Execute a "du" on the share using smbclient program
  169. # get the results into $res
  170. my @cmd = (
  171. $smbclient,
  172. "//$host/$share",
  173. "-U", "$user%$pass",
  174. defined($maxprotocol) ? ("-m", $maxprotocol) : (),
  175. defined($workgroup) ? ("-W", $workgroup) : (),
  176. defined($address) ? ("-I", $address) : (),
  177. defined($opt_P) ? ("-p", $opt_P) : (),
  178. defined($opt_k) ? ("-k") : (),
  179. defined($configfile) ? ("-s, $configfile") : (),
  180. "-c", "du"
  181. );
  182. print join(" ", @cmd) . "\n" if ($verbose);
  183. $res = output_and_error_of(@cmd) or exit $ERRORS{"UNKNOWN"};
  184. #Turn off alarm
  185. alarm(0);
  186. #Split $res into an array of lines
  187. @lines = split /\n/, $res;
  188. #Get the last line into $_
  189. $_ = $lines[$#lines-1];
  190. #print "$_\n";
  191. #Process the last line to get free space.
  192. #If line does not match required regexp, return an UNKNOWN error
  193. if (/\s*(\d*) blocks of size (\d*)\. (\d*) blocks available/) {
  194. my ($avail_bytes) = $3 * $2;
  195. my ($total_bytes) = $1 * $2;
  196. my ($occupied_bytes) = $1 * $2 - $avail_bytes;
  197. my ($avail) = $avail_bytes/1024;
  198. my ($capper) = int(($3/$1)*100);
  199. my ($mountpt) = "\\\\$host\\$share";
  200. # TODO : why is the kB the standard unit for args ?
  201. my ($warn_bytes) = $total_bytes - $warn * 1024;
  202. if ($warn_type eq "P") {
  203. $warn_bytes = $warn * $1 * $2 / 100;
  204. }
  205. my ($crit_bytes) = $total_bytes - $crit * 1024;
  206. if ($crit_type eq "P") {
  207. $crit_bytes = $crit * $1 * $2 / 100;
  208. }
  209. if (int($avail / 1024) > 0) {
  210. $avail = int($avail / 1024);
  211. if (int($avail /1024) > 0) {
  212. $avail = (int(($avail / 1024)*100))/100;
  213. $avail = $avail ."G";
  214. } else {
  215. $avail = $avail ."M";
  216. }
  217. } else {
  218. $avail = $avail ."K";
  219. }
  220. #print ":$warn:$warn_type:\n";
  221. #print ":$crit:$crit_type:\n";
  222. #print ":$avail:$avail_bytes:$capper:$mountpt:\n";
  223. $perfdata = "'" . $share . "'=" . $occupied_bytes . 'B;'
  224. . $warn_bytes . ';'
  225. . $crit_bytes . ';'
  226. . '0;'
  227. . $total_bytes;
  228. if ($occupied_bytes > $crit_bytes) {
  229. $state = "CRITICAL";
  230. $answer = "CRITICAL: Only $avail ($capper%) free on $mountpt";
  231. } elsif ( $occupied_bytes > $warn_bytes ) {
  232. $state = "WARNING";
  233. $answer = "WARNING: Only $avail ($capper%) free on $mountpt";
  234. } else {
  235. $answer = "Disk ok - $avail ($capper%) free on $mountpt";
  236. }
  237. } else {
  238. $answer = "Result from smbclient not suitable";
  239. $state = "UNKNOWN";
  240. foreach (@lines) {
  241. if (/(Access denied|NT_STATUS_LOGON_FAILURE|NT_STATUS_ACCESS_DENIED)/) {
  242. $answer = "Access Denied";
  243. $state = "CRITICAL";
  244. last;
  245. }
  246. if (/(Unknown host \w*|Connection.*failed)/) {
  247. $answer = "$1";
  248. $state = "CRITICAL";
  249. last;
  250. }
  251. if (/(You specified an invalid share name|NT_STATUS_BAD_NETWORK_NAME)/) {
  252. $answer = "Invalid share name \\\\$host\\$share";
  253. $state = "CRITICAL";
  254. last;
  255. }
  256. }
  257. }
  258. print $answer;
  259. print " | " . $perfdata if ($perfdata);
  260. print "\n";
  261. print "$state\n" if ($verbose);
  262. exit $ERRORS{$state};
  263. sub print_usage () {
  264. print "Usage: $PROGNAME -H <host> -s <share> -u <user>
  265. -p <password> -w <warn> -c <crit> [-W <workgroup>] [-P <port>]
  266. [-a <IP>] [-C <configfile>]\n";
  267. }
  268. sub print_help () {
  269. print_revision($PROGNAME,'@NP_VERSION@');
  270. print "Copyright (c) 2000 Michael Anthon/Karl DeBisschop
  271. Perl Check SMB Disk plugin for Nagios
  272. ";
  273. print_usage();
  274. print "
  275. -H, --hostname=HOST
  276. NetBIOS name of the server
  277. -s, --share=STRING
  278. Share name to be tested
  279. -W, --workgroup=STRING
  280. Workgroup or Domain used (Defaults to \"WORKGROUP\")
  281. -a, --address=IP
  282. IP-address of HOST (only necessary if HOST is in another network)
  283. -u, --user=STRING
  284. Username to log in to server. (Defaults to \"guest\")
  285. -p, --password=STRING
  286. Password to log in to server. (Defaults to an empty password)
  287. -w, --warning=INTEGER or INTEGER[kMG]
  288. Percent of used space at which a warning will be generated (Default: 85%)
  289. -c, --critical=INTEGER or INTEGER[kMG]
  290. Percent of used space at which a critical will be generated (Defaults: 95%)
  291. -P, --port=INTEGER
  292. Port to be used to connect to. Some Windows boxes use 139, others 445 (Defaults to smbclient default)
  293. -C, --configfile=STRING
  294. Path to configfile which should be used by smbclient (Defaults to smb.conf of your smb installation)
  295. If thresholds are followed by either a k, M, or G then check to see if that
  296. much disk space is available (kilobytes, Megabytes, Gigabytes)
  297. Warning percentage should be less than critical
  298. Warning (remaining) disk space should be greater than critical.
  299. ";
  300. support();
  301. }