diff options
Diffstat (limited to 'agent/mibgroup/ucd-snmp/lmSensors.c')
-rw-r--r-- | agent/mibgroup/ucd-snmp/lmSensors.c | 1071 |
1 files changed, 1071 insertions, 0 deletions
diff --git a/agent/mibgroup/ucd-snmp/lmSensors.c b/agent/mibgroup/ucd-snmp/lmSensors.c new file mode 100644 index 0000000..05c60b7 --- /dev/null +++ b/agent/mibgroup/ucd-snmp/lmSensors.c @@ -0,0 +1,1071 @@ +/* lmSensors.c + * + * Sections of this code were derived from the published API's of + * some Sun products. Hence, portions of the code may be copyright + * Sun Microsystems. + * + * Additional code provided by Mike Fisher and Thomas E. Lackley + * + * This component allows net-snmp to report sensor information. + * + * In order to use it, the ./configure invocation must include... + * + * --with-mib-modules="ucd-snmp/lmSensors" + * + * It uses one of three different methodologies. Some platforms make + * use of an lm_sensors driver to access the information on the + * health monitoring hardware, such as the LM75 and LM78 chips. + * + * For further information see http://secure.netroedge.com/~lm78/ + * + * The Solaris platform uses the other two methodologies. Earlier + * platforms such as the Enterprise 450 use kstat to report sensor + * information. Later platforms, such as the V880 use the picld + * daemon to control system resources and report sensor information. + * Picld is supported only on Solaris 2.8 and later. + * + * Both these methodologies are implemented in a "read only" manner. + * You cannot use this code to change anything eg. fan speeds. + * + * The lmSensors component delivers the information documented in the + * LM-SENSORS-MIB. The information is divided up as follows: + * + * -temperatures (in thousandsths of a Celsius degree) + * -fans (rpm's) + * -voltages (in milliVolts) + * -other (switches, LEDs and i2c's (things that use the i2c bus)) + * NOTE: This version does not support gpio's. Still on the learning curve. + * + * Because the MIB only allows output of the datatype Gauge32 this + * limits the amount of meaningful information that can be delivered + * from "other" sensors. Hence, the code does a certain amount of + * translating. See the source for individual sensor types. + * + * If an "other" sensor delivers a value 99, it means that it + * is delivering a "status" that the code does not account for. + * If you discover one of these, please pass it on and I'll + * put it in. + * + * It was recently discovered that the sensors code had not be following + * the MIB for some sensors. The MIB required reporting some items + * in mV and mC. These changes have been noted in the source. + * + * To see debugging messages, run the daemon as follows: + * + * /usr/local/sbin/snmpd -f -L -Ducd-snmp/lmSensors + * (change path to wherever you installed it) + * + * or using gdb: + * + * gdb snmpd + * run -f -L -Ducd-snmp/lmSensors + * + * The component can record up to 256 instances of each type. + * + * The following should always be included first before anything else + */ + +#include <net-snmp/net-snmp-config.h> +#include <net-snmp/net-snmp-features.h> +#include <net-snmp/net-snmp-includes.h> +#include <net-snmp/agent/net-snmp-agent-includes.h> + +/* + * minimal include directives + */ + +#include "util_funcs/header_simple_table.h" +#include <time.h> + +netsnmp_feature_require(table_container) + + +/* + * Load required drivers and libraries. + */ + +#ifdef solaris2 + #include <kstat.h> + #ifdef HAVE_PICL_H + #include <picl.h> /* accesses the picld daemon */ + #else + /* the following should be sufficient for any Sun-based sensors */ + #include </usr/platform/sun4u/include/sys/envctrl.h> + #endif +#else + #include <sensors/sensors.h> + #define CONFIG_FILE_NAME "/etc/sensors.conf" +#endif + +#include "lmSensors.h" + +#define TEMP_TYPE (0) +#define FAN_TYPE (1) +#define VOLT_TYPE (2) +#define MISC_TYPE (3) +#define N_TYPES (4) + +#ifdef solaris2 + #define MAX_NAME (256) + #define MAX_SENSORS (256) /* there's a lot of sensors on a v880 */ +#else + #define MAX_NAME (64) + #define DEFAULT_SENSORS (256) +#endif + + +/* + * lmSensors_variables_oid: + * this is the top level oid that we want to register under. This + * is essentially a prefix, with the suffix appearing in the + * variable below. + */ + + +oid lmSensors_variables_oid[] = + { 1, 3, 6, 1, 4, 1, 2021, 13, 16 }; + +/* + * variable4 lmSensors_variables: + * this variable defines function callbacks and type return information + * for the lmSensors mib section + */ + +struct variable4 lmSensors_variables[] = { + /* + * magic number , variable type , ro/rw , callback fn , L, oidsuffix + */ +#define LMTEMPSENSORSINDEX 3 + {LMTEMPSENSORSINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {2, 1, 1}}, +#define LMTEMPSENSORSDEVICE 4 + {LMTEMPSENSORSDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {2, 1, 2}}, +#define LMTEMPSENSORSVALUE 5 + {LMTEMPSENSORSVALUE, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {2, 1, 3}}, +#define LMFANSENSORSINDEX 8 + {LMFANSENSORSINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {3, 1, 1}}, +#define LMFANSENSORSDEVICE 9 + {LMFANSENSORSDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {3, 1, 2}}, +#define LMFANSENSORSVALUE 10 + {LMFANSENSORSVALUE, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {3, 1, 3}}, +#define LMVOLTSENSORSINDEX 13 + {LMVOLTSENSORSINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {4, 1, 1}}, +#define LMVOLTSENSORSDEVICE 14 + {LMVOLTSENSORSDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {4, 1, 2}}, +#define LMVOLTSENSORSVALUE 15 + {LMVOLTSENSORSVALUE, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {4, 1, 3}}, +#define LMMISCSENSORSINDEX 18 + {LMMISCSENSORSINDEX, ASN_INTEGER, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {5, 1, 1}}, +#define LMMISCSENSORSDEVICE 19 + {LMMISCSENSORSDEVICE, ASN_OCTET_STR, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {5, 1, 2}}, +#define LMMISCSENSORSVALUE 20 + {LMMISCSENSORSVALUE, ASN_GAUGE, NETSNMP_OLDAPI_RONLY, + var_lmSensorsTable, 3, {5, 1, 3}}, +}; + +typedef struct { +#ifdef solaris2 + #ifdef HAVE_PICL_H + char name[PICL_PROPNAMELEN_MAX]; /*required for picld*/ + int value; + #else + char name[MAX_NAME]; + int value; + #endif +#else + char name[MAX_NAME]; + int value; +#endif +} _sensor; + +typedef struct { + int n; +#ifdef solaris2 + _sensor sensor[MAX_SENSORS]; +#else + _sensor* sensor; + size_t current_len; +#endif +} _sensor_array; + +static _sensor_array sensor_array[N_TYPES]; +static time_t timestamp; + +static int sensor_init(void); +static int sensor_load(void); +static int _sensor_load(time_t t); +#ifndef solaris2 +static void free_sensor_arrays(void); +#endif + +/* + * init_lmSensors(): + * Initialization routine. This is called when the agent starts up. + * At a minimum, registration of your variables should take place here. + */ +void +init_lmSensors(void) +{ + sensor_init(); + + /* + * register ourselves with the agent to handle our mib tree + */ + REGISTER_MIB("lmSensors", lmSensors_variables, variable4, + lmSensors_variables_oid); +} + +/* + * shutdown_lmSensors(): + * A shutdown/cleanup routine. This is called when the agent shutsdown. + */ +void +shutdown_lmSensors(void) +{ +#ifndef solaris2 + DEBUGMSG(("ucd-snmp/lmSensors", "=> shutdown_lmSensors\n")); + free_sensor_arrays(); + DEBUGMSG(("ucd-snmp/lmSensors", "<= shutdown_lmSensors\n")); +#endif +} /* shutdown_lmSensors */ + +/* + * var_lmSensorsTable(): + * Handle this table separately from the scalar value case. + * The workings of this are basically the same as for var_lmSensors above. + */ +unsigned char * +var_lmSensorsTable(struct variable *vp, + oid * name, + size_t * length, + int exact, + size_t * var_len, WriteMethod ** write_method) +{ + static long long_ret; + static char string[SPRINT_MAX_LEN]; + + int s_index; + int s_type = -1; + int n_sensors; + unsigned char* ret = NULL; + + _sensor s; + + if (sensor_load()) + { + ret = NULL; + goto leaving; + } + + switch (vp->magic) { + case LMTEMPSENSORSINDEX: + case LMTEMPSENSORSDEVICE: + case LMTEMPSENSORSVALUE: + s_type = TEMP_TYPE; + n_sensors = sensor_array[s_type].n; + break; + + case LMFANSENSORSINDEX: + case LMFANSENSORSDEVICE: + case LMFANSENSORSVALUE: + s_type = FAN_TYPE; + n_sensors = sensor_array[s_type].n; + break; + + case LMVOLTSENSORSINDEX: + case LMVOLTSENSORSDEVICE: + case LMVOLTSENSORSVALUE: + s_type = VOLT_TYPE; + n_sensors = sensor_array[s_type].n; + break; + + case LMMISCSENSORSINDEX: + case LMMISCSENSORSDEVICE: + case LMMISCSENSORSVALUE: + s_type = MISC_TYPE; + n_sensors = sensor_array[s_type].n; + break; + + default: + s_type = -1; + n_sensors = 0; + } + + if (header_simple_table(vp, name, length, exact, + var_len, write_method, + n_sensors) == MATCH_FAILED) + { + ret = NULL; + goto leaving; + } + + if (s_type < 0) + { + ret = NULL; + goto leaving; + } + + s_index = name[*length - 1] - 1; + s = sensor_array[s_type].sensor[s_index]; + + switch (vp->magic) { + case LMTEMPSENSORSINDEX: + case LMFANSENSORSINDEX: + case LMVOLTSENSORSINDEX: + case LMMISCSENSORSINDEX: + long_ret = s_index; + ret = (unsigned char *) &long_ret; + goto leaving; + + case LMTEMPSENSORSDEVICE: + case LMFANSENSORSDEVICE: + case LMVOLTSENSORSDEVICE: + case LMMISCSENSORSDEVICE: + strlcpy(string, s.name, sizeof(string)); + *var_len = strlen(string); + ret = (unsigned char *) string; + goto leaving; + + case LMTEMPSENSORSVALUE: + case LMFANSENSORSVALUE: + case LMVOLTSENSORSVALUE: + case LMMISCSENSORSVALUE: + long_ret = s.value; + ret = (unsigned char *) &long_ret; + goto leaving; + + default: + ERROR_MSG("Unable to handle table request"); + } + +leaving: + return ret; +} + +static int +sensor_init(void) +{ + int res; +#ifndef solaris2 + char filename[] = CONFIG_FILE_NAME; + time_t t = time(NULL); + FILE *fp = fopen(filename, "r"); + int i = 0; + + DEBUGMSG(("ucd-snmp/lmSensors", "=> sensor_init\n")); + + for (i = 0; i < N_TYPES; i++) + { + sensor_array[i].n = 0; + sensor_array[i].current_len = 0; + sensor_array[i].sensor = NULL; + } + + if (!fp) + { + res = 1; + goto leaving; + } + + if (sensors_init(fp)) + { + res = 2; + goto leaving; + } + + _sensor_load(t); /* I'll let the linux people decide whether they want to load right away */ +leaving: +#endif /* not solaris2 */ + + DEBUGMSG(("ucd-snmp/lmSensors", "<= sensor_init\n")); + return res; +} + +static int +sensor_load(void) +{ + int rc = 0; + time_t t = time(NULL); + + if (t > timestamp + 7) /* this may require some tuning - currently 7 seconds*/ + { +#ifndef solaris2 + free_sensor_arrays(); +#endif + rc = _sensor_load(t); + } + + return rc; +} + +/* This next code block includes all kstat and picld code for the Solaris platform. + * If you're not compiling on a Solaris that supports picld, it won't be included. + */ + +#ifdef solaris2 +/* ******* picld sensor procedures * */ +#ifdef HAVE_PICL_H + +/* the following are generic modules for reading sensor information + the scale variable handles miniVolts */ + +static int +read_num_sensor(picl_nodehdl_t childh, const char *prop, int scale, int *value) + { + picl_nodehdl_t sensorh; + picl_propinfo_t sensor_info; + picl_errno_t error_code; + int valid = 1; + + union valu { + char buf[PICL_PROPSIZE_MAX]; + uint32_t us4; + uint16_t us2; + int32_t is4; + int16_t is2; + float f; + } val; + + error_code = (picl_get_propinfo_by_name(childh, prop, + &sensor_info, &sensorh)); + + if (error_code != PICL_SUCCESS) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "sensor info lookup failed in read_num_sensor - error code->%d\n", error_code)); + return(error_code); + } + + error_code = picl_get_propval(sensorh, &val.buf, sensor_info.size); + + if (error_code != PICL_SUCCESS) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "sensor value lookup failed in read_num_sensor - error code->%d\n", error_code)); + return(error_code); + } + + /* Can't make assumptions about the type or size of the value we get... */ + + if (sensor_info.type == PICL_PTYPE_FLOAT) { + *value = (int)(val.f*scale); + } else if (sensor_info.type == PICL_PTYPE_UNSIGNED_INT) { + if (sensor_info.size == 2) { + *value = (int)(val.us2 * scale); + } else if (sensor_info.size == 4) { + *value = (int)(val.us4 * scale); + } else + valid = 0; + } else if (sensor_info.type == PICL_PTYPE_INT) { + if (sensor_info.size == 2) { + *value = (int)(val.is2 * scale); + } else if (sensor_info.size == 4) { + *value = (int)(val.is4 * scale); + } else + valid = 0; + } else + valid = 0; + + if (valid == 0) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "Don't know how to handle data type %d with length %d\n", + sensor_info.type, sensor_info.size)); + error_code = PICL_FAILURE; + } else + DEBUGMSGTL(("ucd-snmp/lmSensors", "read_num_sensor value is %d\n", *value)); + + return(error_code); +} /* end of read_num_sensor() */ + +static int +read_enum_sensor(picl_nodehdl_t childh, const char **options, u_int *value) +{ + picl_nodehdl_t sensorh; + picl_propinfo_t sensor_info; + picl_errno_t error_code; + char state[PICL_PROPSIZE_MAX]; + int i; + + error_code = (picl_get_propinfo_by_name(childh, "State", + &sensor_info, &sensorh)); + + if (error_code != PICL_SUCCESS) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "sensor info lookup failed in read_enum_sensor - error code->%d\n", error_code)); + return(error_code); + } + + error_code = picl_get_propval(sensorh, state, sensor_info.size); + + if (error_code != PICL_SUCCESS) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "sensor value lookup failed in read_enum_sensor - error code->%d\n", error_code)); + return(error_code); + } + + /* Start with error value, then try to fill in something better. + Use case-insensitive match to find the right value since platforms + may return either case. + */ + + *value = 99; + + for (i = 0; options[i] != NULL; i++){ + if (strncasecmp(state, options[i], strlen(options[i])) == 0){ + *value = i; + break; + } + } + + DEBUGMSGTL(("ucd-snmp/lmSensors", "read_enum_sensor value is %d\n", *value)); + return(error_code); +} /* end of read_enum_sensor() */ + +/* scale variable handles miniVolts*/ + +static void +process_num_sensor(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX], + const char propval[PICL_PROPNAMELEN_MAX], int typ, int scale) +{ + int value = 0; + picl_errno_t error_code; + + if (sensor_array[typ].n >= MAX_SENSORS){ + DEBUGMSGTL(("ucd-snmp/lmSensors", + "There are too many sensors of type %d\n",typ)); + } else{ + error_code = read_num_sensor(childh, propval, scale, &value); + + if (error_code == PICL_SUCCESS) { + sensor_array[typ].sensor[sensor_array[typ].n].value = value; + snprintf(sensor_array[typ].sensor[sensor_array[typ].n].name, + (PICL_PROPNAMELEN_MAX - 1),"%s",propname); + sensor_array[typ].sensor[sensor_array[typ].n]. + name[PICL_PROPNAMELEN_MAX - 1] = '\0'; + sensor_array[typ].n++; + } else + DEBUGMSGTL(("ucd-snmp/lmSensors", + "read of %s in process_num_sensor returned error code %d\n", propname, error_code)); + } +} /* end process_num_sensor() */ + +static void +process_enum_sensor(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX], + int typ, const char **options) +{ + int value = 0; + picl_errno_t error_code; + + if (sensor_array[typ].n >= MAX_SENSORS){ + DEBUGMSGTL(("ucd-snmp/lmSensors", + "There are too many sensors of type %d\n",typ)); + } else{ + error_code = read_enum_sensor(childh, options, &value); + + if (error_code == PICL_SUCCESS) { + sensor_array[typ].sensor[sensor_array[typ].n].value = value; + snprintf(sensor_array[typ].sensor[sensor_array[typ].n].name, + (PICL_PROPNAMELEN_MAX - 1),"%s",propname); + sensor_array[typ].sensor[sensor_array[typ].n]. + name[PICL_PROPNAMELEN_MAX - 1] = '\0'; + sensor_array[typ].n++; + } else + DEBUGMSGTL(("ucd-snmp/lmSensors", + "read of %s in process_enum_sensor returned error code %d\n", propname, error_code)); + } +} /* end process_enum_sensor() */ + +/* The following are modules for dealing with individual sensors types. + They call the generic modules above. */ + +static void +process_individual_fan(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + process_num_sensor(childh, propname, "AtoDSensorValue", FAN_TYPE, 1); +} + + +static void +process_newtype_fan(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + process_num_sensor(childh, propname, "Speed", FAN_TYPE, 1); +} + + +static void +process_temperature_sensor(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + process_num_sensor(childh, propname, "Temperature", TEMP_TYPE, 1000); +} /* MIB asks for mC */ + +static void +process_voltage_sensor(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + process_num_sensor(childh, propname, "Voltage", VOLT_TYPE, 1000); +} /* MIB asks for mV */ + +static void +process_digital_sensor(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + process_num_sensor(childh, propname, "AtoDSensorValue", VOLT_TYPE, 1); +} + + +static void +process_switch(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + + const char *settings[]={"OFF","ON","NORMAL","LOCKED","UNKNOWN", + "DIAG","SECURE",NULL}; + + process_enum_sensor(childh, propname, MISC_TYPE, settings); +} + +static void +process_led(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + + const char *settings[]={"OFF","ON","BLINK",NULL}; + process_enum_sensor(childh, propname, MISC_TYPE, settings); +} + +static void +process_i2c(picl_nodehdl_t childh, + const char propname[PICL_PROPNAMELEN_MAX]) +{ + const char *settings[]={"OK",NULL}; + process_enum_sensor(childh, propname, MISC_TYPE, settings); +} + +/* walks its way recusively through the tree of sensors */ + +static int +process_sensors(int level, picl_nodehdl_t nodeh) +{ + picl_nodehdl_t childh; + picl_nodehdl_t nexth; + + char propname[PICL_PROPNAMELEN_MAX]; + char propclass[PICL_CLASSNAMELEN_MAX]; + picl_errno_t error_code; + + level++; + + DEBUGMSGTL(("ucd-snmp/lmSensors","in process_sensors() level %d\n",level)); + + /* look up first child node */ + error_code = picl_get_propval_by_name(nodeh, PICL_PROP_CHILD, &childh, + sizeof (picl_nodehdl_t)); + if (error_code != PICL_SUCCESS) { + DEBUGMSGTL(("ucd-snmp/lmSensors", + "picl_get_propval_by_name(%s) %d\n", + PICL_PROP_CHILD, error_code)); + return (error_code); + } + + /* step through child nodes, get the name first */ + while (error_code == PICL_SUCCESS) { + + error_code = picl_get_propval_by_name(childh, PICL_PROP_NAME, + propname, (PICL_PROPNAMELEN_MAX - 1)); + if (error_code != PICL_SUCCESS) { /*we found a node with no name. Impossible.! */ + DEBUGMSGTL(("ucd-snmp/lmSensors", + "picl_get_propval_by_name(%s) = %d\n", + PICL_PROP_NAME, error_code)); + return (error_code); + } + + error_code = picl_get_propval_by_name(childh, PICL_PROP_CLASSNAME, + propclass, sizeof (propclass)); + if (error_code != PICL_SUCCESS) { /*we found a node with no class. Impossible.! */ + DEBUGMSGTL(("ucd-snmp/lmSensors", + "picl_get_propval_by_name(%s) = %d\n", + PICL_PROP_CLASSNAME, error_code)); + return (error_code); + } + + DEBUGMSGTL(("ucd-snmp/lmSensors","found %s of class %s\n",propname,propclass)); + + if (strstr(propclass,"fan-tachometer")) + process_individual_fan(childh,propname); + else if (strstr(propclass,"fan")) + process_newtype_fan(childh,propname); + else if (strstr(propclass,"temperature-sensor")) + process_temperature_sensor(childh,propname); + else if (strstr(propclass,"voltage-sensor")) + process_voltage_sensor(childh,propname); + else if (strstr(propclass,"digital-sensor")) + process_digital_sensor(childh,propname); + else if (strstr(propclass,"switch")) + process_switch(childh,propname); + else if (strstr(propclass,"led")) + process_led(childh,propname); + else if (strstr(propclass,"i2c")) + process_i2c(childh,propname); +/* + else if (strstr(propclass,"gpio")) + process_gpio(childh,propname); +*/ + + + /* look for children of children (note, this is recursive) */ + if (!(strstr(propclass,"picl") && + (strstr(propname,"frutree") || strstr(propname,"obp")))) { + error_code = process_sensors(level,childh); + DEBUGMSGTL(("ucd-snmp/lmSensors", + "process_sensors(%s) returned %d\n", + propname, error_code)); + } + + /* get next child node at this level*/ + error_code = picl_get_propval_by_name(childh, PICL_PROP_PEER, + &nexth, sizeof (picl_nodehdl_t)); + if (error_code != PICL_SUCCESS) {/* no more children - buh bye*/ + DEBUGMSGTL(("ucd-snmp/lmSensors","Process sensors is out of children! Returning...\n")); + return (error_code); + } + + childh = nexth; + + } /* while */ + return (error_code); +} /* process sensors */ + +#endif +/* ******** end of picld sensor procedures * */ + +#endif /* solaris2 */ +static int +_sensor_load(time_t t) +{ +#ifdef solaris2 + int i,j; +#ifdef HAVE_PICL_H + int er_code; + picl_errno_t error_code; + int level=0; + picl_nodehdl_t rooth; +#else + int typ; + int temp=0; /* do not reset this later, more than one typ has temperatures*/ + int other=0; + const char *fantypes[]={"CPU","PWR","AFB"}; + kstat_ctl_t *kc; + kstat_t *kp; + envctrl_fan_t *fan_info; + envctrl_ps_t *power_info; + envctrl_encl_t *enc_info; +#endif + +/* DEBUGMSG(("ucd-snmp/lmSensors", "Reading the sensors\n")); */ + +/* initialize the array */ + for (i = 0; i < N_TYPES; i++){ + sensor_array[i].n = 0; + for (j=0; j < MAX_SENSORS; j++){ + sensor_array[i].sensor[j].name[0] = '\0'; + sensor_array[i].sensor[j].value = 0; + } + } /*end for i*/ + +/* try picld (if supported), if that doesn't work, try kstat */ +#ifdef HAVE_PICL_H + +er_code = picl_initialize(); + +if (er_code == PICL_SUCCESS) { + + error_code = picl_get_root(&rooth); + + if (error_code != PICL_SUCCESS) { + DEBUGMSG(("ucd-snmp/lmSensors", "picld couldn't get root error code->%d\n",error_code)); + } + else{ + DEBUGMSGTL(("ucd-snmp/lmSensors", "found root\n")); + error_code = process_sensors(level,rooth); + if (error_code != 255) + if (error_code != 7) + DEBUGMSG(("ucd-snmp/lmSensors", "picld had an internal problem error code->%d\n",error_code)); + } /* end else */ + + picl_shutdown(); + +} /* end if err_code for picl_initialize */ + +else { + DEBUGMSG(("ucd-snmp/lmSensors", "picld couldn't initialize picld because error code->%d\n",er_code)); + +} /*end else picl_initialize */ + +#else /* end of picld section */ +/* initialize kstat */ + +kc = kstat_open(); +if (kc == 0) { + DEBUGMSG(("ucd-snmp/lmSensors", "couldn't open kstat")); + } /* endif kc */ +else{ + temp = 0; + kp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, 0, ENVCTRL_KSTAT_FANSTAT); + if (kp == 0) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't lookup fan kstat\n")); + } /* endif lookup fans */ + else{ + if (kstat_read(kc, kp, 0) == -1) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't read fan kstat")); + } /* endif kstatread fan */ + else{ + typ = 1; + fan_info = (envctrl_fan_t *) kp->ks_data; + sensor_array[typ].n = kp->ks_ndata; + for (i=0; i < kp->ks_ndata; i++){ + DEBUGMSG(("ucd-snmp/lmSensors", "found instance %d fan type %d speed %d OK %d bustedfan %d\n", + fan_info->instance, fan_info->type,fan_info->fanspeed,fan_info->fans_ok,fan_info->fanflt_num)); + sensor_array[typ].sensor[i].value = fan_info->fanspeed; + snprintf(sensor_array[typ].sensor[i].name,(MAX_NAME - 1), + "fan type %s number %d",fantypes[fan_info->type],fan_info->instance); + sensor_array[typ].sensor[i].name[MAX_NAME - 1] = '\0'; + fan_info++; + } /* end for fan_info */ + } /* end else kstatread fan */ + } /* end else lookup fans*/ + + + kp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, 0, ENVCTRL_KSTAT_PSNAME); + if (kp == 0) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't lookup power supply kstat\n")); + } /* endif lookup power supply */ + else{ + if (kstat_read(kc, kp, 0) == -1) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't read power supply kstat\n")); + } /* endif kstatread fan */ + else{ + typ = 0; /* this is a power supply temperature, not a voltage*/ + power_info = (envctrl_ps_t *) kp->ks_data; + sensor_array[typ].n = kp->ks_ndata; + for (i=0; i < kp->ks_ndata; i++){ + DEBUGMSG(("ucd-snmp/lmSensors", "found instance %d psupply temp mC %d %dW OK %d share %d limit %d\n", + power_info->instance, power_info->ps_tempr*1000,power_info->ps_rating, + power_info->ps_ok,power_info->curr_share_ok,power_info->limit_ok)); + sensor_array[typ].sensor[temp].value = power_info->ps_tempr*1000; + snprintf(sensor_array[typ].sensor[temp].name,(MAX_NAME-1), + "power supply %d",power_info->instance); + sensor_array[typ].sensor[temp].name[MAX_NAME - 1] = '\0'; + power_info++; /* increment the data structure */ + temp++; /* increment the temperature sensor array element */ + } /* end for power_info */ + } /* end else kstatread power supply */ + } /* end else lookup power supplies*/ + + kp = kstat_lookup(kc, ENVCTRL_MODULE_NAME, 0, ENVCTRL_KSTAT_ENCL); + if (kp == 0) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't lookup enclosure kstat\n")); + } /* endif lookup enclosure */ + else{ + if (kstat_read(kc, kp, 0) == -1) { + DEBUGMSGTL(("ucd-snmp/lmSensors", "couldn't read enclosure kstat\n")); + } /* endif kstatread enclosure */ + else{ + enc_info = (envctrl_encl_t *) kp->ks_data; + other = 0; + for (i=0; i < kp->ks_ndata; i++){ + switch (enc_info->type){ + case ENVCTRL_ENCL_FSP: + DEBUGMSG(("ucd-snmp/lmSensors", "front panel value %d\n",enc_info->value)); + typ = 3; /* misc */ + sensor_array[typ].sensor[other].value = enc_info->value; + strlcpy(sensor_array[typ].sensor[other].name, "FSP", + MAX_NAME); + other++; + break; + case ENVCTRL_ENCL_AMBTEMPR: + DEBUGMSG(("ucd-snmp/lmSensors", "ambient temp mC %d\n",enc_info->value*1000)); + typ = 0; /* temperature sensor */ + sensor_array[typ].sensor[temp].value = enc_info->value*1000; + strlcpy(sensor_array[typ].sensor[temp].name, "Ambient", + MAX_NAME); + temp++; + break; + case ENVCTRL_ENCL_BACKPLANE4: + DEBUGMSG(("ucd-snmp/lmSensors", "There is a backplane4\n")); + typ = 3; /* misc */ + sensor_array[typ].sensor[other].value = enc_info->value; + strlcpy(sensor_array[typ].sensor[other].name, "Backplane4", + MAX_NAME); + other++; + break; + case ENVCTRL_ENCL_BACKPLANE8: + DEBUGMSG(("ucd-snmp/lmSensors", "There is a backplane8\n")); + typ = 3; /* misc */ + sensor_array[typ].sensor[other].value = enc_info->value; + strlcpy(sensor_array[typ].sensor[other].name, "Backplane8", + MAX_NAME); + other++; + break; + case ENVCTRL_ENCL_CPUTEMPR: + DEBUGMSG(("ucd-snmp/lmSensors", "CPU%d temperature mC %d\n",enc_info->instance,enc_info->value*1000)); + typ = 0; /* temperature sensor */ + sensor_array[typ].sensor[temp].value = enc_info->value*1000; + snprintf(sensor_array[typ].sensor[temp].name,MAX_NAME,"CPU%d",enc_info->instance); + sensor_array[typ].sensor[temp].name[MAX_NAME-1]='\0'; /* null terminate */ + temp++; + break; + default: + DEBUGMSG(("ucd-snmp/lmSensors", "unknown element instance %d type %d value %d\n", + enc_info->instance, enc_info->type, enc_info->value)); + break; + } /* end switch */ + enc_info++; + } /* end for enc_info */ + sensor_array[3].n = other; + sensor_array[0].n = temp; + } /* end else kstatread enclosure */ + } /* end else lookup enclosure*/ + + kstat_close(kc); + +} /* end else kstat */ +#endif + +#else /* end solaris2 only ie. ifdef everything else */ + + const sensors_chip_name *chip; + const sensors_feature_data *data; + int chip_nr = 0; + unsigned int i = 0; + + DEBUGMSG(("ucd-snmp/lmSensors", "=> sensor_load\n")); + + for (i = 0; i < N_TYPES; i++) + { + sensor_array[i].n = 0; + sensor_array[i].current_len = 0; + + /* Malloc the default number of sensors. */ + sensor_array[i].sensor = (_sensor*)malloc(sizeof(_sensor) * DEFAULT_SENSORS); + if (sensor_array[i].sensor == NULL) + { + /* Continuing would be unsafe */ + snmp_log(LOG_ERR, "Cannot malloc sensor array!"); + return 1; + } /* end if */ + sensor_array[i].current_len = DEFAULT_SENSORS; + } /* end for */ + + while ((chip = sensors_get_detected_chips(&chip_nr))) { + int a = 0; + int b = 0; + + while ((data = sensors_get_all_features(*chip, &a, &b))) { + char *label = NULL; + double val; + + if ((data->mode & SENSORS_MODE_R) && + (data->mapping == SENSORS_NO_MAPPING) && + !sensors_get_label(*chip, data->number, &label) && + !sensors_get_feature(*chip, data->number, &val)) { + int type = -1; + float mul = 0; + _sensor_array *array; + + /* The label, as determined for a given chip in sensors.conf, + * is used to place each sensor in the appropriate bucket. + * Volt, Fan, Temp, and Misc. If the text being looked for below + * is not in the label of a given sensor (e.g., the temp1 sensor + * has been labeled 'CPU' and not 'CPU temp') it will end up being + * lumped in the MISC bucket. */ + + if (strstr(label, "V")) { + type = VOLT_TYPE; + mul = 1000.0; + } + if (strstr(label, "fan") || strstr(label, "Fan")) { + type = FAN_TYPE; + mul = 1.0; + } + if (strstr(label, "temp") || strstr(label, "Temp")) { + type = TEMP_TYPE; + mul = 1000.0; + } + if (type == -1) { + type = MISC_TYPE; + mul = 1000.0; + } + + array = &sensor_array[type]; + if ( array->current_len <= array->n) { + _sensor* old_buffer = array->sensor; + size_t new_size = (sizeof(_sensor) * array->current_len) + (sizeof(_sensor) * DEFAULT_SENSORS); + array->sensor = (_sensor*)realloc(array->sensor, new_size); + if (array->sensor == NULL) + { + /* Continuing would be unsafe */ + snmp_log(LOG_ERR, "too many sensors to fit, and failed to alloc more, failing on %s\n", label); + free(old_buffer); + old_buffer = NULL; + if (label) { + free(label); + label = NULL; + } /* end if label */ + return 1; + } /* end if array->sensor */ + array->current_len = new_size / sizeof(_sensor); + DEBUGMSG(("ucd-snmp/lmSensors", "type #%d increased to %d elements\n", type, (int)array->current_len)); + } /* end if array->current */ + strlcpy(array->sensor[array->n].name, label, MAX_NAME); + array->sensor[array->n].value = (int) (val * mul); + DEBUGMSGTL(("sensors","sensor %s, value %d\n", + array->sensor[array->n].name, + array->sensor[array->n].value)); + array->n++; + } /* end if data-mode */ + if (label) { + free(label); + label = NULL; + } /* end if label */ + } /* end while data */ + } /* end while chip */ + DEBUGMSG(("ucd-snmp/lmSensors", "<= sensor_load\n")); +#endif /* end else ie. ifdef everything else */ + /* Update the timestamp after a load. */ + timestamp = t; + return 0; +} + +#ifndef solaris2 +/* Free all the sensor arrays. */ +static void +free_sensor_arrays() +{ + unsigned int i = 0; + DEBUGMSG(("ucd-snmp/lmSensors", "=> free_sensor_arrays\n")); + for (i = 0; i < N_TYPES; i++){ + if (sensor_array[i].sensor != NULL) + { + free(sensor_array[i].sensor); + sensor_array[i].sensor = NULL; + } + /* For good measure, reset the other values. */ + sensor_array[i].n = 0; + sensor_array[i].current_len = 0; + } + DEBUGMSG(("ucd-snmp/lmSensors", "<= free_sensor_arrays\n")); +} +#endif |