/****************************************************************************** * 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; }