/* * Copyright (C) 2005 Alex Murray * * 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. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #ifdef HAVE_ASSERT_H #include #endif #ifdef HAVE_SYS_TYPES_H #include #endif #ifdef HAVE_REGEX_H #include #endif #ifdef HAVE_SENSORS_SENSORS_H #include #endif #include "libsensors-sensors-interface.h" #define LIBSENSORS_CONFIG_FILE "/etc/sensors.conf" #define LIBSENSORS_ALTERNATIVE_CONFIG_FILE "/usr/local/etc/sensors.conf" /* this is useful for coming up with new regular expressions: */ #if 0 awk '$1 == "label"' /etc/sensors.conf | sed -e 's/^[^"]*"//' -e 's/".*//' | grep -iv -f regexes | sort -u #endif #define VOLTAGE_EXPS_LENGTH 7 static const char *volt_exps[VOLTAGE_EXPS_LENGTH] = { "vcore", "[0-9]v", "^v", "avdd", "stdby", "batt", "chan" }; static regex_t volt_exps_comp[VOLTAGE_EXPS_LENGTH]; #define FAN_EXPS_LENGTH 1 static const char *fan_exps[FAN_EXPS_LENGTH] = { "fan" }; static regex_t fan_exps_comp[FAN_EXPS_LENGTH]; #define TEMP_EXPS_LENGTH 6 static const char *temp_exps[6] = { "temp", "cpu", "board", "mobo", "crit", "remote" }; static regex_t temp_exps_comp[TEMP_EXPS_LENGTH]; static regex_t uri_re; /* for error handling */ #define LIBSENSORS_ERROR (libsensors_sensors_interface_error_quark()) enum { LIBSENSORS_CHIP_PARSE_ERROR, LIBSENSORS_MISSING_FEATURE_ERROR, LIBSENSORS_REGEX_URL_COMPILE_ERROR, LIBSENSORS_CHIP_NOT_FOUND_ERROR }; /* for error handling */ static GQuark libsensors_sensors_interface_error_quark(void) { static GQuark quark = 0; gchar *string; if (quark == 0) { string = g_strdup_printf("%s-error", sensor_interface[LIBSENSORS]); quark = g_quark_from_string(string); g_free(string); } return quark; } static char *get_chip_name (const sensors_chip_name *chip) { char *name; // taken from lm-sensors:prog/sensors/main.c:sprintf_chip_name switch (chip->bus) { case SENSORS_CHIP_NAME_BUS_ISA: name = g_strdup_printf ("%s-isa-%04x", chip->prefix, chip->addr); break; case SENSORS_CHIP_NAME_BUS_DUMMY: name = g_strdup_printf ("%s-%s-%04x", chip->prefix, chip->busname, chip->addr); break; default: name = g_strdup_printf ("%s-i2c-%d-%02x", chip->prefix, chip->bus, chip->addr); break; } return name; } static SensorType get_sensor_type (const char *name) { int i; int res = REG_NOMATCH; for (i = 0; i < VOLTAGE_EXPS_LENGTH; ++i) { res = regexec (&volt_exps_comp[i], name, 0, NULL, 0); if (res == 0) return VOLTAGE_SENSOR; } for (i = 0; i < FAN_EXPS_LENGTH; ++i) { res = regexec (&fan_exps_comp[i], name, 0, NULL, 0); if (res == 0) return FAN_SENSOR; } for (i = 0; i < TEMP_EXPS_LENGTH; ++i) { res = regexec (&temp_exps_comp[i], name, 0, NULL, 0); if (res == 0) return TEMP_SENSOR; } g_printf ("default\n"); return CURRENT_SENSOR; /* default :) */ } static char *get_sensor_icon (SensorType type) { switch (type) { case TEMP_SENSOR: return CPU_ICON; case FAN_SENSOR: return FAN_ICON; default: return NULL; } } /* If a sensor is 'interesting' to us then return its label, otherwise NULL. */ static char *get_sensor_interesting_label (sensors_chip_name chip, int feature) { char *label; if (sensors_get_ignored (chip, feature)) if (sensors_get_label (chip, feature, &label) == 0) if (! (strcmp ("alarms", label) == 0 || strncmp ("sensor", label, 6) == 0)) return label; else free (label); return NULL; } static void libsensors_sensors_interface_get_sensors(SensorsApplet *sensors_applet) { FILE *file; const sensors_chip_name *chip; int i, result; /* try to open config file, otherwise try alternate config * file - if neither succeed, exit */ if ((file = fopen (LIBSENSORS_CONFIG_FILE, "r")) == NULL) { if ((file = fopen (LIBSENSORS_ALTERNATIVE_CONFIG_FILE, "r")) == NULL) { return; } } /* at this point should have an open config file, if is not * valid, close file and return */ if (sensors_init(file) != 0) { fclose(file); return; } fclose(file); /* libsensors exposes a number of chips - ... */ i = 0; while ((chip = sensors_get_detected_chips (&i)) != NULL) { char *chip_name; const sensors_feature_data *data; int n1 = 0, n2 = 0; chip_name = get_chip_name (chip); /* ... each of which has one or more 'features' ... */ while ((data = sensors_get_all_features (*chip, &n1, &n2)) != NULL) { // error char *label; /* ... some of which are boring ... */ if ((label = get_sensor_interesting_label (*chip, data->number))) { /* ... and some of which are actually sensors */ if ((data->mode & SENSORS_MODE_R) && (data->mapping == SENSORS_NO_MAPPING)) { SensorType type; gboolean visible; gchar *icon; gchar *url; type = get_sensor_type (label); visible = (type == TEMP_SENSOR ? TRUE : FALSE); icon = get_sensor_icon (type); // the 'path' contains all the information we need to // identify this sensor later url = g_strdup_printf ("sensor://%s/%d", chip_name, data->number); // the id identifies a particular sensor for the user; // we default to the label returned by libsensors sensors_applet_add_sensor (sensors_applet, url, label, label, LIBSENSORS, visible, type, icon); g_free (url); } free (label); } } g_free (chip_name); } } gdouble libsensors_sensors_interface_get_sensor_value(const gchar *path, const gchar *id, SensorType type, GError **error) { regmatch_t m[3]; gdouble result = 0; /* parse the uri into a (chip, feature) tuplet */ if (regexec (&uri_re, path, 3, m, 0) == 0) { char *desired_chip_s; sensors_chip_name desired_chip; int feature; int i; const sensors_chip_name *found_chip; desired_chip_s = g_strndup (path + m[1].rm_so, m[1].rm_eo - m[1].rm_so); if (sensors_parse_chip_name (desired_chip_s, &desired_chip) != 0) g_set_error (error, LIBSENSORS_ERROR, LIBSENSORS_CHIP_PARSE_ERROR, "Error parsing chip name"); else { feature = atoi (path + m[2].rm_so, m[2].rm_eo - m[2].rm_so); /* search for the correct chip */ for (i = 0; found_chip = sensors_get_detected_chips (&i); ) { if (sensors_match_chip (desired_chip, *found_chip)) { double value; /* retrieve the value of the feature */ if (sensors_get_feature (*found_chip, feature, &value) == 0) result = value; else g_set_error (error, LIBSENSORS_ERROR, LIBSENSORS_MISSING_FEATURE_ERROR, "Error retrieving sensor value"); break; } } if (found_chip == NULL) g_set_error (error, LIBSENSORS_ERROR, LIBSENSORS_CHIP_NOT_FOUND_ERROR, "Chip not found"); } g_free (desired_chip_s); } else g_set_error (error, LIBSENSORS_ERROR, LIBSENSORS_REGEX_URL_COMPILE_ERROR, "Error compiling URL regex"); return result; } void libsensors_sensors_interface_init(SensorsApplet *sensors_applet) { int res = 0; int i; /* compile the regular expressions */ assert (regcomp (&uri_re, "^sensor://([a-z0-9-]+)/([0-9]+)$", REG_EXTENDED | REG_ICASE) == 0); for (i = 0; i < VOLTAGE_EXPS_LENGTH; ++i) assert (regcomp (&volt_exps_comp[i], volt_exps[i], REG_ICASE) == 0); for (i = 0; i < FAN_EXPS_LENGTH; ++i) assert (regcomp (&fan_exps_comp[i], fan_exps[i], REG_ICASE) == 0); for (i = 0; i < TEMP_EXPS_LENGTH; ++i) assert (regcomp (&temp_exps_comp[i], temp_exps[i], REG_ICASE) == 0); sensors_applet_register_sensors_interface(sensors_applet, LIBSENSORS, libsensors_sensors_interface_get_sensor_value); libsensors_sensors_interface_get_sensors(sensors_applet); for (i = 0; i < VOLTAGE_EXPS_LENGTH; ++i) regfree (&volt_exps_comp[i]); for (i = 0; i < FAN_EXPS_LENGTH; ++i) regfree (&fan_exps_comp[i]); for (i = 0; i < TEMP_EXPS_LENGTH; ++i) regfree (&temp_exps_comp[i]); }