--- /dev/null
+/*#############################################################################
+# #
+# telemetryd - The IPFire Telemetry Collection Service #
+# Copyright (C) 2026 IPFire Development Team #
+# #
+# 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 3 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, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifdef HAVE_SENSORS
+
+#include <ctype.h>
+
+#include <sensors/error.h>
+#include <sensors/sensors.h>
+
+#include "ctx.h"
+#include "sensors.h"
+#include "source.h"
+#include "string.h"
+
+static int sensors_initialized = 0;
+
+int td_sensors_init(td_ctx* ctx) {
+ int r = 0;
+
+ // Initialize sensors if not already done
+ if (!sensors_initialized) {
+ r = sensors_init(NULL);
+ if (r) {
+ ERROR(ctx, "Failed to initialize sensors: %s\n", sensors_strerror(r));
+ return -ENOTSUP;
+ }
+
+ // We are now initialized
+ sensors_initialized = 1;
+ }
+
+ return r;
+}
+
+int td_sensors_cleanup(td_ctx* ctx) {
+ if (sensors_initialized)
+ sensors_cleanup();
+
+ return 0;
+}
+
+static int td_sensors_join_name(char* name, size_t length,
+ const char* chip, const char* label) {
+ int r;
+
+ // Copy everything info the buffer
+ r = __td_string_format(name, length, "%s-%s", chip, label);
+ if (r < 0)
+ return r;
+
+ // Sanitize the name
+ for (char* p = name; *p; p++) {
+ // Convert everything to lower-case
+ if (isupper(*p)) {
+ *p = tolower(*p);
+ continue;
+
+ // Replace whitespace with dashes
+ } else if (isspace(*p)) {
+ *p = '-';
+ continue;
+ }
+
+ // Replace a couple of special characters, too
+ switch (*p) {
+ case '/':
+ case ':':
+ *p = '-';
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ return 0;
+}
+
+int __td_sensors_name(char* name, size_t length,
+ const sensors_chip_name* chip, const sensors_feature* feature) {
+ char chip_name[NAME_MAX];
+ const char* label = NULL;
+ int r;
+
+ // Make the chip name
+ r = sensors_snprintf_chip_name(chip_name, sizeof(chip_name), chip);
+ if (r < 0)
+ return r;
+
+ // Fetch the label of the feature
+ label = sensors_get_label(chip, feature);
+ if (!label)
+ return -ENOTSUP;
+
+ // Put everything together
+ return td_sensors_join_name(name, length, chip_name, label);
+}
+
+int td_sensors_walk(td_ctx* ctx, td_source* source,
+ sensors_feature_type type, td_sensors_walk_callback callback, void* data) {
+ const sensors_feature* feature = NULL;
+ const sensors_chip_name* chip = NULL;
+ int feature_index = 0;
+ int chip_index = 0;
+ int r;
+
+ // Initialize sensors
+ r = td_sensors_init(ctx);
+ if (r < 0)
+ return r;
+
+ // Iterate over all chips
+ for (;;) {
+ chip = sensors_get_detected_chips(NULL, &chip_index);
+ if (!chip)
+ break;
+
+ // Reset the feature index
+ feature_index = 0;
+
+ // Reset r
+ r = 0;
+
+ // Iterate over all features
+ for (;;) {
+ feature = sensors_get_features(chip, &feature_index);
+ if (!feature)
+ break;
+
+ // Skip anything that does not match
+ if (feature->type != type)
+ continue;
+
+ // Read the values
+ r = callback(ctx, source, type, chip, feature, data);
+ if (r < 0)
+ return r;
+ }
+ }
+
+ return 0;
+}
+
+#endif /* HAVE_SENSORS */
--- /dev/null
+/*#############################################################################
+# #
+# telemetryd - The IPFire Telemetry Collection Service #
+# Copyright (C) 2026 IPFire Development Team #
+# #
+# 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 3 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, see <http://www.gnu.org/licenses/>. #
+# #
+#############################################################################*/
+
+#ifndef TELEMETRY_SENSORS_H
+#define TELEMETRY_SENSORS_H
+
+#ifdef HAVE_SENSORS
+
+#include "ctx.h"
+#include "source.h"
+
+#include <sensors/sensors.h>
+
+int td_sensors_init(td_ctx* ctx);
+int td_sensors_cleanup(td_ctx* ctx);
+
+#define td_sensors_name(name, chip, feature) \
+ __td_sensors_name(name, sizeof(name), chip, feature)
+
+int __td_sensors_name(char* name, size_t length,
+ const sensors_chip_name* chip, const sensors_feature* feature);
+
+typedef int (*td_sensors_walk_callback)(td_ctx* ctx, td_source* source,
+ const sensors_feature_type type, const sensors_chip_name* chip,
+ const sensors_feature* feature, void* data);
+
+int td_sensors_walk(td_ctx* ctx, td_source* source, sensors_feature_type type,
+ td_sensors_walk_callback callback, void* data);
+
+#endif /* HAVE_SENSORS */
+
+#endif /* TELEMETRY_SENSORS_H */
#ifdef BUILD_SOURCE_SENSORS
-#include <ctype.h>
#include <errno.h>
#include <sensors/error.h>
#include "../ctx.h"
#include "../metrics.h"
+#include "../sensors.h"
#include "../source.h"
-#include "../string.h"
#include "sensors.h"
-#define sensors_make_name(name, chip, label) \
- __sensors_make_name(name, sizeof(name), chip, label)
-
-static int __sensors_make_name(char* name, size_t length, const char* chip, const char* label) {
- int r;
-
- // Copy everything info the buffer
- r = __td_string_format(name, length, "%s-%s", chip, label);
- if (r < 0)
- return r;
-
- // Sanitize the name
- for (char* p = name; *p; p++) {
- // Convert everything to lower-case
- if (isupper(*p)) {
- *p = tolower(*p);
- continue;
-
- // Replace whitespace with dashes
- } else if (isspace(*p)) {
- *p = '-';
- continue;
- }
-
- // Replace a couple of special characters, too
- switch (*p) {
- case '/':
- case ':':
- *p = '-';
- break;
-
- default:
- break;
- }
- }
-
- return 0;
-}
-
typedef struct sensors_value {
// Field
const char* field;
return 0;
}
-static int read_sensors(td_ctx* ctx, td_source* source,
- sensors_feature_type type, const sensors_value* values) {
- const sensors_feature* feature = NULL;
- const sensors_chip_name* chip = NULL;
+static int read_sensor(td_ctx* ctx, td_source* source,
+ const sensors_feature_type type, const sensors_chip_name* chip,
+ const sensors_feature* feature, void* data) {
+ const sensors_value* values = data;
td_metrics* metrics = NULL;
- const char* label = NULL;
- char chip_name[NAME_MAX];
char name[NAME_MAX];
- int feature_index = 0;
- int chip_index = 0;
int r;
- // Initialize sensors
- r = sensors_init(NULL);
- if (r) {
- ERROR(ctx, "Failed to initialize sensors: %s\n", sensors_strerror(r));
- return -ENOTSUP;
- }
-
- // Iterate over all chips
- for (;;) {
- chip = sensors_get_detected_chips(NULL, &chip_index);
- if (!chip)
- break;
-
- // Make the chip name
- r = sensors_snprintf_chip_name(chip_name, sizeof(chip_name), chip);
- if (r < 0)
- goto ERROR;
-
- // Reset the feature index
- feature_index = 0;
+ // Fetch the name
+ r = td_sensors_name(name, chip, feature);
+ if (r < 0)
+ goto ERROR;
- // Reset r
- r = 0;
+ // Create metrics
+ r = td_source_create_metrics(source, &metrics, name);
+ if (r < 0)
+ goto ERROR;
- // Iterate over all features
- for (;;) {
- feature = sensors_get_features(chip, &feature_index);
- if (!feature)
- break;
+ // Read the values
+ r = read_values(ctx, chip, feature, metrics, values);
+ if (r < 0)
+ goto ERROR;
- // Skip anything that does not match
- if (feature->type != type)
- continue;
-
- // Fetch the label of the chip
- label = sensors_get_label(chip, feature);
-
- // Format the whole name
- r = sensors_make_name(name, chip_name, label);
- if (r < 0)
- goto ERROR;
-
- // Create metrics
- r = td_source_create_metrics(source, &metrics, name);
- if (r < 0)
- goto ERROR;
-
- // Read the values
- r = read_values(ctx, chip, feature, metrics, values);
- if (r < 0)
- goto ERROR;
-
- // Submit the metrics
- r = td_source_submit_metrics(source, metrics);
- if (r < 0)
- goto ERROR;
-
- // Free the metrics
- if (metrics) {
- td_metrics_unref(metrics);
- metrics = NULL;
- }
- }
- }
+ // Submit the metrics
+ r = td_source_submit_metrics(source, metrics);
+ if (r < 0)
+ goto ERROR;
ERROR:
if (metrics)
td_metrics_unref(metrics);
- sensors_cleanup();
return r;
}
(Voltage) Input
*/
static int sensors_input_heartbeat(td_ctx* ctx, td_source* source) {
- const sensors_value values[] = {
+ sensors_value values[] = {
{ "current", SENSORS_SUBFEATURE_IN_INPUT },
{ "min", SENSORS_SUBFEATURE_IN_MIN },
{ "max", SENSORS_SUBFEATURE_IN_MAX },
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_IN, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_IN, read_sensor, values);
}
const td_source_impl sensors_input_source = {
Fan
*/
static int sensors_fan_heartbeat(td_ctx* ctx, td_source* source) {
- const sensors_value values[] = {
+ sensors_value values[] = {
{ "current", SENSORS_SUBFEATURE_FAN_INPUT },
{ "min", SENSORS_SUBFEATURE_FAN_MIN },
{ "max", SENSORS_SUBFEATURE_FAN_MAX },
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_FAN, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_FAN, read_sensor, values);
}
const td_source_impl sensors_fan_source = {
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_TEMP, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_TEMP, read_sensor, values);
}
const td_source_impl sensors_temp_source = {
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_POWER, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_POWER, read_sensor, values);
}
const td_source_impl sensors_power_source = {
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_ENERGY, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_ENERGY, read_sensor, values);
}
const td_source_impl sensors_energy_source = {
{ NULL },
};
- return read_sensors(ctx, source, SENSORS_FEATURE_CURR, values);
+ return td_sensors_walk(ctx, source, SENSORS_FEATURE_CURR, read_sensor, values);
}
const td_source_impl sensors_current_source = {