Code

use fperfdata
[nagiosplug.git] / plugins / check_ups.c
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;
280 /* determines what options are supported by the UPS */
281 int
282 determine_status (void)
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;
319 /* determines what options are supported by the UPS */
320 int
321 determine_supported_vars (void)
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;
368 /* gets a variable value for a specific UPS  */
369 int
370 get_ups_variable (const char *varname, char *buf, size_t buflen)
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;
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)
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();
554 int
555 validate_arguments (void)
557         return OK;
564 \f
565 void
566 print_help (void)
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));
621 void
622 print_usage (void)
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);