1 /******************************************************************************
2 *
3 * CHECK_HPJD.C
4 *
5 * Program: HP printer plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8 *
9 * Last Modified: $Date$
10 *
11 * Command line: CHECK_HPJD <ip_address> [community]
12 *
13 * Description:
14 *
15 * This plugin will attempt to check the status of an HP printer. The
16 * printer must have a JetDirect card installed and TCP/IP protocol
17 * stack enabled. This plugin has only been tested on a few printers
18 * and may not work well on all models of JetDirect cards. Multiple
19 * port JetDirect devices must have an IP address assigned to each
20 * port in order to be monitored.
21 *
22 * Dependencies:
23 *
24 * This plugin used the 'snmpget' command included with the UCD-SNMP
25 * package. If you don't have the package installed you will need to
26 * download it from http://ucd-snmp.ucdavis.edu before you can use
27 * this plugin.
28 *
29 * Return Values:
30 *
31 * UNKNOWN = The plugin could not read/process the output from the printer
32 * OK = Printer looks normal
33 * WARNING = Low toner, paper jam, intervention required, paper out, etc.
34 * CRITICAL = The printer could not be reached (it's probably turned off)
35 *
36 * Acknowledgements:
37 *
38 * The idea for the plugin (as well as some code) were taken from Jim
39 * Trocki's pinter alert script in his "mon" utility, found at
40 * http://www.kernel.org/software/mon
41 *
42 * Notes:
43 * 'JetDirect' is copyrighted by Hewlett-Packard.
44 * HP, please don't sue me... :-)
45 *
46 * License Information:
47 *
48 * This program is free software; you can redistribute it and/or modify
49 * it under the terms of the GNU General Public License as published by
50 * the Free Software Foundation; either version 2 of the License, or
51 * (at your option) any later version.
52 *
53 * This program is distributed in the hope that it will be useful,
54 * but WITHOUT ANY WARRANTY; without even the implied warranty of
55 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
56 * GNU General Public License for more details.
57 *
58 * You should have received a copy of the GNU General Public License
59 * along with this program; if not, write to the Free Software
60 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
61 *
62 *****************************************************************************/
64 #include "common.h"
65 #include "popen.h"
66 #include "utils.h"
68 const char *progname = "check_hpjd";
69 #define REVISION "$Revision$"
70 #define COPYRIGHT "2000-2002"
72 #define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
73 #define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
74 #define HPJD_INTERVENTION_REQUIRED ".1.3.6.1.4.1.11.2.3.9.1.1.2.3"
75 #define HPJD_GD_PERIPHERAL_ERROR ".1.3.6.1.4.1.11.2.3.9.1.1.2.6"
76 #define HPJD_GD_PAPER_JAM ".1.3.6.1.4.1.11.2.3.9.1.1.2.8"
77 #define HPJD_GD_PAPER_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.9"
78 #define HPJD_GD_TONER_LOW ".1.3.6.1.4.1.11.2.3.9.1.1.2.10"
79 #define HPJD_GD_PAGE_PUNT ".1.3.6.1.4.1.11.2.3.9.1.1.2.11"
80 #define HPJD_GD_MEMORY_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.12"
81 #define HPJD_GD_DOOR_OPEN ".1.3.6.1.4.1.11.2.3.9.1.1.2.17"
82 #define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19"
83 #define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3"
85 #define ONLINE 0
86 #define OFFLINE 1
88 #define DEFAULT_COMMUNITY "public"
90 int process_arguments (int, char **);
91 int validate_arguments (void);
92 void print_help (void);
93 void print_usage (void);
95 char *community = DEFAULT_COMMUNITY;
96 char *address = NULL;
99 int
100 main (int argc, char **argv)
101 {
102 char command_line[1024];
103 int result;
104 int line;
105 char input_buffer[MAX_INPUT_BUFFER];
106 char query_string[512];
107 char error_message[MAX_INPUT_BUFFER];
108 char *temp_buffer;
109 int line_status = ONLINE;
110 int paper_status = 0;
111 int intervention_required = 0;
112 int peripheral_error = 0;
113 int paper_jam = 0;
114 int paper_out = 0;
115 int toner_low = 0;
116 int page_punt = 0;
117 int memory_out = 0;
118 int door_open = 0;
119 int paper_output = 0;
120 char display_message[MAX_INPUT_BUFFER];
122 if (process_arguments (argc, argv) != OK)
123 usage ("Invalid command arguments supplied\n");
125 /* removed ' 2>1' at end of command 10/27/1999 - EG */
126 /* create the query string */
127 sprintf
128 (query_string,
129 "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0",
130 HPJD_LINE_STATUS,
131 HPJD_PAPER_STATUS,
132 HPJD_INTERVENTION_REQUIRED,
133 HPJD_GD_PERIPHERAL_ERROR,
134 HPJD_GD_PAPER_JAM,
135 HPJD_GD_PAPER_OUT,
136 HPJD_GD_TONER_LOW,
137 HPJD_GD_PAGE_PUNT,
138 HPJD_GD_MEMORY_OUT,
139 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
141 /* get the command to run */
142 sprintf (command_line, "%s -m : -v 1 %s -c %s %s", PATH_TO_SNMPGET, address,
143 community, query_string);
145 /* run the command */
146 child_process = spopen (command_line);
147 if (child_process == NULL) {
148 printf ("Could not open pipe: %s\n", command_line);
149 return STATE_UNKNOWN;
150 }
152 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
153 if (child_stderr == NULL) {
154 printf ("Could not open stderr for %s\n", command_line);
155 }
157 result = STATE_OK;
159 line = 0;
160 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
162 /* strip the newline character from the end of the input */
163 if (input_buffer[strlen (input_buffer) - 1] == '\n')
164 input_buffer[strlen (input_buffer) - 1] = 0;
166 line++;
168 temp_buffer = strtok (input_buffer, "=");
169 temp_buffer = strtok (NULL, "=");
171 switch (line) {
173 case 1: /* 1st line should contain the line status */
174 if (temp_buffer != NULL)
175 line_status = atoi (temp_buffer);
176 else {
177 result = STATE_UNKNOWN;
178 strcpy (error_message, input_buffer);
179 }
180 break;
182 case 2: /* 2nd line should contain the paper status */
183 if (temp_buffer != NULL)
184 paper_status = atoi (temp_buffer);
185 else {
186 result = STATE_UNKNOWN;
187 strcpy (error_message, input_buffer);
188 }
189 break;
191 case 3: /* 3rd line should be intervention required */
192 if (temp_buffer != NULL)
193 intervention_required = atoi (temp_buffer);
194 else {
195 result = STATE_UNKNOWN;
196 strcpy (error_message, input_buffer);
197 }
198 break;
200 case 4: /* 4th line should be peripheral error */
201 if (temp_buffer != NULL)
202 peripheral_error = atoi (temp_buffer);
203 else {
204 result = STATE_UNKNOWN;
205 strcpy (error_message, input_buffer);
206 }
207 break;
209 case 5: /* 5th line should contain the paper jam status */
210 if (temp_buffer != NULL)
211 paper_jam = atoi (temp_buffer);
212 else {
213 result = STATE_UNKNOWN;
214 strcpy (error_message, input_buffer);
215 }
216 break;
218 case 6: /* 6th line should contain the paper out status */
219 if (temp_buffer != NULL)
220 paper_out = atoi (temp_buffer);
221 else {
222 result = STATE_UNKNOWN;
223 strcpy (error_message, input_buffer);
224 }
225 break;
227 case 7: /* 7th line should contain the toner low status */
228 if (temp_buffer != NULL)
229 toner_low = atoi (temp_buffer);
230 else {
231 result = STATE_UNKNOWN;
232 strcpy (error_message, input_buffer);
233 }
234 break;
236 case 8: /* did data come too slow for engine */
237 if (temp_buffer != NULL)
238 page_punt = atoi (temp_buffer);
239 else {
240 result = STATE_UNKNOWN;
241 strcpy (error_message, input_buffer);
242 }
243 break;
245 case 9: /* did we run out of memory */
246 if (temp_buffer != NULL)
247 memory_out = atoi (temp_buffer);
248 else {
249 result = STATE_UNKNOWN;
250 strcpy (error_message, input_buffer);
251 }
252 break;
254 case 10: /* is there a door open */
255 if (temp_buffer != NULL)
256 door_open = atoi (temp_buffer);
257 else {
258 result = STATE_UNKNOWN;
259 strcpy (error_message, input_buffer);
260 }
261 break;
263 case 11: /* is output tray full */
264 if (temp_buffer != NULL)
265 paper_output = atoi (temp_buffer);
266 else {
267 result = STATE_UNKNOWN;
268 strcpy (error_message, input_buffer);
269 }
270 break;
272 case 12: /* display panel message */
273 if (temp_buffer != NULL)
274 strcpy (display_message, temp_buffer + 1);
275 else {
276 result = STATE_UNKNOWN;
277 strcpy (error_message, input_buffer);
278 }
279 break;
281 default:
282 break;
283 }
285 /* break out of the read loop if we encounter an error */
286 if (result != STATE_OK)
287 break;
288 }
290 /* WARNING if output found on stderr */
291 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
292 result = max_state (result, STATE_WARNING);
294 /* close stderr */
295 (void) fclose (child_stderr);
297 /* close the pipe */
298 if (spclose (child_process))
299 result = max_state (result, STATE_WARNING);
301 /* if there wasn't any output, display an error */
302 if (line == 0) {
304 /*
305 result=STATE_UNKNOWN;
306 strcpy(error_message,"Error: Could not read plugin output\n");
307 */
309 /* might not be the problem, but most likely is.. */
310 result = STATE_UNKNOWN;
311 sprintf (error_message, "Timeout: No response from %s\n", address);
312 }
314 /* if we had no read errors, check the printer status results... */
315 if (result == STATE_OK) {
317 if (paper_jam) {
318 result = STATE_WARNING;
319 strcpy (error_message, "Paper Jam");
320 }
321 else if (paper_out) {
322 result = STATE_WARNING;
323 strcpy (error_message, "Out of Paper");
324 }
325 else if (line_status == OFFLINE) {
326 if (strcmp (error_message, "POWERSAVE ON") != 0) {
327 result = STATE_WARNING;
328 strcpy (error_message, "Printer Offline");
329 }
330 }
331 else if (peripheral_error) {
332 result = STATE_WARNING;
333 strcpy (error_message, "Peripheral Error");
334 }
335 else if (intervention_required) {
336 result = STATE_WARNING;
337 strcpy (error_message, "Intervention Required");
338 }
339 else if (toner_low) {
340 result = STATE_WARNING;
341 strcpy (error_message, "Toner Low");
342 }
343 else if (memory_out) {
344 result = STATE_WARNING;
345 strcpy (error_message, "Insufficient Memory");
346 }
347 else if (door_open) {
348 result = STATE_WARNING;
349 strcpy (error_message, "A Door is Open");
350 }
351 else if (paper_output) {
352 result = STATE_WARNING;
353 strcpy (error_message, "Output Tray is Full");
354 }
355 else if (page_punt) {
356 result = STATE_WARNING;
357 strcpy (error_message, "Data too Slow for Engine");
358 }
359 else if (paper_status) {
360 result = STATE_WARNING;
361 strcpy (error_message, "Unknown Paper Error");
362 }
363 }
365 if (result == STATE_OK)
366 printf ("Printer ok - (%s)\n", display_message);
368 else if (result == STATE_UNKNOWN) {
370 printf ("%s\n", error_message);
372 /* if printer could not be reached, escalate to critical */
373 if (strstr (error_message, "Timeout"))
374 result = STATE_CRITICAL;
375 }
377 else if (result == STATE_WARNING)
378 printf ("%s (%s)\n", error_message, display_message);
380 return result;
381 }
387 /* process command-line arguments */
388 int
389 process_arguments (int argc, char **argv)
390 {
391 int c;
393 #ifdef HAVE_GETOPT_H
394 int option_index = 0;
395 static struct option long_options[] = {
396 {"hostname", required_argument, 0, 'H'},
397 {"community", required_argument, 0, 'C'},
398 /* {"critical", required_argument,0,'c'}, */
399 /* {"warning", required_argument,0,'w'}, */
400 /* {"port", required_argument,0,'P'}, */
401 {"version", no_argument, 0, 'V'},
402 {"help", no_argument, 0, 'h'},
403 {0, 0, 0, 0}
404 };
405 #endif
407 if (argc < 2)
408 return ERROR;
411 while (1) {
412 #ifdef HAVE_GETOPT_H
413 c = getopt_long (argc, argv, "+hVH:C:", long_options, &option_index);
414 #else
415 c = getopt (argc, argv, "+?hVH:C:");
416 #endif
418 if (c == -1 || c == EOF || c == 1)
419 break;
421 switch (c) {
422 case 'H': /* hostname */
423 if (is_host (optarg)) {
424 address = strscpy(address, optarg) ;
425 }
426 else {
427 usage ("Invalid host name\n");
428 }
429 break;
430 case 'C': /* community */
431 community = strscpy (community, optarg);
432 break;
433 case 'V': /* version */
434 print_revision (progname, REVISION);
435 exit (STATE_OK);
436 case 'h': /* help */
437 print_help ();
438 exit (STATE_OK);
439 case '?': /* help */
440 usage ("Invalid argument\n");
441 }
442 }
444 c = optind;
445 if (address == NULL) {
446 if (is_host (argv[c])) {
447 address = argv[c++];
448 }
449 else {
450 usage ("Invalid host name");
451 }
452 }
454 if (argv[c] != NULL ) {
455 community = argv[c];
456 }
458 return validate_arguments ();
459 }
465 int
466 validate_arguments (void)
467 {
468 return OK;
469 }
475 void
476 print_help (void)
477 {
478 print_revision (progname, REVISION);
479 printf
480 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
481 "This plugin tests the STATUS of an HP printer with a JetDirect card.\n"
482 "Net-snmp must be installed on the computer running the plugin.\n\n");
483 print_usage ();
484 printf
485 ("\nOptions:\n"
486 " -H, --hostname=STRING or IPADDRESS\n"
487 " Check server on the indicated host\n"
488 " -C, --community=STRING\n"
489 " The SNMP community name (default=%s)\n"
490 " -h, --help\n"
491 " Print detailed help screen\n"
492 " -V, --version\n" " Print version information\n\n",DEFAULT_COMMUNITY);
493 support ();
494 }
500 void
501 print_usage (void)
502 {
503 printf
504 ("Usage: %s -H host [-C community]\n"
505 " %s --help\n"
506 " %s --version\n", progname, progname, progname);
507 }
510 /*
511 if(argc<2||argc>3){
512 printf("Incorrect number of arguments supplied\n");
513 printf("\n");
514 print_revision(argv[0],"$Revision$");
515 printf("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n");
516 printf("License: GPL\n");
517 printf("\n");
518 printf("Usage: %s <ip_address> [community]\n",argv[0]);
519 printf("\n");
520 printf("Note:\n");
521 printf(" <ip_address> = The IP address of the JetDirect card\n");
522 printf(" [community] = An optional community string used for SNMP communication\n");
523 printf(" with the JetDirect card. The default is 'public'.\n");
524 printf("\n");
525 return STATE_UNKNOWN;
526 }
528 // get the IP address of the JetDirect device
529 strcpy(address,argv[1]);
531 // get the community name to use for SNMP communication
532 if(argc>=3)
533 strcpy(community,argv[2]);
534 else
535 strcpy(community,"public");
536 */