[Nagiosplug-devel] check_load arg parsing bugfix and cleanup

Andreas Ericsson ae at op5.se
Fri May 27 09:10:17 CEST 2005


Feeling a bit stupid here, but I just found a bug in my patch. On system 
with getloadavg(3) it will always return STATE_UNKNOWN if getloadavg 
succeeds and no threshold value is overstepped.

Use the corrected patch attached here instead. The tracker has been updated.

Andreas Ericsson wrote:
> Ahoy.
> 
> Here's a patch to check_load.c which removes a lot of duplicate code and 
> some unnecessary complexity. It also fixes the argument parsing bug.
> 
> LOC count is down by 10% and speed is up by about 15, so I guess that's 
> a good thing.
> 
> Apply with patch -p1 < nagiosplug-check_load.diff
> 
> Next I'll rework the api for running commands, since that's the area 
> where most plugins duplicate efforts and does so in a very non-efficient 
> way. If someone else is already working on this, gimme a holler so we 
> can coordinate the efforts.
> 
> 
> ------------------------------------------------------------------------
> 
> diff -urN ../orig.nplg/plugins/check_load.c ./plugins/check_load.c
> --- ../orig.nplg/plugins/check_load.c	2005-05-27 15:56:34.000000000 +0200
> +++ ./plugins/check_load.c	2005-05-27 17:45:50.000000000 +0200
> @@ -39,37 +39,64 @@
>  #endif /* !defined LOADAVG_1MIN */
>  
>  
> -int process_arguments (int argc, char **argv);
> -int validate_arguments (void);
> +static int process_arguments (int argc, char **argv);
> +static int validate_arguments (void);
>  void print_help (void);
>  void print_usage (void);
>  
> -float wload1 = -1, wload5 = -1, wload15 = -1;
> -float cload1 = -1, cload5 = -1, cload15 = -1;
> +/* strictly for pretty-print usage in loops */
> +static const int nums[3] = { 1, 5, 15 };
> +
> +/* provide some fairly sane defaults */
> +double wload[3] = { 0.0, 0.0, 0.0 };
> +double cload[3] = { 0.0, 0.0, 0.0 };
> +#define la1 la[0]
> +#define la5 la[1]
> +#define la15 la[2]
>  
>  char *status_line;
>  
> +static void
> +get_threshold(char *arg, double *th)
> +{
> +	size_t i, n;
> +	char *str = arg, *p;
> +
> +	n = strlen(arg);
> +	for(i = 0; i < 3; i++) {
> +		th[i] = strtod(str, &p);
> +		if(p == str) break;
> +
> +		str = p + 1;
> +		if(n <= (size_t)(str - arg)) break;
> +	}
> +
> +	/* empty argument or non-floatish, so warn about it and die */
> +	if(!i) usage (_("Warning threshold must be float or float triplet!\n"));
> +
> +	if(i != 2) {
> +		/* one or more numbers were given, so fill array with last
> +		 * we got (most likely to NOT produce the least expected result) */
> +		for(n = i; n < 3; n++) th[n] = th[i];
> +	}
> +}
>  
>  
>  int
>  main (int argc, char **argv)
>  {
> -	int result = STATE_UNKNOWN;
> -	
> -#if HAVE_GETLOADAVG==1
> +	int result = STATE_OK;
> +	int i;
> +
>  	double la[3] = { 0.0, 0.0, 0.0 };	/* NetBSD complains about unitialized arrays */
> -#else
> -# if HAVE_PROC_LOADAVG==1
> -	FILE *fp;
> -	char input_buffer[MAX_INPUT_BUFFER];
> -	char *tmp_ptr;
> -# else
> +#ifndef HAVE_GETLOADAVG
>  	char input_buffer[MAX_INPUT_BUFFER];
> +# ifdef HAVE_PROC_LOADAVG
> +	FILE *fp;
> +	char *str, *next;
>  # endif
>  #endif
>  
> -	float la1, la5, la15;
> -
>  	setlocale (LC_ALL, "");
>  	bindtextdomain (PACKAGE, LOCALEDIR);
>  	textdomain (PACKAGE);
> @@ -77,30 +104,24 @@
>  	if (process_arguments (argc, argv) == ERROR)
>  		usage4 (_("Could not parse arguments"));
>  
> -#if HAVE_GETLOADAVG==1
> +#ifdef HAVE_GETLOADAVG
>  	result = getloadavg (la, 3);
>  	if (result == -1)
>  		return STATE_UNKNOWN;
> -	la1 = la[LOADAVG_1MIN];
> -	la5 = la[LOADAVG_5MIN];
> -	la15 = la[LOADAVG_15MIN];
>  #else
> -# if HAVE_PROC_LOADAVG==1
> +# ifdef HAVE_PROC_LOADAVG
>  	fp = fopen (PROC_LOADAVG, "r");
>  	if (fp == NULL) {
>  		printf (_("Error opening %s\n"), PROC_LOADAVG);
>  		return STATE_UNKNOWN;
>  	}
>  
> -	la1 = la5 = la15 = -1;
> -
>  	while (fgets (input_buffer, MAX_INPUT_BUFFER - 1, fp)) {
> -		tmp_ptr = strtok (input_buffer, " ");
> -		la1 = atof (tmp_ptr);
> -		tmp_ptr = strtok (NULL, " ");
> -		la5 = atof (tmp_ptr);
> -		tmp_ptr = strtok (NULL, " ");
> -		la15 = atof (tmp_ptr);
> +		str = (char *)input_buffer;
> +		for(i = 0; i < 3; i++) {
> +			la[i] = strtod(str, &next);
> +			str = next;
> +		}
>  	}
>  
>  	fclose (fp);
> @@ -126,11 +147,11 @@
>  #endif
>  
>  
> -	if ((la1 < 0.0) || (la5 < 0.0) || (la15 < 0.0)) {
> -#if HAVE_GETLOADAVG==1
> +	if ((la[0] < 0.0) || (la[1] < 0.0) || (la[2] < 0.0)) {
> +#ifdef HAVE_GETLOADAVG
>  		printf (_("Error in getloadavg()\n"));
>  #else
> -# if HAVE_PROC_LOADAVG==1
> +# ifdef HAVE_PROC_LOADAVG
>  		printf (_("Error processing %s\n"), PROC_LOADAVG);
>  # else
>  		printf (_("Error processing %s\n"), PATH_TO_UPTIME);
> @@ -141,27 +162,25 @@
>  
>  	asprintf(&status_line, _("load average: %.2f, %.2f, %.2f"), la1, la5, la15);
>  
> -	if ((la1 >= cload1) || (la5 >= cload5) || (la15 >= cload15))
> -		result = STATE_CRITICAL;
> -	else if ((la1 >= wload1) || (la5 >= wload5) || (la15 >= wload15))
> -		result = STATE_WARNING;
> -	else
> -		result = STATE_OK;
> -
> -	die (result,
> -	     "%s - %s|%s %s %s\n",
> -	     state_text (result),
> -	     status_line,
> -	     fperfdata ("load1", la1, "", (int)wload1, wload1, (int)cload1, cload1, TRUE, 0, FALSE, 0),
> -	     fperfdata ("load5", la5, "", (int)wload5, wload5, (int)cload5, cload5, TRUE, 0, FALSE, 0),
> -	     fperfdata ("load15", la15, "", (int)wload15, wload15, (int)cload15, cload15, TRUE, 0, FALSE, 0));
> -	return STATE_OK;
> -}
> +	for(i = 0; i < 3; i++) {
> +		if(la[i] > cload[i]) {
> +			result = STATE_CRITICAL;
> +			break;
> +		}
> +		else if(la[i] > wload[i]) result = STATE_WARNING;
> +	}
>  
> +	printf("%s - %s|", state_text(result), status_line);
> +	for(i = 0; i < 3; i++)
> +		printf("load%d=%.3f;%.3f;%.3f;0; ", nums[i], la[i], wload[i], cload[i]);
> +
> +	putchar('\n');
> +	return result;
> +}
>  
>  
>  /* process command-line arguments */
> -int
> +static int
>  process_arguments (int argc, char **argv)
>  {
>  	int c = 0;
> @@ -185,37 +204,11 @@
>  			break;
>  
>  		switch (c) {
> -		case 'w':									/* warning time threshold */
> -			if (is_intnonneg (optarg)) {
> -				wload1 = atof (optarg);
> -				wload5 = atof (optarg);
> -				wload15 = atof (optarg);
> -				break;
> -			}
> -			else if (strstr (optarg, ",") &&
> -								 sscanf (optarg, "%f,%f,%f", &wload1, &wload5, &wload15) == 3)
> -				break;
> -			else if (strstr (optarg, ":") &&
> -							 sscanf (optarg, "%f:%f:%f", &wload1, &wload5, &wload15) == 3)
> -				break;
> -			else
> -				usage (_("Warning threshold must be float or float triplet!\n"));
> +		case 'w': /* warning time threshold */
> +			get_threshold(optarg, wload);
>  			break;
> -		case 'c':									/* critical time threshold */
> -			if (is_intnonneg (optarg)) {
> -				cload1 = atof (optarg);
> -				cload5 = atof (optarg);
> -				cload15 = atof (optarg);
> -				break;
> -			}
> -			else if (strstr (optarg, ",") &&
> -							 sscanf (optarg, "%f,%f,%f", &cload1, &cload5, &cload15) == 3)
> -				break;
> -			else if (strstr (optarg, ":") &&
> -							 sscanf (optarg, "%f:%f:%f", &cload1, &cload5, &cload15) == 3)
> -				break;
> -			else
> -				usage (_("Critical threshold must be float or float triplet!\n"));
> +		case 'c': /* critical time threshold */
> +			get_threshold(optarg, cload);
>  			break;
>  		case 'V':									/* version */
>  			print_revision (progname, revision);
> @@ -231,60 +224,38 @@
>  	c = optind;
>  	if (c == argc)
>  		return validate_arguments ();
> -	if (wload1 < 0 && is_nonnegative (argv[c]))
> -		wload1 = atof (argv[c++]);
> -
> -	if (c == argc)
> -		return validate_arguments ();
> -	if (cload1 < 0 && is_nonnegative (argv[c]))
> -		cload1 = atof (argv[c++]);
> -
> -	if (c == argc)
> -		return validate_arguments ();
> -	if (wload5 < 0 && is_nonnegative (argv[c]))
> -		wload5 = atof (argv[c++]);
> -
> -	if (c == argc)
> -		return validate_arguments ();
> -	if (cload5 < 0 && is_nonnegative (argv[c]))
> -		cload5 = atof (argv[c++]);
>  
> -	if (c == argc)
> -		return validate_arguments ();
> -	if (wload15 < 0 && is_nonnegative (argv[c]))
> -		wload15 = atof (argv[c++]);
> -
> -	if (c == argc)
> -		return validate_arguments ();
> -	if (cload15 < 0 && is_nonnegative (argv[c]))
> -		cload15 = atof (argv[c++]);
> +	/* handle the case if both arguments are missing,
> +	 * but not if only one is given without -c or -w flag */
> +	if(c - argc == 2) {
> +		get_threshold(argv[c++], wload);
> +		get_threshold(argv[c++], cload);
> +	}
> +	else if(c - argc == 1) {
> +		get_threshold(argv[c++], cload);
> +	}
>  
>  	return validate_arguments ();
>  }
>  
>  
>  
> -int
> +static int
>  validate_arguments (void)
>  {
> -	if (wload1 < 0)
> -		usage (_("Warning threshold for 1-minute load average is not specified\n"));
> -	if (wload5 < 0)
> -		usage (_("Warning threshold for 5-minute load average is not specified\n"));
> -	if (wload15 < 0)
> -		usage (_("Warning threshold for 15-minute load average is not specified\n"));
> -	if (cload1 < 0)
> -		usage (_("Critical threshold for 1-minute load average is not specified\n"));
> -	if (cload5 < 0)
> -		usage (_("Critical threshold for 5-minute load average is not specified\n"));
> -	if (cload15 < 0)
> -		usage (_("Critical threshold for 15-minute load average is not specified\n"));
> -	if (wload1 > cload1)
> -		usage (_("Parameter inconsistency: 1-minute \"warning load\" greater than \"critical load\".\n"));
> -	if (wload5 > cload5)
> -		usage (_("Parameter inconsistency: 5-minute \"warning load\" greater than \"critical load\".\n"));
> -	if (wload15 > cload15)
> -		usage (_("Parameter inconsistency: 15-minute \"warning load\" greater than \"critical load\".\n"));
> +	int i = 0;
> +
> +	/* match cload first, as it will give the most friendly error message
> +	 * if user hasn't given the -c switch properly */
> +	for(i = 0; i < 3; i++) {
> +		if(cload[i] < 0)
> +			die (STATE_UNKNOWN, _("Critical threshold for %d-minute load average is not specified\n"), nums[i]);
> +		if(wload[i] < 0)
> +			die (STATE_UNKNOWN, _("Warning threshold for %d-minute load average is not specified\n"), nums[i]);
> +		if(wload[i] > cload[i])
> +			die (STATE_UNKNOWN, _("Parameter inconsistency: %d-minute \"warning load\" is greater than \"critical load\"\n"), nums[i]);
> +	}
> +
>  	return OK;
>  }

-- 
Andreas Ericsson                   andreas.ericsson at op5.se
OP5 AB                             www.op5.se
Lead Developer
-------------- next part --------------
An embedded and charset-unspecified text was scrubbed...
Name: nagiosplug-check_load.diff
URL: <http://nagios-plugins.org/archive/devel/attachments/20050527/d1c3655f/attachment.ksh>


More information about the Devel mailing list