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_warn = FALSE;
56 int check_crit = 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 *data;
82 char temp_buffer[MAX_INPUT_BUFFER];
83 double ups_utility_deviation = 0.0;
85 setlocale (LC_ALL, "");
86 bindtextdomain (PACKAGE, LOCALEDIR);
87 textdomain (PACKAGE);
89 ups_status = strdup ("N/A");
90 data = strdup ("");
92 if (process_arguments (argc, argv) != OK)
93 usage ("Invalid command arguments supplied\n");
95 /* initialize alarm signal handling */
96 signal (SIGALRM, socket_timeout_alarm_handler);
98 /* set socket timeout */
99 alarm (socket_timeout);
101 /* determine what variables the UPS supports */
102 if (determine_supported_vars () != OK)
103 return STATE_CRITICAL;
105 /* get the ups status if possible */
106 if (supported_options & UPS_STATUS) {
108 if (determine_status () != OK)
109 return STATE_CRITICAL;
110 ups_status = strdup ("");
111 result = STATE_OK;
113 if (status & UPSSTATUS_OFF) {
114 asprintf (&ups_status, "Off");
115 result = STATE_CRITICAL;
116 }
117 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
118 (UPSSTATUS_OB | UPSSTATUS_LB)) {
119 asprintf (&ups_status, "On Battery, Low Battery");
120 result = STATE_CRITICAL;
121 }
122 else {
123 if (status & UPSSTATUS_OL) {
124 asprintf (&ups_status, "%s%s", ups_status, "Online");
125 }
126 if (status & UPSSTATUS_OB) {
127 asprintf (&ups_status, "%s%s", ups_status, "On Battery");
128 result = STATE_WARNING;
129 }
130 if (status & UPSSTATUS_LB) {
131 asprintf (&ups_status, "%s%s", ups_status, ", Low Battery");
132 result = STATE_WARNING;
133 }
134 if (status & UPSSTATUS_CAL) {
135 asprintf (&ups_status, "%s%s", ups_status, ", Calibrating");
136 }
137 if (status & UPSSTATUS_RB) {
138 asprintf (&ups_status, "%s%s", ups_status, ", Replace Battery");
139 result = STATE_WARNING;
140 }
141 if (status & UPSSTATUS_UNKOWN) {
142 asprintf (&ups_status, "%s%s", ups_status, ", Unknown");
143 }
144 }
145 asprintf (&message, "%sStatus=%s ", message, ups_status);
146 }
148 /* get the ups utility voltage if possible */
149 if (supported_options & UPS_UTILITY) {
151 if (get_ups_variable ("UTILITY", temp_buffer, sizeof (temp_buffer)) != OK)
152 return STATE_CRITICAL;
154 ups_utility_voltage = atof (temp_buffer);
155 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
157 if (ups_utility_voltage > 120.0)
158 ups_utility_deviation = 120.0 - ups_utility_voltage;
159 else
160 ups_utility_deviation = ups_utility_voltage - 120.0;
162 if (check_variable == UPS_UTILITY) {
163 if (check_crit==TRUE && ups_utility_deviation>=critical_value) {
164 result = STATE_CRITICAL;
165 }
166 else if (check_warn==TRUE && ups_utility_deviation>=warning_value) {
167 result = max_state (result, STATE_WARNING);
168 }
169 asprintf (&data, "%s",
170 fperfdata ("voltage", ups_utility_voltage, "V",
171 check_warn, warning_value,
172 check_crit, critical_value,
173 TRUE, 0, FALSE, 0));
174 } else {
175 asprintf (&data, "%s",
176 fperfdata ("voltage", ups_utility_voltage, "V",
177 FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
178 }
179 }
181 /* get the ups battery percent if possible */
182 if (supported_options & UPS_BATTPCT) {
184 if (get_ups_variable ("BATTPCT", temp_buffer, sizeof (temp_buffer)) != OK)
185 return STATE_CRITICAL;
187 ups_battery_percent = atof (temp_buffer);
188 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
190 if (check_variable == UPS_BATTPCT) {
191 if (check_crit==TRUE && ups_battery_percent <= critical_value) {
192 result = STATE_CRITICAL;
193 }
194 else if (check_warn==TRUE && ups_battery_percent<=warning_value) {
195 result = max_state (result, STATE_WARNING);
196 }
197 asprintf (&data, "%s %s", data,
198 perfdata ("battery", (long)ups_battery_percent, "%",
199 check_warn, (long)(1000*warning_value),
200 check_crit, (long)(1000*critical_value),
201 TRUE, 0, TRUE, 100));
202 } else {
203 asprintf (&data, "%s %s", data,
204 perfdata ("battery", (long)ups_battery_percent, "%",
205 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
206 }
207 }
209 /* get the ups load percent if possible */
210 if (supported_options & UPS_LOADPCT) {
212 if (get_ups_variable ("LOADPCT", temp_buffer, sizeof (temp_buffer)) != OK)
213 return STATE_CRITICAL;
215 ups_load_percent = atof (temp_buffer);
216 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
218 if (check_variable == UPS_LOADPCT) {
219 if (check_crit==TRUE && ups_load_percent>=critical_value) {
220 result = STATE_CRITICAL;
221 }
222 else if (check_warn==TRUE && ups_load_percent>=warning_value) {
223 result = max_state (result, STATE_WARNING);
224 }
225 asprintf (&data, "%s %s", data,
226 perfdata ("load", (long)ups_load_percent, "%",
227 check_warn, (long)(1000*warning_value),
228 check_crit, (long)(1000*critical_value),
229 TRUE, 0, TRUE, 100));
230 } else {
231 asprintf (&data, "%s %s", data,
232 perfdata ("load", (long)ups_load_percent, "%",
233 FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
234 }
235 }
237 /* get the ups temperature if possible */
238 if (supported_options & UPS_TEMP) {
240 if (get_ups_variable ("UPSTEMP", temp_buffer, sizeof (temp_buffer)) != OK)
241 return STATE_CRITICAL;
243 ups_temperature = (atof (temp_buffer) * 1.8) + 32;
244 asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
246 if (check_variable == UPS_TEMP) {
247 if (check_crit==TRUE && ups_temperature>=critical_value) {
248 result = STATE_CRITICAL;
249 }
250 else if (check_warn == TRUE && ups_temperature>=warning_value) {
251 result = max_state (result, STATE_WARNING);
252 }
253 asprintf (&data, "%s %s", data,
254 perfdata ("temp", (long)ups_temperature, "degF",
255 check_warn, (long)(1000*warning_value),
256 check_crit, (long)(1000*critical_value),
257 TRUE, 0, FALSE, 0));
258 } else {
259 asprintf (&data, "%s %s", data,
260 perfdata ("temp", (long)ups_temperature, "degF",
261 FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
262 }
263 }
265 /* if the UPS does not support any options we are looking for, report an error */
266 if (supported_options == UPS_NONE) {
267 result = STATE_CRITICAL;
268 asprintf (&message, "UPS does not support any available options\n");
269 }
271 /* reset timeout */
272 alarm (0);
274 printf ("UPS %s - %s|%s\n", state_text(result), message, data);
275 return result;
276 }
280 /* determines what options are supported by the UPS */
281 int
282 determine_status (void)
283 {
284 char recv_buffer[MAX_INPUT_BUFFER];
285 char temp_buffer[MAX_INPUT_BUFFER];
286 char *ptr;
288 if (get_ups_variable ("STATUS", recv_buffer, sizeof (recv_buffer)) !=
289 STATE_OK) {
290 printf ("Invalid response received from hostn");
291 return ERROR;
292 }
294 recv_buffer[strlen (recv_buffer) - 1] = 0;
296 strcpy (temp_buffer, recv_buffer);
297 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
298 ptr = (char *) strtok (NULL, " ")) {
299 if (!strcmp (ptr, "OFF"))
300 status |= UPSSTATUS_OFF;
301 else if (!strcmp (ptr, "OL"))
302 status |= UPSSTATUS_OL;
303 else if (!strcmp (ptr, "OB"))
304 status |= UPSSTATUS_OB;
305 else if (!strcmp (ptr, "LB"))
306 status |= UPSSTATUS_LB;
307 else if (!strcmp (ptr, "CAL"))
308 status |= UPSSTATUS_CAL;
309 else if (!strcmp (ptr, "RB"))
310 status |= UPSSTATUS_RB;
311 else
312 status |= UPSSTATUS_UNKOWN;
313 }
315 return OK;
316 }
319 /* determines what options are supported by the UPS */
320 int
321 determine_supported_vars (void)
322 {
323 char send_buffer[MAX_INPUT_BUFFER];
324 char recv_buffer[MAX_INPUT_BUFFER];
325 char temp_buffer[MAX_INPUT_BUFFER];
326 char *ptr;
329 /* get the list of variables that this UPS supports */
330 if (ups_name)
331 sprintf (send_buffer, "LISTVARS %s\r\n", ups_name);
332 else
333 sprintf (send_buffer, "LISTVARS\r\n");
334 if (process_tcp_request
335 (server_address, server_port, send_buffer, recv_buffer,
336 sizeof (recv_buffer)) != STATE_OK) {
337 printf ("Invalid response received from host\n");
338 return ERROR;
339 }
341 recv_buffer[strlen (recv_buffer) - 1] = 0;
343 if (ups_name)
344 ptr = recv_buffer + 5 + strlen (ups_name) + 2;
345 else
346 ptr = recv_buffer + 5;
348 strcpy (temp_buffer, recv_buffer);
350 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
351 ptr = (char *) strtok (NULL, " ")) {
352 if (!strcmp (ptr, "UTILITY"))
353 supported_options |= UPS_UTILITY;
354 else if (!strcmp (ptr, "BATTPCT"))
355 supported_options |= UPS_BATTPCT;
356 else if (!strcmp (ptr, "LOADPCT"))
357 supported_options |= UPS_LOADPCT;
358 else if (!strcmp (ptr, "STATUS"))
359 supported_options |= UPS_STATUS;
360 else if (!strcmp (ptr, "UPSTEMP"))
361 supported_options |= UPS_TEMP;
362 }
364 return OK;
365 }
368 /* gets a variable value for a specific UPS */
369 int
370 get_ups_variable (const char *varname, char *buf, size_t buflen)
371 {
372 /* char command[MAX_INPUT_BUFFER]; */
373 char temp_buffer[MAX_INPUT_BUFFER];
374 char send_buffer[MAX_INPUT_BUFFER];
375 char *ptr;
377 /* create the command string to send to the UPS daemon */
378 if (ups_name)
379 sprintf (send_buffer, "REQ %s@%s\n", varname, ups_name);
380 else
381 sprintf (send_buffer, "REQ %s\n", varname);
383 /* send the command to the daemon and get a response back */
384 if (process_tcp_request
385 (server_address, server_port, send_buffer, temp_buffer,
386 sizeof (temp_buffer)) != STATE_OK) {
387 printf ("Invalid response received from host\n");
388 return ERROR;
389 }
391 if (ups_name)
392 ptr = temp_buffer + strlen (varname) + 5 + strlen (ups_name) + 1;
393 else
394 ptr = temp_buffer + strlen (varname) + 5;
396 if (!strcmp (ptr, "NOT-SUPPORTED")) {
397 printf ("Error: Variable '%s' is not supported\n", varname);
398 return ERROR;
399 }
401 if (!strcmp (ptr, "DATA-STALE")) {
402 printf ("Error: UPS data is stale\n");
403 return ERROR;
404 }
406 if (!strcmp (ptr, "UNKNOWN-UPS")) {
407 if (ups_name)
408 printf ("Error: UPS '%s' is unknown\n", ups_name);
409 else
410 printf ("Error: UPS is unknown\n");
411 return ERROR;
412 }
414 strncpy (buf, ptr, buflen - 1);
415 buf[buflen - 1] = 0;
417 return OK;
418 }
424 /* Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable]
425 [-wv warn_value] [-cv crit_value] [-to to_sec] */
428 /* process command-line arguments */
429 int
430 process_arguments (int argc, char **argv)
431 {
432 int c;
434 int option = 0;
435 static struct option longopts[] = {
436 {"hostname", required_argument, 0, 'H'},
437 {"ups", required_argument, 0, 'u'},
438 {"port", required_argument, 0, 'p'},
439 {"critical", required_argument, 0, 'c'},
440 {"warning", required_argument, 0, 'w'},
441 {"timeout", required_argument, 0, 't'},
442 {"variable", required_argument, 0, 'v'},
443 {"version", no_argument, 0, 'V'},
444 {"help", no_argument, 0, 'h'},
445 {0, 0, 0, 0}
446 };
448 if (argc < 2)
449 return ERROR;
451 for (c = 1; c < argc; c++) {
452 if (strcmp ("-to", argv[c]) == 0)
453 strcpy (argv[c], "-t");
454 else if (strcmp ("-wt", argv[c]) == 0)
455 strcpy (argv[c], "-w");
456 else if (strcmp ("-ct", argv[c]) == 0)
457 strcpy (argv[c], "-c");
458 }
460 while (1) {
461 c = getopt_long (argc, argv, "hVH:u:p:v:c:w:t:", longopts,
462 &option);
464 if (c == -1 || c == EOF)
465 break;
467 switch (c) {
468 case '?': /* help */
469 usage3 ("Unknown option", optopt);
470 case 'H': /* hostname */
471 if (is_host (optarg)) {
472 server_address = optarg;
473 }
474 else {
475 usage2 ("Invalid host name", optarg);
476 }
477 break;
478 case 'u': /* ups name */
479 ups_name = optarg;
480 break;
481 case 'p': /* port */
482 if (is_intpos (optarg)) {
483 server_port = atoi (optarg);
484 }
485 else {
486 usage2 ("Server port must be a positive integer", optarg);
487 }
488 break;
489 case 'c': /* critical time threshold */
490 if (is_intnonneg (optarg)) {
491 critical_value = atoi (optarg);
492 check_crit = TRUE;
493 }
494 else {
495 usage2 ("Critical time must be a nonnegative integer", optarg);
496 }
497 break;
498 case 'w': /* warning time threshold */
499 if (is_intnonneg (optarg)) {
500 warning_value = atoi (optarg);
501 check_warn = TRUE;
502 }
503 else {
504 usage2 ("Warning time must be a nonnegative integer", optarg);
505 }
506 break;
507 case 'v': /* variable */
508 if (!strcmp (optarg, "LINE"))
509 check_variable = UPS_UTILITY;
510 else if (!strcmp (optarg, "TEMP"))
511 check_variable = UPS_TEMP;
512 else if (!strcmp (optarg, "BATTPCT"))
513 check_variable = UPS_BATTPCT;
514 else if (!strcmp (optarg, "LOADPCT"))
515 check_variable = UPS_LOADPCT;
516 else
517 usage2 ("Unrecognized UPS variable", optarg);
518 break;
519 case 't': /* timeout */
520 if (is_intnonneg (optarg)) {
521 socket_timeout = atoi (optarg);
522 }
523 else {
524 usage ("Time interval must be a nonnegative integer\n");
525 }
526 break;
527 case 'V': /* version */
528 print_revision (progname, "$Revision$");
529 exit (STATE_OK);
530 case 'h': /* help */
531 print_help ();
532 exit (STATE_OK);
533 }
534 }
537 if (server_address == NULL && argc > optind) {
538 if (is_host (argv[optind]))
539 server_address = argv[optind++];
540 else
541 usage ("Invalid host name");
542 }
544 if (server_address == NULL)
545 server_address = strdup("127.0.0.1");
547 return validate_arguments();
548 }
554 int
555 validate_arguments (void)
556 {
557 return OK;
558 }
564 \f
565 void
566 print_help (void)
567 {
568 char *myport;
569 asprintf (&myport, "%d", PORT);
571 print_revision (progname, revision);
573 printf (_("Copyright (c) 2000 Tom Shields"));
574 printf (_(COPYRIGHT), copyright, email);
576 printf (_("This plugin tests the UPS service on the specified host.\n\
577 Network UPS Tools from www.exploits.org must be running for this plugin to\n\
578 work.\n\n"));
580 print_usage ();
582 printf (_(UT_HELP_VRSN));
584 printf (_(UT_HOST_PORT), 'p', myport);
586 printf (_("\
587 -u, --ups=STRING\n\
588 Name of UPS\n"));
590 printf (_(UT_WARN_CRIT));
592 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
594 printf (_(UT_VERBOSE));
596 printf (_("\
597 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
598 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
599 plugin will return an OK state. If the battery is on it will return a WARNING\n\
600 state. If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
601 state.\n\n"));
603 printf (_("\
604 You may also specify a variable to check [such as temperature, utility voltage,\n\
605 battery load, etc.] as well as warning and critical thresholds for the value of\n\
606 that variable. If the remote host has multiple UPS that are being monitored you\n\
607 will have to use the [ups] option to specify which UPS to check.\n\n"));
609 printf (_("Notes:\n\n\
610 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
611 Smart UPS Tools be installed on the remote host. If you do not have the\n\
612 package installed on your system, you can download it from\n\
613 http://www.exploits.org/nut\n\n"));
615 printf (_(UT_SUPPORT));
616 }
621 void
622 print_usage (void)
623 {
624 printf (_("\
625 Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n\
626 [-t timeout] [-v]\n"), progname);
627 printf (_(UT_HLP_VRS), progname, progname);
628 }