- static c_complain_t acpi_dir_complaint = C_COMPLAIN_INIT_STATIC;
-
- FILE *fh;
- char buffer[1024];
- char filename[256];
-
- char *fields[8];
- int numfields;
-
- int i;
- int len;
-
- for (i = 0; i < battery_pmu_num; i++)
- {
- char batnum_str[256];
- double current = INVALID_VALUE;
- double voltage = INVALID_VALUE;
- double charge = INVALID_VALUE;
- double *valptr = NULL;
-
- len = ssnprintf (filename, sizeof (filename), battery_pmu_file, i);
- if ((len < 0) || ((unsigned int)len >= sizeof (filename)))
- continue;
-
- len = ssnprintf (batnum_str, sizeof (batnum_str), "%i", i);
- if ((len < 0) || ((unsigned int)len >= sizeof (batnum_str)))
- continue;
-
- if ((fh = fopen (filename, "r")) == NULL)
- continue;
-
- while (fgets (buffer, sizeof (buffer), fh) != NULL)
- {
- numfields = strsplit (buffer, fields, 8);
-
- if (numfields < 3)
- continue;
-
- if (strcmp ("current", fields[0]) == 0)
- valptr = ¤t;
- else if (strcmp ("voltage", fields[0]) == 0)
- valptr = &voltage;
- else if (strcmp ("charge", fields[0]) == 0)
- valptr = &charge;
- else
- valptr = NULL;
-
- if (valptr != NULL)
- {
- char *endptr;
-
- endptr = NULL;
- errno = 0;
-
- *valptr = strtod (fields[2], &endptr) / 1000.0;
-
- if ((fields[2] == endptr) || (errno != 0))
- *valptr = INVALID_VALUE;
- }
- }
-
- fclose (fh);
- fh = NULL;
-
- if (charge != INVALID_VALUE)
- battery_submit ("0", "charge", charge);
- if (current != INVALID_VALUE)
- battery_submit ("0", "current", current);
- if (voltage != INVALID_VALUE)
- battery_submit ("0", "voltage", voltage);
- }
-
- if (0 == access (battery_acpi_dir, R_OK))
- walk_directory (battery_acpi_dir, battery_read_acpi,
- /* user_data = */ NULL,
- /* include hidden */ 0);
- else
- {
- char errbuf[1024];
- c_complain_once (LOG_WARNING, &acpi_dir_complaint,
- "battery plugin: Failed to access `%s': %s",
- battery_acpi_dir,
- sstrerror (errno, errbuf, sizeof (errbuf)));
- }
+/* Reads a file which contains only a number (and optionally a trailing
+ * newline) and parses that number. */
+static int sysfs_file_to_buffer(char const *dir, /* {{{ */
+ char const *power_supply, char const *basename,
+ char *buffer, size_t buffer_size) {
+ int status;
+ FILE *fp;
+ char filename[PATH_MAX];
+
+ ssnprintf(filename, sizeof(filename), "%s/%s/%s", dir, power_supply,
+ basename);
+
+ /* No file isn't the end of the world -- not every system will be
+ * reporting the same set of statistics */
+ if (access(filename, R_OK) != 0)
+ return ENOENT;
+
+ fp = fopen(filename, "r");
+ if (fp == NULL) {
+ status = errno;
+ if (status != ENOENT) {
+ char errbuf[1024];
+ WARNING("battery plugin: fopen (%s) failed: %s", filename,
+ sstrerror(status, errbuf, sizeof(errbuf)));
+ }
+ return status;
+ }
+
+ if (fgets(buffer, buffer_size, fp) == NULL) {
+ status = errno;
+ if (status != ENODEV) {
+ char errbuf[1024];
+ WARNING("battery plugin: fgets (%s) failed: %s", filename,
+ sstrerror(status, errbuf, sizeof(errbuf)));
+ }
+ fclose(fp);
+ return status;
+ }
+
+ strstripnewline(buffer);
+
+ fclose(fp);
+ return 0;
+} /* }}} int sysfs_file_to_buffer */
+
+/* Reads a file which contains only a number (and optionally a trailing
+ * newline) and parses that number. */
+static int sysfs_file_to_gauge(char const *dir, /* {{{ */
+ char const *power_supply, char const *basename,
+ gauge_t *ret_value) {
+ int status;
+ char buffer[32] = "";
+
+ status =
+ sysfs_file_to_buffer(dir, power_supply, basename, buffer, sizeof(buffer));
+ if (status != 0)
+ return (status);
+
+ return (strtogauge(buffer, ret_value));
+} /* }}} sysfs_file_to_gauge */
+
+static int read_sysfs_capacity(char const *dir, /* {{{ */
+ char const *power_supply,
+ char const *plugin_instance) {
+ gauge_t capacity_charged = NAN;
+ gauge_t capacity_full = NAN;
+ gauge_t capacity_design = NAN;
+ int status;
+
+ status =
+ sysfs_file_to_gauge(dir, power_supply, "energy_now", &capacity_charged);
+ if (status != 0)
+ return (status);
+
+ status =
+ sysfs_file_to_gauge(dir, power_supply, "energy_full", &capacity_full);
+ if (status != 0)
+ return (status);
+
+ status = sysfs_file_to_gauge(dir, power_supply, "energy_full_design",
+ &capacity_design);
+ if (status != 0)
+ return (status);
+
+ submit_capacity(plugin_instance, capacity_charged * SYSFS_FACTOR,
+ capacity_full * SYSFS_FACTOR, capacity_design * SYSFS_FACTOR);
+ return (0);
+} /* }}} int read_sysfs_capacity */
+
+static int read_sysfs_callback(char const *dir, /* {{{ */
+ char const *power_supply, void *user_data) {
+ int *battery_index = user_data;
+
+ char const *plugin_instance;
+ char buffer[32];
+ gauge_t v = NAN;
+ _Bool discharging = 0;
+ int status;
+
+ /* Ignore non-battery directories, such as AC power. */
+ status =
+ sysfs_file_to_buffer(dir, power_supply, "type", buffer, sizeof(buffer));
+ if (status != 0)
+ return (0);
+ if (strcasecmp("Battery", buffer) != 0)
+ return (0);
+
+ (void)sysfs_file_to_buffer(dir, power_supply, "status", buffer,
+ sizeof(buffer));
+ if (strcasecmp("Discharging", buffer) == 0)
+ discharging = 1;
+
+ /* FIXME: This is a dirty hack for backwards compatibility: The battery
+ * plugin, for a very long time, has had the plugin_instance
+ * hard-coded to "0". So, to keep backwards compatibility, we'll use
+ * "0" for the first battery we find and the power_supply name for all
+ * following. This should be reverted in a future major version. */
+ plugin_instance = (*battery_index == 0) ? "0" : power_supply;
+ (*battery_index)++;
+
+ read_sysfs_capacity(dir, power_supply, plugin_instance);
+
+ if (sysfs_file_to_gauge(dir, power_supply, "power_now", &v) == 0) {
+ if (discharging)
+ v *= -1.0;
+ battery_submit(plugin_instance, "power", v * SYSFS_FACTOR);
+ }
+ if (sysfs_file_to_gauge(dir, power_supply, "current_now", &v) == 0) {
+ if (discharging)
+ v *= -1.0;
+ battery_submit(plugin_instance, "current", v * SYSFS_FACTOR);
+ }
+
+ if (sysfs_file_to_gauge(dir, power_supply, "voltage_now", &v) == 0)
+ battery_submit(plugin_instance, "voltage", v * SYSFS_FACTOR);
+
+ return (0);
+} /* }}} int read_sysfs_callback */
+
+static int read_sysfs(void) /* {{{ */
+{
+ int status;
+ int battery_counter = 0;