Code

do not translate the strings that will be compared to utility output - LC_ALL is...
[nagiosplug.git] / plugins / check_ups.c
1 /******************************************************************************
2 *
3 * CHECK_UPS.C
4 *
5 * Program: UPS monitor plugin for Nagios
6 * License: GPL
7 * Copyright (c) 1999 Ethan Galstad (nagios@nagios.org)
8 *
9 * Last Modified: $Date$
10 *
11 * Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable] \
12 *                          [-wv warn_value] [-cv crit_value] [-to to_sec]
13 *
14 * Description:
15 *
17 * This plugin attempts to determine the status of an UPS
18 * (Uninterruptible Power Supply) on a remote host (or the local host)
19 * that is being monitored with Russel Kroll's "Smarty UPS Tools"
20 * package. If the UPS is online or calibrating, the plugin will
21 * return an OK state. If the battery is on it will return a WARNING
22 * state.  If the UPS is off or has a low battery the plugin will
23 * return a CRITICAL state.  You may also specify a variable to check
24 * (such as temperature, utility voltage, battery load, etc.)  as well
25 * as warning and critical thresholds for the value of that variable.
26 * If the remote host has multiple UPS that are being monitored you
27 * will have to use the [ups] option to specify which UPS to check.
28 *
29 * Notes:
30 *
31 * This plugin requires that the UPSD daemon distributed with Russel
32 * Kroll's "Smart UPS Tools" be installed on the remote host.  If you
33 * don't have the package installed on your system, you can download
34 * it from http://www.exploits.org/nut
35 *
36 * License Information:
37 *
38 * This program is free software; you can redistribute it and/or modify
39 * it under the terms of the GNU General Public License as published by
40 * the Free Software Foundation; either version 2 of the License, or
41 * (at your option) any later version.
42 *
43 * This program is distributed in the hope that it will be useful,
44 * but WITHOUT ANY WARRANTY; without even the implied warranty of
45 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See the
46 * GNU General Public License for more details.
47 *
48 * You should have received a copy of the GNU General Public License
49 * along with this program; if not, write to the Free Software
50 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
51 *
52 ******************************************************************************/
54 #include "config.h"
55 #include "common.h"
56 #include "netutils.h"
57 #include "utils.h"
59 const char *progname = "check_ups";
60 #define REVISION "$Revision$"
61 #define COPYRIGHT "1999-2002"
62 #define AUTHOR "Ethan Galstad"
63 #define EMAIL "nagios@nagios.org"
65 #define CHECK_NONE      0
67 #define PORT     3493
69 #define UPS_NONE     0   /* no supported options */
70 #define UPS_UTILITY  1   /* supports utility line voltage */
71 #define UPS_BATTPCT  2   /* supports percent battery remaining */
72 #define UPS_STATUS   4   /* supports UPS status */
73 #define UPS_TEMP     8   /* supports UPS temperature */
74 #define UPS_LOADPCT     16   /* supports load percent */
76 #define UPSSTATUS_NONE     0
77 #define UPSSTATUS_OFF      1
78 #define UPSSTATUS_OL       2
79 #define UPSSTATUS_OB       4
80 #define UPSSTATUS_LB       8
81 #define UPSSTATUS_CAL     16
82 #define UPSSTATUS_RB      32  /*Replace Battery */
83 #define UPSSTATUS_UNKOWN  64
85 int server_port = PORT;
86 char *server_address = "127.0.0.1";
87 char *ups_name = NULL;
88 double warning_value = 0.0L;
89 double critical_value = 0.0L;
90 int check_warning_value = FALSE;
91 int check_critical_value = FALSE;
92 int check_variable = UPS_NONE;
93 int supported_options = UPS_NONE;
94 int status = UPSSTATUS_NONE;
96 double ups_utility_voltage = 0.0L;
97 double ups_battery_percent = 0.0L;
98 double ups_load_percent = 0.0L;
99 double ups_temperature = 0.0L;
100 char *ups_status = "N/A";
102 int determine_status (void);
103 int determine_supported_vars (void);
104 int get_ups_variable (const char *, char *, int);
106 int process_arguments (int, char **);
107 int validate_arguments (void);
108 void print_help (void);
109 void print_usage (void);
111 int
112 main (int argc, char **argv)
114         int result = STATE_OK;
115         char *message;
116         char temp_buffer[MAX_INPUT_BUFFER];
118         double ups_utility_deviation = 0.0L;
120         if (process_arguments (argc, argv) != OK)
121                 usage ("Invalid command arguments supplied\n");
123         /* initialize alarm signal handling */
124         signal (SIGALRM, socket_timeout_alarm_handler);
126         /* set socket timeout */
127         alarm (socket_timeout);
129         /* determine what variables the UPS supports */
130         if (determine_supported_vars () != OK)
131                 return STATE_CRITICAL;
133         /* get the ups status if possible */
134         if (supported_options & UPS_STATUS) {
136                 if (determine_status () != OK)
137                         return STATE_CRITICAL;
138                 asprintf (&ups_status, "");
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_UNKOWN) {
170                                 asprintf (&ups_status, "%s%s", ups_status, ", Unknown");
171                         }
172                 }
173         }
175         /* get the ups utility voltage if possible */
176         if (supported_options & UPS_UTILITY) {
178                 if (get_ups_variable ("UTILITY", temp_buffer, sizeof (temp_buffer)) != OK)
179                         return STATE_CRITICAL;
181                 ups_utility_voltage = atof (temp_buffer);
183                 if (ups_utility_voltage > 120.0)
184                         ups_utility_deviation = 120.0 - ups_utility_voltage;
185                 else
186                         ups_utility_deviation = ups_utility_voltage - 120.0;
188                 if (check_variable == UPS_UTILITY) {
189                         if (check_critical_value == TRUE
190                                         && ups_utility_deviation >= critical_value) result = STATE_CRITICAL;
191                         else if (check_warning_value == TRUE
192                                                          && ups_utility_deviation >= warning_value
193                                                          && result < STATE_WARNING) result = STATE_WARNING;
194                 }
195         }
197         /* get the ups battery percent if possible */
198         if (supported_options & UPS_BATTPCT) {
200                 if (get_ups_variable ("BATTPCT", temp_buffer, sizeof (temp_buffer)) != OK)
201                         return STATE_CRITICAL;
203                 ups_battery_percent = atof (temp_buffer);
205                 if (check_variable == UPS_BATTPCT) {
206                         if (check_critical_value == TRUE
207                                         && ups_battery_percent <= critical_value) result = STATE_CRITICAL;
208                         else if (check_warning_value == TRUE
209                                                          && ups_battery_percent <= warning_value
210                                                          && result < STATE_WARNING) result = STATE_WARNING;
211                 }
212         }
214         /* get the ups load percent if possible */
215         if (supported_options & UPS_LOADPCT) {
217                 if (get_ups_variable ("LOADPCT", temp_buffer, sizeof (temp_buffer)) != OK)
218                         return STATE_CRITICAL;
220                 ups_load_percent = atof (temp_buffer);
222                 if (check_variable == UPS_LOADPCT) {
223                         if (check_critical_value == TRUE && ups_load_percent >= critical_value)
224                                 result = STATE_CRITICAL;
225                         else if (check_warning_value == TRUE
226                                                          && ups_load_percent >= warning_value && result < STATE_WARNING)
227                                 result = STATE_WARNING;
228                 }
229         }
231         /* get the ups temperature if possible */
232         if (supported_options & UPS_TEMP) {
234                 if (get_ups_variable ("UPSTEMP", temp_buffer, sizeof (temp_buffer)) != OK)
235                         return STATE_CRITICAL;
237                 ups_temperature = (atof (temp_buffer) * 1.8) + 32;
239                 if (check_variable == UPS_TEMP) {
240                         if (check_critical_value == TRUE && ups_temperature >= critical_value)
241                                 result = STATE_CRITICAL;
242                         else if (check_warning_value == TRUE && ups_temperature >= warning_value
243                                                          && result < STATE_WARNING)
244                                 result = STATE_WARNING;
245                 }
246         }
248         /* if the UPS does not support any options we are looking for, report an error */
249         if (supported_options == UPS_NONE)
250                 result = STATE_CRITICAL;
252         /* reset timeout */
253         alarm (0);
256         asprintf (&message, "UPS %s - ", (result == STATE_OK) ? "ok" : "problem");
258         if (supported_options & UPS_STATUS)
259                 asprintf (&message, "%sStatus=%s ", message, ups_status);
261         if (supported_options & UPS_UTILITY)
262                 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
264         if (supported_options & UPS_BATTPCT)
265                 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
267         if (supported_options & UPS_LOADPCT)
268                 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
270         if (supported_options & UPS_TEMP)
271                 asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
273         if (supported_options == UPS_NONE)
274                 asprintf (&message, "UPS does not support any available options\n");
276         printf ("%s\n", message);
278         return result;
283 /* determines what options are supported by the UPS */
284 int
285 determine_status (void)
287         char recv_buffer[MAX_INPUT_BUFFER];
288         char temp_buffer[MAX_INPUT_BUFFER];
289         char *ptr;
291         if (get_ups_variable ("STATUS", recv_buffer, sizeof (recv_buffer)) !=
292                         STATE_OK) {
293                 printf ("Invalid response received from hostn");
294                 return ERROR;
295         }
297         recv_buffer[strlen (recv_buffer) - 1] = 0;
299         strcpy (temp_buffer, recv_buffer);
300         for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
301                          ptr = (char *) strtok (NULL, " ")) {
302                 if (!strcmp (ptr, "OFF"))
303                         status |= UPSSTATUS_OFF;
304                 else if (!strcmp (ptr, "OL"))
305                         status |= UPSSTATUS_OL;
306                 else if (!strcmp (ptr, "OB"))
307                         status |= UPSSTATUS_OB;
308                 else if (!strcmp (ptr, "LB"))
309                         status |= UPSSTATUS_LB;
310                 else if (!strcmp (ptr, "CAL"))
311                         status |= UPSSTATUS_CAL;
312                 else if (!strcmp (ptr, "RB"))
313                         status |= UPSSTATUS_RB;
314                 else
315                         status |= UPSSTATUS_UNKOWN;
316         }
318         return OK;
322 /* determines what options are supported by the UPS */
323 int
324 determine_supported_vars (void)
326         char send_buffer[MAX_INPUT_BUFFER];
327         char recv_buffer[MAX_INPUT_BUFFER];
328         char temp_buffer[MAX_INPUT_BUFFER];
329         char *ptr;
332         /* get the list of variables that this UPS supports */
333         if (ups_name)
334                 sprintf (send_buffer, "LISTVARS %s\r\n", ups_name);
335         else
336                 sprintf (send_buffer, "LISTVARS\r\n");
337         if (process_tcp_request
338                         (server_address, server_port, send_buffer, recv_buffer,
339                          sizeof (recv_buffer)) != STATE_OK) {
340                 printf ("Invalid response received from host\n");
341                 return ERROR;
342         }
344         recv_buffer[strlen (recv_buffer) - 1] = 0;
346         if (ups_name)
347                 ptr = recv_buffer + 5 + strlen (ups_name) + 2;
348         else
349                 ptr = recv_buffer + 5;
351         strcpy (temp_buffer, recv_buffer);
353         for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
354                          ptr = (char *) strtok (NULL, " ")) {
355                 if (!strcmp (ptr, "UTILITY"))
356                         supported_options |= UPS_UTILITY;
357                 else if (!strcmp (ptr, "BATTPCT"))
358                         supported_options |= UPS_BATTPCT;
359                 else if (!strcmp (ptr, "LOADPCT"))
360                         supported_options |= UPS_LOADPCT;
361                 else if (!strcmp (ptr, "STATUS"))
362                         supported_options |= UPS_STATUS;
363                 else if (!strcmp (ptr, "UPSTEMP"))
364                         supported_options |= UPS_TEMP;
365         }
367         return OK;
371 /* gets a variable value for a specific UPS  */
372 int
373 get_ups_variable (const char *varname, char *buf, int buflen)
375         /*  char command[MAX_INPUT_BUFFER]; */
376         char temp_buffer[MAX_INPUT_BUFFER];
377         char send_buffer[MAX_INPUT_BUFFER];
378         char *ptr;
380         /* create the command string to send to the UPS daemon */
381         if (ups_name)
382                 sprintf (send_buffer, "REQ %s@%s\n", varname, ups_name);
383         else
384                 sprintf (send_buffer, "REQ %s\n", varname);
386         /* send the command to the daemon and get a response back */
387         if (process_tcp_request
388                         (server_address, server_port, send_buffer, temp_buffer,
389                          sizeof (temp_buffer)) != STATE_OK) {
390                 printf ("Invalid response received from host\n");
391                 return ERROR;
392         }
394         if (ups_name)
395                 ptr = temp_buffer + strlen (varname) + 5 + strlen (ups_name) + 1;
396         else
397                 ptr = temp_buffer + strlen (varname) + 5;
399         if (!strcmp (ptr, "NOT-SUPPORTED")) {
400                 printf ("Error: Variable '%s' is not supported\n", varname);
401                 return ERROR;
402         }
404         if (!strcmp (ptr, "DATA-STALE")) {
405                 printf ("Error: UPS data is stale\n");
406                 return ERROR;
407         }
409         if (!strcmp (ptr, "UNKNOWN-UPS")) {
410                 if (ups_name)
411                         printf ("Error: UPS '%s' is unknown\n", ups_name);
412                 else
413                         printf ("Error: UPS is unknown\n");
414                 return ERROR;
415         }
417         strncpy (buf, ptr, buflen - 1);
418         buf[buflen - 1] = 0;
420         return OK;
427 /* Command line: CHECK_UPS <host_address> [-u ups] [-p port] [-v variable] 
428                            [-wv warn_value] [-cv crit_value] [-to to_sec] */
431 /* process command-line arguments */
432 int
433 process_arguments (int argc, char **argv)
435         int c;
437         int option_index = 0;
438         static struct option long_options[] = {
439                 {"hostname", required_argument, 0, 'H'},
440                 {"ups", required_argument, 0, 'u'},
441                 {"port", required_argument, 0, 'p'},
442                 {"critical", required_argument, 0, 'c'},
443                 {"warning", required_argument, 0, 'w'},
444                 {"timeout", required_argument, 0, 't'},
445                 {"variable", required_argument, 0, 'v'},
446                 {"version", no_argument, 0, 'V'},
447                 {"help", no_argument, 0, 'h'},
448                 {0, 0, 0, 0}
449         };
451         if (argc < 2)
452                 return ERROR;
454         for (c = 1; c < argc; c++) {
455                 if (strcmp ("-to", argv[c]) == 0)
456                         strcpy (argv[c], "-t");
457                 else if (strcmp ("-wt", argv[c]) == 0)
458                         strcpy (argv[c], "-w");
459                 else if (strcmp ("-ct", argv[c]) == 0)
460                         strcpy (argv[c], "-c");
461         }
463         while (1) {
464                 c = getopt_long (argc, argv, "hVH:u:p:v:c:w:t:", long_options,
465                                                                          &option_index);
467                 if (c == -1 || c == EOF)
468                         break;
470                 switch (c) {
471                 case '?':                                                                       /* help */
472                         usage3 ("Unknown option", optopt);
473                 case 'H':                                                                       /* hostname */
474                         if (is_host (optarg)) {
475                                 server_address = optarg;
476                         }
477                         else {
478                                 usage2 ("Invalid host name", optarg);
479                         }
480                         break;
481                 case 'u':                                                                       /* ups name */
482                         ups_name = optarg;
483                         break;
484                 case 'p':                                                                       /* port */
485                         if (is_intpos (optarg)) {
486                                 server_port = atoi (optarg);
487                         }
488                         else {
489                                 usage2 ("Server port must be a positive integer", optarg);
490                         }
491                         break;
492                 case 'c':                                                                       /* critical time threshold */
493                         if (is_intnonneg (optarg)) {
494                                 critical_value = atoi (optarg);
495                                 check_critical_value = TRUE;
496                         }
497                         else {
498                                 usage2 ("Critical time must be a nonnegative integer", optarg);
499                         }
500                         break;
501                 case 'w':                                                                       /* warning time threshold */
502                         if (is_intnonneg (optarg)) {
503                                 warning_value = atoi (optarg);
504                                 check_warning_value = TRUE;
505                         }
506                         else {
507                                 usage2 ("Warning time must be a nonnegative integer", optarg);
508                         }
509                         break;
510                 case 'v':                                                                       /* variable */
511                         if (!strcmp (optarg, "LINE"))
512                                 check_variable = UPS_UTILITY;
513                         else if (!strcmp (optarg, "TEMP"))
514                                 check_variable = UPS_TEMP;
515                         else if (!strcmp (optarg, "BATTPCT"))
516                                 check_variable = UPS_BATTPCT;
517                         else if (!strcmp (optarg, "LOADPCT"))
518                                 check_variable = UPS_LOADPCT;
519                         else
520                                 usage2 ("Unrecognized UPS variable", optarg);
521                         break;
522                 case 't':                                                                       /* timeout */
523                         if (is_intnonneg (optarg)) {
524                                 socket_timeout = atoi (optarg);
525                         }
526                         else {
527                                 usage ("Time interval must be a nonnegative integer\n");
528                         }
529                         break;
530                 case 'V':                                                                       /* version */
531                         print_revision (progname, "$Revision$");
532                         exit (STATE_OK);
533                 case 'h':                                                                       /* help */
534                         print_help ();
535                         exit (STATE_OK);
536                 }
537         }
540         if (server_address == NULL && argc > optind) {
541                 if (is_host (argv[optind]))
542                         server_address = argv[optind++];
543                 else
544                         usage ("Invalid host name");
545         }
547         return validate_arguments();
554 int
555 validate_arguments (void)
557         return OK;
564 void
565 print_help (void)
567         print_revision (progname, "$Revision$");
568         printf
569                 ("Copyright (c) 2000 Tom Shields/Karl DeBisschop\n\n"
570                  "This plugin tests the UPS service on the specified host.\n"
571                  "Newtork UPS Tools for www.exploits.org must be running for this plugin to work.\n\n");
572         print_usage ();
573         printf
574                 ("\nOptions:\n"
575                  " -H, --hostname=STRING or IPADDRESS\n"
576                  "   Check server on the indicated host\n"
577                  " -p, --port=INTEGER\n"
578                  "   Make connection on the indicated port (default: %d)\n"
579                  " -u, --ups=STRING\n"
580                  "   Name of UPS\n"
581                  " -w, --warning=INTEGER\n"
582                  "   Seconds necessary to result in a warning status\n"
583                  " -c, --critical=INTEGER\n"
584                  "   Seconds necessary to result in a critical status\n"
585                  " -t, --timeout=INTEGER\n"
586                  "   Seconds before connection attempt times out (default: %d)\n"
587                  " -v, --verbose\n"
588                  "   Print extra information (command-line use only)\n"
589                  " -h, --help\n"
590                  "   Print detailed help screen\n"
591                  " -V, --version\n"
592                  "   Print version information\n\n", PORT, DEFAULT_SOCKET_TIMEOUT);
593         support ();
600 void
601 print_usage (void)
603         printf
604                 ("Usage: %s -H host [-e expect] [-p port] [-w warn] [-c crit]\n"
605                  "            [-t timeout] [-v]\n"
606                  "       %s --help\n"
607                  "       %s --version\n", progname, progname, progname);