Back to index

nagios-plugins  1.4.16
check_load.c
Go to the documentation of this file.
00001 /*****************************************************************************
00002 * 
00003 * Nagios check_load plugin
00004 * 
00005 * License: GPL
00006 * Copyright (c) 1999-2007 Nagios Plugins Development Team
00007 * 
00008 * Description:
00009 * 
00010 * This file contains the check_load plugin
00011 * 
00012 * This plugin tests the current system load average.
00013 * 
00014 * 
00015 * This program is free software: you can redistribute it and/or modify
00016 * it under the terms of the GNU General Public License as published by
00017 * the Free Software Foundation, either version 3 of the License, or
00018 * (at your option) any later version.
00019 * 
00020 * This program is distributed in the hope that it will be useful,
00021 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023 * GNU General Public License for more details.
00024 * 
00025 * You should have received a copy of the GNU General Public License
00026 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
00027 * 
00028 * 
00029 *****************************************************************************/
00030 
00031 const char *progname = "check_load";
00032 const char *copyright = "1999-2007";
00033 const char *email = "nagiosplug-devel@lists.sourceforge.net";
00034 
00035 #include "common.h"
00036 #include "utils.h"
00037 #include "popen.h"
00038 
00039 #ifdef HAVE_SYS_LOADAVG_H
00040 #include <sys/loadavg.h>
00041 #endif
00042 
00043 /* needed for compilation under NetBSD, as suggested by Andy Doran */
00044 #ifndef LOADAVG_1MIN
00045 #define LOADAVG_1MIN 0
00046 #define LOADAVG_5MIN 1
00047 #define LOADAVG_15MIN       2
00048 #endif /* !defined LOADAVG_1MIN */
00049 
00050 
00051 static int process_arguments (int argc, char **argv);
00052 static int validate_arguments (void);
00053 void print_help (void);
00054 void print_usage (void);
00055 
00056 /* strictly for pretty-print usage in loops */
00057 static const int nums[3] = { 1, 5, 15 };
00058 
00059 /* provide some fairly sane defaults */
00060 double wload[3] = { 0.0, 0.0, 0.0 };
00061 double cload[3] = { 0.0, 0.0, 0.0 };
00062 #define la1 la[0]
00063 #define la5 la[1]
00064 #define la15 la[2]
00065 
00066 char *status_line;
00067 int take_into_account_cpus = 0;
00068 
00069 static void
00070 get_threshold(char *arg, double *th)
00071 {
00072        size_t i, n;
00073        int valid = 0;
00074        char *str = arg, *p;
00075 
00076        n = strlen(arg);
00077        for(i = 0; i < 3; i++) {
00078               th[i] = strtod(str, &p);
00079               if(p == str) break;
00080 
00081               valid = 1;
00082               str = p + 1;
00083               if(n <= (size_t)(str - arg)) break;
00084        }
00085 
00086        /* empty argument or non-floatish, so warn about it and die */
00087        if(!i && !valid) usage (_("Warning threshold must be float or float triplet!\n"));
00088 
00089        if(i != 2) {
00090               /* one or more numbers were given, so fill array with last
00091                * we got (most likely to NOT produce the least expected result) */
00092               for(n = i; n < 3; n++) th[n] = th[i];
00093        }
00094 }
00095 
00096 
00097 int
00098 main (int argc, char **argv)
00099 {
00100        int result;
00101        int i;
00102        long numcpus;
00103 
00104        double la[3] = { 0.0, 0.0, 0.0 };  /* NetBSD complains about unitialized arrays */
00105 #ifndef HAVE_GETLOADAVG
00106        char input_buffer[MAX_INPUT_BUFFER];
00107 # ifdef HAVE_PROC_LOADAVG
00108        FILE *fp;
00109        char *str, *next;
00110 # endif
00111 #endif
00112 
00113        setlocale (LC_ALL, "");
00114        bindtextdomain (PACKAGE, LOCALEDIR);
00115        textdomain (PACKAGE);
00116        setlocale(LC_NUMERIC, "POSIX");
00117 
00118        /* Parse extra opts if any */
00119        argv = np_extra_opts (&argc, argv, progname);
00120 
00121        if (process_arguments (argc, argv) == ERROR)
00122               usage4 (_("Could not parse arguments"));
00123 
00124 #ifdef HAVE_GETLOADAVG
00125        result = getloadavg (la, 3);
00126        if (result != 3)
00127               return STATE_UNKNOWN;
00128 #else
00129 # ifdef HAVE_PROC_LOADAVG
00130        fp = fopen (PROC_LOADAVG, "r");
00131        if (fp == NULL) {
00132               printf (_("Error opening %s\n"), PROC_LOADAVG);
00133               return STATE_UNKNOWN;
00134        }
00135 
00136        while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
00137               str = (char *)input_buffer;
00138               for(i = 0; i < 3; i++) {
00139                      la[i] = strtod(str, &next);
00140                      str = next;
00141               }
00142        }
00143 
00144        fclose (fp);
00145 # else
00146        child_process = spopen (PATH_TO_UPTIME);
00147        if (child_process == NULL) {
00148               printf (_("Error opening %s\n"), PATH_TO_UPTIME);
00149               return STATE_UNKNOWN;
00150        }
00151        child_stderr = fdopen (child_stderr_array[fileno (child_process)], "r");
00152        if (child_stderr == NULL) {
00153               printf (_("Could not open stderr for %s\n"), PATH_TO_UPTIME);
00154        }
00155        fgets (input_buffer, MAX_INPUT_BUFFER - 1, child_process);
00156        sscanf (input_buffer, "%*[^l]load average: %lf, %lf, %lf", &la1, &la5, &la15);
00157 
00158        result = spclose (child_process);
00159        if (result) {
00160               printf (_("Error code %d returned in %s\n"), result, PATH_TO_UPTIME);
00161               return STATE_UNKNOWN;
00162        }
00163 # endif
00164 #endif
00165 
00166        if (take_into_account_cpus == 1) {
00167               if ((numcpus = GET_NUMBER_OF_CPUS()) > 0) {
00168                      la[0] = la[0] / numcpus;
00169                      la[1] = la[1] / numcpus;
00170                      la[2] = la[2] / numcpus;
00171               }
00172        }
00173        if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
00174 #ifdef HAVE_GETLOADAVG
00175               printf (_("Error in getloadavg()\n"));
00176 #else
00177 # ifdef HAVE_PROC_LOADAVG
00178               printf (_("Error processing %s\n"), PROC_LOADAVG);
00179 # else
00180               printf (_("Error processing %s\n"), PATH_TO_UPTIME);
00181 # endif
00182 #endif
00183               return STATE_UNKNOWN;
00184        }
00185 
00186        /* we got this far, so assume OK until we've measured */
00187        result = STATE_OK;
00188 
00189        asprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15);
00190 
00191        for(i = 0; i < 3; i++) {
00192               if(la[i] > cload[i]) {
00193                      result = STATE_CRITICAL;
00194                      break;
00195               }
00196               else if(la[i] > wload[i]) result = STATE_WARNING;
00197        }
00198 
00199        printf("%s - %s|", state_text(result), status_line);
00200        for(i = 0; i < 3; i++)
00201               printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
00202 
00203        putchar('\n');
00204        return result;
00205 }
00206 
00207 
00208 /* process command-line arguments */
00209 static int
00210 process_arguments (int argc, char **argv)
00211 {
00212        int c = 0;
00213 
00214        int option = 0;
00215        static struct option longopts[] = {
00216               {"warning", required_argument, 0, 'w'},
00217               {"critical", required_argument, 0, 'c'},
00218               {"percpu", no_argument, 0, 'r'},
00219               {"version", no_argument, 0, 'V'},
00220               {"help", no_argument, 0, 'h'},
00221               {0, 0, 0, 0}
00222        };
00223 
00224        if (argc < 2)
00225               return ERROR;
00226 
00227        while (1) {
00228               c = getopt_long (argc, argv, "Vhrc:w:", longopts, &option);
00229 
00230               if (c == -1 || c == EOF)
00231                      break;
00232 
00233               switch (c) {
00234               case 'w': /* warning time threshold */
00235                      get_threshold(optarg, wload);
00236                      break;
00237               case 'c': /* critical time threshold */
00238                      get_threshold(optarg, cload);
00239                      break;
00240               case 'r': /* Divide load average by number of CPUs */
00241                      take_into_account_cpus = 1;
00242                      break;
00243               case 'V':                                                             /* version */
00244                      print_revision (progname, NP_VERSION);
00245                      exit (STATE_OK);
00246               case 'h':                                                             /* help */
00247                      print_help ();
00248                      exit (STATE_OK);
00249               case '?':                                                             /* help */
00250                      usage5 ();
00251               }
00252        }
00253 
00254        c = optind;
00255        if (c == argc)
00256               return validate_arguments ();
00257 
00258        /* handle the case if both arguments are missing,
00259         * but not if only one is given without -c or -w flag */
00260        if(c - argc == 2) {
00261               get_threshold(argv[c++], wload);
00262               get_threshold(argv[c++], cload);
00263        }
00264        else if(c - argc == 1) {
00265               get_threshold(argv[c++], cload);
00266        }
00267 
00268        return validate_arguments ();
00269 }
00270 
00271 
00272 
00273 static int
00274 validate_arguments (void)
00275 {
00276        int i = 0;
00277 
00278        /* match cload first, as it will give the most friendly error message
00279         * if user hasn't given the -c switch properly */
00280        for(i = 0; i < 3; i++) {
00281               if(cload[i] < 0)
00282                      die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
00283               if(wload[i] < 0)
00284                      die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
00285               if(wload[i] > cload[i])
00286                      die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
00287        }
00288 
00289        return OK;
00290 }
00291 
00292 
00293 
00294 void
00295 print_help (void)
00296 {
00297        print_revision (progname, NP_VERSION);
00298 
00299        printf ("Copyright (c) 1999 Felipe Gustavo de Almeida <galmeida@linux.ime.usp.br>\n");
00300        printf (COPYRIGHT, copyright, email);
00301 
00302        printf (_("This plugin tests the current system load average."));
00303 
00304   printf ("\n\n");
00305 
00306        print_usage ();
00307 
00308        printf (UT_HELP_VRSN);
00309        printf (UT_EXTRA_OPTS);
00310 
00311        printf (" %s\n", "-w, --warning=WLOAD1,WLOAD5,WLOAD15");
00312   printf ("    %s\n", _("Exit with WARNING status if load average exceeds WLOADn"));
00313   printf (" %s\n", "-c, --critical=CLOAD1,CLOAD5,CLOAD15");
00314   printf ("    %s\n", _("Exit with CRITICAL status if load average exceed CLOADn"));
00315   printf ("    %s\n", _("the load average format is the same used by \"uptime\" and \"w\""));
00316   printf (" %s\n", "-r, --percpu");
00317   printf ("    %s\n", _("Divide the load averages by the number of CPUs (when possible)"));
00318 
00319        printf (UT_SUPPORT);
00320 }
00321 
00322 void
00323 print_usage (void)
00324 {
00325   printf ("%s\n", _("Usage:"));
00326        printf ("%s [-r] -w WLOAD1,WLOAD5,WLOAD15 -c CLOAD1,CLOAD5,CLOAD15\n", progname);
00327 }