summaryrefslogtreecommitdiff
path: root/modules/devices/sensors.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/devices/sensors.c')
-rw-r--r--modules/devices/sensors.c503
1 files changed, 410 insertions, 93 deletions
diff --git a/modules/devices/sensors.c b/modules/devices/sensors.c
index c9d78ff7..095f0bc4 100644
--- a/modules/devices/sensors.c
+++ b/modules/devices/sensors.c
@@ -1,10 +1,10 @@
/*
* HardInfo - Displays System Information
- * Copyright (C) 2003-2006 Leandro A. F. Pereira <leandro@hardinfo.org>
+ * Copyright (C) 2003-2006 L. A. F. Pereira <l@tia.mat.br>
*
* 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, version 2.
+ * the Free Software Foundation, version 2 or later.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -22,12 +22,21 @@
#include "expr.h"
#include "hardinfo.h"
#include "socket.h"
+#include "udisks2_util.h"
+
+#if defined(HAS_LIBSENSORS) && HAS_LIBSENSORS
+#include <sensors/sensors.h>
+#endif
gchar *sensors = NULL;
+gchar *sensor_icons = NULL;
GHashTable *sensor_compute = NULL;
GHashTable *sensor_labels = NULL;
+gboolean hwmon_first_run = TRUE;
+
+static gchar *last_group = NULL;
-static void read_sensor_labels(gchar *driver) {
+static void read_sensor_labels(gchar *devname) {
FILE *conf;
gchar buf[256], *line, *p;
gboolean lock = FALSE;
@@ -55,14 +64,14 @@ static void read_sensor_labels(gchar *driver) {
continue;
} else if (lock && strstr(line, "label")) { /* label lines */
gchar **names = g_strsplit(strstr(line, "label") + 5, " ", 0);
- gchar *name = NULL, *value = NULL;
+ gchar *key = NULL, *value = NULL;
for (i = 0; names[i]; i++) {
if (names[i][0] == '\0')
continue;
- if (!name)
- name = g_strdup(names[i]);
+ if (!key)
+ key = g_strdup_printf("%s/%s", devname, names[i]);
else if (!value)
value = g_strdup(names[i]);
else
@@ -70,7 +79,7 @@ static void read_sensor_labels(gchar *driver) {
}
remove_quotes(value);
- g_hash_table_insert(sensor_labels, name, value);
+ g_hash_table_insert(sensor_labels, key, g_strstrip(value));
g_strfreev(names);
} else if (lock && strstr(line, "ignore")) { /* ignore lines */
@@ -80,19 +89,18 @@ static void read_sensor_labels(gchar *driver) {
while (*p == ' ')
p++;
- g_hash_table_insert(sensor_labels, g_strdup(p), "ignore");
+ g_hash_table_insert(sensor_labels, g_strdup_printf("%s/%s", devname, p), "ignore");
} else if (lock && strstr(line, "compute")) { /* compute lines */
+ strend(line, ',');
gchar **formulas = g_strsplit(strstr(line, "compute") + 7, " ", 0);
- gchar *name = NULL, *formula = NULL;
+ gchar *key = NULL, *formula = NULL;
for (i = 0; formulas[i]; i++) {
if (formulas[i][0] == '\0')
continue;
- if (formulas[i][0] == ',')
- break;
- if (!name)
- name = g_strdup(formulas[i]);
+ if (!key)
+ key = g_strdup_printf("%s/%s", devname, formulas[i]);
else if (!formula)
formula = g_strdup(formulas[i]);
else
@@ -100,7 +108,7 @@ static void read_sensor_labels(gchar *driver) {
}
g_strfreev(formulas);
- g_hash_table_insert(sensor_compute, name,
+ g_hash_table_insert(sensor_compute, key,
math_string_to_postfix(formula));
} else if (g_str_has_prefix(line,
"chip")) { /* chip lines (delimiter) */
@@ -110,7 +118,7 @@ static void read_sensor_labels(gchar *driver) {
for (i = 1; chips[i]; i++) {
strend(chips[i], '*');
- if (g_str_has_prefix(chips[i] + 1, driver)) {
+ if (g_str_has_prefix(chips[i] + 1, devname)) {
lock = TRUE;
break;
}
@@ -128,36 +136,59 @@ static void read_sensor_labels(gchar *driver) {
static void add_sensor(const char *type,
const char *sensor,
- const char *driver,
+ const char *parent,
double value,
- const char *unit) {
+ const char *unit,
+ const char *icon) {
char key[64];
- sensors = h_strdup_cprintf("%s/%s=%.2f%s|%s\n", sensors,
- driver, sensor, value, unit, type);
+ snprintf(key, sizeof(key), "%s/%s", parent, sensor);
+
+ if (SENSORS_GROUP_BY_TYPE) {
+ // group by type
+ if (g_strcmp0(last_group, type) != 0) {
+ sensors = h_strdup_cprintf("[%s]\n", sensors, type);
+ g_free(last_group);
+ last_group = g_strdup(type);
+ }
+ sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors,
+ key, sensor, value, unit, parent);
+ }
+ else {
+ // group by device source / driver
+ if (g_strcmp0(last_group, parent) != 0) {
+ sensors = h_strdup_cprintf("[%s]\n", sensors, parent);
+ g_free(last_group);
+ last_group = g_strdup(parent);
+ }
+ sensors = h_strdup_cprintf("$%s$%s=%.2f%s|%s\n", sensors,
+ key, sensor, value, unit, type);
+ }
+
+ if (icon != NULL) {
+ sensor_icons = h_strdup_cprintf("Icon$%s$%s=%s.png\n", sensor_icons,
+ key, sensor, icon);
+ }
- snprintf(key, sizeof(key), "%s/%s", driver, sensor);
moreinfo_add_with_prefix("DEV", key, g_strdup_printf("%.2f%s", value, unit));
lginterval = h_strdup_cprintf("UpdateInterval$%s=1000\n", lginterval, key);
}
-static gchar *get_sensor_label(gchar *sensor) {
+static gchar *get_sensor_label_from_conf(gchar *key) {
gchar *ret;
+ ret = g_hash_table_lookup(sensor_labels, key);
- ret = g_hash_table_lookup(sensor_labels, sensor);
- if (!ret)
- ret = g_strdup(sensor);
- else
- ret = g_strdup(ret);
+ if (ret)
+ return g_strdup(ret);
- return ret;
+ return NULL;
}
-static float adjust_sensor(gchar *name, float value) {
+static float adjust_sensor(gchar *key, float value) {
GSList *postfix;
- postfix = g_hash_table_lookup(sensor_compute, name);
+ postfix = g_hash_table_lookup(sensor_compute, key);
if (!postfix)
return value;
@@ -168,79 +199,137 @@ static char *get_sensor_path(int number, const char *prefix) {
return g_strdup_printf("/sys/class/hwmon/hwmon%d/%s", number, prefix);
}
-static char *determine_driver_for_hwmon_path(char *path) {
- char *tmp, *driver;
+static char *determine_devname_for_hwmon_path(char *path) {
+ char *tmp, *devname = NULL;
+
+ // device name
+ tmp = g_strdup_printf("%s/name", path);
+ g_file_get_contents(tmp, &devname, NULL, NULL);
+ g_free(tmp);
+ if (devname)
+ return g_strstrip(devname);
+ // fallback: driver name (from driver link)
tmp = g_strdup_printf("%s/device/driver", path);
- driver = g_file_read_link(tmp, NULL);
+ devname = g_file_read_link(tmp, NULL);
g_free(tmp);
- if (driver) {
- tmp = g_path_get_basename(driver);
- g_free(driver);
- driver = tmp;
- } else {
+ if (!devname) {
+ // fallback: device folder name (from device link)
tmp = g_strdup_printf("%s/device", path);
- driver = g_file_read_link(tmp, NULL);
+ devname = g_file_read_link(tmp, NULL);
g_free(tmp);
}
- if (!driver) {
- tmp = g_strdup_printf("%s/name", path);
- if (!g_file_get_contents(tmp, &driver, NULL, NULL)) {
- driver = g_strdup("unknown");
- } else {
- driver = g_strstrip(driver);
- }
- g_free(tmp);
+ if (devname) {
+ tmp = g_path_get_basename(devname);
+ g_free(devname);
+ return tmp;
}
- return driver;
+ return g_strdup("unknown");
}
struct HwmonSensor {
const char *friendly_name;
- const char *path_format;
+ const char *value_file_regex;
+ const char *value_path_format;
+ const char *label_path_format;
const char *key_format;
const char *unit;
const float adjust_ratio;
- const int begin_at;
+ const char *icon;
};
static const struct HwmonSensor hwmon_sensors[] = {
{
- "Fan",
+ "Fan Speed",
+ "^fan([0-9]+)_input$",
"%s/fan%d_input",
+ "%s/fan%d_label",
"fan%d",
- "RPM",
+ " RPM",
1.0,
- 1
+ "fan"
},
{
"Temperature",
+ "^temp([0-9]+)_input$",
"%s/temp%d_input",
+ "%s/temp%d_label",
"temp%d",
"\302\260C",
1000.0,
- 1
+ "therm"
},
{
"Voltage",
+ "^in([0-9]+)_input$",
"%s/in%d_input",
+ "%s/in%d_label",
"in%d",
"V",
1000.0,
- 0
+ "bolt"
+ },
+ {
+ "Current",
+ "^curr([0-9]+)_input$",
+ "%s/curr%d_input",
+ "%s/curr%d_label",
+ "curr%d",
+ " A",
+ 1000.0,
+ "bolt"
+ },
+ {
+ "Power",
+ "^power([0-9]+)_input$",
+ "%s/power%d_input",
+ "%s/power%d_label",
+ "power%d",
+ " W",
+ 1000000.0,
+ "bolt"
+ },
+ {
+ "CPU Voltage",
+ "^cpu([0-9]+)_vid$",
+ "%s/cpu%d_vid",
+ NULL,
+ "cpu%d_vid",
+ " V",
+ 1000.0,
+ "bolt"
},
{ }
};
static const char *hwmon_prefix[] = {"device", "", NULL};
+static gboolean read_raw_hwmon_value(gchar *path_hwmon, const gchar *item_path_format, int item_id, gchar **result){
+ gchar *full_path;
+ gboolean file_result;
+
+ if (item_path_format == NULL)
+ return FALSE;
+
+ full_path = g_strdup_printf(item_path_format, path_hwmon, item_id);
+ file_result = g_file_get_contents(full_path, result, NULL, NULL);
+
+ g_free(full_path);
+
+ return file_result;
+}
+
static void read_sensors_hwmon(void) {
- int hwmon, count;
- gchar *path_hwmon, *path_sensor, *tmp, *driver, *name, *mon;
- const char **prefix;
+ int hwmon, count, min, max;
+ gchar *path_hwmon, *tmp, *devname, *name, *mon, *key;
+ const char **prefix, *entry;
+ GDir *dir;
+ GRegex *regex;
+ GMatchInfo *match_info;
+ GError *err = NULL;
for (prefix = hwmon_prefix; *prefix; prefix++) {
hwmon = 0;
@@ -248,56 +337,92 @@ static void read_sensors_hwmon(void) {
while (path_hwmon && g_file_test(path_hwmon, G_FILE_TEST_EXISTS)) {
const struct HwmonSensor *sensor;
- driver = determine_driver_for_hwmon_path(path_hwmon);
- DEBUG("hwmon%d has driver=%s", hwmon, driver);
-
- if (!sensor_labels) {
- read_sensor_labels(driver);
+ devname = determine_devname_for_hwmon_path(path_hwmon);
+ DEBUG("hwmon%d has device=%s", hwmon, devname);
+ if (hwmon_first_run) {
+ read_sensor_labels(devname);
}
+ dir = g_dir_open(path_hwmon, 0, NULL);
+ if (!dir)
+ continue;
+
for (sensor = hwmon_sensors; sensor->friendly_name; sensor++) {
DEBUG("current sensor type=%s", sensor->friendly_name);
+ regex = g_regex_new (sensor->value_file_regex, 0, 0, &err);
+ if (err != NULL){
+ g_free(err);
+ err = NULL;
+ continue;
+ }
- for (count = sensor->begin_at;; count++) {
- path_sensor =
- g_strdup_printf(sensor->path_format, path_hwmon, count);
- DEBUG("should be reading from %s", path_sensor);
- if (!g_file_get_contents(path_sensor, &tmp, NULL, NULL)) {
- g_free(path_sensor);
- if (count < 256)
- continue; // brute-force find all
- else
- break;
+ g_dir_rewind(dir);
+ min = 999;
+ max = -1;
+
+ while ((entry = g_dir_read_name(dir))) {
+ g_regex_match(regex, entry, 0, &match_info);
+ if (g_match_info_matches(match_info)) {
+ tmp = g_match_info_fetch(match_info, 1);
+ count = atoi(tmp);
+ g_free (tmp);
+
+ if (count < min){
+ min = count;
+ }
+ if (count > max){
+ max = count;
+ }
+ }
+ g_match_info_free(match_info);
+ }
+ g_regex_unref(regex);
+
+ for (count = min; count <= max; count++) {
+ if (!read_raw_hwmon_value(path_hwmon, sensor->value_path_format, count, &tmp)) {
+ continue;
}
mon = g_strdup_printf(sensor->key_format, count);
- name = get_sensor_label(mon);
+ key = g_strdup_printf("%s/%s", devname, mon);
+ name = get_sensor_label_from_conf(key);
+ if (name == NULL){
+ if (read_raw_hwmon_value(path_hwmon, sensor->label_path_format, count, &name)){
+ name = g_strchomp(name);
+ }
+ else{
+ name = g_strdup(mon);
+ }
+ }
+
if (!g_str_equal(name, "ignore")) {
- float adjusted = adjust_sensor(mon,
+ float adjusted = adjust_sensor(key,
atof(tmp) / sensor->adjust_ratio);
add_sensor(sensor->friendly_name,
name,
- driver,
+ devname,
adjusted,
- sensor->unit);
+ sensor->unit,
+ sensor->icon);
}
g_free(tmp);
g_free(mon);
+ g_free(key);
g_free(name);
- g_free(path_sensor);
}
}
+ g_dir_close(dir);
g_free(path_hwmon);
- g_free(driver);
+ g_free(devname);
path_hwmon = get_sensor_path(++hwmon, *prefix);
}
-
g_free(path_hwmon);
}
+ hwmon_first_run = FALSE;
}
static void read_sensors_acpi(void) {
@@ -323,7 +448,8 @@ static void read_sensors_acpi(void) {
entry,
"ACPI Thermal Zone",
temperature,
- "\302\260C");
+ "\302\260C",
+ "therm");
}
}
@@ -332,6 +458,78 @@ static void read_sensors_acpi(void) {
}
}
+// Sensors for Apple PowerPC devices using Windfarm driver.
+struct WindfarmSensorType {
+ const char *type;
+ const char *icon;
+ const char *file_regex;
+ const char *unit;
+ gboolean with_decimal_p;
+};
+static const struct WindfarmSensorType windfarm_sensor_types[] = {
+ {"Fan", "fan", "^[a-z-]+-fan(-[0-9]+)?$", " RPM", FALSE},
+ {"Temperature", "therm", "^[a-z-]+-temp(-[0-9]+)?$", "\302\260C", TRUE},
+ {"Power", "bolt", "^[a-z-]+-power(-[0-9]+)?$", " W", TRUE},
+ {"Current", "bolt", "^[a-z-]+-current(-[0-9]+)?$", " A", TRUE},
+ {"Voltage", "bolt", "^[a-z-]+-voltage(-[0-9]+)?$", " V", TRUE},
+ { }
+};
+static void read_sensors_windfarm(void)
+{
+ const gchar *path_wf = "/sys/devices/platform/windfarm.0";
+ GDir *wf;
+ gchar *tmp = NULL;
+ gint v1, v2;
+ double value;
+
+ wf = g_dir_open(path_wf, 0, NULL);
+ if (wf) {
+ GRegex *regex;
+ GError *err = NULL;
+ const gchar *entry;
+ const struct WindfarmSensorType *sensor;
+
+ for (sensor = windfarm_sensor_types; sensor->type; sensor++) {
+ DEBUG("current windfarm sensor type=%s", sensor->type);
+ regex = g_regex_new(sensor->file_regex, 0, 0, &err);
+ if (err != NULL) {
+ g_free(err);
+ err = NULL;
+ continue;
+ }
+
+ g_dir_rewind(wf);
+
+ while ((entry = g_dir_read_name(wf))) {
+ if (g_regex_match(regex, entry, 0, NULL)) {
+ gchar *path = g_strdup_printf("%s/%s", path_wf, entry);
+ if (g_file_get_contents(path, &tmp, NULL, NULL)) {
+
+ if (sensor->with_decimal_p) {
+ // format source
+ // https://elixir.free-electrons.com/linux/v5.14/source/drivers/macintosh/windfarm_core.c#L301
+ sscanf(tmp, "%d.%03d", &v1, &v2);
+ value = v1 + (v2 / 1000.0);
+ } else {
+ value = (double)atoi(tmp);
+ }
+ g_free(tmp);
+
+ tmp = g_strdup(entry);
+ add_sensor(sensor->type, g_strdelimit(tmp, "-", ' '),
+ "windfarm", value, sensor->unit,
+ sensor->icon);
+ g_free(tmp);
+ }
+ g_free(path);
+ }
+ }
+ g_regex_unref(regex);
+ }
+ g_dir_close(wf);
+ }
+}
+
static void read_sensors_sys_thermal(void) {
const gchar *path_tz = "/sys/class/thermal";
@@ -355,7 +553,8 @@ static void read_sensors_sys_thermal(void) {
entry,
"thermal",
temperature / 1000.0,
- "\302\260C");
+ "\302\260C",
+ "therm");
g_free(contents);
}
@@ -379,7 +578,8 @@ static void read_sensors_omnibook(void) {
"CPU",
"omnibook",
temperature,
- "\302\260C\n");
+ "\302\260C",
+ "therm");
g_free(contents);
}
@@ -401,7 +601,7 @@ static void read_sensors_hddtemp(void) {
gchar **disks;
int i;
- disks = g_strsplit(buffer, "\n", 0);
+ disks = g_strsplit(buffer, "||", 0);
for (i = 0; disks[i]; i++) {
gchar **fields = g_strsplit(disks[i] + 1, "|", 5);
@@ -412,12 +612,13 @@ static void read_sensors_hddtemp(void) {
* 3 -> C
*/
const gchar *unit = strcmp(fields[3], "C")
- ? "\302\260C" : "\302\260F";
- add_sensor("Hard Drive",
+ ? "\302\260F" : "\302\260C";
+ add_sensor("Drive Temperature",
fields[1],
"hddtemp",
atoi(fields[2]),
- unit);
+ unit,
+ "therm");
g_strfreev(fields);
}
@@ -426,28 +627,144 @@ static void read_sensors_hddtemp(void) {
}
}
+static void read_sensors_udisks2(void) {
+ GSList *node;
+ GSList *temps;
+ udiskt *disk;
+
+ temps = get_udisks2_temps();
+ if (temps == NULL)
+ return;
+
+ for (node = temps; node != NULL; node = node->next) {
+ disk = (udiskt *)node->data;
+ add_sensor("Drive Temperature",
+ disk->drive,
+ "udisks2",
+ disk->temperature,
+ "\302\260C",
+ "therm");
+ udiskt_free(disk);
+ }
+ g_slist_free(temps);
+}
+
+#if HAS_LIBSENSORS
+static const struct libsensors_feature_type {
+ const char *type_name;
+ const char *icon;
+ const char *unit;
+ sensors_subfeature_type input;
+} libsensors_feature_types[SENSORS_FEATURE_MAX] = {
+ [SENSORS_FEATURE_FAN] = {"Fan", "fan", "RPM",
+ SENSORS_SUBFEATURE_FAN_INPUT},
+ [SENSORS_FEATURE_TEMP] = {"Temperature", "therm", "\302\260C",
+ SENSORS_SUBFEATURE_TEMP_INPUT},
+ [SENSORS_FEATURE_POWER] = {"Power", "bolt", "W",
+ SENSORS_SUBFEATURE_POWER_INPUT},
+ [SENSORS_FEATURE_CURR] = {"Current", "bolt", "A",
+ SENSORS_SUBFEATURE_CURR_INPUT},
+ [SENSORS_FEATURE_IN] = {"Voltage", "bolt", "V",
+ SENSORS_SUBFEATURE_IN_INPUT},
+ [SENSORS_FEATURE_VID] = {"CPU Voltage", "bolt", "V",
+ SENSORS_SUBFEATURE_VID},
+};
+static gboolean libsensors_initialized;
+
+static int read_sensors_libsensors(void) {
+ char chip_name_buf[512];
+ const sensors_chip_name *name;
+ int chip_nr = 0;
+ int added_sensors = 0;
+
+ if (!libsensors_initialized)
+ return 0;
+
+ while ((name = sensors_get_detected_chips(NULL, &chip_nr))) {
+ const struct sensors_feature *feat;
+ int feat_nr = 0;
+
+ sensors_snprintf_chip_name(chip_name_buf, 512, name);
+
+ while ((feat = sensors_get_features(name, &feat_nr))) {
+ const struct libsensors_feature_type *feat_descr;
+ const struct sensors_subfeature *subfeat;
+ double value;
+
+ feat_descr = &libsensors_feature_types[feat->type];
+ if (!feat_descr->type_name)
+ continue;
+
+ subfeat = sensors_get_subfeature(name, feat, feat_descr->input);
+ if (!subfeat)
+ continue;
+
+ if (!sensors_get_value(name, subfeat->number, &value)) {
+ char *label = sensors_get_label(name, feat);
+ gchar *label_with_chip = g_strdup_printf("%s (%s)", label, chip_name_buf);
+
+ add_sensor(feat_descr->type_name,
+ label_with_chip,
+ "libsensors",
+ value,
+ feat_descr->unit,
+ feat_descr->icon);
+
+ free(label_with_chip);
+ free(label);
+
+ added_sensors++;
+ }
+ }
+ }
+
+ return added_sensors;
+}
+#else
+static int read_sensors_libsensors(void)
+{
+ return 0;
+}
+#endif
+
void scan_sensors_do(void) {
g_free(sensors);
+ g_free(sensor_icons);
+ g_free(last_group);
+ last_group = NULL;
sensors = g_strdup("");
+ sensor_icons = g_strdup("");
g_free(lginterval);
lginterval = g_strdup("");
- read_sensors_hwmon();
- read_sensors_acpi();
- read_sensors_sys_thermal();
- read_sensors_omnibook();
+ if (read_sensors_libsensors() == 0) {
+ read_sensors_hwmon();
+ read_sensors_acpi();
+ read_sensors_sys_thermal();
+ read_sensors_omnibook();
+ }
+
+ read_sensors_windfarm();
read_sensors_hddtemp();
- /* FIXME: Add support for ibm acpi and more sensors */
+ read_sensors_udisks2();
}
-void sensors_init(void) {
+void sensor_init(void) {
+#if HAS_LIBSENSORS
+ libsensors_initialized = sensors_init(NULL) == 0;
+#endif
+
sensor_labels =
g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
sensor_compute = g_hash_table_new(g_str_hash, g_str_equal);
}
-void sensors_shutdown(void) {
+void sensor_shutdown(void) {
+#if HAS_LIBSENSORS
+ sensors_cleanup();
+#endif
+
g_hash_table_destroy(sensor_labels);
g_hash_table_destroy(sensor_compute);
}