Package: gkrellm
Version: 2.3.1-1
Severity: normal
Tags: patch
Having just downloaded and compiled 2.6.24 for Debian, I note in
the kernel configurator that the proc entries /proc/acpi/battery and
/proc/acpi/ac_adapter are deprecated, and that all future power/battery
stuff should go through the sysfs interfaces. gkrellm 2.3.1 doesn't do
this yet.
So I wrote a patch. I've no idea how "correct" it is, but it
seems to work for me. If it passes muster, please apply to the
mainline.
Schwab
-- System Information:
Debian Release: lenny/sid
APT prefers unstable
APT policy: (500, 'unstable'), (500, 'testing'), (500, 'stable')
Architecture: i386 (i686)
Kernel: Linux 2.6.24 (SMP w/2 CPU cores; PREEMPT)
Locale: LANG=en_US.UTF-8, LC_CTYPE=en_US.UTF-8 (charmap=UTF-8)
Shell: /bin/sh linked to /bin/bash
Versions of packages gkrellm depends on:
ii libatk1.0-0 1.22.0-1 The ATK accessibility toolkit
ii libc6 2.7-6 GNU C Library: Shared libraries
ii libcairo2 1.4.14-1 The Cairo 2D vector graphics libra
ii libgcrypt11 1.4.0-3 LGPL Crypto library - runtime libr
ii libglib2.0-0 2.16.3-1 The GLib library of C routines
ii libgnutls13 2.0.4-3 the GNU TLS library - runtime libr
ii libgtk2.0-0 2.12.9-2 The GTK+ graphical user interface
ii libice6 2:1.0.4-1 X11 Inter-Client Exchange library
ii libpango1.0-0 1.20.2-2 Layout and rendering of internatio
ii libsm6 2:1.0.3-1+b1 X11 Session Management library
ii libx11-6 2:1.0.3-7 X11 client-side library
gkrellm recommends no packages.
-- no debconf information
diff -ru gkrellm-2.3.1/src/sysdeps/linux.c gkrellm-2.3.1-new/src/sysdeps/linux.c
--- gkrellm-2.3.1/src/sysdeps/linux.c 2007-10-30 12:12:46.000000000 -0700
+++ gkrellm-2.3.1-new/src/sysdeps/linux.c 2008-04-17 23:22:45.000000000 -0700
@@ -1441,12 +1441,13 @@
/* ===================================================================== */
/* Battery monitor interface */
-/* ---------------------------- */
-/* ACPI battery interface */
+/* ---------------------- */
+/* ACPI battery interface */
#define ACPI_BATTERY_DIR "/proc/acpi/battery/"
#define ACPI_AC_ADAPTOR_DIR "/proc/acpi/ac_adapter/"
+
typedef struct
{
gint id;
@@ -1557,6 +1558,7 @@
}
}
+
static gboolean
fgets_lower_case(gchar *buf, gint len, FILE *f)
{
@@ -1727,6 +1729,328 @@
return TRUE;
}
+
+/* ---------------------------- */
+/* sysfs power interface */
+#define SYSFS_POWER_SUPPLIES "/sys/class/power_supply/"
+#define SYSFS_TYPE_BATTERY "battery"
+#define SYSFS_TYPE_AC_ADAPTER "mains"
+
+
+typedef struct syspower
+ {
+ gint type;
+ gint id;
+ gint charge_units;
+ gchar const *sysdir;
+ gchar const *sys_charge_full;
+ gchar const *sys_charge_now;
+ gboolean present;
+ gboolean ac_present;
+ gboolean charging;
+ }
+ syspower;
+#define PWRTYPE_BATTERY 0
+#define PWRTYPE_UPS 1
+#define PWRTYPE_MAINS 2
+#define PWRTYPE_USB 3
+
+#define CHGUNITS_INVALID 0
+#define CHGUNITS_PERCENT 1 /* 'capacity' */
+#define CHGUNITS_uWH 2 /* 'energy' */
+#define CHGUNITS_uAH 3 /* 'charge' */
+
+/*
+ * Ordering in this list is significant: Mains power sources appear before
+ * battery sources.
+ */
+static GList *g_sysfs_power_list;
+static gint g_on_line;
+static gint g_pwr_id;
+
+
+static gboolean
+read_sysfs_entry (gchar *buf, gint buflen, gchar const *sysentry)
+ {
+ FILE *f;
+
+ if ((f = fopen (sysentry, "r")))
+ {
+ if (fgets (buf, buflen, f))
+ {
+ fclose (f);
+ return TRUE;
+ }
+ fclose (f);
+ }
+ return FALSE;
+ }
+
+static gboolean
+sysfs_power_data (struct syspower *sp)
+ {
+ uint64_t charge_full, charge_now;
+ gint time_left;
+ gint present;
+ gint percent;
+ gchar sysentry[128];
+ gchar buf[128];
+ gchar *syszap;
+ gboolean charging;
+ gboolean stat_full;
+
+ time_left = -1;
+ charge_full = charge_now = 0;
+ present = 0;
+ percent = 0;
+ charging = FALSE;
+
+ strcpy (sysentry, sp->sysdir);
+ syszap = sysentry + strlen (sysentry);
+
+ /* What type of entry is this? */
+ if (sp->type == PWRTYPE_MAINS)
+ {
+ /* Get the 'on-line' status. */
+ *syszap = '\0';
+ strcat (sysentry, "/online");
+ if (read_sysfs_entry (buf, sizeof (buf), sysentry))
+ g_on_line = strtol (buf, NULL, 0);
+ return TRUE;
+ }
+
+ /*
+ * The rest of this code doesn't know how to handle anything other than
+ * a battery.
+ */
+ if (sp->type != PWRTYPE_BATTERY)
+ return FALSE;
+
+ /* Is the battery still there? */
+ *syszap = '\0';
+ strcat (sysentry, "/present");
+ if (read_sysfs_entry (buf, sizeof (buf), sysentry))
+ present = strtol (buf, NULL, 0);
+
+ if (present)
+ {
+ if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_full))
+ {
+ charge_full = strtoll (buf, NULL, 0);
+ }
+ if (read_sysfs_entry (buf, sizeof (buf), sp->sys_charge_now))
+ {
+ charge_now = strtoll (buf, NULL, 0);
+ }
+ if (sp->charge_units == CHGUNITS_PERCENT)
+ {
+ percent = charge_now;
+ }
+ else
+ {
+ percent = charge_now * 100 / charge_full;
+ }
+
+ /* Get charging status. */
+ *syszap = '\0';
+ strcat (sysentry, "/status");
+ if (read_sysfs_entry (buf, sizeof (buf), sysentry))
+ {
+ charging = !strcasecmp (buf, "charging");
+ stat_full = !strcasecmp (buf, "full");
+ }
+ }
+
+ gkrellm_battery_assign_data (sp->id, present, g_on_line, charging,
+ percent, time_left);
+ return TRUE;
+ }
+
+
+static gboolean
+setup_sysfs_ac_power (gchar const *sysdir)
+ {
+ syspower *sp;
+
+ if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("setup_sysfs_ac_power: %s\n", sysdir);
+ sp = g_new0 (syspower, 1);
+ sp->type = PWRTYPE_MAINS;
+ sp->id = g_pwr_id++;
+ sp->charge_units = CHGUNITS_INVALID;
+ sp->sysdir = g_strdup (sysdir);
+ sp->sys_charge_full =
+ sp->sys_charge_now = NULL;
+
+ /* Add mains power sources to head of list. */
+ g_sysfs_power_list = g_list_prepend (g_sysfs_power_list, sp);
+
+ return TRUE;
+ }
+
+static gboolean
+setup_sysfs_battery (gchar const *sysdir)
+ {
+ syspower *sp;
+ gchar *sys_charge_full = NULL,
+ *sys_charge_now = NULL;
+ gint units;
+ gboolean retval = FALSE;
+
+ /*
+ * There are three flavors of reporting: 'energy', 'charge', and
+ * 'capacity'. Check for them in that order. (Apologies for the
+ * ugliness; you try coding an unrolled 'if ((A || B) && C)' and make it
+ * pretty.)
+ */
+ if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("setup_sysfs_battery: %s\n", sysdir);
+ units = CHGUNITS_uWH;
+ sys_charge_full = g_strconcat (sysdir, "/energy_full", NULL);
+ if (access (sys_charge_full, F_OK | R_OK))
+ {
+ free (sys_charge_full);
+ sys_charge_full = g_strconcat (sysdir, "/energy_full_design", NULL);
+ if (access (sys_charge_full, F_OK | R_OK))
+ {
+ goto try_charge; /* Look down */
+ }
+ }
+ sys_charge_now = g_strconcat (sysdir, "/energy_now", NULL);
+ if (!access (sys_charge_now, F_OK | R_OK))
+ goto done; /* Look down */
+
+try_charge:
+ if (sys_charge_full) free (sys_charge_full), sys_charge_full = NULL;
+ if (sys_charge_now) free (sys_charge_now), sys_charge_now = NULL;
+
+ units = CHGUNITS_uAH;
+ sys_charge_full = g_strconcat (sysdir, "/charge_full", NULL);
+ if (access (sys_charge_full, F_OK | R_OK))
+ {
+ free (sys_charge_full);
+ sys_charge_full = g_strconcat (sysdir, "/charge_full_design", NULL);
+ if (access (sys_charge_full, F_OK | R_OK))
+ {
+ goto try_capacity; /* Look down */
+ }
+ }
+ sys_charge_now = g_strconcat (sysdir, "/charge_now", NULL);
+ if (!access (sys_charge_now, F_OK | R_OK))
+ goto done; /* Look down */
+
+try_capacity:
+ if (sys_charge_full) free (sys_charge_full), sys_charge_full = NULL;
+ if (sys_charge_now) free (sys_charge_now), sys_charge_now = NULL;
+
+ /* This one's a little simpler... */
+ units = CHGUNITS_PERCENT;
+ /*
+ * FIXME: I have no idea if 'capacity_full' actually shows up, since
+ * 'capacity' always defines "full" as always 100%
+ */
+ sys_charge_full = g_strconcat (sysdir, "/capacity_full", NULL);
+ if (access (sys_charge_full, F_OK | R_OK))
+ goto ackphft; /* Look down */
+
+ sys_charge_now = g_strconcat (sysdir, "/capacity_now", NULL);
+ if (access (sys_charge_now, F_OK | R_OK))
+ goto ackphft; /* Look down */
+
+done:
+ sp = g_new0 (syspower, 1);
+ sp->type = PWRTYPE_BATTERY;
+ sp->id = g_pwr_id++;
+ sp->charge_units = units;
+ sp->sysdir = g_strdup (sysdir);
+ sp->sys_charge_full = sys_charge_full;
+ sp->sys_charge_now = sys_charge_now;
+
+ /* Battery power sources are appended to the end of the list. */
+ g_sysfs_power_list = g_list_append (g_sysfs_power_list, sp);
+ if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("setup_sysfs_battery: %s, %s\n",
+ sys_charge_full, sys_charge_now);
+ retval = TRUE;
+
+ if (0)
+ {
+ackphft:
+ if (sys_charge_full) free (sys_charge_full);
+ if (sys_charge_now) free (sys_charge_now);
+ }
+ return retval;
+ }
+
+static gboolean
+setup_sysfs_power_entry (gchar const *sysentry)
+ {
+ FILE *f;
+ gchar *sysdir;
+ gboolean retval = FALSE;
+
+ sysdir = g_strconcat (SYSFS_POWER_SUPPLIES, sysentry, NULL);
+ if (!access (sysdir, F_OK | R_OK))
+ {
+ /*
+ * Read the type of this power source, and setup the appropriate
+ * entry for it.
+ */
+ gchar *type;
+ gchar buf[64];
+
+ type = g_strconcat (sysdir, "/type", NULL);
+ if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("setup_sysfs_power_entry: checking %s\n", type);
+ if ((f = fopen (type, "r")))
+ {
+ if (fgets (buf, sizeof (buf), f))
+ {
+ buf[strlen (buf) - 1] = '\0'; /* Squash newline. */
+ if (!strcasecmp (buf, SYSFS_TYPE_AC_ADAPTER))
+ retval = setup_sysfs_ac_power (sysdir);
+ else if (!strcasecmp (buf, SYSFS_TYPE_BATTERY))
+ retval = setup_sysfs_battery (sysdir);
+ else if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("setup_sysfs_power_entry: unknown power type: %s\n",
+ buf);
+ }
+ fclose (f);
+ }
+ g_free (type);
+ }
+ free (sysdir);
+
+ return retval;
+ }
+
+static gboolean
+sysfs_power_setup (void)
+ {
+ DIR *d;
+ struct dirent *de;
+ gboolean retval = FALSE;
+
+ if (_GK.debug_level & DEBUG_BATTERY)
+ printf ("sysfs_power_setup() entry\n");
+ if ((d = opendir (SYSFS_POWER_SUPPLIES)) == NULL)
+ return retval;
+
+ while ((de = readdir (d)) != NULL)
+ {
+ if ( !strcmp (de->d_name, ".")
+ || !strcmp (de->d_name, ".."))
+ {
+ continue;
+ }
+ retval |= setup_sysfs_power_entry (de->d_name);
+ }
+ closedir (d);
+
+ return retval;
+ }
+
+
/* ---------------------------- */
/* APM battery interface */
@@ -1871,9 +2195,16 @@
{
GList *list;
- if (acpi_battery_list)
- for (list = acpi_battery_list; list; list = list->next)
+ if (g_sysfs_power_list)
+ {
+ for (list = g_sysfs_power_list; list; list = list->next)
+ sysfs_power_data ((syspower *) (list->data));
+ }
+ else if (acpi_battery_list)
+ {
+ for (list = acpi_battery_list; list; list = list->next)
acpi_battery_data((BatteryFile *)(list->data));
+ }
else
apm_battery_data();
}
@@ -1881,7 +2212,9 @@
gboolean
gkrellm_sys_battery_init()
{
- acpi_setup();
+ /* Prefer sysfs power data to /proc/acpi (which is deprecated). */
+ if (!sysfs_power_setup ())
+ acpi_setup();
return TRUE;
}