Code

Fix for regex input of '|', being output causing problems with Nagios' parsing of
[nagiosplug.git] / contrib / check_ms_spooler.pl
1 #!/usr/bin/perl -w
3 # $Id: check_ms_spooler.pl 64 2002-07-16 00:04:42Z stanleyhopcroft $
5 # Revision 1.1  2002/07/16 00:04:42  stanleyhopcroft
6 # Primitive and in need of refinement test of MS spooler (with smbclient)
7 #
8 # Revision 2.5  2002-02-13 07:36:08+11  anwsmh
9 # Correct 'apostrophe' disaster.
10 # Apostrophes in plugin output cause Netsaint notification commands
11 # ( sh echo 'yada $PLUGINOUTPUT$ ..') to fail, usually mysteriously
12 # eg notify OK works but notify CRITICAL does not.
13 # Replace '$var' in print "output" with \"$var\".
14 #
15 # Revision 2.4  2001-11-21 21:36:05+11  anwsmh
16 # Minor corrections
17 #  . replace 'die' by print .. exit $ERRORS{CRITICAL}
18 #  . change concluding message to list the queues (sorted) if there are no enqueued docs.
19 #
20 # Revision 2.3  2001-11-20 11:00:58+11  anwsmh
21 # Major corrections.
22 #  1. to sub AUTOLOAD: coderef parms must be @_ (ie the parm when the new sub is called)
23 #  2. to processing of queue report (no inspection of $last_line; entire $queue_report is
24 #     checked for errors)
25 #  3. cosmetic and debug changes in many places.
26 #
27 # Revision 2.2  2001-11-17 23:30:34+11  anwsmh
28 # After adapting two different queue reports resulting from
29 # different name resolution methods.
30 #
31 # Revision 2.1  2001-11-17 13:21:54+11  anwsmh
32 # Adapt to Netsaint ('use utils, Getopt::Long, and standard switch processing).
33 # Fix many peculiarities.
34 #
37 use strict ;
39 use Getopt::Long ;
40 use utils ;
42 use vars qw($opt_H $opt_s $opt_W $opt_u $opt_p $opt_w $opt_c $debug);
43 use vars '$AUTOLOAD' ;
44 use utils qw($TIMEOUT %ERRORS &print_revision &support &usage);
46 my $PROGNAME = 'check_ms_spooler' ;
48 sub print_help ();
49 sub print_usage ();
50 sub help ();
51 sub version ();
53 delete @ENV{'PATH', 'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
55 use constant SMBCLIENT_PATH     => '/usr/local/samba/bin/smbclient' ;
56 use constant MAX_QUEUES_TO_CHECK => 20 ;                # So that the check doesn't take longer than $TIMEOUT
58 use constant SMBCLIENT_SVC      => sub { return `${\SMBCLIENT_PATH} -L //$_[0] -U $_[1]%$_[2]` } ;
59 use constant SMBCLIENT_QUEUE    => sub { return `${\SMBCLIENT_PATH} //$_[0]/$_[1] -U $_[2]%$_[3] -c 'queue; quit' 2>/dev/null` } ;
61                                                         # The queue results depend on the name resolution method.
63                                                         # Forcing 'wins' or 'bcat' name resolution makes the queue results the
64                                                         # same for all spoolers (those that are resolved with WINS have an extra line
65                                                         # 'Got a positive name query response from <ip address of WINS> ..)
66                                                         # but would fail if there is no WINS and when miscreant spoolers
67                                                         # don't respond to broadcasts.
69 use constant MIN                => sub { my $min = $_[0] ; foreach (@_) { $min = $_ if $_ <= $min; } return $min ; } ;
71 $SIG{"ALRM"} = sub { die "Alarm clock restart" } ;
73 Getopt::Long::Configure('bundling', 'no_ignore_case');
74 GetOptions
75         ("V|version"     => \&version,
76          "h|help"        => \&help,
77          "d|debug"       => \$debug,
78          "p|password=s"  => \$opt_p,
79          "u|username=s"  => \$opt_u,
80          "H|hostname=s"  => \$opt_H);
84 ($opt_H) || usage("MS Spooler name not specified\n");
85 my $spooler = $1 if $opt_H =~ m#(\w+)# ;                # MS host names allow __any__ characters (more than \w)
86 ($spooler) || usage("Invalid MS spooler name: $opt_H\n");
88 ($opt_u) || ($opt_u = 'guest');
89 my $user = $1 if $opt_u =~ m#(\w+)# ;
90 ($user) || usage("Invalid user: $opt_u\n");
92 ($opt_p) || ($opt_p = 'guest');
93 my $pass = $1 if ($opt_p =~ /(.*)/);
94 ($pass) || usage("Invalid password: $opt_p\n");
96 my ($printer, $queue, @queues, $ms_spooler_status, @results, %junk) ;
97 my (@fault_messages, @queue_contents, @services, @prandom_queue_indices) ;
98 my ($queue_contents, $number_of_queues, $state, $queue_report) ;
100 $state = "getting service list (${\SMBCLIENT_PATH} -L $spooler -U $user%$pass) from spooler\n" ;
102 eval {
103   alarm($TIMEOUT) ;
104   @services = SMBCLIENT_SVC->( $spooler, $user, $pass ) ;
105 } ;
106 alarm(0) ;
108 if ($@ and $@ !~ /Alarm clock restart/) {
109   print "Failed. $PROGNAME failed $state. Got \"$@\"\n" ;
110   exit $ERRORS{"CRITICAL"} ;
113 if ($@ and $@ =~ /Alarm clock restart/) {
114   print "Failed. $PROGNAME timed out $state. Got \"@services\"\n" ;
115   exit $ERRORS{"CRITICAL"} ;
118 # tsitc> /usr/local/samba/bin/smbclient //ipaprint1/tt03 -U blah%blah -P -c 'queue; quit'
119 # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
120 # Connection to ipaprint1 failed
122 # tsitc> /usr/local/samba/bin/smbclient -L sna_spl1 -U blah%blah | & more
123 # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
124 # Got a positive name query response from 10.0.100.29 ( 10.0.6.20 )
125 # session setup failed: ERRDOS - ERRnoaccess (Access denied.)
127 if ( grep /Connection to $spooler failed|ERR/, @services ) {
128   print "Failed. $PROGNAME failed $state. Got \"@services\"\n" ;
129   # print "Failed. Request for services list to $spooler failed. Got \"@services\"\n" ;
130   exit $ERRORS{"CRITICAL"} ;
133 # tsitc# /usr/local/samba/bin/smbclient -L ipaprint -U blah%blah
134 # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
135 # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
136
137 #         Sharename      Type      Comment
138 #         ---------      ----      -------
139 #         TH02           Printer   TH02
140 #         ADMIN$         Disk      Remote Admin
141 #         IPC$           IPC       Remote IPC
142 #         S431           Printer   S431
143 #         S402           Printer   S402
144 #         S401           Printer   S401
145 #         C$             Disk      Default share
146 #         BW01           Printer   BW01
147 #         BW02           Printer   BW02
148 #         TL11           Printer   TL11
149 #         TL07           Printer   TL07
150 #         S225           Printer   Discovery South - 2nd Floor - HP CLJ4500
151 #         S224           Printer   S224
152 #         S223           Printer   Discovery South 2nd Floor Trademarks Training
153 #         S222           Printer   S222
154 #         S203           Printer   S203
155 #         S202           Printer   S202
157 my @printers = map  { my @junk = split; $junk[0] }
158                grep { my @junk = split; defined $junk[1] and $junk[1] eq 'Printer' } @services ;
159                                                 # don't check IPC$, ADMIN$ etc.
161 $ms_spooler_status = 0 ;
162 $number_of_queues = MIN->(MAX_QUEUES_TO_CHECK, (scalar(@services) >> 3) + 1) ;
164 $state = "checking queues on $spooler" ;
166 eval {
167                                                 # foreach queues to check
168                                                 #   generate a pseudo-random int in 0 .. $#printers
169                                                 #   drop it if the index has already been generated ;
171   %junk = () ;
172   @prandom_queue_indices = grep { ! $junk{$_}++ } 
173                            map  { int( rand($#printers) ) } ( 1 .. $number_of_queues ) ;
175   @queues = @printers[@prandom_queue_indices] ;
177   # @queues = @printers[ map { int( rand($#printers) ) } ( 1 .. $number_of_queues ) ] ;
179   alarm($TIMEOUT) ;
181   @queue_contents = @fault_messages = () ;
183   foreach $printer (sort @queues) {
185     # Expect 3 lines from a queue report.
186     # If queue is empty, last line is null otherwise
187     # it will contain a queue report or an SMB error
188     
189     # Empty Queue.
190     # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
191     # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
193     # Queue command from a spooler with a DNS name.  
194     # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
195     # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
196     # 65       16307        Microsoft Word - Servicesweoffer2.doc
197     # 68       10410        Microsoft Word - Servicesweoffer.doc
198     # 143      24997        Microsoft Word - Miss Samantha Anne Craig.doc
199     # 182      15635        Microsoft Word - services we provide.doc
200   
201     # Error.
202     # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
203     # Domain=[IPAUSTRALIA] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
204     # tree connect failed: ERRDOS - ERRnosuchshare (You specified an invalid share name)
205   
206     # Can't connect error.
207     # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
208     # Connection to sna_spl2 failed
209   
210   
211     # Empty Queue from a spooler with no DNS name, NetBIOS name resolved by WINS.
212     # Added interface ip=10.0.100.252 bcast=10.255.255.255 nmask=255.0.0.0
213     # Got a positive name query response from 10.0.100.29 ( 10.0.6.20 )
214     # Domain=[SNA_PRINT] OS=[Windows NT 4.0] Server=[NT LAN Manager 4.0]
215   
216     # There are 3 lines of output from smbclient for those spoolers whose names are
217     # resolved by WINS (because those names are NetBIOS and therefore not in DNS);
218     # 4 lines for errors or enqueued jobs
219   
220     print STDERR "${\SMBCLIENT_PATH} //$spooler/$printer -U $user%$pass -c 'queue; quit' ==>\n" if $debug ;
221   
222     @results = SMBCLIENT_QUEUE->( $spooler, $printer, $user, $pass ) ;
224     print STDERR "\"@results\"\n" if $debug ;
225     
226     # set $ms_spooler_status somehow
227   
228     chomp( @results ) ;
229     $queue_report = queue_report->(@results) ;
230     print STDERR '$queue_report for $printer ', "$printer: \"$queue_report\"\n\n" if $debug ;
231   
232     if ( defined $queue_report and ($queue_report !~ /ERR/ && $queue_report !~ /failed/) ) {
233       $ms_spooler_status = 1 ;
234       push @queue_contents, "$printer: $queue_report" if $queue_report ;
235     } else {
236       push @fault_messages, "$printer: $queue_report" ;
237     }
238   }
239   alarm(0) ;
240 } ;
242 if ($@ and $@ !~ /Alarm clock restart/) {
243   print "Failed. $PROGNAME failed at $state. Got \"$@\"\n" ;
244   exit $ERRORS{"CRITCAL"} ;
247 if ($@ and $@ =~ /Alarm clock restart/) {
248   my $i ;
249   foreach (@queues) { $i++ ; last if $_ eq $printer } 
250   print "Failed. Timed out connecting to $printer ($i of $number_of_queues) on //$spooler after $TIMEOUT secs. Got \"@fault_messages\"\n" ;
251   exit $ERRORS{"CRITICAL"} ;
253   
254 if (! $ms_spooler_status) {
255   print "Failed. Couldn't connect to @queues on //$spooler as user $user. Got \"@fault_messages\"\n" ;
256   exit $ERRORS{"CRITICAL"} ;
259 $queue_contents = ( @queue_contents != 0 ? join(" ", (@queue_contents == 1 ? "Queue" : "Queues"), @queue_contents) :
260                                            "All Queues empty" ) ;
261   
262 print "Ok. Connected to ", $queue_contents =~ /empty$/ ? "@{[sort @queues]}" : scalar @queues, " queues on //$spooler. $queue_contents\n" ;
263 exit $ERRORS{"OK"} ;
265 sub print_usage () {
266         print "Usage: $PROGNAME -H <spooler> -u <user> -p <password>\n";
269 sub print_help () {
270         print_revision($PROGNAME,'$Revision: 64 $ ');
271         print "Copyright (c) 2001 Karl DeBisschop/S Hopcroft
273 Perl Check MS Spooler plugin for NetSaint. Display a subset of the queues on an SMB (Samba or MS) print spooler.
275 ";
276         print_usage();
277         print '
278 -H, --hostname=STRING
279    NetBIOS name of the SMB Print spooler (Either Samba or MS spooler)
280 -u, --user=STRING
281    Username to log in to server. (Default: "guest")
282 -p, --password=STRING
283    Password to log in to server. (Default: "guest")
284 -d, --debug
285    Debugging output.
286 -h, --help
287    This stuff.
289 ';
290         support();
293 sub version () {
294         print_revision($PROGNAME,'$Revision: 64 $ ');
295         exit $ERRORS{'OK'};
298 sub help () {
299         print_help();
300         exit $ERRORS{'OK'};
303 sub AUTOLOAD {
305   my @queue_rep = @_ ;
307   # 'Object Oriented Perl', D Conway, p 95
309   no strict 'refs' ;
311   if ( $AUTOLOAD =~ /.*::queue_report/ ) {
313     if ( grep /Got a positive name query response from/, @queue_rep ){
314       *{$AUTOLOAD} = sub { return join ' ', splice(@_, 3) } ;
315       return join '', splice(@queue_rep, 3) ;
316     } else {
317       *{$AUTOLOAD} = sub { return join ' ',splice(@_, 2) } ;
318       return join '', splice(@queue_rep, 2) ;
319     }
320   } else {
321     die "No such subroutine: $AUTOLOAD" ;
322   }