+ status = errno;
+ WARNING ("battery plugin: fgets failed: %s",
+ 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, "voltage_now", &v) == 0)
+ battery_submit (plugin_instance, "voltage", v * SYSFS_FACTOR);
+#if 0
+ if (sysfs_file_to_gauge (dir, power_supply, "voltage_min_design", &v) == 0)
+ battery_submit (plugin_instance, "voltage", v * SYSFS_FACTOR);
+#endif
+
+ return (0);
+} /* }}} int read_sysfs_callback */
+
+static int read_sysfs (void) /* {{{ */
+{
+ int status;
+ int battery_counter = 0;
+
+ if (access (SYSFS_PATH, R_OK) != 0)
+ return (ENOENT);
+
+ status = walk_directory (SYSFS_PATH, read_sysfs_callback,
+ /* user_data = */ &battery_counter,
+ /* include hidden */ 0);
+ return (status);
+} /* }}} int read_sysfs */
+
+static int read_acpi_full_capacity (char const *dir, /* {{{ */
+ char const *power_supply,
+ gauge_t *ret_capacity_full,
+ gauge_t *ret_capacity_design)
+
+{
+ char filename[PATH_MAX];
+ char buffer[1024];
+
+ FILE *fh;
+
+ ssnprintf (filename, sizeof (filename), "%s/%s/info", dir, power_supply);
+ fh = fopen (filename, "r");
+ if ((fh = fopen (filename, "r")) == NULL)
+ return (errno);
+
+ /* last full capacity: 40090 mWh */
+ while (fgets (buffer, sizeof (buffer), fh) != NULL)
+ {
+ gauge_t *value_ptr;
+ int fields_num;
+ char *fields[8];
+ int index;
+
+ if (strncmp ("last full capacity:", buffer, strlen ("last full capacity:")) == 0)
+ {
+ value_ptr = ret_capacity_full;
+ index = 3;
+ }
+ else if (strncmp ("design capacity:", buffer, strlen ("design capacity:")) == 0)
+ {
+ value_ptr = ret_capacity_design;
+ index = 2;
+ }
+ else
+ {
+ continue;
+ }
+
+ fields_num = strsplit (buffer, fields, STATIC_ARRAY_SIZE (fields));
+ if (fields_num <= index)
+ continue;
+
+ strtogauge (fields[index], value_ptr);
+ }
+
+ fclose (fh);
+ return (0);
+} /* }}} int read_acpi_full_capacity */
+
+static int read_acpi_callback (char const *dir, /* {{{ */
+ char const *power_supply,
+ void *user_data)
+{
+ int *battery_index = user_data;
+
+ gauge_t power = NAN;
+ gauge_t voltage = NAN;
+ gauge_t capacity_charged = NAN;
+ gauge_t capacity_full = NAN;
+ gauge_t capacity_design = NAN;
+ _Bool charging = 0;
+ _Bool is_current = 0;
+
+ char const *plugin_instance;
+ char filename[PATH_MAX];
+ char buffer[1024];
+
+ FILE *fh;
+
+ ssnprintf (filename, sizeof (filename), "%s/%s/state", dir, power_supply);
+ fh = fopen (filename, "r");
+ if ((fh = fopen (filename, "r")) == NULL)
+ {
+ if ((errno == EAGAIN) || (errno == EINTR) || (errno == ENOENT))
+ return (0);
+ else
+ return (errno);