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 #define PROGNAME "check_hpjd"
70 #define HPJD_LINE_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.1"
71 #define HPJD_PAPER_STATUS ".1.3.6.1.4.1.11.2.3.9.1.1.2.2"
72 #define HPJD_INTERVENTION_REQUIRED ".1.3.6.1.4.1.11.2.3.9.1.1.2.3"
73 #define HPJD_GD_PERIPHERAL_ERROR ".1.3.6.1.4.1.11.2.3.9.1.1.2.6"
74 #define HPJD_GD_PAPER_JAM ".1.3.6.1.4.1.11.2.3.9.1.1.2.8"
75 #define HPJD_GD_PAPER_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.9"
76 #define HPJD_GD_TONER_LOW ".1.3.6.1.4.1.11.2.3.9.1.1.2.10"
77 #define HPJD_GD_PAGE_PUNT ".1.3.6.1.4.1.11.2.3.9.1.1.2.11"
78 #define HPJD_GD_MEMORY_OUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.12"
79 #define HPJD_GD_DOOR_OPEN ".1.3.6.1.4.1.11.2.3.9.1.1.2.17"
80 #define HPJD_GD_PAPER_OUTPUT ".1.3.6.1.4.1.11.2.3.9.1.1.2.19"
81 #define HPJD_GD_STATUS_DISPLAY ".1.3.6.1.4.1.11.2.3.9.1.1.3"
83 #define ONLINE 0
84 #define OFFLINE 1
86 int process_arguments (int, char **);
87 int call_getopt (int, char **);
88 int validate_arguments (void);
89 void print_help (void);
90 void print_usage (void);
92 char *community = NULL;
93 char *address = NULL;
95 int
96 main (int argc, char **argv)
97 {
98 char command_line[1024];
99 int result;
100 int line;
101 char input_buffer[MAX_INPUT_BUFFER];
102 char query_string[512];
103 char error_message[MAX_INPUT_BUFFER];
104 char *temp_buffer;
105 int line_status = ONLINE;
106 int paper_status = 0;
107 int intervention_required = 0;
108 int peripheral_error = 0;
109 int paper_jam = 0;
110 int paper_out = 0;
111 int toner_low = 0;
112 int page_punt = 0;
113 int memory_out = 0;
114 int door_open = 0;
115 int paper_output = 0;
116 char display_message[MAX_INPUT_BUFFER];
118 if (process_arguments (argc, argv) != OK)
119 usage ("Invalid command arguments supplied\n");
121 /* removed ' 2>1' at end of command 10/27/1999 - EG */
122 /* create the query string */
123 sprintf
124 (query_string,
125 "%s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0 %s.0",
126 HPJD_LINE_STATUS,
127 HPJD_PAPER_STATUS,
128 HPJD_INTERVENTION_REQUIRED,
129 HPJD_GD_PERIPHERAL_ERROR,
130 HPJD_GD_PAPER_JAM,
131 HPJD_GD_PAPER_OUT,
132 HPJD_GD_TONER_LOW,
133 HPJD_GD_PAGE_PUNT,
134 HPJD_GD_MEMORY_OUT,
135 HPJD_GD_DOOR_OPEN, HPJD_GD_PAPER_OUTPUT, HPJD_GD_STATUS_DISPLAY);
137 /* get the command to run */
138 sprintf (command_line, "%s -m : -v 1 %s -c %s %s", PATH_TO_SNMPGET, address,
139 community, query_string);
141 /* run the command */
142 child_process = spopen (command_line);
143 if (child_process == NULL) {
144 printf ("Could not open pipe: %s\n", command_line);
145 return STATE_UNKNOWN;
146 }
148 child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
149 if (child_stderr == NULL) {
150 printf ("Could not open stderr for %s\n", command_line);
151 }
153 result = STATE_OK;
155 line = 0;
156 while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process)) {
158 /* strip the newline character from the end of the input */
159 if (input_buffer[strlen (input_buffer) - 1] == '\n')
160 input_buffer[strlen (input_buffer) - 1] = 0;
162 line++;
164 temp_buffer = strtok (input_buffer, "=");
165 temp_buffer = strtok (NULL, "=");
167 switch (line) {
169 case 1: /* 1st line should contain the line status */
170 if (temp_buffer != NULL)
171 line_status = atoi (temp_buffer);
172 else {
173 result = STATE_UNKNOWN;
174 strcpy (error_message, input_buffer);
175 }
176 break;
178 case 2: /* 2nd line should contain the paper status */
179 if (temp_buffer != NULL)
180 paper_status = atoi (temp_buffer);
181 else {
182 result = STATE_UNKNOWN;
183 strcpy (error_message, input_buffer);
184 }
185 break;
187 case 3: /* 3rd line should be intervention required */
188 if (temp_buffer != NULL)
189 intervention_required = atoi (temp_buffer);
190 else {
191 result = STATE_UNKNOWN;
192 strcpy (error_message, input_buffer);
193 }
194 break;
196 case 4: /* 4th line should be peripheral error */
197 if (temp_buffer != NULL)
198 peripheral_error = atoi (temp_buffer);
199 else {
200 result = STATE_UNKNOWN;
201 strcpy (error_message, input_buffer);
202 }
203 break;
205 case 5: /* 5th line should contain the paper jam status */
206 if (temp_buffer != NULL)
207 paper_jam = atoi (temp_buffer);
208 else {
209 result = STATE_UNKNOWN;
210 strcpy (error_message, input_buffer);
211 }
212 break;
214 case 6: /* 6th line should contain the paper out status */
215 if (temp_buffer != NULL)
216 paper_out = atoi (temp_buffer);
217 else {
218 result = STATE_UNKNOWN;
219 strcpy (error_message, input_buffer);
220 }
221 break;
223 case 7: /* 7th line should contain the toner low status */
224 if (temp_buffer != NULL)
225 toner_low = atoi (temp_buffer);
226 else {
227 result = STATE_UNKNOWN;
228 strcpy (error_message, input_buffer);
229 }
230 break;
232 case 8: /* did data come too slow for engine */
233 if (temp_buffer != NULL)
234 page_punt = atoi (temp_buffer);
235 else {
236 result = STATE_UNKNOWN;
237 strcpy (error_message, input_buffer);
238 }
239 break;
241 case 9: /* did we run out of memory */
242 if (temp_buffer != NULL)
243 memory_out = atoi (temp_buffer);
244 else {
245 result = STATE_UNKNOWN;
246 strcpy (error_message, input_buffer);
247 }
248 break;
250 case 10: /* is there a door open */
251 if (temp_buffer != NULL)
252 door_open = atoi (temp_buffer);
253 else {
254 result = STATE_UNKNOWN;
255 strcpy (error_message, input_buffer);
256 }
257 break;
259 case 11: /* is output tray full */
260 if (temp_buffer != NULL)
261 paper_output = atoi (temp_buffer);
262 else {
263 result = STATE_UNKNOWN;
264 strcpy (error_message, input_buffer);
265 }
266 break;
268 case 12: /* display panel message */
269 if (temp_buffer != NULL)
270 strcpy (display_message, temp_buffer + 1);
271 else {
272 result = STATE_UNKNOWN;
273 strcpy (error_message, input_buffer);
274 }
275 break;
277 default:
278 break;
279 }
281 /* break out of the read loop if we encounter an error */
282 if (result != STATE_OK)
283 break;
284 }
286 /* WARNING if output found on stderr */
287 if (fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_stderr))
288 result = max_state (result, STATE_WARNING);
290 /* close stderr */
291 (void) fclose (child_stderr);
293 /* close the pipe */
294 if (spclose (child_process))
295 result = max_state (result, STATE_WARNING);
297 /* if there wasn't any output, display an error */
298 if (line == 0) {
300 /*
301 result=STATE_UNKNOWN;
302 strcpy(error_message,"Error: Could not read plugin output\n");
303 */
305 /* might not be the problem, but most likely is.. */
306 result = STATE_UNKNOWN;
307 sprintf (error_message, "Timeout: No response from %s\n", address);
308 }
310 /* if we had no read errors, check the printer status results... */
311 if (result == STATE_OK) {
313 if (paper_jam) {
314 result = STATE_WARNING;
315 strcpy (error_message, "Paper Jam");
316 }
317 else if (paper_out) {
318 result = STATE_WARNING;
319 strcpy (error_message, "Out of Paper");
320 }
321 else if (line_status == OFFLINE) {
322 if (strcmp (error_message, "POWERSAVE ON") != 0) {
323 result = STATE_WARNING;
324 strcpy (error_message, "Printer Offline");
325 }
326 }
327 else if (peripheral_error) {
328 result = STATE_WARNING;
329 strcpy (error_message, "Peripheral Error");
330 }
331 else if (intervention_required) {
332 result = STATE_WARNING;
333 strcpy (error_message, "Intervention Required");
334 }
335 else if (toner_low) {
336 result = STATE_WARNING;
337 strcpy (error_message, "Toner Low");
338 }
339 else if (memory_out) {
340 result = STATE_WARNING;
341 strcpy (error_message, "Insufficient Memory");
342 }
343 else if (door_open) {
344 result = STATE_WARNING;
345 strcpy (error_message, "A Door is Open");
346 }
347 else if (paper_output) {
348 result = STATE_WARNING;
349 strcpy (error_message, "Output Tray is Full");
350 }
351 else if (page_punt) {
352 result = STATE_WARNING;
353 strcpy (error_message, "Data too Slow for Engine");
354 }
355 else if (paper_status) {
356 result = STATE_WARNING;
357 strcpy (error_message, "Unknown Paper Error");
358 }
359 }
361 if (result == STATE_OK)
362 printf ("Printer ok - (%s)\n", display_message);
364 else if (result == STATE_UNKNOWN) {
366 printf ("%s\n", error_message);
368 /* if printer could not be reached, escalate to critical */
369 if (strstr (error_message, "Timeout"))
370 result = STATE_CRITICAL;
371 }
373 else if (result == STATE_WARNING)
374 printf ("%s (%s)\n", error_message, display_message);
376 return result;
377 }
383 /* process command-line arguments */
384 int
385 process_arguments (int argc, char **argv)
386 {
387 int c;
389 if (argc < 2)
390 return ERROR;
392 for (c = 1; c < argc; c++) {
393 if (strcmp ("-to", argv[c]) == 0)
394 strcpy (argv[c], "-t");
395 else if (strcmp ("-wt", argv[c]) == 0)
396 strcpy (argv[c], "-w");
397 else if (strcmp ("-ct", argv[c]) == 0)
398 strcpy (argv[c], "-c");
399 }
403 c = 0;
404 while ((c += (call_getopt (argc - c, &argv[c]))) < argc) {
406 if (is_option (argv[c]))
407 continue;
409 if (address == NULL) {
410 if (is_host (argv[c])) {
411 address = argv[c];
412 }
413 else {
414 usage ("Invalid host name");
415 }
416 }
417 else if (community == NULL) {
418 community = argv[c];
419 }
420 }
422 if (address == NULL)
423 address = strscpy (NULL, "127.0.0.1");
425 return validate_arguments ();
426 }
433 int
434 call_getopt (int argc, char **argv)
435 {
436 int c, i = 0;
438 #ifdef HAVE_GETOPT_H
439 int option_index = 0;
440 static struct option long_options[] = {
441 {"hostname", required_argument, 0, 'H'},
442 {"expect", required_argument, 0, 'e'},
443 /* {"critical", required_argument,0,'c'}, */
444 /* {"warning", required_argument,0,'w'}, */
445 /* {"port", required_argument,0,'P'}, */
446 {"verbose", no_argument, 0, 'v'},
447 {"version", no_argument, 0, 'V'},
448 {"help", no_argument, 0, 'h'},
449 {0, 0, 0, 0}
450 };
451 #endif
453 while (1) {
454 #ifdef HAVE_GETOPT_H
455 c = getopt_long (argc, argv, "+hVH:C:", long_options, &option_index);
456 #else
457 c = getopt (argc, argv, "+?hVH:C:");
458 #endif
460 i++;
462 if (c == -1 || c == EOF || c == 1)
463 break;
465 switch (c) {
466 case 'H':
467 case 'C':
468 i++;
469 }
471 switch (c) {
472 case 'H': /* hostname */
473 if (is_host (optarg)) {
474 address = optarg;
475 }
476 else {
477 usage ("Invalid host name\n");
478 }
479 break;
480 case 'C': /* community */
481 community = optarg;
482 break;
483 case 'V': /* version */
484 print_revision (PROGNAME, "$Revision$");
485 exit (STATE_OK);
486 case 'h': /* help */
487 print_help ();
488 exit (STATE_OK);
489 case '?': /* help */
490 usage ("Invalid argument\n");
491 }
492 }
493 return i;
494 }
500 int
501 validate_arguments (void)
502 {
503 return OK;
504 }
510 void
511 print_help (void)
512 {
513 print_revision (PROGNAME, "$Revision$");
514 printf
515 ("Copyright (c) 2000 Ethan Galstad/Karl DeBisschop\n\n"
516 "This plugin tests the STATUS of an HP printer with a JetDirect card.\n"
517 "Net-snmp must be installed on the computer running the plugin.\n\n");
518 print_usage ();
519 printf
520 ("\nOptions:\n"
521 " -H, --hostname=STRING or IPADDRESS\n"
522 " Check server on the indicated host\n"
523 " -C, --community=STRING\n"
524 " The SNMP community name\n"
525 " -h, --help\n"
526 " Print detailed help screen\n"
527 " -V, --version\n" " Print version information\n\n");
528 support ();
529 }
535 void
536 print_usage (void)
537 {
538 printf
539 ("Usage: %s -H host [-C community]\n"
540 " %s --help\n"
541 " %s --version\n", PROGNAME, PROGNAME, PROGNAME);
542 }
545 /*
546 if(argc<2||argc>3){
547 printf("Incorrect number of arguments supplied\n");
548 printf("\n");
549 print_revision(argv[0],"$Revision$");
550 printf("Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)\n");
551 printf("License: GPL\n");
552 printf("\n");
553 printf("Usage: %s <ip_address> [community]\n",argv[0]);
554 printf("\n");
555 printf("Note:\n");
556 printf(" <ip_address> = The IP address of the JetDirect card\n");
557 printf(" [community] = An optional community string used for SNMP communication\n");
558 printf(" with the JetDirect card. The default is 'public'.\n");
559 printf("\n");
560 return STATE_UNKNOWN;
561 }
563 // get the IP address of the JetDirect device
564 strcpy(address,argv[1]);
566 // get the community name to use for SNMP communication
567 if(argc>=3)
568 strcpy(community,argv[2]);
569 else
570 strcpy(community,"public");
571 */