X-Git-Url: https://git.octo.it/?a=blobdiff_plain;f=src%2Fsensors.c;h=1289d4b68177b1f75483712146591854168f92b0;hb=8461fc51ea1af63b4d51c106d128716ecf95bf10;hp=75981e84854ce1c4ae8b012169e73b3c7028cdf8;hpb=55b439475d492599de5134536710180b39dac593;p=collectd.git diff --git a/src/sensors.c b/src/sensors.c index 75981e84..1289d4b6 100644 --- a/src/sensors.c +++ b/src/sensors.c @@ -1,11 +1,10 @@ /** * collectd - src/sensors.c - * Copyright (C) 2005 Florian octo Forster + * Copyright (C) 2005-2007 Florian octo Forster * * This program is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or (at your - * option) any later version. + * Free Software Foundation; only version 2 of the License is applicable. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of @@ -18,187 +17,556 @@ * * Authors: * Florian octo Forster + * + * Lubos Stanek Wed Oct 27, 2006 + * - config ExtendedSensorNaming option + * - precise sensor feature selection (chip-bus-address/type-feature) + * with ExtendedSensorNaming + * - more sensor features (finite list) + * - honor sensors.conf's ignored + * - config Sensor option + * - config IgnoreSelected option **/ #include "collectd.h" #include "common.h" #include "plugin.h" - -#define MODULE_NAME "sensors" +#include "configfile.h" +#include "utils_ignorelist.h" #if defined(HAVE_SENSORS_SENSORS_H) # include -#else -# undef HAVE_LIBSENSORS #endif -#if defined(HAVE_LIBSENSORS) -# define SENSORS_HAVE_READ 1 -#else -# define SENSORS_HAVE_READ 0 +#if !defined(SENSORS_API_VERSION) +# define SENSORS_API_VERSION 0x000 #endif -#define BUFSIZE 512 +/* + * The sensors library prior to version 3.0 (internal version 0x400) didn't + * report the type of values, only a name. The following lists are there to + * convert from the names to the type. They are not used with the new + * interface. + */ +#if SENSORS_API_VERSION < 0x400 +static char *sensor_type_name_map[] = +{ +# define SENSOR_TYPE_VOLTAGE 0 + "voltage", +# define SENSOR_TYPE_FANSPEED 1 + "fanspeed", +# define SENSOR_TYPE_TEMPERATURE 2 + "temperature", +# define SENSOR_TYPE_UNKNOWN 3 + NULL +}; -static char *filename_format = "sensors-%s.rrd"; +struct sensors_labeltypes_s +{ + char *label; + int type; +}; +typedef struct sensors_labeltypes_s sensors_labeltypes_t; -static char *ds_def[] = +/* finite list of known labels extracted from lm_sensors */ +static sensors_labeltypes_t known_features[] = { - "DS:value:GAUGE:25:U:U", - NULL + { "fan1", SENSOR_TYPE_FANSPEED }, + { "fan2", SENSOR_TYPE_FANSPEED }, + { "fan3", SENSOR_TYPE_FANSPEED }, + { "fan4", SENSOR_TYPE_FANSPEED }, + { "fan5", SENSOR_TYPE_FANSPEED }, + { "fan6", SENSOR_TYPE_FANSPEED }, + { "fan7", SENSOR_TYPE_FANSPEED }, + { "AIN2", SENSOR_TYPE_VOLTAGE }, + { "AIN1", SENSOR_TYPE_VOLTAGE }, + { "in10", SENSOR_TYPE_VOLTAGE }, + { "in9", SENSOR_TYPE_VOLTAGE }, + { "in8", SENSOR_TYPE_VOLTAGE }, + { "in7", SENSOR_TYPE_VOLTAGE }, + { "in6", SENSOR_TYPE_VOLTAGE }, + { "in5", SENSOR_TYPE_VOLTAGE }, + { "in4", SENSOR_TYPE_VOLTAGE }, + { "in3", SENSOR_TYPE_VOLTAGE }, + { "in2", SENSOR_TYPE_VOLTAGE }, + { "in0", SENSOR_TYPE_VOLTAGE }, + { "CPU_Temp", SENSOR_TYPE_TEMPERATURE }, + { "remote_temp", SENSOR_TYPE_TEMPERATURE }, + { "temp1", SENSOR_TYPE_TEMPERATURE }, + { "temp2", SENSOR_TYPE_TEMPERATURE }, + { "temp3", SENSOR_TYPE_TEMPERATURE }, + { "temp4", SENSOR_TYPE_TEMPERATURE }, + { "temp5", SENSOR_TYPE_TEMPERATURE }, + { "temp6", SENSOR_TYPE_TEMPERATURE }, + { "temp7", SENSOR_TYPE_TEMPERATURE }, + { "temp", SENSOR_TYPE_TEMPERATURE }, + { "Vccp2", SENSOR_TYPE_VOLTAGE }, + { "Vccp1", SENSOR_TYPE_VOLTAGE }, + { "vdd", SENSOR_TYPE_VOLTAGE }, + { "vid5", SENSOR_TYPE_VOLTAGE }, + { "vid4", SENSOR_TYPE_VOLTAGE }, + { "vid3", SENSOR_TYPE_VOLTAGE }, + { "vid2", SENSOR_TYPE_VOLTAGE }, + { "vid1", SENSOR_TYPE_VOLTAGE }, + { "vid", SENSOR_TYPE_VOLTAGE }, + { "vin4", SENSOR_TYPE_VOLTAGE }, + { "vin3", SENSOR_TYPE_VOLTAGE }, + { "vin2", SENSOR_TYPE_VOLTAGE }, + { "vin1", SENSOR_TYPE_VOLTAGE }, + { "voltbatt", SENSOR_TYPE_VOLTAGE }, + { "volt12", SENSOR_TYPE_VOLTAGE }, + { "volt5", SENSOR_TYPE_VOLTAGE }, + { "vrm", SENSOR_TYPE_VOLTAGE }, + { "5.0V", SENSOR_TYPE_VOLTAGE }, + { "5V", SENSOR_TYPE_VOLTAGE }, + { "3.3V", SENSOR_TYPE_VOLTAGE }, + { "2.5V", SENSOR_TYPE_VOLTAGE }, + { "2.0V", SENSOR_TYPE_VOLTAGE }, + { "12V", SENSOR_TYPE_VOLTAGE } }; -static int ds_num = 1; +static int known_features_num = STATIC_ARRAY_SIZE (known_features); +/* end new naming */ +#endif /* SENSORS_API_VERSION < 0x400 */ -#ifdef HAVE_LIBSENSORS +static const char *config_keys[] = +{ + "Sensor", + "IgnoreSelected" +}; +static int config_keys_num = STATIC_ARRAY_SIZE (config_keys); + +#if SENSORS_API_VERSION < 0x400 typedef struct featurelist { const sensors_chip_name *chip; const sensors_feature_data *data; + int type; + struct featurelist *next; +} featurelist_t; + +# ifndef SENSORS_CONF_PATH +# define SENSORS_CONF_PATH "/etc/sensors.conf" +# endif +/* #endif SENSORS_API_VERSION < 0x400 */ + +#elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) +typedef struct featurelist +{ + const sensors_chip_name *chip; + const sensors_feature *feature; + const sensors_subfeature *subfeature; struct featurelist *next; } featurelist_t; +# ifndef SENSORS_CONF_PATH +# define SENSORS_CONF_PATH "/etc/sensors3.conf" +# endif +/* #endif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */ + +#else /* if SENSORS_API_VERSION >= 0x500 */ +# error "This version of libsensors is not supported yet. Please report this " \ + "as bug." +#endif + +static const char *conffile = SENSORS_CONF_PATH; featurelist_t *first_feature = NULL; -#endif /* defined (HAVE_LIBSENSORS) */ +static ignorelist_t *sensor_list; +static time_t sensors_config_mtime = 0; + +#if SENSORS_API_VERSION < 0x400 +/* full chip name logic borrowed from lm_sensors */ +static int sensors_snprintf_chip_name (char *buf, size_t buf_size, + const sensors_chip_name *chip) +{ + int status = -1; + + if (chip->bus == SENSORS_CHIP_NAME_BUS_ISA) + { + status = snprintf (buf, buf_size, + "%s-isa-%04x", + chip->prefix, + chip->addr); + } + else if (chip->bus == SENSORS_CHIP_NAME_BUS_DUMMY) + { + snprintf (buf, buf_size, "%s-%s-%04x", + chip->prefix, + chip->busname, + chip->addr); + } + else + { + snprintf (buf, buf_size, "%s-i2c-%d-%02x", + chip->prefix, + chip->bus, + chip->addr); + } + + return (status); +} /* int sensors_snprintf_chip_name */ -static void collectd_sensors_init (void) +static int sensors_feature_name_to_type (const char *name) +{ + int i; + + /* Yes, this is slow, but it's only ever done during initialization, so + * it's a one time cost.. */ + for (i = 0; i < known_features_num; i++) + if (strcasecmp (known_features[i].label, name) == 0) + return (known_features[i].type); + + return (SENSOR_TYPE_UNKNOWN); +} /* int sensors_feature_name_to_type */ +#endif + +static int sensors_config (const char *key, const char *value) +{ + if (sensor_list == NULL) + sensor_list = ignorelist_create (1); + + if (strcasecmp (key, "Sensor") == 0) + { + if (ignorelist_add (sensor_list, value)) + { + ERROR ("sensors plugin: " + "Cannot add value to ignorelist."); + return (1); + } + } + else if (strcasecmp (key, "IgnoreSelected") == 0) + { + ignorelist_set_invert (sensor_list, 1); + if ((strcasecmp (value, "True") == 0) + || (strcasecmp (value, "Yes") == 0) + || (strcasecmp (value, "On") == 0)) + ignorelist_set_invert (sensor_list, 0); + } + else + { + return (-1); + } + + return (0); +} + +void sensors_free_features (void) +{ + featurelist_t *thisft; + featurelist_t *nextft; + + if (first_feature == NULL) + return; + + sensors_cleanup (); + + for (thisft = first_feature; thisft != NULL; thisft = nextft) + { + nextft = thisft->next; + sfree (thisft); + } + first_feature = NULL; +} + +static int sensors_load_conf (void) { -#ifdef HAVE_LIBSENSORS FILE *fh; featurelist_t *last_feature = NULL; - featurelist_t *new_feature; const sensors_chip_name *chip; int chip_num; - const sensors_feature_data *data; - int data_num0, data_num1; + struct stat statbuf; + int status; - new_feature = first_feature; - while (new_feature != NULL) + status = stat (conffile, &statbuf); + if (status != 0) { - last_feature = new_feature->next; - free (new_feature); - new_feature = last_feature; + char errbuf[1024]; + ERROR ("sensors plugin: stat (%s) failed: %s", conffile, + sstrerror (errno, errbuf, sizeof (errbuf))); + sensors_config_mtime = 0; } -#ifdef assert - assert (new_feature == NULL); - assert (last_feature == NULL); -#endif + if ((sensors_config_mtime != 0) + && (sensors_config_mtime == statbuf.st_mtime)) + return (0); - if ((fh = fopen ("/etc/sensors.conf", "r")) == NULL) - return; + if (sensors_config_mtime != 0) + { + NOTICE ("sensors plugin: Reloading config from %s", + conffile); + sensors_free_features (); + sensors_config_mtime = 0; + } - if (sensors_init (fh)) + fh = fopen (conffile, "r"); + if (fh == NULL) { - fclose (fh); - syslog (LOG_ERR, "sensors: Cannot initialize sensors. Data will not be collected."); - return; + char errbuf[1024]; + ERROR ("sensors plugin: fopen(%s) failed: %s", conffile, + sstrerror (errno, errbuf, sizeof (errbuf))); + return (-1); } + status = sensors_init (fh); fclose (fh); + if (status != 0) + { + ERROR ("sensors plugin: Cannot initialize sensors. " + "Data will not be collected."); + return (-1); + } + sensors_config_mtime = statbuf.st_mtime; + +#if SENSORS_API_VERSION < 0x400 chip_num = 0; while ((chip = sensors_get_detected_chips (&chip_num)) != NULL) { - data = NULL; - data_num0 = data_num1 = 0; + int feature_num0 = 0; + int feature_num1 = 0; - while ((data = sensors_get_all_features (*chip, &data_num0, &data_num1)) != NULL) + while (42) { + const sensors_feature_data *feature; + int feature_type; + featurelist_t *fl; + + feature = sensors_get_all_features (*chip, + &feature_num0, &feature_num1); + + /* Check if all features have been read. */ + if (feature == NULL) + break; + /* "master features" only */ - if (data->mapping != SENSORS_NO_MAPPING) + if (feature->mapping != SENSORS_NO_MAPPING) continue; - /* Only temperature for now.. */ - if (strncmp (data->name, "temp", 4) - && strncmp (data->name, "fan", 3)) + /* skip ignored in sensors.conf */ + if (sensors_get_ignored (*chip, feature->number) == 0) + break; + + feature_type = sensors_feature_name_to_type ( + feature->name); + if (feature_type == SENSOR_TYPE_UNKNOWN) continue; - if ((new_feature = (featurelist_t *) malloc (sizeof (featurelist_t))) == NULL) + fl = (featurelist_t *) malloc (sizeof (featurelist_t)); + if (fl == NULL) { - perror ("malloc"); + ERROR ("sensors plugin: malloc failed."); continue; } + memset (fl, '\0', sizeof (featurelist_t)); - /* - syslog (LOG_INFO, "sensors: Adding feature: %s/%s", chip->prefix, data->name); - */ - - new_feature->chip = chip; - new_feature->data = data; - new_feature->next = NULL; + fl->chip = chip; + fl->data = feature; + fl->type = feature_type; if (first_feature == NULL) - { - first_feature = new_feature; - last_feature = new_feature; - } + first_feature = fl; else + last_feature->next = fl; + last_feature = fl; + } /* while sensors_get_all_features */ + } /* while sensors_get_detected_chips */ +/* #endif SENSORS_API_VERSION < 0x400 */ + +#elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) + chip_num = 0; + while ((chip = sensors_get_detected_chips (NULL, &chip_num)) != NULL) + { + const sensors_feature *feature; + int feature_num = 0; + + while ((feature = sensors_get_features (chip, &feature_num)) != NULL) + { + const sensors_subfeature *subfeature; + int subfeature_num = 0; + + /* Only handle voltage, fanspeeds and temperatures */ + if ((feature->type != SENSORS_FEATURE_IN) + && (feature->type != SENSORS_FEATURE_FAN) + && (feature->type != SENSORS_FEATURE_TEMP)) + continue; + + while ((subfeature = sensors_get_all_subfeatures (chip, + feature, &subfeature_num)) != NULL) { - last_feature->next = new_feature; - last_feature = new_feature; - } - } - } + featurelist_t *fl; + + if ((subfeature->type != SENSORS_SUBFEATURE_IN_INPUT) + && (subfeature->type != SENSORS_SUBFEATURE_FAN_INPUT) + && (subfeature->type != SENSORS_SUBFEATURE_TEMP_INPUT)) + continue; + + fl = (featurelist_t *) malloc (sizeof (featurelist_t)); + if (fl == NULL) + { + ERROR ("sensors plugin: malloc failed."); + continue; + } + memset (fl, '\0', sizeof (featurelist_t)); + + fl->chip = chip; + fl->feature = feature; + fl->subfeature = subfeature; + + if (first_feature == NULL) + first_feature = fl; + else + last_feature->next = fl; + last_feature = fl; + } /* while (subfeature) */ + } /* while (feature) */ + } /* while (chip) */ +#endif /* (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */ if (first_feature == NULL) + { sensors_cleanup (); -#endif /* defined(HAVE_LIBSENSORS) */ + INFO ("sensors plugin: lm_sensors reports no " + "features. Data will not be collected."); + return (-1); + } - return; -} + return (0); +} /* int sensors_load_conf */ + +static int sensors_shutdown (void) +{ + sensors_free_features (); + ignorelist_free (sensor_list); + + return (0); +} /* int sensors_shutdown */ -static void sensors_write (char *host, char *inst, char *val) +static void sensors_submit (const char *plugin_instance, + const char *type, const char *type_instance, + double val) { - char file[BUFSIZE]; + char match_key[1024]; int status; - status = snprintf (file, BUFSIZE, filename_format, inst); + value_t values[1]; + value_list_t vl = VALUE_LIST_INIT; + + status = snprintf (match_key, sizeof (match_key), "%s/%s-%s", + plugin_instance, type, type_instance); if (status < 1) return; - else if (status >= BUFSIZE) - return; + match_key[sizeof (match_key) - 1] = '\0'; - rrd_update_file (host, file, val, ds_def, ds_num); -} + if (sensor_list != NULL) + { + DEBUG ("sensors plugin: Checking ignorelist for `%s'", match_key); + if (ignorelist_match (sensor_list, match_key)) + return; + } -#if SENSORS_HAVE_READ -static void sensors_submit (const char *feat_name, const char *chip_prefix, double value) -{ - char buf[BUFSIZE]; - char inst[BUFSIZE]; + values[0].gauge = val; - if (snprintf (buf, BUFSIZE, "%u:%.3f", (unsigned int) curtime, value) >= BUFSIZE) - return; + vl.values = values; + vl.values_len = 1; + vl.time = time (NULL); - if (snprintf (inst, BUFSIZE, "%s-%s", chip_prefix, feat_name) >= BUFSIZE) - return; + strncpy (vl.host, hostname_g, sizeof (vl.host)); + vl.host[sizeof (vl.host) - 1] = '\0'; + strncpy (vl.plugin, "sensors", sizeof (vl.plugin)); + vl.plugin[sizeof (vl.plugin) - 1] = '\0'; + strncpy (vl.plugin_instance, plugin_instance, + sizeof (vl.plugin_instance)); + vl.plugin_instance[sizeof (vl.plugin_instance) - 1] = '\0'; + strncpy (vl.type_instance, type_instance, sizeof (vl.type_instance)); + vl.type_instance[sizeof (vl.type_instance) - 1] = '\0'; - plugin_submit (MODULE_NAME, inst, buf); -} + plugin_dispatch_values (type, &vl); +} /* void sensors_submit */ -static void sensors_read (void) +static int sensors_read (void) { - featurelist_t *feature; - double value; + featurelist_t *fl; + + if (sensors_load_conf () != 0) + return (-1); - for (feature = first_feature; feature != NULL; feature = feature->next) +#if SENSORS_API_VERSION < 0x400 + for (fl = first_feature; fl != NULL; fl = fl->next) { - if (sensors_get_feature (*feature->chip, feature->data->number, &value) < 0) + double value; + int status; + char plugin_instance[DATA_MAX_NAME_LEN]; + char type_instance[DATA_MAX_NAME_LEN]; + + status = sensors_get_feature (*fl->chip, + fl->data->number, &value); + if (status < 0) continue; - sensors_submit (feature->data->name, feature->chip->prefix, value); - } -} -#else -# define sensors_read NULL -#endif /* SENSORS_HAVE_READ */ + status = sensors_snprintf_chip_name (plugin_instance, + sizeof (plugin_instance), fl->chip); + if (status < 0) + continue; + plugin_instance[sizeof (plugin_instance) - 1] = '\0'; + + strncpy (type_instance, fl->data->name, + sizeof (type_instance)); + type_instance[sizeof (type_instance) - 1] = '\0'; + + sensors_submit (plugin_instance, + sensor_type_name_map[fl->type], + type_instance, + value); + } /* for fl = first_feature .. NULL */ +/* #endif SENSORS_API_VERSION < 0x400 */ + +#elif (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) + for (fl = first_feature; fl != NULL; fl = fl->next) + { + double value; + int status; + char plugin_instance[DATA_MAX_NAME_LEN]; + char type_instance[DATA_MAX_NAME_LEN]; + const char *type; + + status = sensors_get_value (fl->chip, + fl->subfeature->number, &value); + if (status < 0) + continue; + + status = sensors_snprintf_chip_name (plugin_instance, + sizeof (plugin_instance), fl->chip); + if (status < 0) + continue; + plugin_instance[sizeof (plugin_instance) - 1] = '\0'; + + strncpy (type_instance, fl->feature->name, + sizeof (type_instance)); + type_instance[sizeof (type_instance) - 1] = '\0'; + + if (fl->feature->type == SENSORS_FEATURE_IN) + type = "voltage"; + else if (fl->feature->type + == SENSORS_FEATURE_FAN) + type = "fanspeed"; + else if (fl->feature->type + == SENSORS_FEATURE_TEMP) + type = "input"; + else + continue; + + sensors_submit (plugin_instance, type, type_instance, value); + } /* for fl = first_feature .. NULL */ +#endif /* (SENSORS_API_VERSION >= 0x400) && (SENSORS_API_VERSION < 0x500) */ + + return (0); +} /* int sensors_read */ void module_register (void) { - plugin_register (MODULE_NAME, collectd_sensors_init, sensors_read, sensors_write); -} - -#undef BUFSIZE -#undef MODULE_NAME + plugin_register_config ("sensors", sensors_config, + config_keys, config_keys_num); + plugin_register_read ("sensors", sensors_read); + plugin_register_shutdown ("sensors", sensors_shutdown); +} /* void module_register */