Code

print_help and print_usage() cleanup
[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) != TRUE)
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                         printf (_("%s: Unknown argument: %s\n\n"), progname, optarg);
485                         print_usage ();
486                         exit (STATE_UNKNOWN);
487                 case 'H':                                                                       /* hostname */
488                         if (is_host (optarg)) {
489                                 server_address = optarg;
490                         }
491                         else {
492                                 usage2 (_("Invalid hostname/address"), optarg);
493                         }
494                         break;
495                 case 'T': /* FIXME: to be improved (ie "-T C" for Celsius or "-T F" for Farenheit) */ 
496                         temp_output_c = 1;
497                         break;
498                 case 'u':                                                                       /* ups name */
499                         ups_name = optarg;
500                         break;
501                 case 'p':                                                                       /* port */
502                         if (is_intpos (optarg)) {
503                                 server_port = atoi (optarg);
504                         }
505                         else {
506                                 usage2 ("Port must be a positive integer", optarg);
507                         }
508                         break;
509                 case 'c':                                                                       /* critical time threshold */
510                         if (is_intnonneg (optarg)) {
511                                 critical_value = atoi (optarg);
512                                 check_crit = TRUE;
513                         }
514                         else {
515                                 usage2 ("Critical time must be a positive integer", optarg);
516                         }
517                         break;
518                 case 'w':                                                                       /* warning time threshold */
519                         if (is_intnonneg (optarg)) {
520                                 warning_value = atoi (optarg);
521                                 check_warn = TRUE;
522                         }
523                         else {
524                                 usage2 ("Warning time must be a positive integer", optarg);
525                         }
526                         break;
527                 case 'v':                                                                       /* variable */
528                         if (!strcmp (optarg, "LINE"))
529                                 check_variable = UPS_UTILITY;
530                         else if (!strcmp (optarg, "TEMP"))
531                                 check_variable = UPS_TEMP;
532                         else if (!strcmp (optarg, "BATTPCT"))
533                                 check_variable = UPS_BATTPCT;
534                         else if (!strcmp (optarg, "LOADPCT"))
535                                 check_variable = UPS_LOADPCT;
536                         else
537                                 usage2 ("Unrecognized UPS variable", optarg);
538                         break;
539                 case 't':                                                                       /* timeout */
540                         if (is_intnonneg (optarg)) {
541                                 socket_timeout = atoi (optarg);
542                         }
543                         else {
544                                 usage ("Time interval must be a positive integer\n");
545                         }
546                         break;
547                 case 'V':                                                                       /* version */
548                         print_revision (progname, revision);
549                         exit (STATE_OK);
550                 case 'h':                                                                       /* help */
551                         print_help ();
552                         exit (STATE_OK);
553                 }
554         }
557         if (server_address == NULL && argc > optind) {
558                 if (is_host (argv[optind]))
559                         server_address = argv[optind++];
560                 else
561                         usage2 (_("Invalid hostname/address"), optarg);
562         }
564         if (server_address == NULL)
565                 server_address = strdup("127.0.0.1");
567         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;
584 void
585 print_help (void)
587         char *myport;
588         asprintf (&myport, "%d", PORT);
590         print_revision (progname, revision);
592         printf ("Copyright (c) 2000 Tom Shields");
593         printf ("Copyright (c) 2004 Alain Richard <alain.richard@equation.fr>\n");
594         printf ("Copyright (c) 2004 Arnaud Quette <arnaud.quette@mgeups.com>\n");
595         printf (COPYRIGHT, copyright, email);
597         printf (_("This plugin tests the UPS service on the specified host.\n\
598 Network UPS Tools from www.networkupstools.org must be running for this\n\
599 plugin to work.\n\n"));
601         print_usage ();
603         printf (_(UT_HELP_VRSN));
605         printf (_(UT_HOST_PORT), 'p', myport);
607         printf (_("\
608  -u, --ups=STRING\n\
609     Name of UPS\n"));
611         printf (_("\
612  -T, --temperature\n\
613     Output of temperatures in Celsius\n"));
615         printf (_(UT_WARN_CRIT));
617         printf (_(UT_TIMEOUT), DEFAULT_SOCKET_TIMEOUT);
619         printf (_(UT_VERBOSE));
621         printf (_("\
622 This plugin attempts to determine the status of a UPS (Uninterruptible Power\n\
623 Supply) on a local or remote host. If the UPS is online or calibrating, the\n\
624 plugin will return an OK state. If the battery is on it will return a WARNING\n\
625 state.  If the UPS is off or has a low battery the plugin will return a CRITICAL\n\
626 state.\n\n"));
628         printf (_("\
629 You may also specify a variable to check [such as temperature, utility voltage,\n\
630 battery load, etc.]  as well as warning and critical thresholds for the value of\n\
631 that variable.  If the remote host has multiple UPS that are being monitored you\n\
632 will have to use the [ups] option to specify which UPS to check.\n\n"));
634         printf (_("Notes:\n\n\
635 This plugin requires that the UPSD daemon distributed with Russel Kroll's\n\
636 Smart UPS Tools be installed on the remote host.  If you do not have the\n\
637 package installed on your system, you can download it from\n\
638 http://www.networkupstools.org\n\n"));
640         printf (_(UT_SUPPORT));
645 void
646 print_usage (void)
648         printf ("\
649 Usage: %s -H host -u ups [-p port] [-v variable]\n\
650                   [-wv warn_value] [-cv crit_value] [-to to_sec] [-T]\n", progname);