Code

No floorf on Solaris 9 (Jon Vandegrift - 1374705)
[nagiosplug.git] / plugins / check_ups.c
1 /******************************************************************************
3  check_ups
5  Program: Network UPS Tools plugin for Nagios
6  License: GPL
7  Copyright (c) 2000 Tom Shields
8                2004 Alain Richard <alain.richard@equation.fr>
9                2004 Arnaud Quette <arnaud.quette@mgeups.com>
11  
12  This program is free software; you can redistribute it and/or modify
13  it under the terms of the GNU General Public License as published by
14  the Free Software Foundation; either version 2 of the License, or (at
15  your option) any later version.
17  This program is distributed in the hope that it will be useful, but
18  WITHOUT ANY WARRANTY; without even the implied warranty of
19  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
20  General Public License for more details.
22  You should have received a copy of the GNU General Public License
23  along with this program; if not, write to the Free Software
24  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
26  $Id$
27  
28 ******************************************************************************/
30 const char *progname = "check_ups";
31 const char *revision = "$Revision$";
32 const char *copyright = "2000-2004";
33 const char *email = "nagiosplug-devel@lists.sourceforge.net";
35 #include "common.h"
36 #include "netutils.h"
37 #include "utils.h"
39 enum {
40         PORT = 3493
41 };
43 #define CHECK_NONE       0
45 #define UPS_NONE     0   /* no supported options */
46 #define UPS_UTILITY  1   /* supports utility line voltage */
47 #define UPS_BATTPCT  2   /* supports percent battery remaining */
48 #define UPS_STATUS   4   /* supports UPS status */
49 #define UPS_TEMP     8   /* supports UPS temperature */
50 #define UPS_LOADPCT     16   /* supports load percent */
52 #define UPSSTATUS_NONE       0
53 #define UPSSTATUS_OFF        1
54 #define UPSSTATUS_OL         2
55 #define UPSSTATUS_OB         4
56 #define UPSSTATUS_LB         8
57 #define UPSSTATUS_CAL       16
58 #define UPSSTATUS_RB        32  /*Replace Battery */
59 #define UPSSTATUS_BYPASS    64
60 #define UPSSTATUS_OVER     128
61 #define UPSSTATUS_TRIM     256
62 #define UPSSTATUS_BOOST    512
63 #define UPSSTATUS_CHRG    1024
64 #define UPSSTATUS_DISCHRG 2048
65 #define UPSSTATUS_UNKOWN  4096
67 enum { NOSUCHVAR = ERROR-1 };
69 int server_port = PORT;
70 char *server_address;
71 char *ups_name = NULL;
72 double warning_value = 0.0;
73 double critical_value = 0.0;
74 int check_warn = FALSE;
75 int check_crit = FALSE;
76 int check_variable = UPS_NONE;
77 int supported_options = UPS_NONE;
78 int status = UPSSTATUS_NONE;
80 double ups_utility_voltage = 0.0;
81 double ups_battery_percent = 0.0;
82 double ups_load_percent = 0.0;
83 double ups_temperature = 0.0;
84 char *ups_status;
85 int temp_output_c = 0;
87 int determine_status (void);
88 int get_ups_variable (const char *, char *, size_t);
90 int process_arguments (int, char **);
91 int validate_arguments (void);
92 void print_help (void);
93 void print_usage (void);
95 int
96 main (int argc, char **argv)
97 {
98         int result = STATE_UNKNOWN;
99         char *message;
100         char *data;
101         char *tunits;
102         char temp_buffer[MAX_INPUT_BUFFER];
103         double ups_utility_deviation = 0.0;
104         int res;
106         setlocale (LC_ALL, "");
107         bindtextdomain (PACKAGE, LOCALEDIR);
108         textdomain (PACKAGE);
110         ups_status = strdup ("N/A");
111         data = strdup ("");
112         message = strdup ("");
114         if (process_arguments (argc, argv) == ERROR)
115                 usage4 (_("Could not parse arguments"));
117         /* initialize alarm signal handling */
118         signal (SIGALRM, socket_timeout_alarm_handler);
120         /* set socket timeout */
121         alarm (socket_timeout);
123         /* get the ups status if possible */
124         if (determine_status () != OK)
125                 return STATE_CRITICAL;
126         if (supported_options & UPS_STATUS) {
128                 ups_status = strdup ("");
129                 result = STATE_OK;
131                 if (status & UPSSTATUS_OFF) {
132                         asprintf (&ups_status, "Off");
133                         result = STATE_CRITICAL;
134                 }
135                 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
136                                                  (UPSSTATUS_OB | UPSSTATUS_LB)) {
137                         asprintf (&ups_status, _("On Battery, Low Battery"));
138                         result = STATE_CRITICAL;
139                 }
140                 else {
141                         if (status & UPSSTATUS_OL) {
142                                 asprintf (&ups_status, "%s%s", ups_status, _("Online"));
143                         }
144                         if (status & UPSSTATUS_OB) {
145                                 asprintf (&ups_status, "%s%s", ups_status, _("On Battery"));
146                                 result = STATE_WARNING;
147                         }
148                         if (status & UPSSTATUS_LB) {
149                                 asprintf (&ups_status, "%s%s", ups_status, _(", Low Battery"));
150                                 result = STATE_WARNING;
151                         }
152                         if (status & UPSSTATUS_CAL) {
153                                 asprintf (&ups_status, "%s%s", ups_status, _(", Calibrating"));
154                         }
155                         if (status & UPSSTATUS_RB) {
156                                 asprintf (&ups_status, "%s%s", ups_status, _(", Replace Battery"));
157                                 result = STATE_WARNING;
158                         }
159                         if (status & UPSSTATUS_BYPASS) {
160                                 asprintf (&ups_status, "%s%s", ups_status, _(", On Bypass"));
161                         }
162                         if (status & UPSSTATUS_OVER) {
163                                 asprintf (&ups_status, "%s%s", ups_status, _(", Overload"));
164                         }
165                         if (status & UPSSTATUS_TRIM) {
166                                 asprintf (&ups_status, "%s%s", ups_status, _(", Trimming"));
167                         }
168                         if (status & UPSSTATUS_BOOST) {
169                                 asprintf (&ups_status, "%s%s", ups_status, _(", Boosting"));
170                         }
171                         if (status & UPSSTATUS_CHRG) {
172                                 asprintf (&ups_status, "%s%s", ups_status, _(", Charging"));
173                         }
174                         if (status & UPSSTATUS_DISCHRG) {
175                                 asprintf (&ups_status, "%s%s", ups_status, _(", Discharging"));
176                         }
177                         if (status & UPSSTATUS_UNKOWN) {
178                                 asprintf (&ups_status, "%s%s", ups_status, _(", Unknown"));
179                         }
180                 }
181                 asprintf (&message, "%sStatus=%s ", message, ups_status);
182         }
184         /* get the ups utility voltage if possible */
185         res=get_ups_variable ("input.voltage", temp_buffer, sizeof (temp_buffer));
186         if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY;
187         else if (res != OK)
188                 return STATE_CRITICAL;
189         else {
190                 supported_options |= UPS_UTILITY;
192                 ups_utility_voltage = atof (temp_buffer);
193                 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
195                 if (ups_utility_voltage > 120.0)
196                         ups_utility_deviation = 120.0 - ups_utility_voltage;
197                 else
198                         ups_utility_deviation = ups_utility_voltage - 120.0;
200                 if (check_variable == UPS_UTILITY) {
201                         if (check_crit==TRUE && ups_utility_deviation>=critical_value) {
202                                 result = STATE_CRITICAL;
203                         }
204                         else if (check_warn==TRUE && ups_utility_deviation>=warning_value) {
205                                 result = max_state (result, STATE_WARNING);
206                         }
207                         asprintf (&data, "%s",
208                                   perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
209                                             check_warn, (long)(1000*warning_value),
210                                             check_crit, (long)(1000*critical_value),
211                                             TRUE, 0, FALSE, 0));
212                 } else {
213                         asprintf (&data, "%s",
214                                   perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
215                                             FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
216                 }
217         }
219         /* get the ups battery percent if possible */
220         res=get_ups_variable ("battery.charge", temp_buffer, sizeof (temp_buffer));
221         if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT;
222         else if ( res != OK)
223                 return STATE_CRITICAL;
224         else {
225                 supported_options |= UPS_BATTPCT;
226                 ups_battery_percent = atof (temp_buffer);
227                 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
229                 if (check_variable == UPS_BATTPCT) {
230                         if (check_crit==TRUE && ups_battery_percent <= critical_value) {
231                                 result = STATE_CRITICAL;
232                         }
233                         else if (check_warn==TRUE && ups_battery_percent<=warning_value) {
234                                 result = max_state (result, STATE_WARNING);
235                         }
236                         asprintf (&data, "%s %s", data,
237                                   perfdata ("battery", (long)ups_battery_percent, "%",
238                                             check_warn, (long)(1000*warning_value),
239                                             check_crit, (long)(1000*critical_value),
240                                             TRUE, 0, TRUE, 100));
241                 } else {
242                         asprintf (&data, "%s %s", data,
243                                   perfdata ("battery", (long)ups_battery_percent, "%",
244                                             FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
245                 }
246         }
248         /* get the ups load percent if possible */
249         res=get_ups_variable ("ups.load", temp_buffer, sizeof (temp_buffer));
250         if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT;
251         else if ( res != OK)
252                 return STATE_CRITICAL;
253         else {
254                 supported_options |= UPS_LOADPCT;
255                 ups_load_percent = atof (temp_buffer);
256                 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
258                 if (check_variable == UPS_LOADPCT) {
259                         if (check_crit==TRUE && ups_load_percent>=critical_value) {
260                                 result = STATE_CRITICAL;
261                         }
262                         else if (check_warn==TRUE && ups_load_percent>=warning_value) {
263                                 result = max_state (result, STATE_WARNING);
264                         }
265                         asprintf (&data, "%s %s", data,
266                                   perfdata ("load", (long)ups_load_percent, "%",
267                                             check_warn, (long)(1000*warning_value),
268                                             check_crit, (long)(1000*critical_value),
269                                             TRUE, 0, TRUE, 100));
270                 } else {
271                         asprintf (&data, "%s %s", data,
272                                   perfdata ("load", (long)ups_load_percent, "%",
273                                             FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
274                 }
275         }
277         /* get the ups temperature if possible */
278         res=get_ups_variable ("ups.temperature", temp_buffer, sizeof (temp_buffer));
279         if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP;
280         else if ( res != OK)
281                 return STATE_CRITICAL;
282         else {
283                 supported_options |= UPS_TEMP;
284                 if (temp_output_c) {
285                   tunits="degC";
286                   ups_temperature = atof (temp_buffer);
287                   asprintf (&message, "%sTemp=%3.1fC", message, ups_temperature);
288                 }
289                 else {
290                   tunits="degF";
291                   ups_temperature = (atof (temp_buffer) * 1.8) + 32;
292                   asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
293                 }
295                 if (check_variable == UPS_TEMP) {
296                         if (check_crit==TRUE && ups_temperature>=critical_value) {
297                                 result = STATE_CRITICAL;
298                         }
299                         else if (check_warn == TRUE && ups_temperature>=warning_value) {
300                                 result = max_state (result, STATE_WARNING);
301                         }
302                         asprintf (&data, "%s %s", data,
303                                   perfdata ("temp", (long)ups_temperature, tunits,
304                                             check_warn, (long)(1000*warning_value),
305                                             check_crit, (long)(1000*critical_value),
306                                             TRUE, 0, FALSE, 0));
307                 } else {
308                         asprintf (&data, "%s %s", data,
309                                   perfdata ("temp", (long)ups_temperature, tunits,
310                                             FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
311                 }
312         }
314         /* if the UPS does not support any options we are looking for, report an error */
315         if (supported_options == UPS_NONE) {
316                 result = STATE_CRITICAL;
317                 asprintf (&message, _("UPS does not support any available options\n"));
318         }
320         /* reset timeout */
321         alarm (0);
323         printf ("UPS %s - %s|%s\n", state_text(result), message, data);
324         return result;
329 /* determines what options are supported by the UPS */
330 int
331 determine_status (void)
333         char recv_buffer[MAX_INPUT_BUFFER];
334         char temp_buffer[MAX_INPUT_BUFFER];
335         char *ptr;
336         int res;
338         res=get_ups_variable ("ups.status", recv_buffer, sizeof (recv_buffer));
339         if (res == NOSUCHVAR) return OK;
340         if (res != STATE_OK) {
341                 printf (_("Invalid response received from host\n"));
342                 return ERROR;
343         }
345         supported_options |= UPS_STATUS;
347         strcpy (temp_buffer, recv_buffer);
348         for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
349                          ptr = (char *) strtok (NULL, " ")) {
350                 if (!strcmp (ptr, "OFF"))
351                         status |= UPSSTATUS_OFF;
352                 else if (!strcmp (ptr, "OL"))
353                         status |= UPSSTATUS_OL;
354                 else if (!strcmp (ptr, "OB"))
355                         status |= UPSSTATUS_OB;
356                 else if (!strcmp (ptr, "LB"))
357                         status |= UPSSTATUS_LB;
358                 else if (!strcmp (ptr, "CAL"))
359                         status |= UPSSTATUS_CAL;
360                 else if (!strcmp (ptr, "RB"))
361                         status |= UPSSTATUS_RB;
362                 else if (!strcmp (ptr, "BYPASS"))
363                         status |= UPSSTATUS_BYPASS;
364                 else if (!strcmp (ptr, "OVER"))
365                         status |= UPSSTATUS_OVER;
366                 else if (!strcmp (ptr, "TRIM"))
367                         status |= UPSSTATUS_TRIM;
368                 else if (!strcmp (ptr, "BOOST"))
369                         status |= UPSSTATUS_BOOST;
370                 else if (!strcmp (ptr, "CHRG"))
371                         status |= UPSSTATUS_CHRG;
372                 else if (!strcmp (ptr, "DISCHRG"))
373                         status |= UPSSTATUS_DISCHRG;
374                 else
375                         status |= UPSSTATUS_UNKOWN;
376         }
378         return OK;
382 /* gets a variable value for a specific UPS  */
383 int
384 get_ups_variable (const char *varname, char *buf, size_t buflen)
386         /*  char command[MAX_INPUT_BUFFER]; */
387         char temp_buffer[MAX_INPUT_BUFFER];
388         char send_buffer[MAX_INPUT_BUFFER];
389         char *ptr;
390         int len;
392         *buf=0;
393         
394         /* create the command string to send to the UPS daemon */
395         sprintf (send_buffer, "GET VAR %s %s\n", ups_name, varname);
397         /* send the command to the daemon and get a response back */
398         if (process_tcp_request
399                         (server_address, server_port, send_buffer, temp_buffer,
400                          sizeof (temp_buffer)) != STATE_OK) {
401                 printf (_("Invalid response received from host\n"));
402                 return ERROR;
403         }
405         ptr = temp_buffer;
406         len = strlen(ptr);
407         if (len > 0 && ptr[len-1] == '\n') ptr[len-1]=0;
408         if (strcmp (ptr, "ERR UNKNOWN-UPS") == 0) {
409                 printf (_("CRITICAL - no such ups '%s' on that host\n"), ups_name);
410                 return ERROR;
411         }
413         if (strcmp (ptr, "ERR VAR-NOT-SUPPORTED") == 0) {
414                 /*printf ("Error: Variable '%s' is not supported\n", varname);*/
415                 return NOSUCHVAR;
416         }
418         if (strcmp (ptr, "ERR DATA-STALE") == 0) {
419                 printf (_("CRITICAL - UPS data is stale\n"));
420                 return ERROR;
421         }
423         if (strncmp (ptr, "ERR", 3) == 0) {
424                 printf (_("Unknown error: %s\n"), ptr);
425                 return ERROR;
426         }
428         ptr = temp_buffer + strlen (varname) + strlen (ups_name) + 6;
429         len = strlen(ptr);
430         if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
431                 printf (_("Error: unable to parse variable\n"));
432                 return ERROR;
433         }
434         strncpy (buf, ptr+1, len - 2);
435         buf[len - 2] = 0;
437         return OK;
441 /* Command line: CHECK_UPS -H <host_address> -u ups [-p port] [-v variable] 
442                            [-wv warn_value] [-cv crit_value] [-to to_sec] */
445 /* process command-line arguments */
446 int
447 process_arguments (int argc, char **argv)
449         int c;
451         int option = 0;
452         static struct option longopts[] = {
453                 {"hostname", required_argument, 0, 'H'},
454                 {"ups", required_argument, 0, 'u'},
455                 {"port", required_argument, 0, 'p'},
456                 {"critical", required_argument, 0, 'c'},
457                 {"warning", required_argument, 0, 'w'},
458                 {"timeout", required_argument, 0, 't'},
459                 {"temperature", no_argument, 0, 'T'},
460                 {"variable", required_argument, 0, 'v'},
461                 {"version", no_argument, 0, 'V'},
462                 {"help", no_argument, 0, 'h'},
463                 {0, 0, 0, 0}
464         };
466         if (argc < 2)
467                 return ERROR;
469         for (c = 1; c < argc; c++) {
470                 if (strcmp ("-to", argv[c]) == 0)
471                         strcpy (argv[c], "-t");
472                 else if (strcmp ("-wt", argv[c]) == 0)
473                         strcpy (argv[c], "-w");
474                 else if (strcmp ("-ct", argv[c]) == 0)
475                         strcpy (argv[c], "-c");
476         }
478         while (1) {
479                 c = getopt_long (argc, argv, "hVTH:u:p:v:c:w:t:", longopts,
480                                                                          &option);
482                 if (c == -1 || c == EOF)
483                         break;
485                 switch (c) {
486                 case '?':                                                                       /* help */
487                         usage2 (_("Unknown argument"), optarg);
488                 case 'H':                                                                       /* hostname */
489                         if (is_host (optarg)) {
490                                 server_address = optarg;
491                         }
492                         else {
493                                 usage2 (_("Invalid hostname/address"), optarg);
494                         }
495                         break;
496                 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */ 
497                         temp_output_c = 1;
498                         break;
499                 case 'u':                                                                       /* ups name */
500                         ups_name = optarg;
501                         break;
502                 case 'p':                                                                       /* port */
503                         if (is_intpos (optarg)) {
504                                 server_port = atoi (optarg);
505                         }
506                         else {
507                                 usage2 (_("Port must be a positive integer"), optarg);
508                         }
509                         break;
510                 case 'c':                                                                       /* critical time threshold */
511                         if (is_intnonneg (optarg)) {
512                                 critical_value = atoi (optarg);
513                                 check_crit = TRUE;
514                         }
515                         else {
516                                 usage2 (_("Critical time must be a positive integer"), optarg);
517                         }
518                         break;
519                 case 'w':                                                                       /* warning time threshold */
520                         if (is_intnonneg (optarg)) {
521                                 warning_value = atoi (optarg);
522                                 check_warn = TRUE;
523                         }
524                         else {
525                                 usage2 (_("Warning time must be a positive integer"), optarg);
526                         }
527                         break;
528                 case 'v':                                                                       /* variable */
529                         if (!strcmp (optarg, "LINE"))
530                                 check_variable = UPS_UTILITY;
531                         else if (!strcmp (optarg, "TEMP"))
532                                 check_variable = UPS_TEMP;
533                         else if (!strcmp (optarg, "BATTPCT"))
534                                 check_variable = UPS_BATTPCT;
535                         else if (!strcmp (optarg, "LOADPCT"))
536                                 check_variable = UPS_LOADPCT;
537                         else
538                                 usage2 (_("Unrecognized UPS variable"), optarg);
539                         break;
540                 case 't':                                                                       /* timeout */
541                         if (is_intnonneg (optarg)) {
542                                 socket_timeout = atoi (optarg);
543                         }
544                         else {
545                                 usage4 (_("Timeout interval must be a positive integer"));
546                         }
547                         break;
548                 case 'V':                                                                       /* version */
549                         print_revision (progname, revision);
550                         exit (STATE_OK);
551                 case 'h':                                                                       /* help */
552                         print_help ();
553                         exit (STATE_OK);
554                 }
555         }
558         if (server_address == NULL && argc > optind) {
559                 if (is_host (argv[optind]))
560                         server_address = argv[optind++];
561                 else
562                         usage2 (_("Invalid hostname/address"), optarg);
563         }
565         if (server_address == NULL)
566                 server_address = strdup("127.0.0.1");
568         return validate_arguments();
572 int
573 validate_arguments (void)
575         if (! ups_name) {
576                 printf (_("Error : no ups indicated\n"));
577                 return ERROR;
578         }
579         return OK;
583 void
584 print_help (void)
586         char *myport;
587         asprintf (&myport, "%d", PORT);
589         print_revision (progname, revision);
591         printf ("Copyright (c) 2000 Tom Shields");
592         printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
593         printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
594         printf (COPYRIGHT, copyright, email);
596         printf (_("This plugin tests the UPS service on the specified host.\n\
597 Network UPS Tools from www.networkupstools.org must be running for this\n\
598 plugin to work.\n\n"));
600         print_usage ();
602         printf (_(UT_HELP_VRSN));
604         printf (_(UT_HOST_PORT), 'p', myport);
606         printf (_("\
607  -u, --ups=STRING\n\
608     Name of UPS\n"));
610         printf (_("\
611  -T, --temperature\n\
612     Output of temperatures in Celsius\n"));
614         printf (_(UT_WARN_CRIT));
616         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
618         printf (_(UT_VERBOSE));
620         printf (_("\
621 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
622 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
623 plugin will return an OK state. If the battery is on it will return a WARNING\n\
624 state.  If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
625 state.\n\n"));
627         printf (_("\
628 You may also specify a variable to check [such as temperature, utility voltage,\n\
629 battery load, etc.]  as well as warning and critical thresholds for the value of\n\
630 that variable.  If the remote host has multiple UPS that are being monitored you\n\
631 will have to use the [ups] option to specify which UPS to check.\n\n"));
633         printf (_("Notes:\n\n\
634 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
635 Smart UPS Tools be installed on the remote host.  If you do not have the\n\
636 package installed on your system, you can download it from\n\
637 http://www.networkupstools.org\n\n"));
639         printf (_(UT_SUPPORT));
643 void
644 print_usage (void)
646         printf ("\
647 Usage: %s -H host -u ups [-p port] [-v variable]\n\
648                   [-wv warn_value] [-cv crit_value] [-to to_sec] [-T]\n", progname);