1 /*****************************************************************************
3 * Nagios check_ups plugin
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-2007 Nagios Plugins Development Team
11 * Last Modified: $Date$
15 * This file contains Network UPS Tools plugin for Nagios
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.
21 * This program is free software: you can redistribute it and/or modify
22 * it under the terms of the GNU General Public License as published by
23 * the Free Software Foundation, either version 3 of the License, or
24 * (at your option) any later version.
26 * This program is distributed in the hope that it will be useful,
27 * but WITHOUT ANY WARRANTY; without even the implied warranty of
28 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
29 * GNU General Public License for more details.
31 * You should have received a copy of the GNU General Public License
32 * along with this program. If not, see <http://www.gnu.org/licenses/>.
36 *****************************************************************************/
38 const char *progname
= "check_ups";
39 const char *revision
= "$Revision$";
40 const char *copyright
= "2000-2007";
41 const char *email
= "nagiosplug-devel@lists.sourceforge.net";
53 #define UPS_NONE 0 /* no supported options */
54 #define UPS_UTILITY 1 /* supports utility line voltage */
55 #define UPS_BATTPCT 2 /* supports percent battery remaining */
56 #define UPS_STATUS 4 /* supports UPS status */
57 #define UPS_TEMP 8 /* supports UPS temperature */
58 #define UPS_LOADPCT 16 /* supports load percent */
60 #define UPSSTATUS_NONE 0
61 #define UPSSTATUS_OFF 1
62 #define UPSSTATUS_OL 2
63 #define UPSSTATUS_OB 4
64 #define UPSSTATUS_LB 8
65 #define UPSSTATUS_CAL 16
66 #define UPSSTATUS_RB 32 /*Replace Battery */
67 #define UPSSTATUS_BYPASS 64
68 #define UPSSTATUS_OVER 128
69 #define UPSSTATUS_TRIM 256
70 #define UPSSTATUS_BOOST 512
71 #define UPSSTATUS_CHRG 1024
72 #define UPSSTATUS_DISCHRG 2048
73 #define UPSSTATUS_UNKOWN 4096
75 enum { NOSUCHVAR
= ERROR
-1 };
77 int server_port
= PORT
;
79 char *ups_name
= NULL
;
80 double warning_value
= 0.0;
81 double critical_value
= 0.0;
82 int check_warn
= FALSE
;
83 int check_crit
= FALSE
;
84 int check_variable
= UPS_NONE
;
85 int supported_options
= UPS_NONE
;
86 int status
= UPSSTATUS_NONE
;
88 double ups_utility_voltage
= 0.0;
89 double ups_battery_percent
= 0.0;
90 double ups_load_percent
= 0.0;
91 double ups_temperature
= 0.0;
93 int temp_output_c
= 0;
95 int determine_status (void);
96 int get_ups_variable (const char *, char *, size_t);
98 int process_arguments (int, char **);
99 int validate_arguments (void);
100 void print_help (void);
101 void print_usage (void);
104 main (int argc
, char **argv
)
106 int result
= STATE_UNKNOWN
;
110 char temp_buffer
[MAX_INPUT_BUFFER
];
111 double ups_utility_deviation
= 0.0;
114 setlocale (LC_ALL
, "");
115 bindtextdomain (PACKAGE
, LOCALEDIR
);
116 textdomain (PACKAGE
);
118 ups_status
= strdup ("N/A");
120 message
= strdup ("");
122 /* Parse extra opts if any */
123 argv
=np_extra_opts (&argc
, argv
, progname
);
125 if (process_arguments (argc
, argv
) == ERROR
)
126 usage4 (_("Could not parse arguments"));
128 /* initialize alarm signal handling */
129 signal (SIGALRM
, socket_timeout_alarm_handler
);
131 /* set socket timeout */
132 alarm (socket_timeout
);
134 /* get the ups status if possible */
135 if (determine_status () != OK
)
136 return STATE_CRITICAL
;
137 if (supported_options
& UPS_STATUS
) {
139 ups_status
= strdup ("");
142 if (status
& UPSSTATUS_OFF
) {
143 asprintf (&ups_status
, "Off");
144 result
= STATE_CRITICAL
;
146 else if ((status
& (UPSSTATUS_OB
| UPSSTATUS_LB
)) ==
147 (UPSSTATUS_OB
| UPSSTATUS_LB
)) {
148 asprintf (&ups_status
, _("On Battery, Low Battery"));
149 result
= STATE_CRITICAL
;
152 if (status
& UPSSTATUS_OL
) {
153 asprintf (&ups_status
, "%s%s", ups_status
, _("Online"));
155 if (status
& UPSSTATUS_OB
) {
156 asprintf (&ups_status
, "%s%s", ups_status
, _("On Battery"));
157 result
= STATE_WARNING
;
159 if (status
& UPSSTATUS_LB
) {
160 asprintf (&ups_status
, "%s%s", ups_status
, _(", Low Battery"));
161 result
= STATE_WARNING
;
163 if (status
& UPSSTATUS_CAL
) {
164 asprintf (&ups_status
, "%s%s", ups_status
, _(", Calibrating"));
166 if (status
& UPSSTATUS_RB
) {
167 asprintf (&ups_status
, "%s%s", ups_status
, _(", Replace Battery"));
168 result
= STATE_WARNING
;
170 if (status
& UPSSTATUS_BYPASS
) {
171 asprintf (&ups_status
, "%s%s", ups_status
, _(", On Bypass"));
173 if (status
& UPSSTATUS_OVER
) {
174 asprintf (&ups_status
, "%s%s", ups_status
, _(", Overload"));
176 if (status
& UPSSTATUS_TRIM
) {
177 asprintf (&ups_status
, "%s%s", ups_status
, _(", Trimming"));
179 if (status
& UPSSTATUS_BOOST
) {
180 asprintf (&ups_status
, "%s%s", ups_status
, _(", Boosting"));
182 if (status
& UPSSTATUS_CHRG
) {
183 asprintf (&ups_status
, "%s%s", ups_status
, _(", Charging"));
185 if (status
& UPSSTATUS_DISCHRG
) {
186 asprintf (&ups_status
, "%s%s", ups_status
, _(", Discharging"));
188 if (status
& UPSSTATUS_UNKOWN
) {
189 asprintf (&ups_status
, "%s%s", ups_status
, _(", Unknown"));
192 asprintf (&message
, "%sStatus=%s ", message
, ups_status
);
195 /* get the ups utility voltage if possible */
196 res
=get_ups_variable ("input.voltage", temp_buffer
, sizeof (temp_buffer
));
197 if (res
== NOSUCHVAR
) supported_options
&= ~UPS_UTILITY
;
199 return STATE_CRITICAL
;
201 supported_options
|= UPS_UTILITY
;
203 ups_utility_voltage
= atof (temp_buffer
);
204 asprintf (&message
, "%sUtility=%3.1fV ", message
, ups_utility_voltage
);
206 if (ups_utility_voltage
> 120.0)
207 ups_utility_deviation
= 120.0 - ups_utility_voltage
;
209 ups_utility_deviation
= ups_utility_voltage
- 120.0;
211 if (check_variable
== UPS_UTILITY
) {
212 if (check_crit
==TRUE
&& ups_utility_deviation
>=critical_value
) {
213 result
= STATE_CRITICAL
;
215 else if (check_warn
==TRUE
&& ups_utility_deviation
>=warning_value
) {
216 result
= max_state (result
, STATE_WARNING
);
218 asprintf (&data
, "%s",
219 perfdata ("voltage", (long)(1000*ups_utility_voltage
), "mV",
220 check_warn
, (long)(1000*warning_value
),
221 check_crit
, (long)(1000*critical_value
),
224 asprintf (&data
, "%s",
225 perfdata ("voltage", (long)(1000*ups_utility_voltage
), "mV",
226 FALSE
, 0, FALSE
, 0, TRUE
, 0, FALSE
, 0));
230 /* get the ups battery percent if possible */
231 res
=get_ups_variable ("battery.charge", temp_buffer
, sizeof (temp_buffer
));
232 if (res
== NOSUCHVAR
) supported_options
&= ~UPS_BATTPCT
;
234 return STATE_CRITICAL
;
236 supported_options
|= UPS_BATTPCT
;
237 ups_battery_percent
= atof (temp_buffer
);
238 asprintf (&message
, "%sBatt=%3.1f%% ", message
, ups_battery_percent
);
240 if (check_variable
== UPS_BATTPCT
) {
241 if (check_crit
==TRUE
&& ups_battery_percent
<= critical_value
) {
242 result
= STATE_CRITICAL
;
244 else if (check_warn
==TRUE
&& ups_battery_percent
<=warning_value
) {
245 result
= max_state (result
, STATE_WARNING
);
247 asprintf (&data
, "%s %s", data
,
248 perfdata ("battery", (long)ups_battery_percent
, "%",
249 check_warn
, (long)(1000*warning_value
),
250 check_crit
, (long)(1000*critical_value
),
251 TRUE
, 0, TRUE
, 100));
253 asprintf (&data
, "%s %s", data
,
254 perfdata ("battery", (long)ups_battery_percent
, "%",
255 FALSE
, 0, FALSE
, 0, TRUE
, 0, TRUE
, 100));
259 /* get the ups load percent if possible */
260 res
=get_ups_variable ("ups.load", temp_buffer
, sizeof (temp_buffer
));
261 if ( res
== NOSUCHVAR
) supported_options
&= ~UPS_LOADPCT
;
263 return STATE_CRITICAL
;
265 supported_options
|= UPS_LOADPCT
;
266 ups_load_percent
= atof (temp_buffer
);
267 asprintf (&message
, "%sLoad=%3.1f%% ", message
, ups_load_percent
);
269 if (check_variable
== UPS_LOADPCT
) {
270 if (check_crit
==TRUE
&& ups_load_percent
>=critical_value
) {
271 result
= STATE_CRITICAL
;
273 else if (check_warn
==TRUE
&& ups_load_percent
>=warning_value
) {
274 result
= max_state (result
, STATE_WARNING
);
276 asprintf (&data
, "%s %s", data
,
277 perfdata ("load", (long)ups_load_percent
, "%",
278 check_warn
, (long)(1000*warning_value
),
279 check_crit
, (long)(1000*critical_value
),
280 TRUE
, 0, TRUE
, 100));
282 asprintf (&data
, "%s %s", data
,
283 perfdata ("load", (long)ups_load_percent
, "%",
284 FALSE
, 0, FALSE
, 0, TRUE
, 0, TRUE
, 100));
288 /* get the ups temperature if possible */
289 res
=get_ups_variable ("ups.temperature", temp_buffer
, sizeof (temp_buffer
));
290 if ( res
== NOSUCHVAR
) supported_options
&= ~UPS_TEMP
;
292 return STATE_CRITICAL
;
294 supported_options
|= UPS_TEMP
;
297 ups_temperature
= atof (temp_buffer
);
298 asprintf (&message
, "%sTemp=%3.1fC", message
, ups_temperature
);
302 ups_temperature
= (atof (temp_buffer
) * 1.8) + 32;
303 asprintf (&message
, "%sTemp=%3.1fF", message
, ups_temperature
);
306 if (check_variable
== UPS_TEMP
) {
307 if (check_crit
==TRUE
&& ups_temperature
>=critical_value
) {
308 result
= STATE_CRITICAL
;
310 else if (check_warn
== TRUE
&& ups_temperature
>=warning_value
) {
311 result
= max_state (result
, STATE_WARNING
);
313 asprintf (&data
, "%s %s", data
,
314 perfdata ("temp", (long)ups_temperature
, tunits
,
315 check_warn
, (long)(1000*warning_value
),
316 check_crit
, (long)(1000*critical_value
),
319 asprintf (&data
, "%s %s", data
,
320 perfdata ("temp", (long)ups_temperature
, tunits
,
321 FALSE
, 0, FALSE
, 0, TRUE
, 0, FALSE
, 0));
325 /* if the UPS does not support any options we are looking for, report an error */
326 if (supported_options
== UPS_NONE
) {
327 result
= STATE_CRITICAL
;
328 asprintf (&message
, _("UPS does not support any available options\n"));
334 printf ("UPS %s - %s|%s\n", state_text(result
), message
, data
);
340 /* determines what options are supported by the UPS */
342 determine_status (void)
344 char recv_buffer
[MAX_INPUT_BUFFER
];
345 char temp_buffer
[MAX_INPUT_BUFFER
];
349 res
=get_ups_variable ("ups.status", recv_buffer
, sizeof (recv_buffer
));
350 if (res
== NOSUCHVAR
) return OK
;
351 if (res
!= STATE_OK
) {
352 printf ("%s\n", _("Invalid response received from host"));
356 supported_options
|= UPS_STATUS
;
358 strcpy (temp_buffer
, recv_buffer
);
359 for (ptr
= (char *) strtok (temp_buffer
, " "); ptr
!= NULL
;
360 ptr
= (char *) strtok (NULL
, " ")) {
361 if (!strcmp (ptr
, "OFF"))
362 status
|= UPSSTATUS_OFF
;
363 else if (!strcmp (ptr
, "OL"))
364 status
|= UPSSTATUS_OL
;
365 else if (!strcmp (ptr
, "OB"))
366 status
|= UPSSTATUS_OB
;
367 else if (!strcmp (ptr
, "LB"))
368 status
|= UPSSTATUS_LB
;
369 else if (!strcmp (ptr
, "CAL"))
370 status
|= UPSSTATUS_CAL
;
371 else if (!strcmp (ptr
, "RB"))
372 status
|= UPSSTATUS_RB
;
373 else if (!strcmp (ptr
, "BYPASS"))
374 status
|= UPSSTATUS_BYPASS
;
375 else if (!strcmp (ptr
, "OVER"))
376 status
|= UPSSTATUS_OVER
;
377 else if (!strcmp (ptr
, "TRIM"))
378 status
|= UPSSTATUS_TRIM
;
379 else if (!strcmp (ptr
, "BOOST"))
380 status
|= UPSSTATUS_BOOST
;
381 else if (!strcmp (ptr
, "CHRG"))
382 status
|= UPSSTATUS_CHRG
;
383 else if (!strcmp (ptr
, "DISCHRG"))
384 status
|= UPSSTATUS_DISCHRG
;
386 status
|= UPSSTATUS_UNKOWN
;
393 /* gets a variable value for a specific UPS */
395 get_ups_variable (const char *varname
, char *buf
, size_t buflen
)
397 /* char command[MAX_INPUT_BUFFER]; */
398 char temp_buffer
[MAX_INPUT_BUFFER
];
399 char send_buffer
[MAX_INPUT_BUFFER
];
405 /* create the command string to send to the UPS daemon */
406 sprintf (send_buffer
, "GET VAR %s %s\n", ups_name
, varname
);
408 /* send the command to the daemon and get a response back */
409 if (process_tcp_request
410 (server_address
, server_port
, send_buffer
, temp_buffer
,
411 sizeof (temp_buffer
)) != STATE_OK
) {
412 printf ("%s\n", _("Invalid response received from host"));
418 if (len
> 0 && ptr
[len
-1] == '\n') ptr
[len
-1]=0;
419 if (strcmp (ptr
, "ERR UNKNOWN-UPS") == 0) {
420 printf (_("CRITICAL - no such ups '%s' on that host\n"), ups_name
);
424 if (strcmp (ptr
, "ERR VAR-NOT-SUPPORTED") == 0) {
425 /*printf ("Error: Variable '%s' is not supported\n", varname);*/
429 if (strcmp (ptr
, "ERR DATA-STALE") == 0) {
430 printf ("%s\n", _("CRITICAL - UPS data is stale"));
434 if (strncmp (ptr
, "ERR", 3) == 0) {
435 printf (_("Unknown error: %s\n"), ptr
);
439 ptr
= temp_buffer
+ strlen (varname
) + strlen (ups_name
) + 6;
441 if (len
< 2 || ptr
[0] != '"' || ptr
[len
-1] != '"') {
442 printf ("%s\n", _("Error: unable to parse variable"));
445 strncpy (buf
, ptr
+1, len
- 2);
452 /* Command line: CHECK_UPS -H <host_address> -u ups [-p port] [-v variable]
453 [-wv warn_value] [-cv crit_value] [-to to_sec] */
456 /* process command-line arguments */
458 process_arguments (int argc
, char **argv
)
463 static struct option longopts
[] = {
464 {"hostname", required_argument
, 0, 'H'},
465 {"ups", required_argument
, 0, 'u'},
466 {"port", required_argument
, 0, 'p'},
467 {"critical", required_argument
, 0, 'c'},
468 {"warning", required_argument
, 0, 'w'},
469 {"timeout", required_argument
, 0, 't'},
470 {"temperature", no_argument
, 0, 'T'},
471 {"variable", required_argument
, 0, 'v'},
472 {"version", no_argument
, 0, 'V'},
473 {"help", no_argument
, 0, 'h'},
480 for (c
= 1; c
< argc
; c
++) {
481 if (strcmp ("-to", argv
[c
]) == 0)
482 strcpy (argv
[c
], "-t");
483 else if (strcmp ("-wt", argv
[c
]) == 0)
484 strcpy (argv
[c
], "-w");
485 else if (strcmp ("-ct", argv
[c
]) == 0)
486 strcpy (argv
[c
], "-c");
490 c
= getopt_long (argc
, argv
, "hVTH:u:p:v:c:w:t:", longopts
,
493 if (c
== -1 || c
== EOF
)
499 case 'H': /* hostname */
500 if (is_host (optarg
)) {
501 server_address
= optarg
;
504 usage2 (_("Invalid hostname/address"), optarg
);
507 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */
510 case 'u': /* ups name */
514 if (is_intpos (optarg
)) {
515 server_port
= atoi (optarg
);
518 usage2 (_("Port must be a positive integer"), optarg
);
521 case 'c': /* critical time threshold */
522 if (is_intnonneg (optarg
)) {
523 critical_value
= atoi (optarg
);
527 usage2 (_("Critical time must be a positive integer"), optarg
);
530 case 'w': /* warning time threshold */
531 if (is_intnonneg (optarg
)) {
532 warning_value
= atoi (optarg
);
536 usage2 (_("Warning time must be a positive integer"), optarg
);
539 case 'v': /* variable */
540 if (!strcmp (optarg
, "LINE"))
541 check_variable
= UPS_UTILITY
;
542 else if (!strcmp (optarg
, "TEMP"))
543 check_variable
= UPS_TEMP
;
544 else if (!strcmp (optarg
, "BATTPCT"))
545 check_variable
= UPS_BATTPCT
;
546 else if (!strcmp (optarg
, "LOADPCT"))
547 check_variable
= UPS_LOADPCT
;
549 usage2 (_("Unrecognized UPS variable"), optarg
);
551 case 't': /* timeout */
552 if (is_intnonneg (optarg
)) {
553 socket_timeout
= atoi (optarg
);
556 usage4 (_("Timeout interval must be a positive integer"));
559 case 'V': /* version */
560 print_revision (progname
, revision
);
569 if (server_address
== NULL
&& argc
> optind
) {
570 if (is_host (argv
[optind
]))
571 server_address
= argv
[optind
++];
573 usage2 (_("Invalid hostname/address"), optarg
);
576 if (server_address
== NULL
)
577 server_address
= strdup("127.0.0.1");
579 return validate_arguments();
584 validate_arguments (void)
587 printf ("%s\n", _("Error : no ups indicated"));
598 asprintf (&myport
, "%d", PORT
);
600 print_revision (progname
, revision
);
602 printf ("Copyright (c) 2000 Tom Shields\n");
603 printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
604 printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
605 printf (COPYRIGHT
, copyright
, email
);
607 printf ("%s\n", _("This plugin tests the UPS service on the specified host. Network UPS Tools"));
608 printf ("%s\n", _("from www.networkupstools.org must be running for thisplugin to work."));
614 printf (_(UT_HELP_VRSN
));
615 printf (_(UT_EXTRA_OPTS
));
617 printf (_(UT_HOST_PORT
), 'p', myport
);
619 printf (" %s\n", "-u, --ups=STRING");
620 printf (" %s\n", _("Name of UPS"));
621 printf (" %s\n", "-T, --temperature");
622 printf (" %s\n", _("Output of temperatures in Celsius"));
623 printf (" %s\n", "-v, --variable=STRING");
624 printf (" %s %s\n", _("Valid values for STRING are"), "LINE, TEMP, BATTPCT or LOADPCT");
626 printf (_(UT_WARN_CRIT
));
628 printf (_(UT_TIMEOUT
), DEFAULT_SOCKET_TIMEOUT
);
630 /* TODO: -v clashing with -v/-variable. Commenting out help text since verbose
631 is unused up to now */
632 /* printf (_(UT_VERBOSE)); */
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", _("state."));
642 printf ("%s\n", _("Notes:"));
643 printf (" %s\n", _("You may also specify a variable to check (such as temperature, utility voltage,"));
644 printf (" %s\n", _("battery load, etc.) as well as warning and critical thresholds for the value"));
645 printf (" %s\n", _("of that variable. If the remote host has multiple UPS that are being monitored"));
646 printf (" %s\n", _("you will have to use the --ups option to specify which UPS to check."));
648 printf (" %s\n", _("This plugin requires that the UPSD daemon distributed with Russel Kroll's"));
649 printf (" %s\n", _("Smart UPS Tools be installed on the remote host. If you do not have the"));
650 printf (" %s\n", _("package installed on your system, you can download it from"));
651 printf (" %s\n", _("http://www.networkupstools.org"));
654 printf (_(UT_EXTRA_OPTS_NOTES
));
657 printf (_(UT_SUPPORT
));
664 printf (_("Usage:"));
665 printf ("%s -H host -u ups [-p port] [-v variable] [-w warn_value] [-c crit_value] [-to to_sec] [-T]\n", progname
);