/*
* Copyright (C) 2005 Alex Murray <pragmatine@gmail.com>
*
* 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 <assert.h>
#endif
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_REGEX_H
#include <regex.h>
#endif
#ifdef HAVE_SENSORS_SENSORS_H
#include <sensors/sensors.h>
#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]);
}
syntax highlighted by Code2HTML, v. 0.9.1