check_sensors.cpp 5.23 KB
#include "check_sensors.h"

const char *servicename = (const char*)"SENSORS";

int getTemps(const std::string& sensorName, std::map<std::string, double>& temps) {
  sensors_chip_name const * cn;
  int c = 0;
  while((cn = sensors_get_detected_chips(0, &c)) != 0) {
    if(!strcmp(sensorName.c_str(), cn->prefix)) {
      sensors_feature const *feat;
      int f = 0;
      while((feat = sensors_get_features(cn, &f)) != 0) {
        std::string feature = feat->name;
        if(starts_with(feature,"temp")) {
          sensors_subfeature const *subf;
          int s = 0;
          while((subf = sensors_get_all_subfeatures(cn, feat, &s)) != 0) {    
            std::string subfeature = subf->name;
            if(ends_with(subfeature,"_input")) {
              double value;
              if (subf->flags & SENSORS_MODE_R) {
                int rc = sensors_get_value(cn, subf->number, &value);
                if (rc < 0) {
                  return rc;
                } else {
                  temps[feature] = value;
                }
              }
            }
          }
        }
      }
    }
  }
  return 0;
}

int evalStatus(const std::string& sensorName, double warn, double crit, std::string& status) {
  int ret = OK;
  int rc;
  std::map<std::string, double> temps;
  status = sensorName;

  if((rc = getTemps(sensorName, temps))) {
    status = "Error retrieving temps from libsensors: " + int2str(rc);
    return UNKN;
  }
  if(!temps.size()) {
    status = "Sensor " + sensorName + " not found";
    return UNKN;
  }

  for(const std::pair<std::string, double>& entry : temps) {
    std::string feature = entry.first;
    double value = entry.second;
    if(value > crit && ret != CRIT) {
      ret = CRIT;
    } else if(value > warn && ret == OK) {
      ret = WARN;
    }
    status += " " + feature + ": " + double2str(value);
  }
  return ret;
}

void printVersion() {
  std::cout << "check_sensors v" << VERSION << std::endl << std::endl;
}

void printHelp(bool longVersion) {
  if(longVersion) {
    printVersion();
    std::cout << "Checks for pending, reallocated or uncorrectable sectors in disks using SMART" << std::endl << "WARNING: Requires the setuid bit to be set to run as root" << std::endl << std::endl;
    printHelp(false);
    std::cout << "Options:" << std::endl;
    std::cout << " -h" << std::endl;
    std::cout << "    Print detailed help screen" << std::endl;
    std::cout << " -V" << std::endl;
    std::cout << "    Print version information" << std::endl;
    std::cout << " -w DOUBLE" << std::endl;
    std::cout << "    Warning temperature level" << std::endl;
    std::cout << " -c DOUBLE" << std::endl;
    std::cout << "    Critical temperature level" << std::endl;
    std::cout << " SENSORS" << std::endl;
    std::cout << "    sensor names to retrieve temperature data" << std::endl << std::endl;
    return;
  }
  std::cout << "Usage: " << std::endl << "check_sensors [-hV] -w <temp> -c <temp> SENSORS..." << std::endl << std::endl;
}

void set_timeout(unsigned int sec) {
  struct itimerval timer;
  timer.it_value.tv_sec = sec;
  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 main(int argc, char **argv) {
  set_timeout(10);
  int c;
  char *warningFlag = NULL;
  char *criticalFlag = NULL;

  while((c = getopt (argc, argv, "Vhw:c:")) != -1) {
    switch(c) {
      case 'h':
        printHelp(true);
	return OK;
      case 'V':
        printVersion();
        return OK;
      case 'w':
        warningFlag = optarg;
        break;
      case 'c':
        criticalFlag = optarg;
        break;
      case '?':
        printHelp(false);
        return UNKN;
    }
  }

  if(warningFlag == NULL) {
    std::cout << "Warning flag not specified" << std::endl;
    return UNKN;
  }
  if(criticalFlag == NULL) {
    std::cout << "Critical flag not specified" << std::endl;
    return UNKN;
  }
  if(optind >= argc) {
    std::cout << "No sensors to check" << std::endl;
    return UNKN;
  }

  double warn = 0;
  double crit = 0;

  try {
    warn = str2double(warningFlag);
    crit = str2double(criticalFlag);
  } catch(ConversionException e) {
    std::cout << e.what() << std::endl;
    return UNKN;
  }

  std::vector<std::string> results;
  int returnCode = OK;

  sensors_init(NULL);
  for(int i = optind; i < argc; i++) {
    std::string result;
    switch(evalStatus(argv[i], warn, crit, result)) {
      case OK:
        break;
      case WARN:
        if(returnCode == OK) {returnCode = WARN;}
        break;
      case CRIT:
        returnCode = CRIT;
        break;
      case UNKN:
        returnCode = UNKN;
        break;
    }
    results.push_back(result);
  }
  sensors_cleanup();

  std::cout << servicename;
  if(returnCode == OK) {std::cout << " OK - sensors: ";}
  else if(returnCode == WARN) {std::cout << " WARNING - sensors: ";}
  else if(returnCode == CRIT) {std::cout << " CRITICAL - sensors: ";}
  else if(returnCode == UNKN) {std::cout << " UNKNOWN - sensors: ";}
  for(int i = 0; i < results.size(); ++i) {
    std::cout << results[i];
    if(i != (results.size()-1)) {std::cout << ", ";}
  }
  std::cout << std::endl;
  return returnCode;
}