/* 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 #include #include #include /* * minimal include directives */ #include "util_funcs/header_simple_table.h" #include netsnmp_feature_require(table_container); /* * Load required drivers and libraries. */ #ifdef solaris2 #include #ifdef HAVE_PICL_H #include /* accesses the picld daemon */ #else /* the following should be sufficient for any Sun-based sensors */ #include #endif #else #include #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