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 void
33 print_usage (void)
34 {
35 printf (_("\
36 Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n\
37 [-t timeout] [-v]\n"), progname);
38 printf (_(UT_HLP_VRS), progname, progname);
39 }
41 void
42 print_help (void)
43 {
44 char *myport;
45 asprintf (&myport, "%d", PORT);
47 print_revision (progname, revision);
49 printf (_("Copyright (c) 2000 Tom Shields"));
50 printf (_(COPYRIGHT), copyright, email);
52 printf (_("This plugin tests the UPS service on the specified host.\n\
53 Network UPS Tools from www.exploits.org must be running for this plugin to\n\
54 work.\n\n"));
56 print_usage ();
58 printf (_(UT_HELP_VRSN));
60 printf (_(UT_HOST_PORT), 'p', myport);
62 printf (_("\
63 -u, --ups=STRING\n\
64 Name of UPS\n"));
66 printf (_(UT_WARN_CRIT));
68 printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
70 printf (_(UT_VERBOSE));
72 printf (_("\
73 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
74 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
75 plugin will return an OK state. If the battery is on it will return a WARNING\n\
76 state. If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
77 state.\n\n"));
79 printf (_("\
80 You may also specify a variable to check [such as temperature, utility voltage,\n\
81 battery load, etc.] as well as warning and critical thresholds for the value of\n\
82 that variable. If the remote host has multiple UPS that are being monitored you\n\
83 will have to use the [ups] option to specify which UPS to check.\n\n"));
85 printf (_("Notes:\n\n\
86 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
87 Smart UPS Tools be installed on the remote host. If you do not have the\n\
88 package installed on your system, you can download it from\n\
89 http://www.exploits.org/nut\n\n"));
91 printf (_(UT_SUPPORT));
92 }
93 \f
94 #define CHECK_NONE 0
96 #define UPS_NONE 0 /* no supported options */
97 #define UPS_UTILITY 1 /* supports utility line voltage */
98 #define UPS_BATTPCT 2 /* supports percent battery remaining */
99 #define UPS_STATUS 4 /* supports UPS status */
100 #define UPS_TEMP 8 /* supports UPS temperature */
101 #define UPS_LOADPCT 16 /* supports load percent */
103 #define UPSSTATUS_NONE 0
104 #define UPSSTATUS_OFF 1
105 #define UPSSTATUS_OL 2
106 #define UPSSTATUS_OB 4
107 #define UPSSTATUS_LB 8
108 #define UPSSTATUS_CAL 16
109 #define UPSSTATUS_RB 32 /*Replace Battery */
110 #define UPSSTATUS_UNKOWN 64
112 int server_port = PORT;
113 char *server_address = "127.0.0.1";
114 char *ups_name = NULL;
115 double warning_value = 0.0;
116 double critical_value = 0.0;
117 int check_warning_value = FALSE;
118 int check_critical_value = FALSE;
119 int check_variable = UPS_NONE;
120 int supported_options = UPS_NONE;
121 int status = UPSSTATUS_NONE;
123 double ups_utility_voltage = 0.0;
124 double ups_battery_percent = 0.0;
125 double ups_load_percent = 0.0;
126 double ups_temperature = 0.0;
127 char *ups_status = "N/A";
129 int determine_status (void);
130 int determine_supported_vars (void);
131 int get_ups_variable (const char *, char *, int);
133 int process_arguments (int, char **);
134 int validate_arguments (void);
136 int
137 main (int argc, char **argv)
138 {
139 int result = STATE_OK;
140 char *message;
141 char temp_buffer[MAX_INPUT_BUFFER];
143 double ups_utility_deviation = 0.0;
145 if (process_arguments (argc, argv) != OK)
146 usage ("Invalid command arguments supplied\n");
148 /* initialize alarm signal handling */
149 signal (SIGALRM, socket_timeout_alarm_handler);
151 /* set socket timeout */
152 alarm (socket_timeout);
154 /* determine what variables the UPS supports */
155 if (determine_supported_vars () != OK)
156 return STATE_CRITICAL;
158 /* get the ups status if possible */
159 if (supported_options & UPS_STATUS) {
161 if (determine_status () != OK)
162 return STATE_CRITICAL;
163 asprintf (&ups_status, "");
164 result = STATE_OK;
166 if (status & UPSSTATUS_OFF) {
167 asprintf (&ups_status, "Off");
168 result = STATE_CRITICAL;
169 }
170 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
171 (UPSSTATUS_OB | UPSSTATUS_LB)) {
172 asprintf (&ups_status, "On Battery, Low Battery");
173 result = STATE_CRITICAL;
174 }
175 else {
176 if (status & UPSSTATUS_OL) {
177 asprintf (&ups_status, "%s%s", ups_status, "Online");
178 }
179 if (status & UPSSTATUS_OB) {
180 asprintf (&ups_status, "%s%s", ups_status, "On Battery");
181 result = STATE_WARNING;
182 }
183 if (status & UPSSTATUS_LB) {
184 asprintf (&ups_status, "%s%s", ups_status, ", Low Battery");
185 result = STATE_WARNING;
186 }
187 if (status & UPSSTATUS_CAL) {
188 asprintf (&ups_status, "%s%s", ups_status, ", Calibrating");
189 }
190 if (status & UPSSTATUS_RB) {
191 asprintf (&ups_status, "%s%s", ups_status, ", Replace Battery");
192 result = STATE_WARNING;
193 }
194 if (status & UPSSTATUS_UNKOWN) {
195 asprintf (&ups_status, "%s%s", ups_status, ", Unknown");
196 }
197 }
198 }
200 /* get the ups utility voltage if possible */
201 if (supported_options & UPS_UTILITY) {
203 if (get_ups_variable ("UTILITY", temp_buffer, sizeof (temp_buffer)) != OK)
204 return STATE_CRITICAL;
206 ups_utility_voltage = atof (temp_buffer);
208 if (ups_utility_voltage > 120.0)
209 ups_utility_deviation = 120.0 - ups_utility_voltage;
210 else
211 ups_utility_deviation = ups_utility_voltage - 120.0;
213 if (check_variable == UPS_UTILITY) {
214 if (check_critical_value == TRUE
215 && ups_utility_deviation >= critical_value) result = STATE_CRITICAL;
216 else if (check_warning_value == TRUE
217 && ups_utility_deviation >= warning_value
218 && result < STATE_WARNING) result = STATE_WARNING;
219 }
220 }
222 /* get the ups battery percent if possible */
223 if (supported_options & UPS_BATTPCT) {
225 if (get_ups_variable ("BATTPCT", temp_buffer, sizeof (temp_buffer)) != OK)
226 return STATE_CRITICAL;
228 ups_battery_percent = atof (temp_buffer);
230 if (check_variable == UPS_BATTPCT) {
231 if (check_critical_value == TRUE
232 && ups_battery_percent <= critical_value) result = STATE_CRITICAL;
233 else if (check_warning_value == TRUE
234 && ups_battery_percent <= warning_value
235 && result < STATE_WARNING) result = STATE_WARNING;
236 }
237 }
239 /* get the ups load percent if possible */
240 if (supported_options & UPS_LOADPCT) {
242 if (get_ups_variable ("LOADPCT", temp_buffer, sizeof (temp_buffer)) != OK)
243 return STATE_CRITICAL;
245 ups_load_percent = atof (temp_buffer);
247 if (check_variable == UPS_LOADPCT) {
248 if (check_critical_value == TRUE && ups_load_percent >= critical_value)
249 result = STATE_CRITICAL;
250 else if (check_warning_value == TRUE
251 && ups_load_percent >= warning_value && result < STATE_WARNING)
252 result = STATE_WARNING;
253 }
254 }
256 /* get the ups temperature if possible */
257 if (supported_options & UPS_TEMP) {
259 if (get_ups_variable ("UPSTEMP", temp_buffer, sizeof (temp_buffer)) != OK)
260 return STATE_CRITICAL;
262 ups_temperature = (atof (temp_buffer) * 1.8) + 32;
264 if (check_variable == UPS_TEMP) {
265 if (check_critical_value == TRUE && ups_temperature >= critical_value)
266 result = STATE_CRITICAL;
267 else if (check_warning_value == TRUE && ups_temperature >= warning_value
268 && result < STATE_WARNING)
269 result = STATE_WARNING;
270 }
271 }
273 /* if the UPS does not support any options we are looking for, report an error */
274 if (supported_options == UPS_NONE)
275 result = STATE_CRITICAL;
277 /* reset timeout */
278 alarm (0);
281 asprintf (&message, "UPS %s - ", (result == STATE_OK) ? "ok" : "problem");
283 if (supported_options & UPS_STATUS)
284 asprintf (&message, "%sStatus=%s ", message, ups_status);
286 if (supported_options & UPS_UTILITY)
287 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
289 if (supported_options & UPS_BATTPCT)
290 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
292 if (supported_options & UPS_LOADPCT)
293 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
295 if (supported_options & UPS_TEMP)
296 asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
298 if (supported_options == UPS_NONE)
299 asprintf (&message, "UPS does not support any available options\n");
301 printf ("%s\n", message);
303 return result;
304 }
308 /* determines what options are supported by the UPS */
309 int
310 determine_status (void)
311 {
312 char recv_buffer[MAX_INPUT_BUFFER];
313 char temp_buffer[MAX_INPUT_BUFFER];
314 char *ptr;
316 if (get_ups_variable ("STATUS", recv_buffer, sizeof (recv_buffer)) !=
317 STATE_OK) {
318 printf ("Invalid response received from hostn");
319 return ERROR;
320 }
322 recv_buffer[strlen (recv_buffer) - 1] = 0;
324 strcpy (temp_buffer, recv_buffer);
325 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
326 ptr = (char *) strtok (NULL, " ")) {
327 if (!strcmp (ptr, "OFF"))
328 status |= UPSSTATUS_OFF;
329 else if (!strcmp (ptr, "OL"))
330 status |= UPSSTATUS_OL;
331 else if (!strcmp (ptr, "OB"))
332 status |= UPSSTATUS_OB;
333 else if (!strcmp (ptr, "LB"))
334 status |= UPSSTATUS_LB;
335 else if (!strcmp (ptr, "CAL"))
336 status |= UPSSTATUS_CAL;
337 else if (!strcmp (ptr, "RB"))
338 status |= UPSSTATUS_RB;
339 else
340 status |= UPSSTATUS_UNKOWN;
341 }
343 return OK;
344 }
347 /* determines what options are supported by the UPS */
348 int
349 determine_supported_vars (void)
350 {
351 char send_buffer[MAX_INPUT_BUFFER];
352 char recv_buffer[MAX_INPUT_BUFFER];
353 char temp_buffer[MAX_INPUT_BUFFER];
354 char *ptr;
357 /* get the list of variables that this UPS supports */
358 if (ups_name)
359 sprintf (send_buffer, "LISTVARS %s\r\n", ups_name);
360 else
361 sprintf (send_buffer, "LISTVARS\r\n");
362 if (process_tcp_request
363 (server_address, server_port, send_buffer, recv_buffer,
364 sizeof (recv_buffer)) != STATE_OK) {
365 printf ("Invalid response received from host\n");
366 return ERROR;
367 }
369 recv_buffer[strlen (recv_buffer) - 1] = 0;
371 if (ups_name)
372 ptr = recv_buffer + 5 + strlen (ups_name) + 2;
373 else
374 ptr = recv_buffer + 5;
376 strcpy (temp_buffer, recv_buffer);
378 for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
379 ptr = (char *) strtok (NULL, " ")) {
380 if (!strcmp (ptr, "UTILITY"))
381 supported_options |= UPS_UTILITY;
382 else if (!strcmp (ptr, "BATTPCT"))
383 supported_options |= UPS_BATTPCT;
384 else if (!strcmp (ptr, "LOADPCT"))
385 supported_options |= UPS_LOADPCT;
386 else if (!strcmp (ptr, "STATUS"))
387 supported_options |= UPS_STATUS;
388 else if (!strcmp (ptr, "UPSTEMP"))
389 supported_options |= UPS_TEMP;
390 }
392 return OK;
393 }
396 /* gets a variable value for a specific UPS */
397 int
398 get_ups_variable (const char *varname, char *buf, int buflen)
399 {
400 /* char command[MAX_INPUT_BUFFER]; */
401 char temp_buffer[MAX_INPUT_BUFFER];
402 char send_buffer[MAX_INPUT_BUFFER];
403 char *ptr;
405 /* create the command string to send to the UPS daemon */
406 if (ups_name)
407 sprintf (send_buffer, "REQ %s@%s\n", varname, ups_name);
408 else
409 sprintf (send_buffer, "REQ %s\n", varname);
411 /* send the command to the daemon and get a response back */
412 if (process_tcp_request
413 (server_address, server_port, send_buffer, temp_buffer,
414 sizeof (temp_buffer)) != STATE_OK) {
415 printf ("Invalid response received from host\n");
416 return ERROR;
417 }
419 if (ups_name)
420 ptr = temp_buffer + strlen (varname) + 5 + strlen (ups_name) + 1;
421 else
422 ptr = temp_buffer + strlen (varname) + 5;
424 if (!strcmp (ptr, "NOT-SUPPORTED")) {
425 printf ("Error: Variable '%s' is not supported\n", varname);
426 return ERROR;
427 }
429 if (!strcmp (ptr, "DATA-STALE")) {
430 printf ("Error: UPS data is stale\n");
431 return ERROR;
432 }
434 if (!strcmp (ptr, "UNKNOWN-UPS")) {
435 if (ups_name)
436 printf ("Error: UPS '%s' is unknown\n", ups_name);
437 else
438 printf ("Error: UPS is unknown\n");
439 return ERROR;
440 }
442 strncpy (buf, ptr, buflen - 1);
443 buf[buflen - 1] = 0;
445 return OK;
446 }
452 /* Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable]
453 [-wv warn_value] [-cv crit_value] [-to to_sec] */
456 /* process command-line arguments */
457 int
458 process_arguments (int argc, char **argv)
459 {
460 int c;
462 int option_index = 0;
463 static struct option long_options[] = {
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 {"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, "hVH:u:p:v:c:w:t:", long_options,
490 &option_index);
492 if (c == -1 || c == EOF)
493 break;
495 switch (c) {
496 case '?': /* help */
497 usage3 ("Unknown option", optopt);
498 case 'H': /* hostname */
499 if (is_host (optarg)) {
500 server_address = optarg;
501 }
502 else {
503 usage2 ("Invalid host name", optarg);
504 }
505 break;
506 case 'u': /* ups name */
507 ups_name = optarg;
508 break;
509 case 'p': /* port */
510 if (is_intpos (optarg)) {
511 server_port = atoi (optarg);
512 }
513 else {
514 usage2 ("Server port must be a positive integer", optarg);
515 }
516 break;
517 case 'c': /* critical time threshold */
518 if (is_intnonneg (optarg)) {
519 critical_value = atoi (optarg);
520 check_critical_value = TRUE;
521 }
522 else {
523 usage2 ("Critical time must be a nonnegative integer", optarg);
524 }
525 break;
526 case 'w': /* warning time threshold */
527 if (is_intnonneg (optarg)) {
528 warning_value = atoi (optarg);
529 check_warning_value = TRUE;
530 }
531 else {
532 usage2 ("Warning time must be a nonnegative integer", optarg);
533 }
534 break;
535 case 'v': /* variable */
536 if (!strcmp (optarg, "LINE"))
537 check_variable = UPS_UTILITY;
538 else if (!strcmp (optarg, "TEMP"))
539 check_variable = UPS_TEMP;
540 else if (!strcmp (optarg, "BATTPCT"))
541 check_variable = UPS_BATTPCT;
542 else if (!strcmp (optarg, "LOADPCT"))
543 check_variable = UPS_LOADPCT;
544 else
545 usage2 ("Unrecognized UPS variable", optarg);
546 break;
547 case 't': /* timeout */
548 if (is_intnonneg (optarg)) {
549 socket_timeout = atoi (optarg);
550 }
551 else {
552 usage ("Time interval must be a nonnegative integer\n");
553 }
554 break;
555 case 'V': /* version */
556 print_revision (progname, "$Revision$");
557 exit (STATE_OK);
558 case 'h': /* help */
559 print_help ();
560 exit (STATE_OK);
561 }
562 }
565 if (server_address == NULL && argc > optind) {
566 if (is_host (argv[optind]))
567 server_address = argv[optind++];
568 else
569 usage ("Invalid host name");
570 }
572 return validate_arguments();
573 }
579 int
580 validate_arguments (void)
581 {
582 return OK;
583 }