0cd4c5a0a4c1a6212c456e5af2416ae0b0c8f342
1 /******************************************************************************
2 *
3 * Nagios check_ups plugin
4 *
5 * License: GPL
6 * Copyright (c) 2000 Tom Shields
7 * 2004 Alain Richard <alain.richard@equation.fr>
8 * 2004 Arnaud Quette <arnaud.quette@mgeups.com>
9 * Copyright (c) 2002-2006 nagios-plugins team
10 *
11 * Last Modified: $Date$
12 *
13 * Description:
14 *
15 * This file contains Network UPS Tools plugin for Nagios
16 *
17 * This plugin tests the UPS service on the specified host.Network UPS Tools
18 * from www.networkupstools.org must be running for thisplugin to work.
19 *
20 * License Information:
21 *
22 * This program is free software; you can redistribute it and/or modify
23 * it under the terms of the GNU General Public License as published by
24 * the Free Software Foundation; either version 2 of the License, or
25 * (at your option) any later version.
26 *
27 * This program is distributed in the hope that it will be useful,
28 * but WITHOUT ANY WARRANTY; without even the implied warranty of
29 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
30 * GNU General Public License for more details.
31 *
32 * You should have received a copy of the GNU General Public License
33 * along with this program; if not, write to the Free Software
34 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
35 *
36 * $Id$
37 *
38 ******************************************************************************/
40 const char *progname = "check_ups";
41 const char *revision = "$Revision$";
42 const char *copyright = "2002-2006";
43 const char *email = "nagiosplug-devel@lists.sourceforge.net";
45 #include "common.h"
46 #include "netutils.h"
47 #include "utils.h"
49 enum {
50 PORT = 3493
51 };
53 #define CHECK_NONE 0
55 #define UPS_NONE 0 /* no supported options */
56 #define UPS_UTILITY 1 /* supports utility line voltage */
57 #define UPS_BATTPCT 2 /* supports percent battery remaining */
58 #define UPS_STATUS 4 /* supports UPS status */
59 #define UPS_TEMP 8 /* supports UPS temperature */
60 #define UPS_LOADPCT 16 /* supports load percent */
62 #define UPSSTATUS_NONE 0
63 #define UPSSTATUS_OFF 1
64 #define UPSSTATUS_OL 2
65 #define UPSSTATUS_OB 4
66 #define UPSSTATUS_LB 8
67 #define UPSSTATUS_CAL 16
68 #define UPSSTATUS_RB 32 /*Replace Battery */
69 #define UPSSTATUS_BYPASS 64
70 #define UPSSTATUS_OVER 128
71 #define UPSSTATUS_TRIM 256
72 #define UPSSTATUS_BOOST 512
73 #define UPSSTATUS_CHRG 1024
74 #define UPSSTATUS_DISCHRG 2048
75 #define UPSSTATUS_UNKOWN 4096
77 enum { NOSUCHVAR = ERROR-1 };
79 int server_port = PORT;
80 char *server_address;
81 char *ups_name = NULL;
82 double warning_value = 0.0;
83 double critical_value = 0.0;
84 int check_warn = FALSE;
85 int check_crit = FALSE;
86 int check_variable = UPS_NONE;
87 int supported_options = UPS_NONE;
88 int status = UPSSTATUS_NONE;
90 double ups_utility_voltage = 0.0;
91 double ups_battery_percent = 0.0;
92 double ups_load_percent = 0.0;
93 double ups_temperature = 0.0;
94 char *ups_status;
95 int temp_output_c = 0;
97 int determine_status (void);
98 int get_ups_variable (const char *, char *, size_t);
100 int process_arguments (int, char **);
101 int validate_arguments (void);
102 void print_help (void);
103 void print_usage (void);
105 int
106 main (int argc, char **argv)
107 {
108 int result = STATE_UNKNOWN;
109 char *message;
110 char *data;
111 char *tunits;
112 char temp_buffer[MAX_INPUT_BUFFER];
113 double ups_utility_deviation = 0.0;
114 int res;
116 setlocale (LC_ALL, "");
117 bindtextdomain (PACKAGE, LOCALEDIR);
118 textdomain (PACKAGE);
120 ups_status = strdup ("N/A");
121 data = strdup ("");
122 message = strdup ("");
124 if (process_arguments (argc, argv) == ERROR)
125 usage4 (_("Could not parse arguments"));
127 /* initialize alarm signal handling */
128 signal (SIGALRM, socket_timeout_alarm_handler);
130 /* set socket timeout */
131 alarm (socket_timeout);
133 /* get the ups status if possible */
134 if (determine_status () != OK)
135 return STATE_CRITICAL;
136 if (supported_options & UPS_STATUS) {
138 ups_status = strdup ("");
139 result = STATE_OK;
141 if (status & UPSSTATUS_OFF) {
142 asprintf (&ups_status, "Off");
143 result = STATE_CRITICAL;
144 }
145 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
146 (UPSSTATUS_OB | UPSSTATUS_LB)) {
147 asprintf (&ups_status, _("On Battery, Low Battery"));
148 result = STATE_CRITICAL;
149 }
150 else {
151 if (status & UPSSTATUS_OL) {
152 asprintf (&ups_status, "%s%s", ups_status, _("Online"));
153 }
154 if (status & UPSSTATUS_OB) {
155 asprintf (&ups_status, "%s%s", ups_status, _("On Battery"));
156 result = STATE_WARNING;
157 }
158 if (status & UPSSTATUS_LB) {
159 asprintf (&ups_status, "%s%s", ups_status, _(", Low Battery"));
160 result = STATE_WARNING;
161 }
162 if (status & UPSSTATUS_CAL) {
163 asprintf (&ups_status, "%s%s", ups_status, _(", Calibrating"));
164 }
165 if (status & UPSSTATUS_RB) {
166 asprintf (&ups_status, "%s%s", ups_status, _(", Replace Battery"));
167 result = STATE_WARNING;
168 }
169 if (status & UPSSTATUS_BYPASS) {
170 asprintf (&ups_status, "%s%s", ups_status, _(", On Bypass"));
171 }
172 if (status & UPSSTATUS_OVER) {
173 asprintf (&ups_status, "%s%s", ups_status, _(", Overload"));
174 }
175 if (status & UPSSTATUS_TRIM) {
176 asprintf (&ups_status, "%s%s", ups_status, _(", Trimming"));
177 }
178 if (status & UPSSTATUS_BOOST) {
179 asprintf (&ups_status, "%s%s", ups_status, _(", Boosting"));
180 }
181 if (status & UPSSTATUS_CHRG) {
182 asprintf (&ups_status, "%s%s", ups_status, _(", Charging"));
183 }
184 if (status & UPSSTATUS_DISCHRG) {
185 asprintf (&ups_status, "%s%s", ups_status, _(", Discharging"));
186 }
187 if (status & UPSSTATUS_UNKOWN) {
188 asprintf (&ups_status, "%s%s", ups_status, _(", Unknown"));
189 }
190 }
191 asprintf (&message, "%sStatus=%s ", message, ups_status);
192 }
194 /* get the ups utility voltage if possible */
195 res=get_ups_variable ("input.voltage", temp_buffer, sizeof (temp_buffer));
196 if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY;
197 else if (res != OK)
198 return STATE_CRITICAL;
199 else {
200 supported_options |= UPS_UTILITY;
202 ups_utility_voltage = atof (temp_buffer);
203 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
205 if (ups_utility_voltage > 120.0)
206 ups_utility_deviation = 120.0 - ups_utility_voltage;
207 else
208 ups_utility_deviation = ups_utility_voltage - 120.0;
210 if (check_variable == UPS_UTILITY) {
211 if (check_crit==TRUE && ups_utility_deviation>=critical_value) {
212 result = STATE_CRITICAL;
213 }
214 else if (check_warn==TRUE && ups_utility_deviation>=warning_value) {
215 result = max_state (result, STATE_WARNING);
216 }
217 asprintf (&data, "%s",
218 perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
219 check_warn, (long)(1000*warning_value),
220 check_crit, (long)(1000*critical_value),
221 TRUE, 0, FALSE, 0));
222 } else {
223 asprintf (&data, "%s",
224 perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
225 FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
226 }
227 }
229 /* get the ups battery percent if possible */
230 res=get_ups_variable ("battery.charge", temp_buffer, sizeof (temp_buffer));
231 if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT;
232 else if ( res != OK)
233 return STATE_CRITICAL;
234 else {
235 supported_options |= UPS_BATTPCT;
236 ups_battery_percent = atof (temp_buffer);
237 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
239 if (check_variable == UPS_BATTPCT) {
240 if (check_crit==TRUE && ups_battery_percent <= critical_value) {
241 result = STATE_CRITICAL;
242 }
243 else if (check_warn==TRUE && ups_battery_percent<=warning_value) {
244 result = max_state (result, STATE_WARNING);
245 }
246 asprintf (&data, "%s %s", data,
247 perfdata ("battery", (long)ups_battery_percent, "%",
248 check_warn, (long)(1000*warning_value),
249 check_crit, (long)(1000*critical_value),
250 TRUE, 0, TRUE, 100));
251 } else {
252 asprintf (&data, "%s %s", data,
253 perfdata ("battery", (long)ups_battery_percent, "%",
254 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
255 }
256 }
258 /* get the ups load percent if possible */
259 res=get_ups_variable ("ups.load", temp_buffer, sizeof (temp_buffer));
260 if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT;
261 else if ( res != OK)
262 return STATE_CRITICAL;
263 else {
264 supported_options |= UPS_LOADPCT;
265 ups_load_percent = atof (temp_buffer);
266 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
268 if (check_variable == UPS_LOADPCT) {
269 if (check_crit==TRUE && ups_load_percent>=critical_value) {
270 result = STATE_CRITICAL;
271 }
272 else if (check_warn==TRUE && ups_load_percent>=warning_value) {
273 result = max_state (result, STATE_WARNING);
274 }
275 asprintf (&data, "%s %s", data,
276 perfdata ("load", (long)ups_load_percent, "%",
277 check_warn, (long)(1000*warning_value),
278 check_crit, (long)(1000*critical_value),
279 TRUE, 0, TRUE, 100));
280 } else {
281 asprintf (&data, "%s %s", data,
282 perfdata ("load", (long)ups_load_percent, "%",
283 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
284 }
285 }
287 /* get the ups temperature if possible */
288 res=get_ups_variable ("ups.temperature", temp_buffer, sizeof (temp_buffer));
289 if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP;
290 else if ( res != OK)
291 return STATE_CRITICAL;
292 else {
293 supported_options |= UPS_TEMP;
294 if (temp_output_c) {
295 tunits="degC";
296 ups_temperature = atof (temp_buffer);
297 asprintf (&message, "%sTemp=%3.1fC", message, ups_temperature);
298 }
299 else {
300 tunits="degF";
301 ups_temperature = (atof (temp_buffer) * 1.8) + 32;
302 asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
303 }
305 if (check_variable == UPS_TEMP) {
306 if (check_crit==TRUE && ups_temperature>=critical_value) {
307 result = STATE_CRITICAL;
308 }
309 else if (check_warn == TRUE && ups_temperature>=warning_value) {
310 result = max_state (result, STATE_WARNING);
311 }
312 asprintf (&data, "%s %s", data,
313 perfdata ("temp", (long)ups_temperature, tunits,
314 check_warn, (long)(1000*warning_value),
315 check_crit, (long)(1000*critical_value),
316 TRUE, 0, FALSE, 0));
317 } else {
318 asprintf (&data, "%s %s", data,
319 perfdata ("temp", (long)ups_temperature, tunits,
320 FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
321 }
322 }
324 /* if the UPS does not support any options we are looking for, report an error */
325 if (supported_options == UPS_NONE) {
326 result = STATE_CRITICAL;
327 asprintf (&message, _("UPS does not support any available options\n"));
328 }
330 /* reset timeout */
331 alarm (0);
333 printf ("UPS %s - %s|%s\n", state_text(result), message, data);
334 return result;
335 }
339 /* determines what options are supported by the UPS */
340 int
341 determine_status (void)
342 {
343 char recv_buffer[MAX_INPUT_BUFFER];
344 char temp_buffer[MAX_INPUT_BUFFER];
345 char *ptr;
346 int res;
348 res=get_ups_variable ("ups.status", recv_buffer, sizeof (recv_buffer));
349 if (res == NOSUCHVAR) return OK;
350 if (res != STATE_OK) {
351 printf ("%s\n", _("Invalid response received from host"));
352 return ERROR;
353 }
355 supported_options |= UPS_STATUS;
357 strcpy (temp_buffer, recv_buffer);
358 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
359 ptr = (char *) strtok (NULL, " ")) {
360 if (!strcmp (ptr, "OFF"))
361 status |= UPSSTATUS_OFF;
362 else if (!strcmp (ptr, "OL"))
363 status |= UPSSTATUS_OL;
364 else if (!strcmp (ptr, "OB"))
365 status |= UPSSTATUS_OB;
366 else if (!strcmp (ptr, "LB"))
367 status |= UPSSTATUS_LB;
368 else if (!strcmp (ptr, "CAL"))
369 status |= UPSSTATUS_CAL;
370 else if (!strcmp (ptr, "RB"))
371 status |= UPSSTATUS_RB;
372 else if (!strcmp (ptr, "BYPASS"))
373 status |= UPSSTATUS_BYPASS;
374 else if (!strcmp (ptr, "OVER"))
375 status |= UPSSTATUS_OVER;
376 else if (!strcmp (ptr, "TRIM"))
377 status |= UPSSTATUS_TRIM;
378 else if (!strcmp (ptr, "BOOST"))
379 status |= UPSSTATUS_BOOST;
380 else if (!strcmp (ptr, "CHRG"))
381 status |= UPSSTATUS_CHRG;
382 else if (!strcmp (ptr, "DISCHRG"))
383 status |= UPSSTATUS_DISCHRG;
384 else
385 status |= UPSSTATUS_UNKOWN;
386 }
388 return OK;
389 }
392 /* gets a variable value for a specific UPS */
393 int
394 get_ups_variable (const char *varname, char *buf, size_t buflen)
395 {
396 /* char command[MAX_INPUT_BUFFER]; */
397 char temp_buffer[MAX_INPUT_BUFFER];
398 char send_buffer[MAX_INPUT_BUFFER];
399 char *ptr;
400 int len;
402 *buf=0;
404 /* create the command string to send to the UPS daemon */
405 sprintf (send_buffer, "GET VAR %s %s\n", ups_name, varname);
407 /* send the command to the daemon and get a response back */
408 if (process_tcp_request
409 (server_address, server_port, send_buffer, temp_buffer,
410 sizeof (temp_buffer)) != STATE_OK) {
411 printf ("%s\n", _("Invalid response received from host"));
412 return ERROR;
413 }
415 ptr = temp_buffer;
416 len = strlen(ptr);
417 if (len > 0 && ptr[len-1] == '\n') ptr[len-1]=0;
418 if (strcmp (ptr, "ERR UNKNOWN-UPS") == 0) {
419 printf (_("CRITICAL - no such ups '%s' on that host\n"), ups_name);
420 return ERROR;
421 }
423 if (strcmp (ptr, "ERR VAR-NOT-SUPPORTED") == 0) {
424 /*printf ("Error: Variable '%s' is not supported\n", varname);*/
425 return NOSUCHVAR;
426 }
428 if (strcmp (ptr, "ERR DATA-STALE") == 0) {
429 printf ("%s\n", _("CRITICAL - UPS data is stale"));
430 return ERROR;
431 }
433 if (strncmp (ptr, "ERR", 3) == 0) {
434 printf (_("Unknown error: %s\n"), ptr);
435 return ERROR;
436 }
438 ptr = temp_buffer + strlen (varname) + strlen (ups_name) + 6;
439 len = strlen(ptr);
440 if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
441 printf ("%s\n", _("Error: unable to parse variable"));
442 return ERROR;
443 }
444 strncpy (buf, ptr+1, len - 2);
445 buf[len - 2] = 0;
447 return OK;
448 }
451 /* Command line: CHECK_UPS -H <host_address> -u ups [-p port] [-v variable]
452 [-wv warn_value] [-cv crit_value] [-to to_sec] */
455 /* process command-line arguments */
456 int
457 process_arguments (int argc, char **argv)
458 {
459 int c;
461 int option = 0;
462 static struct option longopts[] = {
463 {"hostname", required_argument, 0, 'H'},
464 {"ups", required_argument, 0, 'u'},
465 {"port", required_argument, 0, 'p'},
466 {"critical", required_argument, 0, 'c'},
467 {"warning", required_argument, 0, 'w'},
468 {"timeout", required_argument, 0, 't'},
469 {"temperature", no_argument, 0, 'T'},
470 {"variable", required_argument, 0, 'v'},
471 {"version", no_argument, 0, 'V'},
472 {"help", no_argument, 0, 'h'},
473 {0, 0, 0, 0}
474 };
476 if (argc < 2)
477 return ERROR;
479 for (c = 1; c < argc; c++) {
480 if (strcmp ("-to", argv[c]) == 0)
481 strcpy (argv[c], "-t");
482 else if (strcmp ("-wt", argv[c]) == 0)
483 strcpy (argv[c], "-w");
484 else if (strcmp ("-ct", argv[c]) == 0)
485 strcpy (argv[c], "-c");
486 }
488 while (1) {
489 c = getopt_long (argc, argv, "hVTH:u:p:v:c:w:t:", longopts,
490 &option);
492 if (c == -1 || c == EOF)
493 break;
495 switch (c) {
496 case '?': /* help */
497 usage5 ();
498 case 'H': /* hostname */
499 if (is_host (optarg)) {
500 server_address = optarg;
501 }
502 else {
503 usage2 (_("Invalid hostname/address"), optarg);
504 }
505 break;
506 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */
507 temp_output_c = 1;
508 break;
509 case 'u': /* ups name */
510 ups_name = optarg;
511 break;
512 case 'p': /* port */
513 if (is_intpos (optarg)) {
514 server_port = atoi (optarg);
515 }
516 else {
517 usage2 (_("Port must be a positive integer"), optarg);
518 }
519 break;
520 case 'c': /* critical time threshold */
521 if (is_intnonneg (optarg)) {
522 critical_value = atoi (optarg);
523 check_crit = TRUE;
524 }
525 else {
526 usage2 (_("Critical time must be a positive integer"), optarg);
527 }
528 break;
529 case 'w': /* warning time threshold */
530 if (is_intnonneg (optarg)) {
531 warning_value = atoi (optarg);
532 check_warn = TRUE;
533 }
534 else {
535 usage2 (_("Warning time must be a positive integer"), optarg);
536 }
537 break;
538 case 'v': /* variable */
539 if (!strcmp (optarg, "LINE"))
540 check_variable = UPS_UTILITY;
541 else if (!strcmp (optarg, "TEMP"))
542 check_variable = UPS_TEMP;
543 else if (!strcmp (optarg, "BATTPCT"))
544 check_variable = UPS_BATTPCT;
545 else if (!strcmp (optarg, "LOADPCT"))
546 check_variable = UPS_LOADPCT;
547 else
548 usage2 (_("Unrecognized UPS variable"), optarg);
549 break;
550 case 't': /* timeout */
551 if (is_intnonneg (optarg)) {
552 socket_timeout = atoi (optarg);
553 }
554 else {
555 usage4 (_("Timeout interval must be a positive integer"));
556 }
557 break;
558 case 'V': /* version */
559 print_revision (progname, revision);
560 exit (STATE_OK);
561 case 'h': /* help */
562 print_help ();
563 exit (STATE_OK);
564 }
565 }
568 if (server_address == NULL && argc > optind) {
569 if (is_host (argv[optind]))
570 server_address = argv[optind++];
571 else
572 usage2 (_("Invalid hostname/address"), optarg);
573 }
575 if (server_address == NULL)
576 server_address = strdup("127.0.0.1");
578 return validate_arguments();
579 }
582 int
583 validate_arguments (void)
584 {
585 if (! ups_name) {
586 printf ("%s\n", _("Error : no ups indicated"));
587 return ERROR;
588 }
589 return OK;
590 }
593 void
594 print_help (void)
595 {
596 char *myport;
597 asprintf (&myport, "%d", PORT);
599 print_revision (progname, revision);
601 printf ("Copyright (c) 2000 Tom Shields");
602 printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
603 printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
604 printf (COPYRIGHT, copyright, email);
606 printf ("%s\n", _("This plugin tests the UPS service on the specified host.Network UPS Tools "));
607 printf ("%s\n", _("from www.networkupstools.org must be running for thisplugin to work."));
609 printf ("\n\n");
611 print_usage ();
613 printf (_(UT_HELP_VRSN));
615 printf (_(UT_HOST_PORT), 'p', myport);
617 printf (" %s\n", "-u, --ups=STRING");
618 printf (" %s\n", _("Name of UPS"));
619 printf (" %s\n", "-T, --temperature");
620 printf (" %s\n", _("Output of temperatures in Celsius"));
621 printf (" %s\n", "-v, --variable=STRING");
622 printf (" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT or LOADPCT");
624 printf (_(UT_WARN_CRIT));
626 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
628 /* TODO: -v clashing with -v/-variable. Commenting out help text since verbose
629 is unused up to now */
630 /* printf (_(UT_VERBOSE)); */
632 printf ("\n");
633 printf ("%s\n", _("Notes:"));
635 printf ("%s\n", _("This plugin attempts to determine the status of a UPS (Uninterruptible Power"));
636 printf ("%s\n", _("Supply) on a local or remote host. If the UPS is online or calibrating, the"));
637 printf ("%s\n", _("plugin will return an OK state. If the battery is on it will return a WARNING"));
638 printf ("%s\n", _("state.If the UPS is off or has a low battery the plugin will return a CRITICAL"));
639 printf ("%s\n\n", _("state."));
641 printf ("%s\n", _("You may also specify a variable to check [such as temperature, utility voltage,"));
642 printf ("%s\n", _("battery load, etc.] as well as warning and critical thresholds for the value of"));
643 printf ("%s\n", _("that variable. If the remote host has multiple UPS that are being monitored you"));
644 printf ("%s\n", _("will have to use the [ups] option to specify which UPS to check."));
646 printf ("%s\n", _("This plugin requires that the UPSD daemon distributed with Russel Kroll's"));
647 printf ("%s\n", _("Smart UPS Tools be installed on the remote host. If you do not have the"));
648 printf ("%s\n", _("package installed on your system, you can download it from http://www.networkupstools.org"));
650 printf (_(UT_SUPPORT));
651 }
654 void
655 print_usage (void)
656 {
657 printf (_("Usage:"));
658 printf ("%s -H host -u ups [-p port] [-v variable] [-w warn_value] [-c crit_value] [-to to_sec] [-T]\n", progname);
659 }