/******************************************************************************
* Nagios check_disk_io plugin
*
* License: GPL
* Author: Konstantin Reichert
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*
* Please visit also http://www.ibm.com/developerworks/wikis/display/WikiPtype/ryo
* Parts of the code within this plugin come from there.
*
******************************************************************************/
#include
#include
#include
#include
#include
#include
#ifndef FIRST_DISK
#define FIRST_DISK ""
#endif
#define DELTA(member) (b[i].member - a[i].member)
/******************************************************************************
* Variables
******************************************************************************/
char * Description1 = "This plugin checks disk IO similar to 'iostat -d' on AIX-Systems.";
char * Description2 = "Thresholds can be set for busy values, but feel free to implement other thresholds.";
char * Description3 = "For more information, please refer to man pages of iostat on AIX-Systems.";
char * Author = "Konstantin Reichert ";
char * Date = "2010/08/20 ";
char * Version = "0.5 ";
int state;
int warn_cnt = 0;
int crit_cnt = 0;
int unkn_cnt = 0;
char *ch;
/* This strips out junk characters found in the names
to work around bugs in some versions */
char *fix(char *s) {
int j;
for(j = 0; j < IDENTIFIER_LENGTH; j++) {
if( !(isalpha(s[j]) ||
isdigit(s[j]) ||
s[j] == '-' ||
s[j] == '_' ||
s[j] == ' '
) ) {
s[j] = 0;
break;
}
}
return s;
}
/******************************************************************************
* Print Usage Info
******************************************************************************/
void print_usage(char *basename) {
printf("Usage:\n\t%s -w -c \n", basename);
printf("\t%s -h \n", basename);
}
/******************************************************************************
* Print Help
******************************************************************************/
void print_help(char *basename) {
printf("%s Version: %s\n\n", basename, Version);
printf("Copyright (c) %s %s\n\n", Date, Author);
printf("%s\n", Description1);
printf("%s\n", Description2);
printf("%s\n", Description3);
printf("You have to disable 'escape_html_tags' in cgi.cfg of your Nagios, to geht HTML formated output of the check.\n\n");
print_usage(basename);
printf("Options: \n");
printf("\t-w Set warning threshold for percentage of time the physical disk/tape was active (bandwidth utilization for the drive).\n");
printf("\t-c Set critical threshold for percentage of time the physical disk/tape was active (bandwidth utilization for the drive).\n");
printf("\t-h Show this help.\n");
exit (0);
}
/******************************************************************************
* Check Thresholds
******************************************************************************/
void check_thresh_valid(double warning, double critical) {
if (warning > critical) {
printf("Warning-Value for must be LESS than Critical-Value!!!\n");
print_usage(ch);
exit(3);
}
}
int check_threshold(double value, double warning, double critical) {
if(value < warning) {
return state = 0;
}
else if((value >= warning) && (value <= critical)) {
warn_cnt++;
return state = 1;
}
else if(value >= critical) {
crit_cnt++;
return state = 2;
}
else {
unkn_cnt++;
return state = 3;
}
}
int main(int argc, char* argv[]) {
ch = argv[0]; /* get the name/path of/to the check */
int arguments;
double warn = 40.0;
double crit = 50.0;
int state = 0;
if (argc <= 1) {
print_usage(ch);
return 2;
}
while ((arguments = getopt (argc, argv, ":w:c:h")) != -1) {
switch (arguments) {
case 'w':
warn = atoi(optarg);
break;
case 'c':
crit = atoi(optarg);
break;
case 'h':
print_help(ch);
break;
case ':':
fprintf (stderr, "Option -%c requires an argument.\n", optopt);
exit(2);
break;
case '?':
fprintf (stderr, "Unknown -%c argument.\n", optopt);
exit(2);
break;
default:
abort();
}
}
check_thresh_valid(warn, crit);
int i, j, ret, disks;
perfstat_disk_t * a;
perfstat_disk_t * b;
perfstat_id_t name;
char * substring;
int seconds = 1;
int times = 1;
char * disk_name;
double tm_act;
double Kbps;
double tps;
double Kb_read;
double Kb_wrtn;
char str[256];
char * perfdata;
/* check how many perfstat_disk_t structures are available */
disks = perfstat_disk(NULL, NULL, sizeof(perfstat_disk_t), 0);
if(disks == -1) {
perror("perfstat_disk(NULL)");
exit(3);
}
/* allocate enough memory for all the structures */
a = malloc(sizeof(perfstat_disk_t) * disks);
b = malloc(sizeof(perfstat_disk_t) * disks);
/* ask to get all the structures available in one call */
/* return code is number of structures returned */
name.name[0] = 0;
ret = perfstat_disk(&name, a, sizeof(perfstat_disk_t), disks);
if(disks == -1) {
perror("perfstat_disk(a)");
exit(4);
}
printf("Checked %d Disks\n",ret);
perfdata = malloc(sizeof(str) * disks);
strcpy(perfdata, " | ");
for(int k = 0; k < times; k++) {
sleep(seconds);
name.name[0] = 0;
ret = perfstat_disk(&name, b, sizeof(perfstat_disk_t), disks);
if(ret == -1) {
perror("perfstat_disk(b)");
exit(4);
}
for (i = 0; i < ret; i++) {
disk_name = fix(b[i].name);
tm_act = (double)DELTA(time)/seconds;
Kbps = (double)(DELTA(rblks)*(double)b[i].bsize/1024.0/(double)seconds)
+ (double)(DELTA(wblks)*(double)b[i].bsize/1024.0/(double)seconds);
tps = (double)DELTA(xfers)/seconds;
Kb_read = (double)(DELTA(rblks)*(double)b[i].bsize/1024.0/(double)seconds);
Kb_wrtn = (double)(DELTA(wblks)*(double)b[i].bsize/1024.0/(double)seconds);
if (check_threshold(tm_act, warn, crit) != 0) {
/* printf("%s: PROBLEM\n - Busy = %.1f%%\n - Kbps = %.2f\n - tps = %.1f\n - Kb_read = %.2f\n - Kb_wrtn = %.2f\n", */
printf("%s: PROBLEM\n - Busy = %.1f%%\n - tps = %.1f\n - Kb_read = %.2f\n - Kb_wrtn = %.2f\n",
disk_name,
tm_act,
/* Kbps, */
tps,
Kb_read,
Kb_wrtn
);
}
/* else {
printf("%s:\n - Busy = %.1f%%\n - Kbps = %.2f\n - tps = %.1f\n - Kb_read = %.2f\n - Kb_wrtn = %.2f\n",
disk_name,
tm_act,
Kbps,
tps,
Kb_read,
Kb_wrtn
);
}*/
sprintf(str, "%s_Busy=%.1f%%;%1.1f;%1.1f ", disk_name, tm_act, warn, crit);
strcat(perfdata, str);
/*sprintf(str, "%s_Kbps=%.1fKb ", disk_name, Kbps);
strcat(perfdata, str);*/
sprintf(str, "%s_tps=%.1f ", disk_name, tps);
strcat(perfdata, str);
sprintf(str, "%s_KbRd=%.1fKb ", disk_name, Kb_read);
strcat(perfdata, str);
sprintf(str, "%s_KbWt=%.1fKb ", disk_name, Kb_wrtn);
strcat(perfdata, str);
}
memcpy(a,b,sizeof(perfstat_disk_t) * disks );
}
if (warn_cnt == 0 && crit_cnt == 0) {
/* printf ("OK\n"); */
state = 0;
}
else if (warn_cnt >= 0 && crit_cnt == 0) {
/* printf ("WARN\n"); */
state = 1;
}
else if (crit_cnt > 0 || crit_cnt >= warn_cnt) {
/* printf ("CRIT\n"); */
state = 2;
}
else {
/* printf ("UNKNOWN\n"); */
state = 3;
}
printf("%s", perfdata);
printf("\n");
free(perfdata);
return state;
}