check_smart.cpp 4.55 KB
#include "check_smart.h"

char *servicename = (char*)"SMART";

int evalStatus(char* disk, string reallocatedCount, string currentPending, string offlineUncorrectable, string *status)
{
	int returnStatus = 0;
	*status = string(disk) + " reallocated_count:";
	string reallocatedNum = reallocatedCount.substr(reallocatedCount.find_last_of(" ")+1);
	if(reallocatedNum != "0")
	{
		returnStatus = 1;
	}
	*status += reallocatedNum + " current_pending:";
	string currentNum = currentPending.substr(currentPending.find_last_of(" ")+1);
	if(currentNum != "0")
	{
		returnStatus = 2;
	}
	*status += currentNum + " offline_uncorrectable:";
	string offlineNum = offlineUncorrectable.substr(offlineUncorrectable.find_last_of(" ")+1);
	if(offlineNum != "0")
	{
		returnStatus = 2;
	}
	*status += offlineNum;
	return returnStatus;
}

void printVersion()
{
	cout << "check_smart v" << VERSION << endl << endl;
}

void printHelp(bool longVersion)
{
	if(longVersion)
	{
		printVersion();
		cout << "Checks for pending, reallocated or uncorrectable sectors in disks using SMART" << endl << "WARNING: Requires the setuid bit to be set to run as root" << endl << endl;
		printHelp(false);
		cout << "Options:" << endl;
		cout << " -h" << endl;
		cout << "    Print detailed help screen" << endl;
		cout << " -V" << endl;
		cout << "    Print version information" << endl;
		cout << " DISKS" << endl;
		cout << "    Disks for which to retrieve S.M.A.R.T data" << endl << endl;
		return;
	}
	cout << "Usage: " << endl << "check_smart [-hV] DISKS..." << endl << endl;
}

int main(int argc, char **argv)
{
	struct itimerval timer;
	timer.it_value.tv_sec = 10;
	timer.it_value.tv_usec = 0;
	timer.it_interval.tv_sec = 0;
	timer.it_interval.tv_usec = 0;
	setitimer (ITIMER_VIRTUAL, &timer, 0);

	struct sigaction sa;
	memset (&sa, 0, sizeof (sa));
	sa.sa_handler = &timer_handler;
	sigaction (SIGVTALRM, &sa, 0);

	int c;
        while ((c = getopt (argc, argv, "Vh")) != -1)
        {
                switch(c)
                {
                        case 'h':
                                printHelp(true);
				return 0;
                        case 'V':
                                printVersion();
				return 0;
                        case '?':
                                printHelp(false);
                                return 3;
		}
	}

	if(argc == 1)
	{
		cout << "No disks checked" << endl;
		return 3;
	}

	string *results = new string[argc-1];
	int returnCode = 0;

	string command = string(SMARTCTL_CMD);
	stringstream sstream;
	string line = "";
	string reallocatedCount = "";
	string currentPending = "";
	string offlineUncorrectable = "";
	string status = "";
	for(int i = 1; i < argc; i++)
	{
		string output;
		int uid = getuid();
		int gid = getgid();
		setuid(0);
		setgid(0);
		int rc = exec(command + argv[i],&output);
		setuid(uid);
		setgid(gid);
		if(rc)
        	{
                	cout << "Error reading SMART data from disk" << endl;
                	exit(3);
        	}
		sstream.str(output);
		while(getline(sstream,line))
		{
			int j = 0;
			while(line[j] == ' ')
			{
				j++;
			}
			size_t spacePos = line.find_first_of(" ",j);
			if(line.substr(j,spacePos-j) == "5")
			{
				reallocatedCount = line;
			}
			else if(line.substr(j,spacePos-j) == "197")
			{
				currentPending = line;
			}
			else if(line.substr(j,spacePos-j) == "198")
                        {
                                offlineUncorrectable = line;
                        }
		}
		if((reallocatedCount == "") || (currentPending == "") || (offlineUncorrectable == ""))
		{
			returnCode = 3;
			status = string(argv[i]) + " status UNKNOWN";
		}
		else
		{
			switch(evalStatus(argv[i],reallocatedCount,currentPending,offlineUncorrectable,&status))
			{
				case 0:
					//everything is OK
					break;
				case 1:
					//Warning issued
					if(!returnCode)
					{
						returnCode = 1;
					}
					break;
				case 2:
					//Critical issued
					returnCode = 2;
					break;
			}
		}
		results[i-1] = status;
		reallocatedCount = "";
                currentPending = "";
                offlineUncorrectable = "";
                output = "";
		line = "";
		status = "";
                sstream.str("");
		sstream.clear();
	}
	cout << servicename;
	if(returnCode == 0)
	{
		cout << " OK - disk status: ";
	}
	else if(returnCode == 1)
	{
		cout << " WARNING - disk status: ";
	}
	else if(returnCode == 2)
	{
		cout << " CRITICAL - disk status: ";
	}
	else if(returnCode == 3)
	{
		cout << " UNKNOWN - disk status: ";
	}
	for(int i = 0; i < (argc-1); i++)
	{
		cout << results[i];
		if(i != (argc-2))
		{
			cout << ", ";
		}
	}
	cout << endl;
	return returnCode;
}