Code

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