Code

Fix to parsing of uptime (Ronald Tin - 1254656)
[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 temp_buffer[MAX_INPUT_BUFFER];
102         double ups_utility_deviation = 0.0;
103         int res;
105         setlocale (LC_ALL, "");
106         bindtextdomain (PACKAGE, LOCALEDIR);
107         textdomain (PACKAGE);
109         ups_status = strdup ("N/A");
110         data = strdup ("");
111         message = strdup ("");
113         if (process_arguments (argc, argv) == ERROR)
114                 usage4 (_("Could not parse arguments"));
116         /* initialize alarm signal handling */
117         signal (SIGALRM, socket_timeout_alarm_handler);
119         /* set socket timeout */
120         alarm (socket_timeout);
122         /* get the ups status if possible */
123         if (determine_status () != OK)
124                 return STATE_CRITICAL;
125         if (supported_options & UPS_STATUS) {
127                 ups_status = strdup ("");
128                 result = STATE_OK;
130                 if (status & UPSSTATUS_OFF) {
131                         asprintf (&ups_status, "Off");
132                         result = STATE_CRITICAL;
133                 }
134                 else if ((status & (UPSSTATUS_OB | UPSSTATUS_LB)) ==
135                                                  (UPSSTATUS_OB | UPSSTATUS_LB)) {
136                         asprintf (&ups_status, _("On Battery, Low Battery"));
137                         result = STATE_CRITICAL;
138                 }
139                 else {
140                         if (status & UPSSTATUS_OL) {
141                                 asprintf (&ups_status, "%s%s", ups_status, _("Online"));
142                         }
143                         if (status & UPSSTATUS_OB) {
144                                 asprintf (&ups_status, "%s%s", ups_status, _("On Battery"));
145                                 result = STATE_WARNING;
146                         }
147                         if (status & UPSSTATUS_LB) {
148                                 asprintf (&ups_status, "%s%s", ups_status, _(", Low Battery"));
149                                 result = STATE_WARNING;
150                         }
151                         if (status & UPSSTATUS_CAL) {
152                                 asprintf (&ups_status, "%s%s", ups_status, _(", Calibrating"));
153                         }
154                         if (status & UPSSTATUS_RB) {
155                                 asprintf (&ups_status, "%s%s", ups_status, _(", Replace Battery"));
156                                 result = STATE_WARNING;
157                         }
158                         if (status & UPSSTATUS_BYPASS) {
159                                 asprintf (&ups_status, "%s%s", ups_status, _(", On Bypass"));
160                         }
161                         if (status & UPSSTATUS_OVER) {
162                                 asprintf (&ups_status, "%s%s", ups_status, _(", Overload"));
163                         }
164                         if (status & UPSSTATUS_TRIM) {
165                                 asprintf (&ups_status, "%s%s", ups_status, _(", Trimming"));
166                         }
167                         if (status & UPSSTATUS_BOOST) {
168                                 asprintf (&ups_status, "%s%s", ups_status, _(", Boosting"));
169                         }
170                         if (status & UPSSTATUS_CHRG) {
171                                 asprintf (&ups_status, "%s%s", ups_status, _(", Charging"));
172                         }
173                         if (status & UPSSTATUS_DISCHRG) {
174                                 asprintf (&ups_status, "%s%s", ups_status, _(", Discharging"));
175                         }
176                         if (status & UPSSTATUS_UNKOWN) {
177                                 asprintf (&ups_status, "%s%s", ups_status, _(", Unknown"));
178                         }
179                 }
180                 asprintf (&message, "%sStatus=%s ", message, ups_status);
181         }
183         /* get the ups utility voltage if possible */
184         res=get_ups_variable ("input.voltage", temp_buffer, sizeof (temp_buffer));
185         if (res == NOSUCHVAR) supported_options &= ~UPS_UTILITY;
186         else if (res != OK)
187                 return STATE_CRITICAL;
188         else {
189                 supported_options |= UPS_UTILITY;
191                 ups_utility_voltage = atof (temp_buffer);
192                 asprintf (&message, "%sUtility=%3.1fV ", message, ups_utility_voltage);
194                 if (ups_utility_voltage > 120.0)
195                         ups_utility_deviation = 120.0 - ups_utility_voltage;
196                 else
197                         ups_utility_deviation = ups_utility_voltage - 120.0;
199                 if (check_variable == UPS_UTILITY) {
200                         if (check_crit==TRUE && ups_utility_deviation>=critical_value) {
201                                 result = STATE_CRITICAL;
202                         }
203                         else if (check_warn==TRUE && ups_utility_deviation>=warning_value) {
204                                 result = max_state (result, STATE_WARNING);
205                         }
206                         asprintf (&data, "%s",
207                                   perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
208                                             check_warn, (long)(1000*warning_value),
209                                             check_crit, (long)(1000*critical_value),
210                                             TRUE, 0, FALSE, 0));
211                 } else {
212                         asprintf (&data, "%s",
213                                   perfdata ("voltage", (long)(1000*ups_utility_voltage), "mV",
214                                             FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
215                 }
216         }
218         /* get the ups battery percent if possible */
219         res=get_ups_variable ("battery.charge", temp_buffer, sizeof (temp_buffer));
220         if (res == NOSUCHVAR) supported_options &= ~UPS_BATTPCT;
221         else if ( res != OK)
222                 return STATE_CRITICAL;
223         else {
224                 supported_options |= UPS_BATTPCT;
225                 ups_battery_percent = atof (temp_buffer);
226                 asprintf (&message, "%sBatt=%3.1f%% ", message, ups_battery_percent);
228                 if (check_variable == UPS_BATTPCT) {
229                         if (check_crit==TRUE && ups_battery_percent <= critical_value) {
230                                 result = STATE_CRITICAL;
231                         }
232                         else if (check_warn==TRUE && ups_battery_percent<=warning_value) {
233                                 result = max_state (result, STATE_WARNING);
234                         }
235                         asprintf (&data, "%s %s", data,
236                                   perfdata ("battery", (long)ups_battery_percent, "%",
237                                             check_warn, (long)(1000*warning_value),
238                                             check_crit, (long)(1000*critical_value),
239                                             TRUE, 0, TRUE, 100));
240                 } else {
241                         asprintf (&data, "%s %s", data,
242                                   perfdata ("battery", (long)ups_battery_percent, "%",
243                                             FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
244                 }
245         }
247         /* get the ups load percent if possible */
248         res=get_ups_variable ("ups.load", temp_buffer, sizeof (temp_buffer));
249         if ( res == NOSUCHVAR ) supported_options &= ~UPS_LOADPCT;
250         else if ( res != OK)
251                 return STATE_CRITICAL;
252         else {
253                 supported_options |= UPS_LOADPCT;
254                 ups_load_percent = atof (temp_buffer);
255                 asprintf (&message, "%sLoad=%3.1f%% ", message, ups_load_percent);
257                 if (check_variable == UPS_LOADPCT) {
258                         if (check_crit==TRUE && ups_load_percent>=critical_value) {
259                                 result = STATE_CRITICAL;
260                         }
261                         else if (check_warn==TRUE && ups_load_percent>=warning_value) {
262                                 result = max_state (result, STATE_WARNING);
263                         }
264                         asprintf (&data, "%s %s", data,
265                                   perfdata ("load", (long)ups_load_percent, "%",
266                                             check_warn, (long)(1000*warning_value),
267                                             check_crit, (long)(1000*critical_value),
268                                             TRUE, 0, TRUE, 100));
269                 } else {
270                         asprintf (&data, "%s %s", data,
271                                   perfdata ("load", (long)ups_load_percent, "%",
272                                             FALSE, 0, FALSE, 0, TRUE, 0, TRUE, 100));
273                 }
274         }
276         /* get the ups temperature if possible */
277         res=get_ups_variable ("ups.temperature", temp_buffer, sizeof (temp_buffer));
278         if ( res == NOSUCHVAR ) supported_options &= ~UPS_TEMP;
279         else if ( res != OK)
280                 return STATE_CRITICAL;
281         else {
282                 supported_options |= UPS_TEMP;
283                 if (temp_output_c) {
284                   ups_temperature = atof (temp_buffer);
285                   asprintf (&message, "%sTemp=%3.1fC", message, ups_temperature);
286                 }
287                 else {
288                   ups_temperature = (atof (temp_buffer) * 1.8) + 32;
289                   asprintf (&message, "%sTemp=%3.1fF", message, ups_temperature);
290                 }
292                 if (check_variable == UPS_TEMP) {
293                         if (check_crit==TRUE && ups_temperature>=critical_value) {
294                                 result = STATE_CRITICAL;
295                         }
296                         else if (check_warn == TRUE && ups_temperature>=warning_value) {
297                                 result = max_state (result, STATE_WARNING);
298                         }
299                         asprintf (&data, "%s %s", data,
300                                   perfdata ("temp", (long)ups_temperature, "degF",
301                                             check_warn, (long)(1000*warning_value),
302                                             check_crit, (long)(1000*critical_value),
303                                             TRUE, 0, FALSE, 0));
304                 } else {
305                         asprintf (&data, "%s %s", data,
306                                   perfdata ("temp", (long)ups_temperature, "degF",
307                                             FALSE, 0, FALSE, 0, TRUE, 0, FALSE, 0));
308                 }
309         }
311         /* if the UPS does not support any options we are looking for, report an error */
312         if (supported_options == UPS_NONE) {
313                 result = STATE_CRITICAL;
314                 asprintf (&message, _("UPS does not support any available options\n"));
315         }
317         /* reset timeout */
318         alarm (0);
320         printf ("UPS %s - %s|%s\n", state_text(result), message, data);
321         return result;
326 /* determines what options are supported by the UPS */
327 int
328 determine_status (void)
330         char recv_buffer[MAX_INPUT_BUFFER];
331         char temp_buffer[MAX_INPUT_BUFFER];
332         char *ptr;
333         int res;
335         res=get_ups_variable ("ups.status", recv_buffer, sizeof (recv_buffer));
336         if (res == NOSUCHVAR) return OK;
337         if (res != STATE_OK) {
338                 printf (_("Invalid response received from host\n"));
339                 return ERROR;
340         }
342         supported_options |= UPS_STATUS;
344         strcpy (temp_buffer, recv_buffer);
345         for (ptr = (char *) strtok (temp_buffer, " "); ptr != NULL;
346                          ptr = (char *) strtok (NULL, " ")) {
347                 if (!strcmp (ptr, "OFF"))
348                         status |= UPSSTATUS_OFF;
349                 else if (!strcmp (ptr, "OL"))
350                         status |= UPSSTATUS_OL;
351                 else if (!strcmp (ptr, "OB"))
352                         status |= UPSSTATUS_OB;
353                 else if (!strcmp (ptr, "LB"))
354                         status |= UPSSTATUS_LB;
355                 else if (!strcmp (ptr, "CAL"))
356                         status |= UPSSTATUS_CAL;
357                 else if (!strcmp (ptr, "RB"))
358                         status |= UPSSTATUS_RB;
359                 else if (!strcmp (ptr, "BYPASS"))
360                         status |= UPSSTATUS_BYPASS;
361                 else if (!strcmp (ptr, "OVER"))
362                         status |= UPSSTATUS_OVER;
363                 else if (!strcmp (ptr, "TRIM"))
364                         status |= UPSSTATUS_TRIM;
365                 else if (!strcmp (ptr, "BOOST"))
366                         status |= UPSSTATUS_BOOST;
367                 else if (!strcmp (ptr, "CHRG"))
368                         status |= UPSSTATUS_CHRG;
369                 else if (!strcmp (ptr, "DISCHRG"))
370                         status |= UPSSTATUS_DISCHRG;
371                 else
372                         status |= UPSSTATUS_UNKOWN;
373         }
375         return OK;
379 /* gets a variable value for a specific UPS  */
380 int
381 get_ups_variable (const char *varname, char *buf, size_t buflen)
383         /*  char command[MAX_INPUT_BUFFER]; */
384         char temp_buffer[MAX_INPUT_BUFFER];
385         char send_buffer[MAX_INPUT_BUFFER];
386         char *ptr;
387         int len;
389         *buf=0;
390         
391         /* create the command string to send to the UPS daemon */
392         sprintf (send_buffer, "GET VAR %s %s\n", ups_name, varname);
394         /* send the command to the daemon and get a response back */
395         if (process_tcp_request
396                         (server_address, server_port, send_buffer, temp_buffer,
397                          sizeof (temp_buffer)) != STATE_OK) {
398                 printf (_("Invalid response received from host\n"));
399                 return ERROR;
400         }
402         ptr = temp_buffer;
403         len = strlen(ptr);
404         if (len > 0 && ptr[len-1] == '\n') ptr[len-1]=0;
405         if (strcmp (ptr, "ERR UNKNOWN-UPS") == 0) {
406                 printf (_("CRITICAL - no such ups '%s' on that host\n"), ups_name);
407                 return ERROR;
408         }
410         if (strcmp (ptr, "ERR VAR-NOT-SUPPORTED") == 0) {
411                 /*printf ("Error: Variable '%s' is not supported\n", varname);*/
412                 return NOSUCHVAR;
413         }
415         if (strcmp (ptr, "ERR DATA-STALE") == 0) {
416                 printf (_("CRITICAL - UPS data is stale\n"));
417                 return ERROR;
418         }
420         if (strncmp (ptr, "ERR", 3) == 0) {
421                 printf (_("Unknown error: %s\n"), ptr);
422                 return ERROR;
423         }
425         ptr = temp_buffer + strlen (varname) + strlen (ups_name) + 6;
426         len = strlen(ptr);
427         if (len < 2 || ptr[0] != '"' || ptr[len-1] != '"') {
428                 printf (_("Error: unable to parse variable\n"));
429                 return ERROR;
430         }
431         strncpy (buf, ptr+1, len - 2);
432         buf[len - 2] = 0;
434         return OK;
438 /* Command line: CHECK_UPS -H <host_address> -u ups [-p port] [-v variable] 
439                            [-wv warn_value] [-cv crit_value] [-to to_sec] */
442 /* process command-line arguments */
443 int
444 process_arguments (int argc, char **argv)
446         int c;
448         int option = 0;
449         static struct option longopts[] = {
450                 {"hostname", required_argument, 0, 'H'},
451                 {"ups", required_argument, 0, 'u'},
452                 {"port", required_argument, 0, 'p'},
453                 {"critical", required_argument, 0, 'c'},
454                 {"warning", required_argument, 0, 'w'},
455                 {"timeout", required_argument, 0, 't'},
456                 {"temperature", no_argument, 0, 'T'},
457                 {"variable", required_argument, 0, 'v'},
458                 {"version", no_argument, 0, 'V'},
459                 {"help", no_argument, 0, 'h'},
460                 {0, 0, 0, 0}
461         };
463         if (argc < 2)
464                 return ERROR;
466         for (c = 1; c < argc; c++) {
467                 if (strcmp ("-to", argv[c]) == 0)
468                         strcpy (argv[c], "-t");
469                 else if (strcmp ("-wt", argv[c]) == 0)
470                         strcpy (argv[c], "-w");
471                 else if (strcmp ("-ct", argv[c]) == 0)
472                         strcpy (argv[c], "-c");
473         }
475         while (1) {
476                 c = getopt_long (argc, argv, "hVTH:u:p:v:c:w:t:", longopts,
477                                                                          &option);
479                 if (c == -1 || c == EOF)
480                         break;
482                 switch (c) {
483                 case '?':                                                                       /* help */
484                         usage2 (_("Unknown argument"), optarg);
485                 case 'H':                                                                       /* hostname */
486                         if (is_host (optarg)) {
487                                 server_address = optarg;
488                         }
489                         else {
490                                 usage2 (_("Invalid hostname/address"), optarg);
491                         }
492                         break;
493                 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */ 
494                         temp_output_c = 1;
495                         break;
496                 case 'u':                                                                       /* ups name */
497                         ups_name = optarg;
498                         break;
499                 case 'p':                                                                       /* port */
500                         if (is_intpos (optarg)) {
501                                 server_port = atoi (optarg);
502                         }
503                         else {
504                                 usage2 (_("Port must be a positive integer"), optarg);
505                         }
506                         break;
507                 case 'c':                                                                       /* critical time threshold */
508                         if (is_intnonneg (optarg)) {
509                                 critical_value = atoi (optarg);
510                                 check_crit = TRUE;
511                         }
512                         else {
513                                 usage2 (_("Critical time must be a positive integer"), optarg);
514                         }
515                         break;
516                 case 'w':                                                                       /* warning time threshold */
517                         if (is_intnonneg (optarg)) {
518                                 warning_value = atoi (optarg);
519                                 check_warn = TRUE;
520                         }
521                         else {
522                                 usage2 (_("Warning time must be a positive integer"), optarg);
523                         }
524                         break;
525                 case 'v':                                                                       /* variable */
526                         if (!strcmp (optarg, "LINE"))
527                                 check_variable = UPS_UTILITY;
528                         else if (!strcmp (optarg, "TEMP"))
529                                 check_variable = UPS_TEMP;
530                         else if (!strcmp (optarg, "BATTPCT"))
531                                 check_variable = UPS_BATTPCT;
532                         else if (!strcmp (optarg, "LOADPCT"))
533                                 check_variable = UPS_LOADPCT;
534                         else
535                                 usage2 (_("Unrecognized UPS variable"), optarg);
536                         break;
537                 case 't':                                                                       /* timeout */
538                         if (is_intnonneg (optarg)) {
539                                 socket_timeout = atoi (optarg);
540                         }
541                         else {
542                                 usage4 (_("Timeout interval must be a positive integer"));
543                         }
544                         break;
545                 case 'V':                                                                       /* version */
546                         print_revision (progname, revision);
547                         exit (STATE_OK);
548                 case 'h':                                                                       /* help */
549                         print_help ();
550                         exit (STATE_OK);
551                 }
552         }
555         if (server_address == NULL && argc > optind) {
556                 if (is_host (argv[optind]))
557                         server_address = argv[optind++];
558                 else
559                         usage2 (_("Invalid hostname/address"), optarg);
560         }
562         if (server_address == NULL)
563                 server_address = strdup("127.0.0.1");
565         return validate_arguments();
569 int
570 validate_arguments (void)
572         if (! ups_name) {
573                 printf (_("Error : no ups indicated\n"));
574                 return ERROR;
575         }
576         return OK;
580 void
581 print_help (void)
583         char *myport;
584         asprintf (&myport, "%d", PORT);
586         print_revision (progname, revision);
588         printf ("Copyright (c) 2000 Tom Shields");
589         printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
590         printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
591         printf (COPYRIGHT, copyright, email);
593         printf (_("This plugin tests the UPS service on the specified host.\n\
594 Network UPS Tools from www.networkupstools.org must be running for this\n\
595 plugin to work.\n\n"));
597         print_usage ();
599         printf (_(UT_HELP_VRSN));
601         printf (_(UT_HOST_PORT), 'p', myport);
603         printf (_("\
604  -u, --ups=STRING\n\
605     Name of UPS\n"));
607         printf (_("\
608  -T, --temperature\n\
609     Output of temperatures in Celsius\n"));
611         printf (_(UT_WARN_CRIT));
613         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
615         printf (_(UT_VERBOSE));
617         printf (_("\
618 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
619 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
620 plugin will return an OK state. If the battery is on it will return a WARNING\n\
621 state.  If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
622 state.\n\n"));
624         printf (_("\
625 You may also specify a variable to check [such as temperature, utility voltage,\n\
626 battery load, etc.]  as well as warning and critical thresholds for the value of\n\
627 that variable.  If the remote host has multiple UPS that are being monitored you\n\
628 will have to use the [ups] option to specify which UPS to check.\n\n"));
630         printf (_("Notes:\n\n\
631 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
632 Smart UPS Tools be installed on the remote host.  If you do not have the\n\
633 package installed on your system, you can download it from\n\
634 http://www.networkupstools.org\n\n"));
636         printf (_(UT_SUPPORT));
640 void
641 print_usage (void)
643         printf ("\
644 Usage: %s -H host -u ups [-p port] [-v variable]\n\
645                   [-wv warn_value] [-cv crit_value] [-to to_sec] [-T]\n", progname);