1 /******************************************************************************
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2 of the License, or (at
6 your option) any later version.
8 This program is distributed in the hope that it will be useful, but
9 WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 General Public License for more details.
13 You should have received a copy of the GNU General Public License
14 along with this program; if not, write to the Free Software
15 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 ******************************************************************************/
19 const char *progname = "check_ups";
20 const char *revision = "$Revision$";
21 const char *copyright = "2000-2002";
22 const char *email = "nagiosplug-devel@lists.sourceforge.net";
24 #include "common.h"
25 #include "netutils.h"
26 #include "utils.h"
28 enum {
29 PORT = 3493
30 };
32 #define CHECK_NONE 0
34 #define UPS_NONE 0 /* no supported options */
35 #define UPS_UTILITY 1 /* supports utility line voltage */
36 #define UPS_BATTPCT 2 /* supports percent battery remaining */
37 #define UPS_STATUS 4 /* supports UPS status */
38 #define UPS_TEMP 8 /* supports UPS temperature */
39 #define UPS_LOADPCT 16 /* supports load percent */
41 #define UPSSTATUS_NONE 0
42 #define UPSSTATUS_OFF 1
43 #define UPSSTATUS_OL 2
44 #define UPSSTATUS_OB 4
45 #define UPSSTATUS_LB 8
46 #define UPSSTATUS_CAL 16
47 #define UPSSTATUS_RB 32 /*Replace Battery */
48 #define UPSSTATUS_UNKOWN 64
50 int server_port = PORT;
51 char *server_address;
52 char *ups_name = NULL;
53 double warning_value = 0.0;
54 double critical_value = 0.0;
55 int check_warning_value = FALSE;
56 int check_critical_value = FALSE;
57 int check_variable = UPS_NONE;
58 int supported_options = UPS_NONE;
59 int status = UPSSTATUS_NONE;
61 double ups_utility_voltage = 0.0;
62 double ups_battery_percent = 0.0;
63 double ups_load_percent = 0.0;
64 double ups_temperature = 0.0;
65 char *ups_status;
67 int determine_status (void);
68 int determine_supported_vars (void);
69 int get_ups_variable (const char *, char *, size_t);
71 int process_arguments (int, char **);
72 int validate_arguments (void);
73 void print_help (void);
74 void print_usage (void);
76 int
77 main (int argc, char **argv)
78 {
79 int result = STATE_OK;
80 char *message;
81 char temp_buffer[MAX_INPUT_BUFFER];
82 double ups_utility_deviation = 0.0;
84 setlocale (LC_ALL, "");
85 bindtextdomain (PACKAGE, LOCALEDIR);
86 textdomain (PACKAGE);
88 ups_status = strdup ("N/A");
90 if (process_arguments (argc, argv) != OK)
91 usage ("Invalid command arguments supplied\n");
93 /* initialize alarm signal handling */
94 signal (SIGALRM, socket_timeout_alarm_handler);
96 /* set socket timeout */
97 alarm (socket_timeout);
99 /* determine what variables the UPS supports */
100 if (determine_supported_vars () != OK)
101 return STATE_CRITICAL;
103 /* get the ups status if possible */
104 if (supported_options & UPS_STATUS) {
106 if (determine_status () != OK)
107 return STATE_CRITICAL;
108 ups_status = strdup ("");
109 result = STATE_OK;
111 if (status & UPSSTATUS_OFF) {
112 asprintf (&ups_status, "Off");
113 result = STATE_CRITICAL;
114 }
115 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
116 (UPSSTATUS_OB | UPSSTATUS_LB)) {
117 asprintf (&ups_status, "On Battery, Low Battery");
118 result = STATE_CRITICAL;
119 }
120 else {
121 if (status & UPSSTATUS_OL) {
122 asprintf (&ups_status, "%s%s", ups_status, "Online");
123 }
124 if (status & UPSSTATUS_OB) {
125 asprintf (&ups_status, "%s%s", ups_status, "On Battery");
126 result = STATE_WARNING;
127 }
128 if (status & UPSSTATUS_LB) {
129 asprintf (&ups_status, "%s%s", ups_status, ", Low Battery");
130 result = STATE_WARNING;
131 }
132 if (status & UPSSTATUS_CAL) {
133 asprintf (&ups_status, "%s%s", ups_status, ", Calibrating");
134 }
135 if (status & UPSSTATUS_RB) {
136 asprintf (&ups_status, "%s%s", ups_status, ", Replace Battery");
137 result = STATE_WARNING;
138 }
139 if (status & UPSSTATUS_UNKOWN) {
140 asprintf (&ups_status, "%s%s", ups_status, ", Unknown");
141 }
142 }
143 }
145 /* get the ups utility voltage if possible */
146 if (supported_options & UPS_UTILITY) {
148 if (get_ups_variable ("UTILITY", temp_buffer, sizeof (temp_buffer)) != OK)
149 return STATE_CRITICAL;
151 ups_utility_voltage = atof (temp_buffer);
153 if (ups_utility_voltage > 120.0)
154 ups_utility_deviation = 120.0 - ups_utility_voltage;
155 else
156 ups_utility_deviation = ups_utility_voltage - 120.0;
158 if (check_variable == UPS_UTILITY) {
159 if (check_critical_value == TRUE
160 && ups_utility_deviation >= critical_value) result = STATE_CRITICAL;
161 else if (check_warning_value == TRUE
162 && ups_utility_deviation >= warning_value
163 && result < STATE_WARNING) result = STATE_WARNING;
164 }
165 }
167 /* get the ups battery percent if possible */
168 if (supported_options & UPS_BATTPCT) {
170 if (get_ups_variable ("BATTPCT", temp_buffer, sizeof (temp_buffer)) != OK)
171 return STATE_CRITICAL;
173 ups_battery_percent = atof (temp_buffer);
175 if (check_variable == UPS_BATTPCT) {
176 if (check_critical_value == TRUE
177 && ups_battery_percent <= critical_value) result = STATE_CRITICAL;
178 else if (check_warning_value == TRUE
179 && ups_battery_percent <= warning_value
180 && result < STATE_WARNING) result = STATE_WARNING;
181 }
182 }
184 /* get the ups load percent if possible */
185 if (supported_options & UPS_LOADPCT) {
187 if (get_ups_variable ("LOADPCT", temp_buffer, sizeof (temp_buffer)) != OK)
188 return STATE_CRITICAL;
190 ups_load_percent = atof (temp_buffer);
192 if (check_variable == UPS_LOADPCT) {
193 if (check_critical_value == TRUE && ups_load_percent >= critical_value)
194 result = STATE_CRITICAL;
195 else if (check_warning_value == TRUE
196 && ups_load_percent >= warning_value && result < STATE_WARNING)
197 result = STATE_WARNING;
198 }
199 }
201 /* get the ups temperature if possible */
202 if (supported_options & UPS_TEMP) {
204 if (get_ups_variable ("UPSTEMP", temp_buffer, sizeof (temp_buffer)) != OK)
205 return STATE_CRITICAL;
207 ups_temperature = (atof (temp_buffer) * 1.8) + 32;
209 if (check_variable == UPS_TEMP) {
210 if (check_critical_value == TRUE && ups_temperature >= critical_value)
211 result = STATE_CRITICAL;
212 else if (check_warning_value == TRUE && ups_temperature >= warning_value
213 && result < STATE_WARNING)
214 result = STATE_WARNING;
215 }
216 }
218 /* if the UPS does not support any options we are looking for, report an error */
219 if (supported_options == UPS_NONE)
220 result = STATE_CRITICAL;
222 /* reset timeout */
223 alarm (0);
226 asprintf (&message, "UPS %s - ", (result == STATE_OK) ? "ok" : "problem");
228 if (supported_options & UPS_STATUS)
229 asprintf (&message, "%sStatus=%s ", message, ups_status);
231 if (supported_options & UPS_UTILITY)
232 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
234 if (supported_options & UPS_BATTPCT)
235 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
237 if (supported_options & UPS_LOADPCT)
238 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
240 if (supported_options & UPS_TEMP)
241 asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
243 if (supported_options == UPS_NONE)
244 asprintf (&message, "UPS does not support any available options\n");
246 printf ("%s\n", message);
248 return result;
249 }
253 /* determines what options are supported by the UPS */
254 int
255 determine_status (void)
256 {
257 char recv_buffer[MAX_INPUT_BUFFER];
258 char temp_buffer[MAX_INPUT_BUFFER];
259 char *ptr;
261 if (get_ups_variable ("STATUS", recv_buffer, sizeof (recv_buffer)) !=
262 STATE_OK) {
263 printf ("Invalid response received from hostn");
264 return ERROR;
265 }
267 recv_buffer[strlen (recv_buffer) - 1] = 0;
269 strcpy (temp_buffer, recv_buffer);
270 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
271 ptr = (char *) strtok (NULL, " ")) {
272 if (!strcmp (ptr, "OFF"))
273 status |= UPSSTATUS_OFF;
274 else if (!strcmp (ptr, "OL"))
275 status |= UPSSTATUS_OL;
276 else if (!strcmp (ptr, "OB"))
277 status |= UPSSTATUS_OB;
278 else if (!strcmp (ptr, "LB"))
279 status |= UPSSTATUS_LB;
280 else if (!strcmp (ptr, "CAL"))
281 status |= UPSSTATUS_CAL;
282 else if (!strcmp (ptr, "RB"))
283 status |= UPSSTATUS_RB;
284 else
285 status |= UPSSTATUS_UNKOWN;
286 }
288 return OK;
289 }
292 /* determines what options are supported by the UPS */
293 int
294 determine_supported_vars (void)
295 {
296 char send_buffer[MAX_INPUT_BUFFER];
297 char recv_buffer[MAX_INPUT_BUFFER];
298 char temp_buffer[MAX_INPUT_BUFFER];
299 char *ptr;
302 /* get the list of variables that this UPS supports */
303 if (ups_name)
304 sprintf (send_buffer, "LISTVARS %s\r\n", ups_name);
305 else
306 sprintf (send_buffer, "LISTVARS\r\n");
307 if (process_tcp_request
308 (server_address, server_port, send_buffer, recv_buffer,
309 sizeof (recv_buffer)) != STATE_OK) {
310 printf ("Invalid response received from host\n");
311 return ERROR;
312 }
314 recv_buffer[strlen (recv_buffer) - 1] = 0;
316 if (ups_name)
317 ptr = recv_buffer + 5 + strlen (ups_name) + 2;
318 else
319 ptr = recv_buffer + 5;
321 strcpy (temp_buffer, recv_buffer);
323 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
324 ptr = (char *) strtok (NULL, " ")) {
325 if (!strcmp (ptr, "UTILITY"))
326 supported_options |= UPS_UTILITY;
327 else if (!strcmp (ptr, "BATTPCT"))
328 supported_options |= UPS_BATTPCT;
329 else if (!strcmp (ptr, "LOADPCT"))
330 supported_options |= UPS_LOADPCT;
331 else if (!strcmp (ptr, "STATUS"))
332 supported_options |= UPS_STATUS;
333 else if (!strcmp (ptr, "UPSTEMP"))
334 supported_options |= UPS_TEMP;
335 }
337 return OK;
338 }
341 /* gets a variable value for a specific UPS */
342 int
343 get_ups_variable (const char *varname, char *buf, size_t buflen)
344 {
345 /* char command[MAX_INPUT_BUFFER]; */
346 char temp_buffer[MAX_INPUT_BUFFER];
347 char send_buffer[MAX_INPUT_BUFFER];
348 char *ptr;
350 /* create the command string to send to the UPS daemon */
351 if (ups_name)
352 sprintf (send_buffer, "REQ %s@%s\n", varname, ups_name);
353 else
354 sprintf (send_buffer, "REQ %s\n", varname);
356 /* send the command to the daemon and get a response back */
357 if (process_tcp_request
358 (server_address, server_port, send_buffer, temp_buffer,
359 sizeof (temp_buffer)) != STATE_OK) {
360 printf ("Invalid response received from host\n");
361 return ERROR;
362 }
364 if (ups_name)
365 ptr = temp_buffer + strlen (varname) + 5 + strlen (ups_name) + 1;
366 else
367 ptr = temp_buffer + strlen (varname) + 5;
369 if (!strcmp (ptr, "NOT-SUPPORTED")) {
370 printf ("Error: Variable '%s' is not supported\n", varname);
371 return ERROR;
372 }
374 if (!strcmp (ptr, "DATA-STALE")) {
375 printf ("Error: UPS data is stale\n");
376 return ERROR;
377 }
379 if (!strcmp (ptr, "UNKNOWN-UPS")) {
380 if (ups_name)
381 printf ("Error: UPS '%s' is unknown\n", ups_name);
382 else
383 printf ("Error: UPS is unknown\n");
384 return ERROR;
385 }
387 strncpy (buf, ptr, buflen - 1);
388 buf[buflen - 1] = 0;
390 return OK;
391 }
397 /* Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable]
398 [-wv warn_value] [-cv crit_value] [-to to_sec] */
401 /* process command-line arguments */
402 int
403 process_arguments (int argc, char **argv)
404 {
405 int c;
407 int option = 0;
408 static struct option longopts[] = {
409 {"hostname", required_argument, 0, 'H'},
410 {"ups", required_argument, 0, 'u'},
411 {"port", required_argument, 0, 'p'},
412 {"critical", required_argument, 0, 'c'},
413 {"warning", required_argument, 0, 'w'},
414 {"timeout", required_argument, 0, 't'},
415 {"variable", required_argument, 0, 'v'},
416 {"version", no_argument, 0, 'V'},
417 {"help", no_argument, 0, 'h'},
418 {0, 0, 0, 0}
419 };
421 if (argc < 2)
422 return ERROR;
424 for (c = 1; c < argc; c++) {
425 if (strcmp ("-to", argv[c]) == 0)
426 strcpy (argv[c], "-t");
427 else if (strcmp ("-wt", argv[c]) == 0)
428 strcpy (argv[c], "-w");
429 else if (strcmp ("-ct", argv[c]) == 0)
430 strcpy (argv[c], "-c");
431 }
433 while (1) {
434 c = getopt_long (argc, argv, "hVH:u:p:v:c:w:t:", longopts,
435 &option);
437 if (c == -1 || c == EOF)
438 break;
440 switch (c) {
441 case '?': /* help */
442 usage3 ("Unknown option", optopt);
443 case 'H': /* hostname */
444 if (is_host (optarg)) {
445 server_address = optarg;
446 }
447 else {
448 usage2 ("Invalid host name", optarg);
449 }
450 break;
451 case 'u': /* ups name */
452 ups_name = optarg;
453 break;
454 case 'p': /* port */
455 if (is_intpos (optarg)) {
456 server_port = atoi (optarg);
457 }
458 else {
459 usage2 ("Server port must be a positive integer", optarg);
460 }
461 break;
462 case 'c': /* critical time threshold */
463 if (is_intnonneg (optarg)) {
464 critical_value = atoi (optarg);
465 check_critical_value = TRUE;
466 }
467 else {
468 usage2 ("Critical time must be a nonnegative integer", optarg);
469 }
470 break;
471 case 'w': /* warning time threshold */
472 if (is_intnonneg (optarg)) {
473 warning_value = atoi (optarg);
474 check_warning_value = TRUE;
475 }
476 else {
477 usage2 ("Warning time must be a nonnegative integer", optarg);
478 }
479 break;
480 case 'v': /* variable */
481 if (!strcmp (optarg, "LINE"))
482 check_variable = UPS_UTILITY;
483 else if (!strcmp (optarg, "TEMP"))
484 check_variable = UPS_TEMP;
485 else if (!strcmp (optarg, "BATTPCT"))
486 check_variable = UPS_BATTPCT;
487 else if (!strcmp (optarg, "LOADPCT"))
488 check_variable = UPS_LOADPCT;
489 else
490 usage2 ("Unrecognized UPS variable", optarg);
491 break;
492 case 't': /* timeout */
493 if (is_intnonneg (optarg)) {
494 socket_timeout = atoi (optarg);
495 }
496 else {
497 usage ("Time interval must be a nonnegative integer\n");
498 }
499 break;
500 case 'V': /* version */
501 print_revision (progname, "$Revision$");
502 exit (STATE_OK);
503 case 'h': /* help */
504 print_help ();
505 exit (STATE_OK);
506 }
507 }
510 if (server_address == NULL && argc > optind) {
511 if (is_host (argv[optind]))
512 server_address = argv[optind++];
513 else
514 usage ("Invalid host name");
515 }
517 if (server_address == NULL)
518 server_address = strdup("127.0.0.1");
520 return validate_arguments();
521 }
527 int
528 validate_arguments (void)
529 {
530 return OK;
531 }
537 \f
538 void
539 print_help (void)
540 {
541 char *myport;
542 asprintf (&myport, "%d", PORT);
544 print_revision (progname, revision);
546 printf (_("Copyright (c) 2000 Tom Shields"));
547 printf (_(COPYRIGHT), copyright, email);
549 printf (_("This plugin tests the UPS service on the specified host.\n\
550 Network UPS Tools from www.exploits.org must be running for this plugin to\n\
551 work.\n\n"));
553 print_usage ();
555 printf (_(UT_HELP_VRSN));
557 printf (_(UT_HOST_PORT), 'p', myport);
559 printf (_("\
560 -u, --ups=STRING\n\
561 Name of UPS\n"));
563 printf (_(UT_WARN_CRIT));
565 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
567 printf (_(UT_VERBOSE));
569 printf (_("\
570 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
571 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
572 plugin will return an OK state. If the battery is on it will return a WARNING\n\
573 state. If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
574 state.\n\n"));
576 printf (_("\
577 You may also specify a variable to check [such as temperature, utility voltage,\n\
578 battery load, etc.] as well as warning and critical thresholds for the value of\n\
579 that variable. If the remote host has multiple UPS that are being monitored you\n\
580 will have to use the [ups] option to specify which UPS to check.\n\n"));
582 printf (_("Notes:\n\n\
583 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
584 Smart UPS Tools be installed on the remote host. If you do not have the\n\
585 package installed on your system, you can download it from\n\
586 http://www.exploits.org/nut\n\n"));
588 printf (_(UT_SUPPORT));
589 }
594 void
595 print_usage (void)
596 {
597 printf (_("\
598 Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n\
599 [-t timeout] [-v]\n"), progname);
600 printf (_(UT_HLP_VRS), progname, progname);
601 }