summaryrefslogtreecommitdiff
path: root/agent/mibgroup/ucd-snmp/lmSensors.c
diff options
context:
space:
mode:
Diffstat (limited to 'agent/mibgroup/ucd-snmp/lmSensors.c')
-rw-r--r--agent/mibgroup/ucd-snmp/lmSensors.c1071
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